1 /* DWARF DWZ handling for GDB. 2 3 Copyright (C) 2003-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 "dwarf2/dwz.h" 22 23 #include "build-id.h" 24 #include "debuginfod-support.h" 25 #include "dwarf2/read.h" 26 #include "dwarf2/sect-names.h" 27 #include "filenames.h" 28 #include "gdb_bfd.h" 29 #include "gdbcore.h" 30 #include "gdbsupport/pathstuff.h" 31 #include "gdbsupport/scoped_fd.h" 32 33 const char * 34 dwz_file::read_string (struct objfile *objfile, LONGEST str_offset) 35 { 36 str.read (objfile); 37 38 if (str.buffer == NULL) 39 error (_("DW_FORM_GNU_strp_alt used without .debug_str " 40 "section [in module %s]"), 41 bfd_get_filename (dwz_bfd.get ())); 42 if (str_offset >= str.size) 43 error (_("DW_FORM_GNU_strp_alt pointing outside of " 44 ".debug_str section [in module %s]"), 45 bfd_get_filename (dwz_bfd.get ())); 46 gdb_assert (HOST_CHAR_BIT == 8); 47 if (str.buffer[str_offset] == '\0') 48 return NULL; 49 return (const char *) (str.buffer + str_offset); 50 } 51 52 /* A helper function to find the sections for a .dwz file. */ 53 54 static void 55 locate_dwz_sections (bfd *abfd, asection *sectp, dwz_file *dwz_file) 56 { 57 /* Note that we only support the standard ELF names, because .dwz 58 is ELF-only (at the time of writing). */ 59 if (dwarf2_elf_names.abbrev.matches (sectp->name)) 60 { 61 dwz_file->abbrev.s.section = sectp; 62 dwz_file->abbrev.size = bfd_section_size (sectp); 63 } 64 else if (dwarf2_elf_names.info.matches (sectp->name)) 65 { 66 dwz_file->info.s.section = sectp; 67 dwz_file->info.size = bfd_section_size (sectp); 68 } 69 else if (dwarf2_elf_names.str.matches (sectp->name)) 70 { 71 dwz_file->str.s.section = sectp; 72 dwz_file->str.size = bfd_section_size (sectp); 73 } 74 else if (dwarf2_elf_names.line.matches (sectp->name)) 75 { 76 dwz_file->line.s.section = sectp; 77 dwz_file->line.size = bfd_section_size (sectp); 78 } 79 else if (dwarf2_elf_names.macro.matches (sectp->name)) 80 { 81 dwz_file->macro.s.section = sectp; 82 dwz_file->macro.size = bfd_section_size (sectp); 83 } 84 else if (dwarf2_elf_names.gdb_index.matches (sectp->name)) 85 { 86 dwz_file->gdb_index.s.section = sectp; 87 dwz_file->gdb_index.size = bfd_section_size (sectp); 88 } 89 else if (dwarf2_elf_names.debug_names.matches (sectp->name)) 90 { 91 dwz_file->debug_names.s.section = sectp; 92 dwz_file->debug_names.size = bfd_section_size (sectp); 93 } 94 } 95 96 /* Attempt to find a .dwz file (whose full path is represented by 97 FILENAME) in all of the specified debug file directories provided. 98 99 Return the equivalent gdb_bfd_ref_ptr of the .dwz file found, or 100 nullptr if it could not find anything. */ 101 102 static gdb_bfd_ref_ptr 103 dwz_search_other_debugdirs (std::string &filename, bfd_byte *buildid, 104 size_t buildid_len) 105 { 106 /* Let's assume that the path represented by FILENAME has the 107 "/.dwz/" subpath in it. This is what (most) GNU/Linux 108 distributions do, anyway. */ 109 size_t dwz_pos = filename.find ("/.dwz/"); 110 111 if (dwz_pos == std::string::npos) 112 return nullptr; 113 114 /* This is an obvious assertion, but it's here more to educate 115 future readers of this code that FILENAME at DWZ_POS *must* 116 contain a directory separator. */ 117 gdb_assert (IS_DIR_SEPARATOR (filename[dwz_pos])); 118 119 gdb_bfd_ref_ptr dwz_bfd; 120 std::vector<gdb::unique_xmalloc_ptr<char>> debugdir_vec 121 = dirnames_to_char_ptr_vec (debug_file_directory.c_str ()); 122 123 for (const gdb::unique_xmalloc_ptr<char> &debugdir : debugdir_vec) 124 { 125 /* The idea is to iterate over the 126 debug file directories provided by the user and 127 replace the hard-coded path in the "filename" by each 128 debug-file-directory. 129 130 For example, suppose that filename is: 131 132 /usr/lib/debug/.dwz/foo.dwz 133 134 And suppose that we have "$HOME/bar" as the 135 debug-file-directory. We would then adjust filename 136 to look like: 137 138 $HOME/bar/.dwz/foo.dwz 139 140 which would hopefully allow us to find the alt debug 141 file. */ 142 std::string ddir = debugdir.get (); 143 144 if (ddir.empty ()) 145 continue; 146 147 /* Make sure the current debug-file-directory ends with a 148 directory separator. This is needed because, if FILENAME 149 contains something like "/usr/lib/abcde/.dwz/foo.dwz" and 150 DDIR is "/usr/lib/abc", then could wrongfully skip it 151 below. */ 152 if (!IS_DIR_SEPARATOR (ddir.back ())) 153 ddir += SLASH_STRING; 154 155 /* Check whether the beginning of FILENAME is DDIR. If it is, 156 then we are dealing with a file which we already attempted to 157 open before, so we just skip it and continue processing the 158 remaining debug file directories. */ 159 if (filename.size () > ddir.size () 160 && filename.compare (0, ddir.size (), ddir) == 0) 161 continue; 162 163 /* Replace FILENAME's default debug-file-directory with 164 DDIR. */ 165 std::string new_filename = ddir + &filename[dwz_pos + 1]; 166 167 dwz_bfd = gdb_bfd_open (new_filename.c_str (), gnutarget); 168 169 if (dwz_bfd == nullptr) 170 continue; 171 172 if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid)) 173 { 174 dwz_bfd.reset (nullptr); 175 continue; 176 } 177 178 /* Found it. */ 179 break; 180 } 181 182 return dwz_bfd; 183 } 184 185 /* See dwz.h. */ 186 187 struct dwz_file * 188 dwarf2_get_dwz_file (dwarf2_per_bfd *per_bfd, bool require) 189 { 190 bfd_size_type buildid_len_arg; 191 size_t buildid_len; 192 bfd_byte *buildid; 193 194 if (per_bfd->dwz_file != NULL) 195 return per_bfd->dwz_file.get (); 196 197 bfd_set_error (bfd_error_no_error); 198 gdb::unique_xmalloc_ptr<char> data 199 (bfd_get_alt_debug_link_info (per_bfd->obfd, 200 &buildid_len_arg, &buildid)); 201 if (data == NULL) 202 { 203 if (bfd_get_error () == bfd_error_no_error) 204 { 205 if (!require) 206 return nullptr; 207 error (_("could not read '.gnu_debugaltlink' section")); 208 } 209 error (_("could not read '.gnu_debugaltlink' section: %s"), 210 bfd_errmsg (bfd_get_error ())); 211 } 212 213 gdb::unique_xmalloc_ptr<bfd_byte> buildid_holder (buildid); 214 215 buildid_len = (size_t) buildid_len_arg; 216 217 std::string filename = data.get (); 218 219 if (!IS_ABSOLUTE_PATH (filename.c_str ())) 220 { 221 gdb::unique_xmalloc_ptr<char> abs 222 = gdb_realpath (bfd_get_filename (per_bfd->obfd)); 223 224 filename = ldirname (abs.get ()) + SLASH_STRING + filename; 225 } 226 227 /* First try the file name given in the section. If that doesn't 228 work, try to use the build-id instead. */ 229 gdb_bfd_ref_ptr dwz_bfd (gdb_bfd_open (filename.c_str (), gnutarget)); 230 if (dwz_bfd != NULL) 231 { 232 if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid)) 233 dwz_bfd.reset (nullptr); 234 } 235 236 if (dwz_bfd == NULL) 237 dwz_bfd = build_id_to_debug_bfd (buildid_len, buildid); 238 239 if (dwz_bfd == nullptr) 240 { 241 /* If the user has provided us with different 242 debug file directories, we can try them in order. */ 243 dwz_bfd = dwz_search_other_debugdirs (filename, buildid, buildid_len); 244 } 245 246 if (dwz_bfd == nullptr) 247 { 248 gdb::unique_xmalloc_ptr<char> alt_filename; 249 const char *origname = bfd_get_filename (per_bfd->obfd); 250 251 scoped_fd fd (debuginfod_debuginfo_query (buildid, 252 buildid_len, 253 origname, 254 &alt_filename)); 255 256 if (fd.get () >= 0) 257 { 258 /* File successfully retrieved from server. */ 259 dwz_bfd = gdb_bfd_open (alt_filename.get (), gnutarget); 260 261 if (dwz_bfd == nullptr) 262 warning (_("File \"%s\" from debuginfod cannot be opened as bfd"), 263 alt_filename.get ()); 264 else if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid)) 265 dwz_bfd.reset (nullptr); 266 } 267 } 268 269 if (dwz_bfd == NULL) 270 error (_("could not find '.gnu_debugaltlink' file for %s"), 271 bfd_get_filename (per_bfd->obfd)); 272 273 std::unique_ptr<struct dwz_file> result 274 (new struct dwz_file (std::move (dwz_bfd))); 275 276 for (asection *sec : gdb_bfd_sections (result->dwz_bfd)) 277 locate_dwz_sections (result->dwz_bfd.get (), sec, result.get ()); 278 279 gdb_bfd_record_inclusion (per_bfd->obfd, result->dwz_bfd.get ()); 280 per_bfd->dwz_file = std::move (result); 281 return per_bfd->dwz_file.get (); 282 } 283