- Maintenance script qa.sh: * Add SLE-12/x86_64 to "known clean configs". * Add fail for PR29405. * Add fail for PR26915. - Patches added: * gdb-testsuite-fix-gdb.threads-killed-outside.exp-on-aarch64.patch - Maintenance script qa.sh: * Remove PR29247 internal-error. * Add SLE-15/aarch64 to "known clean configs". - Patches added: * gdb-fix-watchpoints-triggered.patch - Maintenance script qa.sh: * Add kfails for PR25038, PR29253, and PR29423. * Remove gdb.mi/mi-var-invalidate-shlib.exp kfails. - Mention qa-local.sh, qa-remote.sh and README.qa as sources. - Maintenance script qa-local.sh: * Use have_combo consistently. - Maintenance script qa.sh: * Add kfail_aarch64. * Add PR29419/PR29409 kfails. * Update PR29247 kfails. - Patches added: * make-gdb.ada-float-bits.exp-more-generic.patch * gdb-testsuite-fix-gdb.ada-literals.exp-with-aarch64.patch - Actually apply fixup-gdb-test-bt-cfi-without-die.patch and fixup-2-gdb-rhbz1553104-s390x-arch12-test.patch. - Also remove gdb-6.5-readline-long-line-crash-test.patch from patches list in gdb.spec. - Patches added: * powerpc-add-support-for-ieee-128-bit-format.patch * powerpc-correct-the-gdb-ioctl-values-for-tcgets-tcsets-tcsetsw-and-tcsetsf.patch * gdb-testsuite-remove-target-limits-in-gdb.base-catch-syscall.exp.patch * powerpc-fix-for-gdb.base-eh_return.exp.patch * fix-comparison-of-unsigned-long-int-to-int-in-record_linux_system_call.patch * gdb-testsuite-fix-gdb.reverse-test_ioctl_tcsetsw.exp-with-libc-debuginfo.patch * fixup-gdb-test-bt-cfi-without-die.patch * fix-core-file-detach-crash-corefiles-29275.patch * gdb-testsuite-fix-gdb.dwarf2-dw2-out-of-range-end-of-seq.exp-on-aarch64.patch * gdb-testsuite-fix-gdb.base-catch-syscall.exp-without-enable-targets.patch * gdb-testsuite-fix-gdb.base-catch-syscall.exp-with-with-expat-no.patch * fix-for-gdb.base-solib-search.exp-test.patch - Patch removed: * gdb-6.7-ppc-clobbered-registers-O2-test.patch * gdb-6.5-readline-long-line-crash-test.patch - Patches updated: * gdb-tdep-update-syscalls-ppc64-ppc-linux.xml.patch * gdb-testsuite-handle-pipe2-syscall-in-gdb.base-catch-syscall.exp.patch - Maintenance script qa.sh: * Add PR28504 KFAILs. * Make .sum file matching less complex. * Add fedora test-case kfail. - Maintenance script qa-local.sh: * Fix incorrect path name. - Update comments in gdb.spec. - Patches added: * powerpc-update-expected-floating-point-output-for-gdb.arch-altivec-regs.exp-and-gdb.arch-vsx-regs.exp.patch - Patches updated: * gdb-testsuite-support-recording-of-getrandom.patch (add aarch64 part) - Maintenance script qa.sh: * Add i586 to known clean configs. - Patches added: * gdb-testsuite-enable-some-test-cases-for-x86_64-m32.patch * gdb-testsuite-fix-gdb.reverse-i387-env-reverse.exp-for-pie.patch * gdb-testsuite-support-recording-of-getrandom.patch - Patches updated: * gdb-record-handle-statx-system-call.patch - Maintenance script qa.sh: * Allow only two summary files, for i586. * Add i586 KFAILs. - Maintenance script qa-local.sh: * Add i586. - Maintenance script qa-local.sh: * Fix rpm pathname. - Maintenance script qa-remote.sh: * Skip stale config openSUSE_Leap_15.2. - Maintenance script qa.sh: * Drop known clean config: Leap 15.2 x86_64. - Maintenance script qa-local.sh: * Add cleanup step. * Add "build all configs without testsuite" step. * For "build all configs with testsuite" step, redirect output to log and produce PASS/FAIL line, and make sure buildroot is removed also in case of missing rpm. * Use "--clean --trust-all-projects" for osc build commands. * Drop openSUSE_Leap_15.2. - Maintenance script qa.sh: * Rename argument 6 to -local. * Add PR29247 KFAILs. * Update internal-error regexps. - New maintenance script qa-remote.sh. - Add "build all configs without testsuite" step in README.qa. - Patches added (backport from trunk): * gdb-testsuite-remove-attach-test-from-can_spawn_for_attach.patch - README.qa: * Add remote qa entry. * Update local qa entry: * Add notes entry. * Other updates to match changes in qa-local.sh. - Fix installed but unpackaged /usr/share/info/ctf-spec.info.gz. - Rebase to 12.1 release (as in fedora 36 @ 89947a7): * DBX mode is deprecated, and will be removed in GDB 13. * GDB 12 is the last release of GDB that will support building against Python 2. From GDB 13, it will only be possible to build GDB itself with Python 3 support. * Improved C++ template support: GDB now treats functions/types involving C++ templates like it does function overloads. Users may omit parameter lists to set breakpoints on families of template functions, including types/functions composed of multiple template types: (gdb) break template_func(template_1, int) The above will set breakpoints at every function `template_func' where the first function parameter is any template type named `template_1' and the second function parameter is `int'. TAB completion also gains similar improvements. * New commands: maint set backtrace-on-fatal-signal on|off maint show backtrace-on-fatal-signal This setting is 'on' by default. When 'on' GDB will print a limited backtrace to stderr in the situation where GDB terminates with a fatal signal. This only supported on some platforms where the backtrace and backtrace_symbols_fd functions are available. set source open on|off show source open This setting, which is on by default, controls whether GDB will try to open source code files. Switching this off will stop GDB trying to open and read source code files, which can be useful if the files are located over a slow network connection. set varsize-limit show varsize-limit These are now deprecated aliases for "set max-value-size" and "show max-value-size". task apply [all | TASK-IDS...] [FLAG]... COMMAND Like "thread apply", but applies COMMAND to Ada tasks. watch [...] task ID Watchpoints can now be restricted to a specific Ada task. maint set internal-error backtrace on|off maint show internal-error backtrace maint set internal-warning backtrace on|off maint show internal-warning backtrace GDB can now print a backtrace of itself when it encounters either an internal-error, or an internal-warning. This is on by default for internal-error and off by default for internal-warning. set logging on|off Deprecated and replaced by "set logging enabled on|off". set logging enabled on|off show logging enabled These commands set or show whether logging is enabled or disabled. exit You can now exit GDB by using the new command "exit", in addition to the existing "quit" command. set debug threads on|off show debug threads Print additional debug messages about thread creation and deletion. set debug linux-nat on|off show debug linux-nat These new commands replaced the old 'set debug lin-lwp' and 'show debug lin-lwp' respectively. Turning this setting on prints debug messages relating to GDB's handling of native Linux inferiors. maint flush source-cache Flush the contents of the source code cache. maint set gnu-source-highlight enabled on|off maint show gnu-source-highlight enabled Whether GDB should use the GNU Source Highlight library for adding styling to source code. When off, the library will not be used, even when available. When GNU Source Highlight isn't used, or can't add styling to a particular source file, then the Python Pygments library will be used instead. set suppress-cli-notifications (on|off) show suppress-cli-notifications This controls whether printing the notifications is suppressed for CLI. CLI notifications occur when you change the selected context (i.e., the current inferior, thread and/or the frame), or when the program being debugged stops (e.g., because of hitting a breakpoint, completing source-stepping, an interrupt, etc.). set style disassembler enabled on|off show style disassembler enabled If GDB is compiled with Python support, and the Python Pygments package is available, then, when this setting is on, disassembler output will have styling applied. set ada source-charset show ada source-charset Set the character set encoding that is assumed for Ada symbols. Valid values for this follow the values that can be passed to the GNAT compiler via the '-gnati' option. The default is ISO-8859-1. * Changed commands: print Printing of floating-point values with base-modifying formats like /x has been changed to display the underlying bytes of the value in the desired base. This was GDB's documented behavior, but was never implemented correctly. maint packet This command can now print a reply, if the reply includes non-printable characters. Any non-printable characters are printed as escaped hex, e.g. \x?? where '??' is replaces with the value of the non-printable character. clone-inferior The clone-inferior command now ensures that the TTY, CMD and ARGS settings are copied from the original inferior to the new one. All modifications to the environment variables done using the 'set environment' or 'unset environment' commands are also copied to the new inferior. set debug lin-lwp on|off show debug lin-lwp These commands have been removed from GDB. The new command 'set debug linux-nat' and 'show debug linux-nat' should be used instead. info win This command now includes information about the width of the tui windows in its output. * GDB's Ada parser now supports an extension for specifying the exact byte contents of a floating-point literal. This can be useful for setting floating-point registers to a precise value without loss of precision. The syntax is an extension of the based literal syntax. Use, e.g., "16lf#0123abcd#" -- the number of "l"s controls the width of the floating-point type, and the "f" is the marker for floating point. * MI changes: ** The '-add-inferior' with no option flags now inherits the connection of the current inferior, this restores the behaviour of GDB as it was prior to GDB 10. ** The '-add-inferior' command now accepts a '--no-connection' option, which causes the new inferior to start without a connection. * Python API: ** New function gdb.add_history(), which takes a gdb.Value object and adds the value it represents to GDB's history list. An integer, the index of the new item in the history list, is returned. ** New function gdb.history_count(), which returns the number of values in GDB's value history. ** New gdb.events.gdb_exiting event. This event is called with a gdb.GdbExitingEvent object which has the read-only attribute 'exit_code', which contains the value of the GDB exit code. This event is triggered once GDB decides it is going to exit, but before GDB starts to clean up its internal state. ** New function gdb.architecture_names(), which returns a list containing all of the possible Architecture.name() values. Each entry is a string. ** New function gdb.Architecture.integer_type(), which returns an integer type given a size and a signed-ness. ** New gdb.TargetConnection object type that represents a connection (as displayed by the 'info connections' command). A sub-class, gdb.RemoteTargetConnection, is used to represent 'remote' and 'extended-remote' connections. ** The gdb.Inferior type now has a 'connection' property which is an instance of gdb.TargetConnection, the connection used by this inferior. This can be None if the inferior has no connection. ** New 'gdb.events.connection_removed' event registry, which emits a 'gdb.ConnectionEvent' when a connection is removed from GDB. This event has a 'connection' property, a gdb.TargetConnection object for the connection being removed. ** New gdb.connections() function that returns a list of all currently active connections. ** New gdb.RemoteTargetConnection.send_packet(PACKET) method. This is equivalent to the existing 'maint packet' CLI command; it allows a user specified packet to be sent to the remote target. ** New function gdb.host_charset(), returns a string, which is the name of the current host charset. ** New gdb.set_parameter(NAME, VALUE). This sets the gdb parameter NAME to VALUE. ** New gdb.with_parameter(NAME, VALUE). This returns a context manager that temporarily sets the gdb parameter NAME to VALUE, then resets it when the context is exited. ** The gdb.Value.format_string method now takes a 'styling' argument, which is a boolean. When true, the returned string can include escape sequences to apply styling. The styling will only be present if styling is otherwise turned on in GDB (see 'help set styling'). When false, which is the default if the argument is not given, then no styling is applied to the returned string. ** New read-only attribute gdb.InferiorThread.details, which is either a string, containing additional, target specific thread state information, or None, if there is no such additional information. ** New read-only attribute gdb.Type.is_scalar, which is True for scalar types, and False for all other types. ** New read-only attribute gdb.Type.is_signed. This attribute should only be read when Type.is_scalar is True, and will be True for signed types, and False for all other types. Attempting to read this attribute for non-scalar types will raise a ValueError. ** It is now possible to add GDB/MI commands implemented in Python. - Update libipt to v2.0.5. - Patches added: * gdb-6.3-rh-testversion-20041202.patch * gdb-6.5-BEA-testsuite.patch * gdb-6.6-buildid-locate-misleading-warning-missing-debuginfo-rhbz981154.patch * gdb-6.7-charsign-test.patch * gdb-6.8-bz466901-backtrace-full-prelinked.patch * gdb-fix-for-gdb.base-eof-exit.exp-test-failures.patch * gdb-improved-eof-handling-when-using-readline-7.patch * gdb-libexec-add-index.patch * gdb-tdep-detect-get_pc_thunk-call-in-i386-prologue.patch * gdb-testsuite-address-test-failures-in-gdb.mi-mi-multi-commands.exp.patch * gdb-testsuite-detect-change-instead-of-init-in-gdb.mi-mi-var-block.exp.patch * gdb-testsuite-fix-gdb.opt-clobbered-registers-o2.exp-with-gcc-12.patch * gdb-testsuite-fix-occasional-failure-in-gdb.mi-mi-multi-commands.exp.patch * gdb-testsuite-fix-test-failure-when-building-against-readline-v7.patch * gdb-testsuite-handle-older-python-in-gdb.python-py-send-packet.py.patch * gdb-testsuite-handle-quotes-in-gdb_py_module_available.patch * gdb-testsuite-handle-unordered-dict-in-gdb.python-py-mi-cmd.exp.patch * gdb-testsuite-skip-gdb.fortran-namelist.exp-for-gfortran-4.8.patch * gdb-testsuite-workaround-unnecessary-.s-file-with-gfortran-4.8.patch - Patches dropped: * aarch64-make-gdbserver-register-set-selection-dynamic.patch * fix-build-with-current-gcc-el_explicit-location-always-non-null.patch * fix-gdb.base-sigstep.exp-test-for-ppc.patch * fix-gdb.multi-multi-term-settings.exp-race.patch * fixup-2-gdb-6.6-buildid-locate.patch * fixup-gdb-6.6-buildid-locate.patch * gdb-6.3-inferior-notification-20050721.patch * gdb-ada-fix-assert-in-ada_is_unconstrained_packed_array_type.patch * gdb-build-add-cxx_dialect-to-cxx.patch * gdb-build-make-c-exp.y-work-with-bison-3.8.patch * gdb-doc-fix-print-inferior-events-default.patch * gdb-exp-improve-error-reading-variable-message.patch * gdb-fortran-handle-dw-at-string-length-with-loclistptr.patch * gdb-r_version-check.patch * gdb-rhbz1976887-field-location-kind.patch * gdb-rhbz2012976-paper-over-fortran-lex-problems.patch * gdb-symtab-add-call_site_eq-and-call_site_hash.patch * gdb-symtab-c-ify-call_site.patch * gdb-symtab-fix-htab_find_slot-call-in-read_call_site_scope.patch * gdb-symtab-fix-segfault-in-search_one_symtab.patch * gdb-symtab-remove-compunit_call_site_htab.patch * gdb-symtab-use-unrelocated-addresses-in-call_site.patch * gdb-tdep-fix-avx512-m32-support-in-gdbserver.patch * gdb-tdep-rs6000-don-t-skip-system-call-in-skip_prologue.patch * gdb-test-for-rhbz1976887.patch * gdb-testsuite-add-gdb.arch-ppc64-break-on-_exit.exp.patch * gdb-testsuite-add-gdb.opt-break-on-_exit.exp.patch * gdb-testsuite-add-gdb.testsuite-dump-system-info.exp.patch * gdb-testsuite-add-missing-wait-in-gdb.base-signals-state-child.exp.patch * gdb-testsuite-add-nopie-in-two-test-cases.patch * gdb-testsuite-detect-no-mpx-support.patch * gdb-testsuite-disable-inferior-output-in-gdb.base-foll-vfork.exp.patch * gdb-testsuite-don-t-error-when-trying-to-unset-last_spawn_tty_name.patch * gdb-testsuite-factor-out-dump_info-in-gdb.testsuite-dump-system-info.exp.patch * gdb-testsuite-fix-assembly-comments-in-gdb.dwarf2-clang-debug-names.exp.tcl.patch * gdb-testsuite-fix-data-alignment-in-gdb.arch-i386-avx-sse-.exp.patch * gdb-testsuite-fix-fail-in-gdb.base-annota1.exp.patch * gdb-testsuite-fix-fail-in-gdb.tui-basic.exp.patch * gdb-testsuite-fix-fail-in-gdb.tui-corefile-run.exp.patch * gdb-testsuite-fix-gdb.ada-big_packed_array.exp-xfail-for-m32.patch * gdb-testsuite-fix-gdb.arch-i386-pkru.exp-on-linux.patch * gdb-testsuite-fix-gdb.base-annota1.exp-with-pie.patch * gdb-testsuite-fix-gdb.base-dcache-flush.exp.patch * gdb-testsuite-fix-gdb.gdb-selftest.exp.patch * gdb-testsuite-fix-gdb.guile-scm-type.exp-with-gcc-4.8.patch * gdb-testsuite-fix-gdb.python-py-events.exp.patch * gdb-testsuite-fix-gdb.server-server-kill.exp-with-m32.patch * gdb-testsuite-fix-gdb.threads-check-libthread-db.exp-with-glibc-2.34.patch * gdb-testsuite-fix-gdb.threads-linux-dp.exp.patch * gdb-testsuite-fix-gdb.threads-thread-specific-bp.exp.patch * gdb-testsuite-fix-port-detection-in-gdb.debuginfod-fetch_src_and_symbols.exp.patch * gdb-testsuite-fix-regexp-in-gdb.base-foll-vfork.exp.patch * gdb-testsuite-fix-stepi-test-cases-with-unix-m32-fpie-pie.patch * gdb-testsuite-handle-recursive-internal-problem-in-gdb_internal_error_resync.patch * gdb-testsuite-handle-runto-fail-in-gdb.mi-mi-var-cp.exp.patch * gdb-testsuite-handle-sigill-in-two-gdb.arch-powerpc-test-cases.patch * gdb-testsuite-handle-supports_memtag-in-gdb.base-gdb-caching-proc.exp.patch * gdb-testsuite-make-gdb.base-annota1.exp-more-robust.patch * gdb-testsuite-refactor-regexp-in-gdb.base-annota1.exp.patch * gdb-testsuite-support-fpie-fno-pie-pie-no-pie-in-gdb_compile_rust.patch * gdb-testsuite-update-test-gdb.base-step-over-syscall.exp.patch * gdb-testsuite-use-compiler-generated-instead-of-gas-generated-stabs.patch * gdb-tui-fix-breakpoint-display-functionality.patch * ibm-z-add-another-arch14-instruction.patch * ibm-z-remove-lpswey-parameter.patch - Patched updated: * gdb-6.3-gstack-20050411.patch * gdb-6.5-bz185337-resolve-tls-without-debuginfo-v2.patch * gdb-6.6-buildid-locate-rpm-librpm-workaround.patch * gdb-6.6-buildid-locate-rpm-scl.patch * gdb-6.6-buildid-locate-rpm.patch * gdb-6.6-buildid-locate-solib-missing-ids.patch * gdb-6.6-buildid-locate.patch * gdb-cli-add-ignore-errors-command.patch * gdb-container-rh-pkg.patch * gdb-core-open-vdso-warning.patch * gdb-fedora-libncursesw.patch * gdb-gcore-bash.patch * gdb-linux_perf-bundle.patch * gdb-testsuite-handle-init-errors-in-gdb.mi-user-selected-context-sync.exp.patch - Add BuildRequires python-xml. - Maintenance script qa.sh: * Add -sle-12 and -factory options. * Handle *.-fPIE.-pie.sum files. * Add KFAILs for PRs 26292, 29238, 25059, 29240, 29241, 29244, 29245, 29160, 29196. * Move PR27539 KFAILs from kfail_factory to kfail. - New maintenance script qa-local.sh. - New file README.qa. OBS-URL: https://build.opensuse.org/request/show/991863 OBS-URL: https://build.opensuse.org/package/show/devel:gcc/gdb?expand=0&rev=325
1909 lines
60 KiB
Diff
1909 lines
60 KiB
Diff
From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
|
|
From: Fedora GDB patches <invalid@email.com>
|
|
Date: Fri, 27 Oct 2017 21:07:50 +0200
|
|
Subject: gdb-6.6-buildid-locate.patch
|
|
|
|
;; New locating of the matching binaries from the pure core file (build-id).
|
|
;;=push+jan
|
|
|
|
diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h
|
|
--- a/bfd/libbfd-in.h
|
|
+++ b/bfd/libbfd-in.h
|
|
@@ -115,7 +115,7 @@ static inline char *
|
|
bfd_strdup (const char *str)
|
|
{
|
|
size_t len = strlen (str) + 1;
|
|
- char *buf = bfd_malloc (len);
|
|
+ char *buf = (char *) bfd_malloc (len);
|
|
if (buf != NULL)
|
|
memcpy (buf, str, len);
|
|
return buf;
|
|
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
|
|
--- a/bfd/libbfd.h
|
|
+++ b/bfd/libbfd.h
|
|
@@ -120,7 +120,7 @@ static inline char *
|
|
bfd_strdup (const char *str)
|
|
{
|
|
size_t len = strlen (str) + 1;
|
|
- char *buf = bfd_malloc (len);
|
|
+ char *buf = (char *) bfd_malloc (len);
|
|
if (buf != NULL)
|
|
memcpy (buf, str, len);
|
|
return buf;
|
|
diff --git a/gdb/build-id.c b/gdb/build-id.c
|
|
--- a/gdb/build-id.c
|
|
+++ b/gdb/build-id.c
|
|
@@ -24,13 +24,71 @@
|
|
#include "gdbsupport/gdb_vecs.h"
|
|
#include "symfile.h"
|
|
#include "objfiles.h"
|
|
+#include <sys/stat.h>
|
|
+#include "elf-bfd.h"
|
|
+#include "elf/common.h"
|
|
+#include "elf/external.h"
|
|
+#include "elf/internal.h"
|
|
#include "filenames.h"
|
|
+#include "gdb_bfd.h"
|
|
+#include "gdbcmd.h"
|
|
#include "gdbcore.h"
|
|
+#include "inferior.h"
|
|
+#include "objfiles.h"
|
|
+#include "observable.h"
|
|
+#include "symfile.h"
|
|
+
|
|
+#define BUILD_ID_VERBOSE_NONE 0
|
|
+#define BUILD_ID_VERBOSE_FILENAMES 1
|
|
+#define BUILD_ID_VERBOSE_BINARY_PARSE 2
|
|
+static int build_id_verbose = BUILD_ID_VERBOSE_FILENAMES;
|
|
+static void
|
|
+show_build_id_verbose (struct ui_file *file, int from_tty,
|
|
+ struct cmd_list_element *c, const char *value)
|
|
+{
|
|
+ fprintf_filtered (file, _("Verbosity level of the build-id locator is %s.\n"),
|
|
+ value);
|
|
+}
|
|
+/* Locate NT_GNU_BUILD_ID and return its matching debug filename.
|
|
+ FIXME: NOTE decoding should be unified with the BFD core notes decoding. */
|
|
+
|
|
+static struct bfd_build_id *
|
|
+build_id_buf_get (bfd *templ, gdb_byte *buf, bfd_size_type size)
|
|
+{
|
|
+ bfd_byte *p;
|
|
+
|
|
+ p = buf;
|
|
+ while (p < buf + size)
|
|
+ {
|
|
+ /* FIXME: bad alignment assumption. */
|
|
+ Elf_External_Note *xnp = (Elf_External_Note *) p;
|
|
+ size_t namesz = H_GET_32 (templ, xnp->namesz);
|
|
+ size_t descsz = H_GET_32 (templ, xnp->descsz);
|
|
+ bfd_byte *descdata = (gdb_byte *) xnp->name + BFD_ALIGN (namesz, 4);
|
|
+
|
|
+ if (H_GET_32 (templ, xnp->type) == NT_GNU_BUILD_ID
|
|
+ && namesz == sizeof "GNU"
|
|
+ && memcmp (xnp->name, "GNU", sizeof "GNU") == 0)
|
|
+ {
|
|
+ size_t sz = descsz;
|
|
+ gdb_byte *data = (gdb_byte *) descdata;
|
|
+ struct bfd_build_id *retval;
|
|
+
|
|
+ retval = (struct bfd_build_id *) xmalloc (sizeof *retval - 1 + sz);
|
|
+ retval->size = sz;
|
|
+ memcpy (retval->data, data, sz);
|
|
+
|
|
+ return retval;
|
|
+ }
|
|
+ p = descdata + BFD_ALIGN (descsz, 4);
|
|
+ }
|
|
+ return NULL;
|
|
+}
|
|
|
|
/* See build-id.h. */
|
|
|
|
const struct bfd_build_id *
|
|
-build_id_bfd_get (bfd *abfd)
|
|
+build_id_bfd_shdr_get (bfd *abfd)
|
|
{
|
|
if (!bfd_check_format (abfd, bfd_object)
|
|
&& !bfd_check_format (abfd, bfd_core))
|
|
@@ -43,6 +101,348 @@ build_id_bfd_get (bfd *abfd)
|
|
return NULL;
|
|
}
|
|
|
|
+/* Core files may have missing (corrupt) SHDR but PDHR is correct there.
|
|
+ bfd_elf_bfd_from_remote_memory () has too much overhead by
|
|
+ allocating/reading all the available ELF PT_LOADs. */
|
|
+
|
|
+static struct bfd_build_id *
|
|
+build_id_phdr_get (bfd *templ, bfd_vma loadbase, unsigned e_phnum,
|
|
+ Elf_Internal_Phdr *i_phdr)
|
|
+{
|
|
+ int i;
|
|
+ struct bfd_build_id *retval = NULL;
|
|
+
|
|
+ for (i = 0; i < e_phnum; i++)
|
|
+ if (i_phdr[i].p_type == PT_NOTE && i_phdr[i].p_filesz > 0)
|
|
+ {
|
|
+ Elf_Internal_Phdr *hdr = &i_phdr[i];
|
|
+ gdb_byte *buf;
|
|
+ int err;
|
|
+
|
|
+ buf = (gdb_byte *) xmalloc (hdr->p_filesz);
|
|
+ err = target_read_memory (loadbase + i_phdr[i].p_vaddr, buf,
|
|
+ hdr->p_filesz);
|
|
+ if (err == 0)
|
|
+ retval = build_id_buf_get (templ, buf, hdr->p_filesz);
|
|
+ else
|
|
+ retval = NULL;
|
|
+ xfree (buf);
|
|
+ if (retval != NULL)
|
|
+ break;
|
|
+ }
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+/* First we validate the file by reading in the ELF header and checking
|
|
+ the magic number. */
|
|
+
|
|
+static inline bfd_boolean
|
|
+elf_file_p (Elf64_External_Ehdr *x_ehdrp64)
|
|
+{
|
|
+ gdb_assert (sizeof (Elf64_External_Ehdr) >= sizeof (Elf32_External_Ehdr));
|
|
+ gdb_assert (offsetof (Elf64_External_Ehdr, e_ident)
|
|
+ == offsetof (Elf32_External_Ehdr, e_ident));
|
|
+ gdb_assert (sizeof (((Elf64_External_Ehdr *) 0)->e_ident)
|
|
+ == sizeof (((Elf32_External_Ehdr *) 0)->e_ident));
|
|
+
|
|
+ return ((x_ehdrp64->e_ident[EI_MAG0] == ELFMAG0)
|
|
+ && (x_ehdrp64->e_ident[EI_MAG1] == ELFMAG1)
|
|
+ && (x_ehdrp64->e_ident[EI_MAG2] == ELFMAG2)
|
|
+ && (x_ehdrp64->e_ident[EI_MAG3] == ELFMAG3));
|
|
+}
|
|
+
|
|
+/* Translate an ELF file header in external format into an ELF file header in
|
|
+ internal format. */
|
|
+
|
|
+#define H_GET_WORD(bfd, ptr) (is64 ? H_GET_64 (bfd, (ptr)) \
|
|
+ : H_GET_32 (bfd, (ptr)))
|
|
+#define H_GET_SIGNED_WORD(bfd, ptr) (is64 ? H_GET_S64 (bfd, (ptr)) \
|
|
+ : H_GET_S32 (bfd, (ptr)))
|
|
+
|
|
+static void
|
|
+elf_swap_ehdr_in (bfd *abfd,
|
|
+ const Elf64_External_Ehdr *src64,
|
|
+ Elf_Internal_Ehdr *dst)
|
|
+{
|
|
+ int is64 = bfd_get_arch_size (abfd) == 64;
|
|
+#define SRC(field) (is64 ? src64->field \
|
|
+ : ((const Elf32_External_Ehdr *) src64)->field)
|
|
+
|
|
+ int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma;
|
|
+ memcpy (dst->e_ident, SRC (e_ident), EI_NIDENT);
|
|
+ dst->e_type = H_GET_16 (abfd, SRC (e_type));
|
|
+ dst->e_machine = H_GET_16 (abfd, SRC (e_machine));
|
|
+ dst->e_version = H_GET_32 (abfd, SRC (e_version));
|
|
+ if (signed_vma)
|
|
+ dst->e_entry = H_GET_SIGNED_WORD (abfd, SRC (e_entry));
|
|
+ else
|
|
+ dst->e_entry = H_GET_WORD (abfd, SRC (e_entry));
|
|
+ dst->e_phoff = H_GET_WORD (abfd, SRC (e_phoff));
|
|
+ dst->e_shoff = H_GET_WORD (abfd, SRC (e_shoff));
|
|
+ dst->e_flags = H_GET_32 (abfd, SRC (e_flags));
|
|
+ dst->e_ehsize = H_GET_16 (abfd, SRC (e_ehsize));
|
|
+ dst->e_phentsize = H_GET_16 (abfd, SRC (e_phentsize));
|
|
+ dst->e_phnum = H_GET_16 (abfd, SRC (e_phnum));
|
|
+ dst->e_shentsize = H_GET_16 (abfd, SRC (e_shentsize));
|
|
+ dst->e_shnum = H_GET_16 (abfd, SRC (e_shnum));
|
|
+ dst->e_shstrndx = H_GET_16 (abfd, SRC (e_shstrndx));
|
|
+
|
|
+#undef SRC
|
|
+}
|
|
+
|
|
+/* Translate an ELF program header table entry in external format into an
|
|
+ ELF program header table entry in internal format. */
|
|
+
|
|
+static void
|
|
+elf_swap_phdr_in (bfd *abfd,
|
|
+ const Elf64_External_Phdr *src64,
|
|
+ Elf_Internal_Phdr *dst)
|
|
+{
|
|
+ int is64 = bfd_get_arch_size (abfd) == 64;
|
|
+#define SRC(field) (is64 ? src64->field \
|
|
+ : ((const Elf32_External_Phdr *) src64)->field)
|
|
+
|
|
+ int signed_vma = get_elf_backend_data (abfd)->sign_extend_vma;
|
|
+
|
|
+ dst->p_type = H_GET_32 (abfd, SRC (p_type));
|
|
+ dst->p_flags = H_GET_32 (abfd, SRC (p_flags));
|
|
+ dst->p_offset = H_GET_WORD (abfd, SRC (p_offset));
|
|
+ if (signed_vma)
|
|
+ {
|
|
+ dst->p_vaddr = H_GET_SIGNED_WORD (abfd, SRC (p_vaddr));
|
|
+ dst->p_paddr = H_GET_SIGNED_WORD (abfd, SRC (p_paddr));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ dst->p_vaddr = H_GET_WORD (abfd, SRC (p_vaddr));
|
|
+ dst->p_paddr = H_GET_WORD (abfd, SRC (p_paddr));
|
|
+ }
|
|
+ dst->p_filesz = H_GET_WORD (abfd, SRC (p_filesz));
|
|
+ dst->p_memsz = H_GET_WORD (abfd, SRC (p_memsz));
|
|
+ dst->p_align = H_GET_WORD (abfd, SRC (p_align));
|
|
+
|
|
+#undef SRC
|
|
+}
|
|
+
|
|
+#undef H_GET_SIGNED_WORD
|
|
+#undef H_GET_WORD
|
|
+
|
|
+static Elf_Internal_Phdr *
|
|
+elf_get_phdr (bfd *templ, bfd_vma ehdr_vma, unsigned *e_phnum_pointer,
|
|
+ bfd_vma *loadbase_pointer)
|
|
+{
|
|
+ /* sizeof (Elf64_External_Ehdr) >= sizeof (Elf32_External_Ehdr) */
|
|
+ Elf64_External_Ehdr x_ehdr64; /* Elf file header, external form */
|
|
+ Elf_Internal_Ehdr i_ehdr; /* Elf file header, internal form */
|
|
+ bfd_size_type x_phdrs_size;
|
|
+ gdb_byte *x_phdrs_ptr;
|
|
+ Elf_Internal_Phdr *i_phdrs;
|
|
+ int err;
|
|
+ unsigned int i;
|
|
+ bfd_vma loadbase;
|
|
+ int loadbase_set;
|
|
+
|
|
+ gdb_assert (templ != NULL);
|
|
+ gdb_assert (sizeof (Elf64_External_Ehdr) >= sizeof (Elf32_External_Ehdr));
|
|
+
|
|
+ /* Read in the ELF header in external format. */
|
|
+ err = target_read_memory (ehdr_vma, (bfd_byte *) &x_ehdr64, sizeof x_ehdr64);
|
|
+ if (err)
|
|
+ {
|
|
+ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE)
|
|
+ warning (_("build-id: Error reading ELF header at address 0x%lx"),
|
|
+ (unsigned long) ehdr_vma);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /* Now check to see if we have a valid ELF file, and one that BFD can
|
|
+ make use of. The magic number must match, the address size ('class')
|
|
+ and byte-swapping must match our XVEC entry. */
|
|
+
|
|
+ if (! elf_file_p (&x_ehdr64)
|
|
+ || x_ehdr64.e_ident[EI_VERSION] != EV_CURRENT
|
|
+ || !((bfd_get_arch_size (templ) == 64
|
|
+ && x_ehdr64.e_ident[EI_CLASS] == ELFCLASS64)
|
|
+ || (bfd_get_arch_size (templ) == 32
|
|
+ && x_ehdr64.e_ident[EI_CLASS] == ELFCLASS32)))
|
|
+ {
|
|
+ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE)
|
|
+ warning (_("build-id: Unrecognized ELF header at address 0x%lx"),
|
|
+ (unsigned long) ehdr_vma);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ /* Check that file's byte order matches xvec's */
|
|
+ switch (x_ehdr64.e_ident[EI_DATA])
|
|
+ {
|
|
+ case ELFDATA2MSB: /* Big-endian */
|
|
+ if (! bfd_header_big_endian (templ))
|
|
+ {
|
|
+ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE)
|
|
+ warning (_("build-id: Unrecognized "
|
|
+ "big-endian ELF header at address 0x%lx"),
|
|
+ (unsigned long) ehdr_vma);
|
|
+ return NULL;
|
|
+ }
|
|
+ break;
|
|
+ case ELFDATA2LSB: /* Little-endian */
|
|
+ if (! bfd_header_little_endian (templ))
|
|
+ {
|
|
+ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE)
|
|
+ warning (_("build-id: Unrecognized "
|
|
+ "little-endian ELF header at address 0x%lx"),
|
|
+ (unsigned long) ehdr_vma);
|
|
+ return NULL;
|
|
+ }
|
|
+ break;
|
|
+ case ELFDATANONE: /* No data encoding specified */
|
|
+ default: /* Unknown data encoding specified */
|
|
+ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE)
|
|
+ warning (_("build-id: Unrecognized "
|
|
+ "ELF header endianity at address 0x%lx"),
|
|
+ (unsigned long) ehdr_vma);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ elf_swap_ehdr_in (templ, &x_ehdr64, &i_ehdr);
|
|
+
|
|
+ /* The file header tells where to find the program headers.
|
|
+ These are what we use to actually choose what to read. */
|
|
+
|
|
+ if (i_ehdr.e_phentsize != (bfd_get_arch_size (templ) == 64
|
|
+ ? sizeof (Elf64_External_Phdr)
|
|
+ : sizeof (Elf32_External_Phdr))
|
|
+ || i_ehdr.e_phnum == 0)
|
|
+ {
|
|
+ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE)
|
|
+ warning (_("build-id: Invalid ELF program headers from the ELF header "
|
|
+ "at address 0x%lx"), (unsigned long) ehdr_vma);
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ x_phdrs_size = (bfd_get_arch_size (templ) == 64 ? sizeof (Elf64_External_Phdr)
|
|
+ : sizeof (Elf32_External_Phdr));
|
|
+
|
|
+ i_phdrs = (Elf_Internal_Phdr *) xmalloc (i_ehdr.e_phnum * (sizeof *i_phdrs + x_phdrs_size));
|
|
+ x_phdrs_ptr = (gdb_byte *) &i_phdrs[i_ehdr.e_phnum];
|
|
+ err = target_read_memory (ehdr_vma + i_ehdr.e_phoff, (bfd_byte *) x_phdrs_ptr,
|
|
+ i_ehdr.e_phnum * x_phdrs_size);
|
|
+ if (err)
|
|
+ {
|
|
+ free (i_phdrs);
|
|
+ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE)
|
|
+ warning (_("build-id: Error reading "
|
|
+ "ELF program headers at address 0x%lx"),
|
|
+ (unsigned long) (ehdr_vma + i_ehdr.e_phoff));
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ loadbase = ehdr_vma;
|
|
+ loadbase_set = 0;
|
|
+ for (i = 0; i < i_ehdr.e_phnum; ++i)
|
|
+ {
|
|
+ elf_swap_phdr_in (templ, (Elf64_External_Phdr *)
|
|
+ (x_phdrs_ptr + i * x_phdrs_size), &i_phdrs[i]);
|
|
+ /* IA-64 vDSO may have two mappings for one segment, where one mapping
|
|
+ is executable only, and one is read only. We must not use the
|
|
+ executable one (PF_R is the first one, PF_X the second one). */
|
|
+ if (i_phdrs[i].p_type == PT_LOAD && (i_phdrs[i].p_flags & PF_R))
|
|
+ {
|
|
+ /* Only the first PT_LOAD segment indicates the file bias.
|
|
+ Next segments may have P_VADDR arbitrarily higher.
|
|
+ If the first segment has P_VADDR zero any next segment must not
|
|
+ confuse us, the first one sets LOADBASE certainly enough. */
|
|
+ if (!loadbase_set && i_phdrs[i].p_offset == 0)
|
|
+ {
|
|
+ loadbase = ehdr_vma - i_phdrs[i].p_vaddr;
|
|
+ loadbase_set = 1;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (build_id_verbose >= BUILD_ID_VERBOSE_BINARY_PARSE)
|
|
+ warning (_("build-id: Found ELF header at address 0x%lx, loadbase 0x%lx"),
|
|
+ (unsigned long) ehdr_vma, (unsigned long) loadbase);
|
|
+
|
|
+ *e_phnum_pointer = i_ehdr.e_phnum;
|
|
+ *loadbase_pointer = loadbase;
|
|
+ return i_phdrs;
|
|
+}
|
|
+
|
|
+/* BUILD_ID_ADDR_GET gets ADDR located somewhere in the object.
|
|
+ Find the first section before ADDR containing an ELF header.
|
|
+ We rely on the fact the sections from multiple files do not mix.
|
|
+ FIXME: We should check ADDR is contained _inside_ the section with possibly
|
|
+ missing content (P_FILESZ < P_MEMSZ). These omitted sections are currently
|
|
+ hidden by _BFD_ELF_MAKE_SECTION_FROM_PHDR. */
|
|
+
|
|
+static CORE_ADDR build_id_addr;
|
|
+struct build_id_addr_sect
|
|
+ {
|
|
+ struct build_id_addr_sect *next;
|
|
+ asection *sect;
|
|
+ };
|
|
+static struct build_id_addr_sect *build_id_addr_sect;
|
|
+
|
|
+static void build_id_addr_candidate (bfd *abfd, asection *sect, void *obj)
|
|
+{
|
|
+ if (build_id_addr >= bfd_section_vma (sect))
|
|
+ {
|
|
+ struct build_id_addr_sect *candidate;
|
|
+
|
|
+ candidate = (struct build_id_addr_sect *) xmalloc (sizeof *candidate);
|
|
+ candidate->next = build_id_addr_sect;
|
|
+ build_id_addr_sect = candidate;
|
|
+ candidate->sect = sect;
|
|
+ }
|
|
+}
|
|
+
|
|
+struct bfd_build_id *
|
|
+build_id_addr_get (CORE_ADDR addr)
|
|
+{
|
|
+ struct build_id_addr_sect *candidate;
|
|
+ struct bfd_build_id *retval = NULL;
|
|
+ Elf_Internal_Phdr *i_phdr = NULL;
|
|
+ bfd_vma loadbase = 0;
|
|
+ unsigned e_phnum = 0;
|
|
+
|
|
+ if (core_bfd == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ build_id_addr = addr;
|
|
+ gdb_assert (build_id_addr_sect == NULL);
|
|
+ bfd_map_over_sections (core_bfd, build_id_addr_candidate, NULL);
|
|
+
|
|
+ /* Sections are sorted in the high-to-low VMAs order.
|
|
+ Stop the search on the first ELF header we find.
|
|
+ Do not continue the search even if it does not contain NT_GNU_BUILD_ID. */
|
|
+
|
|
+ for (candidate = build_id_addr_sect; candidate != NULL;
|
|
+ candidate = candidate->next)
|
|
+ {
|
|
+ i_phdr = elf_get_phdr (core_bfd,
|
|
+ bfd_section_vma (candidate->sect),
|
|
+ &e_phnum, &loadbase);
|
|
+ if (i_phdr != NULL)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (i_phdr != NULL)
|
|
+ {
|
|
+ retval = build_id_phdr_get (core_bfd, loadbase, e_phnum, i_phdr);
|
|
+ xfree (i_phdr);
|
|
+ }
|
|
+
|
|
+ while (build_id_addr_sect != NULL)
|
|
+ {
|
|
+ candidate = build_id_addr_sect;
|
|
+ build_id_addr_sect = candidate->next;
|
|
+ xfree (candidate);
|
|
+ }
|
|
+
|
|
+ return retval;
|
|
+}
|
|
+
|
|
/* See build-id.h. */
|
|
|
|
int
|
|
@@ -51,7 +451,7 @@ build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check)
|
|
const struct bfd_build_id *found;
|
|
int retval = 0;
|
|
|
|
- found = build_id_bfd_get (abfd);
|
|
+ found = build_id_bfd_shdr_get (abfd);
|
|
|
|
if (found == NULL)
|
|
warning (_("File \"%s\" has no build-id, file skipped"),
|
|
@@ -66,63 +466,166 @@ build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check)
|
|
return retval;
|
|
}
|
|
|
|
+static char *
|
|
+link_resolve (const char *symlink, int level)
|
|
+{
|
|
+ char buf[PATH_MAX + 1], *retval;
|
|
+ gdb::unique_xmalloc_ptr<char> target;
|
|
+ ssize_t got;
|
|
+
|
|
+ if (level > 10)
|
|
+ return xstrdup (symlink);
|
|
+
|
|
+ got = readlink (symlink, buf, sizeof (buf));
|
|
+ if (got < 0 || got >= sizeof (buf))
|
|
+ return xstrdup (symlink);
|
|
+ buf[got] = '\0';
|
|
+
|
|
+ if (IS_ABSOLUTE_PATH (buf))
|
|
+ target = make_unique_xstrdup (buf);
|
|
+ else
|
|
+ {
|
|
+ const std::string dir (ldirname (symlink));
|
|
+
|
|
+ target = xstrprintf ("%s"
|
|
+#ifndef HAVE_DOS_BASED_FILE_SYSTEM
|
|
+ "/"
|
|
+#else /* HAVE_DOS_BASED_FILE_SYSTEM */
|
|
+ "\\"
|
|
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
|
|
+ "%s", dir.c_str(), buf);
|
|
+ }
|
|
+
|
|
+ retval = link_resolve (target.get (), level + 1);
|
|
+ return retval;
|
|
+}
|
|
+
|
|
/* Helper for build_id_to_debug_bfd. LINK is a path to a potential
|
|
build-id-based separate debug file, potentially a symlink to the real file.
|
|
If the file exists and matches BUILD_ID, return a BFD reference to it. */
|
|
|
|
static gdb_bfd_ref_ptr
|
|
-build_id_to_debug_bfd_1 (const std::string &link, size_t build_id_len,
|
|
- const bfd_byte *build_id)
|
|
+build_id_to_debug_bfd_1 (const std::string &orig_link, size_t build_id_len,
|
|
+ const bfd_byte *build_id, char **link_return)
|
|
{
|
|
+ gdb_bfd_ref_ptr ret_bfd = {};
|
|
+ std::string ret_link;
|
|
+
|
|
if (separate_debug_file_debug)
|
|
{
|
|
- fprintf_unfiltered (gdb_stdlog, _(" Trying %s..."), link.c_str ());
|
|
- gdb_flush (gdb_stdlog);
|
|
+ fprintf_unfiltered (gdb_stdlog, _(" Trying %s..."), orig_link.c_str ());
|
|
+ gdb_flush (gdb_stdout);
|
|
}
|
|
|
|
- /* lrealpath() is expensive even for the usually non-existent files. */
|
|
- gdb::unique_xmalloc_ptr<char> filename_holder;
|
|
- const char *filename = nullptr;
|
|
- if (startswith (link, TARGET_SYSROOT_PREFIX))
|
|
- filename = link.c_str ();
|
|
- else if (access (link.c_str (), F_OK) == 0)
|
|
+ for (unsigned seqno = 0;; seqno++)
|
|
{
|
|
- filename_holder.reset (lrealpath (link.c_str ()));
|
|
- filename = filename_holder.get ();
|
|
- }
|
|
+ std::string link = orig_link;
|
|
|
|
- if (filename == NULL)
|
|
- {
|
|
- if (separate_debug_file_debug)
|
|
- fprintf_unfiltered (gdb_stdlog,
|
|
- _(" no, unable to compute real path\n"));
|
|
+ if (seqno > 0)
|
|
+ {
|
|
+ /* There can be multiple build-id symlinks pointing to real files
|
|
+ with the same build-id (such as hard links). Some of the real
|
|
+ files may not be installed. */
|
|
|
|
- return {};
|
|
- }
|
|
+ string_appendf (link, ".%u", seqno);
|
|
+ }
|
|
|
|
- /* We expect to be silent on the non-existing files. */
|
|
- gdb_bfd_ref_ptr debug_bfd = gdb_bfd_open (filename, gnutarget);
|
|
+ ret_link = link;
|
|
|
|
- if (debug_bfd == NULL)
|
|
- {
|
|
- if (separate_debug_file_debug)
|
|
- fprintf_unfiltered (gdb_stdlog, _(" no, unable to open.\n"));
|
|
+ struct stat statbuf_trash;
|
|
+
|
|
+ /* `access' automatically dereferences LINK. */
|
|
+ if (lstat (link.c_str (), &statbuf_trash) != 0)
|
|
+ {
|
|
+ /* Stop increasing SEQNO. */
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* lrealpath() is expensive even for the usually non-existent files. */
|
|
+ gdb::unique_xmalloc_ptr<char> filename_holder;
|
|
+ const char *filename = nullptr;
|
|
+ if (startswith (link, TARGET_SYSROOT_PREFIX))
|
|
+ filename = link.c_str ();
|
|
+ else if (access (link.c_str (), F_OK) == 0)
|
|
+ {
|
|
+ filename_holder.reset (lrealpath (link.c_str ()));
|
|
+ filename = filename_holder.get ();
|
|
+ }
|
|
+
|
|
+ if (filename == NULL)
|
|
+ {
|
|
+ if (separate_debug_file_debug)
|
|
+ fprintf_unfiltered (gdb_stdlog,
|
|
+ _(" no, unable to compute real path\n"));
|
|
+
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* We expect to be silent on the non-existing files. */
|
|
+ gdb_bfd_ref_ptr debug_bfd = gdb_bfd_open (filename, gnutarget);
|
|
+
|
|
+ if (debug_bfd == NULL)
|
|
+ {
|
|
+ if (separate_debug_file_debug)
|
|
+ fprintf_unfiltered (gdb_stdlog, _(" no, unable to open.\n"));
|
|
|
|
- return {};
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (!build_id_verify (debug_bfd.get(), build_id_len, build_id))
|
|
+ {
|
|
+ if (separate_debug_file_debug)
|
|
+ fprintf_unfiltered (gdb_stdlog,
|
|
+ _(" no, build-id does not match.\n"));
|
|
+
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ ret_bfd = debug_bfd;
|
|
+ break;
|
|
}
|
|
|
|
- if (!build_id_verify (debug_bfd.get(), build_id_len, build_id))
|
|
+ std::string link_all;
|
|
+
|
|
+ if (ret_bfd != NULL)
|
|
{
|
|
if (separate_debug_file_debug)
|
|
- fprintf_unfiltered (gdb_stdlog, _(" no, build-id does not match.\n"));
|
|
+ fprintf_unfiltered (gdb_stdlog, _(" yes!\n"));
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ /* If none of the real files is found report as missing file
|
|
+ always the non-.%u-suffixed file. */
|
|
+ std::string link0 = orig_link;
|
|
|
|
- return {};
|
|
+ /* If the symlink has target request to install the target.
|
|
+ BASE-debuginfo.rpm contains the symlink but BASE.rpm may be missing.
|
|
+ https://bugzilla.redhat.com/show_bug.cgi?id=981154 */
|
|
+ std::string link0_resolved (link_resolve (link0.c_str (), 0));
|
|
+
|
|
+ if (link_all.empty ())
|
|
+ link_all = link0_resolved;
|
|
+ else
|
|
+ {
|
|
+ /* Use whitespace instead of DIRNAME_SEPARATOR to be compatible with
|
|
+ its possible use as an argument for installation command. */
|
|
+ link_all += " " + link0_resolved;
|
|
+ }
|
|
}
|
|
|
|
- if (separate_debug_file_debug)
|
|
- fprintf_unfiltered (gdb_stdlog, _(" yes!\n"));
|
|
+ if (link_return != NULL)
|
|
+ {
|
|
+ if (ret_bfd != NULL)
|
|
+ {
|
|
+ *link_return = xstrdup (ret_link.c_str ());
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ *link_return = xstrdup (link_all.c_str ());
|
|
+ }
|
|
+ }
|
|
|
|
- return debug_bfd;
|
|
+ return ret_bfd;
|
|
}
|
|
|
|
/* Common code for finding BFDs of a given build-id. This function
|
|
@@ -131,7 +634,7 @@ build_id_to_debug_bfd_1 (const std::string &link, size_t build_id_len,
|
|
|
|
static gdb_bfd_ref_ptr
|
|
build_id_to_bfd_suffix (size_t build_id_len, const bfd_byte *build_id,
|
|
- const char *suffix)
|
|
+ const char *suffix, char **link_return)
|
|
{
|
|
/* Keep backward compatibility so that DEBUG_FILE_DIRECTORY being "" will
|
|
cause "/.build-id/..." lookups. */
|
|
@@ -154,16 +657,17 @@ build_id_to_bfd_suffix (size_t build_id_len, const bfd_byte *build_id,
|
|
if (size > 0)
|
|
{
|
|
size--;
|
|
- string_appendf (link, "%02x/", (unsigned) *data++);
|
|
+ string_appendf (link, "%02x", (unsigned) *data++);
|
|
}
|
|
-
|
|
+ if (size > 0)
|
|
+ link += "/";
|
|
while (size-- > 0)
|
|
string_appendf (link, "%02x", (unsigned) *data++);
|
|
|
|
link += suffix;
|
|
|
|
gdb_bfd_ref_ptr debug_bfd
|
|
- = build_id_to_debug_bfd_1 (link, build_id_len, build_id);
|
|
+ = build_id_to_debug_bfd_1 (link, build_id_len, build_id, link_return);
|
|
if (debug_bfd != NULL)
|
|
return debug_bfd;
|
|
|
|
@@ -174,7 +678,8 @@ build_id_to_bfd_suffix (size_t build_id_len, const bfd_byte *build_id,
|
|
if (!gdb_sysroot.empty ())
|
|
{
|
|
link = gdb_sysroot + link;
|
|
- debug_bfd = build_id_to_debug_bfd_1 (link, build_id_len, build_id);
|
|
+ debug_bfd = build_id_to_debug_bfd_1 (link, build_id_len, build_id,
|
|
+ link_return);
|
|
if (debug_bfd != NULL)
|
|
return debug_bfd;
|
|
}
|
|
@@ -183,30 +688,649 @@ build_id_to_bfd_suffix (size_t build_id_len, const bfd_byte *build_id,
|
|
return {};
|
|
}
|
|
|
|
+char *
|
|
+build_id_to_filename (const struct bfd_build_id *build_id, char **link_return)
|
|
+{
|
|
+ gdb_bfd_ref_ptr abfd;
|
|
+ char *result;
|
|
+
|
|
+ abfd = build_id_to_exec_bfd (build_id->size, build_id->data, link_return);
|
|
+ if (abfd == NULL)
|
|
+ return NULL;
|
|
+
|
|
+ result = xstrdup (bfd_get_filename (abfd.get ()));
|
|
+ return result;
|
|
+}
|
|
+
|
|
+#ifdef HAVE_LIBRPM
|
|
+
|
|
+#include <rpm/rpmlib.h>
|
|
+#include <rpm/rpmts.h>
|
|
+#include <rpm/rpmdb.h>
|
|
+#include <rpm/header.h>
|
|
+#ifdef DLOPEN_LIBRPM
|
|
+#include <dlfcn.h>
|
|
+#endif
|
|
+
|
|
+/* Workarodun https://bugzilla.redhat.com/show_bug.cgi?id=643031
|
|
+ librpm must not exit() an application on SIGINT
|
|
+
|
|
+ Enable or disable a signal handler. SIGNUM: signal to enable (or disable
|
|
+ if negative). HANDLER: sa_sigaction handler (or NULL to use
|
|
+ rpmsqHandler()). Returns: no. of refs, -1 on error. */
|
|
+extern int rpmsqEnable (int signum, /* rpmsqAction_t handler */ void *handler);
|
|
+int
|
|
+rpmsqEnable (int signum, /* rpmsqAction_t handler */ void *handler)
|
|
+{
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* This MISSING_RPM_HASH tracker is used to collect all the missing rpm files
|
|
+ and avoid their duplicities during a single inferior run. */
|
|
+
|
|
+static struct htab *missing_rpm_hash;
|
|
+
|
|
+/* This MISSING_RPM_LIST tracker is used to collect and print as a single line
|
|
+ all the rpms right before the nearest GDB prompt. It gets cleared after
|
|
+ each such print (it is questionable if we should clear it after the print).
|
|
+ */
|
|
+
|
|
+struct missing_rpm
|
|
+ {
|
|
+ struct missing_rpm *next;
|
|
+ char rpm[1];
|
|
+ };
|
|
+static struct missing_rpm *missing_rpm_list;
|
|
+static int missing_rpm_list_entries;
|
|
+
|
|
+/* Returns the count of newly added rpms. */
|
|
+
|
|
+static int
|
|
+#ifndef GDB_INDEX_VERIFY_VENDOR
|
|
+missing_rpm_enlist (const char *filename)
|
|
+#else
|
|
+missing_rpm_enlist_1 (const char *filename, int verify_vendor)
|
|
+#endif
|
|
+{
|
|
+ static int rpm_init_done = 0;
|
|
+ rpmts ts;
|
|
+ rpmdbMatchIterator mi;
|
|
+ int count = 0;
|
|
+
|
|
+#ifdef DLOPEN_LIBRPM
|
|
+ /* Duplicate here the declarations to verify they match. The same sanity
|
|
+ check is present also in `configure.ac'. */
|
|
+ extern char * headerFormat(Header h, const char * fmt, errmsg_t * errmsg);
|
|
+ static char *(*headerFormat_p) (Header h, const char * fmt, errmsg_t *errmsg);
|
|
+ extern int rpmReadConfigFiles(const char * file, const char * target);
|
|
+ static int (*rpmReadConfigFiles_p) (const char * file, const char * target);
|
|
+ extern rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi);
|
|
+ static rpmdbMatchIterator (*rpmdbFreeIterator_p) (rpmdbMatchIterator mi);
|
|
+ extern Header rpmdbNextIterator(rpmdbMatchIterator mi);
|
|
+ static Header (*rpmdbNextIterator_p) (rpmdbMatchIterator mi);
|
|
+ extern rpmts rpmtsCreate(void);
|
|
+ static rpmts (*rpmtsCreate_p) (void);
|
|
+ extern rpmts rpmtsFree(rpmts ts);
|
|
+ static rpmts (*rpmtsFree_p) (rpmts ts);
|
|
+ extern rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmTag rpmtag,
|
|
+ const void * keyp, size_t keylen);
|
|
+ static rpmdbMatchIterator (*rpmtsInitIterator_p) (const rpmts ts,
|
|
+ rpmTag rpmtag,
|
|
+ const void *keyp,
|
|
+ size_t keylen);
|
|
+#else /* !DLOPEN_LIBRPM */
|
|
+# define headerFormat_p headerFormat
|
|
+# define rpmReadConfigFiles_p rpmReadConfigFiles
|
|
+# define rpmdbFreeIterator_p rpmdbFreeIterator
|
|
+# define rpmdbNextIterator_p rpmdbNextIterator
|
|
+# define rpmtsCreate_p rpmtsCreate
|
|
+# define rpmtsFree_p rpmtsFree
|
|
+# define rpmtsInitIterator_p rpmtsInitIterator
|
|
+#endif /* !DLOPEN_LIBRPM */
|
|
+
|
|
+ gdb_assert (filename != NULL);
|
|
+
|
|
+ if (strcmp (filename, BUILD_ID_MAIN_EXECUTABLE_FILENAME) == 0)
|
|
+ return 0;
|
|
+
|
|
+ if (is_target_filename (filename))
|
|
+ return 0;
|
|
+
|
|
+ if (filename[0] != '/')
|
|
+ {
|
|
+ warning (_("Ignoring non-absolute filename: <%s>"), filename);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!rpm_init_done)
|
|
+ {
|
|
+ static int init_tried;
|
|
+
|
|
+ /* Already failed the initialization before? */
|
|
+ if (init_tried)
|
|
+ return 0;
|
|
+ init_tried = 1;
|
|
+
|
|
+#ifdef DLOPEN_LIBRPM
|
|
+ {
|
|
+ void *h;
|
|
+
|
|
+ h = dlopen (DLOPEN_LIBRPM, RTLD_LAZY);
|
|
+ if (!h)
|
|
+ {
|
|
+ warning (_("Unable to open \"%s\" (%s), "
|
|
+ "missing debuginfos notifications will not be displayed"),
|
|
+ DLOPEN_LIBRPM, dlerror ());
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ if (!((headerFormat_p = (char *(*) (Header h, const char * fmt, errmsg_t *errmsg)) dlsym (h, "headerFormat"))
|
|
+ && (rpmReadConfigFiles_p = (int (*) (const char * file, const char * target)) dlsym (h, "rpmReadConfigFiles"))
|
|
+ && (rpmdbFreeIterator_p = (rpmdbMatchIterator (*) (rpmdbMatchIterator mi)) dlsym (h, "rpmdbFreeIterator"))
|
|
+ && (rpmdbNextIterator_p = (Header (*) (rpmdbMatchIterator mi)) dlsym (h, "rpmdbNextIterator"))
|
|
+ && (rpmtsCreate_p = (rpmts (*) (void)) dlsym (h, "rpmtsCreate"))
|
|
+ && (rpmtsFree_p = (rpmts (*) (rpmts ts)) dlsym (h, "rpmtsFree"))
|
|
+ && (rpmtsInitIterator_p = (rpmdbMatchIterator (*) (const rpmts ts, rpmTag rpmtag, const void *keyp, size_t keylen)) dlsym (h, "rpmtsInitIterator"))))
|
|
+ {
|
|
+ warning (_("Opened library \"%s\" is incompatible (%s), "
|
|
+ "missing debuginfos notifications will not be displayed"),
|
|
+ DLOPEN_LIBRPM, dlerror ());
|
|
+ if (dlclose (h))
|
|
+ warning (_("Error closing library \"%s\": %s\n"), DLOPEN_LIBRPM,
|
|
+ dlerror ());
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+#endif /* DLOPEN_LIBRPM */
|
|
+
|
|
+ if (rpmReadConfigFiles_p (NULL, NULL) != 0)
|
|
+ {
|
|
+ warning (_("Error reading the rpm configuration files"));
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ rpm_init_done = 1;
|
|
+ }
|
|
+
|
|
+ ts = rpmtsCreate_p ();
|
|
+
|
|
+ mi = rpmtsInitIterator_p (ts, RPMTAG_BASENAMES, filename, 0);
|
|
+ if (mi != NULL)
|
|
+ {
|
|
+#ifndef GDB_INDEX_VERIFY_VENDOR
|
|
+ for (;;)
|
|
+#else
|
|
+ if (!verify_vendor) for (;;)
|
|
+#endif
|
|
+ {
|
|
+ Header h;
|
|
+ char *debuginfo, **slot, *s, *s2;
|
|
+ errmsg_t err;
|
|
+ size_t srcrpmlen = sizeof (".src.rpm") - 1;
|
|
+ size_t debuginfolen = sizeof ("-debuginfo") - 1;
|
|
+ rpmdbMatchIterator mi_debuginfo;
|
|
+
|
|
+ h = rpmdbNextIterator_p (mi);
|
|
+ if (h == NULL)
|
|
+ break;
|
|
+
|
|
+ /* Verify the debuginfo file is not already installed. */
|
|
+
|
|
+ debuginfo = headerFormat_p (h, "%{sourcerpm}-debuginfo.%{arch}",
|
|
+ &err);
|
|
+ if (!debuginfo)
|
|
+ {
|
|
+ warning (_("Error querying the rpm file `%s': %s"), filename,
|
|
+ err);
|
|
+ continue;
|
|
+ }
|
|
+ /* s = `.src.rpm-debuginfo.%{arch}' */
|
|
+ s = strrchr (debuginfo, '-') - srcrpmlen;
|
|
+ s2 = NULL;
|
|
+ if (s > debuginfo && memcmp (s, ".src.rpm", srcrpmlen) == 0)
|
|
+ {
|
|
+ /* s2 = `-%{release}.src.rpm-debuginfo.%{arch}' */
|
|
+ s2 = (char *) memrchr (debuginfo, '-', s - debuginfo);
|
|
+ }
|
|
+ if (s2)
|
|
+ {
|
|
+ /* s2 = `-%{version}-%{release}.src.rpm-debuginfo.%{arch}' */
|
|
+ s2 = (char *) memrchr (debuginfo, '-', s2 - debuginfo);
|
|
+ }
|
|
+ if (!s2)
|
|
+ {
|
|
+ warning (_("Error querying the rpm file `%s': %s"), filename,
|
|
+ debuginfo);
|
|
+ xfree (debuginfo);
|
|
+ continue;
|
|
+ }
|
|
+ /* s = `.src.rpm-debuginfo.%{arch}' */
|
|
+ /* s2 = `-%{version}-%{release}.src.rpm-debuginfo.%{arch}' */
|
|
+ memmove (s2 + debuginfolen, s2, s - s2);
|
|
+ memcpy (s2, "-debuginfo", debuginfolen);
|
|
+ /* s = `XXXX.%{arch}' */
|
|
+ /* strlen ("XXXX") == srcrpmlen + debuginfolen */
|
|
+ /* s2 = `-debuginfo-%{version}-%{release}XX.%{arch}' */
|
|
+ /* strlen ("XX") == srcrpmlen */
|
|
+ memmove (s + debuginfolen, s + srcrpmlen + debuginfolen,
|
|
+ strlen (s + srcrpmlen + debuginfolen) + 1);
|
|
+ /* s = `-debuginfo-%{version}-%{release}.%{arch}' */
|
|
+
|
|
+ /* RPMDBI_PACKAGES requires keylen == sizeof (int). */
|
|
+ /* RPMDBI_LABEL is an interface for NVR-based dbiFindByLabel(). */
|
|
+ mi_debuginfo = rpmtsInitIterator_p (ts, (rpmTag) RPMDBI_LABEL, debuginfo, 0);
|
|
+ xfree (debuginfo);
|
|
+ if (mi_debuginfo)
|
|
+ {
|
|
+ rpmdbFreeIterator_p (mi_debuginfo);
|
|
+ count = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* The allocated memory gets utilized below for MISSING_RPM_HASH. */
|
|
+ debuginfo = headerFormat_p (h,
|
|
+ "%{name}-%{version}-%{release}.%{arch}",
|
|
+ &err);
|
|
+ if (!debuginfo)
|
|
+ {
|
|
+ warning (_("Error querying the rpm file `%s': %s"), filename,
|
|
+ err);
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ /* Base package name for `debuginfo-install'. We do not use the
|
|
+ `yum' command directly as the line
|
|
+ yum --enablerepo='*debug*' install NAME-debuginfo.ARCH
|
|
+ would be more complicated than just:
|
|
+ debuginfo-install NAME-VERSION-RELEASE.ARCH
|
|
+ Do not supply the rpm base name (derived from .src.rpm name) as
|
|
+ debuginfo-install is unable to install the debuginfo package if
|
|
+ the base name PKG binary rpm is not installed while for example
|
|
+ PKG-libs would be installed (RH Bug 467901).
|
|
+ FUTURE: After multiple debuginfo versions simultaneously installed
|
|
+ get supported the support for the VERSION-RELEASE tags handling
|
|
+ may need an update. */
|
|
+
|
|
+ if (missing_rpm_hash == NULL)
|
|
+ {
|
|
+ /* DEL_F is passed NULL as MISSING_RPM_LIST's HTAB_DELETE
|
|
+ should not deallocate the entries. */
|
|
+
|
|
+ missing_rpm_hash = htab_create_alloc (64, htab_hash_string,
|
|
+ (int (*) (const void *, const void *)) streq,
|
|
+ NULL, xcalloc, xfree);
|
|
+ }
|
|
+ slot = (char **) htab_find_slot (missing_rpm_hash, debuginfo, INSERT);
|
|
+ /* XCALLOC never returns NULL. */
|
|
+ gdb_assert (slot != NULL);
|
|
+ if (*slot == NULL)
|
|
+ {
|
|
+ struct missing_rpm *missing_rpm;
|
|
+
|
|
+ *slot = debuginfo;
|
|
+
|
|
+ missing_rpm = (struct missing_rpm *) xmalloc (sizeof (*missing_rpm) + strlen (debuginfo));
|
|
+ strcpy (missing_rpm->rpm, debuginfo);
|
|
+ missing_rpm->next = missing_rpm_list;
|
|
+ missing_rpm_list = missing_rpm;
|
|
+ missing_rpm_list_entries++;
|
|
+ }
|
|
+ else
|
|
+ xfree (debuginfo);
|
|
+ count++;
|
|
+ }
|
|
+#ifdef GDB_INDEX_VERIFY_VENDOR
|
|
+ else /* verify_vendor */
|
|
+ {
|
|
+ int vendor_pass = 0, vendor_fail = 0;
|
|
+
|
|
+ for (;;)
|
|
+ {
|
|
+ Header h;
|
|
+ errmsg_t err;
|
|
+ char *vendor;
|
|
+
|
|
+ h = rpmdbNextIterator_p (mi);
|
|
+ if (h == NULL)
|
|
+ break;
|
|
+
|
|
+ vendor = headerFormat_p (h, "%{vendor}", &err);
|
|
+ if (!vendor)
|
|
+ {
|
|
+ warning (_("Error querying the rpm file `%s': %s"), filename,
|
|
+ err);
|
|
+ continue;
|
|
+ }
|
|
+ if (strcmp (vendor, "Red Hat, Inc.") == 0)
|
|
+ vendor_pass = 1;
|
|
+ else
|
|
+ vendor_fail = 1;
|
|
+ xfree (vendor);
|
|
+ }
|
|
+ count = vendor_pass != 0 && vendor_fail == 0;
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ rpmdbFreeIterator_p (mi);
|
|
+ }
|
|
+
|
|
+ rpmtsFree_p (ts);
|
|
+
|
|
+ return count;
|
|
+}
|
|
+
|
|
+#ifdef GDB_INDEX_VERIFY_VENDOR
|
|
+missing_rpm_enlist (const char *filename)
|
|
+{
|
|
+ return missing_rpm_enlist_1 (filename, 0);
|
|
+}
|
|
+
|
|
+extern int rpm_verify_vendor (const char *filename);
|
|
+int
|
|
+rpm_verify_vendor (const char *filename)
|
|
+{
|
|
+ return missing_rpm_enlist_1 (filename, 1);
|
|
+}
|
|
+#endif
|
|
+
|
|
+static bool
|
|
+missing_rpm_list_compar (const char *ap, const char *bp)
|
|
+{
|
|
+ return strcoll (ap, bp) < 0;
|
|
+}
|
|
+
|
|
+/* It returns a NULL-terminated array of strings needing to be FREEd. It may
|
|
+ also return only NULL. */
|
|
+
|
|
+static void
|
|
+missing_rpm_list_print (void)
|
|
+{
|
|
+ struct missing_rpm *list_iter;
|
|
+
|
|
+ if (missing_rpm_list_entries == 0)
|
|
+ return;
|
|
+
|
|
+ std::vector<const char *> array (missing_rpm_list_entries);
|
|
+ size_t idx = 0;
|
|
+
|
|
+ for (list_iter = missing_rpm_list; list_iter != NULL;
|
|
+ list_iter = list_iter->next)
|
|
+ {
|
|
+ array[idx++] = list_iter->rpm;
|
|
+ }
|
|
+ gdb_assert (idx == missing_rpm_list_entries);
|
|
+
|
|
+ std::sort (array.begin (), array.end (), missing_rpm_list_compar);
|
|
+
|
|
+ /* We zero out the number of missing RPMs here because of a nasty
|
|
+ bug (see RHBZ 1801974).
|
|
+
|
|
+ When we call 'puts_unfiltered' below, if pagination is on and if
|
|
+ the number of missing RPMs is big enough to trigger pagination,
|
|
+ we will end up in an infinite recursion. The call chain looks
|
|
+ like this:
|
|
+
|
|
+ missing_rpm_list_print -> puts_unfiltered -> fputs_maybe_filtered
|
|
+ -> prompt_for_continue -> display_gdb_prompt ->
|
|
+ debug_flush_missing -> missing_rpm_list_print ...
|
|
+
|
|
+ For this reason, we make sure MISSING_RPM_LIST_ENTRIES is zero
|
|
+ *before* calling any print function. */
|
|
+ missing_rpm_list_entries = 0;
|
|
+
|
|
+ printf_unfiltered (_("Missing separate debuginfos, use: %s"),
|
|
+#ifdef DNF_DEBUGINFO_INSTALL
|
|
+ "dnf "
|
|
+#endif
|
|
+ "debuginfo-install");
|
|
+ for (const char *el : array)
|
|
+ {
|
|
+ puts_unfiltered (" ");
|
|
+ puts_unfiltered (el);
|
|
+ }
|
|
+ puts_unfiltered ("\n");
|
|
+
|
|
+ while (missing_rpm_list != NULL)
|
|
+ {
|
|
+ list_iter = missing_rpm_list;
|
|
+ missing_rpm_list = list_iter->next;
|
|
+ xfree (list_iter);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+missing_rpm_change (void)
|
|
+{
|
|
+ debug_flush_missing ();
|
|
+
|
|
+ gdb_assert (missing_rpm_list == NULL);
|
|
+ if (missing_rpm_hash != NULL)
|
|
+ {
|
|
+ htab_delete (missing_rpm_hash);
|
|
+ missing_rpm_hash = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
+enum missing_exec
|
|
+ {
|
|
+ /* Init state. EXEC_BFD also still could be NULL. */
|
|
+ MISSING_EXEC_NOT_TRIED,
|
|
+ /* We saw a non-NULL EXEC_BFD but RPM has no info about it. */
|
|
+ MISSING_EXEC_NOT_FOUND,
|
|
+ /* We found EXEC_BFD by RPM and we either have its symbols (either embedded
|
|
+ or separate) or the main executable's RPM is now contained in
|
|
+ MISSING_RPM_HASH. */
|
|
+ MISSING_EXEC_ENLISTED
|
|
+ };
|
|
+static enum missing_exec missing_exec = MISSING_EXEC_NOT_TRIED;
|
|
+
|
|
+#endif /* HAVE_LIBRPM */
|
|
+
|
|
+void
|
|
+debug_flush_missing (void)
|
|
+{
|
|
+#ifdef HAVE_LIBRPM
|
|
+ missing_rpm_list_print ();
|
|
+#endif
|
|
+}
|
|
+
|
|
+/* This MISSING_FILEPAIR_HASH tracker is used only for the duplicite messages
|
|
+ yum --enablerepo='*debug*' install ...
|
|
+ avoidance. */
|
|
+
|
|
+struct missing_filepair
|
|
+ {
|
|
+ char *binary;
|
|
+ char *debug;
|
|
+ char data[1];
|
|
+ };
|
|
+
|
|
+static struct htab *missing_filepair_hash;
|
|
+static struct obstack missing_filepair_obstack;
|
|
+
|
|
+static void *
|
|
+missing_filepair_xcalloc (size_t nmemb, size_t nmemb_size)
|
|
+{
|
|
+ void *retval;
|
|
+ size_t size = nmemb * nmemb_size;
|
|
+
|
|
+ retval = obstack_alloc (&missing_filepair_obstack, size);
|
|
+ memset (retval, 0, size);
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+static hashval_t
|
|
+missing_filepair_hash_func (const struct missing_filepair *elem)
|
|
+{
|
|
+ hashval_t retval = 0;
|
|
+
|
|
+ retval ^= htab_hash_string (elem->binary);
|
|
+ if (elem->debug != NULL)
|
|
+ retval ^= htab_hash_string (elem->debug);
|
|
+
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+static int
|
|
+missing_filepair_eq (const struct missing_filepair *elem1,
|
|
+ const struct missing_filepair *elem2)
|
|
+{
|
|
+ return strcmp (elem1->binary, elem2->binary) == 0
|
|
+ && ((elem1->debug == NULL) == (elem2->debug == NULL))
|
|
+ && (elem1->debug == NULL || strcmp (elem1->debug, elem2->debug) == 0);
|
|
+}
|
|
+
|
|
+static void
|
|
+missing_filepair_change (void)
|
|
+{
|
|
+ if (missing_filepair_hash != NULL)
|
|
+ {
|
|
+ obstack_free (&missing_filepair_obstack, NULL);
|
|
+ /* All their memory came just from missing_filepair_OBSTACK. */
|
|
+ missing_filepair_hash = NULL;
|
|
+ }
|
|
+#ifdef HAVE_LIBRPM
|
|
+ missing_exec = MISSING_EXEC_NOT_TRIED;
|
|
+#endif
|
|
+}
|
|
+
|
|
+static void
|
|
+debug_print_executable_changed (void)
|
|
+{
|
|
+#ifdef HAVE_LIBRPM
|
|
+ missing_rpm_change ();
|
|
+#endif
|
|
+ missing_filepair_change ();
|
|
+}
|
|
+
|
|
+/* Notify user the file BINARY with (possibly NULL) associated separate debug
|
|
+ information file DEBUG is missing. DEBUG may or may not be the build-id
|
|
+ file such as would be:
|
|
+ /usr/lib/debug/.build-id/dd/b1d2ce632721c47bb9e8679f369e2295ce71be.debug
|
|
+ */
|
|
+
|
|
+void
|
|
+debug_print_missing (const char *binary, const char *debug)
|
|
+{
|
|
+ size_t binary_len0 = strlen (binary) + 1;
|
|
+ size_t debug_len0 = debug ? strlen (debug) + 1 : 0;
|
|
+ struct missing_filepair missing_filepair_find;
|
|
+ struct missing_filepair *missing_filepair;
|
|
+ struct missing_filepair **slot;
|
|
+
|
|
+ if (build_id_verbose < BUILD_ID_VERBOSE_FILENAMES)
|
|
+ return;
|
|
+
|
|
+ if (missing_filepair_hash == NULL)
|
|
+ {
|
|
+ obstack_init (&missing_filepair_obstack);
|
|
+ missing_filepair_hash = htab_create_alloc (64,
|
|
+ (hashval_t (*) (const void *)) missing_filepair_hash_func,
|
|
+ (int (*) (const void *, const void *)) missing_filepair_eq, NULL,
|
|
+ missing_filepair_xcalloc, NULL);
|
|
+ }
|
|
+
|
|
+ /* Use MISSING_FILEPAIR_FIND first instead of calling obstack_alloc with
|
|
+ obstack_free in the case of a (rare) match. The problem is ALLOC_F for
|
|
+ MISSING_FILEPAIR_HASH allocates from MISSING_FILEPAIR_OBSTACK maintenance
|
|
+ structures for MISSING_FILEPAIR_HASH. Calling obstack_free would possibly
|
|
+ not to free only MISSING_FILEPAIR but also some such structures (allocated
|
|
+ during the htab_find_slot call). */
|
|
+
|
|
+ missing_filepair_find.binary = (char *) binary;
|
|
+ missing_filepair_find.debug = (char *) debug;
|
|
+ slot = (struct missing_filepair **) htab_find_slot (missing_filepair_hash,
|
|
+ &missing_filepair_find,
|
|
+ INSERT);
|
|
+
|
|
+ /* While it may be still printed duplicitely with the missing debuginfo file
|
|
+ * it is due to once printing about the binary file build-id link and once
|
|
+ * about the .debug file build-id link as both the build-id symlinks are
|
|
+ * located in the debuginfo package. */
|
|
+
|
|
+ if (*slot != NULL)
|
|
+ return;
|
|
+
|
|
+ missing_filepair = (struct missing_filepair *) obstack_alloc (&missing_filepair_obstack,
|
|
+ sizeof (*missing_filepair) - 1
|
|
+ + binary_len0 + debug_len0);
|
|
+ missing_filepair->binary = missing_filepair->data;
|
|
+ memcpy (missing_filepair->binary, binary, binary_len0);
|
|
+ if (debug != NULL)
|
|
+ {
|
|
+ missing_filepair->debug = missing_filepair->binary + binary_len0;
|
|
+ memcpy (missing_filepair->debug, debug, debug_len0);
|
|
+ }
|
|
+ else
|
|
+ missing_filepair->debug = NULL;
|
|
+
|
|
+ *slot = missing_filepair;
|
|
+
|
|
+#ifdef HAVE_LIBRPM
|
|
+ if (missing_exec == MISSING_EXEC_NOT_TRIED)
|
|
+ {
|
|
+ const char *execfilename = get_exec_file (0);
|
|
+
|
|
+ if (execfilename != NULL)
|
|
+ {
|
|
+ if (missing_rpm_enlist (execfilename) == 0)
|
|
+ missing_exec = MISSING_EXEC_NOT_FOUND;
|
|
+ else
|
|
+ missing_exec = MISSING_EXEC_ENLISTED;
|
|
+ }
|
|
+ }
|
|
+ if (missing_exec != MISSING_EXEC_ENLISTED)
|
|
+ if ((binary[0] == 0 || missing_rpm_enlist (binary) == 0)
|
|
+ && (debug == NULL || missing_rpm_enlist (debug) == 0))
|
|
+#endif /* HAVE_LIBRPM */
|
|
+ {
|
|
+ /* We do not collect and flush these messages as each such message
|
|
+ already requires its own separate lines. */
|
|
+
|
|
+ fprintf_unfiltered (gdb_stdlog,
|
|
+ _("Missing separate debuginfo for %s\n"), binary);
|
|
+ if (debug != NULL)
|
|
+ fprintf_unfiltered (gdb_stdlog, _("Try: %s %s\n"),
|
|
+#ifdef DNF_DEBUGINFO_INSTALL
|
|
+ "dnf"
|
|
+#else
|
|
+ "yum"
|
|
+#endif
|
|
+ " --enablerepo='*debug*' install", debug);
|
|
+ }
|
|
+}
|
|
+
|
|
/* See build-id.h. */
|
|
|
|
gdb_bfd_ref_ptr
|
|
-build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id)
|
|
+build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id,
|
|
+ char **link_return)
|
|
{
|
|
- return build_id_to_bfd_suffix (build_id_len, build_id, ".debug");
|
|
+ return build_id_to_bfd_suffix (build_id_len, build_id, ".debug",
|
|
+ link_return);
|
|
}
|
|
|
|
/* See build-id.h. */
|
|
|
|
gdb_bfd_ref_ptr
|
|
-build_id_to_exec_bfd (size_t build_id_len, const bfd_byte *build_id)
|
|
+build_id_to_exec_bfd (size_t build_id_len, const bfd_byte *build_id,
|
|
+ char **link_return)
|
|
{
|
|
- return build_id_to_bfd_suffix (build_id_len, build_id, "");
|
|
+ return build_id_to_bfd_suffix (build_id_len, build_id, "", link_return);
|
|
}
|
|
|
|
/* See build-id.h. */
|
|
|
|
std::string
|
|
-find_separate_debug_file_by_buildid (struct objfile *objfile)
|
|
+find_separate_debug_file_by_buildid (struct objfile *objfile,
|
|
+ gdb::unique_xmalloc_ptr<char> *build_id_filename_return)
|
|
{
|
|
const struct bfd_build_id *build_id;
|
|
|
|
- build_id = build_id_bfd_get (objfile->obfd);
|
|
+ if (build_id_filename_return)
|
|
+ *build_id_filename_return = NULL;
|
|
+
|
|
+ build_id = build_id_bfd_shdr_get (objfile->obfd);
|
|
if (build_id != NULL)
|
|
{
|
|
if (separate_debug_file_debug)
|
|
@@ -214,8 +1338,21 @@ find_separate_debug_file_by_buildid (struct objfile *objfile)
|
|
_("\nLooking for separate debug info (build-id) for "
|
|
"%s\n"), objfile_name (objfile));
|
|
|
|
+ char *build_id_filename_cstr = NULL;
|
|
gdb_bfd_ref_ptr abfd (build_id_to_debug_bfd (build_id->size,
|
|
- build_id->data));
|
|
+ build_id->data,
|
|
+ (!build_id_filename_return ? NULL : &build_id_filename_cstr)));
|
|
+ if (build_id_filename_return)
|
|
+ {
|
|
+ if (!build_id_filename_cstr)
|
|
+ gdb_assert (!*build_id_filename_return);
|
|
+ else
|
|
+ {
|
|
+ *build_id_filename_return = gdb::unique_xmalloc_ptr<char> (build_id_filename_cstr);
|
|
+ build_id_filename_cstr = NULL;
|
|
+ }
|
|
+ }
|
|
+
|
|
/* Prevent looping on a stripped .debug file. */
|
|
if (abfd != NULL
|
|
&& filename_cmp (bfd_get_filename (abfd.get ()),
|
|
@@ -228,3 +1365,22 @@ find_separate_debug_file_by_buildid (struct objfile *objfile)
|
|
|
|
return std::string ();
|
|
}
|
|
+
|
|
+void _initialize_build_id ();
|
|
+
|
|
+void
|
|
+_initialize_build_id ()
|
|
+{
|
|
+ add_setshow_zinteger_cmd ("build-id-verbose", no_class, &build_id_verbose,
|
|
+ _("\
|
|
+Set debugging level of the build-id locator."), _("\
|
|
+Show debugging level of the build-id locator."), _("\
|
|
+Level 1 (default) enables printing the missing debug filenames,\n\
|
|
+level 2 also prints the parsing of binaries to find the identificators."),
|
|
+ NULL,
|
|
+ show_build_id_verbose,
|
|
+ &setlist, &showlist);
|
|
+
|
|
+ gdb::observers::executable_changed.attach (debug_print_executable_changed,
|
|
+ "build-id");
|
|
+}
|
|
diff --git a/gdb/build-id.h b/gdb/build-id.h
|
|
--- a/gdb/build-id.h
|
|
+++ b/gdb/build-id.h
|
|
@@ -23,9 +23,10 @@
|
|
#include "gdb_bfd.h"
|
|
#include "gdbsupport/rsp-low.h"
|
|
|
|
-/* Locate NT_GNU_BUILD_ID from ABFD and return its content. */
|
|
+/* Separate debuginfo files have corrupted PHDR but SHDR is correct there.
|
|
+ Locate NT_GNU_BUILD_ID from ABFD and return its content. */
|
|
|
|
-extern const struct bfd_build_id *build_id_bfd_get (bfd *abfd);
|
|
+extern const struct bfd_build_id *build_id_bfd_shdr_get (bfd *abfd);
|
|
|
|
/* Return true if ABFD has NT_GNU_BUILD_ID matching the CHECK value.
|
|
Otherwise, issue a warning and return false. */
|
|
@@ -38,21 +39,26 @@ extern int build_id_verify (bfd *abfd,
|
|
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);
|
|
+ const bfd_byte *build_id,
|
|
+ char **link_return = NULL);
|
|
+
|
|
+extern char *build_id_to_filename (const struct bfd_build_id *build_id,
|
|
+ char **link_return);
|
|
|
|
/* 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);
|
|
+ const bfd_byte *build_id,
|
|
+ char **link_return);
|
|
|
|
/* 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. */
|
|
|
|
-extern std::string find_separate_debug_file_by_buildid
|
|
- (struct objfile *objfile);
|
|
+extern std::string find_separate_debug_file_by_buildid (struct objfile *objfile,
|
|
+ gdb::unique_xmalloc_ptr<char> *build_id_filename_return);
|
|
|
|
/* Return an hex-string representation of BUILD_ID. */
|
|
|
|
diff --git a/gdb/coffread.c b/gdb/coffread.c
|
|
--- a/gdb/coffread.c
|
|
+++ b/gdb/coffread.c
|
|
@@ -710,7 +710,8 @@ coff_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
|
|
/* Try to add separate debug file if no symbols table found. */
|
|
if (!objfile->has_partial_symbols ())
|
|
{
|
|
- std::string debugfile = find_separate_debug_file_by_buildid (objfile);
|
|
+ std::string debugfile = find_separate_debug_file_by_buildid (objfile,
|
|
+ NULL);
|
|
|
|
if (debugfile.empty ())
|
|
debugfile = find_separate_debug_file_by_debuglink (objfile);
|
|
diff --git a/gdb/corelow.c b/gdb/corelow.c
|
|
--- a/gdb/corelow.c
|
|
+++ b/gdb/corelow.c
|
|
@@ -22,6 +22,10 @@
|
|
#include <signal.h>
|
|
#include <fcntl.h>
|
|
#include "frame.h" /* required by inferior.h */
|
|
+#include "auxv.h"
|
|
+#include "build-id.h"
|
|
+#include "elf/common.h"
|
|
+#include "gdbcmd.h"
|
|
#include "inferior.h"
|
|
#include "infrun.h"
|
|
#include "symtab.h"
|
|
@@ -356,6 +360,8 @@ add_to_thread_list (asection *asect, asection *reg_sect)
|
|
switch_to_thread (thr); /* Yes, make it current. */
|
|
}
|
|
|
|
+static bool build_id_core_loads = true;
|
|
+
|
|
/* Issue a message saying we have no core to debug, if FROM_TTY. */
|
|
|
|
static void
|
|
@@ -392,19 +398,26 @@ core_file_command (const char *filename, int from_tty)
|
|
static void
|
|
locate_exec_from_corefile_build_id (bfd *abfd, int from_tty)
|
|
{
|
|
- const bfd_build_id *build_id = build_id_bfd_get (abfd);
|
|
+ const bfd_build_id *build_id = build_id_bfd_shdr_get (abfd);
|
|
if (build_id == nullptr)
|
|
return;
|
|
|
|
+ char *build_id_filename;
|
|
gdb_bfd_ref_ptr execbfd
|
|
- = build_id_to_exec_bfd (build_id->size, build_id->data);
|
|
+ = build_id_to_exec_bfd (build_id->size, build_id->data,
|
|
+ &build_id_filename);
|
|
|
|
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));
|
|
+ if (current_program_space->symfile_object_file != NULL)
|
|
+ current_program_space->symfile_object_file->flags |=
|
|
+ OBJF_BUILD_ID_CORE_LOADED;
|
|
}
|
|
+ else
|
|
+ debug_print_missing (BUILD_ID_MAIN_EXECUTABLE_FILENAME, build_id_filename);
|
|
}
|
|
|
|
/* See gdbcore.h. */
|
|
@@ -1209,4 +1222,11 @@ _initialize_corelow ()
|
|
maintenance_print_core_file_backed_mappings,
|
|
_("Print core file's file-backed mappings."),
|
|
&maintenanceprintlist);
|
|
+
|
|
+ add_setshow_boolean_cmd ("build-id-core-loads", class_files,
|
|
+ &build_id_core_loads, _("\
|
|
+Set whether CORE-FILE loads the build-id associated files automatically."), _("\
|
|
+Show whether CORE-FILE loads the build-id associated files automatically."),
|
|
+ NULL, NULL, NULL,
|
|
+ &setlist, &showlist);
|
|
}
|
|
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
|
|
--- a/gdb/doc/gdb.texinfo
|
|
+++ b/gdb/doc/gdb.texinfo
|
|
@@ -21524,6 +21524,27 @@ information files.
|
|
|
|
@end table
|
|
|
|
+You can also adjust the current verbosity of the @dfn{build id} locating.
|
|
+
|
|
+@table @code
|
|
+
|
|
+@kindex set build-id-verbose
|
|
+@item set build-id-verbose 0
|
|
+No additional messages are printed.
|
|
+
|
|
+@item set build-id-verbose 1
|
|
+Missing separate debug filenames are printed.
|
|
+
|
|
+@item set build-id-verbose 2
|
|
+Missing separate debug filenames are printed and also all the parsing of the
|
|
+binaries to find their @dfn{build id} content is printed.
|
|
+
|
|
+@kindex show build-id-verbose
|
|
+@item show build-id-verbose
|
|
+Show the current verbosity value for the @dfn{build id} content locating.
|
|
+
|
|
+@end table
|
|
+
|
|
@cindex @code{.gnu_debuglink} sections
|
|
@cindex debug link sections
|
|
A debug link is a special section of the executable file named
|
|
diff --git a/gdb/dwarf2/index-cache.c b/gdb/dwarf2/index-cache.c
|
|
--- a/gdb/dwarf2/index-cache.c
|
|
+++ b/gdb/dwarf2/index-cache.c
|
|
@@ -97,7 +97,7 @@ index_cache::store (dwarf2_per_objfile *per_objfile)
|
|
return;
|
|
|
|
/* Get build id of objfile. */
|
|
- const bfd_build_id *build_id = build_id_bfd_get (obj->obfd);
|
|
+ const bfd_build_id *build_id = build_id_bfd_shdr_get (obj->obfd);
|
|
if (build_id == nullptr)
|
|
{
|
|
index_cache_debug ("objfile %s has no build id",
|
|
@@ -114,7 +114,8 @@ index_cache::store (dwarf2_per_objfile *per_objfile)
|
|
|
|
if (dwz != nullptr)
|
|
{
|
|
- const bfd_build_id *dwz_build_id = build_id_bfd_get (dwz->dwz_bfd.get ());
|
|
+ const bfd_build_id *dwz_build_id
|
|
+ = build_id_bfd_shdr_get (dwz->dwz_bfd.get ());
|
|
|
|
if (dwz_build_id == nullptr)
|
|
{
|
|
diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
|
|
--- a/gdb/dwarf2/read.c
|
|
+++ b/gdb/dwarf2/read.c
|
|
@@ -5476,7 +5476,7 @@ get_gdb_index_contents_from_section (objfile *obj, T *section_owner)
|
|
static gdb::array_view<const gdb_byte>
|
|
get_gdb_index_contents_from_cache (objfile *obj, dwarf2_per_bfd *dwarf2_per_bfd)
|
|
{
|
|
- const bfd_build_id *build_id = build_id_bfd_get (obj->obfd);
|
|
+ const bfd_build_id *build_id = build_id_bfd_shdr_get (obj->obfd);
|
|
if (build_id == nullptr)
|
|
return {};
|
|
|
|
@@ -5489,7 +5489,7 @@ get_gdb_index_contents_from_cache (objfile *obj, dwarf2_per_bfd *dwarf2_per_bfd)
|
|
static gdb::array_view<const gdb_byte>
|
|
get_gdb_index_contents_from_cache_dwz (objfile *obj, dwz_file *dwz)
|
|
{
|
|
- const bfd_build_id *build_id = build_id_bfd_get (dwz->dwz_bfd.get ());
|
|
+ const bfd_build_id *build_id = build_id_bfd_shdr_get (dwz->dwz_bfd.get ());
|
|
if (build_id == nullptr)
|
|
return {};
|
|
|
|
diff --git a/gdb/elfread.c b/gdb/elfread.c
|
|
--- a/gdb/elfread.c
|
|
+++ b/gdb/elfread.c
|
|
@@ -1270,7 +1270,9 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
|
|
&& objfile->separate_debug_objfile == NULL
|
|
&& objfile->separate_debug_objfile_backlink == NULL)
|
|
{
|
|
- std::string debugfile = find_separate_debug_file_by_buildid (objfile);
|
|
+ gdb::unique_xmalloc_ptr<char> build_id_filename;
|
|
+ std::string debugfile
|
|
+ = find_separate_debug_file_by_buildid (objfile, &build_id_filename);
|
|
|
|
if (debugfile.empty ())
|
|
debugfile = find_separate_debug_file_by_debuglink (objfile);
|
|
@@ -1285,7 +1287,7 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
|
|
else
|
|
{
|
|
has_dwarf2 = false;
|
|
- const struct bfd_build_id *build_id = build_id_bfd_get (objfile->obfd);
|
|
+ const struct bfd_build_id *build_id = build_id_bfd_shdr_get (objfile->obfd);
|
|
|
|
if (build_id != nullptr)
|
|
{
|
|
@@ -1310,6 +1312,10 @@ elf_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
|
|
has_dwarf2 = true;
|
|
}
|
|
}
|
|
+ /* Check if any separate debug info has been extracted out. */
|
|
+ else if (bfd_get_section_by_name (objfile->obfd, ".gnu_debuglink")
|
|
+ != NULL)
|
|
+ debug_print_missing (objfile_name (objfile), build_id_filename.get ());
|
|
}
|
|
}
|
|
}
|
|
diff --git a/gdb/exec.c b/gdb/exec.c
|
|
--- a/gdb/exec.c
|
|
+++ b/gdb/exec.c
|
|
@@ -238,7 +238,7 @@ validate_exec_file (int from_tty)
|
|
current_exec_file = get_exec_file (0);
|
|
|
|
const bfd_build_id *exec_file_build_id
|
|
- = build_id_bfd_get (current_program_space->exec_bfd ());
|
|
+ = build_id_bfd_shdr_get (current_program_space->exec_bfd ());
|
|
if (exec_file_build_id != nullptr)
|
|
{
|
|
/* Prepend the target prefix, to force gdb_bfd_open to open the
|
|
@@ -251,7 +251,7 @@ validate_exec_file (int from_tty)
|
|
if (abfd != nullptr)
|
|
{
|
|
const bfd_build_id *target_exec_file_build_id
|
|
- = build_id_bfd_get (abfd.get ());
|
|
+ = build_id_bfd_shdr_get (abfd.get ());
|
|
|
|
if (target_exec_file_build_id != nullptr)
|
|
{
|
|
diff --git a/gdb/objfiles.h b/gdb/objfiles.h
|
|
--- a/gdb/objfiles.h
|
|
+++ b/gdb/objfiles.h
|
|
@@ -769,6 +769,10 @@ struct objfile
|
|
bool skip_jit_symbol_lookup = false;
|
|
};
|
|
|
|
+/* This file was loaded according to the BUILD_ID_CORE_LOADS rules. */
|
|
+
|
|
+#define OBJF_BUILD_ID_CORE_LOADED static_cast<enum objfile_flag>(1 << 12)
|
|
+
|
|
/* A deleter for objfile. */
|
|
|
|
struct objfile_deleter
|
|
diff --git a/gdb/python/py-objfile.c b/gdb/python/py-objfile.c
|
|
--- a/gdb/python/py-objfile.c
|
|
+++ b/gdb/python/py-objfile.c
|
|
@@ -132,7 +132,7 @@ objfpy_get_build_id (PyObject *self, void *closure)
|
|
|
|
try
|
|
{
|
|
- build_id = build_id_bfd_get (objfile->obfd);
|
|
+ build_id = build_id_bfd_shdr_get (objfile->obfd);
|
|
}
|
|
catch (const gdb_exception &except)
|
|
{
|
|
@@ -600,7 +600,7 @@ objfpy_lookup_objfile_by_build_id (const char *build_id)
|
|
/* Don't return separate debug files. */
|
|
if (objfile->separate_debug_objfile_backlink != NULL)
|
|
continue;
|
|
- obfd_build_id = build_id_bfd_get (objfile->obfd);
|
|
+ obfd_build_id = build_id_bfd_shdr_get (objfile->obfd);
|
|
if (obfd_build_id == NULL)
|
|
continue;
|
|
if (objfpy_build_id_matches (obfd_build_id, build_id))
|
|
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c
|
|
--- a/gdb/solib-svr4.c
|
|
+++ b/gdb/solib-svr4.c
|
|
@@ -45,6 +45,7 @@
|
|
#include "auxv.h"
|
|
#include "gdb_bfd.h"
|
|
#include "probe.h"
|
|
+#include "build-id.h"
|
|
|
|
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
|
|
static int svr4_have_link_map_offsets (void);
|
|
@@ -1248,9 +1249,51 @@ svr4_read_so_list (svr4_info *info, CORE_ADDR lm, CORE_ADDR prev_lm,
|
|
continue;
|
|
}
|
|
|
|
- strncpy (newobj->so_name, buffer.get (), SO_NAME_MAX_PATH_SIZE - 1);
|
|
- newobj->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
|
|
- strcpy (newobj->so_original_name, newobj->so_name);
|
|
+ {
|
|
+ struct bfd_build_id *build_id;
|
|
+
|
|
+ strncpy (newobj->so_original_name, buffer.get (), SO_NAME_MAX_PATH_SIZE - 1);
|
|
+ newobj->so_original_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
|
|
+ /* May get overwritten below. */
|
|
+ strcpy (newobj->so_name, newobj->so_original_name);
|
|
+
|
|
+ build_id = build_id_addr_get (((lm_info_svr4 *) newobj->lm_info)->l_ld);
|
|
+ if (build_id != NULL)
|
|
+ {
|
|
+ char *name, *build_id_filename;
|
|
+
|
|
+ /* Missing the build-id matching separate debug info file
|
|
+ would be handled while SO_NAME gets loaded. */
|
|
+ name = build_id_to_filename (build_id, &build_id_filename);
|
|
+ if (name != NULL)
|
|
+ {
|
|
+ strncpy (newobj->so_name, name, SO_NAME_MAX_PATH_SIZE - 1);
|
|
+ newobj->so_name[SO_NAME_MAX_PATH_SIZE - 1] = '\0';
|
|
+ xfree (name);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ debug_print_missing (newobj->so_name, build_id_filename);
|
|
+
|
|
+ /* In the case the main executable was found according to
|
|
+ its build-id (from a core file) prevent loading
|
|
+ a different build of a library with accidentally the
|
|
+ same SO_NAME.
|
|
+
|
|
+ It suppresses bogus backtraces (and prints "??" there
|
|
+ instead) if the on-disk files no longer match the
|
|
+ running program version. */
|
|
+
|
|
+ if (current_program_space->symfile_object_file != NULL
|
|
+ && (current_program_space->symfile_object_file->flags
|
|
+ & OBJF_BUILD_ID_CORE_LOADED) != 0)
|
|
+ newobj->so_name[0] = 0;
|
|
+ }
|
|
+
|
|
+ xfree (build_id_filename);
|
|
+ xfree (build_id);
|
|
+ }
|
|
+ }
|
|
|
|
/* If this entry has no name, or its name matches the name
|
|
for the main executable, don't include it in the list. */
|
|
diff --git a/gdb/source.c b/gdb/source.c
|
|
--- a/gdb/source.c
|
|
+++ b/gdb/source.c
|
|
@@ -1199,7 +1199,7 @@ open_source_file (struct symtab *s)
|
|
srcpath += s->filename;
|
|
}
|
|
|
|
- const struct bfd_build_id *build_id = build_id_bfd_get (ofp->obfd);
|
|
+ const struct bfd_build_id *build_id = build_id_bfd_shdr_get (ofp->obfd);
|
|
|
|
/* Query debuginfod for the source file. */
|
|
if (build_id != nullptr && !srcpath.empty ())
|
|
diff --git a/gdb/symfile.h b/gdb/symfile.h
|
|
--- a/gdb/symfile.h
|
|
+++ b/gdb/symfile.h
|
|
@@ -332,12 +332,18 @@ bool expand_symtabs_matching
|
|
void map_symbol_filenames (gdb::function_view<symbol_filename_ftype> fun,
|
|
bool need_fullname);
|
|
|
|
+
|
|
/* Target-agnostic function to load the sections of an executable into memory.
|
|
|
|
ARGS should be in the form "EXECUTABLE [OFFSET]", where OFFSET is an
|
|
optional offset to apply to each section. */
|
|
extern void generic_load (const char *args, int from_tty);
|
|
|
|
+/* build-id support. */
|
|
+extern struct bfd_build_id *build_id_addr_get (CORE_ADDR addr);
|
|
+extern void debug_print_missing (const char *binary, const char *debug);
|
|
+#define BUILD_ID_MAIN_EXECUTABLE_FILENAME _("the main executable file")
|
|
+
|
|
/* From minidebug.c. */
|
|
|
|
extern gdb_bfd_ref_ptr find_separate_debug_file_in_section (struct objfile *);
|
|
diff --git a/gdb/testsuite/gdb.base/corefile.exp b/gdb/testsuite/gdb.base/corefile.exp
|
|
--- a/gdb/testsuite/gdb.base/corefile.exp
|
|
+++ b/gdb/testsuite/gdb.base/corefile.exp
|
|
@@ -343,3 +343,33 @@ gdb_test_multiple "core-file $corefile" $test {
|
|
pass $test
|
|
}
|
|
}
|
|
+
|
|
+
|
|
+# Test auto-loading of binary files through build-id from the core file.
|
|
+set buildid [build_id_debug_filename_get $binfile]
|
|
+set wholetest "binfile found by build-id"
|
|
+if {$buildid == ""} {
|
|
+ untested "$wholetest (binary has no build-id)"
|
|
+} else {
|
|
+ gdb_exit
|
|
+ gdb_start
|
|
+
|
|
+ regsub {\.debug$} $buildid {} buildid
|
|
+ set debugdir [standard_output_file ${testfile}-debugdir]
|
|
+ file delete -force -- $debugdir
|
|
+ file mkdir $debugdir/[file dirname $buildid]
|
|
+ file copy $binfile $debugdir/$buildid
|
|
+
|
|
+ set test "show debug-file-directory"
|
|
+ gdb_test_multiple $test $test {
|
|
+ -re "The directory where separate debug symbols are searched for is \"(.*)\"\\.\r\n$gdb_prompt $" {
|
|
+ set debugdir_orig $expect_out(1,string)
|
|
+ pass $test
|
|
+ }
|
|
+ }
|
|
+ gdb_test_no_output "set debug-file-directory $debugdir:$debugdir_orig" "set debug-file-directory"
|
|
+ gdb_test "show build-id-core-loads" {Whether CORE-FILE loads the build-id associated files automatically is on\.}
|
|
+ gdb_test "core-file $corefile" "\r\nProgram terminated with .*" "core-file without executable"
|
|
+ gdb_test "info files" "Local exec file:\r\n\[ \t\]*`[string_to_regexp $debugdir/$buildid]', file type .*"
|
|
+ pass $wholetest
|
|
+}
|
|
diff --git a/gdb/testsuite/gdb.base/gdbinit-history.exp b/gdb/testsuite/gdb.base/gdbinit-history.exp
|
|
--- a/gdb/testsuite/gdb.base/gdbinit-history.exp
|
|
+++ b/gdb/testsuite/gdb.base/gdbinit-history.exp
|
|
@@ -185,7 +185,8 @@ proc test_empty_history_filename { } {
|
|
global env
|
|
global gdb_prompt
|
|
|
|
- set common_history [list "set height 0" "set width 0"]
|
|
+ set common_history [list "set height 0" "set width 0" \
|
|
+ "set build-id-verbose 0"]
|
|
|
|
set test_dir [standard_output_file history_test]
|
|
remote_exec host "mkdir -p $test_dir"
|
|
diff --git a/gdb/testsuite/gdb.base/new-ui-pending-input.exp b/gdb/testsuite/gdb.base/new-ui-pending-input.exp
|
|
--- a/gdb/testsuite/gdb.base/new-ui-pending-input.exp
|
|
+++ b/gdb/testsuite/gdb.base/new-ui-pending-input.exp
|
|
@@ -62,6 +62,7 @@ proc test_command_line_new_ui_pending_input {} {
|
|
set options ""
|
|
append options " -iex \"set height 0\""
|
|
append options " -iex \"set width 0\""
|
|
+ append options " -iex \"set build-id-verbose 0\""
|
|
append options " -iex \"new-ui console $extra_tty_name\""
|
|
append options " -ex \"b $bpline\""
|
|
append options " -ex \"run\""
|
|
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
|
|
--- a/gdb/testsuite/lib/gdb.exp
|
|
+++ b/gdb/testsuite/lib/gdb.exp
|
|
@@ -141,7 +141,8 @@ if ![info exists INTERNAL_GDBFLAGS] {
|
|
"-nx" \
|
|
"-data-directory $BUILD_DATA_DIRECTORY" \
|
|
{-iex "set height 0"} \
|
|
- {-iex "set width 0"}]]
|
|
+ {-iex "set width 0"} \
|
|
+ {-iex "set build-id-verbose 0"}]]
|
|
}
|
|
|
|
# The variable gdb_prompt is a regexp which matches the gdb prompt.
|
|
@@ -2200,6 +2201,17 @@ proc default_gdb_start { } {
|
|
}
|
|
}
|
|
|
|
+ # Turn off the missing warnings as the testsuite does not expect it.
|
|
+ send_gdb "set build-id-verbose 0\n"
|
|
+ gdb_expect 10 {
|
|
+ -re "$gdb_prompt $" {
|
|
+ verbose "Disabled the missing debug infos warnings." 2
|
|
+ }
|
|
+ timeout {
|
|
+ warning "Could not disable the missing debug infos warnings.."
|
|
+ }
|
|
+ }
|
|
+
|
|
gdb_debug_init
|
|
return 0
|
|
}
|
|
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
|
|
--- a/gdb/testsuite/lib/mi-support.exp
|
|
+++ b/gdb/testsuite/lib/mi-support.exp
|
|
@@ -322,6 +322,16 @@ proc default_mi_gdb_start { args } {
|
|
warning "Couldn't set the width to 0."
|
|
}
|
|
}
|
|
+ # Turn off the missing warnings as the testsuite does not expect it.
|
|
+ send_gdb "190-gdb-set build-id-verbose 0\n"
|
|
+ gdb_expect 10 {
|
|
+ -re ".*190-gdb-set build-id-verbose 0\r\n190\\\^done\r\n$mi_gdb_prompt$" {
|
|
+ verbose "Disabled the missing debug infos warnings." 2
|
|
+ }
|
|
+ timeout {
|
|
+ warning "Could not disable the missing debug infos warnings.."
|
|
+ }
|
|
+ }
|
|
|
|
if { $separate_inferior_pty } {
|
|
mi_create_inferior_pty
|