db493ec
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
db493ec
From: Keith Seitz <keiths@redhat.com>
db493ec
Date: Tue, 9 Jun 2020 08:29:41 -0700
db493ec
Subject: gdb-rhbz1838777-debuginfod.patch
db493ec
db493ec
;; Backport debuginofd support.
db493ec
;; (Aaron Merey, RH BZ 183877)
db493ec
db493ec
commit 0d79cdc494d5eb9db26a602d62c92d49f83f407e
db493ec
Author: Aaron Merey <amerey@redhat.com>
db493ec
Date:   Wed Feb 26 17:40:49 2020 -0500
db493ec
db493ec
    Add debuginfod support to GDB
db493ec
db493ec
    debuginfod is a lightweight web service that indexes ELF/DWARF debugging
db493ec
    resources by build-id and serves them over HTTP.
db493ec
db493ec
    This patch enables GDB to query debuginfod servers for separate debug
db493ec
    files and source code when it is otherwise not able to find them.
db493ec
db493ec
    GDB can be built with debuginfod using the --with-debuginfod configure
db493ec
    option.
db493ec
db493ec
    This requires that libdebuginfod be installed and found at configure time.
db493ec
db493ec
    debuginfod is packaged with elfutils, starting with version 0.178.
db493ec
db493ec
    For more information see https://sourceware.org/elfutils/.
db493ec
db493ec
    Tested on x86_64 Fedora 31.
db493ec
db493ec
    gdb/ChangeLog:
db493ec
    2020-02-26  Aaron Merey  <amerey@redhat.com>
db493ec
db493ec
            * Makefile.in: Handle optional debuginfod support.
db493ec
            * NEWS: Update.
db493ec
            * README: Add --with-debuginfod summary.
db493ec
            * config.in: Regenerate.
db493ec
            * configure: Regenerate.
db493ec
            * configure.ac: Handle optional debuginfod support.
db493ec
            * debuginfod-support.c: debuginfod helper functions.
db493ec
            * debuginfod-support.h: Ditto.
db493ec
            * doc/gdb.texinfo: Add --with-debuginfod to configure options
db493ec
            summary.
db493ec
            * dwarf2/read.c (dwarf2_get_dwz_file): Query debuginfod servers
db493ec
            when a dwz file cannot be found.
db493ec
            * elfread.c (elf_symfile_read): Query debuginfod servers when a
db493ec
            debuginfo file cannot be found.
db493ec
            * source.c (open_source_file): Query debuginfod servers when a
db493ec
            source file cannot be found.
db493ec
            * top.c (print_gdb_configuration): Include
db493ec
            --{with,without}-debuginfod in the output.
db493ec
db493ec
    gdb/testsuite/ChangeLog:
db493ec
    2020-02-26  Aaron Merey  <amerey@redhat.com>
db493ec
db493ec
            * gdb.debuginfod: New directory for debuginfod tests.
db493ec
            * gdb.debuginfod/main.c: New test file.
db493ec
            * gdb.debuginfod/fetch_src_and_symbols.exp: New tests.
db493ec
db493ec
diff --git a/config/debuginfod.m4 b/config/debuginfod.m4
db493ec
new file mode 100644
db493ec
--- /dev/null
db493ec
+++ b/config/debuginfod.m4
db493ec
@@ -0,0 +1,38 @@
db493ec
+dnl Copyright (C) 1997-2019 Free Software Foundation, Inc.
db493ec
+dnl This file is free software, distributed under the terms of the GNU
db493ec
+dnl General Public License.  As a special exception to the GNU General
db493ec
+dnl Public License, this file may be distributed as part of a program
db493ec
+dnl that contains a configuration script generated by Autoconf, under
db493ec
+dnl the same distribution terms as the rest of that program.
db493ec
+
db493ec
+AC_DEFUN([AC_DEBUGINFOD],
db493ec
+[
db493ec
+# Enable debuginfod
db493ec
+AC_ARG_WITH([debuginfod],
db493ec
+        AC_HELP_STRING([--with-debuginfod],
db493ec
+                       [Enable debuginfo lookups with debuginfod (auto/yes/no)]),
db493ec
+        [], [with_debuginfod=auto])
db493ec
+AC_MSG_CHECKING([whether to use debuginfod])
db493ec
+AC_MSG_RESULT([$with_debuginfod])
db493ec
+
db493ec
+if test "${with_debuginfod}" = no; then
db493ec
+  AC_MSG_WARN([debuginfod support disabled; some features may be unavailable.])
db493ec
+else
db493ec
+  AC_CHECK_LIB([debuginfod], [debuginfod_begin], [have_debuginfod_lib=yes])
db493ec
+  AC_CHECK_DECL([debuginfod_begin], [have_debuginfod_h=yes], [],
db493ec
+                [#include <elfutils/debuginfod.h>])
db493ec
+  if test "x$have_debuginfod_lib" = "xyes" -a \
db493ec
+          "x$have_debuginfod_h" = "xyes"; then
db493ec
+    AC_DEFINE([HAVE_LIBDEBUGINFOD], [1],
db493ec
+              [Define to 1 if debuginfod is enabled.])
db493ec
+    AC_SUBST([LIBDEBUGINFOD], ["-ldebuginfod"])
db493ec
+  else
db493ec
+    AC_SUBST([LIBDEBUGINFOD], [])
db493ec
+    if test "$with_debuginfod" = yes; then
db493ec
+      AC_MSG_ERROR([debuginfod is missing or unusable])
db493ec
+    else
db493ec
+      AC_MSG_WARN([debuginfod is missing or unusable; some features may be unavailable.])
db493ec
+    fi
db493ec
+  fi
db493ec
+fi
db493ec
+])
db493ec
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
db493ec
--- a/gdb/Makefile.in
db493ec
+++ b/gdb/Makefile.in
db493ec
@@ -612,7 +612,8 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(LIBCTF) $(ZLIB) \
db493ec
 	@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
db493ec
 	$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
db493ec
 	$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR) \
db493ec
-	$(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS)
db493ec
+	$(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) \
db493ec
+	@LIBDEBUGINFOD@
db493ec
 CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) $(LIBCTF) \
db493ec
 	$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
db493ec
 
db493ec
@@ -1016,6 +1017,7 @@ COMMON_SFILES = \
db493ec
 	dbxread.c \
db493ec
 	dcache.c \
db493ec
 	debug.c \
db493ec
+	debuginfod-support.c \
db493ec
 	dictionary.c \
db493ec
 	disasm.c \
db493ec
 	disasm-selftests.c \
db493ec
diff --git a/gdb/NEWS b/gdb/NEWS
db493ec
--- a/gdb/NEWS
db493ec
+++ b/gdb/NEWS
db493ec
@@ -932,6 +932,20 @@ SH-5/SH64 running OpenBSD 	SH-5/SH64 support in sh*-*-openbsd*
db493ec
      manual for a further description of this feature.
db493ec
 
db493ec
 
db493ec
+* GDB now supports debuginfod, an HTTP server for distributing ELF/DWARF
db493ec
+  debugging information as well as source code.
db493ec
+
db493ec
+  When built with debuginfod, GDB can automatically query debuginfod
db493ec
+  servers for the separate debug files and source code of the executable
db493ec
+  being debugged.
db493ec
+
db493ec
+  To build GDB with debuginfod, pass --with-debuginfod to configure (this
db493ec
+  requires libdebuginfod, the debuginfod client library).
db493ec
+
db493ec
+  debuginfod is distributed with elfutils, starting with version 0.178.
db493ec
+
db493ec
+  You can get the latest version from https://sourceware.org/elfutils.
db493ec
+
db493ec
 * New features in the GDB remote stub, GDBserver
db493ec
 
db493ec
   ** GDBserver is now able to start inferior processes with a
db493ec
diff --git a/gdb/README b/gdb/README
db493ec
--- a/gdb/README
db493ec
+++ b/gdb/README
db493ec
@@ -432,6 +432,15 @@ more obscure GDB `configure' options are not listed here.
db493ec
      Use the curses library instead of the termcap library, for
db493ec
      text-mode terminal operations.
db493ec
 
db493ec
+`--with-debuginfod'
db493ec
+     Build GDB with libdebuginfod, the debuginfod client library.  Used
db493ec
+     to automatically fetch source files and separate debug files from
db493ec
+     debuginfod servers using the associated executable's build ID.
db493ec
+     Enabled by default if libdebuginfod is installed and found at
db493ec
+     configure time.  debuginfod is packaged with elfutils, starting
db493ec
+     with version 0.178.  You can get the latest version from
db493ec
+     'https://sourceware.org/elfutils/'.
db493ec
+
db493ec
 `--with-libunwind-ia64'
db493ec
      Use the libunwind library for unwinding function call stack on ia64
db493ec
      target platforms.
db493ec
diff --git a/gdb/config.in b/gdb/config.in
db493ec
--- a/gdb/config.in
db493ec
+++ b/gdb/config.in
db493ec
@@ -230,6 +230,9 @@
db493ec
 /* Define if you have the babeltrace library. */
db493ec
 #undef HAVE_LIBBABELTRACE
db493ec
 
db493ec
+/* Define to 1 if debuginfod is enabled. */
db493ec
+#undef HAVE_LIBDEBUGINFOD
db493ec
+
db493ec
 /* Define if you have the expat library. */
db493ec
 #undef HAVE_LIBEXPAT
db493ec
 
db493ec
diff --git a/gdb/configure b/gdb/configure
db493ec
--- a/gdb/configure
db493ec
+++ b/gdb/configure
db493ec
@@ -758,6 +758,7 @@ REPORT_BUGS_TEXI
db493ec
 REPORT_BUGS_TO
db493ec
 PKGVERSION
db493ec
 CODESIGN_CERT
db493ec
+LIBDEBUGINFOD
db493ec
 HAVE_NATIVE_GCORE_TARGET
db493ec
 TARGET_OBS
db493ec
 subdirs
db493ec
@@ -875,6 +876,7 @@ enable_64_bit_bfd
db493ec
 enable_gdbmi
db493ec
 enable_tui
db493ec
 enable_gdbtk
db493ec
+with_debuginfod
db493ec
 with_libunwind_ia64
db493ec
 with_curses
db493ec
 enable_profiling
db493ec
@@ -1611,6 +1613,8 @@ Optional Packages:
db493ec
                           do not restrict auto-loaded files locations
db493ec
   --with-rpm              query rpm database for missing debuginfos (yes/no,
db493ec
                           def. auto=librpm.so)
db493ec
+  --with-debuginfod       Enable debuginfo lookups with debuginfod
db493ec
+                          (auto/yes/no)
db493ec
   --with-libunwind-ia64   use libunwind frame unwinding for ia64 targets
db493ec
   --with-curses           use the curses library instead of the termcap
db493ec
                           library
db493ec
@@ -2271,6 +2275,52 @@ rm -f conftest.val
db493ec
 
db493ec
 } # ac_fn_c_compute_int
db493ec
 
db493ec
+# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
db493ec
+# ---------------------------------------------
db493ec
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
db493ec
+# accordingly.
db493ec
+ac_fn_c_check_decl ()
db493ec
+{
db493ec
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
db493ec
+  as_decl_name=`echo $2|sed 's/ *(.*//'`
db493ec
+  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
db493ec
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
db493ec
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
db493ec
+if eval \${$3+:} false; then :
db493ec
+  $as_echo_n "(cached) " >&6
db493ec
+else
db493ec
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
db493ec
+/* end confdefs.h.  */
db493ec
+$4
db493ec
+int
db493ec
+main ()
db493ec
+{
db493ec
+#ifndef $as_decl_name
db493ec
+#ifdef __cplusplus
db493ec
+  (void) $as_decl_use;
db493ec
+#else
db493ec
+  (void) $as_decl_name;
db493ec
+#endif
db493ec
+#endif
db493ec
+
db493ec
+  ;
db493ec
+  return 0;
db493ec
+}
db493ec
+_ACEOF
db493ec
+if ac_fn_c_try_compile "$LINENO"; then :
db493ec
+  eval "$3=yes"
db493ec
+else
db493ec
+  eval "$3=no"
db493ec
+fi
db493ec
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
db493ec
+fi
db493ec
+eval ac_res=\$$3
db493ec
+	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
db493ec
+$as_echo "$ac_res" >&6; }
db493ec
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
db493ec
+
db493ec
+} # ac_fn_c_check_decl
db493ec
+
db493ec
 # ac_fn_c_check_func LINENO FUNC VAR
db493ec
 # ----------------------------------
db493ec
 # Tests whether FUNC exists, setting the cache variable VAR accordingly
db493ec
@@ -2449,52 +2499,6 @@ $as_echo "$ac_res" >&6; }
db493ec
 
db493ec
 } # ac_fn_c_check_type
db493ec
 
db493ec
-# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
db493ec
-# ---------------------------------------------
db493ec
-# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
db493ec
-# accordingly.
db493ec
-ac_fn_c_check_decl ()
db493ec
-{
db493ec
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
db493ec
-  as_decl_name=`echo $2|sed 's/ *(.*//'`
db493ec
-  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
db493ec
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
db493ec
-$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
db493ec
-if eval \${$3+:} false; then :
db493ec
-  $as_echo_n "(cached) " >&6
db493ec
-else
db493ec
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
db493ec
-/* end confdefs.h.  */
db493ec
-$4
db493ec
-int
db493ec
-main ()
db493ec
-{
db493ec
-#ifndef $as_decl_name
db493ec
-#ifdef __cplusplus
db493ec
-  (void) $as_decl_use;
db493ec
-#else
db493ec
-  (void) $as_decl_name;
db493ec
-#endif
db493ec
-#endif
db493ec
-
db493ec
-  ;
db493ec
-  return 0;
db493ec
-}
db493ec
-_ACEOF
db493ec
-if ac_fn_c_try_compile "$LINENO"; then :
db493ec
-  eval "$3=yes"
db493ec
-else
db493ec
-  eval "$3=no"
db493ec
-fi
db493ec
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
db493ec
-fi
db493ec
-eval ac_res=\$$3
db493ec
-	       { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
db493ec
-$as_echo "$ac_res" >&6; }
db493ec
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
db493ec
-
db493ec
-} # ac_fn_c_check_decl
db493ec
-
db493ec
 # ac_fn_cxx_try_link LINENO
db493ec
 # -------------------------
db493ec
 # Try to link conftest.$ac_ext, and return whether this succeeded.
db493ec
@@ -6658,8 +6662,8 @@ $as_echo_n "checking specific librpm version... " >&6; }
db493ec
   if test "$cross_compiling" = yes; then :
db493ec
   { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
db493ec
 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
db493ec
-as_fn_error "cannot run test program while cross compiling
db493ec
-See \`config.log' for more details." "$LINENO" 5; }
db493ec
+as_fn_error $? "cannot run test program while cross compiling
db493ec
+See \`config.log' for more details" "$LINENO" 5; }
db493ec
 else
db493ec
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
db493ec
 /* end confdefs.h.  */
db493ec
@@ -6830,7 +6834,7 @@ $as_echo "#define HAVE_LIBRPM 1" >>confdefs.h
db493ec
 $as_echo "no" >&6; }
db493ec
     LIBS="$save_LIBS"
db493ec
     if $DLOPEN_REQUIRE; then
db493ec
-      as_fn_error "Specific name $LIBRPM was requested but it could not be opened." "$LINENO" 5
db493ec
+      as_fn_error $? "Specific name $LIBRPM was requested but it could not be opened." "$LINENO" 5
db493ec
     fi
db493ec
 
db493ec
 
db493ec
@@ -6845,7 +6849,7 @@ if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
db493ec
 set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
db493ec
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
db493ec
 $as_echo_n "checking for $ac_word... " >&6; }
db493ec
-if test "${ac_cv_path_PKG_CONFIG+set}" = set; then :
db493ec
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
db493ec
   $as_echo_n "(cached) " >&6
db493ec
 else
db493ec
   case $PKG_CONFIG in
db493ec
@@ -6859,7 +6863,7 @@ do
db493ec
   IFS=$as_save_IFS
db493ec
   test -z "$as_dir" && as_dir=.
db493ec
     for ac_exec_ext in '' $ac_executable_extensions; do
db493ec
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
db493ec
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
db493ec
     ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
db493ec
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
db493ec
     break 2
db493ec
@@ -6888,7 +6892,7 @@ if test -z "$ac_cv_path_PKG_CONFIG"; then
db493ec
 set dummy pkg-config; ac_word=$2
db493ec
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
db493ec
 $as_echo_n "checking for $ac_word... " >&6; }
db493ec
-if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then :
db493ec
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
db493ec
   $as_echo_n "(cached) " >&6
db493ec
 else
db493ec
   case $ac_pt_PKG_CONFIG in
db493ec
@@ -6902,7 +6906,7 @@ do
db493ec
   IFS=$as_save_IFS
db493ec
   test -z "$as_dir" && as_dir=.
db493ec
     for ac_exec_ext in '' $ac_executable_extensions; do
db493ec
-  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
db493ec
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
db493ec
     ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
db493ec
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
db493ec
     break 2
db493ec
@@ -7086,7 +7090,7 @@ $as_echo "#define HAVE_LIBRPM 1" >>confdefs.h
db493ec
       LIBS="$LIBS $RPM_LIBS"
db493ec
     else
db493ec
       if $RPM_REQUIRE; then
db493ec
-	as_fn_error "$RPM_PKG_ERRORS" "$LINENO" 5
db493ec
+	as_fn_error $? "$RPM_PKG_ERRORS" "$LINENO" 5
db493ec
       else
db493ec
 	{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $RPM_PKG_ERRORS" >&5
db493ec
 $as_echo "$as_me: WARNING: $RPM_PKG_ERRORS" >&2;}
db493ec
@@ -7332,8 +7336,92 @@ $as_echo "$as_me: WARNING: gdbtk isn't supported on $host; disabling" >&2;}
db493ec
     enable_gdbtk=no ;;
db493ec
 esac
db493ec
 
db493ec
-# Libunwind support for ia64.
db493ec
+# Handle optional debuginfod support
db493ec
+
db493ec
+# Enable debuginfod
db493ec
+
db493ec
+# Check whether --with-debuginfod was given.
db493ec
+if test "${with_debuginfod+set}" = set; then :
db493ec
+  withval=$with_debuginfod;
db493ec
+else
db493ec
+  with_debuginfod=auto
db493ec
+fi
db493ec
+
db493ec
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use debuginfod" >&5
db493ec
+$as_echo_n "checking whether to use debuginfod... " >&6; }
db493ec
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_debuginfod" >&5
db493ec
+$as_echo "$with_debuginfod" >&6; }
db493ec
+
db493ec
+if test "${with_debuginfod}" = no; then
db493ec
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: debuginfod support disabled; some features may be unavailable." >&5
db493ec
+$as_echo "$as_me: WARNING: debuginfod support disabled; some features may be unavailable." >&2;}
db493ec
+else
db493ec
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for debuginfod_begin in -ldebuginfod" >&5
db493ec
+$as_echo_n "checking for debuginfod_begin in -ldebuginfod... " >&6; }
db493ec
+if ${ac_cv_lib_debuginfod_debuginfod_begin+:} false; then :
db493ec
+  $as_echo_n "(cached) " >&6
db493ec
+else
db493ec
+  ac_check_lib_save_LIBS=$LIBS
db493ec
+LIBS="-ldebuginfod  $LIBS"
db493ec
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
db493ec
+/* end confdefs.h.  */
db493ec
+
db493ec
+/* Override any GCC internal prototype to avoid an error.
db493ec
+   Use char because int might match the return type of a GCC
db493ec
+   builtin and then its argument prototype would still apply.  */
db493ec
+#ifdef __cplusplus
db493ec
+extern "C"
db493ec
+#endif
db493ec
+char debuginfod_begin ();
db493ec
+int
db493ec
+main ()
db493ec
+{
db493ec
+return debuginfod_begin ();
db493ec
+  ;
db493ec
+  return 0;
db493ec
+}
db493ec
+_ACEOF
db493ec
+if ac_fn_c_try_link "$LINENO"; then :
db493ec
+  ac_cv_lib_debuginfod_debuginfod_begin=yes
db493ec
+else
db493ec
+  ac_cv_lib_debuginfod_debuginfod_begin=no
db493ec
+fi
db493ec
+rm -f core conftest.err conftest.$ac_objext \
db493ec
+    conftest$ac_exeext conftest.$ac_ext
db493ec
+LIBS=$ac_check_lib_save_LIBS
db493ec
+fi
db493ec
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_debuginfod_debuginfod_begin" >&5
db493ec
+$as_echo "$ac_cv_lib_debuginfod_debuginfod_begin" >&6; }
db493ec
+if test "x$ac_cv_lib_debuginfod_debuginfod_begin" = xyes; then :
db493ec
+  have_debuginfod_lib=yes
db493ec
+fi
db493ec
+
db493ec
+  ac_fn_c_check_decl "$LINENO" "debuginfod_begin" "ac_cv_have_decl_debuginfod_begin" "#include <elfutils/debuginfod.h>
db493ec
+"
db493ec
+if test "x$ac_cv_have_decl_debuginfod_begin" = xyes; then :
db493ec
+  have_debuginfod_h=yes
db493ec
+fi
db493ec
+
db493ec
+  if test "x$have_debuginfod_lib" = "xyes" -a \
db493ec
+          "x$have_debuginfod_h" = "xyes"; then
db493ec
+
db493ec
+$as_echo "#define HAVE_LIBDEBUGINFOD 1" >>confdefs.h
db493ec
+
db493ec
+    LIBDEBUGINFOD="-ldebuginfod"
db493ec
 
db493ec
+  else
db493ec
+
db493ec
+    if test "$with_debuginfod" = yes; then
db493ec
+      as_fn_error $? "debuginfod is missing or unusable" "$LINENO" 5
db493ec
+    else
db493ec
+      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: debuginfod is missing or unusable; some features may be unavailable." >&5
db493ec
+$as_echo "$as_me: WARNING: debuginfod is missing or unusable; some features may be unavailable." >&2;}
db493ec
+    fi
db493ec
+  fi
db493ec
+fi
db493ec
+
db493ec
+
db493ec
+# Libunwind support for ia64.
db493ec
 
db493ec
 # Check whether --with-libunwind-ia64 was given.
db493ec
 if test "${with_libunwind_ia64+set}" = set; then :
db493ec
@@ -16441,7 +16529,7 @@ _ACEOF
db493ec
 for ac_header in selinux/selinux.h
db493ec
 do :
db493ec
   ac_fn_c_check_header_mongrel "$LINENO" "selinux/selinux.h" "ac_cv_header_selinux_selinux_h" "$ac_includes_default"
db493ec
-if test "x$ac_cv_header_selinux_selinux_h" = x""yes; then :
db493ec
+if test "x$ac_cv_header_selinux_selinux_h" = xyes; then :
db493ec
   cat >>confdefs.h <<_ACEOF
db493ec
 #define HAVE_SELINUX_SELINUX_H 1
db493ec
 _ACEOF
db493ec
@@ -16452,7 +16540,7 @@ done
db493ec
 
db493ec
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for security_get_boolean_active in -lselinux" >&5
db493ec
 $as_echo_n "checking for security_get_boolean_active in -lselinux... " >&6; }
db493ec
-if test "${ac_cv_lib_selinux_security_get_boolean_active+set}" = set; then :
db493ec
+if ${ac_cv_lib_selinux_security_get_boolean_active+:} false; then :
db493ec
   $as_echo_n "(cached) " >&6
db493ec
 else
db493ec
   ac_check_lib_save_LIBS=$LIBS
db493ec
@@ -16486,7 +16574,7 @@ LIBS=$ac_check_lib_save_LIBS
db493ec
 fi
db493ec
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_selinux_security_get_boolean_active" >&5
db493ec
 $as_echo "$ac_cv_lib_selinux_security_get_boolean_active" >&6; }
db493ec
-if test "x$ac_cv_lib_selinux_security_get_boolean_active" = x""yes; then :
db493ec
+if test "x$ac_cv_lib_selinux_security_get_boolean_active" = xyes; then :
db493ec
   cat >>confdefs.h <<_ACEOF
db493ec
 #define HAVE_LIBSELINUX 1
db493ec
 _ACEOF
db493ec
diff --git a/gdb/configure.ac b/gdb/configure.ac
db493ec
--- a/gdb/configure.ac
db493ec
+++ b/gdb/configure.ac
db493ec
@@ -18,6 +18,8 @@ dnl along with this program.  If not, see <http://www.gnu.org/licenses/>.
db493ec
 
db493ec
 dnl Process this file with autoconf to produce a configure script.
db493ec
 
db493ec
+m4_include(../config/debuginfod.m4)
db493ec
+
db493ec
 AC_INIT(main.c)
db493ec
 AC_CONFIG_HEADERS(config.h:config.in, [echo > stamp-h])
db493ec
 AM_MAINTAINER_MODE
db493ec
@@ -516,8 +518,10 @@ case $host_os in
db493ec
     enable_gdbtk=no ;;
db493ec
 esac
db493ec
 
db493ec
-# Libunwind support for ia64.
db493ec
+# Handle optional debuginfod support
db493ec
+AC_DEBUGINFOD
db493ec
 
db493ec
+# Libunwind support for ia64.
db493ec
 AC_ARG_WITH(libunwind-ia64,
db493ec
 AS_HELP_STRING([--with-libunwind-ia64],
db493ec
 	       [use libunwind frame unwinding for ia64 targets]),,
db493ec
diff --git a/gdb/debuginfod-support.c b/gdb/debuginfod-support.c
db493ec
new file mode 100644
db493ec
--- /dev/null
db493ec
+++ b/gdb/debuginfod-support.c
db493ec
@@ -0,0 +1,155 @@
db493ec
+/* debuginfod utilities for GDB.
db493ec
+   Copyright (C) 2020 Free Software Foundation, Inc.
db493ec
+
db493ec
+   This file is part of GDB.
db493ec
+
db493ec
+   This program is free software; you can redistribute it and/or modify
db493ec
+   it under the terms of the GNU General Public License as published by
db493ec
+   the Free Software Foundation; either version 3 of the License, or
db493ec
+   (at your option) any later version.
db493ec
+
db493ec
+   This program is distributed in the hope that it will be useful,
db493ec
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
db493ec
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
db493ec
+   GNU General Public License for more details.
db493ec
+
db493ec
+   You should have received a copy of the GNU General Public License
db493ec
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
db493ec
+
db493ec
+#include "defs.h"
db493ec
+#include <errno.h>
db493ec
+#include "cli/cli-style.h"
db493ec
+#include "gdbsupport/scoped_fd.h"
db493ec
+#include "debuginfod-support.h"
db493ec
+
db493ec
+#ifndef HAVE_LIBDEBUGINFOD
db493ec
+scoped_fd
db493ec
+debuginfod_source_query (const unsigned char *build_id,
db493ec
+			 int build_id_len,
db493ec
+			 const char *srcpath,
db493ec
+			 gdb::unique_xmalloc_ptr<char> *destname)
db493ec
+{
db493ec
+  return scoped_fd (-ENOSYS);
db493ec
+}
db493ec
+
db493ec
+scoped_fd
db493ec
+debuginfod_debuginfo_query (const unsigned char *build_id,
db493ec
+			    int build_id_len,
db493ec
+			    const char *filename,
db493ec
+			    gdb::unique_xmalloc_ptr<char> *destname)
db493ec
+{
db493ec
+  return scoped_fd (-ENOSYS);
db493ec
+}
db493ec
+#else
db493ec
+#include <elfutils/debuginfod.h>
db493ec
+
db493ec
+/* TODO: Use debuginfod API extensions instead of these globals.  */
db493ec
+static std::string desc;
db493ec
+static std::string fname;
db493ec
+static bool has_printed;
db493ec
+
db493ec
+static int
db493ec
+progressfn (debuginfod_client *c, long cur, long total)
db493ec
+{
db493ec
+  if (check_quit_flag ())
db493ec
+    {
db493ec
+      printf_filtered ("Cancelling download of %s %ps...\n",
db493ec
+		       desc.c_str (),
db493ec
+		       styled_string (file_name_style.style (), fname.c_str ()));
db493ec
+      return 1;
db493ec
+    }
db493ec
+
db493ec
+  if (!has_printed && total != 0)
db493ec
+    {
db493ec
+      /* Print this message only once.  */
db493ec
+      has_printed = true;
db493ec
+      printf_filtered ("Downloading %s %ps...\n",
db493ec
+		       desc.c_str (),
db493ec
+		       styled_string (file_name_style.style (), fname.c_str ()));
db493ec
+    }
db493ec
+
db493ec
+  return 0;
db493ec
+}
db493ec
+
db493ec
+static debuginfod_client *
db493ec
+debuginfod_init ()
db493ec
+{
db493ec
+  debuginfod_client *c = debuginfod_begin ();
db493ec
+
db493ec
+  if (c != nullptr)
db493ec
+    debuginfod_set_progressfn (c, progressfn);
db493ec
+
db493ec
+  return c;
db493ec
+}
db493ec
+
db493ec
+/* See debuginfod-support.h  */
db493ec
+
db493ec
+scoped_fd
db493ec
+debuginfod_source_query (const unsigned char *build_id,
db493ec
+			 int build_id_len,
db493ec
+			 const char *srcpath,
db493ec
+			 gdb::unique_xmalloc_ptr<char> *destname)
db493ec
+{
db493ec
+  if (getenv (DEBUGINFOD_URLS_ENV_VAR) == NULL)
db493ec
+    return scoped_fd (-ENOSYS);
db493ec
+
db493ec
+  debuginfod_client *c = debuginfod_init ();
db493ec
+
db493ec
+  if (c == nullptr)
db493ec
+    return scoped_fd (-ENOMEM);
db493ec
+
db493ec
+  desc = std::string ("source file");
db493ec
+  fname = std::string (srcpath);
db493ec
+  has_printed = false;
db493ec
+
db493ec
+  scoped_fd fd (debuginfod_find_source (c,
db493ec
+					build_id,
db493ec
+					build_id_len,
db493ec
+					srcpath,
db493ec
+					nullptr));
db493ec
+
db493ec
+  /* TODO: Add 'set debug debuginfod' command to control when error messages are shown.  */
db493ec
+  if (fd.get () < 0 && fd.get () != -ENOENT)
db493ec
+    printf_filtered (_("Download failed: %s.  Continuing without source file %ps.\n"),
db493ec
+		     safe_strerror (-fd.get ()),
db493ec
+		     styled_string (file_name_style.style (),  srcpath));
db493ec
+  else
db493ec
+    destname->reset (xstrdup (srcpath));
db493ec
+
db493ec
+  debuginfod_end (c);
db493ec
+  return fd;
db493ec
+}
db493ec
+
db493ec
+/* See debuginfod-support.h  */
db493ec
+
db493ec
+scoped_fd
db493ec
+debuginfod_debuginfo_query (const unsigned char *build_id,
db493ec
+			    int build_id_len,
db493ec
+			    const char *filename,
db493ec
+			    gdb::unique_xmalloc_ptr<char> *destname)
db493ec
+{
db493ec
+  if (getenv (DEBUGINFOD_URLS_ENV_VAR) == NULL)
db493ec
+    return scoped_fd (-ENOSYS);
db493ec
+
db493ec
+  debuginfod_client *c = debuginfod_init ();
db493ec
+
db493ec
+  if (c == nullptr)
db493ec
+    return scoped_fd (-ENOMEM);
db493ec
+
db493ec
+  desc = std::string ("separate debug info for");
db493ec
+  fname = std::string (filename);
db493ec
+  has_printed = false;
db493ec
+  char *dname = nullptr;
db493ec
+
db493ec
+  scoped_fd fd (debuginfod_find_debuginfo (c, build_id, build_id_len, &dname));
db493ec
+
db493ec
+  if (fd.get () < 0 && fd.get () != -ENOENT)
db493ec
+    printf_filtered (_("Download failed: %s.  Continuing without debug info for %ps.\n"),
db493ec
+		     safe_strerror (-fd.get ()),
db493ec
+		     styled_string (file_name_style.style (),  filename));
db493ec
+
db493ec
+  destname->reset (dname);
db493ec
+  debuginfod_end (c);
db493ec
+  return fd;
db493ec
+}
db493ec
+#endif
db493ec
diff --git a/gdb/debuginfod-support.h b/gdb/debuginfod-support.h
db493ec
new file mode 100644
db493ec
--- /dev/null
db493ec
+++ b/gdb/debuginfod-support.h
db493ec
@@ -0,0 +1,62 @@
db493ec
+/* debuginfod utilities for GDB.
db493ec
+   Copyright (C) 2020 Free Software Foundation, Inc.
db493ec
+
db493ec
+   This file is part of GDB.
db493ec
+
db493ec
+   This program is free software; you can redistribute it and/or modify
db493ec
+   it under the terms of the GNU General Public License as published by
db493ec
+   the Free Software Foundation; either version 3 of the License, or
db493ec
+   (at your option) any later version.
db493ec
+
db493ec
+   This program is distributed in the hope that it will be useful,
db493ec
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
db493ec
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
db493ec
+   GNU General Public License for more details.
db493ec
+
db493ec
+   You should have received a copy of the GNU General Public License
db493ec
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
db493ec
+
db493ec
+#ifndef DEBUGINFOD_SUPPORT_H
db493ec
+#define DEBUGINFOD_SUPPORT_H
db493ec
+
db493ec
+/* Query debuginfod servers for a source file associated with an
db493ec
+   executable with BUILD_ID.  BUILD_ID can be given as a binary blob or
db493ec
+   a null-terminated string.  If given as a binary blob, BUILD_ID_LEN
db493ec
+   should be the number of bytes.  If given as a null-terminated string,
db493ec
+   BUILD_ID_LEN should be 0.
db493ec
+
db493ec
+   SRC_PATH should be the source file's absolute path that includes the
db493ec
+   compilation directory of the CU associated with the source file.
db493ec
+   For example if a CU's compilation directory is `/my/build` and the
db493ec
+   source file path is `/my/source/foo.c`, then SRC_PATH should be
db493ec
+   `/my/build/../source/foo.c`.
db493ec
+
db493ec
+   If the file is successfully retrieved, its path on the local machine
db493ec
+   is stored in DESTNAME.  If GDB is not built with debuginfod, this
db493ec
+   function returns -ENOSYS.  */
db493ec
+
db493ec
+extern scoped_fd
db493ec
+debuginfod_source_query (const unsigned char *build_id,
db493ec
+			 int build_id_len,
db493ec
+			 const char *src_path,
db493ec
+			 gdb::unique_xmalloc_ptr<char> *destname);
db493ec
+
db493ec
+/* Query debuginfod servers for a debug info file with BUILD_ID.
db493ec
+   BUILD_ID can be given as a binary blob or a null-terminated string.
db493ec
+   If given as a binary blob, BUILD_ID_LEN should be the number of bytes.
db493ec
+   If given as a null-terminated string, BUILD_ID_LEN should be 0.
db493ec
+
db493ec
+   FILENAME should be the name or path of the main binary associated with
db493ec
+   the separate debug info.  It is used for printing messages to the user.
db493ec
+
db493ec
+   If the file is successfully retrieved, its path on the local machine
db493ec
+   is stored in DESTNAME.  If GDB is not built with debuginfod, this
db493ec
+   function returns -ENOSYS.  */
db493ec
+
db493ec
+extern scoped_fd
db493ec
+debuginfod_debuginfo_query (const unsigned char *build_id,
db493ec
+			    int build_id_len,
db493ec
+			    const char *filename,
db493ec
+			    gdb::unique_xmalloc_ptr<char> *destname);
db493ec
+
db493ec
+#endif /* DEBUGINFOD_SUPPORT_H */
db493ec
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
db493ec
--- a/gdb/doc/gdb.texinfo
db493ec
+++ b/gdb/doc/gdb.texinfo
db493ec
@@ -37726,6 +37726,14 @@ supported).
db493ec
 Use the curses library instead of the termcap library, for text-mode
db493ec
 terminal operations.
db493ec
 
db493ec
+@item --with-debuginfod
db493ec
+Build @value{GDBN} with libdebuginfod, the debuginfod client library.
db493ec
+Used to automatically fetch source files and separate debug files from
db493ec
+debuginfod servers using the associated executable's build ID. Enabled
db493ec
+by default if libdebuginfod is installed and found at configure time.
db493ec
+debuginfod is packaged with elfutils, starting with version 0.178. You
db493ec
+can get the latest version from `https://sourceware.org/elfutils/'.
db493ec
+
db493ec
 @item --with-libunwind-ia64
db493ec
 Use the libunwind library for unwinding function call stack on ia64
db493ec
 target platforms.  See http://www.nongnu.org/libunwind/index.html for
db493ec
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
db493ec
--- a/gdb/dwarf2read.c
db493ec
+++ b/gdb/dwarf2read.c
db493ec
@@ -77,6 +77,7 @@
db493ec
 #include "gdbsupport/selftest.h"
db493ec
 #include "rust-lang.h"
db493ec
 #include "gdbsupport/pathstuff.h"
db493ec
+#include "debuginfod-support.h"
db493ec
 
db493ec
 /* When == 1, print basic high level tracing messages.
db493ec
    When > 1, be more verbose.
db493ec
@@ -2717,6 +2718,29 @@ dwarf2_get_dwz_file (struct dwarf2_per_objfile *dwarf2_per_objfile)
db493ec
 	dwz_bfd.reset (nullptr);
db493ec
     }
db493ec
 
db493ec
+  if (dwz_bfd == nullptr)
db493ec
+    {
db493ec
+      gdb::unique_xmalloc_ptr<char> alt_filename;
db493ec
+      const char *origname = dwarf2_per_objfile->objfile->original_name;
db493ec
+
db493ec
+      scoped_fd fd (debuginfod_debuginfo_query (buildid,
db493ec
+						buildid_len,
db493ec
+						origname,
db493ec
+						&alt_filename));
db493ec
+
db493ec
+      if (fd.get () >= 0)
db493ec
+	{
db493ec
+	  /* File successfully retrieved from server.  */
db493ec
+	  dwz_bfd = gdb_bfd_open (alt_filename.get (), gnutarget, -1);
db493ec
+
db493ec
+	  if (dwz_bfd == nullptr)
db493ec
+	    warning (_("File \"%s\" from debuginfod cannot be opened as bfd"),
db493ec
+		     alt_filename.get ());
db493ec
+	  else if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
db493ec
+	    dwz_bfd.reset (nullptr);
db493ec
+	}
db493ec
+    }
db493ec
+
db493ec
   if (dwz_bfd == NULL)
db493ec
     dwz_bfd = build_id_to_debug_bfd (buildid_len, buildid, NULL);
db493ec
 
db493ec
diff --git a/gdb/elfread.c b/gdb/elfread.c
db493ec
--- a/gdb/elfread.c
db493ec
+++ b/gdb/elfread.c
db493ec
@@ -49,6 +49,8 @@
db493ec
 #include "mdebugread.h"
db493ec
 #include "ctfread.h"
db493ec
 #include "gdbsupport/gdb_string_view.h"
db493ec
+#include "gdbsupport/scoped_fd.h"
db493ec
+#include "debuginfod-support.h"
db493ec
 
db493ec
 /* Forward declarations.  */
db493ec
 extern const struct sym_fns elf_sym_fns_gdb_index;
db493ec
@@ -1313,12 +1315,42 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
db493ec
 	  symbol_file_add_separate (debug_bfd.get (), debugfile.c_str (),
db493ec
 				    symfile_flags, objfile);
db493ec
 	}
db493ec
-      /* Check if any separate debug info has been extracted out.  */
db493ec
-      else if (bfd_get_section_by_name (objfile->obfd, ".gnu_debuglink")
db493ec
-	       != NULL)
db493ec
-	debug_print_missing (objfile_name (objfile), build_id_filename.get ());
db493ec
       else
db493ec
-	has_dwarf2 = false;
db493ec
+	{
db493ec
+	  has_dwarf2 = false;
db493ec
+	  const struct bfd_build_id *build_id = build_id_bfd_shdr_get (objfile->obfd);
db493ec
+
db493ec
+	  if (build_id != nullptr)
db493ec
+	    {
db493ec
+	      gdb::unique_xmalloc_ptr<char> symfile_path;
db493ec
+	      scoped_fd fd (debuginfod_debuginfo_query (build_id->data,
db493ec
+							build_id->size,
db493ec
+							objfile->original_name,
db493ec
+							&symfile_path));
db493ec
+
db493ec
+	      if (fd.get () >= 0)
db493ec
+		{
db493ec
+		  /* File successfully retrieved from server.  */
db493ec
+		  gdb_bfd_ref_ptr debug_bfd (symfile_bfd_open (symfile_path.get ()));
db493ec
+
db493ec
+		  if (debug_bfd == nullptr)
db493ec
+		    warning (_("File \"%s\" from debuginfod cannot be opened as bfd"),
db493ec
+			     objfile->original_name);
db493ec
+		  else if (build_id_verify (debug_bfd.get (), build_id->size, build_id->data))
db493ec
+		    {
db493ec
+		      symbol_file_add_separate (debug_bfd.get (), symfile_path.get (),
db493ec
+						symfile_flags, objfile);
db493ec
+		      has_dwarf2 = true;
db493ec
+		    }
db493ec
+		}
db493ec
+	    }
db493ec
+	  /* Check if any separate debug info has been extracted out.  */
db493ec
+	  else if (bfd_get_section_by_name (objfile->obfd, ".gnu_debuglink")
db493ec
+		   != NULL)
db493ec
+	    debug_print_missing (objfile_name (objfile), build_id_filename.get ());
db493ec
+	  else
db493ec
+	    has_dwarf2 = false;
db493ec
+	}
db493ec
     }
db493ec
 
db493ec
   /* Read the CTF section only if there is no DWARF info.  */
db493ec
diff --git a/gdb/source.c b/gdb/source.c
db493ec
--- a/gdb/source.c
db493ec
+++ b/gdb/source.c
db493ec
@@ -47,6 +47,8 @@
db493ec
 #include "gdbsupport/pathstuff.h"
db493ec
 #include "source-cache.h"
db493ec
 #include "cli/cli-style.h"
db493ec
+#include "build-id.h"
db493ec
+#include "debuginfod-support.h"
db493ec
 
db493ec
 #define OPEN_MODE (O_RDONLY | O_BINARY)
db493ec
 #define FDOPEN_MODE FOPEN_RB
db493ec
@@ -1122,6 +1124,34 @@ open_source_file (struct symtab *s)
db493ec
   s->fullname = NULL;
db493ec
   scoped_fd fd = find_and_open_source (s->filename, SYMTAB_DIRNAME (s),
db493ec
 				       &fullname);
db493ec
+
db493ec
+  if (fd.get () < 0)
db493ec
+    {
db493ec
+      if (SYMTAB_COMPUNIT (s) != nullptr)
db493ec
+	{
db493ec
+	  const objfile *ofp = COMPUNIT_OBJFILE (SYMTAB_COMPUNIT (s));
db493ec
+
db493ec
+	  std::string srcpath;
db493ec
+	  if (IS_ABSOLUTE_PATH (s->filename))
db493ec
+	    srcpath = s->filename;
db493ec
+	  else if (SYMTAB_DIRNAME (s) != nullptr)
db493ec
+	    {
db493ec
+	      srcpath = SYMTAB_DIRNAME (s);
db493ec
+	      srcpath += SLASH_STRING;
db493ec
+	      srcpath += s->filename;
db493ec
+	    }
db493ec
+
db493ec
+	  const struct bfd_build_id *build_id = build_id_bfd_shdr_get (ofp->obfd);
db493ec
+
db493ec
+	  /* Query debuginfod for the source file.  */
db493ec
+	  if (build_id != nullptr)
db493ec
+	    fd = debuginfod_source_query (build_id->data,
db493ec
+					  build_id->size,
db493ec
+					  srcpath.c_str (),
db493ec
+					  &fullname);
db493ec
+	}
db493ec
+    }
db493ec
+
db493ec
   s->fullname = fullname.release ();
db493ec
   return fd;
db493ec
 }
db493ec
diff --git a/gdb/testsuite/gdb.debuginfod/fetch_src_and_symbols.exp b/gdb/testsuite/gdb.debuginfod/fetch_src_and_symbols.exp
db493ec
new file mode 100644
db493ec
--- /dev/null
db493ec
+++ b/gdb/testsuite/gdb.debuginfod/fetch_src_and_symbols.exp
db493ec
@@ -0,0 +1,215 @@
db493ec
+# Copyright 2020 Free Software Foundation, Inc.
db493ec
+
db493ec
+# This program is free software; you can redistribute it and/or modify
db493ec
+# it under the terms of the GNU General Public License as published by
db493ec
+# the Free Software Foundation; either version 3 of the License, or
db493ec
+# (at your option) any later version.
db493ec
+#
db493ec
+# This program is distributed in the hope that it will be useful,
db493ec
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
db493ec
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
db493ec
+# GNU General Public License for more details.
db493ec
+#
db493ec
+# You should have received a copy of the GNU General Public License
db493ec
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
db493ec
+
db493ec
+# Test debuginfod functionality
db493ec
+
db493ec
+standard_testfile main.c
db493ec
+
db493ec
+load_lib dwarf.exp
db493ec
+
db493ec
+if { [which debuginfod] == 0 } {
db493ec
+    untested "cannot find debuginfod"
db493ec
+    return -1
db493ec
+}
db493ec
+
db493ec
+if { [which curl] == 0 } {
db493ec
+    untested "cannot find curl"
db493ec
+    return -1
db493ec
+}
db493ec
+
db493ec
+# Skip testing if gdb was not configured with debuginfod
db493ec
+if { [string first "with-debuginfod" \
db493ec
+	  [eval exec $GDB $INTERNAL_GDBFLAGS --configuration]] == -1 } {
db493ec
+    untested "gdb not configured with debuginfod"
db493ec
+    return -1
db493ec
+}
db493ec
+
db493ec
+set cache [standard_output_file ".client_cache"]
db493ec
+set db [standard_output_file ".debuginfod.db"]
db493ec
+
db493ec
+# Delete any preexisting test files
db493ec
+file delete -force $cache
db493ec
+file delete -force $db
db493ec
+
db493ec
+set sourcetmp [standard_output_file tmp-${srcfile}]
db493ec
+set outputdir [standard_output_file {}]
db493ec
+
db493ec
+# Make a copy source file that we can move around
db493ec
+if { [catch {file copy -force ${srcdir}/${subdir}/${srcfile} \
db493ec
+	     [standard_output_file ${sourcetmp}]}] != 0 } {
db493ec
+    error "create temporary file"
db493ec
+    return -1
db493ec
+}
db493ec
+
db493ec
+if { [gdb_compile "$sourcetmp" "$binfile" executable {debug}] != "" } {
db493ec
+    fail "compile"
db493ec
+    return -1
db493ec
+}
db493ec
+
db493ec
+setenv DEBUGINFOD_URLS ""
db493ec
+setenv DEBUGINFOD_TIMEOUT 30
db493ec
+setenv DEBUGINFOD_CACHE_PATH $cache
db493ec
+
db493ec
+# Test that gdb cannot find source without debuginfod
db493ec
+clean_restart $binfile
db493ec
+gdb_test_no_output "set substitute-path $outputdir /dev/null"
db493ec
+gdb_test "list" ".*No such file or directory.*"
db493ec
+
db493ec
+# Strip symbols into separate file and move it so gdb cannot find it without debuginfod
db493ec
+if { [gdb_gnu_strip_debug $binfile ""] != 0 } {
db493ec
+    fail "strip debuginfo"
db493ec
+    return -1
db493ec
+}
db493ec
+
db493ec
+set debugdir [standard_output_file "debug"]
db493ec
+set debuginfo [standard_output_file "fetch_src_and_symbols.debug"]
db493ec
+
db493ec
+file mkdir $debugdir
db493ec
+file rename -force $debuginfo $debugdir
db493ec
+
db493ec
+# Test that gdb cannot find symbols without debuginfod
db493ec
+clean_restart $binfile
db493ec
+gdb_test "file" ".*No symbol file.*"
db493ec
+
db493ec
+# Write some assembly that just has a .gnu_debugaltlink section.
db493ec
+# Copied from testsuite/gdb.dwarf2/dwzbuildid.exp.
db493ec
+proc write_just_debugaltlink {filename dwzname buildid} {
db493ec
+    set asm_file [standard_output_file $filename]
db493ec
+
db493ec
+    Dwarf::assemble $asm_file {
db493ec
+	upvar dwzname dwzname
db493ec
+	upvar buildid buildid
db493ec
+
db493ec
+	gnu_debugaltlink $dwzname $buildid
db493ec
+
db493ec
+	# Only the DWARF reader checks .gnu_debugaltlink, so make sure
db493ec
+	# there is a bit of DWARF in here.
db493ec
+	cu {} {
db493ec
+	    compile_unit {{language @DW_LANG_C}} {
db493ec
+	    }
db493ec
+	}
db493ec
+    }
db493ec
+}
db493ec
+
db493ec
+# Write some DWARF that also sets the buildid.
db493ec
+# Copied from testsuite/gdb.dwarf2/dwzbuildid.exp.
db493ec
+proc write_dwarf_file {filename buildid {value 99}} {
db493ec
+    set asm_file [standard_output_file $filename]
db493ec
+
db493ec
+    Dwarf::assemble $asm_file {
db493ec
+	declare_labels int_label int_label2
db493ec
+
db493ec
+	upvar buildid buildid
db493ec
+	upvar value value
db493ec
+
db493ec
+	build_id $buildid
db493ec
+
db493ec
+	cu {} {
db493ec
+	    compile_unit {{language @DW_LANG_C}} {
db493ec
+	        int_label2: base_type {
db493ec
+		    {name int}
db493ec
+		    {byte_size 4 sdata}
db493ec
+		    {encoding @DW_ATE_signed}
db493ec
+		}
db493ec
+
db493ec
+		constant {
db493ec
+		    {name the_int}
db493ec
+		    {type :$int_label2}
db493ec
+		    {const_value $value data1}
db493ec
+		}
db493ec
+	    }
db493ec
+	}
db493ec
+    }
db493ec
+}
db493ec
+
db493ec
+set buildid "01234567890abcdef0123456"
db493ec
+
db493ec
+write_just_debugaltlink ${binfile}_has_altlink.S ${binfile}_dwz.o $buildid
db493ec
+write_dwarf_file ${binfile}_dwz.S $buildid
db493ec
+
db493ec
+if {[gdb_compile ${binfile}_has_altlink.S ${binfile}_alt.o object nodebug] != ""} {
db493ec
+    fail "compile main with altlink"
db493ec
+    return -1
db493ec
+}
db493ec
+
db493ec
+if {[gdb_compile ${binfile}_dwz.S ${binfile}_dwz.o object nodebug] != ""} {
db493ec
+    fail "compile altlink"
db493ec
+    return -1
db493ec
+}
db493ec
+
db493ec
+file rename -force ${binfile}_dwz.o $debugdir
db493ec
+
db493ec
+# Test that gdb cannot find dwz without debuginfod.
db493ec
+clean_restart
db493ec
+gdb_test "file ${binfile}_alt.o" ".*could not find '.gnu_debugaltlink'.*"
db493ec
+
db493ec
+# Find an unused port
db493ec
+set port 7999
db493ec
+set found 0
db493ec
+while { ! $found } {
db493ec
+  incr port
db493ec
+  if { $port == 65536 } {
db493ec
+    fail "no available ports"
db493ec
+    return -1
db493ec
+  }
db493ec
+
db493ec
+  spawn debuginfod -vvvv -d $db -p $port -F $debugdir
db493ec
+  expect {
db493ec
+    "started http server on IPv4 IPv6 port=$port" { set found 1 }
db493ec
+    "failed to bind to port" { kill_wait_spawned_process $spawn_id }
db493ec
+    timeout {
db493ec
+      fail "find port timeout"
db493ec
+      return -1
db493ec
+    }
db493ec
+  }
db493ec
+}
db493ec
+
db493ec
+set metrics [list "ready 1" \
db493ec
+	     "thread_work_total{role=\"traverse\"} 1" \
db493ec
+	     "thread_work_pending{role=\"scan\"} 0" \
db493ec
+	     "thread_busy{role=\"scan\"} 0"]
db493ec
+
db493ec
+# Check server metrics to confirm init has completed.
db493ec
+foreach m $metrics {
db493ec
+  set timelim 20
db493ec
+  while { $timelim != 0 } {
db493ec
+    sleep 0.5
db493ec
+    catch {exec curl -s http://127.0.0.1:$port/metrics} got
db493ec
+
db493ec
+    if { [regexp $m $got] } {
db493ec
+      break
db493ec
+    }
db493ec
+
db493ec
+    incr timelim -1
db493ec
+  }
db493ec
+
db493ec
+  if { $timelim == 0 } {
db493ec
+    fail "server init timeout"
db493ec
+    return -1
db493ec
+  }
db493ec
+}
db493ec
+
db493ec
+# Point the client to the server
db493ec
+setenv DEBUGINFOD_URLS http://127.0.0.1:$port
db493ec
+
db493ec
+# gdb should now find the symbol and source files
db493ec
+clean_restart $binfile
db493ec
+gdb_test_no_output "set substitute-path $outputdir /dev/null"
db493ec
+gdb_test "br main" "Breakpoint 1 at.*file.*"
db493ec
+gdb_test "l" ".*This program is distributed in the hope.*"
db493ec
+
db493ec
+# gdb should now find the debugaltlink file
db493ec
+clean_restart
db493ec
+gdb_test "file ${binfile}_alt.o" ".*Reading symbols from ${binfile}_alt.o\.\.\.*"
db493ec
diff --git a/gdb/testsuite/gdb.debuginfod/main.c b/gdb/testsuite/gdb.debuginfod/main.c
db493ec
new file mode 100644
db493ec
--- /dev/null
db493ec
+++ b/gdb/testsuite/gdb.debuginfod/main.c
db493ec
@@ -0,0 +1,25 @@
db493ec
+/* This testcase is part of GDB, the GNU debugger.
db493ec
+
db493ec
+   Copyright 2020 Free Software Foundation, Inc.
db493ec
+
db493ec
+   This program is free software; you can redistribute it and/or modify
db493ec
+   it under the terms of the GNU General Public License as published by
db493ec
+   the Free Software Foundation; either version 3 of the License, or
db493ec
+   (at your option) any later version.
db493ec
+
db493ec
+   This program is distributed in the hope that it will be useful,
db493ec
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
db493ec
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
db493ec
+   GNU General Public License for more details.
db493ec
+
db493ec
+   You should have received a copy of the GNU General Public License
db493ec
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
db493ec
+
db493ec
+/* Dummy main function.  */
db493ec
+
db493ec
+int
db493ec
+main()
db493ec
+{
db493ec
+  asm ("main_label: .globl main_label");
db493ec
+  return 0;
db493ec
+}
db493ec
diff --git a/gdb/top.c b/gdb/top.c
db493ec
--- a/gdb/top.c
db493ec
+++ b/gdb/top.c
db493ec
@@ -1513,6 +1513,17 @@ This GDB was configured as follows:\n\
db493ec
              --without-python\n\
db493ec
 "));
db493ec
 #endif
db493ec
+
db493ec
+#if HAVE_LIBDEBUGINFOD
db493ec
+  fprintf_filtered (stream, _("\
db493ec
+             --with-debuginfod\n\
db493ec
+"));
db493ec
+#else
db493ec
+   fprintf_filtered (stream, _("\
db493ec
+             --without-debuginfod\n\
db493ec
+"));
db493ec
+#endif
db493ec
+
db493ec
 #if HAVE_GUILE
db493ec
   fprintf_filtered (stream, _("\
db493ec
              --with-guile\n\