diff options
-rw-r--r-- | binutils/Makefile.am | 6 | ||||
-rw-r--r-- | binutils/Makefile.in | 9 | ||||
-rw-r--r-- | binutils/NEWS | 9 | ||||
-rw-r--r-- | binutils/config.in | 3 | ||||
-rwxr-xr-x | binutils/configure | 184 | ||||
-rw-r--r-- | binutils/configure.ac | 3 | ||||
-rw-r--r-- | binutils/doc/Makefile.in | 5 | ||||
-rw-r--r-- | binutils/doc/binutils.texi | 18 | ||||
-rw-r--r-- | binutils/dwarf.c | 110 | ||||
-rw-r--r-- | binutils/dwarf.h | 4 | ||||
-rw-r--r-- | binutils/objdump.c | 27 | ||||
-rw-r--r-- | binutils/readelf.c | 132 | ||||
-rw-r--r-- | binutils/testsuite/binutils-all/linkdebug.s | 17 | ||||
-rw-r--r-- | config/debuginfod.m4 | 38 | ||||
-rwxr-xr-x | configure | 139 | ||||
-rw-r--r-- | configure.ac | 4 |
16 files changed, 647 insertions, 61 deletions
diff --git a/binutils/Makefile.am b/binutils/Makefile.am index cc23012..f1f3907 100644 --- a/binutils/Makefile.am +++ b/binutils/Makefile.am @@ -53,6 +53,8 @@ AM_CFLAGS = $(WARN_CFLAGS) $(ZLIBINC) AM_CFLAGS_FOR_BUILD = $(WARN_CFLAGS_FOR_BUILD) $(ZLIBINC) LIBICONV = @LIBICONV@ +LIBDEBUGINFOD = @LIBDEBUGINFOD@ + # these two are almost the same program AR_PROG=ar RANLIB_PROG=ranlib @@ -245,7 +247,7 @@ objcopy_SOURCES = objcopy.c not-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS) strings_SOURCES = strings.c $(BULIBS) readelf_SOURCES = readelf.c version.c unwind-ia64.c dwarf.c $(ELFLIBS) -readelf_LDADD = $(LIBINTL) $(LIBCTF_NOBFD) $(LIBIBERTY) $(ZLIB) +readelf_LDADD = $(LIBINTL) $(LIBCTF_NOBFD) $(LIBIBERTY) $(ZLIB) $(LIBDEBUGINFOD) elfedit_SOURCES = elfedit.c version.c $(ELFLIBS) elfedit_LDADD = $(LIBINTL) $(LIBIBERTY) @@ -256,7 +258,7 @@ nm_new_SOURCES = nm.c $(BULIBS) objdump_SOURCES = objdump.c dwarf.c prdbg.c $(DEBUG_SRCS) $(BULIBS) $(ELFLIBS) EXTRA_objdump_SOURCES = od-xcoff.c -objdump_LDADD = $(OBJDUMP_PRIVATE_OFILES) $(OPCODES) $(LIBCTF) $(BFDLIB) $(LIBIBERTY) $(LIBINTL) +objdump_LDADD = $(OBJDUMP_PRIVATE_OFILES) $(OPCODES) $(LIBCTF) $(BFDLIB) $(LIBIBERTY) $(LIBINTL) $(LIBDEBUGINFOD) objdump.@OBJEXT@:objdump.c if am__fastdepCC diff --git a/binutils/Makefile.in b/binutils/Makefile.in index 91dfe25..39f0856 100644 --- a/binutils/Makefile.in +++ b/binutils/Makefile.in @@ -138,7 +138,9 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \ $(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \ $(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \ $(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \ - $(top_srcdir)/../bfd/version.m4 $(top_srcdir)/configure.ac + $(top_srcdir)/../bfd/version.m4 \ + $(top_srcdir)/../config/debuginfod.m4 \ + $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ @@ -449,6 +451,7 @@ LDFLAGS = @LDFLAGS@ LEX = `if [ -f ../flex/flex ]; then echo ../flex/flex; else echo @LEX@; fi` LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBDEBUGINFOD = @LIBDEBUGINFOD@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBINTL_DEP = @LIBINTL_DEP@ @@ -706,14 +709,14 @@ size_SOURCES = size.c $(BULIBS) objcopy_SOURCES = objcopy.c not-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS) strings_SOURCES = strings.c $(BULIBS) readelf_SOURCES = readelf.c version.c unwind-ia64.c dwarf.c $(ELFLIBS) -readelf_LDADD = $(LIBINTL) $(LIBCTF_NOBFD) $(LIBIBERTY) $(ZLIB) +readelf_LDADD = $(LIBINTL) $(LIBCTF_NOBFD) $(LIBIBERTY) $(ZLIB) $(LIBDEBUGINFOD) elfedit_SOURCES = elfedit.c version.c $(ELFLIBS) elfedit_LDADD = $(LIBINTL) $(LIBIBERTY) strip_new_SOURCES = objcopy.c is-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS) nm_new_SOURCES = nm.c $(BULIBS) objdump_SOURCES = objdump.c dwarf.c prdbg.c $(DEBUG_SRCS) $(BULIBS) $(ELFLIBS) EXTRA_objdump_SOURCES = od-xcoff.c -objdump_LDADD = $(OBJDUMP_PRIVATE_OFILES) $(OPCODES) $(LIBCTF) $(BFDLIB) $(LIBIBERTY) $(LIBINTL) +objdump_LDADD = $(OBJDUMP_PRIVATE_OFILES) $(OPCODES) $(LIBCTF) $(BFDLIB) $(LIBIBERTY) $(LIBINTL) $(LIBDEBUGINFOD) cxxfilt_SOURCES = cxxfilt.c $(BULIBS) ar_SOURCES = arparse.y arlex.l ar.c not-ranlib.c arsup.c rename.c binemul.c \ emul_$(EMULATION).c $(BULIBS) diff --git a/binutils/NEWS b/binutils/NEWS index e5e0056..72a9644 100644 --- a/binutils/NEWS +++ b/binutils/NEWS @@ -1,5 +1,14 @@ -*- text -*- +* Binutils now supports debuginfod, an HTTP server for distributing + ELF/DWARF debugging information as well as source code. When built with + debuginfod, readelf and objdump can automatically query debuginfod + servers for separate debug files when they otherwise cannot be found. + To build binutils with debuginfod, pass --with-debuginfod to configure. + This requires libdebuginfod, the debuginfod client library. debuginfod + is distributed with elfutils, starting with version 0.178. For more + information see https://sourceware.org/elfutils. + * Add --output option to the "ar" program. This option can be used to specify the output directory when extracting members from an archive. diff --git a/binutils/config.in b/binutils/config.in index 72ead4e..703f7b1 100644 --- a/binutils/config.in +++ b/binutils/config.in @@ -109,6 +109,9 @@ /* Define if your <locale.h> file defines LC_MESSAGES. */ #undef HAVE_LC_MESSAGES +/* Define to 1 if debuginfod is enabled. */ +#undef HAVE_LIBDEBUGINFOD + /* Define to 1 if you have the <limits.h> header file. */ #undef HAVE_LIMITS_H diff --git a/binutils/configure b/binutils/configure index 50f8d5b..aa91e1b 100755 --- a/binutils/configure +++ b/binutils/configure @@ -684,6 +684,7 @@ WARN_WRITE_STRINGS NO_WERROR WARN_CFLAGS_FOR_BUILD WARN_CFLAGS +LIBDEBUGINFOD OTOOL64 OTOOL LIPO @@ -813,6 +814,7 @@ enable_largefile enable_targets enable_deterministic_archives enable_default_strings_all +with_debuginfod enable_werror enable_build_warnings enable_nls @@ -1483,6 +1485,8 @@ Optional Packages: --with-pic try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-debuginfod Enable debuginfo lookups with debuginfod + (auto/yes/no) --with-system-zlib use installed libz --with-gnu-ld assume the C compiler uses GNU ld default=no --with-libiconv-prefix[=DIR] search for libiconv in DIR/include and DIR/lib @@ -1932,6 +1936,52 @@ $as_echo "$ac_res" >&6; } } # ac_fn_c_check_func +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_c_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_decl + # ac_fn_c_compute_int LINENO EXPR VAR INCLUDES # -------------------------------------------- # Tries to find the compile-time value of EXPR in a program that includes @@ -2168,52 +2218,6 @@ $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type - -# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES -# --------------------------------------------- -# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR -# accordingly. -ac_fn_c_check_decl () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - as_decl_name=`echo $2|sed 's/ *(.*//'` - as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 -$as_echo_n "checking whether $as_decl_name is declared... " >&6; } -if eval \${$3+:} false; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -#ifndef $as_decl_name -#ifdef __cplusplus - (void) $as_decl_use; -#else - (void) $as_decl_name; -#endif -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno - -} # ac_fn_c_check_decl cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. @@ -11523,7 +11527,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11526 "configure" +#line 11530 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -11629,7 +11633,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 11632 "configure" +#line 11636 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -12236,6 +12240,90 @@ fi +# Enable debuginfod + +# Check whether --with-debuginfod was given. +if test "${with_debuginfod+set}" = set; then : + withval=$with_debuginfod; +else + with_debuginfod=auto +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use debuginfod" >&5 +$as_echo_n "checking whether to use debuginfod... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_debuginfod" >&5 +$as_echo "$with_debuginfod" >&6; } + +if test "${with_debuginfod}" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: debuginfod support disabled; some features may be unavailable." >&5 +$as_echo "$as_me: WARNING: debuginfod support disabled; some features may be unavailable." >&2;} +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for debuginfod_begin in -ldebuginfod" >&5 +$as_echo_n "checking for debuginfod_begin in -ldebuginfod... " >&6; } +if ${ac_cv_lib_debuginfod_debuginfod_begin+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldebuginfod $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char debuginfod_begin (); +int +main () +{ +return debuginfod_begin (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_debuginfod_debuginfod_begin=yes +else + ac_cv_lib_debuginfod_debuginfod_begin=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_debuginfod_debuginfod_begin" >&5 +$as_echo "$ac_cv_lib_debuginfod_debuginfod_begin" >&6; } +if test "x$ac_cv_lib_debuginfod_debuginfod_begin" = xyes; then : + have_debuginfod_lib=yes +fi + + ac_fn_c_check_decl "$LINENO" "debuginfod_begin" "ac_cv_have_decl_debuginfod_begin" "#include <elfutils/debuginfod.h> +" +if test "x$ac_cv_have_decl_debuginfod_begin" = xyes; then : + have_debuginfod_h=yes +fi + + if test "x$have_debuginfod_lib" = "xyes" -a \ + "x$have_debuginfod_h" = "xyes"; then + +$as_echo "#define HAVE_LIBDEBUGINFOD 1" >>confdefs.h + + LIBDEBUGINFOD="-ldebuginfod" + + else + + if test "$with_debuginfod" = yes; then + as_fn_error $? "debuginfod is missing or unusable" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: debuginfod is missing or unusable; some features may be unavailable." >&5 +$as_echo "$as_me: WARNING: debuginfod is missing or unusable; some features may be unavailable." >&2;} + fi + fi +fi + + + cat >>confdefs.h <<_ACEOF #define DEFAULT_STRINGS_ALL $default_strings_all _ACEOF diff --git a/binutils/configure.ac b/binutils/configure.ac index d77161f..385ab01 100644 --- a/binutils/configure.ac +++ b/binutils/configure.ac @@ -18,6 +18,7 @@ dnl <http://www.gnu.org/licenses/>. dnl m4_include([../bfd/version.m4]) +m4_include([../config/debuginfod.m4]) AC_INIT([binutils], BFD_VERSION) AC_CONFIG_SRCDIR(ar.c) @@ -63,6 +64,8 @@ else default_strings_all=1 fi], [default_strings_all=1]) +AC_DEBUGINFOD + AC_DEFINE_UNQUOTED(DEFAULT_STRINGS_ALL, $default_strings_all, [Should strings use -a behavior by default?]) diff --git a/binutils/doc/Makefile.in b/binutils/doc/Makefile.in index 52c39ba..b0e7b7b 100644 --- a/binutils/doc/Makefile.in +++ b/binutils/doc/Makefile.in @@ -127,7 +127,9 @@ am__aclocal_m4_deps = $(top_srcdir)/../bfd/acinclude.m4 \ $(top_srcdir)/../config/zlib.m4 $(top_srcdir)/../libtool.m4 \ $(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \ $(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \ - $(top_srcdir)/../bfd/version.m4 $(top_srcdir)/configure.ac + $(top_srcdir)/../bfd/version.m4 \ + $(top_srcdir)/../config/debuginfod.m4 \ + $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) @@ -284,6 +286,7 @@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBDEBUGINFOD = @LIBDEBUGINFOD@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ LIBINTL_DEP = @LIBINTL_DEP@ diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index f938e74..71af6c5 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -154,6 +154,7 @@ in the section entitled ``GNU Free Documentation License''. * elfedit:: Update ELF header and property of ELF files * Common Options:: Command-line options for all utilities * Selecting the Target System:: How these utilities determine the target +* debuginfod:: Using binutils with debuginfod * Reporting Bugs:: Reporting Bugs * GNU Free Documentation License:: GNU Free Documentation License * Binutils Index:: Binutils Index @@ -5201,6 +5202,23 @@ Ways to specify: deduced from the input file @end enumerate +@node debuginfod +@chapter debuginfod +@cindex separate debug files + +debuginfod is a web service that indexes ELF/DWARF debugging resources +by build-id and serves them over HTTP. + +Binutils can be built with the debuginfod client library +@code{libdebuginfod} using the @option{--with-debuginfod} configure option. +This option is enabled by default if @code{libdebuginfod} is installed +and found at configure time. This allows @command{objdump} and +@command{readelf} to automatically query debuginfod servers for +separate debug files when the files are otherwise not found. + +debuginfod is packaged with elfutils, starting with version 0.178. +You can get the latest version from `https://sourceware.org/elfutils/'. + @node Reporting Bugs @chapter Reporting Bugs @cindex bugs 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) diff --git a/binutils/dwarf.h b/binutils/dwarf.h index 3335858..6956692 100644 --- a/binutils/dwarf.h +++ b/binutils/dwarf.h @@ -256,6 +256,10 @@ extern bfd_boolean reloc_at (struct dwarf_section *, dwarf_vma); extern dwarf_vma read_leb128 (unsigned char *, const unsigned char *const, bfd_boolean, unsigned int *, int *); +#if HAVE_LIBDEBUGINFOD +extern unsigned char * get_build_id (void *); +#endif + static inline void report_leb_status (int status) { diff --git a/binutils/objdump.c b/binutils/objdump.c index 210b67e..27b0fb6 100644 --- a/binutils/objdump.c +++ b/binutils/objdump.c @@ -2945,6 +2945,33 @@ 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 ATTRIBUTE_UNUSED) diff --git a/binutils/readelf.c b/binutils/readelf.c index 17c27ce..4326cd0 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -14194,6 +14194,138 @@ load_specific_debug_section (enum dwarf_section_display_enum debug, return TRUE; } +#if HAVE_LIBDEBUGINFOD +/* Return a hex string representation of the build-id. */ +unsigned char * +get_build_id (void * data) +{ + Filedata * filedata = (Filedata *)data; + Elf_Internal_Shdr * shdr; + unsigned long i; + + /* Iterate through notes to find note.gnu.build-id. */ + for (i = 0, shdr = filedata->section_headers; + i < filedata->file_header.e_shnum && shdr != NULL; + i++, shdr++) + { + if (shdr->sh_type != SHT_NOTE) + continue; + + char * next; + char * end; + size_t data_remaining; + size_t min_notesz; + Elf_External_Note * enote; + Elf_Internal_Note inote; + + bfd_vma offset = shdr->sh_offset; + bfd_vma align = shdr->sh_addralign; + bfd_vma length = shdr->sh_size; + + enote = (Elf_External_Note *) get_section_contents (shdr, filedata); + if (enote == NULL) + continue; + + if (align < 4) + align = 4; + else if (align != 4 && align != 8) + continue; + + end = (char *) enote + length; + data_remaining = end - (char *) enote; + + if (!is_ia64_vms (filedata)) + { + min_notesz = offsetof (Elf_External_Note, name); + if (data_remaining < min_notesz) + { + warn (ngettext ("debuginfod: Corrupt note: only %ld byte remains, " + "not enough for a full note\n", + "Corrupt note: only %ld bytes remain, " + "not enough for a full note\n", + data_remaining), + (long) data_remaining); + break; + } + data_remaining -= min_notesz; + + inote.type = BYTE_GET (enote->type); + inote.namesz = BYTE_GET (enote->namesz); + inote.namedata = enote->name; + inote.descsz = BYTE_GET (enote->descsz); + inote.descdata = ((char *) enote + + ELF_NOTE_DESC_OFFSET (inote.namesz, align)); + inote.descpos = offset + (inote.descdata - (char *) enote); + next = ((char *) enote + + ELF_NOTE_NEXT_OFFSET (inote.namesz, inote.descsz, align)); + } + else + { + Elf64_External_VMS_Note *vms_enote; + + /* PR binutils/15191 + Make sure that there is enough data to read. */ + min_notesz = offsetof (Elf64_External_VMS_Note, name); + if (data_remaining < min_notesz) + { + warn (ngettext ("debuginfod: Corrupt note: only %ld byte remains, " + "not enough for a full note\n", + "Corrupt note: only %ld bytes remain, " + "not enough for a full note\n", + data_remaining), + (long) data_remaining); + break; + } + data_remaining -= min_notesz; + + vms_enote = (Elf64_External_VMS_Note *) enote; + inote.type = BYTE_GET (vms_enote->type); + inote.namesz = BYTE_GET (vms_enote->namesz); + inote.namedata = vms_enote->name; + inote.descsz = BYTE_GET (vms_enote->descsz); + inote.descdata = inote.namedata + align_power (inote.namesz, 3); + inote.descpos = offset + (inote.descdata - (char *) enote); + next = inote.descdata + align_power (inote.descsz, 3); + } + + /* Skip malformed notes. */ + if ((size_t) (inote.descdata - inote.namedata) < inote.namesz + || (size_t) (inote.descdata - inote.namedata) > data_remaining + || (size_t) (next - inote.descdata) < inote.descsz + || ((size_t) (next - inote.descdata) + > data_remaining - (size_t) (inote.descdata - inote.namedata))) + { + warn (_("debuginfod: note with invalid namesz and/or descsz found\n")); + warn (_(" type: 0x%lx, namesize: 0x%08lx, descsize: 0x%08lx, alignment: %u\n"), + inote.type, inote.namesz, inote.descsz, (int) align); + continue; + } + + /* Check if this is the build-id note. If so then convert the build-id + bytes to a hex string. */ + if (inote.namesz > 0 + && const_strneq (inote.namedata, "GNU") + && inote.type == NT_GNU_BUILD_ID) + { + unsigned long j; + char * build_id; + + build_id = malloc (inote.descsz * 2 + 1); + if (build_id == NULL) + return NULL; + + for (j = 0; j < inote.descsz; ++j) + sprintf (build_id + (j * 2), "%02x", inote.descdata[j] & 0xff); + build_id[inote.descsz * 2] = '\0'; + + return (unsigned char *)build_id; + } + } + + return NULL; +} +#endif /* HAVE_LIBDEBUGINFOD */ + /* If this is not NULL, load_debug_section will only look for sections within the list of sections given here. */ static unsigned int * section_subset = NULL; diff --git a/binutils/testsuite/binutils-all/linkdebug.s b/binutils/testsuite/binutils-all/linkdebug.s index a13a4c6..518f0ce 100644 --- a/binutils/testsuite/binutils-all/linkdebug.s +++ b/binutils/testsuite/binutils-all/linkdebug.s @@ -18,9 +18,22 @@ /* This is the separate debug info file. */ -/* Create a .debug_abbrev section for use by the .debug_info section +/* Create .note.gnu.build-id note for use by the .gnu_debugaltlink in the main object file. */ - + + .section .note.gnu.build-id,"a",%note + .balign 4 + .dc.l 0x04 ;# Name size + .dc.l 0x18 ;# Description size + .dc.l 0x03 ;# Type + .asciz "GNU" ;# Name + .dc.b 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 + .dc.b 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff + .dc.b 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef + + /* Create a .debug_abbrev section for use by the .debug_info section + in the main object file. */ + .section .debug_abbrev,"",%progbits abbrevs: .uleb128 0x01 ;# Abbrev code. diff --git a/config/debuginfod.m4 b/config/debuginfod.m4 new file mode 100644 index 0000000..9979abe --- /dev/null +++ b/config/debuginfod.m4 @@ -0,0 +1,38 @@ +dnl Copyright (C) 1997-2019 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +AC_DEFUN([AC_DEBUGINFOD], +[ +# Enable debuginfod +AC_ARG_WITH([debuginfod], + AC_HELP_STRING([--with-debuginfod], + [Enable debuginfo lookups with debuginfod (auto/yes/no)]), + [], [with_debuginfod=auto]) +AC_MSG_CHECKING([whether to use debuginfod]) +AC_MSG_RESULT([$with_debuginfod]) + +if test "${with_debuginfod}" = no; then + AC_MSG_WARN([debuginfod support disabled; some features may be unavailable.]) +else + AC_CHECK_LIB([debuginfod], [debuginfod_begin], [have_debuginfod_lib=yes]) + AC_CHECK_DECL([debuginfod_begin], [have_debuginfod_h=yes], [], + [#include <elfutils/debuginfod.h>]) + if test "x$have_debuginfod_lib" = "xyes" -a \ + "x$have_debuginfod_h" = "xyes"; then + AC_DEFINE([HAVE_LIBDEBUGINFOD], [1], + [Define to 1 if debuginfod is enabled.]) + AC_SUBST([LIBDEBUGINFOD], ["-ldebuginfod"]) + else + AC_SUBST([LIBDEBUGINFOD], []) + if test "$with_debuginfod" = yes; then + AC_MSG_ERROR([debuginfod is missing or unusable]) + else + AC_MSG_WARN([debuginfod is missing or unusable; some features may be unavailable.]) + fi + fi +fi +]) @@ -690,6 +690,7 @@ extra_mpc_gmp_configure_flags extra_mpfr_configure_flags gmpinc gmplibs +LIBDEBUGINFOD do_compare GNATMAKE GNATBIND @@ -790,6 +791,7 @@ enable_libssp enable_libstdcxx enable_liboffloadmic enable_bootstrap +with_debuginfod with_mpc with_mpc_include with_mpc_lib @@ -1553,6 +1555,8 @@ Optional Packages: --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-build-libsubdir=DIR Directory where to find libraries for build system --with-system-zlib use installed libz + --with-debuginfod Enable debuginfo lookups with debuginfod + (auto/yes/no) --with-mpc=PATH specify prefix directory for installed MPC package. Equivalent to --with-mpc-include=PATH/include plus --with-mpc-lib=PATH/lib @@ -1921,6 +1925,52 @@ fi as_fn_set_status $ac_retval } # ac_fn_c_try_link + +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_c_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_decl cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. @@ -5433,6 +5483,92 @@ gmplibs="-lmpc -lmpfr -lgmp" gmpinc= have_gmp=no +# Check for debuginfod + + +# Enable debuginfod + +# Check whether --with-debuginfod was given. +if test "${with_debuginfod+set}" = set; then : + withval=$with_debuginfod; +else + with_debuginfod=auto +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use debuginfod" >&5 +$as_echo_n "checking whether to use debuginfod... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_debuginfod" >&5 +$as_echo "$with_debuginfod" >&6; } + +if test "${with_debuginfod}" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: debuginfod support disabled; some features may be unavailable." >&5 +$as_echo "$as_me: WARNING: debuginfod support disabled; some features may be unavailable." >&2;} +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for debuginfod_begin in -ldebuginfod" >&5 +$as_echo_n "checking for debuginfod_begin in -ldebuginfod... " >&6; } +if ${ac_cv_lib_debuginfod_debuginfod_begin+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldebuginfod $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char debuginfod_begin (); +int +main () +{ +return debuginfod_begin (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_debuginfod_debuginfod_begin=yes +else + ac_cv_lib_debuginfod_debuginfod_begin=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_debuginfod_debuginfod_begin" >&5 +$as_echo "$ac_cv_lib_debuginfod_debuginfod_begin" >&6; } +if test "x$ac_cv_lib_debuginfod_debuginfod_begin" = xyes; then : + have_debuginfod_lib=yes +fi + + ac_fn_c_check_decl "$LINENO" "debuginfod_begin" "ac_cv_have_decl_debuginfod_begin" "#include <elfutils/debuginfod.h> +" +if test "x$ac_cv_have_decl_debuginfod_begin" = xyes; then : + have_debuginfod_h=yes +fi + + if test "x$have_debuginfod_lib" = "xyes" -a \ + "x$have_debuginfod_h" = "xyes"; then + +$as_echo "#define HAVE_LIBDEBUGINFOD 1" >>confdefs.h + + LIBDEBUGINFOD="-ldebuginfod" + + else + + if test "$with_debuginfod" = yes; then + as_fn_error $? "debuginfod is missing or unusable" "$LINENO" 5 + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: debuginfod is missing or unusable; some features may be unavailable." >&5 +$as_echo "$as_me: WARNING: debuginfod is missing or unusable; some features may be unavailable." >&2;} + fi + fi +fi + + # Specify a location for mpc # check for this first so it ends up on the link line before mpfr. @@ -5587,8 +5723,7 @@ if test -d ${srcdir}/gcc && test "x$have_gmp" = xno; then # Check for the recommended and required versions of GMP. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the correct version of gmp.h" >&5 $as_echo_n "checking for the correct version of gmp.h... " >&6; } - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "gmp.h" int diff --git a/configure.ac b/configure.ac index 7433bad..544fab3 100644 --- a/configure.ac +++ b/configure.ac @@ -23,6 +23,7 @@ m4_include(config/acx.m4) m4_include(config/override.m4) m4_include(config/proginstall.m4) m4_include(config/elf.m4) +m4_include(config/debuginfod.m4) m4_include([libtool.m4]) m4_include([ltoptions.m4]) m4_include([ltsugar.m4]) @@ -1363,6 +1364,9 @@ gmplibs="-lmpc -lmpfr -lgmp" gmpinc= have_gmp=no +# Check for debuginfod +AC_DEBUGINFOD + # Specify a location for mpc # check for this first so it ends up on the link line before mpfr. AC_ARG_WITH(mpc, |