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