#include "cli/cli-cmds.h"
#include "xml-tdesc.h"
#include "memtag.h"
+#include "cli/cli-style.h"
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
void
core_target::build_file_mappings ()
{
+ /* Type holding information about a single file mapped into the inferior
+ at the point when the core file was created. Associates a build-id
+ with the list of regions the file is mapped into. */
+ struct mapped_file
+ {
+ /* Type for a region of a file that was mapped into the inferior when
+ the core file was generated. */
+ struct region
+ {
+ /* Constructor. See member variables for argument descriptions. */
+ region (CORE_ADDR start_, CORE_ADDR end_, CORE_ADDR file_ofs_)
+ : start (start_),
+ end (end_),
+ file_ofs (file_ofs_)
+ { /* Nothing. */ }
+
+ /* The inferior address for the start of the mapped region. */
+ CORE_ADDR start;
+
+ /* The inferior address immediately after the mapped region. */
+ CORE_ADDR end;
+
+ /* The offset within the mapped file for this content. */
+ CORE_ADDR file_ofs;
+ };
+
+ /* If not nullptr, then this is the build-id associated with this
+ file. */
+ const bfd_build_id *build_id = nullptr;
+
+ /* If true then we have seen multiple different build-ids associated
+ with the same filename. The build_id field will have been set back
+ to nullptr, and we should not set build_id in future. */
+ bool ignore_build_id_p = false;
+
+ /* All the mapped regions of this file. */
+ std::vector<region> regions;
+ };
+
std::unordered_map<std::string, struct bfd *> bfd_map;
std::unordered_set<std::string> unavailable_paths;
+ /* All files mapped into the core file. The key is the filename. */
+ std::unordered_map<std::string, mapped_file> mapped_files;
+
/* See linux_read_core_file_mappings() in linux-tdep.c for an example
read_core_file_mappings method. */
gdbarch_read_core_file_mappings (m_core_gdbarch,
weed out non-file-backed mappings. */
gdb_assert (filename != nullptr);
- if (unavailable_paths.find (filename) != unavailable_paths.end ())
+ /* Add this mapped region to the data for FILENAME. */
+ mapped_file &file_data = mapped_files[filename];
+ file_data.regions.emplace_back (start, end, file_ofs);
+ if (build_id != nullptr && !file_data.ignore_build_id_p)
{
- /* We have already seen some mapping for FILENAME but failed to
- find/open the file. There is no point in trying the same
- thing again so just record that the range [start, end) is
- unavailable. */
- m_core_unavailable_mappings.emplace_back (start, end - start);
- return;
- }
-
- struct bfd *bfd = bfd_map[filename];
- if (bfd == nullptr)
- {
- /* Use exec_file_find() to do sysroot expansion. It'll
- also strip the potential sysroot "target:" prefix. If
- there is no sysroot, an equivalent (possibly more
- canonical) pathname will be provided. */
- gdb::unique_xmalloc_ptr<char> expanded_fname
- = exec_file_find (filename, NULL);
-
- if (expanded_fname == nullptr && build_id != nullptr)
- debuginfod_exec_query (build_id->data, build_id->size,
- filename, &expanded_fname);
-
- if (expanded_fname == nullptr)
+ if (file_data.build_id == nullptr)
+ file_data.build_id = build_id;
+ else if (!build_id_equal (build_id, file_data.build_id))
{
- m_core_unavailable_mappings.emplace_back (start, end - start);
- unavailable_paths.insert (filename);
- warning (_("Can't open file %s during file-backed mapping "
- "note processing"),
- filename);
- return;
+ warning (_("Multiple build-ids found for %ps"),
+ styled_string (file_name_style.style (), filename));
+ file_data.build_id = nullptr;
+ file_data.ignore_build_id_p = true;
}
+ }
+ });
+
+ for (const auto &iter : mapped_files)
+ {
+ const std::string &filename = iter.first;
+ const mapped_file &file_data = iter.second;
+
+ /* Use exec_file_find() to do sysroot expansion. It'll
+ also strip the potential sysroot "target:" prefix. If
+ there is no sysroot, an equivalent (possibly more
+ canonical) pathname will be provided. */
+ gdb::unique_xmalloc_ptr<char> expanded_fname
+ = exec_file_find (filename.c_str (), nullptr);
+
+ bool build_id_mismatch = false;
+ if (expanded_fname != nullptr && file_data.build_id != nullptr)
+ {
+ /* We temporarily open the bfd as a structured target, this
+ allows us to read the build-id from the bfd if there is one.
+ For this task it's OK if we reuse an already open bfd object,
+ so we make this call through GDB's bfd cache. Once we've
+ checked the build-id (if there is one) we'll drop this
+ reference and re-open the bfd using the "binary" target. */
+ gdb_bfd_ref_ptr tmp_bfd
+ = gdb_bfd_open (expanded_fname.get (), gnutarget);
+
+ if (tmp_bfd != nullptr
+ && bfd_check_format (tmp_bfd.get (), bfd_object)
+ && build_id_bfd_get (tmp_bfd.get ()) != nullptr)
+ {
+ /* The newly opened TMP_BFD has a build-id, and this mapped
+ file has a build-id extracted from the core-file. Check
+ the build-id's match, and if not, reject TMP_BFD. */
+ const struct bfd_build_id *found
+ = build_id_bfd_get (tmp_bfd.get ());
+ if (!build_id_equal (found, file_data.build_id))
+ build_id_mismatch = true;
+ }
+ }
- bfd = bfd_openr (expanded_fname.get (), "binary");
+ gdb_bfd_ref_ptr abfd;
+ if (expanded_fname != nullptr && !build_id_mismatch)
+ {
+ struct bfd *b = bfd_openr (expanded_fname.get (), "binary");
+ abfd = gdb_bfd_ref_ptr::new_reference (b);
+ }
- if (bfd == nullptr || !bfd_check_format (bfd, bfd_object))
- {
- m_core_unavailable_mappings.emplace_back (start, end - start);
- unavailable_paths.insert (filename);
- warning (_("Can't open file %s which was expanded to %s "
+ if ((expanded_fname == nullptr
+ || abfd == nullptr
+ || !bfd_check_format (abfd.get (), bfd_object))
+ && file_data.build_id != nullptr)
+ {
+ expanded_fname = nullptr;
+ debuginfod_exec_query (file_data.build_id->data,
+ file_data.build_id->size,
+ filename.c_str (), &expanded_fname);
+ if (expanded_fname != nullptr)
+ {
+ struct bfd *b = bfd_openr (expanded_fname.get (), "binary");
+ abfd = gdb_bfd_ref_ptr::new_reference (b);
+ }
+ }
+
+ if (expanded_fname == nullptr
+ || abfd == nullptr
+ || !bfd_check_format (abfd.get (), bfd_object))
+ {
+ /* If ABFD was opened, but the wrong format, close it now. */
+ abfd = nullptr;
+
+ /* Record all regions for this file as unavailable. */
+ for (const mapped_file::region ®ion : file_data.regions)
+ m_core_unavailable_mappings.emplace_back (region.start,
+ region.end
+ - region.start);
+
+ /* And give the user an appropriate warning. */
+ if (build_id_mismatch)
+ {
+ if (expanded_fname == nullptr
+ || filename == expanded_fname.get ())
+ warning (_("File %ps doesn't match build-id from core-file "
+ "during file-backed mapping processing"),
+ styled_string (file_name_style.style (),
+ filename.c_str ()));
+ else
+ warning (_("File %ps which was expanded to %ps, doesn't match "
+ "build-id from core-file during file-backed "
+ "mapping processing"),
+ styled_string (file_name_style.style (),
+ filename.c_str ()),
+ styled_string (file_name_style.style (),
+ expanded_fname.get ()));
+ }
+ else
+ {
+ if (expanded_fname == nullptr
+ || filename == expanded_fname.get ())
+ warning (_("Can't open file %ps during file-backed mapping "
+ "note processing"),
+ styled_string (file_name_style.style (),
+ filename.c_str ()));
+ else
+ warning (_("Can't open file %ps which was expanded to %ps "
"during file-backed mapping note processing"),
- filename, expanded_fname.get ());
+ styled_string (file_name_style.style (),
+ filename.c_str ()),
+ styled_string (file_name_style.style (),
+ expanded_fname.get ()));
+ }
+ }
+ else
+ {
+ /* Ensure that the bfd will be closed when core_bfd is closed.
+ This can be checked before/after a core file detach via "maint
+ info bfds". */
+ gdb_bfd_record_inclusion (current_program_space->core_bfd (),
+ abfd.get ());
+
+ /* Create sections for each mapped region. */
+ for (const mapped_file::region ®ion : file_data.regions)
+ {
+ /* Make new BFD section. All sections have the same name,
+ which is permitted by bfd_make_section_anyway(). */
+ asection *sec = bfd_make_section_anyway (abfd.get (), "load");
+ if (sec == nullptr)
+ error (_("Can't make section"));
+ sec->filepos = region.file_ofs;
+ bfd_set_section_flags (sec, SEC_READONLY | SEC_HAS_CONTENTS);
+ bfd_set_section_size (sec, region.end - region.start);
+ bfd_set_section_vma (sec, region.start);
+ bfd_set_section_lma (sec, region.start);
+ bfd_set_section_alignment (sec, 2);
+
+ /* Set target_section fields. */
+ m_core_file_mappings.emplace_back (region.start, region.end, sec);
+ }
+ }
- if (bfd != nullptr)
- bfd_close (bfd);
- return;
- }
- /* Ensure that the bfd will be closed when core_bfd is closed.
- This can be checked before/after a core file detach via
- "maint info bfds". */
- gdb_bfd_record_inclusion (current_program_space->core_bfd (), bfd);
- bfd_map[filename] = bfd;
- }
+ /* If this is a bfd of a shared library, record its soname and
+ build-id. */
+ if (file_data.build_id != nullptr && abfd != nullptr)
+ {
+ gdb::unique_xmalloc_ptr<char> soname
+ = gdb_bfd_read_elf_soname (bfd_get_filename (abfd.get ()));
- /* Make new BFD section. All sections have the same name,
- which is permitted by bfd_make_section_anyway(). */
- asection *sec = bfd_make_section_anyway (bfd, "load");
- if (sec == nullptr)
- error (_("Can't make section"));
- sec->filepos = file_ofs;
- bfd_set_section_flags (sec, SEC_READONLY | SEC_HAS_CONTENTS);
- bfd_set_section_size (sec, end - start);
- bfd_set_section_vma (sec, start);
- bfd_set_section_lma (sec, start);
- bfd_set_section_alignment (sec, 2);
-
- /* Set target_section fields. */
- m_core_file_mappings.emplace_back (start, end, sec);
-
- /* If this is a bfd of a shared library, record its soname
- and build id. */
- if (build_id != nullptr)
- {
- gdb::unique_xmalloc_ptr<char> soname
- = gdb_bfd_read_elf_soname (bfd->filename);
- if (soname != nullptr)
- set_cbfd_soname_build_id (current_program_space->cbfd,
- soname.get (), build_id);
- }
- });
+ if (soname != nullptr)
+ set_cbfd_soname_build_id (current_program_space->cbfd,
+ soname.get (), file_data.build_id);
+ }
+ }
normalize_mem_ranges (&m_core_unavailable_mappings);
}
--- /dev/null
+/* Copyright 2024 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This is in the shared library. */
+extern int foo (void);
+
+int
+main (void)
+{
+ int res = foo ();
+ return res;
+}
--- /dev/null
+/* Copyright 2024 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+volatile int *library_ptr = (int *) POINTER_VALUE;
+
+int
+foo (void)
+{
+ return *library_ptr;
+}
--- /dev/null
+/* Copyright 2024 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+volatile void* library_base_address = 0;
+volatile int *ptr = 0;
+
+int
+main ()
+{
+ struct stat buf;
+ int res;
+
+ int fd = open (SHLIB_FILENAME, O_RDONLY);
+ assert (fd != -1);
+
+ res = fstat (fd, &buf);
+ assert (res == 0);
+
+ library_base_address
+ = mmap (NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+
+ res = *ptr; /* Undefined behaviour here. */
+
+ return 0;
+}
--- /dev/null
+# Copyright 2024 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+# This test checks GDB's ability to use build-ids when setting up file backed
+# mappings as part of reading a core-file.
+#
+# A core-file contains a list of the files that were mapped into the process
+# at the time of the core-file creation. If the file was mapped read-only
+# then the file contents will not be present in the core-file, but instead GDB
+# is expected to open the mapped file and read the contents from there if
+# needed. And this is what GDB does.
+#
+# GDB (via the BFD library) will also spot if a mapped looks like a valid ELF
+# and contains a build-id, this build-id is passed back to GDB so that GDB can
+# validate the on-disk file it finds matches the file that was mapped when the
+# core-file was created.
+#
+# In addition, if the on-disk file is found to have a non-matching build-id
+# then GDB can use debuginfod to (try) and download a suitable file.
+#
+# This test is about checking that this file backed mapping mechanism works
+# correctly; that GDB will spot when the build-ids fail to match and will
+# refuse to load an incorrect file. Additionally we check that the correct
+# file can be downloaded from debuginfod.
+#
+# The test is rather contrived though. Instead of relying on having a shared
+# library mapped at the time of crash we mmap a shared library into the
+# process and then check this mapping within the test.
+#
+# The problem with using a normal shared library load for this test is that
+# the shared library list is processed as part of a separate step when opening
+# the core file. Right now this separate step doesn't check the build-ids
+# correctly, so GDB will potentially open the wrong shared library file. The
+# sections of this incorrect shared library are then added to GDB's list of
+# target sections, and are used to satisfy memory reads, which can give the
+# wrong results.
+#
+# This obviously needs fixing, but is a separate problem from the one being
+# tested here, so this test deliberately checks the mapping using a file that
+# is mmaped rather than loaded as a shared library, as such the file is in the
+# core-files list of mapped files, but is not in the shared library list.
+#
+# Despite this test living in the gdb.debuginfod/ directory, only the last
+# part of this test actually uses debuginfod, everything up to that point is
+# pretty generic.
+
+require {!is_remote host}
+require {!is_remote target}
+
+load_lib debuginfod-support.exp
+
+require allow_shlib_tests
+
+standard_testfile -1.c -2.c -3.c
+
+# Compile an executable that loads the shared library as an actual
+# shared library, then use GDB to figure out the offset of the
+# variable 'library_ptr' within the library.
+set library_filename [standard_output_file "libfoo.so"]
+set binfile2 [standard_output_file "library_loader"]
+
+if {[prepare_for_testing_full "build exec which loads the shared library" \
+ [list $library_filename \
+ { debug shlib build-id \
+ additional_flags=-DPOINTER_VALUE=0x12345678 } \
+ $srcfile2 {}] \
+ [list $binfile2 [list debug shlib=$library_filename ] \
+ $srcfile { debug }]] != 0} {
+ return
+}
+
+if {![runto_main]} {
+ return
+}
+
+if { [is_address_zero_readable] } {
+ return
+}
+
+set ptr_address [get_hexadecimal_valueof "&library_ptr" "unknown"]
+
+set ptr_offset "unknown"
+gdb_test_multiple "info proc mappings" "" {
+ -re "^\\s+($hex)\\s+($hex)\\s+$hex\\s+($hex)\[^\r\n\]+$library_filename\r\n" {
+ set low_addr $expect_out(1,string)
+ set high_addr $expect_out(2,string)
+ set file_offset $expect_out(3,string)
+
+ if {[expr $ptr_address >= $low_addr] && [expr $ptr_address < $high_addr]} {
+ set mapping_offset [expr $ptr_address - $low_addr]
+ set ptr_offset [format 0x%x [expr $file_offset + $mapping_offset]]
+ }
+
+ exp_continue
+ }
+
+ -re "^$gdb_prompt $" {
+ }
+
+ -re "(^\[^\r\n\]*)\r\n" {
+ set tmp $expect_out(1,string)
+ exp_continue
+ }
+}
+
+gdb_assert { $ptr_offset ne "unknown" } \
+ "found pointer offset"
+
+set ptr_size [get_integer_valueof "sizeof (library_ptr)" "unknown"]
+set ptr_format_char ""
+if { $ptr_size == 2 } {
+ set ptr_format_char "b"
+} elseif { $ptr_size == 4 } {
+ set ptr_format_char "w"
+} elseif { $ptr_size == 8 } {
+ set ptr_format_char "g"
+}
+if { $ptr_format_char eq "" } {
+ untested "could not figure out size of library_ptr variable"
+ return
+}
+
+# Helper proc to read a value from inferior memory. Reads at address held in
+# global PTR_ADDRESS, and use PTR_FORMAT_CHAR for the size of the read.
+proc read_ptr_value { } {
+ set value ""
+ gdb_test_multiple "x/1${::ptr_format_char}x ${::ptr_address}" "" {
+ -re -wrap "^${::hex}(?:\\s+<\[^>\]+>)?:\\s+($::hex)" {
+ set value $expect_out(1,string)
+ }
+ -re -wrap "^${::hex}(?:\\s+<\[^>\]+>)?:\\s+Cannot access memory at address ${::hex}" {
+ set value "unavailable"
+ }
+ }
+ return $value
+}
+
+set ptr_expected_value [read_ptr_value]
+if { $ptr_expected_value eq "" } {
+ untested "could not find expected value for library_ptr"
+ return
+}
+
+# Now compile a second executable. This one doesn't load the shared
+# library as an actual shared library, but instead mmaps the library
+# into the executable.
+#
+# Load this executable within GDB and confirm that we can use the
+# offset we calculated previously to view the value of 'library_ptr'.
+set opts [list debug additional_flags=-DSHLIB_FILENAME=\"$library_filename\"]
+if {[prepare_for_testing "prepare second executable" $binfile \
+ $srcfile3 $opts] != 0} {
+ return
+}
+
+if {![runto_main]} {
+ return
+}
+
+gdb_breakpoint [gdb_get_line_number "Undefined behaviour here" $srcfile3]
+gdb_continue_to_breakpoint "run to breakpoint"
+
+set library_base_address \
+ [get_hexadecimal_valueof "library_base_address" "unknown"]
+set ptr_address [format 0x%x [expr $library_base_address + $ptr_offset]]
+
+set ptr_value [read_ptr_value]
+gdb_assert { $ptr_value == $ptr_expected_value } \
+ "check value of pointer variable"
+
+# Now rerun the second executable outside of GDB. The executable should crash
+# and generate a corefile.
+set corefile [core_find $binfile]
+if {$corefile eq ""} {
+ untested "could not generate core file"
+ return
+}
+
+# Load a core file from the global COREFILE. Use TESTNAME as the name
+# of the test.
+#
+# If LINE_RE is not the empty string then this is a regexp for a line
+# that we expect to see in the output when loading the core file, if
+# the line is not present then this test will fail.
+#
+# Any lines beginning with 'warning: ' will cause this test to fail.
+#
+# A couple of other standard lines that are produced when loading a
+# core file are also checked for, just to make sure the core file
+# loading has progressed as expected.
+proc load_core_file { testname { line_re "" } } {
+ set code {}
+
+ if { $line_re ne "" } {
+ append code {
+ -re "^$line_re\r\n" {
+ set saw_expected_line true
+ exp_continue
+ }
+ }
+ set saw_expected_line false
+ } else {
+ set saw_expected_line true
+ }
+
+ set saw_unknown_warning false
+ set saw_generated_by_line false
+ set saw_prog_terminated_line false
+
+ append code {
+ -re "^warning: \[^\r\n\]+\r\n" {
+ set saw_unknown_warning true
+ exp_continue
+ }
+
+ -re "^Core was generated by \[^\r\n\]+\r\n" {
+ set saw_generated_by_line true
+ exp_continue
+ }
+
+ -re "^Program terminated with signal SIGSEGV, Segmentation fault\\.\r\n" {
+ set saw_prog_terminated_line true
+ exp_continue
+ }
+
+ -re "^$::gdb_prompt $" {
+ gdb_assert {$saw_generated_by_line \
+ && $saw_prog_terminated_line \
+ && $saw_expected_line \
+ && !$saw_unknown_warning} \
+ $gdb_test_name
+ }
+
+ -re "^\[^\r\n\]*\r\n" {
+ exp_continue
+ }
+ }
+
+ set res [catch { return [gdb_test_multiple "core-file $::corefile" \
+ "$testname" $code] } string]
+
+ if {$res == 1} {
+ global errorInfo errorCode
+ return -code error -errorinfo $errorInfo -errorcode $errorCode $string
+ } elseif {$res == 2} {
+ return $string
+ } else {
+ # We expect RES to be 2 (TCL_RETURN) or 1 (TCL_ERROR). If we get
+ # here then somehow the 'catch' above finished without hitting
+ # either of those cases, which is .... weird.
+ perror "unexepcted return value, code = $res, value = $string"
+ return -1
+ }
+}
+
+# And now restart GDB, load the core-file and check that the library shows as
+# being mapped in, and that we can still read the library_ptr value from
+# memory.
+clean_restart $binfile
+
+load_core_file "load core file"
+
+set library_base_address [get_hexadecimal_valueof "library_base_address" \
+ "unknown" "get library_base_address in core-file"]
+set ptr_address [format 0x%x [expr $library_base_address + $ptr_offset]]
+
+set ptr_value [read_ptr_value]
+gdb_assert { $ptr_value == $ptr_expected_value } \
+ "check value of pointer variable from core-file"
+
+# Now move the shared library file away and restart GDB. This time when we
+# load the core-file we should see a warning that GDB has failed to map in the
+# library file. An attempt to read the variable from the library file should
+# fail / give a warning.
+set library_backup_filename [standard_output_file "libfoo.so.backup"]
+remote_exec build "mv \"$library_filename\" \"$library_backup_filename\""
+
+clean_restart $binfile
+
+load_core_file "load corefile with library file missing" \
+ "warning: Can't open file [string_to_regexp $library_filename] during file-backed mapping note processing"
+
+set ptr_value [read_ptr_value]
+gdb_assert { $ptr_value eq "unavailable" } \
+ "check value of pointer is unavailable with library file missing"
+
+# Build a new version of the shared library, keep the library the same size,
+# but change the contents so the build-id changes. Then restart GDB and load
+# the core-file again. GDB should spot that the build-id for the shared
+# library is not as expected, and should refuse to map in the shared library.
+if {[build_executable "build second version of shared library" \
+ $library_filename $srcfile2 \
+ { debug shlib build-id \
+ additional_flags=-DPOINTER_VALUE=0x11223344 }] != 0} {
+ return
+}
+
+clean_restart $binfile
+
+load_core_file "load corefile with wrong library in place" \
+ "warning: File [string_to_regexp $library_filename] doesn't match build-id from core-file during file-backed mapping processing"
+
+set ptr_value [read_ptr_value]
+gdb_assert { $ptr_value eq "unavailable" } \
+ "check value of pointer is unavailable with wrong library in place"
+
+# Setup a debuginfod server which can serve the original shared library file.
+# Then restart GDB and load the core-file. GDB should download the original
+# shared library from debuginfod and use that to provide the file backed
+# mapping.
+if {![allow_debuginfod_tests]} {
+ untested "skippig debuginfod parts of this test"
+ return
+}
+
+set server_dir [standard_output_file "debuginfod.server"]
+file mkdir $server_dir
+file rename -force $library_backup_filename $server_dir
+
+prepare_for_debuginfod cache db
+
+set url [start_debuginfod $db $server_dir]
+if { $url eq "" } {
+ unresolved "failed to start debuginfod server"
+ return
+}
+
+with_debuginfod_env $cache {
+ setenv DEBUGINFOD_URLS $url
+
+ clean_restart
+ gdb_test_no_output "set debuginfod enabled on" \
+ "enabled debuginfod for initial test"
+ gdb_load $binfile
+
+ load_core_file "load corefile, download library from debuginfod" \
+ "Downloading\[^\r\n\]* executable for [string_to_regexp $library_filename]\\.\\.\\."
+
+ set ptr_value [read_ptr_value]
+ gdb_assert { $ptr_value == $ptr_expected_value } \
+ "check value of pointer variable after downloading library file"
+}
+
+stop_debuginfod