/src/elfutils/libdw/dwarf_begin_elf.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Create descriptor from ELF descriptor for processing file. |
2 | | Copyright (C) 2002-2011, 2014, 2015, 2017, 2018 Red Hat, Inc. |
3 | | Copyright (C) 2023, Mark J. Wielaard <mark@klomp.org> |
4 | | This file is part of elfutils. |
5 | | |
6 | | This file is free software; you can redistribute it and/or modify |
7 | | it under the terms of either |
8 | | |
9 | | * the GNU Lesser General Public License as published by the Free |
10 | | Software Foundation; either version 3 of the License, or (at |
11 | | your option) any later version |
12 | | |
13 | | or |
14 | | |
15 | | * the GNU General Public License as published by the Free |
16 | | Software Foundation; either version 2 of the License, or (at |
17 | | your option) any later version |
18 | | |
19 | | or both in parallel, as here. |
20 | | |
21 | | elfutils is distributed in the hope that it will be useful, but |
22 | | WITHOUT ANY WARRANTY; without even the implied warranty of |
23 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
24 | | General Public License for more details. |
25 | | |
26 | | You should have received copies of the GNU General Public License and |
27 | | the GNU Lesser General Public License along with this program. If |
28 | | not, see <http://www.gnu.org/licenses/>. */ |
29 | | |
30 | | #ifdef HAVE_CONFIG_H |
31 | | # include <config.h> |
32 | | #endif |
33 | | |
34 | | #include <system.h> |
35 | | |
36 | | #include <assert.h> |
37 | | #include <stdbool.h> |
38 | | #include <stddef.h> |
39 | | #include <stdlib.h> |
40 | | #include <stdio.h> |
41 | | #include <string.h> |
42 | | #include <sys/types.h> |
43 | | #include <sys/stat.h> |
44 | | #include <fcntl.h> |
45 | | |
46 | | #include "libelfP.h" |
47 | | #include "libdwP.h" |
48 | | |
49 | | |
50 | | /* Section names. (Note .debug_str_offsets is the largest 19 chars.) */ |
51 | | static const char dwarf_scnnames[IDX_last][19] = |
52 | | { |
53 | | [IDX_debug_info] = ".debug_info", |
54 | | [IDX_debug_types] = ".debug_types", |
55 | | [IDX_debug_abbrev] = ".debug_abbrev", |
56 | | [IDX_debug_addr] = ".debug_addr", |
57 | | [IDX_debug_aranges] = ".debug_aranges", |
58 | | [IDX_debug_line] = ".debug_line", |
59 | | [IDX_debug_line_str] = ".debug_line_str", |
60 | | [IDX_debug_frame] = ".debug_frame", |
61 | | [IDX_debug_loc] = ".debug_loc", |
62 | | [IDX_debug_loclists] = ".debug_loclists", |
63 | | [IDX_debug_pubnames] = ".debug_pubnames", |
64 | | [IDX_debug_str] = ".debug_str", |
65 | | [IDX_debug_str_offsets] = ".debug_str_offsets", |
66 | | [IDX_debug_macinfo] = ".debug_macinfo", |
67 | | [IDX_debug_macro] = ".debug_macro", |
68 | | [IDX_debug_ranges] = ".debug_ranges", |
69 | | [IDX_debug_rnglists] = ".debug_rnglists", |
70 | | [IDX_debug_cu_index] = ".debug_cu_index", |
71 | | [IDX_debug_tu_index] = ".debug_tu_index", |
72 | | [IDX_gnu_debugaltlink] = ".gnu_debugaltlink" |
73 | | }; |
74 | 1.64M | #define ndwarf_scnnames (sizeof (dwarf_scnnames) / sizeof (dwarf_scnnames[0])) |
75 | | |
76 | | /* Map from section index to string section index. |
77 | | Non-string sections should have STR_SCN_IDX_last. */ |
78 | | static const enum string_section_index scn_to_string_section_idx[IDX_last] = |
79 | | { |
80 | | [IDX_debug_info] = STR_SCN_IDX_last, |
81 | | [IDX_debug_types] = STR_SCN_IDX_last, |
82 | | [IDX_debug_abbrev] = STR_SCN_IDX_last, |
83 | | [IDX_debug_addr] = STR_SCN_IDX_last, |
84 | | [IDX_debug_aranges] = STR_SCN_IDX_last, |
85 | | [IDX_debug_line] = STR_SCN_IDX_last, |
86 | | [IDX_debug_line_str] = STR_SCN_IDX_debug_line_str, |
87 | | [IDX_debug_frame] = STR_SCN_IDX_last, |
88 | | [IDX_debug_loc] = STR_SCN_IDX_last, |
89 | | [IDX_debug_loclists] = STR_SCN_IDX_last, |
90 | | [IDX_debug_pubnames] = STR_SCN_IDX_last, |
91 | | [IDX_debug_str] = STR_SCN_IDX_debug_str, |
92 | | [IDX_debug_str_offsets] = STR_SCN_IDX_last, |
93 | | [IDX_debug_macinfo] = STR_SCN_IDX_last, |
94 | | [IDX_debug_macro] = STR_SCN_IDX_last, |
95 | | [IDX_debug_ranges] = STR_SCN_IDX_last, |
96 | | [IDX_debug_rnglists] = STR_SCN_IDX_last, |
97 | | [IDX_debug_cu_index] = STR_SCN_IDX_last, |
98 | | [IDX_debug_tu_index] = STR_SCN_IDX_last, |
99 | | [IDX_gnu_debugaltlink] = STR_SCN_IDX_last |
100 | | }; |
101 | | |
102 | | static enum dwarf_type |
103 | | scn_dwarf_type (Dwarf *result, size_t shstrndx, Elf_Scn *scn) |
104 | 1.69M | { |
105 | 1.69M | GElf_Shdr shdr_mem; |
106 | 1.69M | GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); |
107 | 1.69M | if (shdr == NULL) |
108 | 0 | return TYPE_UNKNOWN; |
109 | | |
110 | 1.69M | const char *scnname = elf_strptr (result->elf, shstrndx, |
111 | 1.69M | shdr->sh_name); |
112 | 1.69M | if (scnname != NULL) |
113 | 30.6k | { |
114 | 30.6k | if (startswith (scnname, ".gnu.debuglto_.debug")) |
115 | 7.17k | return TYPE_GNU_LTO; |
116 | 23.4k | else if (strcmp (scnname, ".debug_cu_index") == 0 |
117 | 23.4k | || strcmp (scnname, ".debug_tu_index") == 0 |
118 | 23.4k | || strcmp (scnname, ".zdebug_cu_index") == 0 |
119 | 23.4k | || strcmp (scnname, ".zdebug_tu_index") == 0) |
120 | 2.98k | return TYPE_DWO; |
121 | 20.4k | else if (startswith (scnname, ".debug_") || startswith (scnname, ".zdebug_")) |
122 | 9.18k | { |
123 | 9.18k | size_t len = strlen (scnname); |
124 | 9.18k | if (strcmp (scnname + len - 4, ".dwo") == 0) |
125 | 7.75k | return TYPE_DWO; |
126 | 1.43k | else |
127 | 1.43k | return TYPE_PLAIN; |
128 | 9.18k | } |
129 | 30.6k | } |
130 | 1.67M | return TYPE_UNKNOWN; |
131 | 1.69M | } |
132 | | static Dwarf * |
133 | | check_section (Dwarf *result, size_t shstrndx, Elf_Scn *scn, bool inscngrp) |
134 | 508k | { |
135 | 508k | GElf_Shdr shdr_mem; |
136 | 508k | GElf_Shdr *shdr; |
137 | | |
138 | | /* Get the section header data. */ |
139 | 508k | shdr = gelf_getshdr (scn, &shdr_mem); |
140 | 508k | if (shdr == NULL) |
141 | | /* We may read /proc/PID/mem with only program headers mapped and section |
142 | | headers out of the mapped pages. */ |
143 | 0 | goto err; |
144 | | |
145 | | /* Ignore any SHT_NOBITS sections. Debugging sections should not |
146 | | have been stripped, but in case of a corrupt file we won't try |
147 | | to look at the missing data. */ |
148 | 508k | if (unlikely (shdr->sh_type == SHT_NOBITS)) |
149 | 3.27k | return result; |
150 | | |
151 | | /* Make sure the section is part of a section group only iff we |
152 | | really need it. If we are looking for the global (= non-section |
153 | | group debug info) we have to ignore all the info in section |
154 | | groups. If we are looking into a section group we cannot look at |
155 | | a section which isn't part of the section group. */ |
156 | 504k | if (! inscngrp && (shdr->sh_flags & SHF_GROUP) != 0) |
157 | | /* Ignore the section. */ |
158 | 374k | return result; |
159 | | |
160 | | |
161 | | /* We recognize the DWARF section by their names. This is not very |
162 | | safe and stable but the best we can do. */ |
163 | 130k | const char *scnname = elf_strptr (result->elf, shstrndx, |
164 | 130k | shdr->sh_name); |
165 | 130k | if (scnname == NULL) |
166 | 1.59k | { |
167 | | /* The section name must be valid. Otherwise is the ELF file |
168 | | invalid. */ |
169 | 1.69k | err: |
170 | 1.69k | Dwarf_Sig8_Hash_free (&result->sig8_hash); |
171 | 1.69k | __libdw_seterrno (DWARF_E_INVALID_ELF); |
172 | 1.69k | free (result); |
173 | 1.69k | return NULL; |
174 | 1.59k | } |
175 | | |
176 | | /* Recognize the various sections. Most names start with .debug_. |
177 | | They might be compressed (and start with .z). Or end with .dwo |
178 | | for split dwarf sections. Or start with .gnu.debuglto_ for |
179 | | LTO debug sections. We should only use one consistent set at |
180 | | a time. We prefer PLAIN over DWO over LTO. */ |
181 | 128k | size_t cnt; |
182 | 128k | bool gnu_compressed = false; |
183 | 1.51M | for (cnt = 0; cnt < ndwarf_scnnames; ++cnt) |
184 | 1.45M | { |
185 | | /* .debug_cu_index and .debug_tu_index don't have a .dwo suffix, |
186 | | but they are for DWO. */ |
187 | 1.45M | if (result->type != TYPE_DWO |
188 | 1.45M | && (cnt == IDX_debug_cu_index || cnt == IDX_debug_tu_index)) |
189 | 121k | continue; |
190 | 1.33M | bool need_dot_dwo = |
191 | 1.33M | (result->type == TYPE_DWO |
192 | 1.33M | && cnt != IDX_debug_cu_index |
193 | 1.33M | && cnt != IDX_debug_tu_index); |
194 | 1.33M | size_t dbglen = strlen (dwarf_scnnames[cnt]); |
195 | 1.33M | size_t scnlen = strlen (scnname); |
196 | 1.33M | if (strncmp (scnname, dwarf_scnnames[cnt], dbglen) == 0 |
197 | 1.33M | && ((!need_dot_dwo && dbglen == scnlen) |
198 | 3.59k | || (need_dot_dwo |
199 | 1.52k | && scnlen == dbglen + 4 |
200 | 1.52k | && strstr (scnname, ".dwo") == scnname + dbglen))) |
201 | 2.72k | break; |
202 | 1.33M | else if (scnname[0] == '.' && scnname[1] == 'z' |
203 | 1.33M | && (strncmp (&scnname[2], &dwarf_scnnames[cnt][1], |
204 | 218k | dbglen - 1) == 0 |
205 | 218k | && ((!need_dot_dwo && scnlen == dbglen + 1) |
206 | 70.1k | || (need_dot_dwo |
207 | 8.76k | && scnlen == dbglen + 5 |
208 | 8.76k | && strstr (scnname, |
209 | 2.32k | ".dwo") == scnname + dbglen + 1)))) |
210 | 63.4k | { |
211 | 63.4k | gnu_compressed = true; |
212 | 63.4k | break; |
213 | 63.4k | } |
214 | 1.26M | else if (scnlen > 14 /* .gnu.debuglto_ prefix. */ |
215 | 1.26M | && startswith (scnname, ".gnu.debuglto_") |
216 | 1.26M | && strcmp (&scnname[14], dwarf_scnnames[cnt]) == 0) |
217 | 599 | { |
218 | 599 | if (result->type == TYPE_GNU_LTO) |
219 | 321 | break; |
220 | 599 | } |
221 | 1.33M | } |
222 | | |
223 | 128k | if (cnt >= ndwarf_scnnames) |
224 | | /* Not a debug section; ignore it. */ |
225 | 61.9k | return result; |
226 | | |
227 | 66.5k | if (unlikely (result->sectiondata[cnt] != NULL)) |
228 | | /* A section appears twice. That's bad. We ignore the section. */ |
229 | 53.5k | return result; |
230 | | |
231 | | /* We cannot know whether or not a GNU compressed section has already |
232 | | been uncompressed or not, so ignore any errors. */ |
233 | 12.9k | if (gnu_compressed) |
234 | 10.2k | elf_compress_gnu (scn, 0, 0); |
235 | | |
236 | 12.9k | if ((shdr->sh_flags & SHF_COMPRESSED) != 0) |
237 | 4.91k | { |
238 | 4.91k | if (elf_compress (scn, 0, 0) < 0) |
239 | 4.08k | { |
240 | | /* It would be nice if we could fail with a specific error. |
241 | | But we don't know if this was an essential section or not. |
242 | | So just continue for now. See also valid_p(). */ |
243 | 4.08k | return result; |
244 | 4.08k | } |
245 | 4.91k | } |
246 | | |
247 | | /* Get the section data. Should be raw bytes, no conversion needed. */ |
248 | 8.85k | Elf_Data *data = elf_rawdata (scn, NULL); |
249 | 8.85k | if (data == NULL) |
250 | 96 | goto err; |
251 | | |
252 | 8.75k | if (data->d_buf == NULL || data->d_size == 0) |
253 | | /* No data actually available, ignore it. */ |
254 | 7.88k | return result; |
255 | | |
256 | | /* We can now read the section data into results. */ |
257 | 875 | result->sectiondata[cnt] = data; |
258 | | |
259 | | /* If the section contains string data, we want to know a size of a prefix |
260 | | where any string will be null-terminated. */ |
261 | 875 | enum string_section_index string_section_idx = scn_to_string_section_idx[cnt]; |
262 | 875 | if (string_section_idx < STR_SCN_IDX_last) |
263 | 133 | { |
264 | 133 | size_t size = data->d_size; |
265 | | /* Reduce the size by the number of non-zero bytes at the end of the |
266 | | section. */ |
267 | 2.66M | while (size > 0 && *((const char *) data->d_buf + size - 1) != '\0') |
268 | 2.66M | --size; |
269 | 133 | result->string_section_size[string_section_idx] = size; |
270 | 133 | } |
271 | | |
272 | 875 | return result; |
273 | 8.75k | } |
274 | | |
275 | | char * |
276 | | __libdw_elfpath (int fd) |
277 | 15.2k | { |
278 | | /* strlen ("/proc/self/fd/") = 14 + strlen (<MAXINT>) = 10 + 1 = 25. */ |
279 | 15.2k | char devfdpath[25]; |
280 | 15.2k | sprintf (devfdpath, "/proc/self/fd/%u", fd); |
281 | 15.2k | return realpath (devfdpath, NULL); |
282 | 15.2k | } |
283 | | |
284 | | |
285 | | void |
286 | | __libdw_set_debugdir (Dwarf *dbg) |
287 | 211 | { |
288 | 211 | if (dbg->elfpath == NULL || dbg->elfpath[0] != '/') |
289 | 114 | return; |
290 | 97 | size_t dirlen = strrchr (dbg->elfpath, '/') - dbg->elfpath + 1; |
291 | 97 | dbg->debugdir = malloc (dirlen + 1); |
292 | 97 | if (dbg->debugdir == NULL) |
293 | 0 | return; |
294 | 97 | memcpy (dbg->debugdir, dbg->elfpath, dirlen); |
295 | 97 | dbg->debugdir[dirlen] = '\0'; |
296 | 97 | } |
297 | | |
298 | | |
299 | | /* Check whether all the necessary DWARF information is available. */ |
300 | | static Dwarf * |
301 | | valid_p (Dwarf *result) |
302 | 5.69k | { |
303 | | /* We looked at all the sections. Now determine whether all the |
304 | | sections with debugging information we need are there. |
305 | | |
306 | | Require at least one section that can be read "standalone". */ |
307 | 5.69k | if (likely (result != NULL) |
308 | 5.69k | && unlikely (result->sectiondata[IDX_debug_info] == NULL |
309 | 5.69k | && result->sectiondata[IDX_debug_line] == NULL |
310 | 5.69k | && result->sectiondata[IDX_debug_frame] == NULL)) |
311 | 3.88k | { |
312 | 3.88k | Dwarf_Sig8_Hash_free (&result->sig8_hash); |
313 | 3.88k | __libdw_seterrno (DWARF_E_NO_DWARF); |
314 | 3.88k | free (result); |
315 | 3.88k | result = NULL; |
316 | 3.88k | } |
317 | | |
318 | | /* We are setting up some "fake" CUs, which need an address size. |
319 | | Check the ELF class to come up with something reasonable. */ |
320 | 5.69k | int elf_addr_size = 8; |
321 | 5.69k | if (result != NULL) |
322 | 114 | { |
323 | 114 | GElf_Ehdr ehdr; |
324 | 114 | if (gelf_getehdr (result->elf, &ehdr) == NULL) |
325 | 0 | { |
326 | 0 | Dwarf_Sig8_Hash_free (&result->sig8_hash); |
327 | 0 | __libdw_seterrno (DWARF_E_INVALID_ELF); |
328 | 0 | free (result); |
329 | 0 | result = NULL; |
330 | 0 | } |
331 | 114 | else if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) |
332 | 45 | elf_addr_size = 4; |
333 | 114 | } |
334 | | |
335 | | /* For dwarf_location_attr () we need a "fake" CU to indicate |
336 | | where the "fake" attribute data comes from. This is a block |
337 | | inside the .debug_loc or .debug_loclists section. */ |
338 | 5.69k | if (result != NULL && result->sectiondata[IDX_debug_loc] != NULL) |
339 | 2 | { |
340 | 2 | result->fake_loc_cu = malloc (sizeof (Dwarf_CU)); |
341 | 2 | if (unlikely (result->fake_loc_cu == NULL)) |
342 | 0 | { |
343 | 0 | Dwarf_Sig8_Hash_free (&result->sig8_hash); |
344 | 0 | __libdw_seterrno (DWARF_E_NOMEM); |
345 | 0 | free (result); |
346 | 0 | result = NULL; |
347 | 0 | } |
348 | 2 | else |
349 | 2 | { |
350 | 2 | result->fake_loc_cu->sec_idx = IDX_debug_loc; |
351 | 2 | result->fake_loc_cu->dbg = result; |
352 | 2 | result->fake_loc_cu->startp |
353 | 2 | = result->sectiondata[IDX_debug_loc]->d_buf; |
354 | 2 | result->fake_loc_cu->endp |
355 | 2 | = (result->sectiondata[IDX_debug_loc]->d_buf |
356 | 2 | + result->sectiondata[IDX_debug_loc]->d_size); |
357 | 2 | result->fake_loc_cu->address_size = elf_addr_size; |
358 | 2 | result->fake_loc_cu->offset_size = 4; |
359 | 2 | result->fake_loc_cu->version = 4; |
360 | 2 | result->fake_loc_cu->split = NULL; |
361 | 2 | eu_search_tree_init (&result->fake_loc_cu->locs_tree); |
362 | 2 | rwlock_init (result->fake_loc_cu->abbrev_lock); |
363 | 2 | rwlock_init (result->fake_loc_cu->split_lock); |
364 | 2 | mutex_init (result->fake_loc_cu->src_lock); |
365 | 2 | mutex_init (result->fake_loc_cu->str_off_base_lock); |
366 | 2 | mutex_init (result->fake_loc_cu->intern_lock); |
367 | 2 | } |
368 | 2 | } |
369 | | |
370 | 5.69k | if (result != NULL && result->sectiondata[IDX_debug_loclists] != NULL) |
371 | 2 | { |
372 | 2 | result->fake_loclists_cu = malloc (sizeof (Dwarf_CU)); |
373 | 2 | if (unlikely (result->fake_loclists_cu == NULL)) |
374 | 0 | { |
375 | 0 | Dwarf_Sig8_Hash_free (&result->sig8_hash); |
376 | 0 | __libdw_seterrno (DWARF_E_NOMEM); |
377 | 0 | free (result->fake_loc_cu); |
378 | 0 | free (result); |
379 | 0 | result = NULL; |
380 | 0 | } |
381 | 2 | else |
382 | 2 | { |
383 | 2 | result->fake_loclists_cu->sec_idx = IDX_debug_loclists; |
384 | 2 | result->fake_loclists_cu->dbg = result; |
385 | 2 | result->fake_loclists_cu->startp |
386 | 2 | = result->sectiondata[IDX_debug_loclists]->d_buf; |
387 | 2 | result->fake_loclists_cu->endp |
388 | 2 | = (result->sectiondata[IDX_debug_loclists]->d_buf |
389 | 2 | + result->sectiondata[IDX_debug_loclists]->d_size); |
390 | 2 | result->fake_loclists_cu->address_size = elf_addr_size; |
391 | 2 | result->fake_loclists_cu->offset_size = 4; |
392 | 2 | result->fake_loclists_cu->version = 5; |
393 | 2 | result->fake_loclists_cu->split = NULL; |
394 | 2 | eu_search_tree_init (&result->fake_loclists_cu->locs_tree); |
395 | 2 | rwlock_init (result->fake_loclists_cu->abbrev_lock); |
396 | 2 | rwlock_init (result->fake_loclists_cu->split_lock); |
397 | 2 | mutex_init (result->fake_loclists_cu->src_lock); |
398 | 2 | mutex_init (result->fake_loclists_cu->str_off_base_lock); |
399 | 2 | mutex_init (result->fake_loclists_cu->intern_lock); |
400 | 2 | } |
401 | 2 | } |
402 | | |
403 | | /* For DW_OP_constx/GNU_const_index and DW_OP_addrx/GNU_addr_index |
404 | | the dwarf_location_attr () will need a "fake" address CU to |
405 | | indicate where the attribute data comes from. This is a just |
406 | | inside the .debug_addr section, if it exists. */ |
407 | 5.69k | if (result != NULL && result->sectiondata[IDX_debug_addr] != NULL) |
408 | 5 | { |
409 | 5 | result->fake_addr_cu = malloc (sizeof (Dwarf_CU)); |
410 | 5 | if (unlikely (result->fake_addr_cu == NULL)) |
411 | 0 | { |
412 | 0 | Dwarf_Sig8_Hash_free (&result->sig8_hash); |
413 | 0 | __libdw_seterrno (DWARF_E_NOMEM); |
414 | 0 | free (result->fake_loc_cu); |
415 | 0 | free (result->fake_loclists_cu); |
416 | 0 | free (result); |
417 | 0 | result = NULL; |
418 | 0 | } |
419 | 5 | else |
420 | 5 | { |
421 | 5 | result->fake_addr_cu->sec_idx = IDX_debug_addr; |
422 | 5 | result->fake_addr_cu->dbg = result; |
423 | 5 | result->fake_addr_cu->startp |
424 | 5 | = result->sectiondata[IDX_debug_addr]->d_buf; |
425 | 5 | result->fake_addr_cu->endp |
426 | 5 | = (result->sectiondata[IDX_debug_addr]->d_buf |
427 | 5 | + result->sectiondata[IDX_debug_addr]->d_size); |
428 | 5 | result->fake_addr_cu->address_size = elf_addr_size; |
429 | 5 | result->fake_addr_cu->offset_size = 4; |
430 | 5 | result->fake_addr_cu->version = 5; |
431 | 5 | result->fake_addr_cu->split = NULL; |
432 | 5 | eu_search_tree_init (&result->fake_addr_cu->locs_tree); |
433 | 5 | rwlock_init (result->fake_addr_cu->abbrev_lock); |
434 | 5 | rwlock_init (result->fake_addr_cu->split_lock); |
435 | 5 | mutex_init (result->fake_addr_cu->src_lock); |
436 | 5 | mutex_init (result->fake_addr_cu->str_off_base_lock); |
437 | 5 | mutex_init (result->fake_addr_cu->intern_lock); |
438 | 5 | } |
439 | 5 | } |
440 | | |
441 | 5.69k | if (result != NULL) |
442 | 114 | { |
443 | 114 | result->elfpath = __libdw_elfpath (result->elf->fildes); |
444 | 114 | __libdw_set_debugdir(result); |
445 | 114 | } |
446 | | |
447 | 5.69k | return result; |
448 | 5.69k | } |
449 | | |
450 | | |
451 | | static Dwarf * |
452 | | global_read (Dwarf *result, Elf *elf, size_t shstrndx) |
453 | 5.69k | { |
454 | 5.69k | Elf_Scn *scn = NULL; |
455 | | |
456 | | /* First check the type (PLAIN, DWO, LTO) we are looking for. We |
457 | | prefer PLAIN if available over DWO, over LTO. */ |
458 | 1.69M | while ((scn = elf_nextscn (elf, scn)) != NULL && result->type != TYPE_PLAIN) |
459 | 1.69M | { |
460 | 1.69M | enum dwarf_type type = scn_dwarf_type (result, shstrndx, scn); |
461 | 1.69M | if (type > result->type) |
462 | 1.84k | result->type = type; |
463 | 1.69M | } |
464 | | |
465 | 5.69k | scn = NULL; |
466 | 513k | while (result != NULL && (scn = elf_nextscn (elf, scn)) != NULL) |
467 | 508k | result = check_section (result, shstrndx, scn, false); |
468 | | |
469 | 5.69k | return valid_p (result); |
470 | 5.69k | } |
471 | | |
472 | | |
473 | | static Dwarf * |
474 | | scngrp_read (Dwarf *result, Elf *elf, size_t shstrndx, Elf_Scn *scngrp) |
475 | 0 | { |
476 | 0 | GElf_Shdr shdr_mem; |
477 | 0 | GElf_Shdr *shdr = gelf_getshdr (scngrp, &shdr_mem); |
478 | 0 | if (shdr == NULL) |
479 | 0 | { |
480 | 0 | Dwarf_Sig8_Hash_free (&result->sig8_hash); |
481 | 0 | __libdw_seterrno (DWARF_E_INVALID_ELF); |
482 | 0 | free (result); |
483 | 0 | return NULL; |
484 | 0 | } |
485 | | |
486 | 0 | if ((shdr->sh_flags & SHF_COMPRESSED) != 0 |
487 | 0 | && elf_compress (scngrp, 0, 0) < 0) |
488 | 0 | { |
489 | 0 | Dwarf_Sig8_Hash_free (&result->sig8_hash); |
490 | 0 | __libdw_seterrno (DWARF_E_COMPRESSED_ERROR); |
491 | 0 | free (result); |
492 | 0 | return NULL; |
493 | 0 | } |
494 | | |
495 | | /* SCNGRP is the section descriptor for a section group which might |
496 | | contain debug sections. */ |
497 | 0 | Elf_Data *data = elf_getdata (scngrp, NULL); |
498 | 0 | if (data == NULL) |
499 | 0 | { |
500 | | /* We cannot read the section content. Fail! */ |
501 | 0 | Dwarf_Sig8_Hash_free (&result->sig8_hash); |
502 | 0 | free (result); |
503 | 0 | return NULL; |
504 | 0 | } |
505 | | |
506 | | /* The content of the section is a number of 32-bit words which |
507 | | represent section indices. The first word is a flag word. */ |
508 | 0 | Elf32_Word *scnidx = (Elf32_Word *) data->d_buf; |
509 | 0 | size_t cnt; |
510 | | |
511 | | /* First check the type (PLAIN, DWO, LTO) we are looking for. We |
512 | | prefer PLAIN if available over DWO, over LTO. */ |
513 | 0 | for (cnt = 1; cnt * sizeof (Elf32_Word) <= data->d_size; ++cnt) |
514 | 0 | { |
515 | 0 | Elf_Scn *scn = elf_getscn (elf, scnidx[cnt]); |
516 | 0 | if (scn == NULL) |
517 | 0 | { |
518 | | /* A section group refers to a non-existing section. Should |
519 | | never happen. */ |
520 | 0 | Dwarf_Sig8_Hash_free (&result->sig8_hash); |
521 | 0 | __libdw_seterrno (DWARF_E_INVALID_ELF); |
522 | 0 | free (result); |
523 | 0 | return NULL; |
524 | 0 | } |
525 | | |
526 | 0 | enum dwarf_type type = scn_dwarf_type (result, shstrndx, scn); |
527 | 0 | if (type > result->type) |
528 | 0 | result->type = type; |
529 | 0 | } |
530 | | |
531 | 0 | for (cnt = 1; cnt * sizeof (Elf32_Word) <= data->d_size && result != NULL; ++cnt) |
532 | 0 | { |
533 | 0 | Elf_Scn *scn = elf_getscn (elf, scnidx[cnt]); |
534 | 0 | assert (scn != NULL); // checked above |
535 | 0 | result = check_section (result, shstrndx, scn, true); |
536 | 0 | if (result == NULL) |
537 | 0 | break; |
538 | 0 | } |
539 | | |
540 | 0 | return valid_p (result); |
541 | 0 | } |
542 | | |
543 | | |
544 | | Dwarf * |
545 | | dwarf_begin_elf (Elf *elf, Dwarf_Cmd cmd, Elf_Scn *scngrp) |
546 | 5.73k | { |
547 | 5.73k | GElf_Ehdr *ehdr; |
548 | 5.73k | GElf_Ehdr ehdr_mem; |
549 | | |
550 | | /* Get the ELF header of the file. We need various pieces of |
551 | | information from it. */ |
552 | 5.73k | ehdr = gelf_getehdr (elf, &ehdr_mem); |
553 | 5.73k | if (ehdr == NULL) |
554 | 0 | { |
555 | 0 | if (elf_kind (elf) != ELF_K_ELF) |
556 | 0 | __libdw_seterrno (DWARF_E_NOELF); |
557 | 0 | else |
558 | 0 | __libdw_seterrno (DWARF_E_GETEHDR_ERROR); |
559 | |
|
560 | 0 | return NULL; |
561 | 0 | } |
562 | | |
563 | | |
564 | | /* Default memory allocation size. */ |
565 | 5.73k | size_t mem_default_size = sysconf (_SC_PAGESIZE) - 4 * sizeof (void *); |
566 | 5.73k | assert (sizeof (struct Dwarf) < mem_default_size); |
567 | | |
568 | | /* Allocate the data structure. */ |
569 | 5.73k | Dwarf *result = calloc (1, sizeof (Dwarf)); |
570 | 5.73k | if (unlikely (result == NULL) |
571 | 5.73k | || unlikely (Dwarf_Sig8_Hash_init (&result->sig8_hash, 11) < 0)) |
572 | 0 | { |
573 | 0 | free (result); |
574 | 0 | __libdw_seterrno (DWARF_E_NOMEM); |
575 | 0 | return NULL; |
576 | 0 | } |
577 | | |
578 | | /* Fill in some values. */ |
579 | 5.73k | if ((BYTE_ORDER == LITTLE_ENDIAN && ehdr->e_ident[EI_DATA] == ELFDATA2MSB) |
580 | 5.73k | || (BYTE_ORDER == BIG_ENDIAN && ehdr->e_ident[EI_DATA] == ELFDATA2LSB)) |
581 | 2.05k | result->other_byte_order = true; |
582 | | |
583 | 5.73k | result->elf = elf; |
584 | 5.73k | result->alt_fd = -1; |
585 | 5.73k | result->dwp_fd = -1; |
586 | | |
587 | | /* Initialize the memory handling. Initial blocks are allocated on first |
588 | | actual allocation. */ |
589 | 5.73k | result->mem_default_size = mem_default_size; |
590 | 5.73k | result->oom_handler = __libdw_oom; |
591 | 5.73k | if (pthread_rwlock_init(&result->mem_rwl, NULL) != 0) |
592 | 0 | { |
593 | 0 | free (result); |
594 | 0 | __libdw_seterrno (DWARF_E_NOMEM); /* no memory. */ |
595 | 0 | return NULL; |
596 | 0 | } |
597 | 5.73k | mutex_init (result->dwarf_lock); |
598 | 5.73k | mutex_init (result->macro_lock); |
599 | 5.73k | eu_search_tree_init (&result->cu_tree); |
600 | 5.73k | eu_search_tree_init (&result->tu_tree); |
601 | 5.73k | eu_search_tree_init (&result->split_tree); |
602 | 5.73k | eu_search_tree_init (&result->macro_ops_tree); |
603 | 5.73k | eu_search_tree_init (&result->files_lines_tree); |
604 | | |
605 | 5.73k | result->mem_stacks = 0; |
606 | 5.73k | result->mem_tails = NULL; |
607 | | |
608 | 5.73k | if (cmd == DWARF_C_READ || cmd == DWARF_C_RDWR) |
609 | 5.73k | { |
610 | | /* All sections are recognized by name, so pass the section header |
611 | | string index along to easily get the section names. */ |
612 | 5.73k | size_t shstrndx; |
613 | 5.73k | if (elf_getshdrstrndx (elf, &shstrndx) != 0) |
614 | 46 | { |
615 | 46 | Dwarf_Sig8_Hash_free (&result->sig8_hash); |
616 | 46 | __libdw_seterrno (DWARF_E_INVALID_ELF); |
617 | 46 | free (result); |
618 | 46 | return NULL; |
619 | 46 | } |
620 | | |
621 | | /* If the caller provides a section group we get the DWARF |
622 | | sections only from this section group. Otherwise we search |
623 | | for the first section with the required name. Further |
624 | | sections with the name are ignored. The DWARF specification |
625 | | does not really say this is allowed. */ |
626 | 5.69k | if (scngrp == NULL) |
627 | 5.69k | return global_read (result, elf, shstrndx); |
628 | 0 | else |
629 | 0 | return scngrp_read (result, elf, shstrndx, scngrp); |
630 | 5.69k | } |
631 | 0 | else if (cmd == DWARF_C_WRITE) |
632 | 0 | { |
633 | 0 | Dwarf_Sig8_Hash_free (&result->sig8_hash); |
634 | 0 | __libdw_seterrno (DWARF_E_UNIMPL); |
635 | 0 | free (result); |
636 | 0 | return NULL; |
637 | 0 | } |
638 | | |
639 | 0 | Dwarf_Sig8_Hash_free (&result->sig8_hash); |
640 | 0 | __libdw_seterrno (DWARF_E_INVALID_CMD); |
641 | 0 | free (result); |
642 | 0 | return NULL; |
643 | 5.73k | } |
644 | | INTDEF(dwarf_begin_elf) |