aboutsummaryrefslogtreecommitdiff
path: root/binutils/dwarf.c
diff options
context:
space:
mode:
authorAaron Merey <amerey@redhat.com>2020-01-09 13:19:20 +0000
committerNick Clifton <nickc@redhat.com>2020-01-09 13:19:20 +0000
commit301a9420d947da145884261ac31a7a52438c2894 (patch)
treefb30bb433561f4887f14f356b4802c400939ad7a /binutils/dwarf.c
parent40c75bc8b07abc5d5774ea1c439b69c96e7fd485 (diff)
downloadgdb-301a9420d947da145884261ac31a7a52438c2894.zip
gdb-301a9420d947da145884261ac31a7a52438c2894.tar.gz
gdb-301a9420d947da145884261ac31a7a52438c2894.tar.bz2
Add support for debuginfod to the binutils (disable by default, enabled via a configure time option).
debuginfod is a lightweight web service that indexes ELF/DWARF debugging resources by build-id and serves them over HTTP. This patch enables objdump and readelf to query debuginfod servers when they are otherwise not able to find separate debug files. Binutils can be built with debuginfod using the --with-debuginfod configure option. This requires that libdebuginfod be installed and found at configure time. debuginfod is packaged with elfutils, starting with version 0.178. For more information see https://sourceware.org/elfutils/. toplevel* config/debuginfod.m4: New file. Add macro AC_DEBUGINFOD. Adds new configure option --with-debuginfod. * configure: Regenerate. * configure.ac: Call AC_DEBUGINFOD. binutils* Makefile.am (readelf_LDADD, objdump_LDADD): Add libdebuginfod. * Makefile.in: Regenerate. * NEWS: Update. * config.in: Regenerate. * configure: Regenerate. * configure.ac: Call AC_DEBUGINFOD. * doc/Makefile.in: Regenerate. * doc/binutils.texi: Add section on using binutils with debuginfod. * dwarf.c (debuginfod_fetch_separate_debug_info): New function. Query debuginfod servers for the target debug file. (load_separate_debug_info): Call debuginfod_fetch_separate_debug_info if configured with debuginfod. (load_separate_debug_files): Add file argument to load_separate_debug_info calls. * dwarf.h (get_build_id): Add declaration. * objdump.c (get_build_id): New function. Get build-id of file. * readelf.c (get_build_id): Likewise. * testsuite/binutils-all/debuginfod.exp: New tests. * testsuite/binutils-all/linkdebug.s: Add .note.gnu.build-id section.
Diffstat (limited to 'binutils/dwarf.c')
-rw-r--r--binutils/dwarf.c110
1 files changed, 107 insertions, 3 deletions
diff --git a/binutils/dwarf.c b/binutils/dwarf.c
index 130ba10..9c96f47 100644
--- a/binutils/dwarf.c
+++ b/binutils/dwarf.c
@@ -32,6 +32,10 @@
#include "safe-ctype.h"
#include <assert.h>
+#ifdef HAVE_LIBDEBUGINFOD
+#include <elfutils/debuginfod.h>
+#endif
+
#undef MAX
#undef MIN
#define MAX(a, b) ((a) > (b) ? (a) : (b))
@@ -10128,12 +10132,83 @@ add_separate_debug_file (const char * filename, void * handle)
first_separate_info = i;
}
+#if HAVE_LIBDEBUGINFOD
+/* Query debuginfod servers for the target debuglink or debugaltlink
+ file. If successful, store the path of the file in filename and
+ return TRUE, otherwise return FALSE. */
+
+static bfd_boolean
+debuginfod_fetch_separate_debug_info (struct dwarf_section * section,
+ char ** filename,
+ void * file)
+{
+ size_t build_id_len;
+ unsigned char * build_id;
+
+ if (strcmp (section->uncompressed_name, ".gnu_debuglink") == 0)
+ {
+ /* Get the build-id of file. */
+ build_id = get_build_id (file);
+ build_id_len = 0;
+ }
+ else if (strcmp (section->uncompressed_name, ".gnu_debugaltlink") == 0)
+ {
+ /* Get the build-id of the debugaltlink file. */
+ unsigned int filelen;
+
+ filelen = strnlen ((const char *)section->start, section->size);
+ if (filelen == section->size)
+ /* Corrupt debugaltlink. */
+ return FALSE;
+
+ build_id = section->start + filelen + 1;
+ build_id_len = section->size - (filelen + 1);
+
+ if (build_id_len == 0)
+ return FALSE;
+ }
+ else
+ return FALSE;
+
+ if (build_id)
+ {
+ int fd;
+ debuginfod_client * client;
+
+ client = debuginfod_begin ();
+ if (client == NULL)
+ return FALSE;
+
+ /* Query debuginfod servers for the target file. If found its path
+ will be stored in filename. */
+ fd = debuginfod_find_debuginfo (client, build_id, build_id_len, filename);
+ debuginfod_end (client);
+
+ /* Only free build_id if we allocated space for a hex string
+ in get_build_id (). */
+ if (build_id_len == 0)
+ free (build_id);
+
+ if (fd >= 0)
+ {
+ /* File successfully retrieved. Close fd since we want to
+ use open_debug_file () on filename instead. */
+ close (fd);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+#endif
+
static void *
load_separate_debug_info (const char * main_filename,
struct dwarf_section * xlink,
parse_func_type parse_func,
check_func_type check_func,
- void * func_data)
+ void * func_data,
+ void * file ATTRIBUTE_UNUSED)
{
const char * separate_filename;
char * debug_filename;
@@ -10235,6 +10310,23 @@ load_separate_debug_info (const char * main_filename,
if (check_func (debug_filename, func_data))
goto found;
+#if HAVE_LIBDEBUGINFOD
+ {
+ char * tmp_filename;
+
+ if (debuginfod_fetch_separate_debug_info (xlink,
+ & tmp_filename,
+ file))
+ {
+ /* File successfully downloaded from server, replace
+ debug_filename with the file's path. */
+ free (debug_filename);
+ debug_filename = tmp_filename;
+ goto found;
+ }
+ }
+#endif
+
/* Failed to find the file. */
warn (_("could not find separate debug file '%s'\n"), separate_filename);
warn (_("tried: %s\n"), debug_filename);
@@ -10264,6 +10356,16 @@ load_separate_debug_info (const char * main_filename,
sprintf (debug_filename, "%s", separate_filename);
warn (_("tried: %s\n"), debug_filename);
+#if HAVE_LIBDEBUGINFOD
+ {
+ char *urls = getenv (DEBUGINFOD_URLS_ENV_VAR);
+ if (urls == NULL)
+ urls = "";
+
+ warn (_("tried: DEBUGINFOD_URLS=%s\n"), urls);
+ }
+#endif
+
free (canon_dir);
free (debug_filename);
return NULL;
@@ -10410,7 +10512,8 @@ load_separate_debug_files (void * file, const char * filename)
& debug_displays[gnu_debugaltlink].section,
parse_gnu_debugaltlink,
check_gnu_debugaltlink,
- & build_id_data);
+ & build_id_data,
+ file);
}
if (load_debug_section (gnu_debuglink, file))
@@ -10421,7 +10524,8 @@ load_separate_debug_files (void * file, const char * filename)
& debug_displays[gnu_debuglink].section,
parse_gnu_debuglink,
check_gnu_debuglink,
- & crc32);
+ & crc32,
+ file);
}
if (first_separate_info != NULL)