1 /* Return list address ranges.
2 Copyright (C) 2000-2010 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 unsigned int address_size = *readp++;
152 if (unlikely (address_size != 4 && address_size != 8))
153 goto invalid;
154
155 /* We don't actually support segment selectors. */
156 unsigned int segment_size = *readp++;
157 if (segment_size != 0)
158 goto invalid;
159
160 /* Round the address to the next multiple of 2*address_size. */
161 readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
162 % (2 * address_size));
163
164 while (1)
165 {
166 Dwarf_Word range_address;
167 Dwarf_Word range_length;
168
169 if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp,
170 address_size, &range_address))
171 goto fail;
172
173 if (readp + address_size > readendp)
174 goto invalid;
175
176 if (address_size == 4)
177 range_length = read_4ubyte_unaligned_inc (dbg, readp);
178 else
179 range_length = read_8ubyte_unaligned_inc (dbg, readp);
180
181 /* Two zero values mark the end. */
182 if (range_address == 0 && range_length == 0)
183 break;
184
185 /* We don't use alloca for these temporary structures because
186 the total number of them can be quite large. */
187 struct arangelist *new_arange = malloc (sizeof *new_arange);
188 if (unlikely (new_arange == NULL))
189 {
190 __libdw_seterrno (DWARF_E_NOMEM);
191 goto fail;
192 }
193
194 new_arange->arange.addr = range_address;
195 new_arange->arange.length = range_length;
196
197 /* We store the actual CU DIE offset, not the CU header offset. */
198 const char *cu_header = (dbg->sectiondata[IDX_debug_info]->d_buf
199 + offset);
200 unsigned int offset_size;
201 if (read_4ubyte_unaligned_noncvt (cu_header) == DWARF3_LENGTH_64_BIT)
202 offset_size = 8;
203 else
204 offset_size = 4;
205 new_arange->arange.offset = DIE_OFFSET_FROM_CU_OFFSET (offset,
206 offset_size,
207 false);
208
209 new_arange->next = arangelist;
210 arangelist = new_arange;
211 ++narangelist;
212
213 /* Sanity-check the data. */
214 if (unlikely (new_arange->arange.offset
215 >= dbg->sectiondata[IDX_debug_info]->d_size))
216 goto invalid;
217 }
218 }
219
220 if (narangelist == 0)
221 {
222 assert (arangelist == NULL);
223 if (naranges != NULL)
224 *naranges = 0;
225 *aranges = NULL;
226 return 0;
227 }
228
229 /* Allocate the array for the result. */
230 void *buf = libdw_alloc (dbg, Dwarf_Aranges,
231 sizeof (Dwarf_Aranges)
232 + narangelist * sizeof (Dwarf_Arange), 1);
233
234 /* First use the buffer for the pointers, and sort the entries.
235 We'll write the pointers in the end of the buffer, and then
236 copy into the buffer from the beginning so the overlap works. */
237 assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
238 struct arangelist **sortaranges
239 = (buf + sizeof (Dwarf_Aranges)
240 + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist));
241
242 /* The list is in LIFO order and usually they come in clumps with
243 ascending addresses. So fill from the back to probably start with
244 runs already in order before we sort. */
245 unsigned int i = narangelist;
246 while (i-- > 0)
247 {
248 sortaranges[i] = arangelist;
249 arangelist = arangelist->next;
250 }
251 assert (arangelist == NULL);
252
253 /* Sort by ascending address. */
254 qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
255
256 /* Now that they are sorted, put them in the final array.
257 The buffers overlap, so we've clobbered the early elements
258 of SORTARANGES by the time we're reading the later ones. */
259 *aranges = buf;
260 (*aranges)->dbg = dbg;
261 (*aranges)->naranges = narangelist;
262 dbg->aranges = *aranges;
263 if (naranges != NULL)
264 *naranges = narangelist;
265 for (i = 0; i < narangelist; ++i)
266 {
267 struct arangelist *elt = sortaranges[i];
268 (*aranges)->info[i] = elt->arange;
269 free (elt);
270 }
271
272 return 0;
273 }
274 INTDEF(dwarf_getaranges)
275