From 61ab1364c7efa3934e0ca62af444e6e6e34f219e Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 16 Dec 2021 14:05:40 +0000 Subject: When loading separate debug info files, also attempt to locate a file based upon the build-id. PR 28697 * dwarf.c (load_build_id_debug_file): New function. (try_build_id_prefix): New function. (check_for_and_load_links): Call load_build_id_debug_file. (debug_displays): Add entry for .note.gnu.build-id. * dwarf.h (enum dwarf_section_display_enum): Add note_gnu_build_id. * testsuite/binutils-all/debuginfod.exp (test_fetch_debuglink): Fix regexp for loads via debuglink section. --- binutils/ChangeLog | 12 +++ binutils/dwarf.c | 116 ++++++++++++++++++++++++- binutils/dwarf.h | 1 + binutils/testsuite/binutils-all/debuginfod.exp | 6 +- 4 files changed, 131 insertions(+), 4 deletions(-) (limited to 'binutils') diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 2bbcfcf..9ed85a9 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,15 @@ +2021-12-16 Nick Clifton + + PR 28697 + * dwarf.c (load_build_id_debug_file): New function. + (try_build_id_prefix): New function. + (check_for_and_load_links): Call load_build_id_debug_file. + (debug_displays): Add entry for .note.gnu.build-id. + * dwarf.h (enum dwarf_section_display_enum): Add + note_gnu_build_id. + * testsuite/binutils-all/debuginfod.exp (test_fetch_debuglink): + Fix regexp for loads via debuglink section. + 2021-12-03 Chenghua Xu * MAINTAINERS: Add myself and Zhensong Liu diff --git a/binutils/dwarf.c b/binutils/dwarf.c index eeef98d..12c5b0a 100644 --- a/binutils/dwarf.c +++ b/binutils/dwarf.c @@ -11292,6 +11292,117 @@ load_dwo_file (const char * main_filename, const char * name, const char * dir, return separate_handle; } +static void * +try_build_id_prefix (const char * prefix, char * filename, const unsigned char * data, unsigned long id_len) +{ + char * f = filename; + + f += sprintf (f, prefix); + f += sprintf (f, ".build-id/%02x/", (unsigned) *data++); + id_len --; + while (id_len --) + f += sprintf (f, "%02x", (unsigned) *data++); + f += sprintf (f, ".debug"); + + return open_debug_file (filename); +} + +/* Try to load a debug file based upon the build-id held in the .note.gnu.build-id section. */ + +static void +load_build_id_debug_file (const char * main_filename, void * main_file) +{ + if (! load_debug_section (note_gnu_build_id, main_file)) + return; /* No .note.gnu.build-id section. */ + + struct dwarf_section * section = & debug_displays [note_gnu_build_id].section; + if (section == NULL) + { + warn (_("Unable to load the .note.gnu.build-id section\n")); + return; + } + + if (section->start == NULL || section->size < 0x18) + { + warn (_(".note.gnu.build-id section is corrupt/empty\n")); + return; + } + + /* In theory we should extract the contents of the section into + a note structure and then check the fields. For now though + just use hard coded offsets instead: + + Field Bytes Contents + NSize 0...3 4 + DSize 4...7 8+ + Type 8..11 3 (NT_GNU_BUILD_ID) + Name 12.15 GNU\0 + Data 16.... */ + + /* FIXME: Check the name size, name and type fields. */ + + unsigned long build_id_size; + build_id_size = byte_get (section->start + 4, 4); + if (build_id_size < 8) + { + warn (_(".note.gnu.build-id data size is too small\n")); + return; + } + + if (build_id_size > (section->size - 16)) + { + warn (_(".note.gnu.build-id data size is too bug\n")); + return; + } + + char * filename; + filename = xmalloc (strlen (".build-id/") + + build_id_size * 2 + 2 + + strlen (".debug") + /* The next string should be the same as the longest + name found in the prefixes[] array below. */ + + strlen ("/usrlib64/debug/usr") + + 1); + void * handle; + + static const char * prefixes[] = + { + "", + ".debug/", + "/usr/lib/debug/", + "/usr/lib/debug/usr/", + "/usr/lib64/debug/", + "/usr/lib64/debug/usr" + }; + long unsigned int i; + + for (i = 0; i < ARRAY_SIZE (prefixes); i++) + { + handle = try_build_id_prefix (prefixes[i], filename, + section->start + 16, build_id_size); + if (handle != NULL) + break; + } + /* FIXME: TYhe BFD library also tries a global debugfile directory prefix. */ + if (handle == NULL) + { + /* Failed to find a debug file associated with the build-id. + This is not an error however, rather it just means that + the debug info has probably not been loaded on the system, + or that another method is being used to link to the debug + info. */ + free (filename); + return; + } + + printf (_("%s: Found build-id indexed debug file: %s\n\n"), + main_filename, filename); + + add_separate_debug_file (filename, handle); +} + +/* Try to load a debug file pointed to by the .debug_sup section. */ + static void load_debug_sup_file (const char * main_filename, void * file) { @@ -11409,6 +11520,8 @@ check_for_and_load_links (void * file, const char * filename) } load_debug_sup_file (filename, file); + + load_build_id_debug_file (filename, file); } /* Load the separate debug info file(s) attached to FILE, if any exist. @@ -11779,7 +11892,8 @@ struct dwarf_section_display debug_displays[] = /* Separate debug info files can containt their own .debug_str section, and this might be in *addition* to a .debug_str section already present in the main file. Hence we need to have two entries for .debug_str. */ - { { ".debug_str", ".zdebug_str", "", NO_ABBREVS }, display_debug_str, &do_debug_str, false }, + { { ".debug_str", ".zdebug_str", "", NO_ABBREVS }, display_debug_str, &do_debug_str, false }, + { { ".note.gnu.build-id", "", "", NO_ABBREVS }, display_debug_not_supported, NULL, false }, }; /* A static assertion. */ diff --git a/binutils/dwarf.h b/binutils/dwarf.h index dd4f4c8..1463d20 100644 --- a/binutils/dwarf.h +++ b/binutils/dwarf.h @@ -122,6 +122,7 @@ enum dwarf_section_display_enum gnu_debugaltlink, debug_sup, separate_debug_str, + note_gnu_build_id, max }; diff --git a/binutils/testsuite/binutils-all/debuginfod.exp b/binutils/testsuite/binutils-all/debuginfod.exp index caff955..514fa3d 100644 --- a/binutils/testsuite/binutils-all/debuginfod.exp +++ b/binutils/testsuite/binutils-all/debuginfod.exp @@ -161,10 +161,10 @@ proc test_fetch_debuglink { prog progargs } { set got [binutils_run $prog "$progargs tmpdir/testprog"] - if { [regexp ".*Found separate debug info file.*Contents\[^\n\]*loaded from\[^\n\]*$cache.*" $got] } { + if { [regexp ".*Found separate debug info file.*Contents\[^\n\]*loaded from\[^\n\]*" $got] } { pass "$test ($prog debuglink)" } else { - fail "$test ($prog debuglink)" + fail "$test ($prog did not find debuglink to cache $cache)" } } @@ -180,7 +180,7 @@ proc test_fetch_debugaltlink { prog progargs } { if { [regexp ".*Found separate debug info file\[^\n\]*$cache/$buildid" $got] } { pass "$test ($prog debugaltlink)" } else { - fail "$test ($prog debugaltlink)" + fail "$test ($prog could not load debugaltlink)" } } -- cgit v1.1