LCOV - code coverage report
Current view: top level - libdwfl - cu.c (source / functions) Hit Total Coverage
Test: elfutils-0.174 Lines: 97 112 86.6 %
Date: 2018-09-14 13:30:33 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, 2016, 2017 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      157722 :   return __libdw_first_die_off_from_cu (cu->die.cu);
     159             : }
     160             : 
     161             : static int
     162       78861 : compare_cukey (const void *a, const void *b)
     163             : {
     164      157722 :   Dwarf_Off a_off = cudie_offset (a);
     165      157722 :   Dwarf_Off b_off = cudie_offset (b);
     166       78861 :   return (a_off < b_off) ? -1 : ((a_off > b_off) ? 1 : 0);
     167             : }
     168             : 
     169             : /* Intern the CU if necessary.  */
     170             : static Dwfl_Error
     171        7318 : intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
     172             : {
     173        7318 :   if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
     174             :     {
     175           0 :       if (likely (mod->lazycu == 1))
     176             :         {
     177             :           /* This is the EOF marker.  Now we have interned all the CUs.
     178             :              One increment in MOD->lazycu counts not having hit EOF yet.  */
     179           0 :           *result = (void *) -1;
     180           0 :           less_lazy (mod);
     181             :           return DWFL_E_NOERROR;
     182             :         }
     183             :       else
     184             :         {
     185             :           /* Unexpected EOF, most likely a bogus aranges.  */
     186             :           return (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
     187             :         }
     188             :     }
     189             : 
     190             :   /* Make sure the cuoff points to a real DIE.  */
     191             :   Dwarf_Die cudie;
     192        7318 :   Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cudie);
     193        7318 :   if (die == NULL)
     194             :     return DWFL_E_LIBDW;
     195             : 
     196             :   struct dwfl_cu key;
     197        7318 :   key.die.cu = die->cu;
     198        7318 :   struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
     199        7318 :   if (unlikely (found == NULL))
     200             :     return DWFL_E_NOMEM;
     201             : 
     202        7318 :   if (*found == &key || *found == NULL)
     203             :     {
     204             :       /* This is a new entry, meaning we haven't looked at this CU.  */
     205             : 
     206        7317 :       *found = NULL;
     207             : 
     208        7317 :       struct dwfl_cu *cu = malloc (sizeof *cu);
     209        7317 :       if (unlikely (cu == NULL))
     210             :         return DWFL_E_NOMEM;
     211             : 
     212        7317 :       cu->mod = mod;
     213        7317 :       cu->next = NULL;
     214        7317 :       cu->lines = NULL;
     215        7317 :       cu->die = cudie;
     216             : 
     217        7317 :       struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
     218             :                                                    * sizeof (mod->cu[0])));
     219        7317 :       if (newvec == NULL)
     220             :         {
     221           0 :           free (cu);
     222           0 :           return DWFL_E_NOMEM;
     223             :         }
     224        7317 :       mod->cu = newvec;
     225             : 
     226        7317 :       mod->cu[mod->ncu++] = cu;
     227        7317 :       if (cu->die.cu->start == 0)
     228         132 :         mod->first_cu = cu;
     229             : 
     230        7317 :       *found = cu;
     231             :     }
     232             : 
     233        7318 :   *result = *found;
     234        7318 :   return DWFL_E_NOERROR;
     235             : }
     236             : 
     237             : 
     238             : /* Traverse all the CUs in the module.  */
     239             : 
     240             : Dwfl_Error
     241             : internal_function
     242        7362 : __libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu,
     243             :                   struct dwfl_cu **cu)
     244             : {
     245             :   Dwarf_Off cuoff;
     246             :   struct dwfl_cu **nextp;
     247             : 
     248        7362 :   if (lastcu == NULL)
     249             :     {
     250             :       /* Start the traversal.  */
     251          92 :       cuoff = 0;
     252          92 :       nextp = &mod->first_cu;
     253             :     }
     254             :   else
     255             :     {
     256             :       /* Continue following LASTCU.  */
     257        7270 :       cuoff = lastcu->die.cu->end;
     258        7270 :       nextp = &lastcu->next;
     259             :     }
     260             : 
     261        7362 :   if (*nextp == NULL)
     262             :     {
     263             :       size_t cuhdrsz;
     264             :       Dwarf_Off nextoff;
     265        7351 :       int end = INTUSE(dwarf_nextcu) (mod->dw, cuoff, &nextoff, &cuhdrsz,
     266             :                                       NULL, NULL, NULL);
     267        7351 :       if (end < 0)
     268          92 :         return DWFL_E_LIBDW;
     269        7351 :       if (end > 0)
     270             :         {
     271          92 :           *cu = NULL;
     272          92 :           return DWFL_E_NOERROR;
     273             :         }
     274             : 
     275        7259 :       Dwfl_Error result = intern_cu (mod, cuoff + cuhdrsz, nextp);
     276        7259 :       if (result != DWFL_E_NOERROR)
     277             :         return result;
     278             : 
     279        7259 :       if (*nextp != (void *) -1
     280        7259 :           && (*nextp)->next == NULL && nextoff == (Dwarf_Off) -1l)
     281           0 :         (*nextp)->next = (void *) -1l;
     282             :     }
     283             : 
     284        7270 :   *cu = *nextp == (void *) -1l ? NULL : *nextp;
     285        7270 :   return DWFL_E_NOERROR;
     286             : }
     287             : 
     288             : 
     289             : /* Intern the CU arange points to, if necessary.  */
     290             : 
     291             : static Dwfl_Error
     292         337 : arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu)
     293             : {
     294         337 :   if (arange->cu == NULL)
     295             :     {
     296          59 :       const Dwarf_Arange *dwarange = &mod->dw->aranges->info[arange->arange];
     297          59 :       Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu);
     298          59 :       if (result != DWFL_E_NOERROR)
     299             :         return result;
     300          59 :       assert (arange->cu != NULL && arange->cu != (void *) -1l);
     301          59 :       less_lazy (mod);          /* Each arange with null ->cu counts once.  */
     302             :     }
     303             : 
     304         337 :   *cu = arange->cu;
     305         337 :   return DWFL_E_NOERROR;
     306             : }
     307             : 
     308             : Dwfl_Error
     309             : internal_function
     310         345 : __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_cu **cu)
     311             : {
     312             :   struct dwfl_arange *arange;
     313         345 :   return addrarange (mod, addr, &arange) ?: arangecu (mod, arange, cu);
     314             : }

Generated by: LCOV version 1.13