Home | History | Annotate | Download | only in libdw
      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 (at) 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
     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
    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
    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
    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
    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
    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
    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
    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
    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