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