1 /* Return list address ranges.
2 Copyright (C) 2000, 2001, 2002, 2004 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
21 #include <libdwP.h>
22
23
24 struct arangelist
25 {
26 Dwarf_Arange arange;
27 struct arangelist *next;
28 };
29
30
31 int
dwarf_getaranges(dbg,aranges,naranges)32 dwarf_getaranges (dbg, aranges, naranges)
33 Dwarf *dbg;
34 Dwarf_Aranges **aranges;
35 size_t *naranges;
36 {
37 if (dbg == NULL)
38 return -1;
39
40 if (dbg->aranges != NULL)
41 {
42 *aranges = dbg->aranges;
43 if (naranges != NULL)
44 *naranges = dbg->aranges->naranges;
45 return 0;
46 }
47
48 if (dbg->sectiondata[IDX_debug_aranges]->d_buf == NULL)
49 return -1;
50
51 struct arangelist *arangelist = NULL;
52 unsigned int narangelist = 0;
53
54 const char *readp
55 = (const char *) dbg->sectiondata[IDX_debug_aranges]->d_buf;
56 const char *readendp = readp + dbg->sectiondata[IDX_debug_aranges]->d_size;
57
58 while (readp < readendp)
59 {
60 const char *hdrstart = readp;
61
62 /* Each entry starts with a header:
63
64 1. A 4-byte or 12-byte length containing the length of the
65 set of entries for this compilation unit, not including the
66 length field itself. [...]
67
68 2. A 2-byte version identifier containing the value 2 for
69 DWARF Version 2.1.
70
71 3. A 4-byte or 8-byte offset into the .debug_info section. [...]
72
73 4. A 1-byte unsigned integer containing the size in bytes of
74 an address (or the offset portion of an address for segmented
75 addressing) on the target system.
76
77 5. A 1-byte unsigned integer containing the size in bytes of
78 a segment descriptor on the target system. */
79 Dwarf_Word length = read_4ubyte_unaligned_inc (dbg, readp);
80 unsigned int length_bytes = 4;
81 if (length == 0xffffffff)
82 {
83 length = read_8ubyte_unaligned_inc (dbg, readp);
84 length_bytes = 8;
85 }
86
87 unsigned int version = read_2ubyte_unaligned_inc (dbg, readp);
88 if (version != 2)
89 {
90 invalid:
91 __libdw_seterrno (DWARF_E_INVALID_DWARF);
92 return -1;
93 }
94
95 Dwarf_Word offset;
96 if (length_bytes == 4)
97 offset = read_4ubyte_unaligned_inc (dbg, readp);
98 else
99 offset = read_8ubyte_unaligned_inc (dbg, readp);
100
101 unsigned int address_size = *readp++;
102 if (address_size != 4 && address_size != 8)
103 goto invalid;
104
105 /* Ignore the segment size value. */
106 // XXX Really?
107 (void) *readp++;
108
109 /* Round the address to the next multiple of 2*address_size. */
110 readp += ((2 * address_size - ((readp - hdrstart) % (2 * address_size)))
111 % (2 * address_size));
112
113 //arange_info->offset = offset;
114
115 while (1)
116 {
117 Dwarf_Word range_address;
118 Dwarf_Word range_length;
119
120 if (address_size == 4)
121 {
122 range_address = read_4ubyte_unaligned_inc (dbg, readp);
123 range_length = read_4ubyte_unaligned_inc (dbg, readp);
124 }
125 else
126 {
127 range_address = read_8ubyte_unaligned_inc (dbg, readp);
128 range_length = read_8ubyte_unaligned_inc (dbg, readp);
129 }
130
131 /* Two zero values mark the end. */
132 if (range_address == 0 && range_length == 0)
133 break;
134
135 struct arangelist *new_arange =
136 (struct arangelist *) alloca (sizeof (struct arangelist));
137
138 new_arange->arange.addr = range_address;
139 new_arange->arange.length = range_length;
140
141 /* We store the actual CU DIE offset, not the CU header offset. */
142 const char *cu_header = (dbg->sectiondata[IDX_debug_info]->d_buf
143 + offset);
144 unsigned int offset_size;
145 if (read_4ubyte_unaligned_noncvt (cu_header) == 0xffffffff)
146 offset_size = 8;
147 else
148 offset_size = 4;
149 new_arange->arange.offset = offset + 3 * offset_size - 4 + 3;
150
151 new_arange->next = arangelist;
152 arangelist = new_arange;
153 ++narangelist;
154 }
155 }
156
157 if (narangelist == 0)
158 {
159 if (naranges != NULL)
160 *naranges = 0;
161 *aranges = NULL;
162 return 0;
163 }
164
165 /* Allocate the array for the result. */
166 if (naranges != NULL)
167 *naranges = narangelist;
168 *aranges = libdw_alloc (dbg, Dwarf_Aranges,
169 sizeof (Dwarf_Aranges)
170 + narangelist * sizeof (Dwarf_Arange), 1);
171
172 (*aranges)->dbg = dbg;
173 (*aranges)->naranges = narangelist;
174
175 while (narangelist-- > 0)
176 {
177 (*aranges)->info[narangelist] = arangelist->arange;
178 arangelist = arangelist->next;
179 }
180
181 dbg->aranges = *aranges;
182
183 return 0;
184 }
185