GDB (xrefs)
Loading...
Searching...
No Matches
dwz.c
Go to the documentation of this file.
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
33const char *
34dwz_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
54static void
55locate_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 else if (dwarf2_elf_names.types.matches (sectp->name))
95 {
96 dwz_file->types.s.section = sectp;
97 dwz_file->types.size = bfd_section_size (sectp);
98 }
99}
100
101/* Attempt to find a .dwz file (whose full path is represented by
102 FILENAME) in all of the specified debug file directories provided.
103
104 Return the equivalent gdb_bfd_ref_ptr of the .dwz file found, or
105 nullptr if it could not find anything. */
106
107static gdb_bfd_ref_ptr
108dwz_search_other_debugdirs (std::string &filename, bfd_byte *buildid,
109 size_t buildid_len)
110{
111 /* Let's assume that the path represented by FILENAME has the
112 "/.dwz/" subpath in it. This is what (most) GNU/Linux
113 distributions do, anyway. */
114 size_t dwz_pos = filename.find ("/.dwz/");
115
116 if (dwz_pos == std::string::npos)
117 return nullptr;
118
119 /* This is an obvious assertion, but it's here more to educate
120 future readers of this code that FILENAME at DWZ_POS *must*
121 contain a directory separator. */
122 gdb_assert (IS_DIR_SEPARATOR (filename[dwz_pos]));
123
125 std::vector<gdb::unique_xmalloc_ptr<char>> debugdir_vec
126 = dirnames_to_char_ptr_vec (debug_file_directory.c_str ());
127
128 for (const gdb::unique_xmalloc_ptr<char> &debugdir : debugdir_vec)
129 {
130 /* The idea is to iterate over the
131 debug file directories provided by the user and
132 replace the hard-coded path in the "filename" by each
133 debug-file-directory.
134
135 For example, suppose that filename is:
136
137 /usr/lib/debug/.dwz/foo.dwz
138
139 And suppose that we have "$HOME/bar" as the
140 debug-file-directory. We would then adjust filename
141 to look like:
142
143 $HOME/bar/.dwz/foo.dwz
144
145 which would hopefully allow us to find the alt debug
146 file. */
147 std::string ddir = debugdir.get ();
148
149 if (ddir.empty ())
150 continue;
151
152 /* Make sure the current debug-file-directory ends with a
153 directory separator. This is needed because, if FILENAME
154 contains something like "/usr/lib/abcde/.dwz/foo.dwz" and
155 DDIR is "/usr/lib/abc", then could wrongfully skip it
156 below. */
157 if (!IS_DIR_SEPARATOR (ddir.back ()))
158 ddir += SLASH_STRING;
159
160 /* Check whether the beginning of FILENAME is DDIR. If it is,
161 then we are dealing with a file which we already attempted to
162 open before, so we just skip it and continue processing the
163 remaining debug file directories. */
164 if (filename.size () > ddir.size ()
165 && filename.compare (0, ddir.size (), ddir) == 0)
166 continue;
167
168 /* Replace FILENAME's default debug-file-directory with
169 DDIR. */
170 std::string new_filename = ddir + &filename[dwz_pos + 1];
171
172 dwz_bfd = gdb_bfd_open (new_filename.c_str (), gnutarget);
173
174 if (dwz_bfd == nullptr)
175 continue;
176
177 if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
178 {
179 dwz_bfd.reset (nullptr);
180 continue;
181 }
182
183 /* Found it. */
184 break;
185 }
186
187 return dwz_bfd;
188}
189
190/* See dwz.h. */
191
192struct dwz_file *
193dwarf2_get_dwz_file (dwarf2_per_bfd *per_bfd, bool require)
194{
195 bfd_size_type buildid_len_arg;
196 size_t buildid_len;
197 bfd_byte *buildid;
198
199 if (per_bfd->dwz_file != NULL)
200 return per_bfd->dwz_file.get ();
201
202 bfd_set_error (bfd_error_no_error);
203 gdb::unique_xmalloc_ptr<char> data
204 (bfd_get_alt_debug_link_info (per_bfd->obfd,
205 &buildid_len_arg, &buildid));
206 if (data == NULL)
207 {
208 if (bfd_get_error () == bfd_error_no_error)
209 {
210 if (!require)
211 return nullptr;
212 error (_("could not read '.gnu_debugaltlink' section"));
213 }
214 error (_("could not read '.gnu_debugaltlink' section: %s"),
215 bfd_errmsg (bfd_get_error ()));
216 }
217
218 gdb::unique_xmalloc_ptr<bfd_byte> buildid_holder (buildid);
219
220 buildid_len = (size_t) buildid_len_arg;
221
222 std::string filename = data.get ();
223
224 if (!IS_ABSOLUTE_PATH (filename.c_str ()))
225 {
226 gdb::unique_xmalloc_ptr<char> abs
227 = gdb_realpath (bfd_get_filename (per_bfd->obfd));
228
229 filename = ldirname (abs.get ()) + SLASH_STRING + filename;
230 }
231
232 /* First try the file name given in the section. If that doesn't
233 work, try to use the build-id instead. */
235 if (dwz_bfd != NULL)
236 {
237 if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
238 dwz_bfd.reset (nullptr);
239 }
240
241 if (dwz_bfd == NULL)
242 dwz_bfd = build_id_to_debug_bfd (buildid_len, buildid);
243
244 if (dwz_bfd == nullptr)
245 {
246 /* If the user has provided us with different
247 debug file directories, we can try them in order. */
248 dwz_bfd = dwz_search_other_debugdirs (filename, buildid, buildid_len);
249 }
250
251 if (dwz_bfd == nullptr)
252 {
253 gdb::unique_xmalloc_ptr<char> alt_filename;
254 const char *origname = bfd_get_filename (per_bfd->obfd);
255
256 scoped_fd fd (debuginfod_debuginfo_query (buildid,
257 buildid_len,
258 origname,
259 &alt_filename));
260
261 if (fd.get () >= 0)
262 {
263 /* File successfully retrieved from server. */
264 dwz_bfd = gdb_bfd_open (alt_filename.get (), gnutarget);
265
266 if (dwz_bfd == nullptr)
267 warning (_("File \"%s\" from debuginfod cannot be opened as bfd"),
268 alt_filename.get ());
269 else if (!build_id_verify (dwz_bfd.get (), buildid_len, buildid))
270 dwz_bfd.reset (nullptr);
271 }
272 }
273
274 if (dwz_bfd == NULL)
275 error (_("could not find '.gnu_debugaltlink' file for %s"),
276 bfd_get_filename (per_bfd->obfd));
277
278 std::unique_ptr<struct dwz_file> result
279 (new struct dwz_file (std::move (dwz_bfd)));
280
281 for (asection *sec : gdb_bfd_sections (result->dwz_bfd))
282 locate_dwz_sections (result->dwz_bfd.get (), sec, result.get ());
283
284 gdb_bfd_record_inclusion (per_bfd->obfd, result->dwz_bfd.get ());
285 per_bfd->dwz_file = std::move (result);
286 return per_bfd->dwz_file.get ();
287}
int build_id_verify(bfd *abfd, size_t check_len, const bfd_byte *check)
Definition build-id.c:56
gdb_bfd_ref_ptr build_id_to_debug_bfd(size_t build_id_len, const bfd_byte *build_id)
Definition build-id.c:196
const char * gnutarget
Definition corefile.c:405
scoped_fd debuginfod_debuginfo_query(const unsigned char *build_id, int build_id_len, const char *filename, gdb::unique_xmalloc_ptr< char > *destname)
std::string debug_file_directory
Definition symfile.c:1354
struct dwz_file * dwarf2_get_dwz_file(dwarf2_per_bfd *per_bfd, bool require)
Definition dwz.c:193
static gdb_bfd_ref_ptr dwz_search_other_debugdirs(std::string &filename, bfd_byte *buildid, size_t buildid_len)
Definition dwz.c:108
static void locate_dwz_sections(bfd *abfd, asection *sectp, dwz_file *dwz_file)
Definition dwz.c:55
void gdb_bfd_record_inclusion(bfd *includer, bfd *includee)
Definition gdb_bfd.c:969
gdb_bfd_ref_ptr gdb_bfd_open(const char *name, const char *target, int fd, bool warn_if_slow)
Definition gdb_bfd.c:473
gdb::ref_ptr< struct bfd, gdb_bfd_ref_policy > gdb_bfd_ref_ptr
Definition gdb_bfd.h:79
static gdb_bfd_section_range gdb_bfd_sections(bfd *abfd)
Definition gdb_bfd.h:234
const struct dwarf2_debug_sections dwarf2_elf_names
Definition read.c:175
struct dwarf2_section_names types
Definition sect-names.h:63
struct dwarf2_section_names gdb_index
Definition sect-names.h:67
struct dwarf2_section_names debug_names
Definition sect-names.h:68
struct dwarf2_section_names macro
Definition sect-names.h:57
struct dwarf2_section_names info
Definition sect-names.h:51
struct dwarf2_section_names str
Definition sect-names.h:58
struct dwarf2_section_names abbrev
Definition sect-names.h:52
struct dwarf2_section_names line
Definition sect-names.h:53
bfd * obfd
Definition read.h:462
std::unique_ptr< struct dwz_file > dwz_file
Definition read.h:523
bool matches(const char *name) const
Definition sect-names.h:36
Definition dwz.h:32
const char * read_string(struct objfile *objfile, LONGEST str_offset)
Definition dwz.c:34
const char * filename() const
Definition dwz.h:38
gdb_bfd_ref_ptr dwz_bfd
Definition dwz.h:54
std::string ldirname(const char *filename)
Definition utils.c:3306