LCOV - code coverage report
Current view: top level - libdwfl - cu.c (source / functions) Hit Total Coverage
Test: elfutils-0.190 Lines: 109 127 85.8 %
Date: 2024-03-01 03:34:13 Functions: 7 8 87.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 53 84 63.1 %

           Branch data     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 "libdwP.h"
      35                 :            : #include "memory-access.h"
      36                 :            : #include <search.h>
      37                 :            : 
      38                 :            : 
      39                 :            : static inline Dwarf_Arange *
      40                 :       1052 : dwar (Dwfl_Module *mod, unsigned int idx)
      41                 :            : {
      42                 :       1052 :   return &mod->dw->dieranges->info[mod->aranges[idx].arange];
      43                 :            : }
      44                 :            : 
      45                 :            : 
      46                 :            : static Dwfl_Error
      47                 :        900 : addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
      48                 :            : {
      49         [ +  + ]:        900 :   if (mod->aranges == NULL)
      50                 :            :     {
      51                 :        124 :       struct dwfl_arange *aranges = NULL;
      52                 :        124 :       Dwarf_Aranges *dwaranges = NULL;
      53                 :        124 :       size_t naranges;
      54         [ +  - ]:        124 :       if (__libdw_getdieranges (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         [ +  - ]:        124 :       if (naranges != 0)
      60                 :            :         {
      61                 :        124 :           aranges = malloc (naranges * sizeof *aranges);
      62         [ +  - ]:        124 :           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                 :        124 :           naranges = 0;
      73                 :        124 :           Dwarf_Off lastcu = 0;
      74         [ +  + ]:        292 :           for (size_t i = 0; i < dwaranges->naranges; ++i)
      75   [ +  +  +  + ]:        168 :             if (i == 0 || dwaranges->info[i].offset != lastcu)
      76                 :            :               {
      77                 :        152 :                 aranges[naranges].arange = i;
      78                 :        152 :                 aranges[naranges].cu = NULL;
      79                 :        152 :                 ++naranges;
      80                 :        152 :                 lastcu = dwaranges->info[i].offset;
      81                 :            :               }
      82                 :            :         }
      83                 :            : 
      84                 :            :       /* Store the final array, which is probably much smaller than before.  */
      85                 :        124 :       mod->naranges = naranges;
      86         [ +  - ]:        124 :       if (naranges > 0)
      87                 :        124 :         mod->aranges = (realloc (aranges, naranges * sizeof aranges[0])
      88         [ -  + ]:        124 :                         ?: aranges);
      89         [ #  # ]:          0 :       else if (aranges != NULL)
      90                 :          0 :         free (aranges);
      91                 :        124 :       mod->lazycu += naranges;
      92                 :            :     }
      93                 :            : 
      94                 :            :   /* The address must be inside the module to begin with.  */
      95                 :        900 :   addr = dwfl_deadjust_dwarf_addr (mod, addr);
      96                 :            : 
      97                 :            :   /* The ranges are sorted by address, so we can use binary search.  */
      98                 :        900 :   size_t l = 0, u = mod->naranges;
      99         [ +  - ]:        976 :   while (l < u)
     100                 :            :     {
     101                 :        976 :       size_t idx = (l + u) / 2;
     102                 :        976 :       Dwarf_Addr start = dwar (mod, idx)->addr;
     103         [ -  + ]:        976 :       if (addr < start)
     104                 :            :         {
     105                 :          0 :           u = idx;
     106                 :          0 :           continue;
     107                 :            :         }
     108         [ +  + ]:        976 :       else if (addr > start)
     109                 :            :         {
     110         [ +  + ]:        740 :           if (idx + 1 < mod->naranges)
     111                 :            :             {
     112         [ +  - ]:         76 :               if (addr >= dwar (mod, idx + 1)->addr)
     113                 :            :                 {
     114                 :         76 :                   l = idx + 1;
     115                 :         76 :                   continue;
     116                 :            :                 }
     117                 :            :             }
     118                 :            :           else
     119                 :            :             {
     120                 :            :               /* It might be in the last range.  */
     121                 :        664 :               const Dwarf_Arange *last
     122                 :        664 :                 = &mod->dw->dieranges->info[mod->dw->dieranges->naranges - 1];
     123         [ +  + ]:        664 :               if (addr > last->addr + last->length)
     124                 :            :                 break;
     125                 :            :             }
     126                 :            :         }
     127                 :            : 
     128                 :        888 :       *arange = &mod->aranges[idx];
     129                 :        888 :       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                 :        130 : less_lazy (Dwfl_Module *mod)
     149                 :            : {
     150         [ -  + ]:        130 :   if (--mod->lazycu > 0)
     151                 :            :     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                 :     223450 : cudie_offset (const struct dwfl_cu *cu)
     160                 :            : {
     161                 :     223450 :   return __libdw_first_die_off_from_cu (cu->die.cu);
     162                 :            : }
     163                 :            : 
     164                 :            : static int
     165                 :     223450 : compare_cukey (const void *a, const void *b)
     166                 :            : {
     167                 :     223450 :   Dwarf_Off a_off = cudie_offset (a);
     168                 :     223450 :   Dwarf_Off b_off = cudie_offset (b);
     169         [ +  + ]:     223450 :   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                 :      19304 : intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
     175                 :            : {
     176         [ -  + ]:      19304 :   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                 :      19304 :   Dwarf_Die cudie;
     195                 :      19304 :   Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cudie);
     196         [ +  - ]:      19304 :   if (die == NULL)
     197                 :            :     return DWFL_E_LIBDW;
     198                 :            : 
     199                 :      19304 :   struct dwfl_cu key;
     200                 :      19304 :   key.die.cu = die->cu;
     201                 :      19304 :   struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
     202         [ +  - ]:      19304 :   if (unlikely (found == NULL))
     203                 :            :     return DWFL_E_NOMEM;
     204                 :            : 
     205   [ +  +  -  + ]:      19304 :   if (*found == &key || *found == NULL)
     206                 :            :     {
     207                 :            :       /* This is a new entry, meaning we haven't looked at this CU.  */
     208                 :            : 
     209                 :      19302 :       *found = NULL;
     210                 :            : 
     211                 :      19302 :       struct dwfl_cu *cu = malloc (sizeof *cu);
     212         [ +  - ]:      19302 :       if (unlikely (cu == NULL))
     213                 :            :         return DWFL_E_NOMEM;
     214                 :            : 
     215                 :      19302 :       cu->mod = mod;
     216                 :      19302 :       cu->next = NULL;
     217                 :      19302 :       cu->lines = NULL;
     218                 :      19302 :       cu->die = cudie;
     219                 :            : 
     220                 :      19302 :       struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
     221                 :            :                                                    * sizeof (mod->cu[0])));
     222         [ -  + ]:      19302 :       if (newvec == NULL)
     223                 :            :         {
     224                 :          0 :           free (cu);
     225                 :          0 :           return DWFL_E_NOMEM;
     226                 :            :         }
     227                 :      19302 :       mod->cu = newvec;
     228                 :            : 
     229                 :      19302 :       mod->cu[mod->ncu++] = cu;
     230         [ +  + ]:      19302 :       if (cu->die.cu->start == 0)
     231                 :        284 :         mod->first_cu = cu;
     232                 :            : 
     233                 :      19302 :       *found = cu;
     234                 :            :     }
     235                 :            : 
     236                 :      19304 :   *result = *found;
     237                 :      19304 :   return DWFL_E_NOERROR;
     238                 :            : }
     239                 :            : 
     240                 :            : 
     241                 :            : /* Traverse all the CUs in the module.  */
     242                 :            : 
     243                 :            : Dwfl_Error
     244                 :            : internal_function
     245                 :      19388 : __libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu,
     246                 :            :                   struct dwfl_cu **cu)
     247                 :            : {
     248                 :      19388 :   Dwarf_Off cuoff;
     249                 :      19388 :   struct dwfl_cu **nextp;
     250                 :            : 
     251         [ +  + ]:      19388 :   if (lastcu == NULL)
     252                 :            :     {
     253                 :            :       /* Start the traversal.  */
     254                 :        192 :       cuoff = 0;
     255                 :        192 :       nextp = &mod->first_cu;
     256                 :            :     }
     257                 :            :   else
     258                 :            :     {
     259                 :            :       /* Continue following LASTCU.  */
     260                 :      19196 :       cuoff = lastcu->die.cu->end;
     261                 :      19196 :       nextp = &lastcu->next;
     262                 :            :     }
     263                 :            : 
     264         [ +  + ]:      19388 :   if (*nextp == NULL)
     265                 :            :     {
     266                 :      19366 :       size_t cuhdrsz;
     267                 :      19366 :       Dwarf_Off nextoff;
     268                 :      19366 :       int end = INTUSE(dwarf_nextcu) (mod->dw, cuoff, &nextoff, &cuhdrsz,
     269                 :            :                                       NULL, NULL, NULL);
     270         [ +  - ]:      19366 :       if (end < 0)
     271                 :        192 :         return DWFL_E_LIBDW;
     272         [ +  + ]:      19366 :       if (end > 0)
     273                 :            :         {
     274                 :        192 :           *cu = NULL;
     275                 :        192 :           return DWFL_E_NOERROR;
     276                 :            :         }
     277                 :            : 
     278                 :      19174 :       Dwfl_Error result = intern_cu (mod, cuoff + cuhdrsz, nextp);
     279         [ +  - ]:      19174 :       if (result != DWFL_E_NOERROR)
     280                 :            :         return result;
     281                 :            : 
     282         [ +  - ]:      19174 :       if (*nextp != (void *) -1
     283   [ +  -  -  + ]:      19174 :           && (*nextp)->next == NULL && nextoff == (Dwarf_Off) -1l)
     284                 :          0 :         (*nextp)->next = (void *) -1l;
     285                 :            :     }
     286                 :            : 
     287         [ +  - ]:      19196 :   *cu = *nextp == (void *) -1l ? NULL : *nextp;
     288                 :      19196 :   return DWFL_E_NOERROR;
     289                 :            : }
     290                 :            : 
     291                 :            : 
     292                 :            : /* Intern the CU arange points to, if necessary.  */
     293                 :            : 
     294                 :            : static Dwfl_Error
     295                 :        888 : arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu)
     296                 :            : {
     297         [ +  + ]:        888 :   if (arange->cu == NULL)
     298                 :            :     {
     299                 :        130 :       const Dwarf_Arange *dwarange = &mod->dw->dieranges->info[arange->arange];
     300                 :        130 :       Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu);
     301         [ +  - ]:        130 :       if (result != DWFL_E_NOERROR)
     302                 :            :         return result;
     303         [ -  + ]:        130 :       assert (arange->cu != NULL && arange->cu != (void *) -1l);
     304                 :        130 :       less_lazy (mod);          /* Each arange with null ->cu counts once.  */
     305                 :            :     }
     306                 :            : 
     307                 :        888 :   *cu = arange->cu;
     308                 :        888 :   return DWFL_E_NOERROR;
     309                 :            : }
     310                 :            : 
     311                 :            : Dwfl_Error
     312                 :            : internal_function
     313                 :        900 : __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_cu **cu)
     314                 :            : {
     315                 :        900 :   struct dwfl_arange *arange;
     316         [ +  + ]:        900 :   return addrarange (mod, addr, &arange) ?: arangecu (mod, arange, cu);
     317                 :            : }

Generated by: LCOV version 1.16