LCOV - code coverage report
Current view: top level - libdw - libdw_findcu.c (source / functions) Hit Total Coverage
Test: elfutils-0.189 Lines: 130 141 92.2 %
Date: 2023-10-12 16:07:27 Functions: 6 6 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 68 88 77.3 %

           Branch data     Line data    Source code
       1                 :            : /* Find CU for given offset.
       2                 :            :    Copyright (C) 2003-2010, 2014, 2016, 2017, 2018 Red Hat, Inc.
       3                 :            :    This file is part of elfutils.
       4                 :            :    Written by Ulrich Drepper <drepper@redhat.com>, 2003.
       5                 :            : 
       6                 :            :    This file is free software; you can redistribute it and/or modify
       7                 :            :    it under the terms of either
       8                 :            : 
       9                 :            :      * the GNU Lesser General Public License as published by the Free
      10                 :            :        Software Foundation; either version 3 of the License, or (at
      11                 :            :        your option) any later version
      12                 :            : 
      13                 :            :    or
      14                 :            : 
      15                 :            :      * the GNU General Public License as published by the Free
      16                 :            :        Software Foundation; either version 2 of the License, or (at
      17                 :            :        your option) any later version
      18                 :            : 
      19                 :            :    or both in parallel, as here.
      20                 :            : 
      21                 :            :    elfutils is distributed in the hope that it will be useful, but
      22                 :            :    WITHOUT ANY WARRANTY; without even the implied warranty of
      23                 :            :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      24                 :            :    General Public License for more details.
      25                 :            : 
      26                 :            :    You should have received copies of the GNU General Public License and
      27                 :            :    the GNU Lesser General Public License along with this program.  If
      28                 :            :    not, see <http://www.gnu.org/licenses/>.  */
      29                 :            : 
      30                 :            : #ifdef HAVE_CONFIG_H
      31                 :            : # include <config.h>
      32                 :            : #endif
      33                 :            : 
      34                 :            : #include <assert.h>
      35                 :            : #include <search.h>
      36                 :            : #include "libdwP.h"
      37                 :            : 
      38                 :            : static int
      39                 :   13731764 : findcu_cb (const void *arg1, const void *arg2)
      40                 :            : {
      41                 :   13731764 :   struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1;
      42                 :   13731764 :   struct Dwarf_CU *cu2 = (struct Dwarf_CU *) arg2;
      43                 :            : 
      44                 :            :   /* Find out which of the two arguments is the search value.  It has
      45                 :            :      end offset 0.  */
      46         [ +  + ]:   13731764 :   if (cu1->end == 0)
      47                 :            :     {
      48         [ +  + ]:   13253894 :       if (cu1->start < cu2->start)
      49                 :            :         return -1;
      50         [ +  + ]:   13226816 :       if (cu1->start >= cu2->end)
      51                 :   11918088 :         return 1;
      52                 :            :     }
      53                 :            :   else
      54                 :            :     {
      55         [ -  + ]:     477870 :       if (cu2->start < cu1->start)
      56                 :            :         return 1;
      57         [ #  # ]:          0 :       if (cu2->start >= cu1->end)
      58                 :          0 :         return -1;
      59                 :            :     }
      60                 :            : 
      61                 :            :   return 0;
      62                 :            : }
      63                 :            : 
      64                 :            : int
      65                 :        474 : __libdw_finddbg_cb (const void *arg1, const void *arg2)
      66                 :            : {
      67                 :        474 :   Dwarf *dbg1 = (Dwarf *) arg1;
      68                 :        474 :   Dwarf *dbg2 = (Dwarf *) arg2;
      69                 :            : 
      70                 :        474 :   Elf_Data *dbg1_data = dbg1->sectiondata[IDX_debug_info];
      71                 :        474 :   unsigned char *dbg1_start = dbg1_data->d_buf;
      72                 :        474 :   size_t dbg1_size = dbg1_data->d_size;
      73                 :            : 
      74                 :        474 :   Elf_Data *dbg2_data = dbg2->sectiondata[IDX_debug_info];
      75                 :        474 :   unsigned char *dbg2_start = dbg2_data->d_buf;
      76                 :        474 :   size_t dbg2_size = dbg2_data->d_size;
      77                 :            : 
      78                 :            :   /* Find out which of the two arguments is the search value.  It has
      79                 :            :      a size of 0.  */
      80         [ +  + ]:        474 :   if (dbg1_size == 0)
      81                 :            :     {
      82         [ +  - ]:        440 :       if (dbg1_start < dbg2_start)
      83                 :            :         return -1;
      84         [ +  + ]:        440 :       if (dbg1_start >= dbg2_start + dbg2_size)
      85                 :        144 :         return 1;
      86                 :            :     }
      87                 :            :   else
      88                 :            :     {
      89         [ +  + ]:         34 :       if (dbg2_start < dbg1_start)
      90                 :            :         return 1;
      91         [ +  - ]:          4 :       if (dbg2_start >= dbg1_start + dbg1_size)
      92                 :          4 :         return -1;
      93                 :            :     }
      94                 :            : 
      95                 :            :   return 0;
      96                 :            : }
      97                 :            : 
      98                 :            : struct Dwarf_CU *
      99                 :            : internal_function
     100                 :      46916 : __libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
     101                 :            : {
     102                 :      93832 :   Dwarf_Off *const offsetp
     103         [ +  + ]:      46916 :     = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
     104                 :      46916 :   void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
     105                 :            : 
     106                 :      46916 :   Dwarf_Off oldoff = *offsetp;
     107                 :      46916 :   uint16_t version;
     108                 :      46916 :   uint8_t unit_type;
     109                 :      46916 :   uint8_t address_size;
     110                 :      46916 :   uint8_t offset_size;
     111                 :      46916 :   Dwarf_Off abbrev_offset;
     112                 :      46916 :   uint64_t unit_id8;
     113                 :      46916 :   Dwarf_Off subdie_offset;
     114                 :            : 
     115         [ +  + ]:      46916 :   if (__libdw_next_unit (dbg, debug_types, oldoff, offsetp, NULL,
     116                 :            :                          &version, &unit_type, &abbrev_offset,
     117                 :            :                          &address_size, &offset_size,
     118                 :            :                          &unit_id8, &subdie_offset) != 0)
     119                 :            :     /* No more entries.  */
     120                 :            :     return NULL;
     121                 :            : 
     122                 :            :   /* We only know how to handle the DWARF version 2 through 5 formats.
     123                 :            :      For v4 debug types we only handle version 4.  */
     124   [ +  -  +  - ]:      46906 :   if (unlikely (version < 2) || unlikely (version > 5)
     125   [ +  +  -  + ]:      46906 :       || (debug_types && unlikely (version != 4)))
     126                 :            :     {
     127                 :          0 :       __libdw_seterrno (DWARF_E_VERSION);
     128                 :          0 :       return NULL;
     129                 :            :     }
     130                 :            : 
     131                 :            :   /* We only handle 32 or 64 bit (4 or 8 byte) addresses and offsets.
     132                 :            :      Just assume we are dealing with 64bit in case the size is "unknown".
     133                 :            :      Too much code assumes if it isn't 4 then it is 8 (or the other way
     134                 :            :      around).  */
     135         [ -  + ]:      46906 :   if (unlikely (address_size != 4 && address_size != 8))
     136                 :          0 :     address_size = 8;
     137         [ -  + ]:      46906 :   if (unlikely (offset_size != 4 && offset_size != 8))
     138                 :          0 :     offset_size = 8;
     139                 :            : 
     140                 :            :   /* Invalid or truncated debug section data?  */
     141                 :      46906 :   size_t sec_idx = debug_types ? IDX_debug_types : IDX_debug_info;
     142                 :      46906 :   Elf_Data *data = dbg->sectiondata[sec_idx];
     143         [ -  + ]:      46906 :   if (unlikely (*offsetp > data->d_size))
     144                 :          0 :     *offsetp = data->d_size;
     145                 :            : 
     146                 :            :   /* Create an entry for this CU.  */
     147         [ +  + ]:      46906 :   struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
     148                 :            : 
     149                 :      46906 :   newp->dbg = dbg;
     150                 :      46906 :   newp->sec_idx = sec_idx;
     151                 :      46906 :   newp->start = oldoff;
     152                 :      46906 :   newp->end = *offsetp;
     153                 :      46906 :   newp->address_size = address_size;
     154                 :      46906 :   newp->offset_size = offset_size;
     155                 :      46906 :   newp->version = version;
     156                 :      46906 :   newp->unit_id8 = unit_id8;
     157                 :      46906 :   newp->subdie_offset = subdie_offset;
     158                 :      46906 :   Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
     159                 :      46906 :   newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
     160                 :      46906 :   newp->files = NULL;
     161                 :      46906 :   newp->lines = NULL;
     162                 :      46906 :   newp->locs = NULL;
     163                 :      46906 :   newp->split = (Dwarf_CU *) -1;
     164                 :      46906 :   newp->base_address = (Dwarf_Addr) -1;
     165                 :      46906 :   newp->addr_base = (Dwarf_Off) -1;
     166                 :      46906 :   newp->str_off_base = (Dwarf_Off) -1;
     167                 :      46906 :   newp->ranges_base = (Dwarf_Off) -1;
     168                 :      46906 :   newp->locs_base = (Dwarf_Off) -1;
     169                 :            : 
     170                 :      46906 :   newp->startp = data->d_buf + newp->start;
     171                 :      46906 :   newp->endp = data->d_buf + newp->end;
     172                 :            : 
     173                 :            :   /* v4 debug type units have version == 4 and unit_type == DW_UT_type.  */
     174         [ +  + ]:      46906 :   if (debug_types)
     175                 :         36 :     newp->unit_type = DW_UT_type;
     176         [ +  + ]:      46870 :   else if (version < 5)
     177                 :            :     {
     178                 :            :       /* This is a reasonable guess (and needed to get the CUDIE).  */
     179                 :       1246 :       newp->unit_type = DW_UT_compile;
     180                 :            : 
     181                 :            :       /* But set it correctly from the actual CUDIE tag.  */
     182                 :       1246 :       Dwarf_Die cudie = CUDIE (newp);
     183                 :       1246 :       int tag = INTUSE(dwarf_tag) (&cudie);
     184         [ +  + ]:       1246 :       if (tag == DW_TAG_compile_unit)
     185                 :            :         {
     186                 :       1196 :           Dwarf_Attribute dwo_id;
     187         [ +  + ]:       1196 :           if (INTUSE(dwarf_attr) (&cudie, DW_AT_GNU_dwo_id, &dwo_id) != NULL)
     188                 :            :             {
     189                 :        142 :               Dwarf_Word id8;
     190         [ +  - ]:        142 :               if (INTUSE(dwarf_formudata) (&dwo_id, &id8) == 0)
     191                 :            :                 {
     192         [ +  + ]:        142 :                   if (INTUSE(dwarf_haschildren) (&cudie) == 0
     193         [ +  - ]:         68 :                       && INTUSE(dwarf_hasattr) (&cudie,
     194                 :            :                                                 DW_AT_GNU_dwo_name) == 1)
     195                 :         68 :                     newp->unit_type = DW_UT_skeleton;
     196                 :            :                   else
     197                 :         74 :                     newp->unit_type = DW_UT_split_compile;
     198                 :            : 
     199                 :        142 :                   newp->unit_id8 = id8;
     200                 :            :                 }
     201                 :            :             }
     202                 :            :         }
     203         [ +  + ]:         50 :       else if (tag == DW_TAG_partial_unit)
     204                 :         46 :         newp->unit_type = DW_UT_partial;
     205         [ -  + ]:          4 :       else if (tag == DW_TAG_type_unit)
     206                 :          0 :         newp->unit_type = DW_UT_type;
     207                 :            :     }
     208                 :            :   else
     209                 :      45624 :     newp->unit_type = unit_type;
     210                 :            : 
     211                 :            :   /* Store a reference to any type unit ids in the hash for quick lookup.  */
     212         [ +  + ]:      46906 :   if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)
     213                 :         36 :     Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, unit_id8, newp);
     214                 :            : 
     215                 :            :   /* Add the new entry to the search tree.  */
     216         [ -  + ]:      46906 :   if (tsearch (newp, tree, findcu_cb) == NULL)
     217                 :            :     {
     218                 :            :       /* Something went wrong.  Undo the operation.  */
     219                 :          0 :       *offsetp = oldoff;
     220                 :          0 :       __libdw_seterrno (DWARF_E_NOMEM);
     221                 :          0 :       return NULL;
     222                 :            :     }
     223                 :            : 
     224                 :            :   return newp;
     225                 :            : }
     226                 :            : 
     227                 :            : struct Dwarf_CU *
     228                 :            : internal_function
     229                 :      76024 : __libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool v4_debug_types)
     230                 :            : {
     231         [ +  + ]:      76024 :   void **tree = v4_debug_types ? &dbg->tu_tree : &dbg->cu_tree;
     232                 :     152048 :   Dwarf_Off *next_offset
     233                 :      76024 :     = v4_debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
     234                 :            : 
     235                 :            :   /* Maybe we already know that CU.  */
     236                 :      76024 :   struct Dwarf_CU fake = { .start = start, .end = 0 };
     237                 :      76024 :   struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
     238         [ +  + ]:      76024 :   if (found != NULL)
     239                 :      29112 :     return *found;
     240                 :            : 
     241         [ +  + ]:      46912 :   if (start < *next_offset)
     242                 :            :     {
     243                 :         10 :       __libdw_seterrno (DWARF_E_INVALID_DWARF);
     244                 :         10 :       return NULL;
     245                 :            :     }
     246                 :            : 
     247                 :            :   /* No.  Then read more CUs.  */
     248                 :      46912 :   while (1)
     249                 :            :     {
     250                 :      46912 :       struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, v4_debug_types);
     251         [ +  + ]:      46912 :       if (newp == NULL)
     252                 :            :         return NULL;
     253                 :            : 
     254                 :            :       /* Is this the one we are looking for?  */
     255   [ +  +  +  - ]:      46904 :       if (start < *next_offset || start == newp->start)
     256                 :      46894 :         return newp;
     257                 :            :     }
     258                 :            :   /* NOTREACHED */
     259                 :            : }
     260                 :            : 
     261                 :            : struct Dwarf_CU *
     262                 :            : internal_function
     263                 :    1279942 : __libdw_findcu_addr (Dwarf *dbg, void *addr)
     264                 :            : {
     265                 :    1279942 :   void **tree;
     266                 :    1279942 :   Dwarf_Off start;
     267         [ +  + ]:    1279942 :   if (addr >= dbg->sectiondata[IDX_debug_info]->d_buf
     268                 :    1279616 :       && addr < (dbg->sectiondata[IDX_debug_info]->d_buf
     269         [ +  + ]:    1279616 :                  + dbg->sectiondata[IDX_debug_info]->d_size))
     270                 :            :     {
     271                 :    1279584 :       tree = &dbg->cu_tree;
     272                 :    1279584 :       start = addr - dbg->sectiondata[IDX_debug_info]->d_buf;
     273                 :            :     }
     274         [ +  + ]:        358 :   else if (dbg->sectiondata[IDX_debug_types] != NULL
     275         [ +  - ]:         32 :            && addr >= dbg->sectiondata[IDX_debug_types]->d_buf
     276                 :         32 :            && addr < (dbg->sectiondata[IDX_debug_types]->d_buf
     277         [ +  - ]:         32 :                       + dbg->sectiondata[IDX_debug_types]->d_size))
     278                 :            :     {
     279                 :         32 :       tree = &dbg->tu_tree;
     280                 :         32 :       start = addr - dbg->sectiondata[IDX_debug_types]->d_buf;
     281                 :            :     }
     282                 :            :   else
     283                 :            :     return NULL;
     284                 :            : 
     285                 :    1279616 :   struct Dwarf_CU fake = { .start = start, .end = 0 };
     286                 :    1279616 :   struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
     287                 :            : 
     288         [ -  + ]:    1279616 :   if (found != NULL)
     289                 :    1279616 :     return *found;
     290                 :            : 
     291                 :            :   return NULL;
     292                 :            : }
     293                 :            : 
     294                 :            : Dwarf *
     295                 :            : internal_function
     296                 :        296 : __libdw_find_split_dbg_addr (Dwarf *dbg, void *addr)
     297                 :            : {
     298                 :            :   /* XXX Assumes split DWARF only has CUs in main IDX_debug_info.  */
     299                 :        296 :   Elf_Data fake_data = { .d_buf = addr, .d_size = 0 };
     300                 :        296 :   Dwarf fake = { .sectiondata[IDX_debug_info] = &fake_data };
     301                 :        296 :   Dwarf **found = tfind (&fake, &dbg->split_tree, __libdw_finddbg_cb);
     302                 :            : 
     303         [ +  - ]:        296 :   if (found != NULL)
     304                 :        296 :     return *found;
     305                 :            : 
     306                 :            :   return NULL;
     307                 :            : }

Generated by: LCOV version 1.16