[binutils-gdb] When loading separate debug info files, also attempt to locate a file based upon the build-id.

Nick Clifton nickc@sourceware.org
Thu Dec 16 14:06:15 GMT 2021


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=61ab1364c7efa3934e0ca62af444e6e6e34f219e

commit 61ab1364c7efa3934e0ca62af444e6e6e34f219e
Author: Nick Clifton <nickc@redhat.com>
Date:   Thu Dec 16 14:05:40 2021 +0000

    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.

Diff:
---
 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(-)

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 2bbcfcf54f6..9ed85a93c53 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,15 @@
+2021-12-16  Nick Clifton  <nickc@redhat.com>
+
+	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  <xuchenghua@loongson.cn>
 
 	* MAINTAINERS: Add myself and Zhensong Liu
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index eeef98d4a18..12c5b0a8fa2 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 dd4f4c8251e..1463d2027a0 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 caff955db3e..514fa3d5b30 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)"
     }
 }


More information about the Binutils-cvs mailing list