LCOV - code coverage report
Current view: top level - elfutils/libdwfl - cu.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 95 109 87.2 %
Date: 2012-10-31 Functions: 7 8 87.5 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 50 76 65.8 %

           Branch data     Line data    Source code
       1                 :            : /* Keeping track of DWARF compilation units in libdwfl.
       2                 :            :    Copyright (C) 2005-2010 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                 :         39 :   return &mod->dw->aranges->info[mod->aranges[idx].arange];
      39                 :            : }
      40                 :            : 
      41                 :            : 
      42                 :            : static Dwfl_Error
      43                 :         46 : addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
      44                 :            : {
      45         [ +  + ]:         46 :   if (mod->aranges == NULL)
      46                 :            :     {
      47                 :         23 :       struct dwfl_arange *aranges = NULL;
      48                 :         23 :       Dwarf_Aranges *dwaranges = NULL;
      49                 :            :       size_t naranges;
      50         [ +  - ]:         23 :       if (INTUSE(dwarf_getaranges) (mod->dw, &dwaranges, &naranges) != 0)
      51                 :            :         return DWFL_E_LIBDW;
      52                 :            : 
      53                 :            :       /* If the module has no aranges (when no code is included) we
      54                 :            :          allocate nothing.  */
      55         [ +  + ]:         23 :       if (naranges != 0)
      56                 :            :         {
      57                 :         19 :           aranges = malloc (naranges * sizeof *aranges);
      58         [ +  - ]:         19 :           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                 :         19 :           naranges = 0;
      69                 :         19 :           Dwarf_Off lastcu = 0;
      70         [ +  + ]:         43 :           for (size_t i = 0; i < dwaranges->naranges; ++i)
      71 [ +  + ][ +  - ]:         24 :             if (i == 0 || dwaranges->info[i].offset != lastcu)
      72                 :            :               {
      73                 :         24 :                 aranges[naranges].arange = i;
      74                 :         24 :                 aranges[naranges].cu = NULL;
      75                 :         24 :                 ++naranges;
      76                 :         24 :                 lastcu = dwaranges->info[i].offset;
      77                 :            :               }
      78                 :            :         }
      79                 :            : 
      80                 :            :       /* Store the final array, which is probably much smaller than before.  */
      81                 :         23 :       mod->naranges = naranges;
      82                 :         46 :       mod->aranges = (realloc (aranges, naranges * sizeof aranges[0])
      83         [ -  + ]:         23 :                       ?: aranges);
      84                 :         23 :       mod->lazycu += naranges;
      85                 :            :     }
      86                 :            : 
      87                 :            :   /* The address must be inside the module to begin with.  */
      88                 :         46 :   addr = dwfl_deadjust_dwarf_addr (mod, addr);
      89                 :            : 
      90                 :            :   /* The ranges are sorted by address, so we can use binary search.  */
      91                 :         46 :   size_t l = 0, u = mod->naranges;
      92         [ +  + ]:         84 :   while (l < u)
      93                 :            :     {
      94                 :         38 :       size_t idx = (l + u) / 2;
      95                 :        114 :       Dwarf_Addr start = dwar (mod, idx)->addr;
      96         [ -  + ]:         38 :       if (addr < start)
      97                 :            :         {
      98                 :          0 :           u = idx;
      99                 :          0 :           continue;
     100                 :            :         }
     101         [ +  + ]:         38 :       else if (addr > start)
     102                 :            :         {
     103         [ +  + ]:         27 :           if (idx + 1 < mod->naranges)
     104                 :            :             {
     105         [ -  + ]:          1 :               if (addr >= dwar (mod, idx + 1)->addr)
     106                 :            :                 {
     107                 :          0 :                   l = idx + 1;
     108                 :          0 :                   continue;
     109                 :            :                 }
     110                 :            :             }
     111                 :            :           else
     112                 :            :             {
     113                 :            :               /* It might be in the last range.  */
     114                 :         26 :               const Dwarf_Arange *last
     115                 :         26 :                 = &mod->dw->aranges->info[mod->dw->aranges->naranges - 1];
     116         [ +  - ]:         26 :               if (addr > last->addr + last->length)
     117                 :            :                 break;
     118                 :            :             }
     119                 :            :         }
     120                 :            : 
     121                 :         38 :       *arange = &mod->aranges[idx];
     122                 :         38 :       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                 :          0 :     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                 :         19 : less_lazy (Dwfl_Module *mod)
     142                 :            : {
     143         [ -  + ]:         19 :   if (--mod->lazycu > 0)
     144                 :         19 :     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                 :      90360 :   return DIE_OFFSET_FROM_CU_OFFSET (cu->die.cu->start, cu->die.cu->offset_size,
     159                 :            :                                     0);
     160                 :            : }
     161                 :            : 
     162                 :            : static int
     163                 :      45180 : compare_cukey (const void *a, const void *b)
     164                 :            : {
     165                 :      45180 :   return cudie_offset (a) - cudie_offset (b);
     166                 :            : }
     167                 :            : 
     168                 :            : /* Intern the CU if necessary.  */
     169                 :            : static Dwfl_Error
     170                 :       3725 : intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
     171                 :            : {
     172                 :            :   struct Dwarf_CU dwkey;
     173                 :            :   struct dwfl_cu key;
     174                 :       3725 :   key.die.cu = &dwkey;
     175                 :       3725 :   dwkey.offset_size = 0;
     176                 :       3725 :   dwkey.start = cuoff - (3 * 0 - 4 + 3);
     177                 :       3725 :   struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
     178         [ +  - ]:       3725 :   if (unlikely (found == NULL))
     179                 :            :     return DWFL_E_NOMEM;
     180                 :            : 
     181 [ +  + ][ -  + ]:       3725 :   if (*found == &key || *found == NULL)
     182                 :            :     {
     183         [ -  + ]:       3724 :       if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
     184                 :            :         {
     185                 :            :           /* This is the EOF marker.  Now we have interned all the CUs.
     186                 :            :              One increment in MOD->lazycu counts not having hit EOF yet.  */
     187                 :          0 :           *found = (void *) -1l;
     188                 :          0 :           less_lazy (mod);
     189                 :            :         }
     190                 :            :       else
     191                 :            :         {
     192                 :            :           /* This is a new entry, meaning we haven't looked at this CU.  */
     193                 :            : 
     194                 :       3724 :           *found = NULL;
     195                 :            : 
     196                 :       3724 :           struct dwfl_cu *cu = malloc (sizeof *cu);
     197         [ +  - ]:       3724 :           if (unlikely (cu == NULL))
     198                 :            :             return DWFL_E_NOMEM;
     199                 :            : 
     200                 :       3724 :           cu->mod = mod;
     201                 :       3724 :           cu->next = NULL;
     202                 :       3724 :           cu->lines = NULL;
     203                 :            : 
     204                 :            :           /* XXX use non-searching lookup */
     205                 :       3724 :           Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cu->die);
     206         [ +  - ]:       3724 :           if (die == NULL)
     207                 :            :             return DWFL_E_LIBDW;
     208         [ -  + ]:       3724 :           assert (die == &cu->die);
     209                 :            : 
     210                 :       3724 :           struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
     211                 :            :                                                        * sizeof (mod->cu[0])));
     212         [ -  + ]:       3724 :           if (newvec == NULL)
     213                 :            :             {
     214                 :          0 :               free (cu);
     215                 :            :               return DWFL_E_NOMEM;
     216                 :            :             }
     217                 :       3724 :           mod->cu = newvec;
     218                 :            : 
     219                 :       3724 :           mod->cu[mod->ncu++] = cu;
     220         [ +  + ]:       3724 :           if (cu->die.cu->start == 0)
     221                 :         48 :             mod->first_cu = cu;
     222                 :            : 
     223                 :       3724 :           *found = cu;
     224                 :            :         }
     225                 :            :     }
     226                 :            : 
     227                 :       3725 :   *result = *found;
     228                 :            :   return DWFL_E_NOERROR;
     229                 :            : }
     230                 :            : 
     231                 :            : 
     232                 :            : /* Traverse all the CUs in the module.  */
     233                 :            : 
     234                 :            : Dwfl_Error
     235                 :            : internal_function
     236                 :       3753 : __libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu,
     237                 :            :                   struct dwfl_cu **cu)
     238                 :            : {
     239                 :            :   Dwarf_Off cuoff;
     240                 :            :   struct dwfl_cu **nextp;
     241                 :            : 
     242         [ +  + ]:       3753 :   if (lastcu == NULL)
     243                 :            :     {
     244                 :            :       /* Start the traversal.  */
     245                 :         36 :       cuoff = 0;
     246                 :         36 :       nextp = &mod->first_cu;
     247                 :            :     }
     248                 :            :   else
     249                 :            :     {
     250                 :            :       /* Continue following LASTCU.  */
     251                 :       3717 :       cuoff = lastcu->die.cu->end;
     252                 :       3717 :       nextp = &lastcu->next;
     253                 :            :     }
     254                 :            : 
     255         [ +  + ]:       3753 :   if (*nextp == NULL)
     256                 :            :     {
     257                 :            :       size_t cuhdrsz;
     258                 :            :       Dwarf_Off nextoff;
     259                 :       3742 :       int end = INTUSE(dwarf_nextcu) (mod->dw, cuoff, &nextoff, &cuhdrsz,
     260                 :            :                                       NULL, NULL, NULL);
     261         [ +  - ]:       3742 :       if (end < 0)
     262                 :            :         return DWFL_E_LIBDW;
     263         [ +  + ]:       3742 :       if (end > 0)
     264                 :            :         {
     265                 :         36 :           *cu = NULL;
     266                 :            :           return DWFL_E_NOERROR;
     267                 :            :         }
     268                 :            : 
     269                 :       3706 :       Dwfl_Error result = intern_cu (mod, cuoff + cuhdrsz, nextp);
     270         [ +  - ]:       3706 :       if (result != DWFL_E_NOERROR)
     271                 :            :         return result;
     272                 :            : 
     273 [ +  - ][ -  + ]:       3706 :       if ((*nextp)->next == NULL && nextoff == (Dwarf_Off) -1l)
     274                 :       3742 :         (*nextp)->next = (void *) -1l;
     275                 :            :     }
     276                 :            : 
     277         [ +  - ]:       3717 :   *cu = *nextp == (void *) -1l ? NULL : *nextp;
     278                 :       3753 :   return DWFL_E_NOERROR;
     279                 :            : }
     280                 :            : 
     281                 :            : 
     282                 :            : /* Intern the CU arange points to, if necessary.  */
     283                 :            : 
     284                 :            : static Dwfl_Error
     285                 :         38 : arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu)
     286                 :            : {
     287         [ +  + ]:         38 :   if (arange->cu == NULL)
     288                 :            :     {
     289                 :         19 :       const Dwarf_Arange *dwarange = &mod->dw->aranges->info[arange->arange];
     290                 :         19 :       Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu);
     291         [ +  - ]:         19 :       if (result != DWFL_E_NOERROR)
     292                 :            :         return result;
     293         [ -  + ]:         19 :       assert (arange->cu != NULL && arange->cu != (void *) -1l);
     294                 :         19 :       less_lazy (mod);          /* Each arange with null ->cu counts once.  */
     295                 :            :     }
     296                 :            : 
     297                 :         38 :   *cu = arange->cu;
     298                 :         38 :   return DWFL_E_NOERROR;
     299                 :            : }
     300                 :            : 
     301                 :            : Dwfl_Error
     302                 :            : internal_function
     303                 :         46 : __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_cu **cu)
     304                 :            : {
     305                 :            :   struct dwfl_arange *arange;
     306         [ +  + ]:         46 :   return addrarange (mod, addr, &arange) ?: arangecu (mod, arange, cu);
     307                 :      90520 : }

Generated by: LCOV version 1.9