@@ -52,8 +52,8 @@ show validate-build-id
* New features in the GDB remote stub, GDBserver
** library-list-svr4 contains also optional attribute 'build-id' for
- each library. GDB does not load library with build-id that
- does not match such attribute.
+ each library and one optional attribute 'main-build-id'. GDB does
+ not load binaries with build-id that does not match such attribute.
*** Changes in GDB 7.10
@@ -62,7 +62,7 @@ build_id_bfd_get (bfd *abfd)
/* See build-id.h. */
int
-build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check)
+build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check, int advice)
{
const struct bfd_build_id *found;
char *message, *check_hex;
@@ -93,9 +93,12 @@ build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check)
return 1;
back_to = make_cleanup (xfree, message);
- warning (_("Symbol file \"%s\" could not be validated (%s) and "
- "will be ignored; or use 'set validate-build-id off'."),
- bfd_get_filename (abfd), message);
+ if (!advice)
+ warning ("%s", message);
+ else
+ warning (_("Symbol file \"%s\" could not be validated (%s) and "
+ "will be ignored; or use 'set validate-build-id off'."),
+ bfd_get_filename (abfd), message);
do_cleanups (back_to);
return 0;
}
@@ -25,10 +25,11 @@
extern const struct bfd_build_id *build_id_bfd_get (bfd *abfd);
/* Return true if ABFD has NT_GNU_BUILD_ID matching the CHECK value.
- Otherwise, issue a warning and return false. */
+ Otherwise, issue a warning and return false. Boolean ADVICE says whether
+ the warning should suggest to user there is the 'validate-build-id' flag. */
-extern int build_id_verify (bfd *abfd,
- size_t check_len, const bfd_byte *check);
+extern int build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check,
+ int advice);
extern struct file_location
build_id_to_file (size_t build_id_len, const bfd_byte *build_id,
@@ -18109,6 +18109,41 @@ libraries that were loaded by explicit user requests are not
discarded.
@end table
+@table @code
+@kindex set validate-build-id
+@cindex override @value{GDBN} build-id check
+@item set validate-build-id @var{mode}
+Setting to override @value{GDBN} build-id check.
+
+Inferior binaries (shared libraries or main executable) and symbol files
+(for all of those) may contain unique build-id. @value{GDBN} expects
+the build-ids of each binary and its corresponding symbol file to be
+identical. If they are not identical, then by default @value{GDBN} will
+@value{GDBN} will ignore symbol files with non-matching build-id while
+printing:
+
+@smallexample
+ warning: Symbol file "libfoo.so.1" could not be validated (inferior
+ build ID 66f87872 is not identical to symbol file "libfoo.so.1" build
+ ID df81e8db) and will be ignored; or use 'set validate-build-id off'.
+@end smallexample
+
+Turning off this setting would load such symbol file without any warning.
+
+If remote build-id is present but it does not match local build-id (or local
+build-id is not present) then this setting enables (@var{mode} is @code{off}) or
+disables (@var{mode} is @code{on}) loading of such symbol file. On systems
+where build-id is not present in the remote system this setting has no effect.
+The default value is @code{on}.
+
+Loading non-matching symbol file may confuse debugging including breakage
+of backtrace output.
+
+@kindex show validate-build-id
+@item show validate-build-id
+Display the current mode of build-id check override.
+@end table
+
Sometimes you may wish that @value{GDBN} stops and gives you control
when any of shared library events happen. The best way to do this is
to use @code{catch load} and @code{catch unload} (@pxref{Set
@@ -39763,7 +39798,9 @@ address the file was prelinked to during the library load.
Additionally the single @code{main-lm} attribute specifies address of
@code{struct link_map} used for the main executable. This parameter is used
-for TLS access and its presence is optional.
+for TLS access and its presence is optional. Similarly the single
+@code{main-build-id} optional attribute specifies hex encoded
+@code{NT_GNU_BUILD_ID} note for the main executable.
@value{GDBN} must be linked with the Expat library to support XML
SVR4 library lists. @xref{Expat}.
@@ -39772,7 +39809,8 @@ A simple memory map, with two loaded libraries (which do not use prelink),
looks like this:
@smallexample
-<library-list-svr4 version="1.0" main-lm="0xe4f8f8">
+<library-list-svr4 version="1.0" main-lm="0xe4f8f8"
+ main-build-id="b96b2f6fbfb7d144b676cb66f56b6100">
<library name="/lib/ld-linux.so.2" lm="0xe4f51c" l_addr="0xe2d000"
l_ld="0xe4eefc"/>
<library name="/lib/libc.so.6" lm="0xe4fbe8" l_addr="0x154000"
@@ -39785,8 +39823,9 @@ The format of an SVR4 library list is described by this DTD:
@smallexample
<!-- library-list-svr4: Root element with versioning -->
<!ELEMENT library-list-svr4 (library)*>
-<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
-<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
+<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
+<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
+<!ATTLIST library-list-svr4 main-build-id CDATA #IMPLIED>
<!ELEMENT library EMPTY>
<!ATTLIST library name CDATA #REQUIRED>
<!ATTLIST library lm CDATA #REQUIRED>
@@ -2498,7 +2498,7 @@ dwarf2_get_dwz_file (void)
dwz_bfd = gdb_bfd_open (filename, gnutarget, -1);
if (dwz_bfd != NULL)
{
- if (!build_id_verify (dwz_bfd, buildid_len, buildid))
+ if (!build_id_verify (dwz_bfd, buildid_len, buildid, 1 /* advice */))
{
gdb_bfd_unref (dwz_bfd);
dwz_bfd = NULL;
@@ -35,6 +35,7 @@
#include "progspace.h"
#include "gdb_bfd.h"
#include "gcore.h"
+#include "build-id.h"
#include <fcntl.h>
#include "readline/readline.h"
@@ -143,11 +144,16 @@ exec_file_and_symbols_resync (struct inferior *inf, int from_tty)
{
char *exec_file, *full_exec_path = NULL;
struct cleanup *old_chain = save_current_program_space ();
+ size_t build_idsz;
+ gdb_byte *build_id;
/* Switch over temporarily, while reading executable and
symbols. */
set_current_program_space (inf->pspace);
+ solib_main_build_id (&build_idsz, &build_id);
+ make_cleanup (xfree, build_id);
+
/* Try to determine a filename from the process itself. */
exec_file = target_pid_to_exec_file (inf->pid);
if (exec_file != NULL)
@@ -155,8 +161,7 @@ exec_file_and_symbols_resync (struct inferior *inf, int from_tty)
/* If gdb_sysroot is not empty and the discovered filename
is absolute then prefix the filename with gdb_sysroot. */
if (*gdb_sysroot != '\0' && IS_ABSOLUTE_PATH (exec_file))
- full_exec_path = exec_file_find (exec_file, 0 /* build_idsz */,
- NULL /* build_id */, NULL);
+ full_exec_path = exec_file_find (exec_file, build_idsz, build_id, NULL);
if (full_exec_path == NULL)
{
@@ -167,8 +172,8 @@ exec_file_and_symbols_resync (struct inferior *inf, int from_tty)
Attempt to qualify the filename against the source path.
(If that fails, we'll just fall back on the original
filename. Not much more we can do...) */
- if (!source_full_path_of (exec_file, 0 /* build_idsz */,
- NULL /* build_id */, &full_exec_path))
+ if (!source_full_path_of (exec_file, build_idsz, build_id,
+ &full_exec_path))
full_exec_path = xstrdup (exec_file);
}
}
@@ -179,6 +184,7 @@ exec_file_and_symbols_resync (struct inferior *inf, int from_tty)
warning (_("Detected exec-file mismatch on %s. Running %s; Loaded %s"),
target_pid_to_str (pid_to_ptid (inf->pid)),
full_exec_path, exec_filename);
+ build_id_verify (exec_bfd, build_idsz, build_id, 0 /* advice */);
reopen_exec_file ();
}
else if (full_exec_path != NULL)
@@ -194,6 +200,9 @@ exec_file_and_symbols_resync (struct inferior *inf, int from_tty)
"Running %s; Loaded %s"),
target_pid_to_str (pid_to_ptid (inf->pid)),
full_exec_path, symbol_filename);
+
+ build_id_verify (symfile_objfile->obfd, build_idsz, build_id,
+ 0 /* advice */);
}
else if (full_exec_path != NULL)
symbol_file_add_main (0, full_exec_path, from_tty);
@@ -6,8 +6,9 @@
<!-- library-list-svr4: Root element with versioning -->
<!ELEMENT library-list-svr4 (library)*>
-<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
-<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
+<!ATTLIST library-list-svr4 version CDATA #FIXED "1.0">
+<!ATTLIST library-list-svr4 main-lm CDATA #IMPLIED>
+<!ATTLIST library-list-svr4 main-build-id CDATA #IMPLIED>
<!ELEMENT library EMPTY>
<!ATTLIST library name CDATA #REQUIRED>
@@ -6915,8 +6915,25 @@ linux_qxfer_libraries_svr4 (const char *annex, unsigned char *readbuf,
exited above due to failed get_r_debug. */
if (lm_prev == 0)
{
+ const char *hex_enc_build_id = get_hex_build_id (l_addr, l_ld, &data);
+
sprintf (p, " main-lm=\"0x%lx\"", (unsigned long) lm_addr);
p = p + strlen (p);
+
+ if (hex_enc_build_id != NULL)
+ {
+ while (allocated
+ < p - document + 200 + strlen (hex_enc_build_id))
+ {
+ /* Expand to guarantee sufficient storage. */
+ uintptr_t document_len = p - document;
+
+ document = xrealloc (document, 2 * allocated);
+ allocated *= 2;
+ p = document + document_len;
+ }
+ p += sprintf (p, " main-build-id=\"%s\"", hex_enc_build_id);
+ }
}
else
{
@@ -358,6 +358,8 @@ struct svr4_info
/* Load map address for the main executable. */
CORE_ADDR main_lm_addr;
+ size_t main_build_idsz;
+ gdb_byte *main_build_id;
CORE_ADDR interp_text_sect_low;
CORE_ADDR interp_text_sect_high;
@@ -1087,6 +1089,9 @@ struct svr4_library_list
/* Inferior address of struct link_map used for the main executable. It is
NULL if not known. */
CORE_ADDR main_lm;
+
+ size_t main_build_idsz;
+ gdb_byte *main_build_id;
};
/* Implementation for target_so_ops.free_so. */
@@ -1175,13 +1180,13 @@ hex2bin_allocate (const char *hex, gdb_byte **binp, size_t *binszp,
hex_len = strlen (hex);
if (hex_len == 0)
{
- warning (_("Shared library \"%s\" received empty build-id "
+ warning (_("Binary file \"%s\" received empty build-id "
"from gdbserver"), filename);
return;
}
if ((hex_len & 1U) != 0)
{
- warning (_("Shared library \"%s\" received odd number "
+ warning (_("Binary file \"%s\" received odd number "
"of build-id \"%s\" hex characters from gdbserver"),
filename, hex);
return;
@@ -1191,7 +1196,7 @@ hex2bin_allocate (const char *hex, gdb_byte **binp, size_t *binszp,
*binszp = hex2bin (hex, *binp, binsz);
if (*binszp != binsz)
{
- warning (_("Shared library \"%s\" received invalid "
+ warning (_("Binary file \"%s\" received invalid "
"build-id \"%s\" hex character at encoded byte "
"position %s (first as 0) from gdbserver"),
filename, hex, pulongest (*binszp));
@@ -1245,6 +1250,10 @@ svr4_library_list_start_list (struct gdb_xml_parser *parser,
struct svr4_library_list *list = user_data;
const char *version = xml_find_attribute (attributes, "version")->value;
struct gdb_xml_value *main_lm = xml_find_attribute (attributes, "main-lm");
+ const struct gdb_xml_value *const att_main_build_id
+ = xml_find_attribute (attributes, "main-build-id");
+ const char *const main_hex_build_id = (att_main_build_id
+ ? att_main_build_id->value : NULL);
if (strcmp (version, "1.0") != 0)
gdb_xml_error (parser,
@@ -1253,6 +1262,8 @@ svr4_library_list_start_list (struct gdb_xml_parser *parser,
if (main_lm)
list->main_lm = *(ULONGEST *) main_lm->value;
+ hex2bin_allocate (main_hex_build_id, &list->main_build_id,
+ &list->main_build_idsz, _("main executable"));
}
/* The allowed elements and attributes for an XML library list.
@@ -1282,6 +1293,7 @@ static const struct gdb_xml_attribute svr4_library_list_attributes[] =
{
{ "version", GDB_XML_AF_NONE, NULL, NULL },
{ "main-lm", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
+ { "main-build-id", GDB_XML_AF_OPTIONAL, NULL, NULL },
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
@@ -1509,15 +1521,24 @@ svr4_current_sos_direct (struct svr4_info *info)
Unfortunately statically linked inferiors will also fall back through this
suboptimal code path. */
+ library_list.main_build_id = NULL;
+ library_list.main_build_idsz = 0;
info->using_xfer = svr4_current_sos_via_xfer_libraries (&library_list,
NULL);
if (info->using_xfer)
{
if (library_list.main_lm)
info->main_lm_addr = library_list.main_lm;
+ if (library_list.main_build_id != NULL)
+ {
+ xfree (info->main_build_id);
+ info->main_build_id = library_list.main_build_id;
+ info->main_build_idsz = library_list.main_build_idsz;
+ }
return library_list.head ? library_list.head : svr4_default_sos ();
}
+ xfree (library_list.main_build_id);
/* Always locate the debug struct, in case it has moved. */
info->debug_base = 0;
@@ -1576,6 +1597,25 @@ svr4_current_sos_1 (void)
return svr4_current_sos_direct (info);
}
+/* Implement svr4_so_ops's target_so_ops method main_build_id. */
+
+static void
+svr4_main_build_id (size_t *build_idszp, gdb_byte **build_idp)
+{
+ struct svr4_info *info = get_svr4_info ();
+
+ /* If the solib list has been read and stored by the probes
+ interface then even main_build_id should be valid there. */
+ if (info->solib_list == NULL)
+ svr4_current_sos_direct (info);
+
+ *build_idszp = info->main_build_idsz;
+ if (*build_idszp == 0)
+ *build_idp = NULL;
+ else
+ *build_idp = xmemdup (info->main_build_id, *build_idszp, *build_idszp);
+}
+
/* Implement the "current_sos" target_so_ops method. */
static struct so_list *
@@ -3125,6 +3165,9 @@ svr4_clear_solib (void)
info->debug_loader_offset = 0;
xfree (info->debug_loader_name);
info->debug_loader_name = NULL;
+ xfree (info->main_build_id);
+ info->main_build_id = NULL;
+ info->main_build_idsz = 0;
}
/* Clear any bits of ADDR that wouldn't fit in a target-format
@@ -3336,6 +3379,7 @@ _initialize_svr4_solib (void)
svr4_so_ops.special_symbol_handling = svr4_special_symbol_handling;
svr4_so_ops.current_sos = svr4_current_sos;
svr4_so_ops.open_symbol_file_object = open_symbol_file_object;
+ svr4_so_ops.main_build_id = svr4_main_build_id;
svr4_so_ops.in_dynsym_resolve_code = svr4_in_dynsym_resolve_code;
svr4_so_ops.bfd_open = solib_bfd_open;
svr4_so_ops.lookup_lib_global_symbol = elf_lookup_lib_symbol;
@@ -1669,6 +1669,20 @@ solib_global_lookup (struct objfile *objfile,
return (struct block_symbol) {NULL, NULL};
}
+/* See solist.h. */
+
+void
+solib_main_build_id (size_t *build_idszp, gdb_byte **build_idp)
+{
+ const struct target_so_ops *ops = ops = solib_ops (target_gdbarch ());
+
+ if (ops->main_build_id != NULL)
+ return ops->main_build_id (build_idszp, build_idp);
+
+ *build_idszp = 0;
+ *build_idp = NULL;
+}
+
/* Lookup the value for a specific symbol from dynamic symbol table. Look
up symbol from ABFD. MATCH_SYM is a callback function to determine
whether to pick up a symbol. DATA is the input of this callback
@@ -135,6 +135,13 @@ struct target_so_ops
catch_errors requires a pointer argument. */
int (*open_symbol_file_object) (void *from_ttyp);
+ /* Report build-id of the main executable. Both BUILD_IDSZP and
+ BUILD_IDP must not be NULL. If returned *BUILD_IDSZP is zero
+ build-id is not known. Returned *BUILD_IDP must be xfree-d by
+ the caller. This pointer can be NULL, in which case this
+ functionality is not supported for this target. */
+ void (*main_build_id) (size_t *build_idszp, gdb_byte **build_idp);
+
/* Determine if PC lies in the dynamic symbol resolution code of
the run time loader. */
int (*in_dynsym_resolve_code) (CORE_ADDR pc);
@@ -212,4 +219,7 @@ struct block_symbol solib_global_lookup (struct objfile *objfile,
const char *name,
const domain_enum domain);
+/* See target_so_ops's main_build_id. */
+void solib_main_build_id (size_t *build_idszp, gdb_byte **build_idp);
+
#endif
@@ -916,7 +916,7 @@ file_location_from_filename (const char *filename, enum openp_flags opts,
return file;
}
- if (!build_id_verify (file.abfd, build_idsz, build_id))
+ if (!build_id_verify (file.abfd, build_idsz, build_id, 1 /* advice */))
{
do_cleanups (back_to);
file_location_enoent (&file);
new file mode 100644
@@ -0,0 +1,39 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2015 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 <unistd.h>
+
+int _bar = 21;
+
+int
+bar (void)
+{
+ return 42 - _bar;
+}
+
+int
+foo (void)
+{
+ return 24 + bar();
+}
+
+int
+main (void)
+{
+ sleep (60);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,39 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2015 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 <unistd.h>
+
+int _bar = 42;
+
+int
+bar (void)
+{
+ return _bar + 21;
+}
+
+int
+foo (void)
+{
+ return _bar;
+}
+
+int
+main (void)
+{
+ sleep (60);
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,158 @@
+# Copyright 2015 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/>. */
+
+standard_testfile
+
+if [is_remote target] {
+ untested "only local remote is currently supported"
+ return -1
+}
+if [is_remote host] {
+ untested "only local host is currently supported"
+ return -1
+}
+if [target_info exists use_gdb_stub] {
+ untested "only extended-remote target is supported for this test"
+ return -1
+}
+
+clean_restart
+
+if ![gdb_is_target_remote] {
+ untested "only gdbserver supports build-id reporting"
+ return -1
+}
+if ![target_is_gdbserver] {
+ untested "only FSF gdbserver supports build-id reporting"
+ return -1
+}
+
+# Test overview:
+# generate two executable. One that will be used by the process
+# and another, modified, that will be found by gdb. Gdb should
+# detect the mismatch and refuse to use mismatched executable.
+
+# First version of the object.
+set srcmainfilerun ${testfile}.c
+
+# Modified version of the object.
+# Code in -mod.c is tuned so it gives a mismatch.
+set srcmainfilegdb ${testfile}-mod.c
+
+# So file name:
+set binmainfilebase {testfile}
+
+# Setup run directory (where program is run from)
+# It contains the right executable.
+set binmainfiledirrun [standard_output_file ${testfile}_wd]
+set binmainfilerun ${binmainfiledirrun}/${binmainfilebase}
+
+# Second executable version is in current directory, '-mod' version.
+set binmainfiledirgdb [standard_output_file ""]
+set binmainfilegdb ${binmainfiledirgdb}/${binmainfilebase}
+
+file delete -force -- "${binmainfiledirrun}"
+file mkdir "${binmainfiledirrun}"
+
+set exec_opts {}
+lappend exec_opts "additional_flags=-DDIRNAME\=\"${binmainfiledirrun}\""
+lappend exec_opts "debug"
+lappend exec_opts "ldflags=-Wl,--build-id"
+
+if { [build_executable $testfile.exp $binmainfilerun $srcmainfilerun $exec_opts] != 0 } {
+ return -1
+}
+if { [build_executable $testfile.exp $binmainfilegdb $srcmainfilegdb $exec_opts] != 0 } {
+ return -1
+}
+
+set test_spawn_id [spawn_wait_for_attach $binmainfilerun]
+set testpid [spawn_id_get_pid $test_spawn_id]
+
+file copy -force $binmainfilerun $binmainfilerun-backup
+file copy -force $binmainfilegdb $binmainfilerun
+
+with_test_prefix "forced wrong executable" {
+ clean_restart $binmainfilerun
+
+ set test "attach"
+ gdb_test_multiple "attach $testpid" "$test" {
+ -re "Attaching to program: .*\r\nwarning: Detected exec-file mismatch .*\r\nwarning: inferior build ID .*\r\n$gdb_prompt $" {
+ pass "$test"
+ }
+ }
+
+ gdb_test "detach"
+}
+
+with_test_prefix "unavailable autodetected executable" {
+ clean_restart
+
+ set test "attach"
+ gdb_test_multiple "attach $testpid" "$test" {
+ -re "Attaching to process $testpid\r\n.*\r\n$gdb_prompt $" {
+ pass "$test"
+ }
+ }
+
+ set test "bt"
+ gdb_test_multiple $test $test {
+ -re " in main \[^\r\n\]*\r\n$gdb_prompt $" {
+ fail $test
+ }
+ -re "\r\n$gdb_prompt $" {
+ pass $test
+ }
+ }
+
+ gdb_test "detach"
+}
+
+# Test locating file by its build-id - if the regular filename does not match.
+# build-id file has to be a symlink - otherwise so_list->so_name shown in 'info
+# sharedlibrary' would contain the build-id hash and not the library name.
+set build_id_debug_relative [build_id_debug_filename_get $binmainfilerun-backup]
+if { ![regexp {^(.*)\.debug$} $build_id_debug_relative trash build_id_relative] } {
+ fail "strip debug $build_id_debug_relative"
+ return
+}
+set build_id_filename "${binmainfiledirrun}/$build_id_relative"
+file mkdir [file dirname $build_id_filename]
+remote_exec host "ln -sf $binmainfilerun-backup $build_id_filename"
+
+with_test_prefix "build-id autodetected executable" {
+ clean_restart
+
+ gdb_test_no_output "set debug-file-directory $binmainfiledirrun" "set debug-file-directory"
+
+ set test "attach"
+ gdb_test_multiple "attach $testpid" "$test" {
+ -re "\r\nwarning: Detected exec-file mismatch .*\r\n$gdb_prompt $" {
+ fail "$test"
+ }
+ -re "\r\nwarning: inferior build ID .*\r\n$gdb_prompt $" {
+ fail "$test"
+ }
+ -re "Attaching to process $testpid\r\n.*\r\n$gdb_prompt $" {
+ pass "$test"
+ }
+ }
+
+ gdb_test "bt" " in main \[^\r\n\]*"
+
+ gdb_test "detach"
+}
+
+kill_wait_spawned_process $test_spawn_id