When loading separate debug info files, also attempt to locate a file based upon...
authorNick Clifton <nickc@redhat.com>
Thu, 16 Dec 2021 14:05:40 +0000 (14:05 +0000)
committerNick Clifton <nickc@redhat.com>
Thu, 16 Dec 2021 14:05:40 +0000 (14:05 +0000)
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
binutils/dwarf.c
binutils/dwarf.h
binutils/testsuite/binutils-all/debuginfod.exp

index 2bbcfcf54f65839c8f617a672ed7c1a2e6832c16..9ed85a93c5333dfe48f88a913dbf0752d3d74795 100644 (file)
@@ -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
index eeef98d4a184728242493ae7b640c36f4384ff46..12c5b0a8fa29372783b8bbbe34c8d3bfc7f58c42 100644 (file)
@@ -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.  */
index dd4f4c8251e2f03eb2ae29c3a99f2d21cba06641..1463d2027a065f08b1d0931ec320b7cb572c32e4 100644 (file)
@@ -122,6 +122,7 @@ enum dwarf_section_display_enum
   gnu_debugaltlink,
   debug_sup,
   separate_debug_str,
+  note_gnu_build_id,
   max
 };
 
index caff955db3e4c743377ae4d3ed6eda393d35c0fd..514fa3d5b3059ad57c95d6db685134dd7c7b5b89 100644 (file)
@@ -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)"
     }
 }