Branch data Line data Source code
1 : : /* Read DWARF package file index sections.
2 : : Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
3 : : This file is part of elfutils.
4 : :
5 : : This file is free software; you can redistribute it and/or modify
6 : : it under the terms of either
7 : :
8 : : * the GNU Lesser General Public License as published by the Free
9 : : Software Foundation; either version 3 of the License, or (at
10 : : your option) any later version
11 : :
12 : : or
13 : :
14 : : * the GNU General Public License as published by the Free
15 : : Software Foundation; either version 2 of the License, or (at
16 : : your option) any later version
17 : :
18 : : or both in parallel, as here.
19 : :
20 : : elfutils is distributed in the hope that it will be useful, but
21 : : WITHOUT ANY WARRANTY; without even the implied warranty of
22 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 : : General Public License for more details.
24 : :
25 : : You should have received copies of the GNU General Public License and
26 : : the GNU Lesser General Public License along with this program. If
27 : : not, see <http://www.gnu.org/licenses/>. */
28 : :
29 : : #ifdef HAVE_CONFIG_H
30 : : # include <config.h>
31 : : #endif
32 : :
33 : : #include "libdwP.h"
34 : :
35 : : static Dwarf_Package_Index *
36 : 12 : __libdw_read_package_index (Dwarf *dbg, bool tu)
37 : : {
38 : 12 : Elf_Data *data;
39 [ + + ]: 12 : if (tu)
40 : 6 : data = dbg->sectiondata[IDX_debug_tu_index];
41 : : else
42 : 6 : data = dbg->sectiondata[IDX_debug_cu_index];
43 : :
44 : : /* We need at least 16 bytes for the header. */
45 [ - + - + ]: 12 : if (data == NULL || data->d_size < 16)
46 : : {
47 : 0 : invalid:
48 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
49 : 0 : return NULL;
50 : : }
51 : :
52 : 12 : const unsigned char *datap = data->d_buf;
53 : 12 : const unsigned char *endp = datap + data->d_size;
54 : 12 : uint16_t version;
55 : : /* In GNU DebugFission for DWARF 4, the version is 2 as a uword. In the
56 : : standardized DWARF 5 format, it is a uhalf followed by a padding uhalf.
57 : : Check for both. */
58 [ - + + + ]: 12 : if (read_4ubyte_unaligned (dbg, datap) == 2)
59 : : version = 2;
60 : : else
61 : : {
62 [ - + ]: 4 : version = read_2ubyte_unaligned (dbg, datap);
63 [ - + ]: 4 : if (version != 5)
64 : : {
65 : 0 : __libdw_seterrno (DWARF_E_VERSION);
66 : 0 : return NULL;
67 : : }
68 : : }
69 : 12 : datap += 4;
70 [ - + ]: 12 : uint32_t section_count = read_4ubyte_unaligned_inc (dbg, datap);
71 [ - + ]: 12 : uint32_t unit_count = read_4ubyte_unaligned_inc (dbg, datap);
72 [ - + ]: 12 : uint32_t slot_count = read_4ubyte_unaligned_inc (dbg, datap);
73 : :
74 : : /* The specification has a stricter requirement that
75 : : slot_count > 3 * unit_count / 2, but this is enough for us. */
76 [ - + ]: 12 : if (slot_count < unit_count)
77 : 0 : goto invalid;
78 : :
79 : : /* After the header, the section must contain:
80 : :
81 : : 8 byte signature per hash table slot
82 : : + 4 byte index per hash table slot
83 : : + Section offset table with 1 header row, 1 row per unit, 1 column per
84 : : section, 4 bytes per field
85 : : + Section size table with 1 row per unit, 1 column per section, 4 bytes
86 : : per field
87 : :
88 : : We have to be careful about overflow when checking this. */
89 : 12 : const unsigned char *hash_table = datap;
90 [ - + ]: 12 : if ((size_t) (endp - hash_table) < (uint64_t) slot_count * 12)
91 : 0 : goto invalid;
92 : 12 : const unsigned char *indices = hash_table + (size_t) slot_count * 8;
93 : 12 : const unsigned char *sections = indices + (size_t) slot_count * 4;
94 [ - + ]: 12 : if ((size_t) (endp - sections) < (uint64_t) section_count * 4)
95 : 0 : goto invalid;
96 : 12 : const unsigned char *section_offsets = sections + (size_t) section_count * 4;
97 [ + - ]: 12 : if ((uint64_t) unit_count * section_count > UINT64_MAX / 8
98 : 12 : || ((size_t) (endp - section_offsets)
99 [ - + ]: 12 : < (uint64_t) unit_count * section_count * 8))
100 : 0 : goto invalid;
101 : 12 : const unsigned char *section_sizes
102 : 12 : = section_offsets + (uint64_t) unit_count * section_count * 4;
103 : :
104 : 12 : Dwarf_Package_Index *index = malloc (sizeof (*index));
105 [ - + ]: 12 : if (index == NULL)
106 : : {
107 : 0 : __libdw_seterrno (DWARF_E_NOMEM);
108 : 0 : return NULL;
109 : : }
110 : :
111 : 12 : index->dbg = dbg;
112 : : /* Set absent sections to UINT32_MAX. */
113 : 12 : memset (index->sections, 0xff, sizeof (index->sections));
114 [ + + ]: 88 : for (size_t i = 0; i < section_count; i++)
115 : : {
116 [ - + ]: 76 : uint32_t section = read_4ubyte_unaligned (dbg, sections + i * 4);
117 : : /* 2 is DW_SECT_TYPES in version 2 and reserved in version 5. We ignore
118 : : it for version 5.
119 : : 5 is DW_SECT_LOC in version 2 and DW_SECT_LOCLISTS in version 5. We
120 : : use the same index for both.
121 : : 7 is DW_SECT_MACINFO in version 2 and DW_SECT_MACRO in version 5. We
122 : : use the same index for both.
123 : : 8 is DW_SECT_MACRO in version 2 and DW_SECT_RNGLISTS in version 5. We
124 : : use the same index for version 2's DW_SECT_MACRO as version 2's
125 : : DW_SECT_MACINFO/version 5's DW_SECT_MACRO.
126 : : We ignore unknown sections. */
127 [ - + ]: 76 : if (section == 0)
128 : 0 : continue;
129 [ + + ]: 76 : if (version == 2)
130 : : {
131 [ - + ]: 48 : if (section > 8)
132 : 0 : continue;
133 [ + + ]: 48 : else if (section == 8)
134 : 76 : section = DW_SECT_MACRO;
135 : : }
136 : 28 : else if (section == 2
137 : 28 : || (section
138 [ - + ]: 28 : > sizeof (index->sections) / sizeof (index->sections[0])))
139 : 0 : continue;
140 : 76 : index->sections[section - 1] = i;
141 : : }
142 : :
143 : : /* DW_SECT_INFO (or DW_SECT_TYPES for DWARF 4 type units) and DW_SECT_ABBREV
144 : : are required. */
145 [ + + + + ]: 12 : if (((!tu || dbg->sectiondata[IDX_debug_types] == NULL)
146 [ + - ]: 8 : && index->sections[DW_SECT_INFO - 1] == UINT32_MAX)
147 [ + + + + ]: 12 : || (tu && dbg->sectiondata[IDX_debug_types] != NULL
148 [ + - ]: 4 : && index->sections[DW_SECT_TYPES - 1] == UINT32_MAX)
149 [ - + ]: 12 : || index->sections[DW_SECT_ABBREV - 1] == UINT32_MAX)
150 : : {
151 : 0 : free (index);
152 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
153 : 0 : return NULL;
154 : : }
155 : :
156 : 12 : index->section_count = section_count;
157 : 12 : index->unit_count = unit_count;
158 : 12 : index->slot_count = slot_count;
159 : 12 : index->last_unit_found = 0;
160 : 12 : index->hash_table = hash_table;
161 : 12 : index->indices = indices;
162 : 12 : index->section_offsets = section_offsets;
163 : 12 : index->section_sizes = section_sizes;
164 : :
165 : 12 : return index;
166 : : }
167 : :
168 : : static Dwarf_Package_Index *
169 : 30 : __libdw_package_index (Dwarf *dbg, bool tu)
170 : : {
171 [ + + + + ]: 30 : if (tu && dbg->tu_index != NULL)
172 : : return dbg->tu_index;
173 [ + + ]: 18 : else if (!tu && dbg->cu_index != NULL)
174 : : return dbg->cu_index;
175 : :
176 : 12 : Dwarf_Package_Index *index = __libdw_read_package_index (dbg, tu);
177 [ + - ]: 12 : if (index == NULL)
178 : : return NULL;
179 : :
180 [ + + ]: 12 : if (tu)
181 : 6 : dbg->tu_index = index;
182 : : else
183 : 6 : dbg->cu_index = index;
184 : : return index;
185 : : }
186 : :
187 : : static int
188 : 0 : __libdw_dwp_unit_row (Dwarf_Package_Index *index, uint64_t unit_id,
189 : : uint32_t *unit_rowp)
190 : : {
191 [ # # ]: 0 : if (index == NULL)
192 : : return -1;
193 : :
194 : 0 : uint32_t hash = unit_id;
195 : 0 : uint32_t hash2 = (unit_id >> 32) | 1;
196 : : /* Only check each slot once. */
197 [ # # ]: 0 : for (uint32_t n = index->slot_count; n-- > 0; )
198 : : {
199 : 0 : size_t slot = hash & (index->slot_count - 1);
200 [ # # ]: 0 : uint64_t sig = read_8ubyte_unaligned (index->dbg,
201 : : index->hash_table + slot * 8);
202 [ # # ]: 0 : if (sig == unit_id)
203 : : {
204 [ # # ]: 0 : uint32_t row = read_4ubyte_unaligned (index->dbg,
205 : : index->indices + slot * 4);
206 [ # # ]: 0 : if (row > index->unit_count)
207 : : {
208 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
209 : 0 : return -1;
210 : : }
211 : 0 : *unit_rowp = row;
212 : 0 : return 0;
213 : : }
214 [ # # ]: 0 : else if (sig == 0
215 [ # # ]: 0 : && read_4ubyte_unaligned (index->dbg,
216 [ # # ]: 0 : index->indices + slot * 4) == 0)
217 : : break;
218 : 0 : hash += hash2;
219 : : }
220 : 0 : *unit_rowp = 0;
221 : 0 : return 0;
222 : : }
223 : :
224 : : static int
225 : 300 : __libdw_dwp_section_info (Dwarf_Package_Index *index, uint32_t unit_row,
226 : : unsigned int section, Dwarf_Off *offsetp,
227 : : Dwarf_Off *sizep)
228 : : {
229 [ + - ]: 300 : if (index == NULL)
230 : : return -1;
231 [ - + ]: 300 : if (unit_row == 0)
232 : : {
233 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
234 : 0 : return -1;
235 : : }
236 [ + + ]: 300 : if (index->sections[section - 1] == UINT32_MAX)
237 : : {
238 [ + - ]: 50 : if (offsetp != NULL)
239 : 50 : *offsetp = 0;
240 [ + - ]: 50 : if (sizep != NULL)
241 : 50 : *sizep = 0;
242 : 50 : return 0;
243 : : }
244 : 250 : size_t i = (size_t)(unit_row - 1) * index->section_count
245 : 250 : + index->sections[section - 1];
246 [ + - ]: 250 : if (offsetp != NULL)
247 [ - + ]: 250 : *offsetp = read_4ubyte_unaligned (index->dbg,
248 : : index->section_offsets + i * 4);
249 [ + + ]: 250 : if (sizep != NULL)
250 [ - + ]: 220 : *sizep = read_4ubyte_unaligned (index->dbg,
251 : : index->section_sizes + i * 4);
252 : : return 0;
253 : : }
254 : :
255 : : int
256 : : internal_function
257 : 79026 : __libdw_dwp_find_unit (Dwarf *dbg, bool debug_types, Dwarf_Off off,
258 : : uint16_t version, uint8_t unit_type, uint64_t unit_id8,
259 : : uint32_t *unit_rowp, Dwarf_Off *abbrev_offsetp)
260 : : {
261 : 79026 : if (version >= 5
262 [ + + + + ]: 79026 : && unit_type != DW_UT_split_compile && unit_type != DW_UT_split_type)
263 : : {
264 : 77652 : not_dwp:
265 : 78996 : *unit_rowp = 0;
266 : 78996 : *abbrev_offsetp = 0;
267 : 78996 : return 0;
268 : : }
269 : 1374 : bool tu = unit_type == DW_UT_split_type || debug_types;
270 [ + + + + ]: 2700 : if (dbg->sectiondata[tu ? IDX_debug_tu_index : IDX_debug_cu_index] == NULL)
271 : 1344 : goto not_dwp;
272 : 30 : Dwarf_Package_Index *index = __libdw_package_index (dbg, tu);
273 [ - + ]: 30 : if (index == NULL)
274 : : return -1;
275 : :
276 : : /* This is always called for ascending offsets. The most obvious way for a
277 : : producer to generate the section offset table is sorted by offset; both
278 : : GNU dwp and llvm-dwp do this. In this common case, we can avoid the full
279 : : lookup. */
280 [ + - ]: 30 : if (index->last_unit_found < index->unit_count)
281 : : {
282 : 30 : Dwarf_Off offset, size;
283 [ + + - + ]: 52 : if (__libdw_dwp_section_info (index, index->last_unit_found + 1,
284 : : debug_types ? DW_SECT_TYPES : DW_SECT_INFO,
285 : : &offset, &size) != 0)
286 : 0 : return -1;
287 [ + - + - ]: 30 : if (offset <= off && off - offset < size)
288 : : {
289 : 30 : *unit_rowp = ++index->last_unit_found;
290 : 30 : goto done;
291 : : }
292 : : else
293 : : /* The units are not sorted. Don't try again. */
294 : 0 : index->last_unit_found = index->unit_count;
295 : : }
296 : :
297 [ # # ]: 0 : if (version >= 5 || debug_types)
298 : : {
299 : : /* In DWARF 5 and in type units, the unit signature is available in the
300 : : unit header. */
301 [ # # ]: 0 : if (__libdw_dwp_unit_row (index, unit_id8, unit_rowp) != 0)
302 : : return -1;
303 : : }
304 : : else
305 : : {
306 : : /* In DWARF 4 compilation units, the unit signature is an attribute. We
307 : : can't parse attributes in the split unit until we get the abbreviation
308 : : table offset from the package index, which is a chicken-and-egg
309 : : problem. We could get the signature from the skeleton unit, but that
310 : : may not be available.
311 : :
312 : : Instead, we resort to a linear scan through the section offset table.
313 : : Finding all units is therefore quadratic in the number of units.
314 : : However, this will likely never be needed in practice because of the
315 : : sorted fast path above. If this ceases to be the case, we can try to
316 : : plumb through the skeleton unit's signature when it is available, or
317 : : build a sorted lookup table for binary search. */
318 [ # # ]: 0 : if (index->sections[DW_SECT_INFO - 1] == UINT32_MAX)
319 : : {
320 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
321 : 0 : return -1;
322 : : }
323 [ # # ]: 0 : for (uint32_t i = 0; i < index->unit_count; i++)
324 : : {
325 : 0 : Dwarf_Off offset, size;
326 : 0 : __libdw_dwp_section_info (index, i + 1, DW_SECT_INFO, &offset,
327 : : &size);
328 [ # # # # ]: 0 : if (offset <= off && off - offset < size)
329 : : {
330 : 0 : *unit_rowp = i + 1;
331 : 0 : goto done;
332 : : }
333 : : }
334 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
335 : 0 : return -1;
336 : : }
337 : :
338 : 30 : done:
339 : 30 : return __libdw_dwp_section_info (index, *unit_rowp, DW_SECT_ABBREV,
340 : : abbrev_offsetp, NULL);
341 : : }
342 : :
343 : : Dwarf_CU *
344 : : internal_function
345 : 0 : __libdw_dwp_findcu_id (Dwarf *dbg, uint64_t unit_id8)
346 : : {
347 : 0 : Dwarf_Package_Index *index = __libdw_package_index (dbg, false);
348 : 0 : uint32_t unit_row;
349 : 0 : Dwarf_Off offset;
350 : 0 : Dwarf_CU *cu;
351 [ # # ]: 0 : if (__libdw_dwp_unit_row (index, unit_id8, &unit_row) == 0
352 [ # # ]: 0 : && __libdw_dwp_section_info (index, unit_row, DW_SECT_INFO, &offset,
353 : : NULL) == 0
354 [ # # ]: 0 : && (cu = __libdw_findcu (dbg, offset, false)) != NULL
355 [ # # ]: 0 : && cu->unit_type == DW_UT_split_compile
356 [ # # ]: 0 : && cu->unit_id8 == unit_id8)
357 : : return cu;
358 : : else
359 : 0 : return NULL;
360 : : }
361 : :
362 : : int
363 : 240 : dwarf_cu_dwp_section_info (Dwarf_CU *cu, unsigned int section,
364 : : Dwarf_Off *offsetp, Dwarf_Off *sizep)
365 : : {
366 [ - + ]: 240 : if (cu == NULL)
367 : : return -1;
368 [ - + ]: 240 : if (section < DW_SECT_INFO || section > DW_SECT_RNGLISTS)
369 : : {
370 : 0 : __libdw_seterrno (DWARF_E_UNKNOWN_SECTION);
371 : 0 : return -1;
372 : : }
373 [ - + ]: 240 : if (cu->dwp_row == 0)
374 : : {
375 [ # # ]: 0 : if (offsetp != NULL)
376 : 0 : *offsetp = 0;
377 [ # # ]: 0 : if (sizep != NULL)
378 : 0 : *sizep = 0;
379 : 0 : return 0;
380 : : }
381 : : else
382 : : {
383 : 720 : Dwarf_Package_Index *index
384 [ + + ]: 240 : = cu->unit_type == DW_UT_split_compile
385 : 240 : ? cu->dbg->cu_index : cu->dbg->tu_index;
386 : 240 : return __libdw_dwp_section_info (index, cu->dwp_row, section, offsetp,
387 : : sizep);
388 : : }
389 : : }
390 : : INTDEF(dwarf_cu_dwp_section_info)
|