1 /* Return location expression list.
2 Copyright (C) 2000-2010 Red Hat, Inc.
3 This file is part of Red Hat elfutils.
4 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5
6 Red Hat elfutils is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 2 of the License.
9
10 Red Hat elfutils is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with Red Hat elfutils; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18
19 In addition, as a special exception, Red Hat, Inc. gives You the
20 additional right to link the code of Red Hat elfutils with code licensed
21 under any Open Source Initiative certified open source license
22 (http://www.opensource.org/licenses/index.php) which requires the
23 distribution of source code with any binary distribution and to
24 distribute linked combinations of the two. Non-GPL Code permitted under
25 this exception must only link to the code of Red Hat elfutils through
26 those well defined interfaces identified in the file named EXCEPTION
27 found in the source code files (the "Approved Interfaces"). The files
28 of Non-GPL Code may instantiate templates or use macros or inline
29 functions from the Approved Interfaces without causing the resulting
30 work to be covered by the GNU General Public License. Only Red Hat,
31 Inc. may make changes or additions to the list of Approved Interfaces.
32 Red Hat's grant of this exception is conditioned upon your not adding
33 any new exceptions. If you wish to add a new Approved Interface or
34 exception, please contact Red Hat. You must obey the GNU General Public
35 License in all respects for all of the Red Hat elfutils code and other
36 code used in conjunction with Red Hat elfutils except the Non-GPL Code
37 covered by this exception. If you modify this file, you may extend this
38 exception to your version of the file, but you are not obligated to do
39 so. If you do not wish to provide this exception without modification,
40 you must delete this exception statement from your version and license
41 this file solely under the GPL without exception.
42
43 Red Hat elfutils is an included package of the Open Invention Network.
44 An included package of the Open Invention Network is a package for which
45 Open Invention Network licensees cross-license their patents. No patent
46 license is granted, either expressly or impliedly, by designation as an
47 included package. Should you wish to participate in the Open Invention
48 Network licensing program, please visit www.openinventionnetwork.com
49 <http://www.openinventionnetwork.com>. */
50
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 #endif
54
55 #include <dwarf.h>
56 #include <search.h>
57 #include <stdlib.h>
58 #include <assert.h>
59
60 #include <libdwP.h>
61
62
63 static bool
attr_ok(Dwarf_Attribute * attr)64 attr_ok (Dwarf_Attribute *attr)
65 {
66 if (attr == NULL)
67 return false;
68
69 /* Must be one of the attributes listed below. */
70 switch (attr->code)
71 {
72 case DW_AT_location:
73 case DW_AT_data_member_location:
74 case DW_AT_vtable_elem_location:
75 case DW_AT_string_length:
76 case DW_AT_use_location:
77 case DW_AT_frame_base:
78 case DW_AT_return_addr:
79 case DW_AT_static_link:
80 break;
81
82 default:
83 __libdw_seterrno (DWARF_E_NO_LOCLIST);
84 return false;
85 }
86
87 return true;
88 }
89
90
91 struct loclist
92 {
93 uint8_t atom;
94 Dwarf_Word number;
95 Dwarf_Word number2;
96 Dwarf_Word offset;
97 struct loclist *next;
98 };
99
100
101 static int
loc_compare(const void * p1,const void * p2)102 loc_compare (const void *p1, const void *p2)
103 {
104 const struct loc_s *l1 = (const struct loc_s *) p1;
105 const struct loc_s *l2 = (const struct loc_s *) p2;
106
107 if ((uintptr_t) l1->addr < (uintptr_t) l2->addr)
108 return -1;
109 if ((uintptr_t) l1->addr > (uintptr_t) l2->addr)
110 return 1;
111
112 return 0;
113 }
114
115 /* For each DW_OP_implicit_value, we store a special entry in the cache.
116 This points us directly to the block data for later fetching. */
117 static void
store_implicit_value(Dwarf * dbg,void ** cache,Dwarf_Op * op,unsigned char * data)118 store_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op,
119 unsigned char *data)
120 {
121 struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s,
122 sizeof (struct loc_block_s), 1);
123 block->addr = op;
124 block->data = data + op->number2;
125 block->length = op->number;
126 (void) tsearch (block, cache, loc_compare);
127 }
128
129 int
dwarf_getlocation_implicit_value(attr,op,return_block)130 dwarf_getlocation_implicit_value (attr, op, return_block)
131 Dwarf_Attribute *attr;
132 const Dwarf_Op *op;
133 Dwarf_Block *return_block;
134 {
135 if (attr == NULL)
136 return -1;
137
138 struct loc_block_s fake = { .addr = (void *) op };
139 struct loc_block_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
140 if (unlikely (found == NULL))
141 {
142 __libdw_seterrno (DWARF_E_NO_BLOCK);
143 return -1;
144 }
145
146 return_block->length = (*found)->length;
147 return_block->data = (*found)->data;
148 return 0;
149 }
150
151 /* DW_AT_data_member_location can be a constant as well as a loclistptr.
152 Only data[48] indicate a loclistptr. */
153 static int
check_constant_offset(Dwarf_Attribute * attr,Dwarf_Op ** llbuf,size_t * listlen)154 check_constant_offset (Dwarf_Attribute *attr,
155 Dwarf_Op **llbuf, size_t *listlen)
156 {
157 if (attr->code != DW_AT_data_member_location)
158 return 1;
159
160 switch (attr->form)
161 {
162 /* Punt for any non-constant form. */
163 default:
164 return 1;
165
166 case DW_FORM_data1:
167 case DW_FORM_data2:
168 case DW_FORM_data4:
169 case DW_FORM_data8:
170 case DW_FORM_sdata:
171 case DW_FORM_udata:
172 break;
173 }
174
175 /* Check whether we already cached this location. */
176 struct loc_s fake = { .addr = attr->valp };
177 struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare);
178
179 if (found == NULL)
180 {
181 Dwarf_Word offset;
182 if (INTUSE(dwarf_formudata) (attr, &offset) != 0)
183 return -1;
184
185 Dwarf_Op *result = libdw_alloc (attr->cu->dbg,
186 Dwarf_Op, sizeof (Dwarf_Op), 1);
187
188 result->atom = DW_OP_plus_uconst;
189 result->number = offset;
190 result->number2 = 0;
191 result->offset = 0;
192
193 /* Insert a record in the search tree so we can find it again later. */
194 struct loc_s *newp = libdw_alloc (attr->cu->dbg,
195 struct loc_s, sizeof (struct loc_s),
196 1);
197 newp->addr = attr->valp;
198 newp->loc = result;
199 newp->nloc = 1;
200
201 found = tsearch (newp, &attr->cu->locs, loc_compare);
202 }
203
204 assert ((*found)->nloc == 1);
205
206 if (llbuf != NULL)
207 {
208 *llbuf = (*found)->loc;
209 *listlen = 1;
210 }
211
212 return 0;
213 }
214
215 int
216 internal_function
__libdw_intern_expression(Dwarf * dbg,bool other_byte_order,unsigned int address_size,unsigned int ref_size,void ** cache,const Dwarf_Block * block,bool cfap,bool valuep,Dwarf_Op ** llbuf,size_t * listlen,int sec_index)217 __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
218 unsigned int address_size, unsigned int ref_size,
219 void **cache, const Dwarf_Block *block,
220 bool cfap, bool valuep,
221 Dwarf_Op **llbuf, size_t *listlen, int sec_index)
222 {
223 /* Check whether we already looked at this list. */
224 struct loc_s fake = { .addr = block->data };
225 struct loc_s **found = tfind (&fake, cache, loc_compare);
226 if (found != NULL)
227 {
228 /* We already saw it. */
229 *llbuf = (*found)->loc;
230 *listlen = (*found)->nloc;
231
232 if (valuep)
233 {
234 assert (*listlen > 1);
235 assert ((*llbuf)[*listlen - 1].atom == DW_OP_stack_value);
236 }
237
238 return 0;
239 }
240
241 const unsigned char *data = block->data;
242 const unsigned char *const end_data = data + block->length;
243
244 const struct { bool other_byte_order; } bo = { other_byte_order };
245
246 struct loclist *loclist = NULL;
247 unsigned int n = 0;
248 /* Decode the opcodes. It is possible in some situations to have a
249 block of size zero. */
250 while (data < end_data)
251 {
252 struct loclist *newloc;
253 newloc = (struct loclist *) alloca (sizeof (struct loclist));
254 newloc->number = 0;
255 newloc->number2 = 0;
256 newloc->offset = data - block->data;
257 newloc->next = loclist;
258 loclist = newloc;
259 ++n;
260
261 switch ((newloc->atom = *data++))
262 {
263 case DW_OP_addr:
264 /* Address, depends on address size of CU. */
265 if (__libdw_read_address_inc (dbg, sec_index, &data,
266 address_size, &newloc->number))
267 return -1;
268 break;
269
270 case DW_OP_call_ref:
271 /* DW_FORM_ref_addr, depends on offset size of CU. */
272 if (__libdw_read_offset_inc (dbg, sec_index, &data, ref_size,
273 &newloc->number, IDX_debug_info, 0))
274 return -1;
275 break;
276
277 case DW_OP_deref:
278 case DW_OP_dup:
279 case DW_OP_drop:
280 case DW_OP_over:
281 case DW_OP_swap:
282 case DW_OP_rot:
283 case DW_OP_xderef:
284 case DW_OP_abs:
285 case DW_OP_and:
286 case DW_OP_div:
287 case DW_OP_minus:
288 case DW_OP_mod:
289 case DW_OP_mul:
290 case DW_OP_neg:
291 case DW_OP_not:
292 case DW_OP_or:
293 case DW_OP_plus:
294 case DW_OP_shl:
295 case DW_OP_shr:
296 case DW_OP_shra:
297 case DW_OP_xor:
298 case DW_OP_eq:
299 case DW_OP_ge:
300 case DW_OP_gt:
301 case DW_OP_le:
302 case DW_OP_lt:
303 case DW_OP_ne:
304 case DW_OP_lit0 ... DW_OP_lit31:
305 case DW_OP_reg0 ... DW_OP_reg31:
306 case DW_OP_nop:
307 case DW_OP_push_object_address:
308 case DW_OP_call_frame_cfa:
309 case DW_OP_form_tls_address:
310 case DW_OP_GNU_push_tls_address:
311 case DW_OP_stack_value:
312 /* No operand. */
313 break;
314
315 case DW_OP_const1u:
316 case DW_OP_pick:
317 case DW_OP_deref_size:
318 case DW_OP_xderef_size:
319 if (unlikely (data >= end_data))
320 {
321 invalid:
322 __libdw_seterrno (DWARF_E_INVALID_DWARF);
323 return -1;
324 }
325
326 newloc->number = *data++;
327 break;
328
329 case DW_OP_const1s:
330 if (unlikely (data >= end_data))
331 goto invalid;
332
333 newloc->number = *((int8_t *) data);
334 ++data;
335 break;
336
337 case DW_OP_const2u:
338 if (unlikely (data + 2 > end_data))
339 goto invalid;
340
341 newloc->number = read_2ubyte_unaligned_inc (&bo, data);
342 break;
343
344 case DW_OP_const2s:
345 case DW_OP_skip:
346 case DW_OP_bra:
347 case DW_OP_call2:
348 if (unlikely (data + 2 > end_data))
349 goto invalid;
350
351 newloc->number = read_2sbyte_unaligned_inc (&bo, data);
352 break;
353
354 case DW_OP_const4u:
355 if (unlikely (data + 4 > end_data))
356 goto invalid;
357
358 newloc->number = read_4ubyte_unaligned_inc (&bo, data);
359 break;
360
361 case DW_OP_const4s:
362 case DW_OP_call4:
363 if (unlikely (data + 4 > end_data))
364 goto invalid;
365
366 newloc->number = read_4sbyte_unaligned_inc (&bo, data);
367 break;
368
369 case DW_OP_const8u:
370 if (unlikely (data + 8 > end_data))
371 goto invalid;
372
373 newloc->number = read_8ubyte_unaligned_inc (&bo, data);
374 break;
375
376 case DW_OP_const8s:
377 if (unlikely (data + 8 > end_data))
378 goto invalid;
379
380 newloc->number = read_8sbyte_unaligned_inc (&bo, data);
381 break;
382
383 case DW_OP_constu:
384 case DW_OP_plus_uconst:
385 case DW_OP_regx:
386 case DW_OP_piece:
387 /* XXX Check size. */
388 get_uleb128 (newloc->number, data);
389 break;
390
391 case DW_OP_consts:
392 case DW_OP_breg0 ... DW_OP_breg31:
393 case DW_OP_fbreg:
394 /* XXX Check size. */
395 get_sleb128 (newloc->number, data);
396 break;
397
398 case DW_OP_bregx:
399 /* XXX Check size. */
400 get_uleb128 (newloc->number, data);
401 get_sleb128 (newloc->number2, data);
402 break;
403
404 case DW_OP_bit_piece:
405 /* XXX Check size. */
406 get_uleb128 (newloc->number, data);
407 get_uleb128 (newloc->number2, data);
408 break;
409
410 case DW_OP_implicit_value:
411 /* This cannot be used in a CFI expression. */
412 if (unlikely (dbg == NULL))
413 goto invalid;
414
415 /* XXX Check size. */
416 get_uleb128 (newloc->number, data); /* Block length. */
417 if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number))
418 goto invalid;
419 newloc->number2 = data - block->data; /* Relative block offset. */
420 data += newloc->number; /* Skip the block. */
421 break;
422
423 case DW_OP_GNU_implicit_pointer:
424 /* DW_FORM_ref_addr, depends on offset size of CU. */
425 if (__libdw_read_offset_inc (dbg, sec_index, &data, ref_size,
426 &newloc->number, IDX_debug_info, 0))
427 return -1;
428 /* XXX Check size. */
429 get_uleb128 (newloc->number2, data); /* Byte offset. */
430 break;
431
432 default:
433 goto invalid;
434 }
435 }
436
437 if (unlikely (n == 0))
438 {
439 /* This is not allowed.
440
441 XXX Is it? */
442 goto invalid;
443 }
444
445 if (valuep)
446 {
447 struct loclist *newloc;
448 newloc = (struct loclist *) alloca (sizeof (struct loclist));
449 newloc->atom = DW_OP_stack_value;
450 newloc->number = 0;
451 newloc->number2 = 0;
452 newloc->offset = data - block->data;
453 newloc->next = loclist;
454 loclist = newloc;
455 ++n;
456 }
457
458 if (cfap)
459 ++n;
460
461 /* Allocate the array. */
462 Dwarf_Op *result;
463 if (dbg != NULL)
464 result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n);
465 else
466 {
467 result = malloc (sizeof *result * n);
468 if (result == NULL)
469 {
470 nomem:
471 __libdw_seterrno (DWARF_E_NOMEM);
472 return -1;
473 }
474 }
475
476 /* Store the result. */
477 *llbuf = result;
478 *listlen = n;
479
480 if (cfap)
481 {
482 /* Synthesize the operation to push the CFA before the expression. */
483 --n;
484 result[0].atom = DW_OP_call_frame_cfa;
485 result[0].number = 0;
486 result[0].number2 = 0;
487 result[0].offset = -1;
488 }
489
490 do
491 {
492 /* We populate the array from the back since the list is backwards. */
493 --n;
494 result[n].atom = loclist->atom;
495 result[n].number = loclist->number;
496 result[n].number2 = loclist->number2;
497 result[n].offset = loclist->offset;
498
499 if (result[n].atom == DW_OP_implicit_value)
500 store_implicit_value (dbg, cache, &result[n], block->data);
501
502 loclist = loclist->next;
503 }
504 while (n > 0);
505
506 /* Insert a record in the search tree so that we can find it again later. */
507 struct loc_s *newp;
508 if (dbg != NULL)
509 newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1);
510 else
511 {
512 newp = malloc (sizeof *newp);
513 if (newp == NULL)
514 {
515 free (result);
516 goto nomem;
517 }
518 }
519
520 newp->addr = block->data;
521 newp->loc = result;
522 newp->nloc = *listlen;
523 (void) tsearch (newp, cache, loc_compare);
524
525 /* We did it. */
526 return 0;
527 }
528
529 static int
getlocation(struct Dwarf_CU * cu,const Dwarf_Block * block,Dwarf_Op ** llbuf,size_t * listlen,int sec_index)530 getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block,
531 Dwarf_Op **llbuf, size_t *listlen, int sec_index)
532 {
533 return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order,
534 cu->address_size, (cu->version == 2
535 ? cu->address_size
536 : cu->offset_size),
537 &cu->locs, block,
538 false, false,
539 llbuf, listlen, sec_index);
540 }
541
542 int
dwarf_getlocation(attr,llbuf,listlen)543 dwarf_getlocation (attr, llbuf, listlen)
544 Dwarf_Attribute *attr;
545 Dwarf_Op **llbuf;
546 size_t *listlen;
547 {
548 if (! attr_ok (attr))
549 return -1;
550
551 int result = check_constant_offset (attr, llbuf, listlen);
552 if (result != 1)
553 return result;
554
555 /* If it has a block form, it's a single location expression. */
556 Dwarf_Block block;
557 if (INTUSE(dwarf_formblock) (attr, &block) != 0)
558 return -1;
559
560 return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu));
561 }
562
563 int
dwarf_getlocation_addr(attr,address,llbufs,listlens,maxlocs)564 dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs)
565 Dwarf_Attribute *attr;
566 Dwarf_Addr address;
567 Dwarf_Op **llbufs;
568 size_t *listlens;
569 size_t maxlocs;
570 {
571 if (! attr_ok (attr))
572 return -1;
573
574 if (llbufs == NULL)
575 maxlocs = SIZE_MAX;
576
577 /* If it has a block form, it's a single location expression. */
578 Dwarf_Block block;
579 if (INTUSE(dwarf_formblock) (attr, &block) == 0)
580 {
581 if (maxlocs == 0)
582 return 0;
583 if (llbufs != NULL &&
584 getlocation (attr->cu, &block, &llbufs[0], &listlens[0],
585 cu_sec_idx (attr->cu)) != 0)
586 return -1;
587 return listlens[0] == 0 ? 0 : 1;
588 }
589
590 int error = INTUSE(dwarf_errno) ();
591 if (unlikely (error != DWARF_E_NO_BLOCK))
592 {
593 __libdw_seterrno (error);
594 return -1;
595 }
596
597 int result = check_constant_offset (attr, &llbufs[0], &listlens[0]);
598 if (result != 1)
599 return result ?: 1;
600
601 unsigned char *endp;
602 unsigned char *readp = __libdw_formptr (attr, IDX_debug_loc,
603 DWARF_E_NO_LOCLIST, &endp, NULL);
604 if (readp == NULL)
605 return -1;
606
607 Dwarf_Addr base = (Dwarf_Addr) -1;
608 size_t got = 0;
609 while (got < maxlocs)
610 {
611 if (endp - readp < attr->cu->address_size * 2)
612 {
613 invalid:
614 __libdw_seterrno (DWARF_E_INVALID_DWARF);
615 return -1;
616 }
617
618 Dwarf_Addr begin;
619 Dwarf_Addr end;
620
621 int status
622 = __libdw_read_begin_end_pair_inc (attr->cu->dbg, IDX_debug_loc,
623 &readp, attr->cu->address_size,
624 &begin, &end, &base);
625 if (status == 2) /* End of list entry. */
626 break;
627 else if (status == 1) /* Base address selected. */
628 continue;
629 else if (status < 0)
630 return status;
631
632 if (endp - readp < 2)
633 goto invalid;
634
635 /* We have a location expression. */
636 block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp);
637 block.data = readp;
638 if (endp - readp < (ptrdiff_t) block.length)
639 goto invalid;
640 readp += block.length;
641
642 if (base == (Dwarf_Addr) -1)
643 {
644 /* Fetch the CU's base address. */
645 Dwarf_Die cudie = CUDIE (attr->cu);
646
647 /* Find the base address of the compilation unit. It will
648 normally be specified by DW_AT_low_pc. In DWARF-3 draft 4,
649 the base address could be overridden by DW_AT_entry_pc. It's
650 been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
651 for compilation units with discontinuous ranges. */
652 Dwarf_Attribute attr_mem;
653 if (unlikely (INTUSE(dwarf_lowpc) (&cudie, &base) != 0)
654 && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie,
655 DW_AT_entry_pc,
656 &attr_mem),
657 &base) != 0)
658 {
659 if (INTUSE(dwarf_errno) () != 0)
660 return -1;
661
662 /* The compiler provided no base address when it should
663 have. Buggy GCC does this when it used absolute
664 addresses in the location list and no DW_AT_ranges. */
665 base = 0;
666 }
667 }
668
669 if (address >= base + begin && address < base + end)
670 {
671 /* This one matches the address. */
672 if (llbufs != NULL
673 && unlikely (getlocation (attr->cu, &block,
674 &llbufs[got], &listlens[got],
675 IDX_debug_loc) != 0))
676 return -1;
677 ++got;
678 }
679 }
680
681 return got;
682 }
683