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