1 /* Return list address ranges.
2 Copyright (C) 2000-2010, 2016, 2017 Red Hat, Inc.
3 Copyright (C) 2023 Mark J. Wielaard <mark@klomp.org>
4 This file is part of elfutils.
5 Written by Ulrich Drepper <drepper@redhat.com>, 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 <assert.h>
37 #include "libdwP.h"
38 #include <dwarf.h>
39
40 struct arangelist
41 {
42 Dwarf_Arange arange;
43 struct arangelist *next;
44 };
45
46 /* Compare by Dwarf_Arange.addr, given pointers into an array of pointeers. */
47 static int
compare_aranges(const void * a,const void * b)48 compare_aranges (const void *a, const void *b)
49 {
50 struct arangelist *const *p1 = a, *const *p2 = b;
51 struct arangelist *l1 = *p1, *l2 = *p2;
52 if (l1->arange.addr != l2->arange.addr)
53 return (l1->arange.addr < l2->arange.addr) ? -1 : 1;
54 return 0;
55 }
56
57 int
dwarf_getaranges(Dwarf * dbg,Dwarf_Aranges ** aranges,size_t * naranges)58 dwarf_getaranges (Dwarf *dbg, Dwarf_Aranges **aranges, size_t *naranges)
59 {
60 if (dbg == NULL)
61 return -1;
62
63 if (dbg->aranges != NULL)
64 {
65 *aranges = dbg->aranges;
66 if (naranges != NULL)
67 *naranges = dbg->aranges->naranges;
68 return 0;
69 }
70
71 if (dbg->sectiondata[IDX_debug_aranges] == NULL)
72 {
73 /* No such section. */
74 *aranges = NULL;
75 if (naranges != NULL)
76 *naranges = 0;
77 return 0;
78 }
79
80 if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
81 return -1;
82
83 struct arangelist *arangelist = NULL;
84 unsigned int narangelist = 0;
85
86 const unsigned char *readp = dbg->sectiondata[IDX_debug_aranges]->d_buf;
87 const unsigned char *readendp
88 = readp + dbg->sectiondata[IDX_debug_aranges]->d_size;
89
90 while (readp < readendp)
91 {
92 const unsigned char *hdrstart = readp;
93
94 /* Each entry starts with a header:
95
96 1. A 4-byte or 12-byte length containing the length of the
97 set of entries for this compilation unit, not including the
98 length field itself. [...]
99
100 2. A 2-byte version identifier containing the value 2 for
101 DWARF Version 2.1.
102
103 3. A 4-byte or 8-byte offset into the .debug_info section. [...]
104
105 4. A 1-byte unsigned integer containing the size in bytes of
106 an address (or the offset portion of an address for segmented
107 addressing) on the target system.
108
109 5. A 1-byte unsigned integer containing the size in bytes of
110 a segment descriptor on the target system. */
111 if (unlikely (readp + 4 > readendp))
112 goto invalid;
113
114 Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
115 unsigned int length_bytes = 4;
116 if (length == DWARF3_LENGTH_64_BIT)
117 {
118 if (unlikely (readp + 8 > readendp))
119 goto invalid;
120
121 length = read_8ubyte_unaligned_inc (dbg, readp);
122 length_bytes = 8;
123 }
124 else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
125 && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
126 goto invalid;
127
128 const unsigned char *endp = readp + length;
129 if (unlikely (endp > readendp))
130 goto invalid;
131
132 if (unlikely (readp + 2 > readendp))
133 goto invalid;
134
135 unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
136 if (version != 2)
137 {
138 invalid:
139 __libdw_seterrno (DWARF_E_INVALID_DWARF);
140 fail:
141 while (arangelist != NULL)
142 {
143 struct arangelist *next = arangelist->next;
144 free (arangelist);
145 arangelist = next;
146 }
147 return -1;
148 }
149
150 Dwarf_Word offset = 0;
151 if (__libdw_read_offset_inc (dbg,
152 IDX_debug_aranges, &readp,
153 length_bytes, &offset, IDX_debug_info, 4))
154 goto fail;
155
156 /* Next up two bytes for address and segment size. */
157 if (readp + 2 > readendp)
158 goto invalid;
159
160 unsigned int address_size = *readp++;
161 if (unlikely (address_size != 4 && address_size != 8))
162 goto invalid;
163
164 /* We don't actually support segment selectors. */
165 unsigned int segment_size = *readp++;
166 if (segment_size != 0)
167 goto invalid;
168
169 /* Round the address to the next multiple of 2*address_size. */
170 readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
171 % (2 * address_size));
172
173 while (1)
174 {
175 Dwarf_Word range_address;
176 Dwarf_Word range_length;
177
178 if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp,
179 address_size, &range_address))
180 goto fail;
181
182 if (readp + address_size > readendp)
183 goto invalid;
184
185 if (address_size == 4)
186 range_length = read_4ubyte_unaligned_inc (dbg, readp);
187 else
188 range_length = read_8ubyte_unaligned_inc (dbg, readp);
189
190 /* Two zero values mark the end. But in some cases (bugs)
191 there might be such entries in the middle of the table.
192 Ignore and continue, we'll check the actual length of
193 the table to see if we are really at the end. */
194 if (range_address == 0 && range_length == 0)
195 {
196 if (readp >= endp)
197 break;
198 else
199 continue;
200 }
201
202 /* We don't use alloca for these temporary structures because
203 the total number of them can be quite large. */
204 struct arangelist *new_arange = malloc (sizeof *new_arange);
205 if (unlikely (new_arange == NULL))
206 {
207 __libdw_seterrno (DWARF_E_NOMEM);
208 goto fail;
209 }
210
211 new_arange->arange.addr = range_address;
212 new_arange->arange.length = range_length;
213
214 /* We store the actual CU DIE offset, not the CU header offset. */
215 Dwarf_CU *cu = __libdw_findcu (dbg, offset, false);
216 if (unlikely (cu == NULL))
217 {
218 /* We haven't gotten a chance to link in the new_arange
219 into the arangelist, don't leak it. */
220 free (new_arange);
221 goto fail;
222 }
223 new_arange->arange.offset = __libdw_first_die_off_from_cu (cu);
224
225 new_arange->next = arangelist;
226 arangelist = new_arange;
227 ++narangelist;
228
229 /* Sanity-check the data. */
230 if (unlikely (new_arange->arange.offset
231 >= dbg->sectiondata[IDX_debug_info]->d_size))
232 goto invalid;
233 }
234 }
235
236 if (narangelist == 0)
237 {
238 assert (arangelist == NULL);
239 if (naranges != NULL)
240 *naranges = 0;
241 *aranges = NULL;
242 return 0;
243 }
244
245 /* Allocate the array for the result. */
246 void *buf = libdw_alloc (dbg, Dwarf_Aranges,
247 sizeof (Dwarf_Aranges)
248 + narangelist * sizeof (Dwarf_Arange), 1);
249
250 /* First use the buffer for the pointers, and sort the entries.
251 We'll write the pointers in the end of the buffer, and then
252 copy into the buffer from the beginning so the overlap works. */
253 assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
254 struct arangelist **sortaranges
255 = (buf + sizeof (Dwarf_Aranges)
256 + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist));
257
258 /* The list is in LIFO order and usually they come in clumps with
259 ascending addresses. So fill from the back to probably start with
260 runs already in order before we sort. */
261 unsigned int i = narangelist;
262 while (i-- > 0)
263 {
264 sortaranges[i] = arangelist;
265 arangelist = arangelist->next;
266 }
267 assert (arangelist == NULL);
268
269 /* Sort by ascending address. */
270 qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
271
272 /* Now that they are sorted, put them in the final array.
273 The buffers overlap, so we've clobbered the early elements
274 of SORTARANGES by the time we're reading the later ones. */
275 *aranges = buf;
276 (*aranges)->dbg = dbg;
277 (*aranges)->naranges = narangelist;
278 dbg->aranges = *aranges;
279 if (naranges != NULL)
280 *naranges = narangelist;
281 for (i = 0; i < narangelist; ++i)
282 {
283 struct arangelist *elt = sortaranges[i];
284 (*aranges)->info[i] = elt->arange;
285 free (elt);
286 }
287
288 return 0;
289 }
290 INTDEF(dwarf_getaranges)
291