blob: f7cf050f5ed73d9acd2bcfa1f19af0c64c9cff18 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Return list address ranges.
2 Copyright (C) 2000, 2001, 2002, 2004, 2005 Red Hat, Inc.
3 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
4
5 This program is Open Source software; you can redistribute it and/or
6 modify it under the terms of the Open Software License version 1.0 as
7 published by the Open Source Initiative.
8
9 You should have received a copy of the Open Software License along
10 with this program; if not, you may obtain a copy of the Open Software
11 License version 1.0 from http://www.opensource.org/licenses/osl.php or
12 by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
13 3001 King Ranch Road, Ukiah, CA 95482. */
14
15#ifdef HAVE_CONFIG_H
16# include <config.h>
17#endif
18
19#include <stdlib.h>
20#include <assert.h>
21#include "libdwP.h"
22
23
24struct arangelist
25{
26 Dwarf_Arange arange;
27 struct arangelist *next;
28};
29
30/* Compare by Dwarf_Arange.addr, given pointers into an array of pointeers. */
31static int
32compare_aranges (const void *a, const void *b)
33{
34 Dwarf_Arange *const *p1 = a, *const *p2 = b;
35 Dwarf_Arange *l1 = *p1, *l2 = *p2;
36 return l1->addr - l2->addr;
37}
38
39int
40dwarf_getaranges (dbg, aranges, naranges)
41 Dwarf *dbg;
42 Dwarf_Aranges **aranges;
43 size_t *naranges;
44{
45 if (dbg == NULL)
46 return -1;
47
48 if (dbg->aranges != NULL)
49 {
50 *aranges = dbg->aranges;
51 if (naranges != NULL)
52 *naranges = dbg->aranges->naranges;
53 return 0;
54 }
55
56 if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
57 return -1;
58
59 struct arangelist *arangelist = NULL;
60 unsigned int narangelist = 0;
61
62 const char *readp
63 = (const char *) dbg->sectiondata[IDX_debug_aranges]->d_buf;
64 const char *readendp = readp + dbg->sectiondata[IDX_debug_aranges]->d_size;
65
66 while (readp < readendp)
67 {
68 const char *hdrstart = readp;
69
70 /* Each entry starts with a header:
71
72 1. A 4-byte or 12-byte length containing the length of the
73 set of entries for this compilation unit, not including the
74 length field itself. [...]
75
76 2. A 2-byte version identifier containing the value 2 for
77 DWARF Version 2.1.
78
79 3. A 4-byte or 8-byte offset into the .debug_info section. [...]
80
81 4. A 1-byte unsigned integer containing the size in bytes of
82 an address (or the offset portion of an address for segmented
83 addressing) on the target system.
84
85 5. A 1-byte unsigned integer containing the size in bytes of
86 a segment descriptor on the target system. */
87 Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
88 unsigned int length_bytes = 4;
89 if (length == 0xffffffff)
90 {
91 length = read_8ubyte_unaligned_inc (dbg, readp);
92 length_bytes = 8;
93 }
94
95 unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
96 if (version != 2)
97 {
98 invalid:
99 __libdw_seterrno (DWARF_E_INVALID_DWARF);
100 return -1;
101 }
102
103 Dwarf_Word offset;
104 if (length_bytes == 4)
105 offset = read_4ubyte_unaligned_inc (dbg, readp);
106 else
107 offset = read_8ubyte_unaligned_inc (dbg, readp);
108
109 unsigned int address_size = *readp++;
110 if (address_size != 4 && address_size != 8)
111 goto invalid;
112
113 /* Ignore the segment size value. */
114 // XXX Really?
115 (void) *readp++;
116
117 /* Round the address to the next multiple of 2*address_size. */
118 readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
119 % (2 * address_size));
120
121 while (1)
122 {
123 Dwarf_Word range_address;
124 Dwarf_Word range_length;
125
126 if (address_size == 4)
127 {
128 range_address = read_4ubyte_unaligned_inc (dbg, readp);
129 range_length = read_4ubyte_unaligned_inc (dbg, readp);
130 }
131 else
132 {
133 range_address = read_8ubyte_unaligned_inc (dbg, readp);
134 range_length = read_8ubyte_unaligned_inc (dbg, readp);
135 }
136
137 /* Two zero values mark the end. */
138 if (range_address == 0 && range_length == 0)
139 break;
140
141 struct arangelist *new_arange =
142 (struct arangelist *) alloca (sizeof (struct arangelist));
143
144 new_arange->arange.addr = range_address;
145 new_arange->arange.length = range_length;
146
147 /* We store the actual CU DIE offset, not the CU header offset. */
148 const char *cu_header = (dbg->sectiondata[IDX_debug_info]->d_buf
149 + offset);
150 unsigned int offset_size;
151 if (read_4ubyte_unaligned_noncvt (cu_header) == 0xffffffff)
152 offset_size = 8;
153 else
154 offset_size = 4;
155 new_arange->arange.offset = offset + 3 * offset_size - 4 + 3;
156
157 new_arange->next = arangelist;
158 arangelist = new_arange;
159 ++narangelist;
160 }
161 }
162
163 if (narangelist == 0)
164 {
165 if (naranges != NULL)
166 *naranges = 0;
167 *aranges = NULL;
168 return 0;
169 }
170
171 /* Allocate the array for the result. */
172 void *buf = libdw_alloc (dbg, Dwarf_Aranges,
173 sizeof (Dwarf_Aranges)
174 + narangelist * sizeof (Dwarf_Arange), 1);
175
176 /* First use the buffer for the pointers, and sort the entries.
177 We'll write the pointers in the end of the buffer, and then
178 copy into the buffer from the beginning so the overlap works. */
179 assert (sizeof (Dwarf_Arange) >= sizeof (Dwarf_Arange *));
180 Dwarf_Arange **sortaranges = (buf + sizeof (Dwarf_Aranges)
181 + ((sizeof (Dwarf_Arange)
182 - sizeof (Dwarf_Arange *)) * narangelist));
183
184 /* The list is in LIFO order and usually they come in clumps with
185 ascending addresses. So fill from the back to probably start with
186 runs already in order before we sort. */
187 unsigned int i = narangelist;
188 while (i-- > 0)
189 {
190 sortaranges[i] = &arangelist->arange;
191 arangelist = arangelist->next;
192 }
193 assert (arangelist == NULL);
194
195 /* Sort by ascending address. */
196 qsort (sortaranges, narangelist, sizeof sortaranges[0], &compare_aranges);
197
198 /* Now that they are sorted, put them in the final array.
199 The buffers overlap, so we've clobbered the early elements
200 of SORTARANGES by the time we're reading the later ones. */
201 *aranges = buf;
202 (*aranges)->dbg = dbg;
203 (*aranges)->naranges = narangelist;
204 dbg->aranges = *aranges;
205 if (naranges != NULL)
206 *naranges = narangelist;
207 for (i = 0; i < narangelist; ++i)
208 (*aranges)->info[i] = *sortaranges[i];
209
210 return 0;
211}
212INTDEF(dwarf_getaranges)