X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fbuild-id.c;h=e8d77bb44c80305dfc682aa94eb75ea05c83f409;hb=f1d293cc58bfe5f6b507dc2351f17632df8ab677;hp=491900b3e545c72325a54fc79847b8872fa63aae;hpb=ecd75fc8eed3bde86036141228074a20e55dcfc9;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/build-id.c b/gdb/build-id.c index 491900b3e5..e8d77bb44c 100644 --- a/gdb/build-id.c +++ b/gdb/build-id.c @@ -1,6 +1,6 @@ /* build-id-related functions. - Copyright (C) 1991-2014 Free Software Foundation, Inc. + Copyright (C) 1991-2019 Free Software Foundation, Inc. This file is part of GDB. @@ -19,30 +19,28 @@ #include "defs.h" #include "bfd.h" -#include "elf-bfd.h" #include "gdb_bfd.h" #include "build-id.h" -#include -#include "gdb_vecs.h" +#include "gdbsupport/gdb_vecs.h" #include "symfile.h" #include "objfiles.h" #include "filenames.h" +#include "gdbcore.h" -/* Locate NT_GNU_BUILD_ID from ABFD and return its content. */ +/* See build-id.h. */ -static const struct elf_build_id * +const struct bfd_build_id * build_id_bfd_get (bfd *abfd) { if (!bfd_check_format (abfd, bfd_object) - || bfd_get_flavour (abfd) != bfd_target_elf_flavour - /* Although this is ELF_specific, it is safe to do in generic - code because it does not rely on any ELF-specific symbols at - link time, and if the ELF code is not available in BFD, then - ABFD will not have the ELF flavour. */ - || elf_tdata (abfd)->build_id == NULL) + && !bfd_check_format (abfd, bfd_core)) return NULL; - return elf_tdata (abfd)->build_id; + if (abfd->build_id != NULL) + return abfd->build_id; + + /* No build-id */ + return NULL; } /* See build-id.h. */ @@ -50,7 +48,7 @@ build_id_bfd_get (bfd *abfd) int build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check) { - const struct elf_build_id *found; + const struct bfd_build_id *found; int retval = 0; found = build_id_bfd_get (abfd); @@ -68,101 +66,160 @@ build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check) return retval; } -/* See build-id.h. */ +/* 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. */ -bfd * -build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id) +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) { - char *link, *debugdir; - VEC (char_ptr) *debugdir_vec; - struct cleanup *back_to; - int ix; - bfd *abfd = NULL; + if (separate_debug_file_debug) + { + printf_unfiltered (_(" Trying %s..."), link.c_str ()); + gdb_flush (gdb_stdout); + } - /* DEBUG_FILE_DIRECTORY/.build-id/ab/cdef */ - link = alloca (strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1 - + 2 * build_id_len + (sizeof ".debug" - 1) + 1); + /* lrealpath() is expensive even for the usually non-existent files. */ + gdb::unique_xmalloc_ptr filename; + if (access (link.c_str (), F_OK) == 0) + filename.reset (lrealpath (link.c_str ())); + if (filename == NULL) + { + if (separate_debug_file_debug) + printf_unfiltered (_(" no, unable to compute real path\n")); + + return {}; + } + + /* We expect to be silent on the non-existing files. */ + gdb_bfd_ref_ptr debug_bfd = gdb_bfd_open (filename.get (), gnutarget, -1); + + if (debug_bfd == NULL) + { + if (separate_debug_file_debug) + printf_unfiltered (_(" no, unable to open.\n")); + + return {}; + } + + if (!build_id_verify (debug_bfd.get(), build_id_len, build_id)) + { + if (separate_debug_file_debug) + printf_unfiltered (_(" no, build-id does not match.\n")); + + return {}; + } + + if (separate_debug_file_debug) + printf_unfiltered (_(" yes!\n")); + + return debug_bfd; +} + +/* Common code for finding BFDs of a given build-id. This function + works with both debuginfo files (SUFFIX == ".debug") and executable + files (SUFFIX == ""). */ + +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. */ - debugdir_vec = dirnames_to_char_ptr_vec (debug_file_directory); - back_to = make_cleanup_free_char_ptr_vec (debugdir_vec); + std::vector> debugdir_vec + = dirnames_to_char_ptr_vec (debug_file_directory); - for (ix = 0; VEC_iterate (char_ptr, debugdir_vec, ix, debugdir); ++ix) + for (const gdb::unique_xmalloc_ptr &debugdir : debugdir_vec) { - size_t debugdir_len = strlen (debugdir); const gdb_byte *data = build_id; size_t size = build_id_len; - char *s; - char *filename = NULL; - memcpy (link, debugdir, debugdir_len); - s = &link[debugdir_len]; - s += sprintf (s, "/.build-id/"); + /* Compute where the file named after the build-id would be. + + If debugdir is "/usr/lib/debug" and the build-id is abcdef, this will + give "/usr/lib/debug/.build-id/ab/cdef.debug". */ + std::string link = debugdir.get (); + link += "/.build-id/"; + if (size > 0) { size--; - s += sprintf (s, "%02x", (unsigned) *data++); + string_appendf (link, "%02x/", (unsigned) *data++); } - if (size > 0) - *s++ = '/'; - while (size-- > 0) - s += sprintf (s, "%02x", (unsigned) *data++); - strcpy (s, ".debug"); - /* lrealpath() is expensive even for the usually non-existent files. */ - if (access (link, F_OK) == 0) - filename = lrealpath (link); + while (size-- > 0) + string_appendf (link, "%02x", (unsigned) *data++); - if (filename == NULL) - continue; + link += suffix; - /* We expect to be silent on the non-existing files. */ - abfd = gdb_bfd_open_maybe_remote (filename); - if (abfd == NULL) - continue; + gdb_bfd_ref_ptr debug_bfd + = build_id_to_debug_bfd_1 (link, build_id_len, build_id); + if (debug_bfd != NULL) + return debug_bfd; - if (build_id_verify (abfd, build_id_len, build_id)) - break; + /* Try to look under the sysroot as well. If the sysroot is + "/the/sysroot", it will give + "/the/sysroot/usr/lib/debug/.build-id/ab/cdef.debug". - gdb_bfd_unref (abfd); - abfd = NULL; + Don't do it if the sysroot is the target system ("target:"). It + could work in theory, but the lrealpath in build_id_to_debug_bfd_1 + only works with local paths. */ + if (strcmp (gdb_sysroot, TARGET_SYSROOT_PREFIX) != 0) + { + link = gdb_sysroot + link; + debug_bfd = build_id_to_debug_bfd_1 (link, build_id_len, build_id); + if (debug_bfd != NULL) + return debug_bfd; + } } - do_cleanups (back_to); - return abfd; + return {}; +} + +/* 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. */ -char * +std::string find_separate_debug_file_by_buildid (struct objfile *objfile) { - const struct elf_build_id *build_id; + const struct bfd_build_id *build_id; build_id = build_id_bfd_get (objfile->obfd); if (build_id != NULL) { - bfd *abfd; + if (separate_debug_file_debug) + printf_unfiltered (_("\nLooking for separate debug info (build-id) for " + "%s\n"), objfile_name (objfile)); - abfd = build_id_to_debug_bfd (build_id->size, build_id->data); + gdb_bfd_ref_ptr abfd (build_id_to_debug_bfd (build_id->size, + build_id->data)); /* Prevent looping on a stripped .debug file. */ if (abfd != NULL - && filename_cmp (bfd_get_filename (abfd), + && filename_cmp (bfd_get_filename (abfd.get ()), objfile_name (objfile)) == 0) - { - warning (_("\"%s\": separate debug info file has no debug info"), - bfd_get_filename (abfd)); - gdb_bfd_unref (abfd); - } + warning (_("\"%s\": separate debug info file has no debug info"), + bfd_get_filename (abfd.get ())); else if (abfd != NULL) - { - char *result = xstrdup (bfd_get_filename (abfd)); - - gdb_bfd_unref (abfd); - return result; - } + return std::string (bfd_get_filename (abfd.get ())); } - return NULL; + + return std::string (); }