aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
authorKeith Seitz <keiths@redhat.com>2019-12-07 09:35:03 -0800
committerKeith Seitz <keiths@redhat.com>2019-12-07 12:05:41 -0800
commitaa2d5a4229eb541406d3b91a384ad6a62caf7760 (patch)
treecb77da7a06472447d1d9174c9fdc31f30311c305 /gdb
parent5fa370e437f39bf73a133cc84c4e6329943522bf (diff)
downloadgdb-aa2d5a4229eb541406d3b91a384ad6a62caf7760.zip
gdb-aa2d5a4229eb541406d3b91a384ad6a62caf7760.tar.gz
gdb-aa2d5a4229eb541406d3b91a384ad6a62caf7760.tar.bz2
Core file build-id support
This patch uses new BFD support for detecting build-ids in core files. After this patch, it is possible to run gdb with only the core file, and gdb will automatically load the executable and debug info [example from tests]: $ gdb -nx -q (gdb) core-file corefile-buildid.core [New LWP 29471] Reading symbols from gdb.base/corefile-buildid/debugdir-exec/.build-id/36/fe5722c5a7ca3ac746a84e223c6a2a69193a24... Core was generated by `outputs/gdb.base/coref'. Program terminated with signal SIGABRT, Aborted. (gdb) This work is based on functionality available in Fedora originally written by Jan Kratochvil. Regression tested on buildbot. gdb/ChangeLog: 2019-12-07 Keith Seitz <keiths@redhat.com> * build-id.c (build_id_bfd_get): Permit bfd_core, too. (build_id_to_debug_bfd): Make static, rewriting to use build_id_to_bfd_suffix. (build_id_to_bfd_suffix): Copy of build_id_to_debug_bfd, adding `suffix' parameter. Append SUFFIX to file names when searching for matching files. (build_id_to_debug_bfd): Use build_id_to_bfd_suffix. (build_id_to_exec_bfd): Likewise. * build-id.h (build_id_to_debug_bfd): Clarify that function searches for BFD of debug info file. (build_id_to_exec_bfd): Declare. * corelow.c: Include build-id.h. (locate_exec_from_corefile_build_id): New function. (core_target_open): If no executable BFD is found, search for a core file BFD using build-id. gdb/testsuite/ChangeLog: 2019-12-07 Keith Seitz <keiths@redhat.com> * gdb.base/corefile-buildid-shlib-shr.c: New file. * gdb.base/corefile-buildid-shlib.c: New file. * gdb.base/corefile-buildid.c: New file. * gdb.base/corefile-buildid.exp: New file. Change-Id: I15e9e8e58f10c68b5cae55e2eba58df1e8aef529
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog18
-rw-r--r--gdb/build-id.c30
-rw-r--r--gdb/build-id.h12
-rw-r--r--gdb/corelow.c25
-rw-r--r--gdb/testsuite/ChangeLog7
-rw-r--r--gdb/testsuite/gdb.base/corefile-buildid-shlib-shr.c29
-rw-r--r--gdb/testsuite/gdb.base/corefile-buildid-shlib.c58
-rw-r--r--gdb/testsuite/gdb.base/corefile-buildid.c43
-rw-r--r--gdb/testsuite/gdb.base/corefile-buildid.exp271
9 files changed, 485 insertions, 8 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index f06ad13..ee45156 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,21 @@
+2019-12-07 Keith Seitz <keiths@redhat.com>
+
+ * build-id.c (build_id_bfd_get): Permit bfd_core, too.
+ (build_id_to_debug_bfd): Make static, rewriting to use
+ build_id_to_bfd_suffix.
+ (build_id_to_bfd_suffix): Copy of build_id_to_debug_bfd,
+ adding `suffix' parameter. Append SUFFIX to file names
+ when searching for matching files.
+ (build_id_to_debug_bfd): Use build_id_to_bfd_suffix.
+ (build_id_to_exec_bfd): Likewise.
+ * build-id.h (build_id_to_debug_bfd): Clarify that function
+ searches for BFD of debug info file.
+ (build_id_to_exec_bfd): Declare.
+ * corelow.c: Include build-id.h.
+ (locate_exec_from_corefile_build_id): New function.
+ (core_target_open): If no executable BFD is found,
+ search for a core file BFD using build-id.
+
2019-12-06 Christian Biesinger <cbiesinger@google.com>
* bcache.c: Put in namespace gdb.
diff --git a/gdb/build-id.c b/gdb/build-id.c
index 048da2a..e8d77bb 100644
--- a/gdb/build-id.c
+++ b/gdb/build-id.c
@@ -32,7 +32,8 @@
const struct bfd_build_id *
build_id_bfd_get (bfd *abfd)
{
- if (!bfd_check_format (abfd, bfd_object))
+ if (!bfd_check_format (abfd, bfd_object)
+ && !bfd_check_format (abfd, bfd_core))
return NULL;
if (abfd->build_id != NULL)
@@ -117,10 +118,13 @@ build_id_to_debug_bfd_1 (const std::string &link, size_t build_id_len,
return debug_bfd;
}
-/* See build-id.h. */
+/* Common code for finding BFDs of a given build-id. This function
+ works with both debuginfo files (SUFFIX == ".debug") and executable
+ files (SUFFIX == ""). */
-gdb_bfd_ref_ptr
-build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id)
+static gdb_bfd_ref_ptr
+build_id_to_bfd_suffix (size_t build_id_len, const bfd_byte *build_id,
+ const char *suffix)
{
/* Keep backward compatibility so that DEBUG_FILE_DIRECTORY being "" will
cause "/.build-id/..." lookups. */
@@ -149,7 +153,7 @@ build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id)
while (size-- > 0)
string_appendf (link, "%02x", (unsigned) *data++);
- link += ".debug";
+ link += suffix;
gdb_bfd_ref_ptr debug_bfd
= build_id_to_debug_bfd_1 (link, build_id_len, build_id);
@@ -177,6 +181,22 @@ build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id)
/* See build-id.h. */
+gdb_bfd_ref_ptr
+build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id)
+{
+ return build_id_to_bfd_suffix (build_id_len, build_id, ".debug");
+}
+
+/* See build-id.h. */
+
+gdb_bfd_ref_ptr
+build_id_to_exec_bfd (size_t build_id_len, const bfd_byte *build_id)
+{
+ return build_id_to_bfd_suffix (build_id_len, build_id, "");
+}
+
+/* See build-id.h. */
+
std::string
find_separate_debug_file_by_buildid (struct objfile *objfile)
{
diff --git a/gdb/build-id.h b/gdb/build-id.h
index 2835a76..d251bc1 100644
--- a/gdb/build-id.h
+++ b/gdb/build-id.h
@@ -34,13 +34,19 @@ extern int build_id_verify (bfd *abfd,
size_t check_len, const bfd_byte *check);
-/* Find and open a BFD given a build-id. If no BFD can be found,
- return NULL. The returned reference to the BFD must be released by
- the caller. */
+/* Find and open a BFD for a debuginfo file given a build-id. If no BFD
+ can be found, return NULL. */
extern gdb_bfd_ref_ptr build_id_to_debug_bfd (size_t build_id_len,
const bfd_byte *build_id);
+/* Find and open a BFD for an executable file given a build-id. If no BFD
+ can be found, return NULL. The returned reference to the BFD must be
+ released by the caller. */
+
+extern gdb_bfd_ref_ptr build_id_to_exec_bfd (size_t build_id_len,
+ const bfd_byte *build_id);
+
/* Find the separate debug file for OBJFILE, by using the build-id
associated with OBJFILE's BFD. If successful, returns the file name for the
separate debug file, otherwise, return an empty string. */
diff --git a/gdb/corelow.c b/gdb/corelow.c
index fa1661e..bdbfae37 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -43,6 +43,7 @@
#include "gdb_bfd.h"
#include "completer.h"
#include "gdbsupport/filestuff.h"
+#include "build-id.h"
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
@@ -351,6 +352,27 @@ core_file_command (const char *filename, int from_tty)
core_target_open (filename, from_tty);
}
+/* Locate (and load) an executable file (and symbols) given the core file
+ BFD ABFD. */
+
+static void
+locate_exec_from_corefile_build_id (bfd *abfd, int from_tty)
+{
+ const bfd_build_id *build_id = build_id_bfd_get (abfd);
+ if (build_id == nullptr)
+ return;
+
+ gdb_bfd_ref_ptr execbfd
+ = build_id_to_exec_bfd (build_id->size, build_id->data);
+
+ if (execbfd != nullptr)
+ {
+ exec_file_attach (bfd_get_filename (execbfd.get ()), from_tty);
+ symbol_file_add_main (bfd_get_filename (execbfd.get ()),
+ symfile_add_flag (from_tty ? SYMFILE_VERBOSE : 0));
+ }
+}
+
/* See gdbcore.h. */
void
@@ -456,6 +478,9 @@ core_target_open (const char *arg, int from_tty)
switch_to_thread (thread);
}
+ if (exec_bfd == nullptr)
+ locate_exec_from_corefile_build_id (core_bfd, from_tty);
+
post_create_inferior (target, from_tty);
/* Now go through the target stack looking for threads since there
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index c9f66ad..17ae51a 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,10 @@
+2019-12-07 Keith Seitz <keiths@redhat.com>
+
+ * gdb.base/corefile-buildid-shlib-shr.c: New file.
+ * gdb.base/corefile-buildid-shlib.c: New file.
+ * gdb.base/corefile-buildid.c: New file.
+ * gdb.base/corefile-buildid.exp: New file.
+
2019-12-06 Tom de Vries <tdevries@suse.de>
* gdb.dwarf2/varval.exp: Add decl before def test.
diff --git a/gdb/testsuite/gdb.base/corefile-buildid-shlib-shr.c b/gdb/testsuite/gdb.base/corefile-buildid-shlib-shr.c
new file mode 100644
index 0000000..55b9bfa
--- /dev/null
+++ b/gdb/testsuite/gdb.base/corefile-buildid-shlib-shr.c
@@ -0,0 +1,29 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2019 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static int crashfunc_global = 1234;
+
+int
+crashfunc (void)
+{
+ printf ("in crashfunc\n");
+ abort ();
+ return crashfunc_global;
+}
diff --git a/gdb/testsuite/gdb.base/corefile-buildid-shlib.c b/gdb/testsuite/gdb.base/corefile-buildid-shlib.c
new file mode 100644
index 0000000..10c523d
--- /dev/null
+++ b/gdb/testsuite/gdb.base/corefile-buildid-shlib.c
@@ -0,0 +1,58 @@
+/* Copyright (C) 2007-2019 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* This shared library will dlopen another shared object.
+ This is based on gdb.base/solib-disc.c. */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __WIN32__
+#include <windows.h>
+#define dlopen(name, mode) LoadLibrary (name)
+#define dlsym(handle, func) GetProcAddress (handle, func)
+#define dlclose(handle) FreeLibrary (handle)
+#define dlerror() "an error occurred"
+#else
+#include <dlfcn.h>
+#endif
+
+const char *the_shlib = SHLIB_NAME;
+
+int
+shlib_function (void)
+{
+ void *handle;
+ int (*func) (void);
+ int result;
+
+ handle = dlopen (the_shlib, RTLD_LAZY);
+ if (!handle)
+ {
+ fprintf (stderr, "%s\n", dlerror ());
+ exit (1);
+ }
+
+ func = (int (*)(void)) dlsym (handle, "crashfunc");
+ if (func == NULL)
+ {
+ fprintf (stderr, "%s\n", dlerror ());
+ exit (1);
+ }
+
+ result = func ();
+ dlclose (handle);
+ return result;
+}
diff --git a/gdb/testsuite/gdb.base/corefile-buildid.c b/gdb/testsuite/gdb.base/corefile-buildid.c
new file mode 100644
index 0000000..ae0a1ca
--- /dev/null
+++ b/gdb/testsuite/gdb.base/corefile-buildid.c
@@ -0,0 +1,43 @@
+/* Copyright (C) 2019 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef TEST_SHARED
+/* A function in the shared library linked with this program. */
+extern int shlib_function (void);
+#else
+#include <stdlib.h>
+
+static int crashfunc_global = 4321;
+
+static int
+crashfunc (void)
+{
+ abort ();
+ return crashfunc_global;
+}
+
+int
+shlib_function (void)
+{
+ return crashfunc ();
+}
+#endif
+
+int
+main (void)
+{
+ int ret = shlib_function ();
+ return ret;
+}
diff --git a/gdb/testsuite/gdb.base/corefile-buildid.exp b/gdb/testsuite/gdb.base/corefile-buildid.exp
new file mode 100644
index 0000000..8a29359
--- /dev/null
+++ b/gdb/testsuite/gdb.base/corefile-buildid.exp
@@ -0,0 +1,271 @@
+# Copyright 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Based on break.exp, written by Rob Savoye. (rob@cygnus.com)
+# Modified to test gdb's handling of separate debug info files.
+# Modified to test gdb's handling of a debug-id retrieval.
+
+# Build-id-related tests for core files.
+
+standard_testfile
+
+# Build a non-shared executable.
+
+proc build_corefile_buildid_exec {} {
+ global testfile srcfile binfile execdir
+
+ if {[build_executable $testfile.exp $testfile $srcfile debug] == -1} {
+ untested "failed to compile"
+ return false
+ }
+
+ # Move executable to non-default path.
+ set builddir [standard_output_file $execdir]
+ remote_exec build "rm -rf $builddir"
+ remote_exec build "mkdir $builddir"
+ remote_exec build "mv $binfile [file join $builddir [file tail $binfile]]"
+
+ return true
+}
+
+# Build a shared executable.
+
+proc build_corefile_buildid_shared {} {
+ global srcdir subdir testfile binfile srcfile sharedir
+
+ set builddir [standard_output_file $sharedir]
+
+ # Compile DSO.
+ set srcdso [file join $srcdir $subdir $testfile-shlib-shr.c]
+ set objdso [standard_output_file $testfile-shlib-shr.so]
+ if {[gdb_compile_shlib $srcdso $objdso {debug}] != ""} {
+ untested "failed to compile dso"
+ return false
+ }
+
+ # Compile shared library.
+ set srclib [file join $srcdir $subdir $testfile-shlib.c]
+ set libname lib$testfile.so
+ set objlib [standard_output_file $libname]
+ set dlopen_lib [shlib_target_file \
+ [file join $builddir [file tail $objdso]]]
+ set opts [list debug shlib_load \
+ additional_flags=-DSHLIB_NAME=\"$dlopen_lib\"]
+ if {[gdb_compile_shlib $srclib $objlib $opts] != ""} {
+ untested "failed to compile shared library"
+ return false
+ }
+
+ # Compile main program.
+ set srcexec [file join $srcdir $subdir $srcfile]
+ set binfile [standard_output_file $testfile-shared]
+ set opts [list debug shlib=$objlib additional_flags=-DTEST_SHARED]
+ if {[gdb_compile $srcexec $binfile executable $opts] != ""} {
+ untested "failed to compile shared executable"
+ return false
+ }
+
+ # Move objects to non-default path.
+ remote_exec build "rm -rf $builddir"
+ remote_exec build "mkdir $builddir"
+ remote_exec build "mv $binfile $builddir"
+ remote_exec build "mv $objdso $builddir"
+ remote_exec build "mv $objlib $builddir"
+
+ return true
+}
+
+# Append DEBUGDIR to the debug-file-directory path.
+
+proc append_debug_dir {debugdir} {
+ global gdb_prompt
+
+ set orig_debugdir {}
+ gdb_test_multiple "show debug-file-directory" \
+ "get debug-file-directory" {
+ -re "The directory where separate debug symbols are searched for is \"(.*)\"\.\[\r\n\]+$gdb_prompt $" {
+ set orig_debugdir $expect_out(1,string)
+ pass "get debug-file-directory"
+ }
+ }
+ gdb_test_no_output "set debug-file-directory $debugdir:$orig_debugdir" \
+ "append debug directory"
+}
+
+# A convenience procedure to check if "info files" mentions the exec file
+# FILE.
+
+proc check_exec_file {file} {
+ send_log "expecting exec file \"$file\"\n"
+ gdb_test "info files" "Local exec file:\[\r\n\t\ \]+`[string_to_regexp $file]'.*"
+}
+
+# Test whether gdb can find an exec file from a core file's build-id.
+# The executable (and separate debuginfo if SEPDEBUG is true) is
+# copied to the .build-id directory.
+#
+# SUFFIX is appended to the .builid-id parent directory name to
+# keep all tests separate.
+# SYMLINK specifies whether build-id files should be copied or symlinked.
+# SHARED is a boolean indicating whether we are testing the shared
+# library core dump test case.
+
+proc locate_exec_from_core_build_id {corefile buildid suffix \
+ sepdebug symlink shared} {
+ global testfile binfile srcfile
+
+ clean_restart
+
+ # Set up the build-id directory and symlink the binary there.
+ if {$symlink} {
+ set d "symlinkdir"
+ } else {
+ set d "debugdir"
+ }
+ set debugdir [standard_output_file $d-$suffix]
+ remote_exec build "rm -rf $debugdir"
+ remote_exec build \
+ "mkdir -p [file join $debugdir [file dirname $buildid]]"
+
+ set files_list {}
+ if {$sepdebug} {
+ lappend files_list "$binfile.stripped" $buildid
+ lappend files_list "$binfile.debug" "$buildid.debug"
+ } else {
+ lappend files_list $binfile $buildid
+ }
+ if {$shared} {
+ global sharedir
+ set builddir [standard_output_file $sharedir]
+ } else {
+ global execdir
+ set builddir [standard_output_file $execdir]
+ }
+ foreach {target name} $files_list {
+ set t [file join $builddir [file tail $target]]
+ if {$symlink} {
+ remote_exec build "ln -s $t [file join $debugdir $name]"
+ } else {
+ remote_exec build "cp $t [file join $debugdir $name]"
+ }
+ }
+
+ # Append the debugdir to the separate debug directory search path.
+ append_debug_dir $debugdir
+
+ gdb_test "core-file $corefile" "Program terminated with .*" \
+ "load core file"
+ if {$symlink} {
+ if {$sepdebug} {
+ set expected_file [file join $builddir \
+ [file tail "$binfile.stripped"]]
+ } else {
+ set expected_file [file join $builddir [file tail $binfile]]
+ }
+ } else {
+ set expected_file $buildid
+ }
+ check_exec_file [file join $debugdir $expected_file]
+}
+
+# Run a build-id tests on a core file.
+# Supported options: "-shared" and "-sepdebug" for running tests
+# of shared and/or stripped/.debug executables.
+
+proc do_corefile_buildid_tests {args} {
+ global binfile testfile srcfile execdir sharedir
+
+ # Parse options.
+ parse_args [list {sepdebug} {shared}]
+
+ # PROGRAM to run to generate core file. This could be different
+ # than the program that was originally built, e.g., for a stripped
+ # executable.
+ if {$shared} {
+ set builddir [standard_output_file $sharedir]
+ } else {
+ set builddir [standard_output_file $execdir]
+ }
+ set program_to_run [file join $builddir [file tail $binfile]]
+
+ # A list of suffixes to use to describe the test and the .build-id
+ # directory for the test. The suffix will be used, joined with spaces,
+ # to prefix all tests for the given run. It will be used, joined with
+ # dashes, to create a unique build-id directory.
+ set suffix {}
+ if {$shared} {
+ lappend suffix "shared"
+ } else {
+ lappend suffix "exec"
+ }
+
+ if {$sepdebug} {
+ # Strip debuginfo into its own file.
+ if {[gdb_gnu_strip_debug [standard_output_file $program_to_run]] \
+ != 0} {
+ untested "could not strip executable for [join $suffix \ ]"
+ return
+ }
+
+ # Run the stripped program instead of the original.
+ set program_to_run [file join $builddir \
+ [file tail "$binfile.stripped"]]
+ lappend suffix "sepdebug"
+ }
+
+ # Find the core file.
+ set corefile [core_find $program_to_run]
+ if {$corefile == ""} {
+ untested "could not generate core file"
+ return
+ }
+ verbose -log "corefile is $corefile"
+
+ # Grab the build-id from the binary, removing ".debug" from the end.
+ set buildid [build_id_debug_filename_get $program_to_run]
+ if {$buildid == ""} {
+ untested "binary for [join $suffix \ ] has no build-id"
+ }
+ regsub {\.debug$} $buildid {} buildid
+ verbose -log "build-id is $buildid"
+
+ with_test_prefix "[join $suffix \ ]" {
+ locate_exec_from_core_build_id $corefile $buildid \
+ [join $suffix -] $sepdebug false $shared
+ }
+
+ with_test_prefix "symlink [join $suffix \ ]" {
+ locate_exec_from_core_build_id $corefile $buildid \
+ [join $suffix -] $sepdebug true $shared
+ }
+}
+
+# Directories where executables will be moved before testing.
+set execdir "build-exec"
+set sharedir "build-shared"
+
+#
+# Do tests
+#
+
+build_corefile_buildid_exec
+do_corefile_buildid_tests
+do_corefile_buildid_tests -sepdebug
+
+if {![skip_shlib_tests]} {
+ build_corefile_buildid_shared
+ do_corefile_buildid_tests -shared
+ do_corefile_buildid_tests -shared -sepdebug
+}