public inbox for binutils-cvs@sourceware.org
 help / color / mirror / Atom feed
* [binutils-gdb] Add debuginfod support for objdump -S
@ 2022-09-06 14:54 Aaron Merey
  0 siblings, 0 replies; only message in thread
From: Aaron Merey @ 2022-09-06 14:54 UTC (permalink / raw)
  To: bfd-cvs

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

commit d647c797b7386dcaca5984a3fbe9fba469771737
Author: Aaron Merey <amerey@redhat.com>
Date:   Fri Sep 2 19:01:56 2022 -0400

    Add debuginfod support for objdump -S
    
    Currently objdump -S is not able to make use files downloaded from debuginfod.
    This is due to bfd_find_nearest_line_discriminator being unable to locate any
    separate debuginfo files in the debuginfod cache. Additionally objdump lacked
    a call to debuginfod_find_source in order to download missing source files.
    
    Fix this by using bfd_find_nearest_line_with_alt instead of
    bfd_find_nearest_line_discriminator. Also add a call to
    debuginfod_find_source in order to download missing source files.
    
    Co-authored-by: Nick Clifton <nickc@redhat.com>

Diff:
---
 binutils/ChangeLog |  13 +++
 binutils/objdump.c | 252 ++++++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 224 insertions(+), 41 deletions(-)

diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index b5711097d50..cfb6417b55e 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -1,3 +1,16 @@
+2022-09-02  Aaron Merey  <amerey@redhat.com>
+
+	PR 29075
+	* objdump.c (find_separate_debug): New function. Finds the bfd
+	corresponding to the separate debuginfod of a given bfd.
+	(find_alt_debug): New function. Finds the bfd corresponding to the
+	.gnu_debugaltlink of a given bfd.
+	(slurp_file): Add bfd parameter. If a source file cannot be found
+	attempt to download it from debuginfod, if enabled.
+	(try_print_file_open): Add bfd parameter and pass it to slurp_file.
+	(show_line): If debuginfod is enabled, call
+	bfd_find_nearest_line_with_alt instead of bfd_find_nearest_line.
+
 2022-09-01  Nick Clifton  <nickc@redhat.com>
 
 	PR 29534
diff --git a/binutils/objdump.c b/binutils/objdump.c
index b34df5392b9..d34f269b406 100644
--- a/binutils/objdump.c
+++ b/binutils/objdump.c
@@ -72,6 +72,10 @@
 #include <sys/mman.h>
 #endif
 
+#ifdef HAVE_LIBDEBUGINFOD
+#include <elfutils/debuginfod.h>
+#endif
+
 /* Internal headers for the ELF .stab-dump code - sorry.  */
 #define	BYTES_IN_WORD	32
 #include "aout/aout64.h"
@@ -1735,28 +1739,174 @@ static struct print_file_list *print_files;
 
 #define SHOW_PRECEDING_CONTEXT_LINES (5)
 
-/* Read a complete file into memory.  */
+#if HAVE_LIBDEBUGINFOD
+/* Return a hex string represention of the build-id.  */
+
+unsigned char *
+get_build_id (void * data)
+{
+  unsigned i;
+  char * build_id_str;
+  bfd * abfd = (bfd *) data;
+  const struct bfd_build_id * build_id;
+
+  build_id = abfd->build_id;
+  if (build_id == NULL)
+    return NULL;
+
+  build_id_str = malloc (build_id->size * 2 + 1);
+  if (build_id_str == NULL)
+    return NULL;
+
+  for (i = 0; i < build_id->size; i++)
+    sprintf (build_id_str + (i * 2), "%02x", build_id->data[i]);
+  build_id_str[build_id->size * 2] = '\0';
+
+  return (unsigned char *) build_id_str;
+}
+
+/* Search for a separate debug file matching ABFD's build-id.  */
+
+static bfd *
+find_separate_debug (const bfd * abfd)
+{
+  const struct bfd_build_id * build_id = abfd->build_id;
+  separate_info * i = first_separate_info;
+
+  if (build_id == NULL || i == NULL)
+    return NULL;
+
+  while (i != NULL)
+    {
+      const bfd * i_bfd = (bfd *) i->handle;
+
+      if (abfd != NULL && i_bfd->build_id != NULL)
+	{
+	  const unsigned char * data = i_bfd->build_id->data;
+	  size_t size = i_bfd->build_id->size;
+
+	  if (size == build_id->size
+	      && memcmp (data, build_id->data, size) == 0)
+	    return (bfd *) i->handle;
+	}
+
+      i = i->next;
+    }
+
+  return NULL;
+}
+
+/* Search for a separate debug file matching ABFD's .gnu_debugaltlink
+    build-id.  */
+
+static bfd *
+find_alt_debug (const bfd * abfd)
+{
+  size_t namelen;
+  size_t id_len;
+  const char * name;
+  struct dwarf_section * section;
+  const struct bfd_build_id * build_id = abfd->build_id;
+  separate_info * i = first_separate_info;
+
+  if (i == NULL
+      || build_id == NULL
+      || !load_debug_section (gnu_debugaltlink, (void *) abfd))
+    return NULL;
+
+  section = &debug_displays[gnu_debugaltlink].section;
+  if (section == NULL)
+    return NULL;
+
+  name = (const char *) section->start;
+  namelen = strnlen (name, section->size) + 1;
+  if (namelen == 1)
+    return NULL;
+  if (namelen >= section->size)
+    return NULL;
+
+  id_len = section->size - namelen;
+  if (id_len < 0x14)
+    return NULL;
+
+  /* Compare the .gnu_debugaltlink build-id with the build-ids of the
+     known separate_info files.  */
+  while (i != NULL)
+    {
+      const bfd * i_bfd = (bfd *) i->handle;
+
+      if (i_bfd != NULL && i_bfd->build_id != NULL)
+	{
+	  const unsigned char * data = i_bfd->build_id->data;
+	  size_t size = i_bfd->build_id->size;
+
+	  if (id_len == size
+	      && memcmp (section->start + namelen, data, size) == 0)
+	    return (bfd *) i->handle;
+	}
+
+      i = i->next;
+    }
+
+  return NULL;
+}
+
+#endif /* HAVE_LIBDEBUGINFOD */
+
+/* Reads the contents of file FN into memory.  Returns a pointer to the buffer.
+   Also returns the size of the buffer in SIZE_RETURN and a filled out
+   stat structure in FST_RETURN.  Returns NULL upon failure.  */
 
 static const char *
-slurp_file (const char *fn, size_t *size, struct stat *fst)
+slurp_file (const char *   fn,
+	    size_t *       size_return,
+	    struct stat *  fst_return,
+	    bfd *          abfd ATTRIBUTE_UNUSED)
 {
 #ifdef HAVE_MMAP
-  int ps = getpagesize ();
+  int ps;
   size_t msize;
 #endif
   const char *map;
-  int fd = open (fn, O_RDONLY | O_BINARY);
+  int fd;
+
+  /* Paranoia.  */
+  if (fn == NULL || * fn == 0 || size_return == NULL || fst_return == NULL)
+    return NULL;
+
+  fd = open (fn, O_RDONLY | O_BINARY);
+
+#if HAVE_LIBDEBUGINFOD
+  if (fd < 0 && use_debuginfod && fn[0] == '/' && abfd != NULL)
+    {
+      unsigned char * build_id;
+      debuginfod_client * client;
+
+      client = debuginfod_begin ();
+      if (client == NULL)
+	return NULL;
+
+      build_id = get_build_id (abfd);
+      fd = debuginfod_find_source (client, build_id, 0, fn, NULL);
+      free (build_id);
+      debuginfod_end (client);
+    }
+#endif
 
   if (fd < 0)
     return NULL;
-  if (fstat (fd, fst) < 0)
+
+  if (fstat (fd, fst_return) < 0)
     {
       close (fd);
       return NULL;
     }
-  *size = fst->st_size;
+
+  *size_return = fst_return->st_size;
+
 #ifdef HAVE_MMAP
-  msize = (*size + ps - 1) & ~(ps - 1);
+  ps = getpagesize ();
+  msize = (*size_return + ps - 1) & ~(ps - 1);
   map = mmap (NULL, msize, PROT_READ, MAP_SHARED, fd, 0);
   if (map != (char *) -1L)
     {
@@ -1764,8 +1914,9 @@ slurp_file (const char *fn, size_t *size, struct stat *fst)
       return map;
     }
 #endif
-  map = (const char *) malloc (*size);
-  if (!map || (size_t) read (fd, (char *) map, *size) != *size)
+
+  map = (const char *) malloc (*size_return);
+  if (!map || (size_t) read (fd, (char *) map, *size_return) != *size_return)
     {
       free ((void *) map);
       map = NULL;
@@ -1831,16 +1982,20 @@ index_file (const char *map, size_t size, unsigned int *maxline)
 }
 
 /* Tries to open MODNAME, and if successful adds a node to print_files
-   linked list and returns that node.  Returns NULL on failure.  */
+   linked list and returns that node.  Also fills in the stat structure
+   pointed to by FST_RETURN.  Returns NULL on failure.  */
 
 static struct print_file_list *
-try_print_file_open (const char *origname, const char *modname, struct stat *fst)
+try_print_file_open (const char *   origname,
+		     const char *   modname,
+		     struct stat *  fst_return,
+		     bfd *          abfd)
 {
   struct print_file_list *p;
 
   p = (struct print_file_list *) xmalloc (sizeof (struct print_file_list));
 
-  p->map = slurp_file (modname, &p->mapsize, fst);
+  p->map = slurp_file (modname, &p->mapsize, fst_return, abfd);
   if (p->map == NULL)
     {
       free (p);
@@ -1870,7 +2025,7 @@ update_source_path (const char *filename, bfd *abfd)
   struct stat fst;
   int i;
 
-  p = try_print_file_open (filename, filename, &fst);
+  p = try_print_file_open (filename, filename, &fst, abfd);
   if (p == NULL)
     {
       if (include_path_count == 0)
@@ -1886,7 +2041,7 @@ update_source_path (const char *filename, bfd *abfd)
 	  char *modname = concat (include_paths[i], "/", fname,
 				  (const char *) 0);
 
-	  p = try_print_file_open (filename, modname, &fst);
+	  p = try_print_file_open (filename, modname, &fst, abfd);
 	  if (p)
 	    break;
 
@@ -1956,10 +2111,52 @@ show_line (bfd *abfd, asection *section, bfd_vma addr_offset)
   if (! with_line_numbers && ! with_source_code)
     return;
 
+#ifdef HAVE_LIBDEBUGINFOD
+  {
+    bfd *debug_bfd;
+    const char *alt_filename = NULL;
+
+    if (use_debuginfod)
+      {
+	bfd *alt_bfd;
+
+	/* PR 29075: Check for separate debuginfo and .gnu_debugaltlink files.
+	   They need to be passed to bfd_find_nearest_line_with_alt in case they
+	   were downloaded from debuginfod.  Otherwise libbfd will attempt to
+	   search for them and fail to locate them.  */
+	debug_bfd = find_separate_debug (abfd);
+	if (debug_bfd == NULL)
+	  debug_bfd = abfd;
+
+	alt_bfd = find_alt_debug (debug_bfd);
+	if (alt_bfd != NULL)
+	  alt_filename = bfd_get_filename (alt_bfd);
+      }
+    else
+      debug_bfd = abfd;
+
+    bfd_set_error (bfd_error_no_error);
+    if (! bfd_find_nearest_line_with_alt (debug_bfd, alt_filename,
+					  section, syms,
+					  addr_offset, &filename,
+					  &functionname, &linenumber,
+					  &discriminator))
+      {
+	if (bfd_get_error () == bfd_error_no_error)
+	  return;
+	if (! bfd_find_nearest_line_discriminator (abfd, section, syms,
+						   addr_offset, &filename,
+						   &functionname, &linenumber,
+						   &discriminator))
+	  return;
+      }
+  }
+#else
   if (! bfd_find_nearest_line_discriminator (abfd, section, syms, addr_offset,
 					     &filename, &functionname,
 					     &linenumber, &discriminator))
     return;
+#endif
 
   if (filename != NULL && *filename == '\0')
     filename = NULL;
@@ -4136,33 +4333,6 @@ open_debug_file (const char * pathname)
   return data;
 }
 
-#if HAVE_LIBDEBUGINFOD
-/* Return a hex string represention of the build-id.  */
-
-unsigned char *
-get_build_id (void * data)
-{
-  unsigned i;
-  char * build_id_str;
-  bfd * abfd = (bfd *) data;
-  const struct bfd_build_id * build_id;
-
-  build_id = abfd->build_id;
-  if (build_id == NULL)
-    return NULL;
-
-  build_id_str = malloc (build_id->size * 2 + 1);
-  if (build_id_str == NULL)
-    return NULL;
-
-  for (i = 0; i < build_id->size; i++)
-    sprintf (build_id_str + (i * 2), "%02x", build_id->data[i]);
-  build_id_str[build_id->size * 2] = '\0';
-
-  return (unsigned char *)build_id_str;
-}
-#endif /* HAVE_LIBDEBUGINFOD */
-
 static void
 dump_dwarf_section (bfd *abfd, asection *section,
 		    void *arg)

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-09-06 14:54 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-06 14:54 [binutils-gdb] Add debuginfod support for objdump -S Aaron Merey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).