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.
6 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
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
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
19 or both in parallel, as here.
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.
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/>. */
42 struct arangelist *next;
45 /* Compare by Dwarf_Arange.addr, given pointers into an array of pointeers. */
47 compare_aranges (const void *a, const void *b)
49 struct arangelist *const *p1 = a, *const *p2 = b;
50 struct arangelist *l1 = *p1, *l2 = *p2;
51 return l1->arange.addr - l2->arange.addr;
55 dwarf_getaranges (dbg, aranges, naranges)
57 Dwarf_Aranges **aranges;
63 if (dbg->aranges != NULL)
65 *aranges = dbg->aranges;
67 *naranges = dbg->aranges->naranges;
71 if (dbg->sectiondata[IDX_debug_aranges] == NULL)
73 /* No such section. */
80 if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
83 struct arangelist *arangelist = NULL;
84 unsigned int narangelist = 0;
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;
90 while (readp < readendp)
92 const unsigned char *hdrstart = readp;
94 /* Each entry starts with a header:
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. [...]
100 2. A 2-byte version identifier containing the value 2 for
103 3. A 4-byte or 8-byte offset into the .debug_info section. [...]
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.
109 5. A 1-byte unsigned integer containing the size in bytes of
110 a segment descriptor on the target system. */
111 Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
112 unsigned int length_bytes = 4;
113 if (length == DWARF3_LENGTH_64_BIT)
115 length = read_8ubyte_unaligned_inc (dbg, readp);
118 else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
119 && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
122 unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
126 __libdw_seterrno (DWARF_E_INVALID_DWARF);
128 while (arangelist != NULL)
130 struct arangelist *next = arangelist->next;
138 if (__libdw_read_offset_inc (dbg,
139 IDX_debug_aranges, &readp,
140 length_bytes, &offset, IDX_debug_info, 4))
143 unsigned int address_size = *readp++;
144 if (address_size != 4 && address_size != 8)
147 /* We don't actually support segment selectors. */
148 unsigned int segment_size = *readp++;
149 if (segment_size != 0)
152 /* Round the address to the next multiple of 2*address_size. */
153 readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
154 % (2 * address_size));
158 Dwarf_Word range_address;
159 Dwarf_Word range_length;
161 if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp,
162 address_size, &range_address))
165 if (address_size == 4)
166 range_length = read_4ubyte_unaligned_inc (dbg, readp);
168 range_length = read_8ubyte_unaligned_inc (dbg, readp);
170 /* Two zero values mark the end. */
171 if (range_address == 0 && range_length == 0)
174 /* We don't use alloca for these temporary structures because
175 the total number of them can be quite large. */
176 struct arangelist *new_arange = malloc (sizeof *new_arange);
177 if (unlikely (new_arange == NULL))
179 __libdw_seterrno (DWARF_E_NOMEM);
183 new_arange->arange.addr = range_address;
184 new_arange->arange.length = range_length;
186 /* We store the actual CU DIE offset, not the CU header offset. */
187 const char *cu_header = (dbg->sectiondata[IDX_debug_info]->d_buf
189 unsigned int offset_size;
190 if (read_4ubyte_unaligned_noncvt (cu_header) == DWARF3_LENGTH_64_BIT)
194 new_arange->arange.offset = DIE_OFFSET_FROM_CU_OFFSET (offset,
198 new_arange->next = arangelist;
199 arangelist = new_arange;
202 /* Sanity-check the data. */
203 if (unlikely (new_arange->arange.offset
204 >= dbg->sectiondata[IDX_debug_info]->d_size))
209 if (narangelist == 0)
211 assert (arangelist == NULL);
212 if (naranges != NULL)
218 /* Allocate the array for the result. */
219 void *buf = libdw_alloc (dbg, Dwarf_Aranges,
220 sizeof (Dwarf_Aranges)
221 + narangelist * sizeof (Dwarf_Arange), 1);
223 /* First use the buffer for the pointers, and sort the entries.
224 We'll write the pointers in the end of the buffer, and then
225 copy into the buffer from the beginning so the overlap works. */
226 assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
227 struct arangelist **sortaranges
228 = (buf + sizeof (Dwarf_Aranges)
229 + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist));
231 /* The list is in LIFO order and usually they come in clumps with
232 ascending addresses. So fill from the back to probably start with
233 runs already in order before we sort. */
234 unsigned int i = narangelist;
237 sortaranges[i] = arangelist;
238 arangelist = arangelist->next;
240 assert (arangelist == NULL);
242 /* Sort by ascending address. */
243 qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
245 /* Now that they are sorted, put them in the final array.
246 The buffers overlap, so we've clobbered the early elements
247 of SORTARANGES by the time we're reading the later ones. */
249 (*aranges)->dbg = dbg;
250 (*aranges)->naranges = narangelist;
251 dbg->aranges = *aranges;
252 if (naranges != NULL)
253 *naranges = narangelist;
254 for (i = 0; i < narangelist; ++i)
256 struct arangelist *elt = sortaranges[i];
257 (*aranges)->info[i] = elt->arange;
263 INTDEF(dwarf_getaranges)