• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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