LCOV - code coverage report
Current view: top level - libdwfl - cu.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 99 114 86.8 %
Date: 2017-05-05 10:17:09 Functions: 6 7 85.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Keeping track of DWARF compilation units in libdwfl.
       2             :    Copyright (C) 2005-2010, 2015 Red Hat, Inc.
       3             :    This file is part of elfutils.
       4             : 
       5             :    This file is free software; you can redistribute it and/or modify
       6             :    it under the terms of either
       7             : 
       8             :      * the GNU Lesser General Public License as published by the Free
       9             :        Software Foundation; either version 3 of the License, or (at
      10             :        your option) any later version
      11             : 
      12             :    or
      13             : 
      14             :      * the GNU General Public License as published by the Free
      15             :        Software Foundation; either version 2 of the License, or (at
      16             :        your option) any later version
      17             : 
      18             :    or both in parallel, as here.
      19             : 
      20             :    elfutils is distributed in the hope that it will be useful, but
      21             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      22             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      23             :    General Public License for more details.
      24             : 
      25             :    You should have received copies of the GNU General Public License and
      26             :    the GNU Lesser General Public License along with this program.  If
      27             :    not, see <http://www.gnu.org/licenses/>.  */
      28             : 
      29             : #ifdef HAVE_CONFIG_H
      30             : # include <config.h>
      31             : #endif
      32             : 
      33             : #include "libdwflP.h"
      34             : #include "../libdw/libdwP.h"
      35             : #include "../libdw/memory-access.h"
      36             : #include <search.h>
      37             : 
      38             : 
      39             : static inline Dwarf_Arange *
      40             : dwar (Dwfl_Module *mod, unsigned int idx)
      41             : {
      42         414 :   return &mod->dw->aranges->info[mod->aranges[idx].arange];
      43             : }
      44             : 
      45             : 
      46             : static Dwfl_Error
      47         345 : addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
      48             : {
      49         345 :   if (mod->aranges == NULL)
      50             :     {
      51          58 :       struct dwfl_arange *aranges = NULL;
      52          58 :       Dwarf_Aranges *dwaranges = NULL;
      53             :       size_t naranges;
      54          58 :       if (INTUSE(dwarf_getaranges) (mod->dw, &dwaranges, &naranges) != 0)
      55           0 :         return DWFL_E_LIBDW;
      56             : 
      57             :       /* If the module has no aranges (when no code is included) we
      58             :          allocate nothing.  */
      59          58 :       if (naranges != 0)
      60             :         {
      61          54 :           aranges = malloc (naranges * sizeof *aranges);
      62          54 :           if (unlikely (aranges == NULL))
      63             :             return DWFL_E_NOMEM;
      64             : 
      65             :           /* libdw has sorted its list by address, which is how we want it.
      66             :              But the sorted list is full of not-quite-contiguous runs pointing
      67             :              to the same CU.  We don't care about the little gaps inside the
      68             :              module, we'll consider them part of the surrounding CU anyway.
      69             :              Collect our own array with just one record for each run of ranges
      70             :              pointing to one CU.  */
      71             : 
      72          54 :           naranges = 0;
      73          54 :           Dwarf_Off lastcu = 0;
      74         135 :           for (size_t i = 0; i < dwaranges->naranges; ++i)
      75          81 :             if (i == 0 || dwaranges->info[i].offset != lastcu)
      76             :               {
      77          73 :                 aranges[naranges].arange = i;
      78          73 :                 aranges[naranges].cu = NULL;
      79          73 :                 ++naranges;
      80          73 :                 lastcu = dwaranges->info[i].offset;
      81             :               }
      82             :         }
      83             : 
      84             :       /* Store the final array, which is probably much smaller than before.  */
      85          58 :       mod->naranges = naranges;
      86         116 :       mod->aranges = (realloc (aranges, naranges * sizeof aranges[0])
      87          58 :                       ?: aranges);
      88          58 :       mod->lazycu += naranges;
      89             :     }
      90             : 
      91             :   /* The address must be inside the module to begin with.  */
      92         345 :   addr = dwfl_deadjust_dwarf_addr (mod, addr);
      93             : 
      94             :   /* The ranges are sorted by address, so we can use binary search.  */
      95         345 :   size_t l = 0, u = mod->naranges;
      96         728 :   while (l < u)
      97             :     {
      98         375 :       size_t idx = (l + u) / 2;
      99         750 :       Dwarf_Addr start = dwar (mod, idx)->addr;
     100         375 :       if (addr < start)
     101             :         {
     102           0 :           u = idx;
     103           0 :           continue;
     104             :         }
     105         375 :       else if (addr > start)
     106             :         {
     107         268 :           if (idx + 1 < mod->naranges)
     108             :             {
     109          78 :               if (addr >= dwar (mod, idx + 1)->addr)
     110             :                 {
     111          38 :                   l = idx + 1;
     112          38 :                   continue;
     113             :                 }
     114             :             }
     115             :           else
     116             :             {
     117             :               /* It might be in the last range.  */
     118         229 :               const Dwarf_Arange *last
     119         229 :                 = &mod->dw->aranges->info[mod->dw->aranges->naranges - 1];
     120         229 :               if (addr > last->addr + last->length)
     121             :                 break;
     122             :             }
     123             :         }
     124             : 
     125         337 :       *arange = &mod->aranges[idx];
     126         337 :       return DWFL_E_NOERROR;
     127             :     }
     128             : 
     129             :   return DWFL_E_ADDR_OUTOFRANGE;
     130             : }
     131             : 
     132             : 
     133             : static void
     134           0 : nofree (void *arg)
     135             : {
     136           0 :   struct dwfl_cu *cu = arg;
     137           0 :   if (cu == (void *) -1l)
     138             :     return;
     139             : 
     140           0 :   assert (cu->mod->lazycu == 0);
     141             : }
     142             : 
     143             : /* One reason fewer to keep the lazy lookup table for CUs.  */
     144             : static inline void
     145             : less_lazy (Dwfl_Module *mod)
     146             : {
     147          59 :   if (--mod->lazycu > 0)
     148             :     return;
     149             : 
     150             :   /* We know about all the CUs now, we don't need this table.  */
     151           0 :   tdestroy (mod->lazy_cu_root, nofree);
     152           0 :   mod->lazy_cu_root = NULL;
     153             : }
     154             : 
     155             : static inline Dwarf_Off
     156             : cudie_offset (const struct dwfl_cu *cu)
     157             : {
     158             :   /* These are real CUs, so there never is a type_sig8.  Note
     159             :      initialization of dwkey.start and offset_size in intern_cu ()
     160             :      to see why this calculates the same value for both key and
     161             :      die.cu search items.  */
     162      128844 :   return DIE_OFFSET_FROM_CU_OFFSET (cu->die.cu->start, cu->die.cu->offset_size,
     163             :                                     0);
     164             : }
     165             : 
     166             : static int
     167       64422 : compare_cukey (const void *a, const void *b)
     168             : {
     169      128844 :   Dwarf_Off a_off = cudie_offset (a);
     170      128844 :   Dwarf_Off b_off = cudie_offset (b);
     171       64422 :   return (a_off < b_off) ? -1 : ((a_off > b_off) ? 1 : 0);
     172             : }
     173             : 
     174             : /* Intern the CU if necessary.  */
     175             : static Dwfl_Error
     176        5630 : intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
     177             : {
     178        5630 :   if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
     179             :     {
     180           0 :       if (likely (mod->lazycu == 1))
     181             :         {
     182             :           /* This is the EOF marker.  Now we have interned all the CUs.
     183             :              One increment in MOD->lazycu counts not having hit EOF yet.  */
     184           0 :           *result = (void *) -1;
     185           0 :           less_lazy (mod);
     186             :           return DWFL_E_NOERROR;
     187             :         }
     188             :       else
     189             :         {
     190             :           /* Unexpected EOF, most likely a bogus aranges.  */
     191             :           return (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
     192             :         }
     193             :     }
     194             : 
     195             :   /* Make sure the cuoff points to a real DIE.  */
     196             :   Dwarf_Die cudie;
     197        5630 :   Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cudie);
     198        5630 :   if (die == NULL)
     199             :     return DWFL_E_LIBDW;
     200             : 
     201             :   struct Dwarf_CU dwkey;
     202             :   struct dwfl_cu key;
     203        5630 :   key.die.cu = &dwkey;
     204        5630 :   dwkey.offset_size = 0;
     205        5630 :   dwkey.start = cuoff - (3 * 0 - 4 + 3);
     206        5630 :   struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
     207        5630 :   if (unlikely (found == NULL))
     208             :     return DWFL_E_NOMEM;
     209             : 
     210        5630 :   if (*found == &key || *found == NULL)
     211             :     {
     212             :       /* This is a new entry, meaning we haven't looked at this CU.  */
     213             : 
     214        5629 :       *found = NULL;
     215             : 
     216        5629 :       struct dwfl_cu *cu = malloc (sizeof *cu);
     217        5629 :       if (unlikely (cu == NULL))
     218             :         return DWFL_E_NOMEM;
     219             : 
     220        5629 :       cu->mod = mod;
     221        5629 :       cu->next = NULL;
     222        5629 :       cu->lines = NULL;
     223        5629 :       cu->die = cudie;
     224             : 
     225        5629 :       struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
     226             :                                                    * sizeof (mod->cu[0])));
     227        5629 :       if (newvec == NULL)
     228             :         {
     229           0 :           free (cu);
     230           0 :           return DWFL_E_NOMEM;
     231             :         }
     232        5629 :       mod->cu = newvec;
     233             : 
     234        5629 :       mod->cu[mod->ncu++] = cu;
     235        5629 :       if (cu->die.cu->start == 0)
     236         100 :         mod->first_cu = cu;
     237             : 
     238        5629 :       *found = cu;
     239             :     }
     240             : 
     241        5630 :   *result = *found;
     242        5630 :   return DWFL_E_NOERROR;
     243             : }
     244             : 
     245             : 
     246             : /* Traverse all the CUs in the module.  */
     247             : 
     248             : Dwfl_Error
     249             : internal_function
     250        5642 : __libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu,
     251             :                   struct dwfl_cu **cu)
     252             : {
     253             :   Dwarf_Off cuoff;
     254             :   struct dwfl_cu **nextp;
     255             : 
     256        5642 :   if (lastcu == NULL)
     257             :     {
     258             :       /* Start the traversal.  */
     259          60 :       cuoff = 0;
     260          60 :       nextp = &mod->first_cu;
     261             :     }
     262             :   else
     263             :     {
     264             :       /* Continue following LASTCU.  */
     265        5582 :       cuoff = lastcu->die.cu->end;
     266        5582 :       nextp = &lastcu->next;
     267             :     }
     268             : 
     269        5642 :   if (*nextp == NULL)
     270             :     {
     271             :       size_t cuhdrsz;
     272             :       Dwarf_Off nextoff;
     273        5631 :       int end = INTUSE(dwarf_nextcu) (mod->dw, cuoff, &nextoff, &cuhdrsz,
     274             :                                       NULL, NULL, NULL);
     275        5631 :       if (end < 0)
     276          60 :         return DWFL_E_LIBDW;
     277        5631 :       if (end > 0)
     278             :         {
     279          60 :           *cu = NULL;
     280          60 :           return DWFL_E_NOERROR;
     281             :         }
     282             : 
     283        5571 :       Dwfl_Error result = intern_cu (mod, cuoff + cuhdrsz, nextp);
     284        5571 :       if (result != DWFL_E_NOERROR)
     285             :         return result;
     286             : 
     287        5571 :       if (*nextp != (void *) -1
     288        5571 :           && (*nextp)->next == NULL && nextoff == (Dwarf_Off) -1l)
     289           0 :         (*nextp)->next = (void *) -1l;
     290             :     }
     291             : 
     292        5582 :   *cu = *nextp == (void *) -1l ? NULL : *nextp;
     293        5582 :   return DWFL_E_NOERROR;
     294             : }
     295             : 
     296             : 
     297             : /* Intern the CU arange points to, if necessary.  */
     298             : 
     299             : static Dwfl_Error
     300         337 : arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu)
     301             : {
     302         337 :   if (arange->cu == NULL)
     303             :     {
     304          59 :       const Dwarf_Arange *dwarange = &mod->dw->aranges->info[arange->arange];
     305          59 :       Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu);
     306          59 :       if (result != DWFL_E_NOERROR)
     307             :         return result;
     308          59 :       assert (arange->cu != NULL && arange->cu != (void *) -1l);
     309          59 :       less_lazy (mod);          /* Each arange with null ->cu counts once.  */
     310             :     }
     311             : 
     312         337 :   *cu = arange->cu;
     313         337 :   return DWFL_E_NOERROR;
     314             : }
     315             : 
     316             : Dwfl_Error
     317             : internal_function
     318         345 : __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_cu **cu)
     319             : {
     320             :   struct dwfl_arange *arange;
     321         345 :   return addrarange (mod, addr, &arange) ?: arangecu (mod, arange, cu);
     322             : }

Generated by: LCOV version 1.12