LCOV - code coverage report
Current view: top level - libdwfl - cu.c (source / functions) Hit Total Coverage
Test: elfutils- Lines: 104 124 83.9 %
Date: 2020-06-11 18:20:19 Functions: 6 10 60.0 %
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           0 : 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          62 :       struct dwfl_arange *aranges = NULL;
      52          62 :       Dwarf_Aranges *dwaranges = NULL;
      53          62 :       size_t naranges;
      54          62 :       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          62 :       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          62 :       mod->naranges = naranges;
      86          62 :       if (naranges > 0)
      87          54 :         mod->aranges = (realloc (aranges, naranges * sizeof aranges[0])
      88          54 :                         ?: aranges);
      89           8 :       else if (aranges != NULL)
      90           0 :         free (aranges);
      91          62 :       mod->lazycu += naranges;
      92             :     }
      93             : 
      94             :   /* The address must be inside the module to begin with.  */
      95         345 :   addr = dwfl_deadjust_dwarf_addr (mod, addr);
      96             : 
      97             :   /* The ranges are sorted by address, so we can use binary search.  */
      98         345 :   size_t l = 0, u = mod->naranges;
      99         383 :   while (l < u)
     100             :     {
     101         375 :       size_t idx = (l + u) / 2;
     102         750 :       Dwarf_Addr start = dwar (mod, idx)->addr;
     103         375 :       if (addr < start)
     104             :         {
     105             :           u = idx;
     106             :           continue;
     107             :         }
     108         375 :       else if (addr > start)
     109             :         {
     110         268 :           if (idx + 1 < mod->naranges)
     111             :             {
     112          39 :               if (addr >= dwar (mod, idx + 1)->addr)
     113             :                 {
     114             :                   l = idx + 1;
     115             :                   continue;
     116             :                 }
     117             :             }
     118             :           else
     119             :             {
     120             :               /* It might be in the last range.  */
     121         458 :               const Dwarf_Arange *last
     122         229 :                 = &mod->dw->aranges->info[mod->dw->aranges->naranges - 1];
     123         229 :               if (addr > last->addr + last->length)
     124             :                 break;
     125             :             }
     126             :         }
     127             : 
     128         337 :       *arange = &mod->aranges[idx];
     129         337 :       return DWFL_E_NOERROR;
     130             :     }
     131             : 
     132             :   return DWFL_E_ADDR_OUTOFRANGE;
     133             : }
     134             : 
     135             : 
     136             : static void
     137           0 : nofree (void *arg)
     138             : {
     139           0 :   struct dwfl_cu *cu = arg;
     140           0 :   if (cu == (void *) -1l)
     141             :     return;
     142             : 
     143           0 :   assert (cu->mod->lazycu == 0);
     144             : }
     145             : 
     146             : /* One reason fewer to keep the lazy lookup table for CUs.  */
     147             : static inline void
     148           0 : less_lazy (Dwfl_Module *mod)
     149             : {
     150           0 :   if (--mod->lazycu > 0)
     151           0 :     return;
     152             : 
     153             :   /* We know about all the CUs now, we don't need this table.  */
     154           0 :   tdestroy (mod->lazy_cu_root, nofree);
     155           0 :   mod->lazy_cu_root = NULL;
     156             : }
     157             : 
     158             : static inline Dwarf_Off
     159           0 : cudie_offset (const struct dwfl_cu *cu)
     160             : {
     161      384248 :   return __libdw_first_die_off_from_cu (cu->die.cu);
     162             : }
     163             : 
     164             : static int
     165       96062 : compare_cukey (const void *a, const void *b)
     166             : {
     167       96062 :   Dwarf_Off a_off = cudie_offset (a);
     168       96062 :   Dwarf_Off b_off = cudie_offset (b);
     169       96062 :   return (a_off < b_off) ? -1 : ((a_off > b_off) ? 1 : 0);
     170             : }
     171             : 
     172             : /* Intern the CU if necessary.  */
     173             : static Dwfl_Error
     174        8665 : intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
     175             : {
     176        8665 :   if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
     177             :     {
     178           0 :       if (likely (mod->lazycu == 1))
     179             :         {
     180             :           /* This is the EOF marker.  Now we have interned all the CUs.
     181             :              One increment in MOD->lazycu counts not having hit EOF yet.  */
     182           0 :           *result = (void *) -1;
     183           0 :           less_lazy (mod);
     184           0 :           return DWFL_E_NOERROR;
     185             :         }
     186             :       else
     187             :         {
     188             :           /* Unexpected EOF, most likely a bogus aranges.  */
     189             :           return (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
     190             :         }
     191             :     }
     192             : 
     193             :   /* Make sure the cuoff points to a real DIE.  */
     194        8665 :   Dwarf_Die cudie;
     195        8665 :   Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cudie);
     196        8665 :   if (die == NULL)
     197             :     return DWFL_E_LIBDW;
     198             : 
     199        8665 :   struct dwfl_cu key;
     200        8665 :   key.die.cu = die->cu;
     201        8665 :   struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
     202        8665 :   if (unlikely (found == NULL))
     203             :     return DWFL_E_NOMEM;
     204             : 
     205        8665 :   if (*found == &key || *found == NULL)
     206             :     {
     207             :       /* This is a new entry, meaning we haven't looked at this CU.  */
     208             : 
     209        8664 :       *found = NULL;
     210             : 
     211        8664 :       struct dwfl_cu *cu = malloc (sizeof *cu);
     212        8664 :       if (unlikely (cu == NULL))
     213             :         return DWFL_E_NOMEM;
     214             : 
     215        8664 :       cu->mod = mod;
     216        8664 :       cu->next = NULL;
     217        8664 :       cu->lines = NULL;
     218        8664 :       cu->die = cudie;
     219             : 
     220        8664 :       struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
     221             :                                                    * sizeof (mod->cu[0])));
     222        8664 :       if (newvec == NULL)
     223             :         {
     224           0 :           free (cu);
     225           0 :           return DWFL_E_NOMEM;
     226             :         }
     227        8664 :       mod->cu = newvec;
     228             : 
     229        8664 :       mod->cu[mod->ncu++] = cu;
     230        8664 :       if (cu->die.cu->start == 0)
     231         129 :         mod->first_cu = cu;
     232             : 
     233        8664 :       *found = cu;
     234             :     }
     235             : 
     236        8665 :   *result = *found;
     237        8665 :   return DWFL_E_NOERROR;
     238             : }
     239             : 
     240             : 
     241             : /* Traverse all the CUs in the module.  */
     242             : 
     243             : Dwfl_Error
     244             : internal_function
     245        8722 : __libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu,
     246             :                   struct dwfl_cu **cu)
     247             : {
     248        8722 :   Dwarf_Off cuoff;
     249        8722 :   struct dwfl_cu **nextp;
     250             : 
     251        8722 :   if (lastcu == NULL)
     252             :     {
     253             :       /* Start the traversal.  */
     254          94 :       cuoff = 0;
     255          94 :       nextp = &mod->first_cu;
     256             :     }
     257             :   else
     258             :     {
     259             :       /* Continue following LASTCU.  */
     260        8628 :       cuoff = lastcu->die.cu->end;
     261        8628 :       nextp = &lastcu->next;
     262             :     }
     263             : 
     264        8722 :   if (*nextp == NULL)
     265             :     {
     266        8700 :       size_t cuhdrsz;
     267        8700 :       Dwarf_Off nextoff;
     268        8700 :       int end = INTUSE(dwarf_nextcu) (mod->dw, cuoff, &nextoff, &cuhdrsz,
     269             :                                       NULL, NULL, NULL);
     270        8700 :       if (end < 0)
     271          94 :         return DWFL_E_LIBDW;
     272        8700 :       if (end > 0)
     273             :         {
     274          94 :           *cu = NULL;
     275          94 :           return DWFL_E_NOERROR;
     276             :         }
     277             : 
     278        8606 :       Dwfl_Error result = intern_cu (mod, cuoff + cuhdrsz, nextp);
     279        8606 :       if (result != DWFL_E_NOERROR)
     280             :         return result;
     281             : 
     282        8606 :       if (*nextp != (void *) -1
     283        8606 :           && (*nextp)->next == NULL && nextoff == (Dwarf_Off) -1l)
     284           0 :         (*nextp)->next = (void *) -1l;
     285             :     }
     286             : 
     287        8628 :   *cu = *nextp == (void *) -1l ? NULL : *nextp;
     288        8628 :   return DWFL_E_NOERROR;
     289             : }
     290             : 
     291             : 
     292             : /* Intern the CU arange points to, if necessary.  */
     293             : 
     294             : static Dwfl_Error
     295         337 : arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu)
     296             : {
     297         337 :   if (arange->cu == NULL)
     298             :     {
     299          59 :       const Dwarf_Arange *dwarange = &mod->dw->aranges->info[arange->arange];
     300          59 :       Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu);
     301          59 :       if (result != DWFL_E_NOERROR)
     302             :         return result;
     303          59 :       assert (arange->cu != NULL && arange->cu != (void *) -1l);
     304          59 :       less_lazy (mod);          /* Each arange with null ->cu counts once.  */
     305             :     }
     306             : 
     307         337 :   *cu = arange->cu;
     308         337 :   return DWFL_E_NOERROR;
     309             : }
     310             : 
     311             : Dwfl_Error
     312             : internal_function
     313         345 : __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_cu **cu)
     314             : {
     315         345 :   struct dwfl_arange *arange;
     316         345 :   return addrarange (mod, addr, &arange) ?: arangecu (mod, arange, cu);
     317             : }

Generated by: LCOV version 1.13