1 /* DWARF DWZ handling for GDB.
3 Copyright (C) 2003-2022 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
21 #include "dwarf2/dwz.h"
24 #include "debuginfod-support.h"
25 #include "dwarf2/read.h"
26 #include "dwarf2/sect-names.h"
27 #include "filenames.h"
30 #include "gdbsupport/pathstuff.h"
31 #include "gdbsupport/scoped_fd.h"
34 dwz_file::read_string (struct objfile
*objfile
, LONGEST str_offset
)
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')
49 return (const char *) (str
.buffer
+ str_offset
);
52 /* A helper function to find the sections for a .dwz file. */
55 locate_dwz_sections (bfd
*abfd
, asection
*sectp
, dwz_file
*dwz_file
)
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
))
61 dwz_file
->abbrev
.s
.section
= sectp
;
62 dwz_file
->abbrev
.size
= bfd_section_size (sectp
);
64 else if (dwarf2_elf_names
.info
.matches (sectp
->name
))
66 dwz_file
->info
.s
.section
= sectp
;
67 dwz_file
->info
.size
= bfd_section_size (sectp
);
69 else if (dwarf2_elf_names
.str
.matches (sectp
->name
))
71 dwz_file
->str
.s
.section
= sectp
;
72 dwz_file
->str
.size
= bfd_section_size (sectp
);
74 else if (dwarf2_elf_names
.line
.matches (sectp
->name
))
76 dwz_file
->line
.s
.section
= sectp
;
77 dwz_file
->line
.size
= bfd_section_size (sectp
);
79 else if (dwarf2_elf_names
.macro
.matches (sectp
->name
))
81 dwz_file
->macro
.s
.section
= sectp
;
82 dwz_file
->macro
.size
= bfd_section_size (sectp
);
84 else if (dwarf2_elf_names
.gdb_index
.matches (sectp
->name
))
86 dwz_file
->gdb_index
.s
.section
= sectp
;
87 dwz_file
->gdb_index
.size
= bfd_section_size (sectp
);
89 else if (dwarf2_elf_names
.debug_names
.matches (sectp
->name
))
91 dwz_file
->debug_names
.s
.section
= sectp
;
92 dwz_file
->debug_names
.size
= bfd_section_size (sectp
);
96 /* Attempt to find a .dwz file (whose full path is represented by
97 FILENAME) in all of the specified debug file directories provided.
99 Return the equivalent gdb_bfd_ref_ptr of the .dwz file found, or
100 nullptr if it could not find anything. */
102 static gdb_bfd_ref_ptr
103 dwz_search_other_debugdirs (std::string
&filename
, bfd_byte
*buildid
,
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/");
111 if (dwz_pos
== std::string::npos
)
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
]));
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 ());
123 for (const gdb::unique_xmalloc_ptr
<char> &debugdir
: debugdir_vec
)
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.
130 For example, suppose that filename is:
132 /usr/lib/debug/.dwz/foo.dwz
134 And suppose that we have "$HOME/bar" as the
135 debug-file-directory. We would then adjust filename
138 $HOME/bar/.dwz/foo.dwz
140 which would hopefully allow us to find the alt debug
142 std::string ddir
= debugdir
.get ();
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
152 if (!IS_DIR_SEPARATOR (ddir
.back ()))
153 ddir
+= SLASH_STRING
;
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)
163 /* Replace FILENAME's default debug-file-directory with
165 std::string new_filename
= ddir
+ &filename
[dwz_pos
+ 1];
167 dwz_bfd
= gdb_bfd_open (new_filename
.c_str (), gnutarget
);
169 if (dwz_bfd
== nullptr)
172 if (!build_id_verify (dwz_bfd
.get (), buildid_len
, buildid
))
174 dwz_bfd
.reset (nullptr);
188 dwarf2_get_dwz_file (dwarf2_per_bfd
*per_bfd
, bool require
)
190 bfd_size_type buildid_len_arg
;
194 if (per_bfd
->dwz_file
!= NULL
)
195 return per_bfd
->dwz_file
.get ();
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
));
203 if (bfd_get_error () == bfd_error_no_error
)
207 error (_("could not read '.gnu_debugaltlink' section"));
209 error (_("could not read '.gnu_debugaltlink' section: %s"),
210 bfd_errmsg (bfd_get_error ()));
213 gdb::unique_xmalloc_ptr
<bfd_byte
> buildid_holder (buildid
);
215 buildid_len
= (size_t) buildid_len_arg
;
217 std::string filename
= data
.get ();
219 if (!IS_ABSOLUTE_PATH (filename
.c_str ()))
221 gdb::unique_xmalloc_ptr
<char> abs
222 = gdb_realpath (bfd_get_filename (per_bfd
->obfd
));
224 filename
= ldirname (abs
.get ()) + SLASH_STRING
+ filename
;
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
));
232 if (!build_id_verify (dwz_bfd
.get (), buildid_len
, buildid
))
233 dwz_bfd
.reset (nullptr);
237 dwz_bfd
= build_id_to_debug_bfd (buildid_len
, buildid
);
239 if (dwz_bfd
== nullptr)
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
);
246 if (dwz_bfd
== nullptr)
248 gdb::unique_xmalloc_ptr
<char> alt_filename
;
249 const char *origname
= bfd_get_filename (per_bfd
->obfd
);
251 scoped_fd
fd (debuginfod_debuginfo_query (buildid
,
258 /* File successfully retrieved from server. */
259 dwz_bfd
= gdb_bfd_open (alt_filename
.get (), gnutarget
);
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);
270 error (_("could not find '.gnu_debugaltlink' file for %s"),
271 bfd_get_filename (per_bfd
->obfd
));
273 std::unique_ptr
<struct dwz_file
> result
274 (new struct dwz_file (std::move (dwz_bfd
)));
276 for (asection
*sec
: gdb_bfd_sections (result
->dwz_bfd
))
277 locate_dwz_sections (result
->dwz_bfd
.get (), sec
, result
.get ());
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 ();