diff options
-rw-r--r-- | bfd/ChangeLog | 8 | ||||
-rw-r--r-- | bfd/bfd-in2.h | 3 | ||||
-rw-r--r-- | bfd/opncls.c | 41 | ||||
-rw-r--r-- | gdb/ChangeLog | 13 | ||||
-rw-r--r-- | gdb/Makefile.in | 8 | ||||
-rw-r--r-- | gdb/build-id.c | 168 | ||||
-rw-r--r-- | gdb/build-id.h | 44 | ||||
-rw-r--r-- | gdb/dwarf2read.c | 32 | ||||
-rw-r--r-- | gdb/elfread.c | 126 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 10 | ||||
-rw-r--r-- | gdb/testsuite/gdb.dwarf2/dwzbuildid.exp | 170 | ||||
-rw-r--r-- | gdb/testsuite/lib/dwarf.exp | 62 |
12 files changed, 530 insertions, 155 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index c5d9827..e8534dd 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,11 @@ +2013-10-08 Tom Tromey <tromey@redhat.com> + + * bfd-in2.h: Rebuild. + * opncls.c (bfd_get_alt_debug_link_info): Add buildid_len + parameter. Change type of buildid_out. Update. + (get_alt_debug_link_info_shim): New function. + (bfd_follow_gnu_debuglink): Use it. + 2013-10-08 Andreas Schwab <schwab@suse.de> * elf32-m68k.c (elf_m68k_size_dynamic_sections): Add DT_DEBUG also diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 41f7a68..67eb7da 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -1067,7 +1067,8 @@ unsigned long bfd_calc_gnu_debuglink_crc32 char *bfd_get_debug_link_info (bfd *abfd, unsigned long *crc32_out); -char *bfd_get_alt_debug_link_info (bfd *abfd, unsigned long *crc32_out); +char *bfd_get_alt_debug_link_info (bfd * abfd, size_t *buildid_len, + bfd_byte **buildid_out); char *bfd_follow_gnu_debuglink (bfd *abfd, const char *dir); diff --git a/bfd/opncls.c b/bfd/opncls.c index cd9c826..f29b2c8 100644 --- a/bfd/opncls.c +++ b/bfd/opncls.c @@ -1194,18 +1194,21 @@ FUNCTION bfd_get_alt_debug_link_info SYNOPSIS - char *bfd_get_alt_debug_link_info (bfd *abfd, unsigned long *crc32_out); + char *bfd_get_alt_debug_link_info (bfd * abfd, size_t *buildid_len, + bfd_byte **buildid_out); DESCRIPTION Fetch the filename and BuildID value for any alternate debuginfo associated with @var{abfd}. Return NULL if no such info found, - otherwise return filename and update @var{buildid_out}. The - returned filename is allocated with @code{malloc}; freeing it - is the responsibility of the caller. + otherwise return filename and update @var{buildid_len} and + @var{buildid_out}. The returned filename and build_id are + allocated with @code{malloc}; freeing them is the + responsibility of the caller. */ char * -bfd_get_alt_debug_link_info (bfd * abfd, unsigned long * buildid_out) +bfd_get_alt_debug_link_info (bfd * abfd, size_t *buildid_len, + bfd_byte **buildid_out) { asection *sect; bfd_byte *contents; @@ -1213,6 +1216,7 @@ bfd_get_alt_debug_link_info (bfd * abfd, unsigned long * buildid_out) char *name; BFD_ASSERT (abfd); + BFD_ASSERT (buildid_len); BFD_ASSERT (buildid_out); sect = bfd_get_section_by_name (abfd, GNU_DEBUGALTLINK); @@ -1227,12 +1231,13 @@ bfd_get_alt_debug_link_info (bfd * abfd, unsigned long * buildid_out) return NULL; } - /* BuildID value is stored after the filename, aligned up to 4 bytes. */ + /* BuildID value is stored after the filename. */ name = (char *) contents; buildid_offset = strlen (name) + 1; - buildid_offset = (buildid_offset + 3) & ~3; - * buildid_out = bfd_get_32 (abfd, contents + buildid_offset); + *buildid_len = bfd_get_section_size (sect) - buildid_offset; + *buildid_out = bfd_malloc (*buildid_len); + memcpy (*buildid_out, contents + buildid_offset, *buildid_len); return name; } @@ -1466,6 +1471,24 @@ bfd_follow_gnu_debuglink (bfd *abfd, const char *dir) separate_debug_file_exists); } +/* Helper for bfd_follow_gnu_debugaltlink. It just pretends to return + a CRC. .gnu_debugaltlink supplies a build-id, which is different, + but this is ok because separate_alt_debug_file_exists ignores the + CRC anyway. */ + +static char * +get_alt_debug_link_info_shim (bfd * abfd, unsigned long *crc32_out) +{ + size_t len; + bfd_byte *buildid = NULL; + char *result = bfd_get_alt_debug_link_info (abfd, &len, &buildid); + + *crc32_out = 0; + free (buildid); + + return result; +} + /* FUNCTION bfd_follow_gnu_debugaltlink @@ -1496,7 +1519,7 @@ char * bfd_follow_gnu_debugaltlink (bfd *abfd, const char *dir) { return find_separate_debug_file (abfd, dir, - bfd_get_alt_debug_link_info, + get_alt_debug_link_info_shim, separate_alt_debug_file_exists); } diff --git a/gdb/ChangeLog b/gdb/ChangeLog index de5db77..5f964d1 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,16 @@ +2013-10-08 Tom Tromey <tromey@redhat.com> + + * Makefile.in (SFILES): Add build-id.c. + (HFILES_NO_SRCDIR): Add build-id.h. + * build-id.c: New file, largely from elfread.c. Modified + most functions. + * build-id.h: New file. + * dwarf2read.c (dwarf2_get_dwz_file): Update for change to + bfd_get_alt_debug_link_info. Verify dwz file's build-id. + Search for dwz file using build-id. + * elfread.c (build_id_bfd_get, build_id_verify) + (build_id_to_debug_filename, find_separate_debug_file): Remove. + 2013-10-08 Joel Brobecker <brobecker@adacore.com> * ada-lang.c (compare_names_with_case): Renamed from diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 6b8927a..2aa8134 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -717,7 +717,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \ bfd-target.c \ block.c blockframe.c \ breakpoint.c break-catch-sig.c break-catch-throw.c \ - buildsym.c \ + build-id.c buildsym.c \ c-exp.y c-lang.c c-typeprint.c c-valprint.c \ charset.c cleanups.c cli-out.c coffread.c coff-pe-read.c \ complaints.c completer.c continuations.c corefile.c corelow.c \ @@ -814,7 +814,8 @@ tui/tui-file.h tui/tui-command.h tui/tui-disasm.h tui/tui-wingeneral.h \ tui/tui-windata.h tui/tui-data.h tui/tui-win.h tui/tui-stack.h \ tui/tui-winsource.h tui/tui-regs.h tui/tui-io.h tui/tui-layout.h \ tui/tui-source.h sol2-tdep.h gregset.h sh-tdep.h sh64-tdep.h \ -expression.h score-tdep.h gdb_select.h ser-tcp.h buildsym.h valprint.h \ +expression.h score-tdep.h gdb_select.h ser-tcp.h \ +build-id.h buildsym.h valprint.h \ typeprint.h mi/mi-getopt.h mi/mi-parse.h mi/mi-console.h \ mi/mi-out.h mi/mi-main.h mi/mi-common.h mi/mi-cmds.h linux-nat.h \ complaints.h gdb_proc_service.h gdb_regex.h xtensa-tdep.h inf-loop.h \ @@ -911,7 +912,8 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \ event-loop.o event-top.o inf-loop.o completer.o \ gdbarch.o arch-utils.o gdbtypes.o gdb_bfd.o gdb_obstack.o \ osabi.o copying.o \ - memattr.o mem-break.o target.o parse.o language.o buildsym.o \ + memattr.o mem-break.o target.o parse.o language.o \ + build-id.o buildsym.o \ findcmd.o \ std-regs.o \ signals.o \ diff --git a/gdb/build-id.c b/gdb/build-id.c new file mode 100644 index 0000000..330ed18 --- /dev/null +++ b/gdb/build-id.c @@ -0,0 +1,168 @@ +/* build-id-related functions. + + Copyright (C) 1991-2013 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 "defs.h" +#include "bfd.h" +#include "elf-bfd.h" +#include "gdb_bfd.h" +#include "build-id.h" +#include "gdb_string.h" +#include "gdb_vecs.h" +#include "symfile.h" +#include "objfiles.h" +#include "filenames.h" + +/* Locate NT_GNU_BUILD_ID from ABFD and return its content. */ + +static const struct elf_build_id * +build_id_bfd_get (bfd *abfd) +{ + if (!bfd_check_format (abfd, bfd_object) + || bfd_get_flavour (abfd) != bfd_target_elf_flavour + /* Although this is ELF_specific, it is safe to do in generic + code because it does not rely on any ELF-specific symbols at + link time, and if the ELF code is not available in BFD, then + ABFD will not have the ELF flavour. */ + || elf_tdata (abfd)->build_id == NULL) + return NULL; + + return elf_tdata (abfd)->build_id; +} + +/* See build-id.h. */ + +int +build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check) +{ + const struct elf_build_id *found; + int retval = 0; + + found = build_id_bfd_get (abfd); + + if (found == NULL) + warning (_("File \"%s\" has no build-id, file skipped"), + bfd_get_filename (abfd)); + else if (found->size != check_len + || memcmp (found->data, check, found->size) != 0) + warning (_("File \"%s\" has a different build-id, file skipped"), + bfd_get_filename (abfd)); + else + retval = 1; + + return retval; +} + +/* See build-id.h. */ + +bfd * +build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id) +{ + char *link, *debugdir; + VEC (char_ptr) *debugdir_vec; + struct cleanup *back_to; + int ix; + bfd *abfd = NULL; + + /* DEBUG_FILE_DIRECTORY/.build-id/ab/cdef */ + link = alloca (strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1 + + 2 * build_id_len + (sizeof ".debug" - 1) + 1); + + /* Keep backward compatibility so that DEBUG_FILE_DIRECTORY being "" will + cause "/.build-id/..." lookups. */ + + debugdir_vec = dirnames_to_char_ptr_vec (debug_file_directory); + back_to = make_cleanup_free_char_ptr_vec (debugdir_vec); + + for (ix = 0; VEC_iterate (char_ptr, debugdir_vec, ix, debugdir); ++ix) + { + size_t debugdir_len = strlen (debugdir); + const gdb_byte *data = build_id; + size_t size = build_id_len; + char *s; + char *filename = NULL; + + memcpy (link, debugdir, debugdir_len); + s = &link[debugdir_len]; + s += sprintf (s, "/.build-id/"); + if (size > 0) + { + size--; + s += sprintf (s, "%02x", (unsigned) *data++); + } + if (size > 0) + *s++ = '/'; + while (size-- > 0) + s += sprintf (s, "%02x", (unsigned) *data++); + strcpy (s, ".debug"); + + /* lrealpath() is expensive even for the usually non-existent files. */ + if (access (link, F_OK) == 0) + filename = lrealpath (link); + + if (filename == NULL) + continue; + + /* We expect to be silent on the non-existing files. */ + abfd = gdb_bfd_open_maybe_remote (filename); + if (abfd == NULL) + continue; + + if (build_id_verify (abfd, build_id_len, build_id)) + break; + + gdb_bfd_unref (abfd); + abfd = NULL; + } + + do_cleanups (back_to); + return abfd; +} + +/* See build-id.h. */ + +char * +find_separate_debug_file_by_buildid (struct objfile *objfile) +{ + const struct elf_build_id *build_id; + + build_id = build_id_bfd_get (objfile->obfd); + if (build_id != NULL) + { + bfd *abfd; + + abfd = build_id_to_debug_bfd (build_id->size, build_id->data); + /* Prevent looping on a stripped .debug file. */ + if (abfd != NULL + && filename_cmp (bfd_get_filename (abfd), + objfile_name (objfile)) == 0) + { + warning (_("\"%s\": separate debug info file has no debug info"), + bfd_get_filename (abfd)); + gdb_bfd_unref (abfd); + } + else if (abfd != NULL) + { + char *result = xstrdup (bfd_get_filename (abfd)); + + gdb_bfd_unref (abfd); + return result; + } + } + return NULL; +} diff --git a/gdb/build-id.h b/gdb/build-id.h new file mode 100644 index 0000000..b3ea4fb --- /dev/null +++ b/gdb/build-id.h @@ -0,0 +1,44 @@ +/* build-id-related functions. + + Copyright (C) 1991-2013 Free Software Foundation, Inc. + + This file is part of GDB. + + 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/>. */ + +#ifndef BUILD_ID_H +#define BUILD_ID_H + +/* Return true if ABFD has NT_GNU_BUILD_ID matching the CHECK value. + Otherwise, issue a warning and return false. */ + +extern int build_id_verify (bfd *abfd, + size_t check_len, const bfd_byte *check); + + +/* Find and open a BFD given a build-id. If no BFD can be found, + return NULL. The returned reference to the BFD must be released by + the caller. */ + +extern bfd *build_id_to_debug_bfd (size_t build_id_len, + const bfd_byte *build_id); + +/* Find the separate debug file for OBJFILE, by using the build-id + associated with OBJFILE's BFD. If successful, returns a malloc'd + file name for the separate debug file. The caller must free this. + Otherwise, returns NULL. */ + +extern char *find_separate_debug_file_by_buildid (struct objfile *objfile); + +#endif /* BUILD_ID_H */ diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index 5e2ace7..4cb66db 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -69,6 +69,7 @@ #include "f-lang.h" #include "source.h" #include "filestuff.h" +#include "build-id.h" #include <fcntl.h> #include "gdb_string.h" @@ -2364,14 +2365,15 @@ dwarf2_get_dwz_file (void) struct cleanup *cleanup; const char *filename; struct dwz_file *result; - unsigned long buildid; + size_t buildid_len; + bfd_byte *buildid; if (dwarf2_per_objfile->dwz_file != NULL) return dwarf2_per_objfile->dwz_file; bfd_set_error (bfd_error_no_error); data = bfd_get_alt_debug_link_info (dwarf2_per_objfile->objfile->obfd, - &buildid); + &buildid_len, &buildid); if (data == NULL) { if (bfd_get_error () == bfd_error_no_error) @@ -2380,6 +2382,7 @@ dwarf2_get_dwz_file (void) bfd_errmsg (bfd_get_error ())); } cleanup = make_cleanup (xfree, data); + make_cleanup (xfree, buildid); filename = (const char *) data; if (!IS_ABSOLUTE_PATH (filename)) @@ -2396,20 +2399,25 @@ dwarf2_get_dwz_file (void) filename = rel; } - /* The format is just a NUL-terminated file name, followed by the - build-id. For now, though, we ignore the build-id. */ + /* First try the file name given in the section. If that doesn't + work, try to use the build-id instead. */ dwz_bfd = gdb_bfd_open (filename, gnutarget, -1); - if (dwz_bfd == NULL) - error (_("could not read '%s': %s"), filename, - bfd_errmsg (bfd_get_error ())); - - if (!bfd_check_format (dwz_bfd, bfd_object)) + if (dwz_bfd != NULL) { - gdb_bfd_unref (dwz_bfd); - error (_("file '%s' was not usable: %s"), filename, - bfd_errmsg (bfd_get_error ())); + if (!build_id_verify (dwz_bfd, buildid_len, buildid)) + { + gdb_bfd_unref (dwz_bfd); + dwz_bfd = NULL; + } } + if (dwz_bfd == NULL) + dwz_bfd = build_id_to_debug_bfd (buildid_len, buildid); + + if (dwz_bfd == NULL) + error (_("could not find '.gnu_debugaltlink' file for %s"), + objfile_name (dwarf2_per_objfile->objfile)); + result = OBSTACK_ZALLOC (&dwarf2_per_objfile->objfile->objfile_obstack, struct dwz_file); result->dwz_bfd = dwz_bfd; diff --git a/gdb/elfread.c b/gdb/elfread.c index 4a3d713..0095ad9 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -45,6 +45,7 @@ #include "regcache.h" #include "bcache.h" #include "gdb_bfd.h" +#include "build-id.h" extern void _initialize_elfread (void); @@ -1087,131 +1088,6 @@ elf_gnu_ifunc_resolver_return_stop (struct breakpoint *b) update_breakpoint_locations (b, sals, sals_end); } -/* Locate NT_GNU_BUILD_ID from ABFD and return its content. */ - -static const struct elf_build_id * -build_id_bfd_get (bfd *abfd) -{ - if (!bfd_check_format (abfd, bfd_object) - || bfd_get_flavour (abfd) != bfd_target_elf_flavour - || elf_tdata (abfd)->build_id == NULL) - return NULL; - - return elf_tdata (abfd)->build_id; -} - -/* Return if FILENAME has NT_GNU_BUILD_ID matching the CHECK value. */ - -static int -build_id_verify (const char *filename, const struct elf_build_id *check) -{ - bfd *abfd; - const struct elf_build_id *found; - int retval = 0; - - /* We expect to be silent on the non-existing files. */ - abfd = gdb_bfd_open_maybe_remote (filename); - if (abfd == NULL) - return 0; - - found = build_id_bfd_get (abfd); - - if (found == NULL) - warning (_("File \"%s\" has no build-id, file skipped"), filename); - else if (found->size != check->size - || memcmp (found->data, check->data, found->size) != 0) - warning (_("File \"%s\" has a different build-id, file skipped"), - filename); - else - retval = 1; - - gdb_bfd_unref (abfd); - - return retval; -} - -static char * -build_id_to_debug_filename (const struct elf_build_id *build_id) -{ - char *link, *debugdir, *retval = NULL; - VEC (char_ptr) *debugdir_vec; - struct cleanup *back_to; - int ix; - - /* DEBUG_FILE_DIRECTORY/.build-id/ab/cdef */ - link = alloca (strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1 - + 2 * build_id->size + (sizeof ".debug" - 1) + 1); - - /* Keep backward compatibility so that DEBUG_FILE_DIRECTORY being "" will - cause "/.build-id/..." lookups. */ - - debugdir_vec = dirnames_to_char_ptr_vec (debug_file_directory); - back_to = make_cleanup_free_char_ptr_vec (debugdir_vec); - - for (ix = 0; VEC_iterate (char_ptr, debugdir_vec, ix, debugdir); ++ix) - { - size_t debugdir_len = strlen (debugdir); - const gdb_byte *data = build_id->data; - size_t size = build_id->size; - char *s; - - memcpy (link, debugdir, debugdir_len); - s = &link[debugdir_len]; - s += sprintf (s, "/.build-id/"); - if (size > 0) - { - size--; - s += sprintf (s, "%02x", (unsigned) *data++); - } - if (size > 0) - *s++ = '/'; - while (size-- > 0) - s += sprintf (s, "%02x", (unsigned) *data++); - strcpy (s, ".debug"); - - /* lrealpath() is expensive even for the usually non-existent files. */ - if (access (link, F_OK) == 0) - retval = lrealpath (link); - - if (retval != NULL && !build_id_verify (retval, build_id)) - { - xfree (retval); - retval = NULL; - } - - if (retval != NULL) - break; - } - - do_cleanups (back_to); - return retval; -} - -static char * -find_separate_debug_file_by_buildid (struct objfile *objfile) -{ - const struct elf_build_id *build_id; - - build_id = build_id_bfd_get (objfile->obfd); - if (build_id != NULL) - { - char *build_id_name; - - build_id_name = build_id_to_debug_filename (build_id); - /* Prevent looping on a stripped .debug file. */ - if (build_id_name != NULL - && filename_cmp (build_id_name, objfile_name (objfile)) == 0) - { - warning (_("\"%s\": separate debug info file has no debug info"), - build_id_name); - xfree (build_id_name); - } - else if (build_id_name != NULL) - return build_id_name; - } - return NULL; -} - /* Scan and build partial symbols for a symbol file. We have been initialized by a call to elf_symfile_init, which currently does nothing. diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 4c15ae8..3e5e970 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2013-10-08 Tom Tromey <tromey@redhat.com> + + * gdb.dwarf2/dwzbuildid.exp: New file. + * lib/dwarf.exp (Dwarf::_section): Add "flags" and "type" + parameters. + (Dwarf::_defer_output): Change "section" parameter to + "section_spec"; update. + (Dwarf::gnu_debugaltlink, Dwarf::_note, Dwarf::build_id): New + procs. + 2013-10-08 Joel Brobecker <brobecker@adacore.com> * gdb.ada/mi_catch_ex.exp: Make "mi_execute_to" test names unique. diff --git a/gdb/testsuite/gdb.dwarf2/dwzbuildid.exp b/gdb/testsuite/gdb.dwarf2/dwzbuildid.exp new file mode 100644 index 0000000..e6ae881 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dwzbuildid.exp @@ -0,0 +1,170 @@ +# Copyright 2013 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/>. + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +# No remote host testing either. +if {[is_remote host]} { + return 0 +} + + +# Lots of source files since we test a few cases and make new files +# for each. +# The tests are: +# ok - the main file refers to a dwz and the buildids match +# mismatch - the buildids do not match +# fallback - the buildids do not match but a match is found via buildid +standard_testfile main.c \ + dwzbuildid-ok-base.S dwzbuildid-ok-sep.S \ + dwzbuildid-mismatch-base.S dwzbuildid-mismatch-sep.S \ + dwzbuildid-fallback-base.S dwzbuildid-fallback-sep.S \ + dwzbuildid-fallback-ok.S + +# Write some assembly that just has a .gnu_debugaltlink section. +proc write_just_debugaltlink {filename dwzname buildid} { + set asm_file [standard_output_file $filename] + + Dwarf::assemble $asm_file { + upvar dwzname dwzname + upvar buildid buildid + + gnu_debugaltlink $dwzname $buildid + + # Only the DWARF reader checks .gnu_debugaltlink, so make sure + # there is a bit of DWARF in here. + cu {} { + compile_unit {{language @DW_LANG_C}} { + } + } + } +} + +# Write some DWARF that also sets the buildid. +proc write_dwarf_file {filename buildid {value 99}} { + set asm_file [standard_output_file $filename] + + Dwarf::assemble $asm_file { + declare_labels partial_label double_label int_label int_label2 + + upvar buildid buildid + upvar value value + + build_id $buildid + + cu {} { + compile_unit {{language @DW_LANG_C}} { + int_label2: base_type { + {name int} + {byte_size 4 sdata} + {encoding @DW_ATE_signed} + } + + constant { + {name the_int} + {type :$int_label2} + {const_value $value data1} + } + } + } + } +} + +if { [gdb_compile ${srcdir}/${subdir}/${srcfile} ${binfile}1.o \ + object {nodebug}] != "" } { + return -1 +} + +# The values don't really matter, just whether they are equal. +set ok_prefix 01 +set ok_suffix 0203040506 +set ok_suffix2 02030405ff +set ok_buildid ${ok_prefix}${ok_suffix} +set ok_buildid2 ${ok_prefix}${ok_suffix2} +set bad_buildid ffffffffffff + +set outdir [standard_output_file {}] +set basedir $outdir/.build-id +file mkdir $basedir $basedir/$ok_prefix + +# Test where the separate debuginfo's buildid matches. +write_just_debugaltlink $srcfile2 ${binfile}3.o $ok_buildid +write_dwarf_file $srcfile3 $ok_buildid + +# Test where the separate debuginfo's buildid does not match. +write_just_debugaltlink $srcfile4 ${binfile}5.o $ok_buildid +write_dwarf_file $srcfile5 $bad_buildid + +# Test where the separate debuginfo's buildid does not match, but then +# we find a match in the .build-id directory. +write_just_debugaltlink $srcfile6 ${binfile}7.o $ok_buildid2 +# Use 77 as the value so that if we load the bad debuginfo, we will +# see the wrong result. +write_dwarf_file $srcfile7 $bad_buildid 77 +write_dwarf_file $srcfile8 $ok_buildid2 + +# Compile everything. +for {set i 2} {$i <= 8} {incr i} { + if {[gdb_compile [standard_output_file [set srcfile$i]] \ + ${binfile}$i.o object nodebug] != ""} { + return -1 + } +} + +# Copy a file into the .build-id place for the "fallback" test. +file copy -force -- ${binfile}8.o $basedir/$ok_prefix/$ok_suffix2.debug + +# Link the executables. +if {[gdb_compile [list ${binfile}1.o ${binfile}2.o] ${binfile}-ok \ + executable {}] != ""} { + return -1 +} + +if {[gdb_compile [list ${binfile}1.o ${binfile}4.o] ${binfile}-mismatch \ + executable {}] != ""} { + return -1 +} + +if {[gdb_compile [list ${binfile}1.o ${binfile}6.o] ${binfile}-fallback \ + executable {}] != ""} { + return -1 +} + + +foreach testname {ok mismatch fallback} { + with_test_prefix $testname { + gdb_exit + gdb_start + gdb_reinitialize_dir $srcdir/$subdir + + gdb_test_no_output "set debug-file-directory $outdir" + + gdb_load ${binfile}-${testname} + + if {[runto_main]} { + if {$testname == "mismatch"} { + gdb_test "print the_int" \ + "No symbol table is loaded.*" + } else { + gdb_test "print the_int" " = 99" + } + } + } +} diff --git a/gdb/testsuite/lib/dwarf.exp b/gdb/testsuite/lib/dwarf.exp index 5264def..c28b986 100644 --- a/gdb/testsuite/lib/dwarf.exp +++ b/gdb/testsuite/lib/dwarf.exp @@ -523,20 +523,27 @@ namespace eval Dwarf { } } - proc _section {name} { - _emit " .section $name" + proc _section {name {flags ""} {type ""}} { + if {$flags == "" && $type == ""} { + _emit " .section $name" + } elseif {$type == ""} { + _emit " .section $name, \"$flags\"" + } else { + _emit " .section $name, \"$flags\", %$type" + } } - proc _defer_output {section body} { + # SECTION_SPEC is a list of arguments to _section. + proc _defer_output {section_spec body} { variable _defer variable _deferred_output set old_defer $_defer - set _defer $section + set _defer [lindex $section_spec 0] if {![info exists _deferred_output($_defer)]} { set _deferred_output($_defer) "" - _section $section + eval _section $section_spec } uplevel $body @@ -948,6 +955,51 @@ namespace eval Dwarf { unset the_array(_) } + # Emit a .gnu_debugaltlink section with the given file name and + # build-id. The buildid should be represented as a hexadecimal + # string, like "ffeeddcc". + proc gnu_debugaltlink {filename buildid} { + _defer_output .gnu_debugaltlink { + _op .ascii [_quote $filename] + foreach {a b} [split $buildid {}] { + _op .byte 0x$a$b + } + } + } + + proc _note {type name hexdata} { + set namelen [expr [string length $name] + 1] + + # Name size. + _op .4byte $namelen + # Data size. + _op .4byte [expr [string length $hexdata] / 2] + # Type. + _op .4byte $type + # The name. + _op .ascii [_quote $name] + # Alignment. + set align 2 + set total [expr {($namelen + (1 << $align) - 1) & (-1 << $align)}] + for {set i $namelen} {$i < $total} {incr i} { + _op .byte 0 + } + # The data. + foreach {a b} [split $hexdata {}] { + _op .byte 0x$a$b + } + } + + # Emit a note section holding the given build-id. + proc build_id {buildid} { + _defer_output {.note.gnu.build-id a note} { + # From elf/common.h. + set NT_GNU_BUILD_ID 3 + + _note $NT_GNU_BUILD_ID GNU $buildid + } + } + # The top-level interface to the DWARF assembler. # FILENAME is the name of the file where the generated assembly # code is written. |