blob: 22a3944fd2e8734516abff03f390dd6d68db60ec [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Return location expression list.
2 Copyright (C) 2000, 2001, 2002 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 <stdlib.h>
21
22#include <libdwarfP.h>
23
24
25struct loclist
26{
27 Dwarf_Small atom;
28 Dwarf_Unsigned number;
29 Dwarf_Unsigned number2;
30 Dwarf_Unsigned offset;
31 struct loclist *next;
32};
33
34struct locdesclist
35{
36 Dwarf_Addr lopc;
37 Dwarf_Addr hipc;
38 Dwarf_Half cents;
39 struct loclist *s;
40 struct locdesclist *next;
41};
42
43
44int
45dwarf_loclist (attr, llbuf, listlen, error)
46 Dwarf_Attribute attr;
47 Dwarf_Locdesc **llbuf;
48 Dwarf_Signed *listlen;
49 Dwarf_Error *error;
50{
51 Dwarf_CU_Info cu = attr->cu;
52 Dwarf_Debug dbg = cu->dbg;
53 Dwarf_Unsigned offset;
54 Dwarf_Unsigned offset_end;
55 Dwarf_Small *locp;
56 struct locdesclist *locdesclist;
57 Dwarf_Locdesc *result;
58 unsigned int n;
59
60 /* Must by one of the attribute listed below. */
61 if (attr->code != DW_AT_location
62 && attr->code != DW_AT_data_member_location
63 && attr->code != DW_AT_vtable_elem_location
64 && attr->code != DW_AT_string_length
65 && attr->code != DW_AT_use_location
66 && attr->code != DW_AT_return_addr)
67 {
68 __libdwarf_error (dbg, error, DW_E_WRONG_ATTR);
69 return DW_DLV_ERROR;
70 }
71
72 /* Must have the form data4 or data8 which act as an offset. */
73 if (attr->form == DW_FORM_data4)
74 offset = read_4ubyte_unaligned (dbg, attr->valp);
75 else if (likely (attr->form == DW_FORM_data8))
76 offset = read_8ubyte_unaligned (dbg, attr->valp);
77 else
78 {
79 __libdwarf_error (dbg, error, DW_E_NO_DATA);
80 return DW_DLV_ERROR;
81 }
82
83 /* Check whether the .debug_loc section is available. */
84 if (unlikely (dbg->sections[IDX_debug_loc].addr == NULL))
85 {
86 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
87 return DW_DLV_ERROR;
88 }
89
90 /* This is the part of the .debug_loc section we can read. */
91 locp = (Dwarf_Small *) dbg->sections[IDX_debug_loc].addr + offset;
92 offset_end = offset + dbg->sections[IDX_debug_loc].size;
93
94 locdesclist = NULL;
95 n = 0;
96 while (1)
97 {
98 Dwarf_Addr lopc;
99 Dwarf_Addr hipc;
100 Dwarf_Ptr data;
101 Dwarf_Unsigned len2;
102 struct locdesclist *newdesc;
103 Dwarf_Small *locp;
104 Dwarf_Small *blkendp;
105 Dwarf_Small *blkstartp;
106
107 if (unlikely (dwarf_get_loclist_entry (dbg, offset, &hipc, &lopc, &data,
108 &len2, &offset, error)
109 != DW_DLV_OK))
110 return DW_DLV_ERROR;
111
112 /* Does this signal the end? */
113 if (lopc == 0 && hipc == 0)
114 break;
115
116 locp = data;
117 blkstartp = locp;
118 blkendp = locp + len2;
119
120 /* Create a new Locdesc entry. */
121 newdesc = (struct locdesclist *) alloca (sizeof (struct locdesclist));
122 newdesc->lopc = lopc;
123 newdesc->hipc = hipc;
124 newdesc->cents = 0;
125 newdesc->s = NULL;
126 newdesc->next = locdesclist;
127 locdesclist = newdesc;
128 ++n;
129
130 /* Decode the opcodes. It is possible in some situations to
131 have a block of size zero. */
132 while (locp < blkendp)
133 {
134 struct loclist *newloc;
135
136 newloc = (struct loclist *) alloca (sizeof (struct loclist));
137 newloc->number = 0;
138 newloc->number2 = 0;
139 newloc->offset = locp - blkstartp;
140 newloc->next = newdesc->s;
141 newdesc->s = newloc;
142 ++newdesc->cents;
143
144 newloc->atom = *locp;
145 switch (*locp++)
146 {
147 case DW_OP_addr:
148 /* Address, depends on address size of CU. */
149 if (cu->address_size == 4)
150 {
151 if (unlikely (locp + 4 > blkendp))
152 {
153 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
154 return DW_DLV_ERROR;
155 }
156 newloc->number = read_4ubyte_unaligned (dbg, locp);
157 locp += 4;
158 }
159 else
160 {
161 if (unlikely (locp + 8 > blkendp))
162 {
163 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
164 return DW_DLV_ERROR;
165 }
166 newloc->number = read_8ubyte_unaligned (dbg, locp);
167 locp += 8;
168 }
169 break;
170
171 case DW_OP_deref:
172 case DW_OP_dup:
173 case DW_OP_drop:
174 case DW_OP_over:
175 case DW_OP_swap:
176 case DW_OP_rot:
177 case DW_OP_xderef:
178 case DW_OP_abs:
179 case DW_OP_and:
180 case DW_OP_div:
181 case DW_OP_minus:
182 case DW_OP_mod:
183 case DW_OP_mul:
184 case DW_OP_neg:
185 case DW_OP_not:
186 case DW_OP_or:
187 case DW_OP_plus:
188 case DW_OP_shl:
189 case DW_OP_shr:
190 case DW_OP_shra:
191 case DW_OP_xor:
192 case DW_OP_eq:
193 case DW_OP_ge:
194 case DW_OP_gt:
195 case DW_OP_le:
196 case DW_OP_lt:
197 case DW_OP_ne:
198 case DW_OP_lit0:
199 case DW_OP_lit1:
200 case DW_OP_lit2:
201 case DW_OP_lit3:
202 case DW_OP_lit4:
203 case DW_OP_lit5:
204 case DW_OP_lit6:
205 case DW_OP_lit7:
206 case DW_OP_lit8:
207 case DW_OP_lit9:
208 case DW_OP_lit10:
209 case DW_OP_lit11:
210 case DW_OP_lit12:
211 case DW_OP_lit13:
212 case DW_OP_lit14:
213 case DW_OP_lit15:
214 case DW_OP_lit16:
215 case DW_OP_lit17:
216 case DW_OP_lit18:
217 case DW_OP_lit19:
218 case DW_OP_lit20:
219 case DW_OP_lit21:
220 case DW_OP_lit22:
221 case DW_OP_lit23:
222 case DW_OP_lit24:
223 case DW_OP_lit25:
224 case DW_OP_lit26:
225 case DW_OP_lit27:
226 case DW_OP_lit28:
227 case DW_OP_lit29:
228 case DW_OP_lit30:
229 case DW_OP_lit31:
230 case DW_OP_reg0:
231 case DW_OP_reg1:
232 case DW_OP_reg2:
233 case DW_OP_reg3:
234 case DW_OP_reg4:
235 case DW_OP_reg5:
236 case DW_OP_reg6:
237 case DW_OP_reg7:
238 case DW_OP_reg8:
239 case DW_OP_reg9:
240 case DW_OP_reg10:
241 case DW_OP_reg11:
242 case DW_OP_reg12:
243 case DW_OP_reg13:
244 case DW_OP_reg14:
245 case DW_OP_reg15:
246 case DW_OP_reg16:
247 case DW_OP_reg17:
248 case DW_OP_reg18:
249 case DW_OP_reg19:
250 case DW_OP_reg20:
251 case DW_OP_reg21:
252 case DW_OP_reg22:
253 case DW_OP_reg23:
254 case DW_OP_reg24:
255 case DW_OP_reg25:
256 case DW_OP_reg26:
257 case DW_OP_reg27:
258 case DW_OP_reg28:
259 case DW_OP_reg29:
260 case DW_OP_reg30:
261 case DW_OP_reg31:
262 case DW_OP_nop:
263 case DW_OP_push_object_address:
264 case DW_OP_call_ref:
265 /* No operand. */
266 break;
267
268 case DW_OP_const1u:
269 case DW_OP_pick:
270 case DW_OP_deref_size:
271 case DW_OP_xderef_size:
272 if (unlikely (locp >= blkendp))
273 {
274 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
275 return DW_DLV_ERROR;
276 }
277 newloc->number = *((uint8_t *) locp)++;
278 break;
279
280 case DW_OP_const1s:
281 if (unlikely (locp >= blkendp))
282 {
283 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
284 return DW_DLV_ERROR;
285 }
286 newloc->number = *((int8_t *) locp)++;
287 break;
288
289 case DW_OP_const2u:
290 if (unlikely (locp + 2 > blkendp))
291 {
292 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
293 return DW_DLV_ERROR;
294 }
295 newloc->number = read_2ubyte_unaligned (dbg, locp);
296 locp += 2;
297 break;
298
299 case DW_OP_const2s:
300 case DW_OP_skip:
301 case DW_OP_bra:
302 case DW_OP_call2:
303 if (unlikely (locp + 2 > blkendp))
304 {
305 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
306 return DW_DLV_ERROR;
307 }
308 newloc->number = read_2sbyte_unaligned (dbg, locp);
309 locp += 2;
310 break;
311
312 case DW_OP_const4u:
313 if (unlikely (locp + 4 > blkendp))
314 {
315 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
316 return DW_DLV_ERROR;
317 }
318 newloc->number = read_4ubyte_unaligned (dbg, locp);
319 locp += 4;
320 break;
321
322 case DW_OP_const4s:
323 case DW_OP_call4:
324 if (unlikely (locp + 4 > blkendp))
325 {
326 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
327 return DW_DLV_ERROR;
328 }
329 newloc->number = read_4sbyte_unaligned (dbg, locp);
330 locp += 4;
331 break;
332
333 case DW_OP_const8u:
334 if (unlikely (locp + 8 > blkendp))
335 {
336 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
337 return DW_DLV_ERROR;
338 }
339 newloc->number = read_8ubyte_unaligned (dbg, locp);
340 locp += 8;
341 break;
342
343 case DW_OP_const8s:
344 if (unlikely (locp + 8 > blkendp))
345 {
346 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
347 return DW_DLV_ERROR;
348 }
349 newloc->number = read_8sbyte_unaligned (dbg, locp);
350 locp += 8;
351 break;
352
353 case DW_OP_constu:
354 case DW_OP_plus_uconst:
355 case DW_OP_regx:
356 case DW_OP_piece:
357 /* XXX Check size. */
358 get_uleb128 (newloc->number, locp);
359 break;
360
361 case DW_OP_consts:
362 case DW_OP_breg0:
363 case DW_OP_breg1:
364 case DW_OP_breg2:
365 case DW_OP_breg3:
366 case DW_OP_breg4:
367 case DW_OP_breg5:
368 case DW_OP_breg6:
369 case DW_OP_breg7:
370 case DW_OP_breg8:
371 case DW_OP_breg9:
372 case DW_OP_breg10:
373 case DW_OP_breg11:
374 case DW_OP_breg12:
375 case DW_OP_breg13:
376 case DW_OP_breg14:
377 case DW_OP_breg15:
378 case DW_OP_breg16:
379 case DW_OP_breg17:
380 case DW_OP_breg18:
381 case DW_OP_breg19:
382 case DW_OP_breg20:
383 case DW_OP_breg21:
384 case DW_OP_breg22:
385 case DW_OP_breg23:
386 case DW_OP_breg24:
387 case DW_OP_breg25:
388 case DW_OP_breg26:
389 case DW_OP_breg27:
390 case DW_OP_breg28:
391 case DW_OP_breg29:
392 case DW_OP_breg30:
393 case DW_OP_breg31:
394 case DW_OP_fbreg:
395 /* XXX Check size. */
396 get_sleb128 (newloc->number, locp);
397 break;
398
399 case DW_OP_bregx:
400 /* XXX Check size. */
401 get_uleb128 (newloc->number, locp);
402 get_sleb128 (newloc->number2, locp);
403 break;
404
405 default:
406 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
407 return DW_DLV_ERROR;
408 }
409 }
410 }
411
412 if (unlikely (n == 0))
413 {
414 /* This is not allowed.
415
416 XXX Is it? */
417 __libdwarf_error (dbg, error, DW_E_INVALID_DWARF);
418 return DW_DLV_ERROR;
419 }
420
421 /* Allocate the array. */
422 result = (Dwarf_Locdesc *) malloc (n * sizeof (Dwarf_Locdesc));
423 if (result == NULL)
424 {
425 __libdwarf_error (dbg, error, DW_E_NOMEM);
426 return DW_DLV_ERROR;
427 }
428
429 /* Store the result. */
430 *llbuf = result;
431 *listlen = n;
432
433 do
434 {
435 unsigned int cents;
436 struct loclist *s;
437
438 /* We populate the array from the back since the list is
439 backwards. */
440 --n;
441
442 result[n].ld_lopc = locdesclist->lopc;
443 result[n].ld_hipc = locdesclist->hipc;
444 result[n].ld_cents = cents = locdesclist->cents;
445 result[n].ld_s = (Dwarf_Loc *) malloc (cents * sizeof (Dwarf_Loc));
446 if (result == NULL)
447 {
448 /* XXX Should be bother freeing memory? */
449 __libdwarf_error (dbg, error, DW_E_NOMEM);
450 return DW_DLV_ERROR;
451 }
452
453 s = locdesclist->s;
454 while (cents-- > 0)
455 {
456 /* This list is also backwards. */
457 result[n].ld_s[cents].lr_atom = s->atom;
458 result[n].ld_s[cents].lr_number = s->number;
459 result[n].ld_s[cents].lr_number2 = s->number2;
460 result[n].ld_s[cents].lr_offset = s->offset;
461 s = s->next;
462 }
463
464 locdesclist = locdesclist->next;
465 }
466 while (n > 0);
467
468 /* We did it. */
469 return DW_DLV_OK;
470}