LCOV - code coverage report
Current view: top level - libdw - libdw_findcu.c (source / functions) Hit Total Coverage
Test: elfutils-0.191 Lines: 138 149 92.6 %
Date: 2024-08-30 13:26:44 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 "eu-search.h"
      36                 :            : #include "libdwP.h"
      37                 :            : 
      38                 :            : static int
      39                 :   15189986 : findcu_cb (const void *arg1, const void *arg2)
      40                 :            : {
      41                 :   15189986 :   struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1;
      42                 :   15189986 :   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         [ +  + ]:   15189986 :   if (cu1->end == 0)
      47                 :            :     {
      48         [ +  + ]:   14394352 :       if (cu1->start < cu2->start)
      49                 :            :         return -1;
      50         [ +  + ]:   14366088 :       if (cu1->start >= cu2->end)
      51                 :   12986706 :         return 1;
      52                 :            :     }
      53                 :            :   else
      54                 :            :     {
      55         [ -  + ]:     795634 :       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         [ +  + ]:         48 :       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                 :      71580 : __libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
     101                 :            : {
     102                 :     143160 :   Dwarf_Off *const offsetp
     103         [ +  + ]:      71580 :     = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
     104                 :      71580 :   search_tree *tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
     105                 :            : 
     106                 :      71580 :   Dwarf_Off oldoff = *offsetp;
     107                 :      71580 :   uint16_t version;
     108                 :      71580 :   uint8_t unit_type;
     109                 :      71580 :   uint8_t address_size;
     110                 :      71580 :   uint8_t offset_size;
     111                 :      71580 :   Dwarf_Off abbrev_offset;
     112                 :      71580 :   uint64_t unit_id8;
     113                 :      71580 :   Dwarf_Off subdie_offset;
     114                 :            : 
     115         [ +  + ]:      71580 :   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   [ +  -  +  - ]:      71570 :   if (unlikely (version < 2) || unlikely (version > 5)
     125   [ +  +  -  + ]:      71570 :       || (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         [ -  + ]:      71570 :   if (unlikely (address_size != 4 && address_size != 8))
     136                 :          0 :     address_size = 8;
     137         [ -  + ]:      71570 :   if (unlikely (offset_size != 4 && offset_size != 8))
     138                 :          0 :     offset_size = 8;
     139                 :            : 
     140                 :            :   /* Invalid or truncated debug section data?  */
     141                 :      71570 :   size_t sec_idx = debug_types ? IDX_debug_types : IDX_debug_info;
     142                 :      71570 :   Elf_Data *data = dbg->sectiondata[sec_idx];
     143         [ -  + ]:      71570 :   if (unlikely (*offsetp > data->d_size))
     144                 :          0 :     *offsetp = data->d_size;
     145                 :            : 
     146                 :      71570 :   uint32_t dwp_row;
     147                 :      71570 :   Dwarf_Off dwp_abbrev_offset;
     148         [ -  + ]:      71570 :   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                 :      71570 :   abbrev_offset += dwp_abbrev_offset;
     152                 :            : 
     153                 :            :   /* Create an entry for this CU.  */
     154         [ +  + ]:      71570 :   struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
     155                 :            : 
     156                 :      71570 :   newp->dbg = dbg;
     157                 :      71570 :   newp->sec_idx = sec_idx;
     158                 :      71570 :   newp->start = oldoff;
     159                 :      71570 :   newp->end = *offsetp;
     160                 :      71570 :   newp->dwp_row = dwp_row;
     161                 :      71570 :   newp->address_size = address_size;
     162                 :      71570 :   newp->offset_size = offset_size;
     163                 :      71570 :   newp->version = version;
     164                 :      71570 :   newp->unit_id8 = unit_id8;
     165                 :      71570 :   newp->subdie_offset = subdie_offset;
     166                 :      71570 :   Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
     167                 :      71570 :   newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
     168                 :      71570 :   newp->files = NULL;
     169                 :      71570 :   newp->lines = NULL;
     170                 :      71570 :   newp->split = (Dwarf_CU *) -1;
     171                 :      71570 :   newp->base_address = (Dwarf_Addr) -1;
     172                 :      71570 :   newp->addr_base = (Dwarf_Off) -1;
     173                 :      71570 :   newp->str_off_base = (Dwarf_Off) -1;
     174                 :      71570 :   newp->ranges_base = (Dwarf_Off) -1;
     175                 :      71570 :   newp->locs_base = (Dwarf_Off) -1;
     176                 :            : 
     177                 :      71570 :   newp->startp = data->d_buf + newp->start;
     178                 :      71570 :   newp->endp = data->d_buf + newp->end;
     179                 :      71570 :   eu_search_tree_init (&newp->locs_tree);
     180                 :      71570 :   rwlock_init (newp->abbrev_lock);
     181                 :      71570 :   rwlock_init (newp->split_lock);
     182                 :            : 
     183                 :            :   /* v4 debug type units have version == 4 and unit_type == DW_UT_type.  */
     184         [ +  + ]:      71570 :   if (debug_types)
     185                 :         44 :     newp->unit_type = DW_UT_type;
     186         [ +  + ]:      71526 :   else if (version < 5)
     187                 :            :     {
     188                 :            :       /* This is a reasonable guess (and needed to get the CUDIE).  */
     189                 :       1344 :       newp->unit_type = DW_UT_compile;
     190                 :            : 
     191                 :            :       /* But set it correctly from the actual CUDIE tag.  */
     192                 :       1344 :       Dwarf_Die cudie = CUDIE (newp);
     193                 :       1344 :       int tag = INTUSE(dwarf_tag) (&cudie);
     194         [ +  + ]:       1344 :       if (tag == DW_TAG_compile_unit)
     195                 :            :         {
     196                 :       1298 :           Dwarf_Attribute dwo_id;
     197         [ +  + ]:       1298 :           if (INTUSE(dwarf_attr) (&cudie, DW_AT_GNU_dwo_id, &dwo_id) != NULL)
     198                 :            :             {
     199                 :        270 :               Dwarf_Word id8;
     200         [ +  - ]:        270 :               if (INTUSE(dwarf_formudata) (&dwo_id, &id8) == 0)
     201                 :            :                 {
     202         [ +  + ]:        270 :                   if (INTUSE(dwarf_haschildren) (&cudie) == 0
     203         [ +  - ]:        132 :                       && INTUSE(dwarf_hasattr) (&cudie,
     204                 :            :                                                 DW_AT_GNU_dwo_name) == 1)
     205                 :        132 :                     newp->unit_type = DW_UT_skeleton;
     206                 :            :                   else
     207                 :        138 :                     newp->unit_type = DW_UT_split_compile;
     208                 :            : 
     209                 :        270 :                   newp->unit_id8 = id8;
     210                 :            :                 }
     211                 :            :             }
     212                 :            :         }
     213         [ +  + ]:         46 :       else if (tag == DW_TAG_partial_unit)
     214                 :         42 :         newp->unit_type = DW_UT_partial;
     215         [ -  + ]:          4 :       else if (tag == DW_TAG_type_unit)
     216                 :          0 :         newp->unit_type = DW_UT_type;
     217                 :            :     }
     218                 :            :   else
     219                 :      70182 :     newp->unit_type = unit_type;
     220                 :            : 
     221                 :            :   /* Store a reference to any type unit ids in the hash for quick lookup.  */
     222         [ +  + ]:      71570 :   if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)
     223                 :         74 :     Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, unit_id8, newp);
     224                 :            : 
     225                 :            :   /* Add the new entry to the search tree.  */
     226         [ -  + ]:      71570 :   if (eu_tsearch (newp, tree, findcu_cb) == NULL)
     227                 :            :     {
     228                 :            :       /* Something went wrong.  Undo the operation.  */
     229                 :          0 :       *offsetp = oldoff;
     230                 :          0 :       __libdw_seterrno (DWARF_E_NOMEM);
     231                 :          0 :       return NULL;
     232                 :            :     }
     233                 :            : 
     234                 :            :   return newp;
     235                 :            : }
     236                 :            : 
     237                 :            : struct Dwarf_CU *
     238                 :            : internal_function
     239                 :     100962 : __libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool v4_debug_types)
     240                 :            : {
     241         [ +  + ]:     100962 :   search_tree *tree = v4_debug_types ? &dbg->tu_tree : &dbg->cu_tree;
     242                 :     201924 :   Dwarf_Off *next_offset
     243                 :     100962 :     = v4_debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
     244                 :            : 
     245                 :            :   /* Maybe we already know that CU.  */
     246                 :     100962 :   struct Dwarf_CU fake = { .start = start, .end = 0 };
     247                 :     100962 :   struct Dwarf_CU **found = eu_tfind (&fake, tree, findcu_cb);
     248                 :     100962 :   struct Dwarf_CU *result = NULL;
     249         [ +  + ]:     100962 :   if (found != NULL)
     250                 :      29406 :     return *found;
     251                 :            : 
     252                 :      71556 :   rwlock_wrlock (dbg->dwarf_lock);
     253                 :            : 
     254         [ +  + ]:      71556 :   if (start < *next_offset)
     255                 :         10 :     __libdw_seterrno (DWARF_E_INVALID_DWARF);
     256                 :            :   else
     257                 :            :     {
     258                 :            :       /* No.  Then read more CUs.  */
     259                 :      71576 :       while (1)
     260                 :            :         {
     261                 :      71576 :           struct Dwarf_CU *newp
     262                 :      71576 :             = __libdw_intern_next_unit (dbg, v4_debug_types);
     263                 :            : 
     264         [ +  + ]:      71576 :           if (newp == NULL)
     265                 :            :             {
     266                 :            :               result = NULL;
     267                 :            :               break;
     268                 :            :             }
     269                 :            : 
     270                 :            :           /* Is this the one we are looking for?  */
     271   [ +  +  +  - ]:      71568 :           if (start < *next_offset || start == newp->start)
     272                 :            :             {
     273                 :            :               result = newp;
     274                 :            :               break;
     275                 :            :             }
     276                 :            :         }
     277                 :            :     }
     278                 :            : 
     279                 :            :   rwlock_unlock (dbg->dwarf_lock);
     280                 :            :   return result;
     281                 :            : }
     282                 :            : 
     283                 :            : struct Dwarf_CU *
     284                 :            : internal_function
     285                 :    1350302 : __libdw_findcu_addr (Dwarf *dbg, void *addr)
     286                 :            : {
     287                 :    1350302 :   search_tree *tree;
     288                 :    1350302 :   Dwarf_Off start;
     289         [ +  + ]:    1350302 :   if (addr >= dbg->sectiondata[IDX_debug_info]->d_buf
     290                 :    1349976 :       && addr < (dbg->sectiondata[IDX_debug_info]->d_buf
     291         [ +  + ]:    1349976 :                  + dbg->sectiondata[IDX_debug_info]->d_size))
     292                 :            :     {
     293                 :    1349944 :       tree = &dbg->cu_tree;
     294                 :    1349944 :       start = addr - dbg->sectiondata[IDX_debug_info]->d_buf;
     295                 :            :     }
     296         [ +  + ]:        358 :   else if (dbg->sectiondata[IDX_debug_types] != NULL
     297         [ +  - ]:         32 :            && addr >= dbg->sectiondata[IDX_debug_types]->d_buf
     298                 :         32 :            && addr < (dbg->sectiondata[IDX_debug_types]->d_buf
     299         [ +  - ]:         32 :                       + dbg->sectiondata[IDX_debug_types]->d_size))
     300                 :            :     {
     301                 :         32 :       tree = &dbg->tu_tree;
     302                 :         32 :       start = addr - dbg->sectiondata[IDX_debug_types]->d_buf;
     303                 :            :     }
     304                 :            :   else
     305                 :            :     return NULL;
     306                 :            : 
     307                 :    1349976 :   struct Dwarf_CU fake = { .start = start, .end = 0 };
     308                 :    1349976 :   struct Dwarf_CU **found = eu_tfind (&fake, tree, findcu_cb);
     309                 :            : 
     310         [ -  + ]:    1349976 :   if (found != NULL)
     311                 :    1349976 :     return *found;
     312                 :            : 
     313                 :            :   return NULL;
     314                 :            : }
     315                 :            : 
     316                 :            : Dwarf *
     317                 :            : internal_function
     318                 :        296 : __libdw_find_split_dbg_addr (Dwarf *dbg, void *addr)
     319                 :            : {
     320                 :            :   /* XXX Assumes split DWARF only has CUs in main IDX_debug_info.  */
     321                 :        296 :   Elf_Data fake_data = { .d_buf = addr, .d_size = 0 };
     322                 :        296 :   Dwarf fake = { .sectiondata[IDX_debug_info] = &fake_data };
     323                 :        296 :   Dwarf **found = eu_tfind (&fake, &dbg->split_tree, __libdw_finddbg_cb);
     324                 :            : 
     325         [ +  - ]:        296 :   if (found != NULL)
     326                 :        296 :     return *found;
     327                 :            : 
     328                 :            :   return NULL;
     329                 :            : }

Generated by: LCOV version 1.16