LCOV - code coverage report
Current view: top level - libdw - libdw_findcu.c (source / functions) Hit Total Coverage
Test: elfutils-0.191 Lines: 135 146 92.5 %
Date: 2024-05-12 22:47:49 Functions: 6 6 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 70 90 77.8 %

           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                 :   15280452 : findcu_cb (const void *arg1, const void *arg2)
      40                 :            : {
      41                 :   15280452 :   struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1;
      42                 :   15280452 :   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         [ +  + ]:   15280452 :   if (cu1->end == 0)
      47                 :            :     {
      48         [ +  + ]:   14392776 :       if (cu1->start < cu2->start)
      49                 :            :         return -1;
      50         [ +  + ]:   14364632 :       if (cu1->start >= cu2->end)
      51                 :   12994322 :         return 1;
      52                 :            :     }
      53                 :            :   else
      54                 :            :     {
      55         [ -  + ]:     887676 :       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                 :        522 : __libdw_finddbg_cb (const void *arg1, const void *arg2)
      66                 :            : {
      67                 :        522 :   Dwarf *dbg1 = (Dwarf *) arg1;
      68                 :        522 :   Dwarf *dbg2 = (Dwarf *) arg2;
      69                 :            : 
      70                 :        522 :   Elf_Data *dbg1_data = dbg1->sectiondata[IDX_debug_info];
      71                 :        522 :   unsigned char *dbg1_start = dbg1_data->d_buf;
      72                 :        522 :   size_t dbg1_size = dbg1_data->d_size;
      73                 :            : 
      74                 :        522 :   Elf_Data *dbg2_data = dbg2->sectiondata[IDX_debug_info];
      75                 :        522 :   unsigned char *dbg2_start = dbg2_data->d_buf;
      76                 :        522 :   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         [ +  + ]:        522 :   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         [ +  + ]:         82 :       if (dbg2_start < dbg1_start)
      90                 :            :         return 1;
      91         [ +  + ]:         52 :       if (dbg2_start >= dbg1_start + dbg1_size)
      92                 :          8 :         return -1;
      93                 :            :     }
      94                 :            : 
      95                 :            :   return 0;
      96                 :            : }
      97                 :            : 
      98                 :            : struct Dwarf_CU *
      99                 :            : internal_function
     100                 :      80786 : __libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
     101                 :            : {
     102                 :     161572 :   Dwarf_Off *const offsetp
     103         [ +  + ]:      80786 :     = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
     104                 :      80786 :   void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
     105                 :            : 
     106                 :      80786 :   Dwarf_Off oldoff = *offsetp;
     107                 :      80786 :   uint16_t version;
     108                 :      80786 :   uint8_t unit_type;
     109                 :      80786 :   uint8_t address_size;
     110                 :      80786 :   uint8_t offset_size;
     111                 :      80786 :   Dwarf_Off abbrev_offset;
     112                 :      80786 :   uint64_t unit_id8;
     113                 :      80786 :   Dwarf_Off subdie_offset;
     114                 :            : 
     115         [ +  + ]:      80786 :   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   [ +  -  +  - ]:      80776 :   if (unlikely (version < 2) || unlikely (version > 5)
     125   [ +  +  -  + ]:      80776 :       || (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         [ -  + ]:      80776 :   if (unlikely (address_size != 4 && address_size != 8))
     136                 :          0 :     address_size = 8;
     137         [ -  + ]:      80776 :   if (unlikely (offset_size != 4 && offset_size != 8))
     138                 :          0 :     offset_size = 8;
     139                 :            : 
     140                 :            :   /* Invalid or truncated debug section data?  */
     141                 :      80776 :   size_t sec_idx = debug_types ? IDX_debug_types : IDX_debug_info;
     142                 :      80776 :   Elf_Data *data = dbg->sectiondata[sec_idx];
     143         [ -  + ]:      80776 :   if (unlikely (*offsetp > data->d_size))
     144                 :          0 :     *offsetp = data->d_size;
     145                 :            : 
     146                 :      80776 :   uint32_t dwp_row;
     147                 :      80776 :   Dwarf_Off dwp_abbrev_offset;
     148         [ -  + ]:      80776 :   if (__libdw_dwp_find_unit (dbg, debug_types, oldoff, version, unit_type,
     149                 :            :                              unit_id8, &dwp_row, &dwp_abbrev_offset) != 0)
     150                 :            :     return NULL;
     151                 :      80776 :   abbrev_offset += dwp_abbrev_offset;
     152                 :            : 
     153                 :            :   /* Create an entry for this CU.  */
     154         [ +  + ]:      80776 :   struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
     155                 :            : 
     156                 :      80776 :   newp->dbg = dbg;
     157                 :      80776 :   newp->sec_idx = sec_idx;
     158                 :      80776 :   newp->start = oldoff;
     159                 :      80776 :   newp->end = *offsetp;
     160                 :      80776 :   newp->dwp_row = dwp_row;
     161                 :      80776 :   newp->address_size = address_size;
     162                 :      80776 :   newp->offset_size = offset_size;
     163                 :      80776 :   newp->version = version;
     164                 :      80776 :   newp->unit_id8 = unit_id8;
     165                 :      80776 :   newp->subdie_offset = subdie_offset;
     166                 :      80776 :   Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
     167                 :      80776 :   newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
     168                 :      80776 :   newp->files = NULL;
     169                 :      80776 :   newp->lines = NULL;
     170                 :      80776 :   newp->locs = NULL;
     171                 :      80776 :   newp->split = (Dwarf_CU *) -1;
     172                 :      80776 :   newp->base_address = (Dwarf_Addr) -1;
     173                 :      80776 :   newp->addr_base = (Dwarf_Off) -1;
     174                 :      80776 :   newp->str_off_base = (Dwarf_Off) -1;
     175                 :      80776 :   newp->ranges_base = (Dwarf_Off) -1;
     176                 :      80776 :   newp->locs_base = (Dwarf_Off) -1;
     177                 :            : 
     178                 :      80776 :   newp->startp = data->d_buf + newp->start;
     179                 :      80776 :   newp->endp = data->d_buf + newp->end;
     180                 :            : 
     181                 :            :   /* v4 debug type units have version == 4 and unit_type == DW_UT_type.  */
     182         [ +  + ]:      80776 :   if (debug_types)
     183                 :         44 :     newp->unit_type = DW_UT_type;
     184         [ +  + ]:      80732 :   else if (version < 5)
     185                 :            :     {
     186                 :            :       /* This is a reasonable guess (and needed to get the CUDIE).  */
     187                 :       1402 :       newp->unit_type = DW_UT_compile;
     188                 :            : 
     189                 :            :       /* But set it correctly from the actual CUDIE tag.  */
     190                 :       1402 :       Dwarf_Die cudie = CUDIE (newp);
     191                 :       1402 :       int tag = INTUSE(dwarf_tag) (&cudie);
     192         [ +  + ]:       1402 :       if (tag == DW_TAG_compile_unit)
     193                 :            :         {
     194                 :       1352 :           Dwarf_Attribute dwo_id;
     195         [ +  + ]:       1352 :           if (INTUSE(dwarf_attr) (&cudie, DW_AT_GNU_dwo_id, &dwo_id) != NULL)
     196                 :            :             {
     197                 :        270 :               Dwarf_Word id8;
     198         [ +  - ]:        270 :               if (INTUSE(dwarf_formudata) (&dwo_id, &id8) == 0)
     199                 :            :                 {
     200         [ +  + ]:        270 :                   if (INTUSE(dwarf_haschildren) (&cudie) == 0
     201         [ +  - ]:        132 :                       && INTUSE(dwarf_hasattr) (&cudie,
     202                 :            :                                                 DW_AT_GNU_dwo_name) == 1)
     203                 :        132 :                     newp->unit_type = DW_UT_skeleton;
     204                 :            :                   else
     205                 :        138 :                     newp->unit_type = DW_UT_split_compile;
     206                 :            : 
     207                 :        270 :                   newp->unit_id8 = id8;
     208                 :            :                 }
     209                 :            :             }
     210                 :            :         }
     211         [ +  + ]:         50 :       else if (tag == DW_TAG_partial_unit)
     212                 :         46 :         newp->unit_type = DW_UT_partial;
     213         [ -  + ]:          4 :       else if (tag == DW_TAG_type_unit)
     214                 :          0 :         newp->unit_type = DW_UT_type;
     215                 :            :     }
     216                 :            :   else
     217                 :      79330 :     newp->unit_type = unit_type;
     218                 :            : 
     219                 :            :   /* Store a reference to any type unit ids in the hash for quick lookup.  */
     220         [ +  + ]:      80776 :   if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)
     221                 :         74 :     Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, unit_id8, newp);
     222                 :            : 
     223                 :            :   /* Add the new entry to the search tree.  */
     224         [ -  + ]:      80776 :   if (tsearch (newp, tree, findcu_cb) == NULL)
     225                 :            :     {
     226                 :            :       /* Something went wrong.  Undo the operation.  */
     227                 :          0 :       *offsetp = oldoff;
     228                 :          0 :       __libdw_seterrno (DWARF_E_NOMEM);
     229                 :          0 :       return NULL;
     230                 :            :     }
     231                 :            : 
     232                 :            :   return newp;
     233                 :            : }
     234                 :            : 
     235                 :            : struct Dwarf_CU *
     236                 :            : internal_function
     237                 :     112762 : __libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool v4_debug_types)
     238                 :            : {
     239         [ +  + ]:     112762 :   void **tree = v4_debug_types ? &dbg->tu_tree : &dbg->cu_tree;
     240                 :     225524 :   Dwarf_Off *next_offset
     241                 :     112762 :     = v4_debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
     242                 :            : 
     243                 :            :   /* Maybe we already know that CU.  */
     244                 :     112762 :   struct Dwarf_CU fake = { .start = start, .end = 0 };
     245                 :     112762 :   struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
     246         [ +  + ]:     112762 :   if (found != NULL)
     247                 :      32000 :     return *found;
     248                 :            : 
     249         [ +  + ]:      80762 :   if (start < *next_offset)
     250                 :            :     {
     251                 :         10 :       __libdw_seterrno (DWARF_E_INVALID_DWARF);
     252                 :         10 :       return NULL;
     253                 :            :     }
     254                 :            : 
     255                 :            :   /* No.  Then read more CUs.  */
     256                 :      80782 :   while (1)
     257                 :            :     {
     258                 :      80782 :       struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, v4_debug_types);
     259         [ +  + ]:      80782 :       if (newp == NULL)
     260                 :            :         return NULL;
     261                 :            : 
     262                 :            :       /* Is this the one we are looking for?  */
     263   [ +  +  +  - ]:      80774 :       if (start < *next_offset || start == newp->start)
     264                 :      80744 :         return newp;
     265                 :            :     }
     266                 :            :   /* NOTREACHED */
     267                 :            : }
     268                 :            : 
     269                 :            : struct Dwarf_CU *
     270                 :            : internal_function
     271                 :    1338636 : __libdw_findcu_addr (Dwarf *dbg, void *addr)
     272                 :            : {
     273                 :    1338636 :   void **tree;
     274                 :    1338636 :   Dwarf_Off start;
     275         [ +  + ]:    1338636 :   if (addr >= dbg->sectiondata[IDX_debug_info]->d_buf
     276                 :    1338310 :       && addr < (dbg->sectiondata[IDX_debug_info]->d_buf
     277         [ +  + ]:    1338310 :                  + dbg->sectiondata[IDX_debug_info]->d_size))
     278                 :            :     {
     279                 :    1338278 :       tree = &dbg->cu_tree;
     280                 :    1338278 :       start = addr - dbg->sectiondata[IDX_debug_info]->d_buf;
     281                 :            :     }
     282         [ +  + ]:        358 :   else if (dbg->sectiondata[IDX_debug_types] != NULL
     283         [ +  - ]:         32 :            && addr >= dbg->sectiondata[IDX_debug_types]->d_buf
     284                 :         32 :            && addr < (dbg->sectiondata[IDX_debug_types]->d_buf
     285         [ +  - ]:         32 :                       + dbg->sectiondata[IDX_debug_types]->d_size))
     286                 :            :     {
     287                 :         32 :       tree = &dbg->tu_tree;
     288                 :         32 :       start = addr - dbg->sectiondata[IDX_debug_types]->d_buf;
     289                 :            :     }
     290                 :            :   else
     291                 :            :     return NULL;
     292                 :            : 
     293                 :    1338310 :   struct Dwarf_CU fake = { .start = start, .end = 0 };
     294                 :    1338310 :   struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
     295                 :            : 
     296         [ -  + ]:    1338310 :   if (found != NULL)
     297                 :    1338310 :     return *found;
     298                 :            : 
     299                 :            :   return NULL;
     300                 :            : }
     301                 :            : 
     302                 :            : Dwarf *
     303                 :            : internal_function
     304                 :        296 : __libdw_find_split_dbg_addr (Dwarf *dbg, void *addr)
     305                 :            : {
     306                 :            :   /* XXX Assumes split DWARF only has CUs in main IDX_debug_info.  */
     307                 :        296 :   Elf_Data fake_data = { .d_buf = addr, .d_size = 0 };
     308                 :        296 :   Dwarf fake = { .sectiondata[IDX_debug_info] = &fake_data };
     309                 :        296 :   Dwarf **found = tfind (&fake, &dbg->split_tree, __libdw_finddbg_cb);
     310                 :            : 
     311         [ +  - ]:        296 :   if (found != NULL)
     312                 :        296 :     return *found;
     313                 :            : 
     314                 :            :   return NULL;
     315                 :            : }

Generated by: LCOV version 1.16