Line data Source code
1 : /* Return location expression list.
2 : Copyright (C) 2000-2010, 2013-2015 Red Hat, Inc.
3 : This file is part of elfutils.
4 : Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5 :
6 : This file is free software; you can redistribute it and/or modify
7 : it under the terms of either
8 :
9 : * 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
22 : 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 :
26 : 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/>. */
29 :
30 : #ifdef HAVE_CONFIG_H
31 : # include <config.h>
32 : #endif
33 :
34 : #include <dwarf.h>
35 : #include <search.h>
36 : #include <stdlib.h>
37 : #include <assert.h>
38 :
39 : #include <libdwP.h>
40 :
41 :
42 : static bool
43 835 : attr_ok (Dwarf_Attribute *attr)
44 : {
45 835 : if (attr == NULL)
46 : return false;
47 :
48 : /* Must be one of the attributes listed below. */
49 835 : switch (attr->code)
50 : {
51 : case DW_AT_location:
52 : case DW_AT_data_member_location:
53 : case DW_AT_vtable_elem_location:
54 : case DW_AT_string_length:
55 : case DW_AT_use_location:
56 : case DW_AT_frame_base:
57 : case DW_AT_return_addr:
58 : case DW_AT_static_link:
59 : case DW_AT_segment:
60 : case DW_AT_GNU_call_site_value:
61 : case DW_AT_GNU_call_site_data_value:
62 : case DW_AT_GNU_call_site_target:
63 : case DW_AT_GNU_call_site_target_clobbered:
64 : break;
65 :
66 : default:
67 0 : __libdw_seterrno (DWARF_E_NO_LOCLIST);
68 0 : return false;
69 : }
70 :
71 : return true;
72 : }
73 :
74 :
75 : struct loclist
76 : {
77 : uint8_t atom;
78 : Dwarf_Word number;
79 : Dwarf_Word number2;
80 : Dwarf_Word offset;
81 : struct loclist *next;
82 : };
83 :
84 :
85 : static int
86 5286 : loc_compare (const void *p1, const void *p2)
87 : {
88 5286 : const struct loc_s *l1 = (const struct loc_s *) p1;
89 5286 : const struct loc_s *l2 = (const struct loc_s *) p2;
90 :
91 5286 : if ((uintptr_t) l1->addr < (uintptr_t) l2->addr)
92 : return -1;
93 5263 : if ((uintptr_t) l1->addr > (uintptr_t) l2->addr)
94 : return 1;
95 :
96 48 : return 0;
97 : }
98 :
99 : /* For each DW_OP_implicit_value, we store a special entry in the cache.
100 : This points us directly to the block data for later fetching. */
101 : static void
102 2 : store_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op)
103 : {
104 2 : struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s,
105 : sizeof (struct loc_block_s), 1);
106 2 : const unsigned char *data = (const unsigned char *) (uintptr_t) op->number2;
107 : // Ignored, equal to op->number. And data length already checked.
108 2 : (void) __libdw_get_uleb128 (&data, data + len_leb128 (Dwarf_Word));
109 2 : block->addr = op;
110 2 : block->data = (unsigned char *) data;
111 2 : block->length = op->number;
112 2 : (void) tsearch (block, cache, loc_compare);
113 2 : }
114 :
115 : int
116 2 : dwarf_getlocation_implicit_value (Dwarf_Attribute *attr, const Dwarf_Op *op,
117 : Dwarf_Block *return_block)
118 : {
119 2 : if (attr == NULL)
120 : return -1;
121 :
122 2 : struct loc_block_s fake = { .addr = (void *) op };
123 2 : struct loc_block_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
124 2 : if (unlikely (found == NULL))
125 : {
126 0 : __libdw_seterrno (DWARF_E_NO_BLOCK);
127 0 : return -1;
128 : }
129 :
130 2 : return_block->length = (*found)->length;
131 2 : return_block->data = (*found)->data;
132 2 : return 0;
133 : }
134 :
135 : /* DW_AT_data_member_location can be a constant as well as a loclistptr.
136 : Only data[48] indicate a loclistptr. */
137 : static int
138 814 : check_constant_offset (Dwarf_Attribute *attr,
139 : Dwarf_Op **llbuf, size_t *listlen)
140 : {
141 814 : if (attr->code != DW_AT_data_member_location)
142 : return 1;
143 :
144 0 : switch (attr->form)
145 : {
146 : /* Punt for any non-constant form. */
147 : default:
148 : return 1;
149 :
150 : case DW_FORM_data1:
151 : case DW_FORM_data2:
152 : case DW_FORM_data4:
153 : case DW_FORM_data8:
154 : case DW_FORM_sdata:
155 : case DW_FORM_udata:
156 : break;
157 : }
158 :
159 : /* Check whether we already cached this location. */
160 0 : struct loc_s fake = { .addr = attr->valp };
161 0 : struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
162 :
163 0 : if (found == NULL)
164 : {
165 : Dwarf_Word offset;
166 0 : if (INTUSE(dwarf_formudata) (attr, &offset) != 0)
167 0 : return -1;
168 :
169 0 : Dwarf_Op *result = libdw_alloc (attr->cu->dbg,
170 : Dwarf_Op, sizeof (Dwarf_Op), 1);
171 :
172 0 : result->atom = DW_OP_plus_uconst;
173 0 : result->number = offset;
174 0 : result->number2 = 0;
175 0 : result->offset = 0;
176 :
177 : /* Insert a record in the search tree so we can find it again later. */
178 0 : struct loc_s *newp = libdw_alloc (attr->cu->dbg,
179 : struct loc_s, sizeof (struct loc_s),
180 : 1);
181 0 : newp->addr = attr->valp;
182 0 : newp->loc = result;
183 0 : newp->nloc = 1;
184 :
185 0 : found = tsearch (newp, &attr->cu->locs, loc_compare);
186 : }
187 :
188 0 : assert ((*found)->nloc == 1);
189 :
190 0 : if (llbuf != NULL)
191 : {
192 0 : *llbuf = (*found)->loc;
193 0 : *listlen = 1;
194 : }
195 :
196 : return 0;
197 : }
198 :
199 : int
200 : internal_function
201 832 : __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
202 : unsigned int address_size, unsigned int ref_size,
203 : void **cache, const Dwarf_Block *block,
204 : bool cfap, bool valuep,
205 : Dwarf_Op **llbuf, size_t *listlen, int sec_index)
206 : {
207 : /* Empty location expressions don't have any ops to intern. */
208 832 : if (block->length == 0)
209 : {
210 0 : *listlen = 0;
211 0 : return 0;
212 : }
213 :
214 : /* Check whether we already looked at this list. */
215 832 : struct loc_s fake = { .addr = block->data };
216 832 : struct loc_s **found = tfind (&fake, cache, loc_compare);
217 832 : if (found != NULL)
218 : {
219 : /* We already saw it. */
220 46 : *llbuf = (*found)->loc;
221 46 : *listlen = (*found)->nloc;
222 :
223 46 : if (valuep)
224 : {
225 0 : assert (*listlen > 1);
226 0 : assert ((*llbuf)[*listlen - 1].atom == DW_OP_stack_value);
227 : }
228 :
229 : return 0;
230 : }
231 :
232 786 : const unsigned char *data = block->data;
233 786 : const unsigned char *const end_data = data + block->length;
234 :
235 786 : const struct { bool other_byte_order; } bo = { other_byte_order };
236 :
237 786 : struct loclist *loclist = NULL;
238 786 : unsigned int n = 0;
239 :
240 : /* Stack allocate at most this many locs. */
241 : #define MAX_STACK_LOCS 256
242 : struct loclist stack_locs[MAX_STACK_LOCS];
243 : #define NEW_LOC() ({ struct loclist *ll; \
244 : ll = (likely (n < MAX_STACK_LOCS) \
245 : ? &stack_locs[n] \
246 : : malloc (sizeof (struct loclist))); \
247 : if (unlikely (ll == NULL)) \
248 : goto nomem; \
249 : n++; \
250 : ll->next = loclist; \
251 : loclist = ll; \
252 : ll; })
253 :
254 786 : if (cfap)
255 : {
256 : /* Synthesize the operation to push the CFA before the expression. */
257 5 : struct loclist *newloc = NEW_LOC ();
258 5 : newloc->atom = DW_OP_call_frame_cfa;
259 5 : newloc->number = 0;
260 5 : newloc->number2 = 0;
261 5 : newloc->offset = -1;
262 : }
263 :
264 : /* Decode the opcodes. It is possible in some situations to have a
265 : block of size zero. */
266 2037 : while (data < end_data)
267 : {
268 : struct loclist *newloc;
269 1251 : newloc = NEW_LOC ();
270 1251 : newloc->number = 0;
271 1251 : newloc->number2 = 0;
272 1251 : newloc->offset = data - block->data;
273 :
274 1251 : switch ((newloc->atom = *data++))
275 : {
276 : case DW_OP_addr:
277 : /* Address, depends on address size of CU. */
278 684 : if (dbg == NULL)
279 : {
280 : // XXX relocation?
281 0 : if (address_size == 4)
282 : {
283 0 : if (unlikely (data + 4 > end_data))
284 : goto invalid;
285 : else
286 0 : newloc->number = read_4ubyte_unaligned_inc (&bo, data);
287 : }
288 : else
289 : {
290 0 : if (unlikely (data + 8 > end_data))
291 : goto invalid;
292 : else
293 0 : newloc->number = read_8ubyte_unaligned_inc (&bo, data);
294 : }
295 : }
296 684 : else if (__libdw_read_address_inc (dbg, sec_index, &data,
297 684 : address_size, &newloc->number))
298 : goto invalid;
299 : break;
300 :
301 : case DW_OP_call_ref:
302 : /* DW_FORM_ref_addr, depends on offset size of CU. */
303 0 : if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data,
304 : ref_size,
305 0 : &newloc->number,
306 : IDX_debug_info, 0))
307 : goto invalid;
308 : break;
309 :
310 : case DW_OP_deref:
311 : case DW_OP_dup:
312 : case DW_OP_drop:
313 : case DW_OP_over:
314 : case DW_OP_swap:
315 : case DW_OP_rot:
316 : case DW_OP_xderef:
317 : case DW_OP_abs:
318 : case DW_OP_and:
319 : case DW_OP_div:
320 : case DW_OP_minus:
321 : case DW_OP_mod:
322 : case DW_OP_mul:
323 : case DW_OP_neg:
324 : case DW_OP_not:
325 : case DW_OP_or:
326 : case DW_OP_plus:
327 : case DW_OP_shl:
328 : case DW_OP_shr:
329 : case DW_OP_shra:
330 : case DW_OP_xor:
331 : case DW_OP_eq:
332 : case DW_OP_ge:
333 : case DW_OP_gt:
334 : case DW_OP_le:
335 : case DW_OP_lt:
336 : case DW_OP_ne:
337 : case DW_OP_lit0 ... DW_OP_lit31:
338 : case DW_OP_reg0 ... DW_OP_reg31:
339 : case DW_OP_nop:
340 : case DW_OP_push_object_address:
341 : case DW_OP_call_frame_cfa:
342 : case DW_OP_form_tls_address:
343 : case DW_OP_GNU_push_tls_address:
344 : case DW_OP_stack_value:
345 : /* No operand. */
346 : break;
347 :
348 : case DW_OP_const1u:
349 : case DW_OP_pick:
350 : case DW_OP_deref_size:
351 : case DW_OP_xderef_size:
352 5 : if (unlikely (data >= end_data))
353 : {
354 : invalid:
355 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
356 : returnmem:
357 : /* Free any dynamicly allocated loclists, if any. */
358 0 : while (n > MAX_STACK_LOCS)
359 : {
360 0 : struct loclist *loc = loclist;
361 0 : loclist = loc->next;
362 0 : free (loc);
363 0 : n--;
364 : }
365 : return -1;
366 : }
367 :
368 5 : newloc->number = *data++;
369 5 : break;
370 :
371 : case DW_OP_const1s:
372 26 : if (unlikely (data >= end_data))
373 : goto invalid;
374 :
375 26 : newloc->number = *((int8_t *) data);
376 26 : ++data;
377 26 : break;
378 :
379 : case DW_OP_const2u:
380 3 : if (unlikely (data + 2 > end_data))
381 : goto invalid;
382 :
383 3 : newloc->number = read_2ubyte_unaligned_inc (&bo, data);
384 3 : break;
385 :
386 : case DW_OP_const2s:
387 : case DW_OP_skip:
388 : case DW_OP_bra:
389 : case DW_OP_call2:
390 123 : if (unlikely (data + 2 > end_data))
391 : goto invalid;
392 :
393 123 : newloc->number = read_2sbyte_unaligned_inc (&bo, data);
394 123 : break;
395 :
396 : case DW_OP_const4u:
397 1 : if (unlikely (data + 4 > end_data))
398 : goto invalid;
399 :
400 1 : newloc->number = read_4ubyte_unaligned_inc (&bo, data);
401 1 : break;
402 :
403 : case DW_OP_const4s:
404 : case DW_OP_call4:
405 : case DW_OP_GNU_parameter_ref:
406 3 : if (unlikely (data + 4 > end_data))
407 : goto invalid;
408 :
409 3 : newloc->number = read_4sbyte_unaligned_inc (&bo, data);
410 3 : break;
411 :
412 : case DW_OP_const8u:
413 48 : if (unlikely (data + 8 > end_data))
414 : goto invalid;
415 :
416 48 : newloc->number = read_8ubyte_unaligned_inc (&bo, data);
417 48 : break;
418 :
419 : case DW_OP_const8s:
420 0 : if (unlikely (data + 8 > end_data))
421 : goto invalid;
422 :
423 0 : newloc->number = read_8sbyte_unaligned_inc (&bo, data);
424 0 : break;
425 :
426 : case DW_OP_constu:
427 : case DW_OP_plus_uconst:
428 : case DW_OP_regx:
429 : case DW_OP_piece:
430 : case DW_OP_GNU_convert:
431 : case DW_OP_GNU_reinterpret:
432 6 : get_uleb128 (newloc->number, data, end_data);
433 6 : break;
434 :
435 : case DW_OP_consts:
436 : case DW_OP_breg0 ... DW_OP_breg31:
437 : case DW_OP_fbreg:
438 11 : get_sleb128 (newloc->number, data, end_data);
439 11 : break;
440 :
441 : case DW_OP_bregx:
442 0 : get_uleb128 (newloc->number, data, end_data);
443 0 : if (unlikely (data >= end_data))
444 : goto invalid;
445 0 : get_sleb128 (newloc->number2, data, end_data);
446 0 : break;
447 :
448 : case DW_OP_bit_piece:
449 : case DW_OP_GNU_regval_type:
450 0 : get_uleb128 (newloc->number, data, end_data);
451 0 : if (unlikely (data >= end_data))
452 : goto invalid;
453 0 : get_uleb128 (newloc->number2, data, end_data);
454 0 : break;
455 :
456 : case DW_OP_implicit_value:
457 : case DW_OP_GNU_entry_value:
458 : /* This cannot be used in a CFI expression. */
459 8 : if (unlikely (dbg == NULL))
460 : goto invalid;
461 :
462 : /* start of block inc. len. */
463 8 : newloc->number2 = (Dwarf_Word) (uintptr_t) data;
464 8 : get_uleb128 (newloc->number, data, end_data); /* Block length. */
465 8 : if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number))
466 : goto invalid;
467 8 : data += newloc->number; /* Skip the block. */
468 8 : break;
469 :
470 : case DW_OP_GNU_implicit_pointer:
471 : /* DW_FORM_ref_addr, depends on offset size of CU. */
472 2 : if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data,
473 : ref_size,
474 1 : &newloc->number,
475 : IDX_debug_info, 0))
476 : goto invalid;
477 1 : if (unlikely (data >= end_data))
478 : goto invalid;
479 1 : get_uleb128 (newloc->number2, data, end_data); /* Byte offset. */
480 1 : break;
481 :
482 : case DW_OP_GNU_deref_type:
483 1 : if (unlikely (data + 1 >= end_data))
484 : goto invalid;
485 1 : newloc->number = *data++;
486 1 : get_uleb128 (newloc->number2, data, end_data);
487 1 : break;
488 :
489 : case DW_OP_GNU_const_type:
490 : {
491 : size_t size;
492 1 : get_uleb128 (newloc->number, data, end_data);
493 1 : if (unlikely (data >= end_data))
494 : goto invalid;
495 :
496 : /* start of block inc. len. */
497 1 : newloc->number2 = (Dwarf_Word) (uintptr_t) data;
498 1 : size = *data++;
499 1 : if (unlikely ((Dwarf_Word) (end_data - data) < size))
500 : goto invalid;
501 1 : data += size; /* Skip the block. */
502 : }
503 1 : break;
504 :
505 : default:
506 : goto invalid;
507 : }
508 : }
509 :
510 786 : if (unlikely (n == 0))
511 : {
512 : /* This is not allowed.
513 : It would mean an empty location expression, which we handled
514 : already as a special case above. */
515 : goto invalid;
516 : }
517 :
518 786 : if (valuep)
519 : {
520 0 : struct loclist *newloc = NEW_LOC ();
521 0 : newloc->atom = DW_OP_stack_value;
522 0 : newloc->number = 0;
523 0 : newloc->number2 = 0;
524 0 : newloc->offset = data - block->data;
525 : }
526 :
527 : /* Allocate the array. */
528 : Dwarf_Op *result;
529 786 : if (dbg != NULL)
530 780 : result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n);
531 : else
532 : {
533 6 : result = malloc (sizeof *result * n);
534 6 : if (result == NULL)
535 : {
536 : nomem:
537 0 : __libdw_seterrno (DWARF_E_NOMEM);
538 0 : goto returnmem;
539 : }
540 : }
541 :
542 : /* Store the result. */
543 786 : *llbuf = result;
544 786 : *listlen = n;
545 :
546 : do
547 : {
548 : /* We populate the array from the back since the list is backwards. */
549 1256 : --n;
550 1256 : result[n].atom = loclist->atom;
551 1256 : result[n].number = loclist->number;
552 1256 : result[n].number2 = loclist->number2;
553 1256 : result[n].offset = loclist->offset;
554 :
555 1256 : if (result[n].atom == DW_OP_implicit_value)
556 2 : store_implicit_value (dbg, cache, &result[n]);
557 :
558 1256 : struct loclist *loc = loclist;
559 1256 : loclist = loclist->next;
560 1256 : if (unlikely (n + 1 > MAX_STACK_LOCS))
561 137 : free (loc);
562 : }
563 1256 : while (n > 0);
564 :
565 : /* Insert a record in the search tree so that we can find it again later. */
566 : struct loc_s *newp;
567 786 : if (dbg != NULL)
568 780 : newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1);
569 : else
570 : {
571 6 : newp = malloc (sizeof *newp);
572 6 : if (newp == NULL)
573 : {
574 0 : free (result);
575 0 : goto nomem;
576 : }
577 : }
578 :
579 786 : newp->addr = block->data;
580 786 : newp->loc = result;
581 786 : newp->nloc = *listlen;
582 786 : (void) tsearch (newp, cache, loc_compare);
583 :
584 : /* We did it. */
585 786 : return 0;
586 : }
587 :
588 : static int
589 821 : getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
590 : Dwarf_Op **llbuf, size_t *listlen, int sec_index)
591 : {
592 : /* Empty location expressions don't have any ops to intern.
593 : Note that synthetic empty_cu doesn't have an associated DWARF dbg. */
594 821 : if (block->length == 0)
595 : {
596 0 : *listlen = 0;
597 0 : return 0;
598 : }
599 :
600 3284 : return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order,
601 1642 : cu->address_size, (cu->version == 2
602 0 : ? cu->address_size
603 821 : : cu->offset_size),
604 : &cu->locs, block,
605 : false, false,
606 : llbuf, listlen, sec_index);
607 : }
608 :
609 : int
610 767 : dwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **llbuf, size_t *listlen)
611 : {
612 767 : if (! attr_ok (attr))
613 : return -1;
614 :
615 767 : int result = check_constant_offset (attr, llbuf, listlen);
616 767 : if (result != 1)
617 : return result;
618 :
619 : /* If it has a block form, it's a single location expression. */
620 : Dwarf_Block block;
621 767 : if (INTUSE(dwarf_formblock) (attr, &block) != 0)
622 : return -1;
623 :
624 1520 : return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu));
625 : }
626 :
627 : static int
628 47 : attr_base_address (Dwarf_Attribute *attr, Dwarf_Addr *basep)
629 : {
630 : /* Fetch the CU's base address. */
631 94 : Dwarf_Die cudie = CUDIE (attr->cu);
632 :
633 : /* Find the base address of the compilation unit. It will
634 : normally be specified by DW_AT_low_pc. In DWARF-3 draft 4,
635 : the base address could be overridden by DW_AT_entry_pc. It's
636 : been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
637 : for compilation units with discontinuous ranges. */
638 : Dwarf_Attribute attr_mem;
639 47 : if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0)
640 0 : && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
641 : DW_AT_entry_pc,
642 : &attr_mem),
643 : basep) != 0)
644 : {
645 0 : if (INTUSE(dwarf_errno) () != 0)
646 : return -1;
647 :
648 : /* The compiler provided no base address when it should
649 : have. Buggy GCC does this when it used absolute
650 : addresses in the location list and no DW_AT_ranges. */
651 0 : *basep = 0;
652 : }
653 : return 0;
654 : }
655 :
656 : static int
657 47 : initial_offset_base (Dwarf_Attribute *attr, ptrdiff_t *offset,
658 : Dwarf_Addr *basep)
659 : {
660 47 : if (attr_base_address (attr, basep) != 0)
661 : return -1;
662 :
663 : Dwarf_Word start_offset;
664 47 : if (__libdw_formptr (attr, IDX_debug_loc,
665 : DWARF_E_NO_LOCLIST,
666 : NULL, &start_offset) == NULL)
667 : return -1;
668 :
669 47 : *offset = start_offset;
670 47 : return 0;
671 : }
672 :
673 : static ptrdiff_t
674 67 : getlocations_addr (Dwarf_Attribute *attr, ptrdiff_t offset,
675 : Dwarf_Addr *basep, Dwarf_Addr *startp, Dwarf_Addr *endp,
676 : Dwarf_Addr address, const Elf_Data *locs, Dwarf_Op **expr,
677 : size_t *exprlen)
678 : {
679 67 : unsigned char *readp = locs->d_buf + offset;
680 67 : unsigned char *readendp = locs->d_buf + locs->d_size;
681 :
682 : next:
683 107 : if (readendp - readp < attr->cu->address_size * 2)
684 : {
685 : invalid:
686 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
687 : return -1;
688 : }
689 :
690 : Dwarf_Addr begin;
691 : Dwarf_Addr end;
692 :
693 107 : switch (__libdw_read_begin_end_pair_inc (attr->cu->dbg, IDX_debug_loc,
694 : &readp, attr->cu->address_size,
695 : &begin, &end, basep))
696 : {
697 : case 0: /* got location range. */
698 : break;
699 : case 1: /* base address setup. */
700 : goto next;
701 : case 2: /* end of loclist */
702 : return 0;
703 : default: /* error */
704 : return -1;
705 : }
706 :
707 100 : if (readendp - readp < 2)
708 : goto invalid;
709 :
710 : /* We have a location expression. */
711 : Dwarf_Block block;
712 100 : block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp);
713 100 : block.data = readp;
714 100 : if (readendp - readp < (ptrdiff_t) block.length)
715 : goto invalid;
716 100 : readp += block.length;
717 :
718 100 : *startp = *basep + begin;
719 100 : *endp = *basep + end;
720 :
721 : /* If address is minus one we want them all, otherwise only matching. */
722 100 : if (address != (Dwarf_Word) -1 && (address < *startp || address >= *endp))
723 : goto next;
724 :
725 60 : if (getlocation (attr->cu, &block, expr, exprlen, IDX_debug_loc) != 0)
726 : return -1;
727 :
728 60 : return readp - (unsigned char *) locs->d_buf;
729 : }
730 :
731 : int
732 41 : dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address,
733 : Dwarf_Op **llbufs, size_t *listlens, size_t maxlocs)
734 : {
735 41 : if (! attr_ok (attr))
736 : return -1;
737 :
738 41 : if (llbufs == NULL)
739 0 : maxlocs = SIZE_MAX;
740 :
741 : /* If it has a block form, it's a single location expression. */
742 : Dwarf_Block block;
743 41 : if (INTUSE(dwarf_formblock) (attr, &block) == 0)
744 : {
745 1 : if (maxlocs == 0)
746 : return 0;
747 2 : if (llbufs != NULL &&
748 1 : getlocation (attr->cu, &block, &llbufs[0], &listlens[0],
749 1 : cu_sec_idx (attr->cu)) != 0)
750 : return -1;
751 1 : return listlens[0] == 0 ? 0 : 1;
752 : }
753 :
754 40 : int error = INTUSE(dwarf_errno) ();
755 40 : if (unlikely (error != DWARF_E_NO_BLOCK))
756 : {
757 0 : __libdw_seterrno (error);
758 0 : return -1;
759 : }
760 :
761 40 : int result = check_constant_offset (attr, &llbufs[0], &listlens[0]);
762 40 : if (result != 1)
763 0 : return result ?: 1;
764 :
765 : Dwarf_Addr base, start, end;
766 : Dwarf_Op *expr;
767 : size_t expr_len;
768 40 : ptrdiff_t off = 0;
769 40 : size_t got = 0;
770 :
771 : /* This is a true loclistptr, fetch the initial base address and offset. */
772 40 : if (initial_offset_base (attr, &off, &base) != 0)
773 : return -1;
774 :
775 40 : const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc];
776 40 : if (d == NULL)
777 : {
778 0 : __libdw_seterrno (DWARF_E_NO_LOCLIST);
779 0 : return -1;
780 : }
781 :
782 80 : while (got < maxlocs
783 40 : && (off = getlocations_addr (attr, off, &base, &start, &end,
784 : address, d, &expr, &expr_len)) > 0)
785 : {
786 : /* This one matches the address. */
787 40 : if (llbufs != NULL)
788 : {
789 40 : llbufs[got] = expr;
790 40 : listlens[got] = expr_len;
791 : }
792 40 : ++got;
793 : }
794 :
795 : /* We might stop early, so off can be zero or positive on success. */
796 40 : if (off < 0)
797 : return -1;
798 :
799 40 : return got;
800 : }
801 :
802 : ptrdiff_t
803 27 : dwarf_getlocations (Dwarf_Attribute *attr, ptrdiff_t offset, Dwarf_Addr *basep,
804 : Dwarf_Addr *startp, Dwarf_Addr *endp, Dwarf_Op **expr,
805 : size_t *exprlen)
806 : {
807 27 : if (! attr_ok (attr))
808 : return -1;
809 :
810 : /* 1 is an invalid offset, meaning no more locations. */
811 27 : if (offset == 1)
812 : return 0;
813 :
814 27 : if (offset == 0)
815 : {
816 : /* If it has a block form, it's a single location expression. */
817 : Dwarf_Block block;
818 7 : if (INTUSE(dwarf_formblock) (attr, &block) == 0)
819 : {
820 0 : if (getlocation (attr->cu, &block, expr, exprlen,
821 0 : cu_sec_idx (attr->cu)) != 0)
822 0 : return -1;
823 :
824 : /* This is the one and only location covering everything. */
825 0 : *startp = 0;
826 0 : *endp = -1;
827 0 : return 1;
828 : }
829 :
830 7 : int error = INTUSE(dwarf_errno) ();
831 7 : if (unlikely (error != DWARF_E_NO_BLOCK))
832 : {
833 0 : __libdw_seterrno (error);
834 0 : return -1;
835 : }
836 :
837 7 : int result = check_constant_offset (attr, expr, exprlen);
838 7 : if (result != 1)
839 : {
840 0 : if (result == 0)
841 : {
842 : /* This is the one and only location covering everything. */
843 0 : *startp = 0;
844 0 : *endp = -1;
845 0 : return 1;
846 : }
847 0 : return result;
848 : }
849 :
850 : /* We must be looking at a true loclistptr, fetch the initial
851 : base address and offset. */
852 7 : if (initial_offset_base (attr, &offset, basep) != 0)
853 : return -1;
854 : }
855 :
856 27 : const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc];
857 27 : if (d == NULL)
858 : {
859 0 : __libdw_seterrno (DWARF_E_NO_LOCLIST);
860 0 : return -1;
861 : }
862 :
863 27 : return getlocations_addr (attr, offset, basep, startp, endp,
864 : (Dwarf_Word) -1, d, expr, exprlen);
865 : }
|