Add debuginfod support to GDB

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

Tested on x86_64 Fedora 31.

gdb/ChangeLog:
2020-02-26  Aaron Merey  <amerey@redhat.com>

        * Makefile.in: Handle optional debuginfod support.
        * NEWS: Update.
        * README: Add --with-debuginfod summary.
        * config.in: Regenerate.
        * configure: Regenerate.
        * configure.ac: Handle optional debuginfod support.
        * debuginfod-support.c: debuginfod helper functions.
        * debuginfod-support.h: Ditto.
        * doc/gdb.texinfo: Add --with-debuginfod to configure options
        summary.
        * dwarf2/read.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-02-26  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.
This commit is contained in:
Aaron Merey 2020-02-26 17:40:49 -05:00
parent b65ce56541
commit 0d79cdc494
17 changed files with 755 additions and 50 deletions

View File

@ -1,3 +1,24 @@
2020-02-26 Aaron Merey <amerey@redhat.com>
* Makefile.in: Handle optional debuginfod support.
* NEWS: Update.
* README: Add --with-debuginfod summary.
* config.in: Regenerate.
* configure: Regenerate.
* configure.ac: Handle optional debuginfod support.
* debuginfod-support.c: debuginfod helper functions.
* debuginfod-support.h: Ditto.
* doc/gdb.texinfo: Add --with-debuginfod to configure options
summary.
* dwarf2/read.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.
2020-02-26 Jérémie Galarneau <jeremie.galarneau@efficios.com>
* thread.c (thr_try_catch_cmd): Print thread name.

View File

@ -617,7 +617,8 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(LIBCTF) $(ZLIB) \
@LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \
$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
$(WIN32LIBS) $(LIBGNU) $(LIBICONV) \
$(LIBMPFR) $(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS)
$(LIBMPFR) $(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) \
@LIBDEBUGINFOD@
CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) $(LIBCTF) \
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) \
$(LIBSUPPORT)
@ -991,6 +992,7 @@ COMMON_SFILES = \
dbxread.c \
dcache.c \
debug.c \
debuginfod-support.c \
dictionary.c \
disasm.c \
disasm-selftests.c \

View File

@ -3,6 +3,20 @@
*** 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.
* New features in the GDB remote stub, GDBserver
** GDBserver is now supported on RISC-V GNU/Linux.

View File

@ -432,6 +432,15 @@ more obscure GDB `configure' options are not listed here.
Use the curses library instead of the termcap library, for
text-mode terminal operations.
`--with-debuginfod'
Build GDB 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/'.
`--with-libunwind-ia64'
Use the libunwind library for unwinding function call stack on ia64
target platforms.

View File

@ -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

182
gdb/configure vendored
View File

@ -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
@ -1602,6 +1604,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
@ -2264,6 +2268,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
@ -2385,52 +2435,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_c_check_member LINENO AGGR MEMBER VAR INCLUDES
# ----------------------------------------------------
# Tries to find if the field MEMBER exists in type AGGR, after including
@ -6836,8 +6840,92 @@ $as_echo "$as_me: WARNING: gdbtk isn't supported on $host; disabling" >&2;}
enable_gdbtk=no ;;
esac
# Libunwind support for ia64.
# Handle optional debuginfod support
# 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
# Libunwind support for ia64.
# Check whether --with-libunwind-ia64 was given.
if test "${with_libunwind_ia64+set}" = set; then :

View File

@ -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
@ -322,8 +324,10 @@ case $host_os in
enable_gdbtk=no ;;
esac
# Libunwind support for ia64.
# Handle optional debuginfod support
AC_DEBUGINFOD
# Libunwind support for ia64.
AC_ARG_WITH(libunwind-ia64,
AS_HELP_STRING([--with-libunwind-ia64],
[use libunwind frame unwinding for ia64 targets]),,

155
gdb/debuginfod-support.c Normal file
View File

@ -0,0 +1,155 @@
/* debuginfod utilities for GDB.
Copyright (C) 2020 Free Software Foundation, Inc.
This file is part of GDB.
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/>. */
#include <errno.h>
#include "defs.h"
#include "cli/cli-style.h"
#include "gdbsupport/scoped_fd.h"
#include "debuginfod-support.h"
#ifndef HAVE_LIBDEBUGINFOD
scoped_fd
debuginfod_source_query (const unsigned char *build_id,
int build_id_len,
const char *srcpath,
gdb::unique_xmalloc_ptr<char> *destname)
{
return scoped_fd (-ENOSYS);
}
scoped_fd
debuginfod_debuginfo_query (const unsigned char *build_id,
int build_id_len,
const char *filename,
gdb::unique_xmalloc_ptr<char> *destname)
{
return scoped_fd (-ENOSYS);
}
#else
#include <elfutils/debuginfod.h>
/* TODO: Use debuginfod API extensions instead of these globals. */
static std::string desc;
static std::string fname;
static bool has_printed;
static int
progressfn (debuginfod_client *c, long cur, long total)
{
if (check_quit_flag ())
{
printf_filtered ("Cancelling download of %s %ps...\n",
desc.c_str (),
styled_string (file_name_style.style (), fname.c_str ()));
return 1;
}
if (!has_printed && total != 0)
{
/* Print this message only once. */
has_printed = true;
printf_filtered ("Downloading %s %ps...\n",
desc.c_str (),
styled_string (file_name_style.style (), fname.c_str ()));
}
return 0;
}
static debuginfod_client *
debuginfod_init ()
{
debuginfod_client *c = debuginfod_begin ();
if (c != nullptr)
debuginfod_set_progressfn (c, progressfn);
return c;
}
/* See debuginfod-support.h */
scoped_fd
debuginfod_source_query (const unsigned char *build_id,
int build_id_len,
const char *srcpath,
gdb::unique_xmalloc_ptr<char> *destname)
{
if (getenv (DEBUGINFOD_URLS_ENV_VAR) == NULL)
return scoped_fd (-ENOSYS);
debuginfod_client *c = debuginfod_init ();
if (c == nullptr)
return scoped_fd (-ENOMEM);
desc = std::string ("source file");
fname = std::string (srcpath);
has_printed = false;
scoped_fd fd (debuginfod_find_source (c,
build_id,
build_id_len,
srcpath,
nullptr));
/* TODO: Add 'set debug debuginfod' command to control when error messages are shown. */
if (fd.get () < 0 && fd.get () != -ENOENT)
printf_filtered (_("Download failed: %s. Continuing without source file %ps.\n"),
safe_strerror (-fd.get ()),
styled_string (file_name_style.style (), srcpath));
else
destname->reset (xstrdup (srcpath));
debuginfod_end (c);
return fd;
}
/* See debuginfod-support.h */
scoped_fd
debuginfod_debuginfo_query (const unsigned char *build_id,
int build_id_len,
const char *filename,
gdb::unique_xmalloc_ptr<char> *destname)
{
if (getenv (DEBUGINFOD_URLS_ENV_VAR) == NULL)
return scoped_fd (-ENOSYS);
debuginfod_client *c = debuginfod_init ();
if (c == nullptr)
return scoped_fd (-ENOMEM);
desc = std::string ("separate debug info for");
fname = std::string (filename);
has_printed = false;
char *dname = nullptr;
scoped_fd fd (debuginfod_find_debuginfo (c, build_id, build_id_len, &dname));
if (fd.get () < 0 && fd.get () != -ENOENT)
printf_filtered (_("Download failed: %s. Continuing without debug info for %ps.\n"),
safe_strerror (-fd.get ()),
styled_string (file_name_style.style (), filename));
destname->reset (dname);
debuginfod_end (c);
return fd;
}
#endif

62
gdb/debuginfod-support.h Normal file
View File

@ -0,0 +1,62 @@
/* debuginfod utilities for GDB.
Copyright (C) 2020 Free Software Foundation, Inc.
This file is part of GDB.
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/>. */
#ifndef DEBUGINFOD_SUPPORT_H
#define DEBUGINFOD_SUPPORT_H
/* Query debuginfod servers for a source file associated with an
executable with BUILD_ID. BUILD_ID can be given as a binary blob or
a null-terminated string. If given as a binary blob, BUILD_ID_LEN
should be the number of bytes. If given as a null-terminated string,
BUILD_ID_LEN should be 0.
SRC_PATH should be the source file's absolute path that includes the
compilation directory of the CU associated with the source file.
For example if a CU's compilation directory is `/my/build` and the
source file path is `/my/source/foo.c`, then SRC_PATH should be
`/my/build/../source/foo.c`.
If the file is successfully retrieved, its path on the local machine
is stored in DESTNAME. If GDB is not built with debuginfod, this
function returns -ENOSYS. */
extern scoped_fd
debuginfod_source_query (const unsigned char *build_id,
int build_id_len,
const char *src_path,
gdb::unique_xmalloc_ptr<char> *destname);
/* Query debuginfod servers for a debug info file with BUILD_ID.
BUILD_ID can be given as a binary blob or a null-terminated string.
If given as a binary blob, BUILD_ID_LEN should be the number of bytes.
If given as a null-terminated string, BUILD_ID_LEN should be 0.
FILENAME should be the name or path of the main binary associated with
the separate debug info. It is used for printing messages to the user.
If the file is successfully retrieved, its path on the local machine
is stored in DESTNAME. If GDB is not built with debuginfod, this
function returns -ENOSYS. */
extern scoped_fd
debuginfod_debuginfo_query (const unsigned char *build_id,
int build_id_len,
const char *filename,
gdb::unique_xmalloc_ptr<char> *destname);
#endif /* DEBUGINFOD_SUPPORT_H */

View File

@ -37848,6 +37848,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

View File

@ -83,6 +83,7 @@
#include "rust-lang.h"
#include "gdbsupport/pathstuff.h"
#include "count-one-bits.h"
#include "debuginfod-support.h"
/* When == 1, print basic high level tracing messages.
When > 1, be more verbose.
@ -2147,6 +2148,29 @@ 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 (dwz_bfd == nullptr)
{
gdb::unique_xmalloc_ptr<char> alt_filename;
const char *origname = dwarf2_per_objfile->objfile->original_name;
scoped_fd fd (debuginfod_debuginfo_query (buildid,
buildid_len,
origname,
&alt_filename));
if (fd.get () >= 0)
{
/* File successfully retrieved from server. */
dwz_bfd = gdb_bfd_open (alt_filename.get (), gnutarget, -1);
if (dwz_bfd == nullptr)
warning (_("File \"%s\" from debuginfod cannot be opened as bfd"),
alt_filename.get ());
else if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
dwz_bfd.reset (nullptr);
}
}
if (dwz_bfd == NULL)
error (_("could not find '.gnu_debugaltlink' file for %s"),
objfile_name (dwarf2_per_objfile->objfile));

View File

@ -49,6 +49,8 @@
#include "mdebugread.h"
#include "ctfread.h"
#include "gdbsupport/gdb_string_view.h"
#include "gdbsupport/scoped_fd.h"
#include "debuginfod-support.h"
/* Forward declarations. */
extern const struct sym_fns elf_sym_fns_gdb_index;
@ -1316,8 +1318,36 @@ 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
else
{
has_dwarf2 = false;
const struct bfd_build_id *build_id = build_id_bfd_get (objfile->obfd);
if (build_id != nullptr)
{
gdb::unique_xmalloc_ptr<char> symfile_path;
scoped_fd fd (debuginfod_debuginfo_query (build_id->data,
build_id->size,
objfile->original_name,
&symfile_path));
if (fd.get () >= 0)
{
/* File successfully retrieved from server. */
gdb_bfd_ref_ptr debug_bfd (symfile_bfd_open (symfile_path.get ()));
if (debug_bfd == nullptr)
warning (_("File \"%s\" from debuginfod cannot be opened as bfd"),
objfile->original_name);
else if (build_id_verify (debug_bfd.get (), build_id->size, build_id->data))
{
symbol_file_add_separate (debug_bfd.get (), symfile_path.get (),
symfile_flags, objfile);
has_dwarf2 = true;
}
}
}
}
}
/* Read the CTF section only if there is no DWARF info. */

View File

@ -48,6 +48,8 @@
#include "source-cache.h"
#include "cli/cli-style.h"
#include "observable.h"
#include "build-id.h"
#include "debuginfod-support.h"
#define OPEN_MODE (O_RDONLY | O_BINARY)
#define FDOPEN_MODE FOPEN_RB
@ -1148,6 +1150,34 @@ open_source_file (struct symtab *s)
s->fullname = NULL;
scoped_fd fd = find_and_open_source (s->filename, SYMTAB_DIRNAME (s),
&fullname);
if (fd.get () < 0)
{
if (SYMTAB_COMPUNIT (s) != nullptr)
{
const objfile *ofp = COMPUNIT_OBJFILE (SYMTAB_COMPUNIT (s));
std::string srcpath;
if (IS_ABSOLUTE_PATH (s->filename))
srcpath = s->filename;
else
{
srcpath = SYMTAB_DIRNAME (s);
srcpath += SLASH_STRING;
srcpath += s->filename;
}
const struct bfd_build_id *build_id = build_id_bfd_get (ofp->obfd);
/* Query debuginfod for the source file. */
if (build_id != nullptr)
fd = debuginfod_source_query (build_id->data,
build_id->size,
srcpath.c_str (),
&fullname);
}
}
s->fullname = fullname.release ();
return fd;
}

View File

@ -1,3 +1,9 @@
2020-02-26 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.
2020-02-26 Tom de Vries <tdevries@suse.de>
PR gdb/25603

View File

@ -0,0 +1,214 @@
# Copyright 2020 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
standard_testfile main.c
load_lib dwarf.exp
if { [which debuginfod] == 0 } {
untested "cannot find debuginfod"
return -1
}
if { [which curl] == 0 } {
untested "cannot find curl"
return -1
}
# Skip testing if gdb was not configured with debuginfod
if { [string first "with-debuginfod" [exec $GDB --configuration]] == -1 } {
untested "gdb not configured with debuginfod"
return -1
}
set cache [standard_output_file ".client_cache"]
set db [standard_output_file ".debuginfod.db"]
# Delete any preexisting test files
file delete -force $cache
file delete -force $db
set sourcetmp [standard_output_file tmp-${srcfile}]
set outputdir [standard_output_file {}]
# Make a copy source file that we can move around
if { [catch {file copy -force ${srcdir}/${subdir}/${srcfile} \
[standard_output_file ${sourcetmp}]}] != 0 } {
error "create temporary file"
return -1
}
if { [gdb_compile "$sourcetmp" "$binfile" executable {debug}] != "" } {
fail "compile"
return -1
}
setenv DEBUGINFOD_URLS ""
setenv DEBUGINFOD_TIMEOUT 30
setenv DEBUGINFOD_CACHE_PATH $cache
# Test that gdb cannot find source without debuginfod
clean_restart $binfile
gdb_test_no_output "set substitute-path $outputdir /dev/null"
gdb_test "list" ".*No such file or directory.*"
# Strip symbols into separate file and move it so gdb cannot find it without debuginfod
if { [gdb_gnu_strip_debug $binfile ""] != 0 } {
fail "strip debuginfo"
return -1
}
set debugdir [standard_output_file "debug"]
set debuginfo [standard_output_file "fetch_src_and_symbols.debug"]
file mkdir $debugdir
file rename -force $debuginfo $debugdir
# Test that gdb cannot find symbols without debuginfod
clean_restart $binfile
gdb_test "file" ".*No symbol file.*"
# 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 "01234567890abcdef0123456"
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 "compile main with altlink"
return -1
}
if {[gdb_compile ${binfile}_dwz.S ${binfile}_dwz.o object nodebug] != ""} {
fail "compile altlink"
return -1
}
file rename -force ${binfile}_dwz.o $debugdir
# Test that gdb cannot find dwz without debuginfod.
clean_restart
gdb_test "file ${binfile}_alt.o" ".*could not find '.gnu_debugaltlink'.*"
# Find an unused port
set port 7999
set found 0
while { ! $found } {
incr port
if { $port == 65536 } {
fail "no available ports"
return -1
}
spawn debuginfod -vvvv -d $db -p $port -F $debugdir
expect {
"started http server on IPv4 IPv6 port=$port" { set found 1 }
"failed to bind to port" { kill_wait_spawned_process $spawn_id }
timeout {
fail "find port timeout"
return -1
}
}
}
set metrics [list "ready 1" \
"thread_work_total{role=\"traverse\"} 1" \
"thread_work_pending{role=\"scan\"} 0" \
"thread_busy{role=\"scan\"} 0"]
# Check server metrics to confirm init has completed.
foreach m $metrics {
set timelim 20
while { $timelim != 0 } {
sleep 0.5
catch {exec curl -s http://127.0.0.1:$port/metrics} got
if { [regexp $m $got] } {
break
}
incr timelim -1
}
if { $timelim == 0 } {
fail "server init timeout"
return -1
}
}
# Point the client to the server
setenv DEBUGINFOD_URLS http://127.0.0.1:$port
# gdb should now find the symbol and source files
clean_restart $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 should now find the debugaltlink file
clean_restart
gdb_test "file ${binfile}_alt.o" ".*Reading symbols from ${binfile}_alt.o\.\.\.*"

View File

@ -0,0 +1,25 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 2020 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;
}

View File

@ -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\