LCOV - code coverage report
Current view: top level - libdw - dwarf_getlocation.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 206 295 69.8 %
Date: 2017-01-05 09:15:16 Functions: 13 13 100.0 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.12