From patchwork Tue Aug 20 20:28:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Merey X-Patchwork-Id: 34196 Received: (qmail 2436 invoked by alias); 20 Aug 2019 20:28:24 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 2249 invoked by uid 89); 20 Aug 2019 20:28:23 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_HELO_PASS autolearn=ham version=3.3.1 spammy=unusable X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 20 Aug 2019 20:28:12 +0000 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 41CB2300C727 for ; Tue, 20 Aug 2019 20:28:11 +0000 (UTC) Received: from localhost.localdomain.com (ovpn-125-215.rdu2.redhat.com [10.10.125.215]) by smtp.corp.redhat.com (Postfix) with ESMTP id B50C960BF4 for ; Tue, 20 Aug 2019 20:28:10 +0000 (UTC) From: Aaron Merey To: gdb-patches@sourceware.org Subject: [RFC PATCH] Support debuginfo and source file fetching via debuginfo server Date: Tue, 20 Aug 2019 16:28:09 -0400 Message-Id: <20190820202809.25367-1-amerey@redhat.com> MIME-Version: 1.0 Debuginfo server is a lightweight web service that indexes debuginfo and source files by build-id and serves them over HTTP. Debuginfo server is able to index unpackaged, locally-built software in addition to RPM files. Debuginfo server is packaged with a shared library, libdbgserver, that provides a small set of client functions for fetching files from debuginfo server. This patch adds debuginfo server support to GDB. In case a source file or separate debuginfo file cannot be found locally, GDB can use libdbgserver to query debuginfo server for the file in question, if enabled to do so. We plan on packaging debuginfo server with elfutils. For more information please see the 'dbgserver' branch of the elfutils git repo (https://sourceware.org/git/?p=elfutils.git;a=shortlog;h=refs/heads/dbgserver). This patch was tested on x86-64 Fedora 29. The testsuite was run both with and without this patch applied and the summaries indicated no regressions. Debuginfo server tests were also added to the testsuite under gdb/testsuite/gdb.dbgserver/. gdb/ChangeLog: * configure.ac: Add --with-dbgserver option. * config.in: Add libdbgserver. * elfread.c (elf_symfile_read): Query debuginfo server if separate debuginfo file cannot be found. * Makefile.in (CLIBS): Add libdbgserver. * source.c (open_source_file): Query debuginfo server if source file cannot be found. * top.c (print_gdb_configuration): Print "--with-dbgserver" or "--without-dbgserver" depending on whether GDB was configured with debuginfo server. gdb/testsuite/ChangeLog: * gdb.dbgserver/: New directory for debuginfo server tests. * gdb.dbgserver/fetch_src_and_symbols.c: New file. * gdb.dbgserver/fetch_src_and_symbols.exp: Test debuginfo server's ability to fetch source and separate debuginfo files. --- gdb/Makefile.in | 5 +- gdb/config.in | 3 + gdb/configure.ac | 26 ++++++ gdb/elfread.c | 27 ++++++ gdb/source.c | 56 +++++++++++ .../gdb.dbgserver/fetch_src_and_symbols.c | 1 + .../gdb.dbgserver/fetch_src_and_symbols.exp | 93 +++++++++++++++++++ gdb/top.c | 9 ++ 8 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 gdb/testsuite/gdb.dbgserver/fetch_src_and_symbols.c create mode 100644 gdb/testsuite/gdb.dbgserver/fetch_src_and_symbols.exp diff --git a/gdb/Makefile.in b/gdb/Makefile.in index d5d095aae4..3149e0ea53 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -210,6 +210,9 @@ INTL = @LIBINTL@ INTL_DEPS = @LIBINTL_DEP@ INTL_CFLAGS = @INCINTL@ +# Where is the dbgserver library, if any? +LIBDBGSERVER = @LIBDBGSERVER@ + # Where is the ICONV library? This will be empty if in libc or not available. LIBICONV = @LIBICONV@ @@ -593,7 +596,7 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(ZLIB) $(INTL) $(LIBIBERTY) $(LIBD @LIBS@ @GUILE_LIBS@ @PYTHON_LIBS@ \ $(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \ $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR) \ - $(SRCHIGH_LIBS) + $(SRCHIGH_LIBS) $(LIBDBGSERVER) CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \ $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU) diff --git a/gdb/config.in b/gdb/config.in index 26ca02f6a3..f2f4b38bd7 100644 --- a/gdb/config.in +++ b/gdb/config.in @@ -231,6 +231,9 @@ /* Define if you have the expat library. */ #undef HAVE_LIBEXPAT +/* Define if you have the dbgserver library. */ +#undef HAVE_LIBDBGSERVER + /* Define to 1 if you have the `libiconvlist' function. */ #undef HAVE_LIBICONVLIST diff --git a/gdb/configure.ac b/gdb/configure.ac index 5a18c16405..a224c7df81 100644 --- a/gdb/configure.ac +++ b/gdb/configure.ac @@ -327,6 +327,32 @@ case $host_os in enable_gdbtk=no ;; esac +# Enable dbgserver +AC_ARG_WITH([dbgserver], + AC_HELP_STRING([--with-dbgserver], + [Enable debuginfo and source-file lookups with dbgserver (auto/yes/no)]), + [], [with_dbgserver=auto]) +AC_MSG_CHECKING([whether to use dbgserver]) +AC_MSG_RESULT([$with_dbgserver]) + +if test "${with_dbgserver}" = no; then + AC_MSG_WARN([dbgserver support disabled; some features may be unavailable.]) + HAVE_LIBDBGSERVER=no +else + AC_LIB_HAVE_LINKFLAGS([dbgserver], [], [#include ], + [const unsigned char buildid; + int buildid_len = 1; + char *path; + path = dbgserver_find_debuginfo (& buildid, buildid_len, &path);]) + if test "$HAVE_LIBDBGSERVER" != yes; then + if test "$with_dbgserver" = yes; then + AC_MSG_ERROR([dbgserver is missing or unusable]) + else + AC_MSG_WARN([dbgserver is missing or unusable; some features may be unavailable.]) + fi + fi +fi + # Libunwind support for ia64. AC_ARG_WITH(libunwind-ia64, diff --git a/gdb/elfread.c b/gdb/elfread.c index 630550b80d..aa81ddf3c3 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -47,6 +47,9 @@ #include "location.h" #include "auxv.h" #include "mdebugread.h" +#if HAVE_LIBDBGSERVER +#include +#endif /* Forward declarations. */ extern const struct sym_fns elf_sym_fns_gdb_index; @@ -1296,6 +1299,30 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags) symbol_file_add_separate (debug_bfd.get (), debugfile.c_str (), symfile_flags, objfile); } +#if HAVE_LIBDBGSERVER + else + { + const struct bfd_build_id *build_id; + char *debugfile_path; + + build_id = build_id_bfd_get (objfile->obfd); + int fd = dbgserver_find_debuginfo (build_id->data, + build_id->size, + &debugfile_path); + + if (fd >= 0) + { + /* debuginfo successfully retrieved from server, reopen + the file as a bfd instead. */ + gdb_bfd_ref_ptr debug_bfd (symfile_bfd_open (debugfile_path)); + + symbol_file_add_separate(debug_bfd.get (), debugfile_path, + symfile_flags, objfile); + close(fd); + free(debugfile_path); + } + } +#endif /* LIBDBGSERVER */ } } diff --git a/gdb/source.c b/gdb/source.c index b27f210802..0150fd7c42 100644 --- a/gdb/source.c +++ b/gdb/source.c @@ -30,6 +30,10 @@ #include #include +#include "build-id.h" +#ifdef HAVE_LIBDBGSERVER +#include +#endif #include "gdbcore.h" #include "gdb_regex.h" #include "symfile.h" @@ -1060,6 +1064,58 @@ open_source_file (struct symtab *s) s->fullname = NULL; scoped_fd fd = find_and_open_source (s->filename, SYMTAB_DIRNAME (s), &fullname); + +#if HAVE_LIBDBGSERVER + if (fd.get() < 0) + { + if (SYMTAB_COMPUNIT(s) != NULL) + { + const struct bfd_build_id *build_id; + const objfile *ofp = COMPUNIT_OBJFILE (SYMTAB_COMPUNIT (s)); + + /* prefix the comp_dir to relative file names */ + const char* dirname = SYMTAB_DIRNAME (s); + int suffname_len = strlen(dirname) + strlen(s->filename) + 2; + char *suffname = (char *) alloca(suffname_len); + if (IS_DIR_SEPARATOR (s->filename[0])) + xsnprintf (suffname, suffname_len, "%s", s->filename); + else + { + xsnprintf (suffname, suffname_len, "%s%s%s", dirname, + SLASH_STRING, s->filename); + } + + build_id = build_id_bfd_get (ofp->obfd); + + /* Query debuginfo-server for the source file. */ + if (build_id != NULL) + { + char *name_in_cache; + int dbgsrv_rc = dbgserver_find_source (build_id->data, + build_id->size, + suffname, + &name_in_cache); + if (dbgsrv_rc >= 0) + { + fullname.reset (xstrdup(name_in_cache)); + free (name_in_cache); + } + else if (dbgsrv_rc == -ENOSYS) + { + /* -ENOSYS indicates that libdbgserver could not find + any dbgserver URLs to query due to $DBGSERVER_URLS + not being defined. Replace -ENOSYS with -ENOENT so + that users who have not configured dbgserver see the + usual error message when a source file cannot be found. */ + dbgsrv_rc = -ENOENT; + } + s->fullname = fullname.release (); + return scoped_fd(dbgsrv_rc); + } + } + } +#endif /* HAVE_LIBDBGSERVER */ + s->fullname = fullname.release (); return fd; } diff --git a/gdb/testsuite/gdb.dbgserver/fetch_src_and_symbols.c b/gdb/testsuite/gdb.dbgserver/fetch_src_and_symbols.c new file mode 100644 index 0000000000..76e8197013 --- /dev/null +++ b/gdb/testsuite/gdb.dbgserver/fetch_src_and_symbols.c @@ -0,0 +1 @@ +int main() { return 0; } diff --git a/gdb/testsuite/gdb.dbgserver/fetch_src_and_symbols.exp b/gdb/testsuite/gdb.dbgserver/fetch_src_and_symbols.exp new file mode 100644 index 0000000000..9d21d6a96d --- /dev/null +++ b/gdb/testsuite/gdb.dbgserver/fetch_src_and_symbols.exp @@ -0,0 +1,93 @@ +# 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 . + +# test dbgserver functionality + +standard_testfile + +# skip testing if dbgserver cannot be found +if { [which dbgserver] == 0 } { + untested "cannot find dbgserver" + return -1 +} + +# skip testing if gdb was not configured with dbgserver +if { [string first "with-dbgserver" [exec $GDB --configuration]] == -1 } { + untested "GDB not configured with dbgserver" + 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 "Could not create temporary file" + return -1 +} + +set sourcetmp [standard_output_file tmp-${srcfile}] +set outputdir [standard_output_file {}] + +if { [gdb_compile "${sourcetmp}" "${binfile}" executable {debug}] != "" } { + return -1 +} + +set port 58002 +set ::env(DBGSERVER_URLS) "localhost:$port" +set ::env(DBGSERVER_TIMEOUT) 10 +set ::env(DBGSERVER_CACHE_PATH) $cache + +# test that gdb cannot find source without dbgserver +gdb_start +gdb_load $binfile +gdb_test_no_output "set substitute-path $outputdir /dev/null" +gdb_test "l" ".*Connection refused\." +gdb_exit + +# strip symbols into separate file and move it so gdb cannot find it without dbgserver +gdb_gnu_strip_debug $binfile + +set debugdir [file join [standard_output_file {}] "debug"] +set debuginfo [file join [standard_output_file {}] "fetch_src_and_symbols.debug"] + +file mkdir -force $debugdir +file copy -force $debuginfo $debugdir +file delete -force $debuginfo + +# test that gdb cannot find symbols without dbgserver +gdb_start +gdb_load $binfile +gdb_test "file" ".*No symbol file.*" +gdb_exit + +# start up dbgserver + +set dbgserver_pid [exec dbgserver -p $port -F $debugdir >/dev/null 2>&1 &] +sleep 5 + +# gdb should now be able to 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" "int main().*return 0;.*" +gdb_exit + +file delete -force $cache +exec kill $dbgserver_pid diff --git a/gdb/top.c b/gdb/top.c index 9d4ce1fa3b..a1715a9910 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -1480,6 +1480,15 @@ This GDB was configured as follows:\n\ --without-python\n\ ")); #endif +#if HAVE_LIBDBGSERVER + fprintf_filtered (stream, _("\ + --with-dbgserver\n\ +")); +#else + fprintf_filtered (stream, _("\ + --without-dbgserver\n\ +")); +#endif #if HAVE_GUILE fprintf_filtered (stream, _("\ --with-guile\n\