summaryrefslogtreecommitdiff
path: root/gdb/debuginfod-support.c
diff options
context:
space:
mode:
authorAaron Merey <amerey@redhat.com>2020-02-26 17:40:49 -0500
committerAaron Merey <amerey@redhat.com>2020-02-26 17:40:49 -0500
commit0d79cdc494d5eb9db26a602d62c92d49f83f407e (patch)
treec30e35ac87c7ee38f63fe479af9e6940cad8574e /gdb/debuginfod-support.c
parentb65ce565416b950d8730b34106c54779c48efd29 (diff)
downloadbinutils-gdb-0d79cdc494d5eb9db26a602d62c92d49f83f407e.tar.gz
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.
Diffstat (limited to 'gdb/debuginfod-support.c')
-rw-r--r--gdb/debuginfod-support.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/gdb/debuginfod-support.c b/gdb/debuginfod-support.c
new file mode 100644
index 00000000000..e0f0fac0766
--- /dev/null
+++ b/gdb/debuginfod-support.c
@@ -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