blob: 6339a8c89a783a35d6dba79dc5093bc42662fa9a [file] [log] [blame]
The Android Open Source Project593c3652008-10-21 07:00:00 -07001/* Return location expression list.
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 <dwarf.h>
20#include <search.h>
21#include <stdlib.h>
22
23#include <libdwP.h>
24
25
26struct loclist
27{
28 uint8_t atom;
29 Dwarf_Word number;
30 Dwarf_Word number2;
31 Dwarf_Word offset;
32 struct loclist *next;
33};
34
35
36static int
37loc_compare (const void *p1, const void *p2)
38{
39 const struct loc_s *l1 = (const struct loc_s *) p1;
40 const struct loc_s *l2 = (const struct loc_s *) p2;
41
42 if ((uintptr_t) l1->addr < (uintptr_t) l2->addr)
43 return -1;
44 if ((uintptr_t) l1->addr > (uintptr_t) l2->addr)
45 return 1;
46
47 return 0;
48}
49
50
51int
52dwarf_getloclist (attr, llbuf, listlen)
53 Dwarf_Attribute *attr;
54 Dwarf_Loc **llbuf;
55 size_t *listlen;
56{
57 /* Must by one of the attribute listed below. */
58 if (attr->code != DW_AT_location
59 && attr->code != DW_AT_data_member_location
60 && attr->code != DW_AT_vtable_elem_location
61 && attr->code != DW_AT_string_length
62 && attr->code != DW_AT_use_location
63 && attr->code != DW_AT_return_addr)
64 {
65 __libdw_seterrno (DWARF_E_NO_LOCLIST);
66 return -1;
67 }
68
69 struct Dwarf_CU *cu = attr->cu;
70 Dwarf *dbg = cu->dbg;
71
72 /* Must have the form data4 or data8 which act as an offset. */
73 Dwarf_Block block;
74 if (dwarf_formblock (attr, &block) != 0)
75 return -1;
76
77 /* Check whether we already looked at this list. */
78 struct loc_s fake = { .addr = block.data };
79 struct loc_s **found = tfind (&fake, &cu->locs, loc_compare);
80 if (found != NULL)
81 {
82 /* We already saw it. */
83 *llbuf = (*found)->loc;
84 *listlen = (*found)->nloc;
85
86 return 0;
87 }
88
89 unsigned char *data = block.data;
90 unsigned char *const end_data = data + block.length;
91
92 struct loclist *loclist = NULL;
93 unsigned int n = 0;
94 /* Decode the opcodes. It is possible in some situations to have a
95 block of size zero. */
96 while (data < end_data)
97 {
98 struct loclist *newloc;
99 newloc = (struct loclist *) alloca (sizeof (struct loclist));
100 newloc->number = 0;
101 newloc->number2 = 0;
102 newloc->offset = data - block.data;
103 newloc->next = loclist;
104 loclist = newloc;
105 ++n;
106
107 switch ((newloc->atom = *data++))
108 {
109 case DW_OP_addr:
110 /* Address, depends on address size of CU. */
111 if (cu->address_size == 4)
112 {
113 if (unlikely (data + 4 > end_data))
114 {
115 invalid:
116 __libdw_seterrno (DWARF_E_INVALID_DWARF);
117 return -1;
118 }
119
120 newloc->number = read_4ubyte_unaligned_inc (dbg, data);
121 }
122 else
123 {
124 if (unlikely (data + 8 > end_data))
125 goto invalid;
126
127 newloc->number = read_8ubyte_unaligned_inc (dbg, data);
128 }
129 break;
130
131 case DW_OP_deref:
132 case DW_OP_dup:
133 case DW_OP_drop:
134 case DW_OP_over:
135 case DW_OP_swap:
136 case DW_OP_rot:
137 case DW_OP_xderef:
138 case DW_OP_abs:
139 case DW_OP_and:
140 case DW_OP_div:
141 case DW_OP_minus:
142 case DW_OP_mod:
143 case DW_OP_mul:
144 case DW_OP_neg:
145 case DW_OP_not:
146 case DW_OP_or:
147 case DW_OP_plus:
148 case DW_OP_shl:
149 case DW_OP_shr:
150 case DW_OP_shra:
151 case DW_OP_xor:
152 case DW_OP_eq:
153 case DW_OP_ge:
154 case DW_OP_gt:
155 case DW_OP_le:
156 case DW_OP_lt:
157 case DW_OP_ne:
158 case DW_OP_lit0 ... DW_OP_lit31:
159 case DW_OP_reg0 ... DW_OP_reg31:
160 case DW_OP_nop:
161 case DW_OP_push_object_address:
162 case DW_OP_call_ref:
163 /* No operand. */
164 break;
165
166 case DW_OP_const1u:
167 case DW_OP_pick:
168 case DW_OP_deref_size:
169 case DW_OP_xderef_size:
170 if (unlikely (data >= end_data))
171 goto invalid;
172
173 newloc->number = *data++;
174 break;
175
176 case DW_OP_const1s:
177 if (unlikely (data >= end_data))
178 goto invalid;
179
180 newloc->number = *((int8_t *) data);
181 ++data;
182 break;
183
184 case DW_OP_const2u:
185 if (unlikely (data + 2 > end_data))
186 goto invalid;
187
188 newloc->number = read_2ubyte_unaligned_inc (dbg, data);
189 break;
190
191 case DW_OP_const2s:
192 case DW_OP_skip:
193 case DW_OP_bra:
194 case DW_OP_call2:
195 if (unlikely (data + 2 > end_data))
196 goto invalid;
197
198 newloc->number = read_2sbyte_unaligned_inc (dbg, data);
199 break;
200
201 case DW_OP_const4u:
202 if (unlikely (data + 4 > end_data))
203 goto invalid;
204
205 newloc->number = read_4ubyte_unaligned_inc (dbg, data);
206 break;
207
208 case DW_OP_const4s:
209 case DW_OP_call4:
210 if (unlikely (data + 4 > end_data))
211 goto invalid;
212
213 newloc->number = read_4sbyte_unaligned_inc (dbg, data);
214 break;
215
216 case DW_OP_const8u:
217 if (unlikely (data + 8 > end_data))
218 goto invalid;
219
220 newloc->number = read_8ubyte_unaligned_inc (dbg, data);
221 break;
222
223 case DW_OP_const8s:
224 if (unlikely (data + 8 > end_data))
225 goto invalid;
226
227 newloc->number = read_8sbyte_unaligned_inc (dbg, data);
228 break;
229
230 case DW_OP_constu:
231 case DW_OP_plus_uconst:
232 case DW_OP_regx:
233 case DW_OP_piece:
234 /* XXX Check size. */
235 get_uleb128 (newloc->number, data);
236 break;
237
238 case DW_OP_consts:
239 case DW_OP_breg0 ... DW_OP_breg31:
240 case DW_OP_fbreg:
241 /* XXX Check size. */
242 get_sleb128 (newloc->number, data);
243 break;
244
245 case DW_OP_bregx:
246 /* XXX Check size. */
247 get_uleb128 (newloc->number, data);
248 get_sleb128 (newloc->number2, data);
249 break;
250
251 default:
252 goto invalid;
253 }
254 }
255
256 if (unlikely (n == 0))
257 {
258 /* This is not allowed.
259
260 XXX Is it? */
261 goto invalid;
262 }
263
264 /* Allocate the array. */
265 Dwarf_Loc *result = libdw_alloc (dbg, Dwarf_Loc, sizeof (Dwarf_Loc), n);
266
267 /* Store the result. */
268 *llbuf = result;
269 *listlen = n;
270
271 do
272 {
273 /* We populate the array from the back since the list is
274 backwards. */
275 --n;
276 result[n].atom = loclist->atom;
277 result[n].number = loclist->number;
278 result[n].number2 = loclist->number2;
279 result[n].offset = loclist->offset;
280
281 loclist = loclist->next;
282 }
283 while (n > 0);
284
285 /* Insert a record in the search tree so that we can find it again
286 later. */
287 struct loc_s *newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s),
288 1);
289 newp->addr = block.data;
290 newp->loc = result;
291 newp->nloc = *listlen;
292 (void) tsearch (newp, &cu->locs, loc_compare);
293
294 /* We did it. */
295 return 0;
296}