blob: 20ac7ec6781cdd9e09f4481e666c5f7760383fd8 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Return list address ranges.
Roland McGrath3e0f7d12010-06-15 23:10:35 -07002 Copyright (C) 2000-2010 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5
Mark Wielaardde2ed972012-06-05 17:15:16 +02006 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00008
Mark Wielaardde2ed972012-06-05 17:15:16 +02009 * 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
Ulrich Drepper361df7d2006-04-04 21:38:57 +000022 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
Mark Wielaardde2ed972012-06-05 17:15:16 +020026 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/>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000029
30#ifdef HAVE_CONFIG_H
31# include <config.h>
32#endif
33
34#include <stdlib.h>
35#include <assert.h>
36#include "libdwP.h"
Ulrich Drepper35f08c42008-01-18 19:59:08 +000037#include <dwarf.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000038
39struct 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. */
46static int
47compare_aranges (const void *a, const void *b)
48{
Roland McGrath5f95e2b2010-10-05 00:56:30 -070049 struct arangelist *const *p1 = a, *const *p2 = b;
50 struct arangelist *l1 = *p1, *l2 = *p2;
51 return l1->arange.addr - l2->arange.addr;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000052}
53
54int
55dwarf_getaranges (dbg, aranges, naranges)
56 Dwarf *dbg;
57 Dwarf_Aranges **aranges;
58 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
Ulrich Dreppere7a73172006-05-22 18:16:45 +000071 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
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000080 if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
81 return -1;
82
83 struct arangelist *arangelist = NULL;
84 unsigned int narangelist = 0;
85
Roland McGrath05c4e042009-06-18 13:56:02 -070086 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;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000089
90 while (readp < readendp)
91 {
Roland McGrath05c4e042009-06-18 13:56:02 -070092 const unsigned char *hdrstart = readp;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000093
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 Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
112 unsigned int length_bytes = 4;
Ulrich Drepper35f08c42008-01-18 19:59:08 +0000113 if (length == DWARF3_LENGTH_64_BIT)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000114 {
115 length = read_8ubyte_unaligned_inc (dbg, readp);
116 length_bytes = 8;
117 }
Ulrich Drepper35f08c42008-01-18 19:59:08 +0000118 else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
119 && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
120 goto invalid;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000121
122 unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
123 if (version != 2)
124 {
125 invalid:
126 __libdw_seterrno (DWARF_E_INVALID_DWARF);
Roland McGrath5f95e2b2010-10-05 00:56:30 -0700127 fail:
128 while (arangelist != NULL)
129 {
130 struct arangelist *next = arangelist->next;
131 free (arangelist);
132 arangelist = next;
133 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000134 return -1;
135 }
136
137 Dwarf_Word offset;
Ulrich Drepper99d23722009-06-14 20:19:45 -0700138 if (__libdw_read_offset_inc (dbg,
Roland McGrath05c4e042009-06-18 13:56:02 -0700139 IDX_debug_aranges, &readp,
Ulrich Drepper99d23722009-06-14 20:19:45 -0700140 length_bytes, &offset, IDX_debug_info, 4))
Roland McGrath5f95e2b2010-10-05 00:56:30 -0700141 goto fail;
Roland McGratha5a89682005-08-02 01:24:01 +0000142
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000143 unsigned int address_size = *readp++;
144 if (address_size != 4 && address_size != 8)
145 goto invalid;
146
Mark Wielaard03d76f42013-11-09 16:45:22 +0100147 /* We don't actually support segment selectors. */
148 unsigned int segment_size = *readp++;
149 if (segment_size != 0)
150 goto invalid;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000151
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));
155
156 while (1)
157 {
158 Dwarf_Word range_address;
159 Dwarf_Word range_length;
160
Roland McGrath05c4e042009-06-18 13:56:02 -0700161 if (__libdw_read_address_inc (dbg, IDX_debug_aranges, &readp,
Ulrich Drepper99d23722009-06-14 20:19:45 -0700162 address_size, &range_address))
Roland McGrath5f95e2b2010-10-05 00:56:30 -0700163 goto fail;
Ulrich Drepper99d23722009-06-14 20:19:45 -0700164
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000165 if (address_size == 4)
Ulrich Drepper99d23722009-06-14 20:19:45 -0700166 range_length = read_4ubyte_unaligned_inc (dbg, readp);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000167 else
Ulrich Drepper99d23722009-06-14 20:19:45 -0700168 range_length = read_8ubyte_unaligned_inc (dbg, readp);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000169
170 /* Two zero values mark the end. */
171 if (range_address == 0 && range_length == 0)
172 break;
173
Roland McGrath5f95e2b2010-10-05 00:56:30 -0700174 /* 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))
178 {
179 __libdw_seterrno (DWARF_E_NOMEM);
180 goto fail;
181 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000182
183 new_arange->arange.addr = range_address;
184 new_arange->arange.length = range_length;
185
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
188 + offset);
189 unsigned int offset_size;
Ulrich Drepper35f08c42008-01-18 19:59:08 +0000190 if (read_4ubyte_unaligned_noncvt (cu_header) == DWARF3_LENGTH_64_BIT)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000191 offset_size = 8;
192 else
193 offset_size = 4;
Ulrich Drepperc57b65c2008-01-18 20:02:36 +0000194 new_arange->arange.offset = DIE_OFFSET_FROM_CU_OFFSET (offset,
Roland McGrath3e0f7d12010-06-15 23:10:35 -0700195 offset_size,
196 false);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000197
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000198 new_arange->next = arangelist;
199 arangelist = new_arange;
200 ++narangelist;
Roland McGrath5f95e2b2010-10-05 00:56:30 -0700201
202 /* Sanity-check the data. */
203 if (unlikely (new_arange->arange.offset
204 >= dbg->sectiondata[IDX_debug_info]->d_size))
205 goto invalid;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000206 }
207 }
208
209 if (narangelist == 0)
210 {
Roland McGrath5f95e2b2010-10-05 00:56:30 -0700211 assert (arangelist == NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000212 if (naranges != NULL)
213 *naranges = 0;
214 *aranges = NULL;
215 return 0;
216 }
217
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);
222
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 *));
Roland McGrath5f95e2b2010-10-05 00:56:30 -0700227 struct arangelist **sortaranges
228 = (buf + sizeof (Dwarf_Aranges)
229 + ((sizeof (Dwarf_Arange) - sizeof sortaranges[0]) * narangelist));
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000230
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;
235 while (i-- > 0)
236 {
Roland McGrath5f95e2b2010-10-05 00:56:30 -0700237 sortaranges[i] = arangelist;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000238 arangelist = arangelist->next;
239 }
240 assert (arangelist == NULL);
241
242 /* Sort by ascending address. */
243 qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
244
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. */
248 *aranges = buf;
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)
Roland McGrath5f95e2b2010-10-05 00:56:30 -0700255 {
256 struct arangelist *elt = sortaranges[i];
257 (*aranges)->info[i] = elt->arange;
258 free (elt);
259 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000260
261 return 0;
262}
263INTDEF(dwarf_getaranges)