1 /* Return list address ranges.
2 Copyright (C) 2000-2010, 2016, 2017 Red Hat, Inc.
3 Copyright (C) 2023 Mark J. Wielaard <[email protected]>
4 This file is part of elfutils.
5 Written by Ulrich Drepper <[email protected]>, 2000.
6
7 This file is free software; you can redistribute it and/or modify
8 it under the terms of either
9
10 * the GNU Lesser General Public License as published by the Free
11 Software Foundation; either version 3 of the License, or (at
12 your option) any later version
13
14 or
15
16 * the GNU General Public License as published by the Free
17 Software Foundation; either version 2 of the License, or (at
18 your option) any later version
19
20 or both in parallel, as here.
21
22 elfutils is distributed in the hope that it will be useful, but
23 WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 General Public License for more details.
26
27 You should have received copies of the GNU General Public License and
28 the GNU Lesser General Public License along with this program. If
29 not, see <http://www.gnu.org/licenses/>. */
30
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34
35 #include <stdlib.h>
36 #include "libdwP.h"
37 #include <dwarf.h>
38
39 struct arangelist
40 {
41 Dwarf_Arange arange;
42 struct arangelist *next;
43 };
44
45 /* Compare by Dwarf_Arange.addr, given pointers into an array of pointeers. */
46 static int
compare_aranges(const void * a,const void * b)47 compare_aranges (const void *a, const void *b)
48 {
49 struct arangelist *const *p1 = a, *const *p2 = b;
50 struct arangelist *l1 = *p1, *l2 = *p2;
51 if (l1->arange.addr != l2->arange.addr)
52 return (l1->arange.addr < l2->arange.addr) ? -1 : 1;
53 return 0;
54 }
55
56 /* Convert ARANGELIST into Dwarf_Aranges and store at ARANGES. */
57 static bool
finalize_aranges(Dwarf * dbg,Dwarf_Aranges ** aranges,size_t * naranges,struct arangelist * arangelist,unsigned int narangelist)58 finalize_aranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges,
59 struct arangelist *arangelist, unsigned int narangelist)
60 {
61 /* Allocate the array for the result. */
62 void *buf = libdw_alloc (dbg, Dwarf_Aranges,
63 sizeof (Dwarf_Aranges)
64 + narangelist * sizeof (Dwarf_Arange), 1);
65
66 /* First use the buffer for the pointers, and sort the entries.
67 We'll write the pointers in the end of the buffer, and then
68 copy into the buffer from the beginning so the overlap works. */
69 eu_static_assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
70 struct arangelist **sortaranges
71 = (buf + sizeof (Dwarf_Aranges)
72 + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist));
73
74 /* The list is in LIFO order and usually they come in clumps with
75 ascending addresses. So fill from the back to probably start with
76 runs already in order before we sort. */
77 unsigned int i = narangelist;
78 while (i-- > 0)
79 {
80 sortaranges[i] = arangelist;
81 arangelist = arangelist->next;
82 }
83
84 /* Something went wrong if narangelist is less then the actual length
85 of arangelist. */
86 if (arangelist != NULL)
87 {
88 __libdw_seterrno (DWARF_E_UNKNOWN_ERROR);
89 return false;
90 }
91
92 /* Sort by ascending address. */
93 qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
94
95 /* Now that they are sorted, put them in the final array.
96 The buffers overlap, so we've clobbered the early elements
97 of SORTARANGES by the time we're reading the later ones. */
98 *aranges = buf;
99 (*aranges)->dbg = dbg;
100 (*aranges)->naranges = narangelist;
101 if (naranges != NULL)
102 *naranges = narangelist;
103 for (i = 0; i < narangelist; ++i)
104 {
105 struct arangelist *elt = sortaranges[i];
106 (*aranges)->info[i] = elt->arange;
107 free (elt);
108 }
109
110 return true;
111 }
112
113 int
__libdw_getdieranges(Dwarf * dbg,Dwarf_Aranges ** aranges,size_t * naranges)114 __libdw_getdieranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges)
115 {
116 if (dbg == NULL)
117 return -1;
118
119 if (dbg->dieranges != NULL)
120 {
121 *aranges = dbg->dieranges;
122 if (naranges != NULL)
123 *naranges = dbg->dieranges->naranges;
124 return 0;
125 }
126
127 struct arangelist *arangelist = NULL;
128 unsigned int narangelist = 0;
129
130 Dwarf_CU *cu = NULL;
131 while (INTUSE(dwarf_get_units) (dbg, cu, &cu, NULL, NULL, NULL, NULL) == 0)
132 {
133 Dwarf_Addr base;
134 Dwarf_Addr low;
135 Dwarf_Addr high;
136
137 Dwarf_Die cudie = CUDIE (cu);
138
139 /* Skip CUs that only contain type information. */
140 if (!INTUSE(dwarf_hasattr) (&cudie, DW_AT_low_pc)
141 && !INTUSE(dwarf_hasattr) (&cudie, DW_AT_ranges))
142 continue;
143
144 ptrdiff_t offset = 0;
145
146 /* Add arange for each range list entry or high_pc and low_pc. */
147 while ((offset = INTUSE(dwarf_ranges) (&cudie, offset,
148 &base, &low, &high)) > 0)
149 {
150 if (offset == -1)
151 {
152 __libdw_seterrno (DWARF_E_INVALID_DWARF);
153 goto fail;
154 }
155
156 struct arangelist *new_arange = malloc (sizeof *new_arange);
157 if (unlikely (new_arange == NULL))
158 {
159 __libdw_seterrno (DWARF_E_NOMEM);
160 goto fail;
161 }
162
163 new_arange->arange.addr = low;
164 new_arange->arange.length = (Dwarf_Word) (high - low);
165 new_arange->arange.offset = __libdw_first_die_off_from_cu (cu);
166
167 new_arange->next = arangelist;
168 arangelist = new_arange;
169 ++narangelist;
170 }
171 }
172
173 if (narangelist == 0)
174 {
175 if (naranges != NULL)
176 *naranges = 0;
177 *aranges = NULL;
178 return 0;
179 }
180
181 if (!finalize_aranges (dbg, aranges, naranges, arangelist, narangelist))
182 goto fail;
183
184 dbg->dieranges = *aranges;
185 return 0;
186
187 fail:
188 while (arangelist != NULL)
189 {
190 struct arangelist *next = arangelist->next;
191 free (arangelist);
192 arangelist = next;
193 }
194 return -1;
195 }
196
197 int
dwarf_getaranges(Dwarf * dbg,Dwarf_Aranges ** aranges,size_t * naranges)198 dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges)
199 {
200 if (dbg == NULL)
201 return -1;
202
203 if (dbg->aranges != NULL)
204 {
205 *aranges = dbg->aranges;
206 if (naranges != NULL)
207 *naranges = dbg->aranges->naranges;
208 return 0;
209 }
210
211 if (dbg->sectiondata[IDX_debug_aranges] == NULL)
212 {
213 /* No such section. */
214 *aranges = NULL;
215 if (naranges != NULL)
216 *naranges = 0;
217 return 0;
218 }
219
220 if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
221 return -1;
222
223 struct arangelist *arangelist = NULL;
224 unsigned int narangelist = 0;
225
226 const unsigned char *readp = dbg->sectiondata[IDX_debug_aranges]->d_buf;
227 const unsigned char *readendp
228 = readp + dbg->sectiondata[IDX_debug_aranges]->d_size;
229
230 while (readp < readendp)
231 {
232 const unsigned char *hdrstart = readp;
233
234 /* Each entry starts with a header:
235
236 1. A 4-byte or 12-byte length containing the length of the
237 set of entries for this compilation unit, not including the
238 length field itself. [...]
239
240 2. A 2-byte version identifier containing the value 2 for
241 DWARF Version 2.1.
242
243 3. A 4-byte or 8-byte offset into the .debug_info section. [...]
244
245 4. A 1-byte unsigned integer containing the size in bytes of
246 an address (or the offset portion of an address for segmented
247 addressing) on the target system.
248
249 5. A 1-byte unsigned integer containing the size in bytes of
250 a segment descriptor on the target system. */
251 if (unlikely (readp + 4 > readendp))
252 goto invalid;
253
254 Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
255 unsigned int length_bytes = 4;
256 if (length == DWARF3_LENGTH_64_BIT)
257 {
258 if (unlikely (readp + 8 > readendp))
259 goto invalid;
260
261 length = read_8ubyte_unaligned_inc (dbg, readp);
262 length_bytes = 8;
263 }
264 else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
265 && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
266 goto invalid;
267
268 const unsigned char *endp = readp + length;
269 if (unlikely (endp > readendp))
270 goto invalid;
271
272 if (unlikely (readp + 2 > readendp))
273 goto invalid;
274
275 unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
276 if (version != 2)
277 {
278 invalid:
279 __libdw_seterrno (DWARF_E_INVALID_DWARF);
280 fail:
281 while (arangelist != NULL)
282 {
283 struct arangelist *next = arangelist->next;
284 free (arangelist);
285 arangelist = next;
286 }
287 return -1;
288 }
289
290 Dwarf_Word offset = 0;
291 if (__libdw_read_offset_inc (dbg,
292 IDX_debug_aranges, &readp,
293 length_bytes, &offset, IDX_debug_info, 4))
294 goto fail;
295
296 /* Next up two bytes for address and segment size. */
297 if (readp + 2 > readendp)
298 goto invalid;
299
300 unsigned int address_size = *readp++;
301 if (unlikely (address_size != 4 && address_size != 8))
302 goto invalid;
303
304 /* We don't actually support segment selectors. */
305 unsigned int segment_size = *readp++;
306 if (segment_size != 0)
307 goto invalid;
308
309 /* Round the address to the next multiple of 2*address_size. */
310 readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
311 % (2 * address_size));
312
313 while (1)
314 {
315 Dwarf_Word range_address;
316 Dwarf_Word range_length;
317
318 if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp,
319 address_size, &range_address))
320 goto fail;
321
322 if (readp + address_size > readendp)
323 goto invalid;
324
325 if (address_size == 4)
326 range_length = read_4ubyte_unaligned_inc (dbg, readp);
327 else
328 range_length = read_8ubyte_unaligned_inc (dbg, readp);
329
330 /* Two zero values mark the end. But in some cases (bugs)
331 there might be such entries in the middle of the table.
332 Ignore and continue, we'll check the actual length of
333 the table to see if we are really at the end. */
334 if (range_address == 0 && range_length == 0)
335 {
336 if (readp >= endp)
337 break;
338 else
339 continue;
340 }
341
342 /* We don't use alloca for these temporary structures because
343 the total number of them can be quite large. */
344 struct arangelist *new_arange = malloc (sizeof *new_arange);
345 if (unlikely (new_arange == NULL))
346 {
347 __libdw_seterrno (DWARF_E_NOMEM);
348 goto fail;
349 }
350
351 new_arange->arange.addr = range_address;
352 new_arange->arange.length = range_length;
353
354 /* We store the actual CU DIE offset, not the CU header offset. */
355 Dwarf_CU *cu = __libdw_findcu (dbg, offset, false);
356 if (unlikely (cu == NULL))
357 {
358 /* We haven't gotten a chance to link in the new_arange
359 into the arangelist, don't leak it. */
360 free (new_arange);
361 goto fail;
362 }
363 new_arange->arange.offset = __libdw_first_die_off_from_cu (cu);
364
365 new_arange->next = arangelist;
366 arangelist = new_arange;
367 ++narangelist;
368
369 /* Sanity-check the data. */
370 if (unlikely (new_arange->arange.offset
371 >= dbg->sectiondata[IDX_debug_info]->d_size))
372 goto invalid;
373 }
374 }
375
376 if (narangelist == 0)
377 {
378 if (naranges != NULL)
379 *naranges = 0;
380 *aranges = NULL;
381 return 0;
382 }
383
384 if (!finalize_aranges (dbg, aranges, naranges, arangelist, narangelist))
385 goto fail;
386
387 dbg->aranges = *aranges;
388 return 0;
389 }
390 INTDEF(dwarf_getaranges)
391