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

Generated by: LCOV version 1.12