1 /* build-id-related functions. 2 3 Copyright (C) 1991-2023 Free Software Foundation, Inc. 4 5 This file is part of GDB. 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 19 20 #include "defs.h" 21 #include "bfd.h" 22 #include "gdb_bfd.h" 23 #include "build-id.h" 24 #include "gdbsupport/gdb_vecs.h" 25 #include "symfile.h" 26 #include "objfiles.h" 27 #include "filenames.h" 28 #include "gdbcore.h" 29 30 /* See build-id.h. */ 31 32 const struct bfd_build_id * 33 build_id_bfd_get (bfd *abfd) 34 { 35 if (!bfd_check_format (abfd, bfd_object) 36 && !bfd_check_format (abfd, bfd_core)) 37 return NULL; 38 39 if (abfd->build_id != NULL) 40 return abfd->build_id; 41 42 /* No build-id */ 43 return NULL; 44 } 45 46 /* See build-id.h. */ 47 48 int 49 build_id_verify (bfd *abfd, size_t check_len, const bfd_byte *check) 50 { 51 const struct bfd_build_id *found; 52 int retval = 0; 53 54 found = build_id_bfd_get (abfd); 55 56 if (found == NULL) 57 warning (_("File \"%s\" has no build-id, file skipped"), 58 bfd_get_filename (abfd)); 59 else if (found->size != check_len 60 || memcmp (found->data, check, found->size) != 0) 61 warning (_("File \"%s\" has a different build-id, file skipped"), 62 bfd_get_filename (abfd)); 63 else 64 retval = 1; 65 66 return retval; 67 } 68 69 /* Helper for build_id_to_debug_bfd. LINK is a path to a potential 70 build-id-based separate debug file, potentially a symlink to the real file. 71 If the file exists and matches BUILD_ID, return a BFD reference to it. */ 72 73 static gdb_bfd_ref_ptr 74 build_id_to_debug_bfd_1 (const std::string &link, size_t build_id_len, 75 const bfd_byte *build_id) 76 { 77 if (separate_debug_file_debug) 78 { 79 gdb_printf (gdb_stdlog, _(" Trying %s..."), link.c_str ()); 80 gdb_flush (gdb_stdlog); 81 } 82 83 /* lrealpath() is expensive even for the usually non-existent files. */ 84 gdb::unique_xmalloc_ptr<char> filename_holder; 85 const char *filename = nullptr; 86 if (startswith (link, TARGET_SYSROOT_PREFIX)) 87 filename = link.c_str (); 88 else if (access (link.c_str (), F_OK) == 0) 89 { 90 filename_holder.reset (lrealpath (link.c_str ())); 91 filename = filename_holder.get (); 92 } 93 94 if (filename == NULL) 95 { 96 if (separate_debug_file_debug) 97 gdb_printf (gdb_stdlog, 98 _(" no, unable to compute real path\n")); 99 100 return {}; 101 } 102 103 /* We expect to be silent on the non-existing files. */ 104 gdb_bfd_ref_ptr debug_bfd = gdb_bfd_open (filename, gnutarget); 105 106 if (debug_bfd == NULL) 107 { 108 if (separate_debug_file_debug) 109 gdb_printf (gdb_stdlog, _(" no, unable to open.\n")); 110 111 return {}; 112 } 113 114 if (!build_id_verify (debug_bfd.get(), build_id_len, build_id)) 115 { 116 if (separate_debug_file_debug) 117 gdb_printf (gdb_stdlog, _(" no, build-id does not match.\n")); 118 119 return {}; 120 } 121 122 if (separate_debug_file_debug) 123 gdb_printf (gdb_stdlog, _(" yes!\n")); 124 125 return debug_bfd; 126 } 127 128 /* Common code for finding BFDs of a given build-id. This function 129 works with both debuginfo files (SUFFIX == ".debug") and executable 130 files (SUFFIX == ""). */ 131 132 static gdb_bfd_ref_ptr 133 build_id_to_bfd_suffix (size_t build_id_len, const bfd_byte *build_id, 134 const char *suffix) 135 { 136 /* Keep backward compatibility so that DEBUG_FILE_DIRECTORY being "" will 137 cause "/.build-id/..." lookups. */ 138 139 std::vector<gdb::unique_xmalloc_ptr<char>> debugdir_vec 140 = dirnames_to_char_ptr_vec (debug_file_directory.c_str ()); 141 142 for (const gdb::unique_xmalloc_ptr<char> &debugdir : debugdir_vec) 143 { 144 const gdb_byte *data = build_id; 145 size_t size = build_id_len; 146 147 /* Compute where the file named after the build-id would be. 148 149 If debugdir is "/usr/lib/debug" and the build-id is abcdef, this will 150 give "/usr/lib/debug/.build-id/ab/cdef.debug". */ 151 std::string link = debugdir.get (); 152 link += "/.build-id/"; 153 154 if (size > 0) 155 { 156 size--; 157 string_appendf (link, "%02x/", (unsigned) *data++); 158 } 159 160 while (size-- > 0) 161 string_appendf (link, "%02x", (unsigned) *data++); 162 163 link += suffix; 164 165 gdb_bfd_ref_ptr debug_bfd 166 = build_id_to_debug_bfd_1 (link, build_id_len, build_id); 167 if (debug_bfd != NULL) 168 return debug_bfd; 169 170 /* Try to look under the sysroot as well. If the sysroot is 171 "/the/sysroot", it will give 172 "/the/sysroot/usr/lib/debug/.build-id/ab/cdef.debug". */ 173 174 if (!gdb_sysroot.empty ()) 175 { 176 link = gdb_sysroot + link; 177 debug_bfd = build_id_to_debug_bfd_1 (link, build_id_len, build_id); 178 if (debug_bfd != NULL) 179 return debug_bfd; 180 } 181 } 182 183 return {}; 184 } 185 186 /* See build-id.h. */ 187 188 gdb_bfd_ref_ptr 189 build_id_to_debug_bfd (size_t build_id_len, const bfd_byte *build_id) 190 { 191 return build_id_to_bfd_suffix (build_id_len, build_id, ".debug"); 192 } 193 194 /* See build-id.h. */ 195 196 gdb_bfd_ref_ptr 197 build_id_to_exec_bfd (size_t build_id_len, const bfd_byte *build_id) 198 { 199 return build_id_to_bfd_suffix (build_id_len, build_id, ""); 200 } 201 202 /* See build-id.h. */ 203 204 std::string 205 find_separate_debug_file_by_buildid (struct objfile *objfile) 206 { 207 const struct bfd_build_id *build_id; 208 209 build_id = build_id_bfd_get (objfile->obfd.get ()); 210 if (build_id != NULL) 211 { 212 if (separate_debug_file_debug) 213 gdb_printf (gdb_stdlog, 214 _("\nLooking for separate debug info (build-id) for " 215 "%s\n"), objfile_name (objfile)); 216 217 gdb_bfd_ref_ptr abfd (build_id_to_debug_bfd (build_id->size, 218 build_id->data)); 219 /* Prevent looping on a stripped .debug file. */ 220 if (abfd != NULL 221 && filename_cmp (bfd_get_filename (abfd.get ()), 222 objfile_name (objfile)) == 0) 223 warning (_("\"%s\": separate debug info file has no debug info"), 224 bfd_get_filename (abfd.get ())); 225 else if (abfd != NULL) 226 return std::string (bfd_get_filename (abfd.get ())); 227 } 228 229 return std::string (); 230 } 231