[1/1] Add debuginfod support to GDB

Message ID CAJDtP-RzP1byHayyOcXeFjucf65mAt4bi9T28nC9zfJ_-0Md3w@mail.gmail.com
State New, archived
Headers

Commit Message

Aaron Merey Jan. 9, 2020, 3:48 a.m. UTC
  
  

Comments

Eli Zaretskii Jan. 9, 2020, 1:48 p.m. UTC | #1
> From: Aaron Merey <amerey@redhat.com>
> Date: Wed, 8 Jan 2020 22:48:11 -0500
> 
> +* GDB now supports debuginfod, an HTTP server for distributing
> +  ELF/DWARF debugging information as well as source code. When built with
> +  debuginfod, GDB can automatically query debuginfod servers for the
> +  separate debug files and source code of the executable being debugged.
> +  To build GDB with debuginfod, pass --with-debuginfod to configure.
> +  This requires libdebuginfod, the debuginfod client library.
> +  debuginfod is distributed with elfutils, starting with version 0.178.
> +  You can get the latest version from https://sourceware.org/elfutils.

This part is OK, but please leave 2 spaces between sentences, per our
conventions.

Thanks.
  
Tom Tromey Jan. 9, 2020, 3:27 p.m. UTC | #2
>>>>> "Aaron" == Aaron Merey <amerey@redhat.com> writes:

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

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

Does the top-level configure really need AC_DEBUGINFOD?

If so, then this part of the patch has to go to gcc-patches first.
But, I suspect it's not needed, in which case dropping it is more
convenient, because we can have debuginfod.m4 locally and not involve
gcc at all.

Aaron> +if test "${with_debuginfod}" = no; then
Aaron> +  AC_MSG_WARN([debuginfod support disabled; some features may be unavailable.])
Aaron> +else
Aaron> +  AC_CHECK_LIB([debuginfod], [debuginfod_begin], [have_debuginfod_lib=yes])

Does and/or should libdebuginfod use pkg-config for this kind of thing?

Aaron> diff --git a/gdb/Makefile.in b/gdb/Makefile.in

Aaron> @@ -612,7 +615,7 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(LIBCTF) $(ZLIB) \
Aaron>  	@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
Aaron>  	$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
Aaron>  	$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR) \
Aaron> -	$(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS)
Aaron> +	$(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) $(LIBDEBUGINFOD)

Should it be before PTHREAD_LIBS?
If not, this is fine.

Aaron> +          /* Allow debuginfod to abort the download if SIGINT is raised.  */
Aaron> +          debuginfod_set_progressfn(

gdb style puts a space before the paren, and usually the paren is kept
next to the arguments if a newline is needed.

Aaron> +            client,
Aaron> +            [] (debuginfod_client *c, long a, long b)
Aaron> +              { return 1 ? check_quit_flag () : 0; }

This looks weird, because there's no need for the "1 ?" part.  Maybe it
should be just:

    return check_quit_flag ();

A lot of this code is duplicated in 3 places.  I think it would be
better to have a helper function to consolidate the shared code.

Aaron> +# Copyright 2010-2019 Free Software Foundation, Inc.

Probably just 2020.

Tom
  
Aaron Merey Jan. 9, 2020, 10:40 p.m. UTC | #3
On Thu, Jan 9, 2020 at 10:27 AM Tom Tromey <tom@tromey.com> wrote:
> Aaron>         * config/debuginfod.m4: New file. Add macro AC_DEBUGINFOD.
> Aaron>         Adds new configure option --with-debuginfod.
> Aaron>         * configure: Regenerate.
> Aaron>         * configure.ac: Call AC_DEBUGINFOD.
>
> Does the top-level configure really need AC_DEBUGINFOD?
>
> If so, then this part of the patch has to go to gcc-patches first.
> But, I suspect it's not needed, in which case dropping it is more
> convenient, because we can have debuginfod.m4 locally and not involve
> gcc at all.

The reason for the top-level AC_DEBUGINFOD is to prevent the top-level
configure check from succeeding in cases where --with-debuginfod is
given but the debuginfod library or header cannot be found.

I should also mention that these same top level changes were also
included in a patch that adds debuginfod support to binutils and that
patch has been merged.

https://sourceware.org/ml/binutils/2020-01/msg00090.html

(I wasn't sure which list to post top-level changes to so I included
them in both patches so that each will work independently.)

> Aaron> +if test "${with_debuginfod}" = no; then
> Aaron> +  AC_MSG_WARN([debuginfod support disabled; some features may be unavailable.])
> Aaron> +else
> Aaron> +  AC_CHECK_LIB([debuginfod], [debuginfod_begin], [have_debuginfod_lib=yes])
>
> Does and/or should libdebuginfod use pkg-config for this kind of thing?

I can change this to use pkg-config.

>
> Aaron> @@ -612,7 +615,7 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(LIBCTF) $(ZLIB) \
> Aaron>          @LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
> Aaron>          $(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
> Aaron>          $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR) \
> Aaron> -        $(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS)
> Aaron> +        $(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) $(LIBDEBUGINFOD)
>
> Should it be before PTHREAD_LIBS?
> If not, this is fine.

This should be ok.

> Aaron> +          /* Allow debuginfod to abort the download if SIGINT is raised.  */
> Aaron> +          debuginfod_set_progressfn(
>
> gdb style puts a space before the paren, and usually the paren is kept
> next to the arguments if a newline is needed.
>
> Aaron> +            client,
> Aaron> +            [] (debuginfod_client *c, long a, long b)
> Aaron> +              { return 1 ? check_quit_flag () : 0; }
>
> This looks weird, because there's no need for the "1 ?" part.  Maybe it
> should be just:
>
>     return check_quit_flag ();
>
> A lot of this code is duplicated in 3 places.  I think it would be
> better to have a helper function to consolidate the shared code.

Agreed, is gdb/gdbsupport/ a good place for this helper?

> Aaron> +# Copyright 2010-2019 Free Software Foundation, Inc.
>
> Probably just 2020.

Sure.
  
Tom Tromey Jan. 10, 2020, 2:23 p.m. UTC | #4
>>>>> "Aaron" == Aaron Merey <amerey@redhat.com> writes:

Aaron> The reason for the top-level AC_DEBUGINFOD is to prevent the top-level
Aaron> configure check from succeeding in cases where --with-debuginfod is
Aaron> given but the debuginfod library or header cannot be found.

As Christian pointed out, this isn't done in other cases.

Aaron> I should also mention that these same top level changes were also
Aaron> included in a patch that adds debuginfod support to binutils and that
Aaron> patch has been merged.

Ok.  Well, if you want to keep that, then you'll also have to submit the
top-level changes to GCC and get them approved there.  gcc and
binutils-gdb share the top-level configury.  It's canonically maintained
in the gcc repository; on occasion we do land a patch in binutils-gdb
first, but normally the process is to land there first.

>> A lot of this code is duplicated in 3 places.  I think it would be
>> better to have a helper function to consolidate the shared code.

Aaron> Agreed, is gdb/gdbsupport/ a good place for this helper?

No, since gdbserver won't use this code.

Tom
  
Aaron Merey Jan. 10, 2020, 4:46 p.m. UTC | #5
On Fri, Jan 10, 2020 at 9:23 AM Tom Tromey <tom@tromey.com> wrote:
> Ok.  Well, if you want to keep that, then you'll also have to submit the
> top-level changes to GCC and get them approved there.  gcc and
> binutils-gdb share the top-level configury.  It's canonically maintained
> in the gcc repository; on occasion we do land a patch in binutils-gdb
> first, but normally the process is to land there first.

Ok good to know. Like you said it's more convenient to have debuginfod.m4
local to gdb. But since the binutils configury uses it too, maybe it's worth
submitting this change to GCC to minimize duplication.

> >> A lot of this code is duplicated in 3 places.  I think it would be
> >> better to have a helper function to consolidate the shared code.
>
> Aaron> Agreed, is gdb/gdbsupport/ a good place for this helper?
>
> No, since gdbserver won't use this code.

Ok how about gdb/debuginfod-support.h then?

Aaron
  
Tom Tromey Jan. 10, 2020, 6:43 p.m. UTC | #6
>>>>> "Aaron" == Aaron Merey <amerey@redhat.com> writes:

Aaron> Ok how about gdb/debuginfod-support.h then?

I think a .c file is more appropriate.

Tom
  

Patch

debuginfod is a lightweight web service that indexes ELF/DWARF debugging
resources by build-id and serves them over HTTP. This patch enables GDB
to query debuginfod servers for separate debug files and source code when
it is otherwise not able to find them. GDB 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/.

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.

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

        * Makefile.in (CLIBS): Add libdebuginfod.
        * NEWS: Update.
        * config.in: Regenerate.
        * configure: Regenerate.
        * configure.ac: Call AC_DEBUGINFOD.
        * doc/gdb.texinfo: Add --with-debuginfod to configure options
        summary.
        * dwarf2read.c (dwarf2_get_dwz_file): Query debuginfod servers
        when a dwz file cannot be found.
        * elfread.c (elf_symfile_read): Query debuginfod servers when a
        debuginfo file cannot be found.
        * source.c (open_source_file): Query debuginfod servers when a
        source file cannot be found.
        * top.c (print_gdb_configuration): Include
        --{with,without}-debuginfod in the output.

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

        * gdb.debuginfod: New directory for debuginfod tests.
        * gdb.debuginfod/main.c: New test file.
        * gdb.debuginfod/fetch_src_and_symbols.exp: New tests.
---
 config/debuginfod.m4                          |  38 +++
 configure                                     | 139 ++++++++++-
 configure.ac                                  |   4 +
 gdb/Makefile.in                               |   5 +-
 gdb/NEWS                                      |   9 +
 gdb/config.in                                 |   3 +
 gdb/configure                                 | 181 ++++++++++----
 gdb/configure.ac                              |   5 +
 gdb/doc/gdb.texinfo                           |   8 +
 gdb/dwarf2read.c                              |  42 ++++
 gdb/elfread.c                                 |  47 +++-
 gdb/source.c                                  |  61 +++++
 .../gdb.debuginfod/fetch_src_and_symbols.exp  | 221 ++++++++++++++++++
 gdb/testsuite/gdb.debuginfod/main.c           |  25 ++
 gdb/top.c                                     |  10 +
 15 files changed, 747 insertions(+), 51 deletions(-)
 create mode 100644 config/debuginfod.m4
 create mode 100644 gdb/testsuite/gdb.debuginfod/fetch_src_and_symbols.exp
 create mode 100644 gdb/testsuite/gdb.debuginfod/main.c

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,
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 0bc8142d2a..aea216c5d7 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -220,6 +220,9 @@  INTL = @LIBINTL@
 INTL_DEPS = @LIBINTL_DEP@
 INTL_CFLAGS = @INCINTL@
 
+# Where is the debuginfod library, if any?
+LIBDEBUGINFOD = @LIBDEBUGINFOD@
+
 # Where is the ICONV library?  This will be empty if in libc or not available.
 LIBICONV = @LIBICONV@
 
@@ -612,7 +615,7 @@  CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(LIBCTF) $(ZLIB) \
 	@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
 	$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
 	$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR) \
-	$(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS)
+	$(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) $(LIBDEBUGINFOD)
 CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) $(LIBCTF) \
 	$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
 
diff --git a/gdb/NEWS b/gdb/NEWS
index 8405bd0632..9039e22753 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,15 @@ 
 
 *** Changes since GDB 9
 
+* GDB now supports debuginfod, an HTTP server for distributing
+  ELF/DWARF debugging information as well as source code. When built with
+  debuginfod, GDB can automatically query debuginfod servers for the
+  separate debug files and source code of the executable being debugged.
+  To build GDB with debuginfod, pass --with-debuginfod to configure.
+  This requires libdebuginfod, the debuginfod client library.
+  debuginfod is distributed with elfutils, starting with version 0.178.
+  You can get the latest version from https://sourceware.org/elfutils.
+
 * Debugging MS-Windows processes now sets $_exitsignal when the
   inferior is terminated by a signal, instead of setting $_exitcode.
 
diff --git a/gdb/config.in b/gdb/config.in
index cb886ba8e1..5939b8e436 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -227,6 +227,9 @@ 
 /* Define if you have the babeltrace library. */
 #undef HAVE_LIBBABELTRACE
 
+/* Define to 1 if debuginfod is enabled. */
+#undef HAVE_LIBDEBUGINFOD
+
 /* Define if you have the expat library. */
 #undef HAVE_LIBEXPAT
 
diff --git a/gdb/configure b/gdb/configure
index b572d414ca..defc674337 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -758,6 +758,7 @@  REPORT_BUGS_TEXI
 REPORT_BUGS_TO
 PKGVERSION
 CODESIGN_CERT
+LIBDEBUGINFOD
 HAVE_NATIVE_GCORE_TARGET
 TARGET_OBS
 subdirs
@@ -869,6 +870,7 @@  enable_64_bit_bfd
 enable_gdbmi
 enable_tui
 enable_gdbtk
+with_debuginfod
 with_libunwind_ia64
 with_curses
 enable_profiling
@@ -1598,6 +1600,8 @@  Optional Packages:
                           [--with-auto-load-dir]
   --without-auto-load-safe-path
                           do not restrict auto-loaded files locations
+  --with-debuginfod       Enable debuginfo lookups with debuginfod
+                          (auto/yes/no)
   --with-libunwind-ia64   use libunwind frame unwinding for ia64 targets
   --with-curses           use the curses library instead of the termcap
                           library
@@ -2251,6 +2255,52 @@  rm -f conftest.val
 
 } # ac_fn_c_compute_int
 
+# 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_check_func LINENO FUNC VAR
 # ----------------------------------
 # Tests whether FUNC exists, setting the cache variable VAR accordingly
@@ -2429,52 +2479,6 @@  $as_echo "$ac_res" >&6; }
 
 } # 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
-
 # ac_fn_cxx_try_link LINENO
 # -------------------------
 # Try to link conftest.$ac_ext, and return whether this succeeded.
@@ -6826,6 +6830,91 @@  esac
 
 # Libunwind support for ia64.
 
+# 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
+
+
 
 # Check whether --with-libunwind-ia64 was given.
 if test "${with_libunwind_ia64+set}" = set; then :
diff --git a/gdb/configure.ac b/gdb/configure.ac
index ca0da7980c..89ea64aeca 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -18,6 +18,8 @@  dnl along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 dnl Process this file with autoconf to produce a configure script.
 
+m4_include([../config/debuginfod.m4])
+
 AC_INIT(main.c)
 AC_CONFIG_HEADERS(config.h:config.in, [echo > stamp-h])
 AM_MAINTAINER_MODE
@@ -325,6 +327,9 @@  esac
 
 # Libunwind support for ia64.
 
+# Check for debuginfod
+AC_DEBUGINFOD
+
 AC_ARG_WITH(libunwind-ia64,
 AS_HELP_STRING([--with-libunwind-ia64],
 	       [use libunwind frame unwinding for ia64 targets]),,
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 65137b1739..8929dc6541 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -37705,6 +37705,14 @@  supported).
 Use the curses library instead of the termcap library, for text-mode
 terminal operations.
 
+@item --with-debuginfod
+Build @value{GDBN} with libdebuginfod, the debuginfod client library.
+Used to automatically fetch source files and separate debug files from
+debuginfod servers using the associated executable's build ID. Enabled
+by default if libdebuginfod is installed and found at configure time.
+debuginfod is packaged with elfutils, starting with version 0.178. You
+can get the latest version from `https://sourceware.org/elfutils/'.
+
 @item --with-libunwind-ia64
 Use the libunwind library for unwinding function call stack on ia64
 target platforms.  See http://www.nongnu.org/libunwind/index.html for
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 04979f3d12..f9c06b8cc6 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -77,6 +77,9 @@ 
 #include "gdbsupport/selftest.h"
 #include "rust-lang.h"
 #include "gdbsupport/pathstuff.h"
+#if HAVE_LIBDEBUGINFOD
+#include "elfutils/debuginfod.h"
+#endif
 
 /* When == 1, print basic high level tracing messages.
    When > 1, be more verbose.
@@ -2708,6 +2711,45 @@  dwarf2_get_dwz_file (struct dwarf2_per_objfile *dwarf2_per_objfile)
   if (dwz_bfd == NULL)
     dwz_bfd = build_id_to_debug_bfd (buildid_len, buildid);
 
+#if HAVE_LIBDEBUGINFOD
+  if (dwz_bfd == NULL)
+    {
+      /* Query debuginfod servers for the dwz file.  */
+      char *alt_filename;
+      debuginfod_client *client;
+
+      client = debuginfod_begin ();
+      if (client != NULL)
+        {
+          /* Allow debuginfod to abort the download if SIGINT is raised.  */
+          debuginfod_set_progressfn(
+            client,
+            [] (debuginfod_client *c, long a, long b)
+              { return 1 ? check_quit_flag () : 0; }
+          );
+
+          /* Query debuginfod servers for symfile.  */
+          scoped_fd fd (debuginfod_find_debuginfo (client,
+                                                   buildid,
+                                                   buildid_len,
+                                                   &alt_filename));
+          debuginfod_end (client);
+
+          if (fd.get () >= 0)
+            {
+              /* File successfully retrieved from server.  */
+              dwz_bfd = gdb_bfd_open (alt_filename, gnutarget, -1);
+
+              if (dwz_bfd != NULL
+                  && !build_id_verify (dwz_bfd.get (), buildid_len, buildid))
+                dwz_bfd.reset (nullptr);
+
+              xfree (alt_filename);
+            }
+        }
+    }
+#endif /* HAVE_LIBDEBUGINFOD */
+
   if (dwz_bfd == NULL)
     error (_("could not find '.gnu_debugaltlink' file for %s"),
 	   objfile_name (dwarf2_per_objfile->objfile));
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 618e4cd566..fbf2e4d34f 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -49,6 +49,10 @@ 
 #include "mdebugread.h"
 #include "ctfread.h"
 #include "gdbsupport/gdb_string_view.h"
+#include "gdbsupport/scoped_fd.h"
+#if HAVE_LIBDEBUGINFOD
+#include <elfutils/debuginfod.h>
+#endif
 
 /* Forward declarations.  */
 extern const struct sym_fns elf_sym_fns_gdb_index;
@@ -1311,8 +1315,47 @@  elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
 	  symbol_file_add_separate (debug_bfd.get (), debugfile.c_str (),
 				    symfile_flags, objfile);
 	}
-	else
-	  has_dwarf2 = false;
+      else
+        {
+          has_dwarf2 = false;
+
+#if HAVE_LIBDEBUGINFOD
+          const struct bfd_build_id *build_id;
+          char *symfile_path;
+          debuginfod_client *client;
+
+          client = debuginfod_begin ();
+          if (client != NULL)
+            {
+              build_id = build_id_bfd_get (objfile->obfd);
+
+              /* Allow debuginfod to abort the download if SIGINT is raised.  */
+              debuginfod_set_progressfn (
+                client,
+                [] (debuginfod_client *c, long a, long b)
+                  { return 1 ? check_quit_flag () : 0; }
+              );
+
+              /* Query debuginfod servers for symfile.  */
+              scoped_fd fd (debuginfod_find_debuginfo (client,
+                                                       build_id->data,
+                                                       build_id->size,
+                                                       &symfile_path));
+              debuginfod_end (client);
+
+              if (fd.get () >= 0)
+                {
+                  /* File successfully retrieved from server.  */
+                  gdb_bfd_ref_ptr debug_bfd (symfile_bfd_open (symfile_path));
+
+                  symbol_file_add_separate (debug_bfd.get (), symfile_path,
+                                            symfile_flags, objfile);
+                  xfree (symfile_path);
+                  has_dwarf2 = true;
+                }
+            }
+#endif /* LIBDEBUGINFOD */
+        }
     }
 
   /* Read the CTF section only if there is no DWARF info.  */
diff --git a/gdb/source.c b/gdb/source.c
index 1bc98d376e..3cdd306b99 100644
--- a/gdb/source.c
+++ b/gdb/source.c
@@ -48,6 +48,11 @@ 
 #include "source-cache.h"
 #include "cli/cli-style.h"
 #include "observable.h"
+#include "build-id.h"
+#ifdef HAVE_LIBDEBUGINFOD
+#include <elfutils/debuginfod.h>
+#endif
+
 
 #define OPEN_MODE (O_RDONLY | O_BINARY)
 #define FDOPEN_MODE FOPEN_RB
@@ -1153,6 +1158,62 @@  open_source_file (struct symtab *s)
   s->fullname = NULL;
   scoped_fd fd = find_and_open_source (s->filename, SYMTAB_DIRNAME (s),
 				       &fullname);
+
+#if HAVE_LIBDEBUGINFOD
+  if (fd.get () < 0)
+    {
+      if (SYMTAB_COMPUNIT (s) != NULL)
+        {
+          const struct bfd_build_id *build_id;
+          const objfile *ofp = COMPUNIT_OBJFILE (SYMTAB_COMPUNIT (s));
+
+          std::string srcpath;
+          if (IS_DIR_SEPARATOR (s->filename[0]))
+            srcpath = s->filename;
+          else
+            {
+              srcpath = SYMTAB_DIRNAME (s);
+              srcpath += SLASH_STRING;
+              srcpath += s->filename;
+            }
+
+          build_id = build_id_bfd_get (ofp->obfd);
+
+          /* Query debuginfod for the source file.  */
+          if (build_id != NULL)
+            {
+              char *name_in_cache;
+              debuginfod_client *client;
+
+              client = debuginfod_begin ();
+              if (client != NULL)
+                {
+
+                  /* Allow debuginfod to abort the download if SIGINT is raised.  */
+                  debuginfod_set_progressfn(
+                    client,
+                    [] (debuginfod_client *c, long a, long b)
+                      { return 1 ? check_quit_flag () : 0; }
+                  );
+
+                  scoped_fd src_fd (debuginfod_find_source (client,
+                                                            build_id->data,
+                                                            build_id->size,
+                                                            srcpath.c_str (),
+                                                            &name_in_cache));
+                  debuginfod_end (client);
+
+                  if (src_fd.get () >= 0)
+                    fullname.reset (name_in_cache);
+
+                  s->fullname = fullname.release ();
+                  return src_fd;
+                }
+            }
+        }
+    }
+#endif /* HAVE_LIBDEBUGINFOD */
+
   s->fullname = fullname.release ();
   return fd;
 }
diff --git a/gdb/testsuite/gdb.debuginfod/fetch_src_and_symbols.exp b/gdb/testsuite/gdb.debuginfod/fetch_src_and_symbols.exp
new file mode 100644
index 0000000000..6d1317bff7
--- /dev/null
+++ b/gdb/testsuite/gdb.debuginfod/fetch_src_and_symbols.exp
@@ -0,0 +1,221 @@ 
+# Copyright 2010-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, see <http://www.gnu.org/licenses/>.
+
+# test debuginfod functionality
+
+set test "debuginfod"
+
+standard_testfile main.c
+
+load_lib dwarf.exp
+
+if { [which debuginfod] == 0 } {
+    untested "$test (cannot find debuginfod)"
+    return -1
+}
+
+if { [which curl] == 0 } {
+    untested "$test (cannot find curl)"
+    return -1
+}
+
+# skip testing if gdb was not configured with debuginfod
+if { [string first "with-debuginfod" [exec $GDB --configuration]] == -1 } {
+    untested "$test (gdb not configured with debuginfod)"
+    return -1
+}
+
+set cache [file join [standard_output_file {}] ".client_cache"]
+
+# make sure there isn't an old client cache lying around
+file delete -force $cache
+
+# make a copy source file that we can move around
+if { [catch {file copy -force ${srcdir}/${subdir}/${srcfile} \
+                              [standard_output_file tmp-${srcfile}]}] != 0 } {
+    error "$test (create temporary file)"
+    return -1
+}
+
+set sourcetmp [standard_output_file tmp-${srcfile}]
+set outputdir [standard_output_file {}]
+
+if { [gdb_compile "$sourcetmp" "$binfile" executable {debug}] != "" } {
+    fail "$test (compile)"
+    return -1
+}
+
+# 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"]
+
+set ::env(DEBUGINFOD_URLS) http://127.0.0.1:$port
+set ::env(DEBUGINFOD_TIMEOUT) 30
+set ::env(DEBUGINFOD_CACHE_PATH) $cache
+
+# test that gdb cannot find source without debuginfod
+gdb_start
+gdb_load $binfile
+gdb_test_no_output "set substitute-path $outputdir /dev/null"
+gdb_test "list" ".*Connection refused.*"
+gdb_exit
+
+# strip symbols into separate file and move it so gdb cannot find it without debuginfod
+if { [gdb_gnu_strip_debug $binfile ""] != 0 } {
+    fail "$test (strip debuginfo)"
+    return -1
+}
+
+set debugdir [file join [standard_output_file {}] "debug"]
+set debuginfo [file join [standard_output_file {}] "fetch_src_and_symbols.debug"]
+
+file mkdir $debugdir
+file rename -force $debuginfo $debugdir
+
+# test that gdb cannot find symbols without debuginfod
+gdb_start
+gdb_load $binfile
+gdb_test "file" ".*No symbol file.*"
+gdb_exit
+
+# Write some assembly that just has a .gnu_debugaltlink section.
+# Copied from testsuite/gdb.dwarf2/dwzbuildid.exp.
+proc write_just_debugaltlink {filename dwzname buildid} {
+    set asm_file [standard_output_file $filename]
+
+    Dwarf::assemble $asm_file {
+        upvar dwzname dwzname
+        upvar buildid buildid
+
+        gnu_debugaltlink $dwzname $buildid
+
+        # Only the DWARF reader checks .gnu_debugaltlink, so make sure
+        # there is a bit of DWARF in here.
+        cu {} {
+            compile_unit {{language @DW_LANG_C}} {
+            }
+        }
+    }
+}
+
+# Write some DWARF that also sets the buildid.
+# Copied from testsuite/gdb.dwarf2/dwzbuildid.exp.
+proc write_dwarf_file {filename buildid {value 99}} {
+    set asm_file [standard_output_file $filename]
+
+    Dwarf::assemble $asm_file {
+        declare_labels int_label int_label2
+
+        upvar buildid buildid
+        upvar value value
+
+        build_id $buildid
+
+        cu {} {
+            compile_unit {{language @DW_LANG_C}} {
+                int_label2: base_type {
+                    {name int}
+                    {byte_size 4 sdata}
+                    {encoding @DW_ATE_signed}
+                }
+
+                constant {
+                    {name the_int}
+                    {type :$int_label2}
+                    {const_value $value data1}
+                }
+            }
+        }
+    }
+}
+
+set buildid "01234567890abcedf0123456"
+
+write_just_debugaltlink ${binfile}_has_altlink.S ${binfile}_dwz.o $buildid
+write_dwarf_file ${binfile}_dwz.S $buildid
+
+if {[gdb_compile ${binfile}_has_altlink.S ${binfile}_alt.o object nodebug] != ""} {
+    fail "$test (compile main with altlink)"
+    return -1
+}
+
+if {[gdb_compile ${binfile}_dwz.S ${binfile}_dwz.o object nodebug] != ""} {
+    fail "$test (compile altlink)"
+    return -1
+}
+
+file rename -force ${binfile}_dwz.o $debugdir
+
+# Test that gdb cannot find dwz without debuginfod.
+gdb_start
+gdb_test "file ${binfile}_alt.o" ".*could not find '.gnu_debugaltlink'.*"
+gdb_exit
+
+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 up debuginfod
+set debuginfod_pid [exec debuginfod -p $port -F $debugdir 2>/dev/null &]
+
+if { !$debuginfod_pid } {
+    fail "$test (server init)"
+    return -1
+}
+
+# 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 -1
+}
+
+# gdb should now find the symbol and source files
+gdb_start
+gdb_load $binfile
+gdb_test_no_output "set substitute-path $outputdir /dev/null"
+gdb_test "br main" "Breakpoint 1 at.*file.*"
+gdb_test "l" ".*This program is distributed in the hope.*"
+gdb_exit
+
+# gdb should now find the debugaltlink file
+gdb_start
+gdb_test "file ${binfile}_alt.o" ".*Reading symbols from ${binfile}_alt.o\.\.\.\[\r\n\]"
+gdb_exit
+
+file delete -force $cache
+catch {exec kill -INT $debuginfod_pid}
diff --git a/gdb/testsuite/gdb.debuginfod/main.c b/gdb/testsuite/gdb.debuginfod/main.c
new file mode 100644
index 0000000000..7d53f8020f
--- /dev/null
+++ b/gdb/testsuite/gdb.debuginfod/main.c
@@ -0,0 +1,25 @@ 
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2004-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, see <http://www.gnu.org/licenses/>.  */
+
+/* Dummy main function.  */
+
+int
+main()
+{
+  asm ("main_label: .globl main_label");
+  return 0;
+}
diff --git a/gdb/top.c b/gdb/top.c
index 3b93683cfa..c6e702bb35 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -1528,6 +1528,16 @@  This GDB was configured as follows:\n\
 "));
 #endif
 
+#if HAVE_LIBDEBUGINFOD
+  fprintf_filtered (stream, _("\
+             --with-debuginfod\n\
+"));
+#else
+   fprintf_filtered (stream, _("\
+             --without-debuginfod\n\
+"));
+#endif
+
 #if HAVE_GUILE
   fprintf_filtered (stream, _("\
              --with-guile\n\
-- 
2.23.0