[1/1] Add debuginfod support to objdump and readelf

Message ID CAJDtP-TJin3RbSxPXURDO8cV7EucCcFo3PbO_K_x1SCOtLy=yg@mail.gmail.com
State New
Headers show
Series
  • Add debuginfod support to objdump and readelf
Related show

Commit Message

Aaron Merey Jan. 9, 2020, 4:07 a.m.

Patch

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/.

Tested on x86-64 Fedora 31.

ChangeLog:
2020-01-08  Aaron Merey  <amerey@redhat.com>

        * config/debuginfod.m4: New file. Add macro AC_DEBUGINFOD. Adds
        new configure option --with-debuginfod.
        * configure: Regenerate.
        * configure.ac: Call AC_DEBUGINFOD.

binutils/ChangeLog:
2020-01-08  Aaron Merey  <amerey@redhat.com>

        * 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.
---
 binutils/Makefile.am                          |   6 +-
 binutils/Makefile.in                          |   9 +-
 binutils/NEWS                                 |   9 +
 binutils/config.in                            |   3 +
 binutils/configure                            | 184 ++++++++++++-----
 binutils/configure.ac                         |   3 +
 binutils/doc/Makefile.in                      |   5 +-
 binutils/doc/binutils.texi                    |  18 ++
 binutils/dwarf.c                              | 110 +++++++++-
 binutils/dwarf.h                              |   4 +
 binutils/objdump.c                            |  27 +++
 binutils/readelf.c                            | 132 ++++++++++++
 .../testsuite/binutils-all/debuginfod.exp     | 189 ++++++++++++++++++
 binutils/testsuite/binutils-all/linkdebug.s   |  17 +-
 config/debuginfod.m4                          |  38 ++++
 configure                                     | 139 ++++++++++++-
 configure.ac                                  |   4 +
 17 files changed, 836 insertions(+), 61 deletions(-)
 create mode 100644 binutils/testsuite/binutils-all/debuginfod.exp
 create mode 100644 config/debuginfod.m4

diff --git a/binutils/Makefile.am b/binutils/Makefile.am
index cc23012064..f1f3907b0b 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 91dfe257f2..39f08563f9 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 e5e0056d66..72a964424e 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 72ead4eb61..703f7b15e7 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 50f8d5b1a2..aa91e1b395 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 d77161f95d..385ab01a26 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 52c39ba2eb..b0e7b7b6c8 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 f938e7437a..71af6c5fcf 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 130ba10be3..9c96f471f8 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 333585836e..6956692676 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 210b67e79b..27b0fb6039 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 17c27ceeda..4326cd00ca 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/debuginfod.exp b/binutils/testsuite/binutils-all/debuginfod.exp
new file mode 100644
index 0000000000..596fcf58df
--- /dev/null
+++ b/binutils/testsuite/binutils-all/debuginfod.exp
@@ -0,0 +1,189 @@ 
+# Copyright (C) 2002-2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+
+# test debuginfod with readelf and objdump
+
+set test "debuginfod"
+
+if {[which debuginfod] == 0} {
+    unsupported "$test (not found)"
+    return
+}
+
+if {[which curl] == 0} {
+    unsupported "$test (curl not found)"
+    return
+}
+
+if { ![is_elf_format] } {
+    unsupported "$test (unsupported target)"
+}
+
+if { [which $OBJDUMP] == 0} {
+    perror "$test $OBJDUMP (does not exist)"
+    return
+}
+
+ if { [which $READELF] == 0} {
+    perror "$test $READELF (does not exist)"
+    return
+}
+
+# Compile testprog.c, move the debuginfo to a separate file and add .gnu_debuglink.
+if { [target_compile $srcdir/$subdir/testprog.c tmpdir/testprog executable debug] != ""} {
+    fail "$test (compilation failed)"
+    return
+}
+
+if { [binutils_run $OBJCOPY "--only-keep-debug tmpdir/testprog tmpdir/testprog.debug"] != "" } {
+    fail "$test (create separate debug info file)"
+    return
+}
+
+if { [binutils_run $OBJCOPY "--strip-debug tmpdir/testprog"] != "" } {
+    fail "$test (strip debug info)"
+    return
+}
+
+if { [binutils_run $OBJCOPY "--add-gnu-debuglink=tmpdir/testprog.debug tmpdir/testprog"] != "" } {
+    fail "$test (add debuglink)"
+    return
+}
+
+# Assemble an elf file with a debugaltlink
+if { ![binutils_assemble $srcdir/$subdir/debuglink.s tmpdir/debuglink.o] } {
+    fail "$test (assemble debuglink)"
+}
+
+if { ![binutils_assemble $srcdir/$subdir/linkdebug.s tmpdir/linkdebug.debug] } {
+    fail "$test (assemble linkdebug)"
+}
+
+# Find an unused port
+set port [exec sh -c "while true; do PORT=`expr '(' \$RANDOM % 1000 ')' + 9000`; ss -atn | fgrep \":\$PORT\" || break; done; echo \$PORT"]
+
+# Specify the directory that files retrieved from the server are written to.
+set cache [file join [pwd] "tmpdir/.debuginfod_cache"]
+
+set ::env(DEBUGINFOD_URLS) http://127.0.0.1:$port
+set ::env(DEBUGINFOD_TIMEOUT) 30
+set ::env(DEBUGINFOD_CACHE_PATH) $cache
+
+# Move debug files into another directory so that readelf and objdump cannot
+# find them without debuginfod.
+file mkdir tmpdir/dbg
+file rename -force tmpdir/testprog.debug tmpdir/dbg
+file rename -force tmpdir/linkdebug.debug tmpdir/dbg
+
+# Remove an old cache if it exists
+file delete -force $cache
+
+# Check whether objdump and readelf are configured with debuginfod.
+# To check this we attempt to follow a broken debuglink. If configured
+# with debuginfod the output will contain the debuginfod URLs that were
+# queried (these queries fail since the server is not yet running).
+set conf_objdump [binutils_run $OBJDUMP "-WK tmpdir/testprog"]
+set conf_readelf [binutils_run $READELF "-wK tmpdir/testprog"]
+
+set debuginfod_pid 0
+
+# Kill the server if we abort early
+proc sigint_handler {} {
+    global debuginfod_pid
+
+    if { $debuginfod_pid != 0 } {
+        catch {exec kill -INT $debuginfod_pid}
+    }
+
+    exit
+}
+
+trap sigint_handler INT
+
+# Start a debuginfod server.
+set debuginfod_pid [exec debuginfod -p $port -F tmpdir/dbg 2>/dev/null &]
+
+if { !$debuginfod_pid } {
+    fail "$test (server init)"
+    return
+}
+
+# Wait for debuginfod indicate it's ready.
+set ready 0
+for {set timelim 30} {$timelim != 0} {incr timelim -1} {
+    sleep 1
+    set want ".*ready 1.*"
+    catch {exec curl -s http://127.0.0.1:$port/metrics} got
+
+    if { [regexp $want $got] } {
+      set ready 1
+      break
+    }
+}
+
+if { !$ready } {
+    fail "$test (server ready)"
+    catch {exec kill -INT $debuginfod_pid}
+    return
+}
+
+# Test whether prog can fetch separate debuginfo using debuginfod
+# if it's configured to do so.
+proc test_fetch_debuglink { prog progargs } {
+    global test
+    global cache
+
+    set got [binutils_run $prog "$progargs tmpdir/testprog"]
+
+    if { [regexp ".*Found separate debug info file.*Contents\[^\n\]*loaded from\[^\n\]*$cache.*" $got] } {
+       pass "$test ($prog debuglink)"
+    } else {
+       fail "$test ($prog debuglink)"
+    }
+}
+
+# Test whether prog can fetch debugaltlink files using debuginfod
+# if it's configured to do so.
+proc test_fetch_debugaltlink { prog progargs } {
+    global test
+    global cache
+
+    set got [binutils_run $prog "$progargs tmpdir/debuglink.o"]
+    set buildid "00112233445566778899aabbccddeeff0123456789abcdef"
+
+    if { [regexp ".*Found separate debug info file\[^\n\]*$cache/$buildid" $got] } {
+        pass "$test ($prog debugaltlink)"
+    } else {
+        fail "$test ($prog debugaltlink)"
+    }
+}
+
+if { [regexp ".*DEBUGINFOD.*" $conf_objdump] } {
+    test_fetch_debuglink $OBJDUMP "-W"
+    test_fetch_debugaltlink $OBJDUMP "-WK"
+} else {
+    untested "$test (objdump not configured with debuginfod)"
+}
+
+if { [regexp ".*DEBUGINFOD.*" $conf_readelf] } {
+    test_fetch_debuglink $READELF "-w"
+    test_fetch_debugaltlink $READELF "-wK"
+} else {
+    untested "$test (readelf not configured with debuginfod)"
+}
+
+file delete -force $cache
+catch {exec kill -INT $debuginfod_pid}
diff --git a/binutils/testsuite/binutils-all/linkdebug.s b/binutils/testsuite/binutils-all/linkdebug.s
index a13a4c6346..518f0ce5a5 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 0000000000..9979abe89d
--- /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
+])
diff --git a/configure b/configure
index 6a9719f609..e02123c36f 100755
--- a/configure
+++ b/configure
@@ -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 7433badc21..544fab3d20 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,
-- 
2.23.0