X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=gdb%2Fbuild-id.c;h=345ed0e196e768d5a503b6aeb52aa19e18d90794;hb=8b8da1a9f31941fa167c9f2bd2a80cdd1dccb452;hp=ed66bc6c9438cea07e4c5434e32dd343280ec4ac;hpb=61baf725eca99af2569262d10aca03dcde2698f6;p=binutils-gdb.git diff --git a/gdb/build-id.c b/gdb/build-id.c index ed66bc6c943..345ed0e196e 100644 --- a/gdb/build-id.c +++ b/gdb/build-id.c @@ -1,6 +1,6 @@ /* build-id-related functions. - Copyright (C) 1991-2017 Free Software Foundation, Inc. + Copyright (C) 1991-2022 Free Software Foundation, Inc. This file is part of GDB. @@ -21,7 +21,7 @@ #include "bfd.h" #include "gdb_bfd.h" #include "build-id.h" -#include "gdb_vecs.h" +#include "gdbsupport/gdb_vecs.h" #include "symfile.h" #include "objfiles.h" #include "filenames.h" @@ -32,7 +32,8 @@ const struct bfd_build_id * build_id_bfd_get (bfd *abfd) { - if (!bfd_check_format (abfd, bfd_object)) + if (!bfd_check_format (abfd, bfd_object) + && !bfd_check_format (abfd, bfd_core)) return NULL; if (abfd->build_id != NULL) @@ -56,7 +57,7 @@ build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check) warning (_("File \"%s\" has no build-id, file skipped"), bfd_get_filename (abfd)); else if (found->size != check_len - || memcmp (found->data, check, found->size) != 0) + || memcmp (found->data, check, found->size) != 0) warning (_("File \"%s\" has a different build-id, file skipped"), bfd_get_filename (abfd)); else @@ -65,82 +66,142 @@ 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; - int alloc_len; - - /* DEBUG_FILE_DIRECTORY/.build-id/ab/cdef */ - alloc_len = (strlen (debug_file_directory) - + (sizeof "/.build-id/" - 1) + 1 - + 2 * build_id_len + (sizeof ".debug" - 1) + 1); - link = (char *) alloca (alloc_len); + if (separate_debug_file_debug) + { + gdb_printf (gdb_stdlog, _(" Trying %s..."), link.c_str ()); + gdb_flush (gdb_stdlog); + } + + /* lrealpath() is expensive even for the usually non-existent files. */ + gdb::unique_xmalloc_ptr 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) + gdb_printf (gdb_stdlog, + _(" 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, gnutarget); + + if (debug_bfd == NULL) + { + if (separate_debug_file_debug) + gdb_printf (gdb_stdlog, _(" no, unable to open.\n")); + + return {}; + } + + if (!build_id_verify (debug_bfd.get(), build_id_len, build_id)) + { + if (separate_debug_file_debug) + gdb_printf (gdb_stdlog, _(" no, build-id does not match.\n")); + + return {}; + } + + if (separate_debug_file_debug) + gdb_printf (gdb_stdlog, _(" 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.c_str ()); - 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; - struct cleanup *inner; - 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"); + string_appendf (link, "%02x", (unsigned) *data++); + + link += suffix; - /* lrealpath() is expensive even for the usually non-existent files. */ - if (access (link, F_OK) == 0) - filename = lrealpath (link); + 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 (filename == NULL) - continue; + /* 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". */ - /* We expect to be silent on the non-existing files. */ - inner = make_cleanup (xfree, filename); - abfd = gdb_bfd_open (filename, gnutarget, -1); - do_cleanups (inner); + if (!gdb_sysroot.empty ()) + { + 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; + } + } - if (abfd == NULL) - continue; + return {}; +} - if (build_id_verify (abfd, build_id_len, build_id)) - break; +/* See build-id.h. */ - gdb_bfd_unref (abfd); - abfd = NULL; - } +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"); +} - do_cleanups (back_to); - return abfd; +/* 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 bfd_build_id *build_id; @@ -148,25 +209,22 @@ find_separate_debug_file_by_buildid (struct objfile *objfile) build_id = build_id_bfd_get (objfile->obfd); if (build_id != NULL) { - bfd *abfd; + if (separate_debug_file_debug) + gdb_printf (gdb_stdlog, + _("\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 (); }