LCOV - code coverage report
Current view: top level - libdw - dwarf_cu_dwp_section_info.c (source / functions) Hit Total Coverage
Test: elfutils-0.190 Lines: 108 169 63.9 %
Date: 2024-02-15 18:25:58 Functions: 5 6 83.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 79 150 52.7 %

           Branch data     Line data    Source code
       1                 :            : /* Read DWARF package file index sections.
       2                 :            :    Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
       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 "libdwP.h"
      34                 :            : 
      35                 :            : static Dwarf_Package_Index *
      36                 :         12 : __libdw_read_package_index (Dwarf *dbg, bool tu)
      37                 :            : {
      38                 :         12 :   Elf_Data *data;
      39         [ +  + ]:         12 :   if (tu)
      40                 :          6 :     data = dbg->sectiondata[IDX_debug_tu_index];
      41                 :            :   else
      42                 :          6 :     data = dbg->sectiondata[IDX_debug_cu_index];
      43                 :            : 
      44                 :            :   /* We need at least 16 bytes for the header.  */
      45   [ -  +  -  + ]:         12 :   if (data == NULL || data->d_size < 16)
      46                 :            :     {
      47                 :          0 :     invalid:
      48                 :          0 :       __libdw_seterrno (DWARF_E_INVALID_DWARF);
      49                 :          0 :       return NULL;
      50                 :            :     }
      51                 :            : 
      52                 :         12 :   const unsigned char *datap = data->d_buf;
      53                 :         12 :   const unsigned char *endp = datap + data->d_size;
      54                 :         12 :   uint16_t version;
      55                 :            :   /* In GNU DebugFission for DWARF 4, the version is 2 as a uword.  In the
      56                 :            :      standardized DWARF 5 format, it is a uhalf followed by a padding uhalf.
      57                 :            :      Check for both.  */
      58   [ -  +  +  + ]:         12 :   if (read_4ubyte_unaligned (dbg, datap) == 2)
      59                 :            :     version = 2;
      60                 :            :   else
      61                 :            :     {
      62         [ -  + ]:          4 :       version = read_2ubyte_unaligned (dbg, datap);
      63         [ -  + ]:          4 :       if (version != 5)
      64                 :            :         {
      65                 :          0 :           __libdw_seterrno (DWARF_E_VERSION);
      66                 :          0 :           return NULL;
      67                 :            :         }
      68                 :            :     }
      69                 :         12 :   datap += 4;
      70         [ -  + ]:         12 :   uint32_t section_count = read_4ubyte_unaligned_inc (dbg, datap);
      71         [ -  + ]:         12 :   uint32_t unit_count = read_4ubyte_unaligned_inc (dbg, datap);
      72         [ -  + ]:         12 :   uint32_t slot_count = read_4ubyte_unaligned_inc (dbg, datap);
      73                 :            : 
      74                 :            :   /* The specification has a stricter requirement that
      75                 :            :      slot_count > 3 * unit_count / 2, but this is enough for us.  */
      76         [ -  + ]:         12 :   if (slot_count < unit_count)
      77                 :          0 :     goto invalid;
      78                 :            : 
      79                 :            :   /* After the header, the section must contain:
      80                 :            : 
      81                 :            :        8 byte signature per hash table slot
      82                 :            :      + 4 byte index per hash table slot
      83                 :            :      + Section offset table with 1 header row, 1 row per unit, 1 column per
      84                 :            :        section, 4 bytes per field
      85                 :            :      + Section size table with 1 row per unit, 1 column per section, 4 bytes
      86                 :            :        per field
      87                 :            : 
      88                 :            :      We have to be careful about overflow when checking this.  */
      89                 :         12 :   const unsigned char *hash_table = datap;
      90         [ -  + ]:         12 :   if ((size_t) (endp - hash_table) < (uint64_t) slot_count * 12)
      91                 :          0 :     goto invalid;
      92                 :         12 :   const unsigned char *indices = hash_table + (size_t) slot_count * 8;
      93                 :         12 :   const unsigned char *sections = indices + (size_t) slot_count * 4;
      94         [ -  + ]:         12 :   if ((size_t) (endp - sections) < (uint64_t) section_count * 4)
      95                 :          0 :     goto invalid;
      96                 :         12 :   const unsigned char *section_offsets = sections + (size_t) section_count * 4;
      97         [ +  - ]:         12 :   if ((uint64_t) unit_count * section_count > UINT64_MAX / 8
      98                 :         12 :       || ((size_t) (endp - section_offsets)
      99         [ -  + ]:         12 :           < (uint64_t) unit_count * section_count * 8))
     100                 :          0 :     goto invalid;
     101                 :         12 :   const unsigned char *section_sizes
     102                 :         12 :     = section_offsets + (uint64_t) unit_count * section_count * 4;
     103                 :            : 
     104                 :         12 :   Dwarf_Package_Index *index = malloc (sizeof (*index));
     105         [ -  + ]:         12 :   if (index == NULL)
     106                 :            :     {
     107                 :          0 :       __libdw_seterrno (DWARF_E_NOMEM);
     108                 :          0 :       return NULL;
     109                 :            :     }
     110                 :            : 
     111                 :         12 :   index->dbg = dbg;
     112                 :            :   /* Set absent sections to UINT32_MAX.  */
     113                 :         12 :   memset (index->sections, 0xff, sizeof (index->sections));
     114         [ +  + ]:         88 :   for (size_t i = 0; i < section_count; i++)
     115                 :            :     {
     116         [ -  + ]:         76 :       uint32_t section = read_4ubyte_unaligned (dbg, sections + i * 4);
     117                 :            :       /* 2 is DW_SECT_TYPES in version 2 and reserved in version 5.  We ignore
     118                 :            :          it for version 5.
     119                 :            :          5 is DW_SECT_LOC in version 2 and DW_SECT_LOCLISTS in version 5.  We
     120                 :            :          use the same index for both.
     121                 :            :          7 is DW_SECT_MACINFO in version 2 and DW_SECT_MACRO in version 5.  We
     122                 :            :          use the same index for both.
     123                 :            :          8 is DW_SECT_MACRO in version 2 and DW_SECT_RNGLISTS in version 5.  We
     124                 :            :          use the same index for version 2's DW_SECT_MACRO as version 2's
     125                 :            :          DW_SECT_MACINFO/version 5's DW_SECT_MACRO.
     126                 :            :          We ignore unknown sections.  */
     127         [ -  + ]:         76 :       if (section == 0)
     128                 :          0 :         continue;
     129         [ +  + ]:         76 :       if (version == 2)
     130                 :            :         {
     131         [ -  + ]:         48 :           if (section > 8)
     132                 :          0 :             continue;
     133         [ +  + ]:         48 :           else if (section == 8)
     134                 :         76 :             section = DW_SECT_MACRO;
     135                 :            :         }
     136                 :         28 :       else if (section == 2
     137                 :         28 :                || (section
     138         [ -  + ]:         28 :                    > sizeof (index->sections) / sizeof (index->sections[0])))
     139                 :          0 :         continue;
     140                 :         76 :       index->sections[section - 1] = i;
     141                 :            :     }
     142                 :            : 
     143                 :            :   /* DW_SECT_INFO (or DW_SECT_TYPES for DWARF 4 type units) and DW_SECT_ABBREV
     144                 :            :      are required.  */
     145   [ +  +  +  + ]:         12 :   if (((!tu || dbg->sectiondata[IDX_debug_types] == NULL)
     146         [ +  - ]:          8 :        && index->sections[DW_SECT_INFO - 1] == UINT32_MAX)
     147   [ +  +  +  + ]:         12 :       || (tu && dbg->sectiondata[IDX_debug_types] != NULL
     148         [ +  - ]:          4 :           && index->sections[DW_SECT_TYPES - 1] == UINT32_MAX)
     149         [ -  + ]:         12 :       || index->sections[DW_SECT_ABBREV - 1] == UINT32_MAX)
     150                 :            :     {
     151                 :          0 :       free (index);
     152                 :          0 :       __libdw_seterrno (DWARF_E_INVALID_DWARF);
     153                 :          0 :       return NULL;
     154                 :            :     }
     155                 :            : 
     156                 :         12 :   index->section_count = section_count;
     157                 :         12 :   index->unit_count = unit_count;
     158                 :         12 :   index->slot_count = slot_count;
     159                 :         12 :   index->last_unit_found = 0;
     160                 :         12 :   index->hash_table = hash_table;
     161                 :         12 :   index->indices = indices;
     162                 :         12 :   index->section_offsets = section_offsets;
     163                 :         12 :   index->section_sizes = section_sizes;
     164                 :            : 
     165                 :         12 :   return index;
     166                 :            : }
     167                 :            : 
     168                 :            : static Dwarf_Package_Index *
     169                 :         30 : __libdw_package_index (Dwarf *dbg, bool tu)
     170                 :            : {
     171   [ +  +  +  + ]:         30 :   if (tu && dbg->tu_index != NULL)
     172                 :            :     return dbg->tu_index;
     173         [ +  + ]:         18 :   else if (!tu && dbg->cu_index != NULL)
     174                 :            :     return dbg->cu_index;
     175                 :            : 
     176                 :         12 :   Dwarf_Package_Index *index = __libdw_read_package_index (dbg, tu);
     177         [ +  - ]:         12 :   if (index == NULL)
     178                 :            :     return NULL;
     179                 :            : 
     180         [ +  + ]:         12 :   if (tu)
     181                 :          6 :     dbg->tu_index = index;
     182                 :            :   else
     183                 :          6 :     dbg->cu_index = index;
     184                 :            :   return index;
     185                 :            : }
     186                 :            : 
     187                 :            : static int
     188                 :          0 : __libdw_dwp_unit_row (Dwarf_Package_Index *index, uint64_t unit_id,
     189                 :            :                       uint32_t *unit_rowp)
     190                 :            : {
     191         [ #  # ]:          0 :   if (index == NULL)
     192                 :            :     return -1;
     193                 :            : 
     194                 :          0 :   uint32_t hash = unit_id;
     195                 :          0 :   uint32_t hash2 = (unit_id >> 32) | 1;
     196                 :            :   /* Only check each slot once.  */
     197         [ #  # ]:          0 :   for (uint32_t n = index->slot_count; n-- > 0; )
     198                 :            :     {
     199                 :          0 :       size_t slot = hash & (index->slot_count - 1);
     200         [ #  # ]:          0 :       uint64_t sig = read_8ubyte_unaligned (index->dbg,
     201                 :            :                                             index->hash_table + slot * 8);
     202         [ #  # ]:          0 :       if (sig == unit_id)
     203                 :            :         {
     204         [ #  # ]:          0 :           uint32_t row = read_4ubyte_unaligned (index->dbg,
     205                 :            :                                                 index->indices + slot * 4);
     206         [ #  # ]:          0 :           if (row > index->unit_count)
     207                 :            :             {
     208                 :          0 :               __libdw_seterrno (DWARF_E_INVALID_DWARF);
     209                 :          0 :               return -1;
     210                 :            :             }
     211                 :          0 :           *unit_rowp = row;
     212                 :          0 :           return 0;
     213                 :            :         }
     214         [ #  # ]:          0 :       else if (sig == 0
     215         [ #  # ]:          0 :                && read_4ubyte_unaligned (index->dbg,
     216         [ #  # ]:          0 :                                          index->indices + slot * 4) == 0)
     217                 :            :         break;
     218                 :          0 :       hash += hash2;
     219                 :            :     }
     220                 :          0 :   *unit_rowp = 0;
     221                 :          0 :   return 0;
     222                 :            : }
     223                 :            : 
     224                 :            : static int
     225                 :        300 : __libdw_dwp_section_info (Dwarf_Package_Index *index, uint32_t unit_row,
     226                 :            :                           unsigned int section, Dwarf_Off *offsetp,
     227                 :            :                           Dwarf_Off *sizep)
     228                 :            : {
     229         [ +  - ]:        300 :   if (index == NULL)
     230                 :            :     return -1;
     231         [ -  + ]:        300 :   if (unit_row == 0)
     232                 :            :     {
     233                 :          0 :       __libdw_seterrno (DWARF_E_INVALID_DWARF);
     234                 :          0 :       return -1;
     235                 :            :     }
     236         [ +  + ]:        300 :   if (index->sections[section - 1] == UINT32_MAX)
     237                 :            :     {
     238         [ +  - ]:         50 :       if (offsetp != NULL)
     239                 :         50 :         *offsetp = 0;
     240         [ +  - ]:         50 :       if (sizep != NULL)
     241                 :         50 :         *sizep = 0;
     242                 :         50 :       return 0;
     243                 :            :     }
     244                 :        250 :   size_t i = (size_t)(unit_row - 1) * index->section_count
     245                 :        250 :              + index->sections[section - 1];
     246         [ +  - ]:        250 :   if (offsetp != NULL)
     247         [ -  + ]:        250 :     *offsetp = read_4ubyte_unaligned (index->dbg,
     248                 :            :                                       index->section_offsets + i * 4);
     249         [ +  + ]:        250 :   if (sizep != NULL)
     250         [ -  + ]:        220 :     *sizep = read_4ubyte_unaligned (index->dbg,
     251                 :            :                                     index->section_sizes + i * 4);
     252                 :            :   return 0;
     253                 :            : }
     254                 :            : 
     255                 :            : int
     256                 :            : internal_function
     257                 :      79026 : __libdw_dwp_find_unit (Dwarf *dbg, bool debug_types, Dwarf_Off off,
     258                 :            :                        uint16_t version, uint8_t unit_type, uint64_t unit_id8,
     259                 :            :                        uint32_t *unit_rowp, Dwarf_Off *abbrev_offsetp)
     260                 :            : {
     261                 :      79026 :   if (version >= 5
     262   [ +  +  +  + ]:      79026 :       && unit_type != DW_UT_split_compile && unit_type != DW_UT_split_type)
     263                 :            :     {
     264                 :      77652 :     not_dwp:
     265                 :      78996 :       *unit_rowp = 0;
     266                 :      78996 :       *abbrev_offsetp = 0;
     267                 :      78996 :       return 0;
     268                 :            :     }
     269                 :       1374 :   bool tu = unit_type == DW_UT_split_type || debug_types;
     270   [ +  +  +  + ]:       2700 :   if (dbg->sectiondata[tu ? IDX_debug_tu_index : IDX_debug_cu_index] == NULL)
     271                 :       1344 :     goto not_dwp;
     272                 :         30 :   Dwarf_Package_Index *index = __libdw_package_index (dbg, tu);
     273         [ -  + ]:         30 :   if (index == NULL)
     274                 :            :     return -1;
     275                 :            : 
     276                 :            :   /* This is always called for ascending offsets.  The most obvious way for a
     277                 :            :      producer to generate the section offset table is sorted by offset; both
     278                 :            :      GNU dwp and llvm-dwp do this.  In this common case, we can avoid the full
     279                 :            :      lookup.  */
     280         [ +  - ]:         30 :   if (index->last_unit_found < index->unit_count)
     281                 :            :     {
     282                 :         30 :       Dwarf_Off offset, size;
     283   [ +  +  -  + ]:         52 :       if (__libdw_dwp_section_info (index, index->last_unit_found + 1,
     284                 :            :                                     debug_types ? DW_SECT_TYPES : DW_SECT_INFO,
     285                 :            :                                     &offset, &size) != 0)
     286                 :          0 :         return -1;
     287   [ +  -  +  - ]:         30 :       if (offset <= off && off - offset < size)
     288                 :            :         {
     289                 :         30 :           *unit_rowp = ++index->last_unit_found;
     290                 :         30 :           goto done;
     291                 :            :         }
     292                 :            :       else
     293                 :            :         /* The units are not sorted. Don't try again.  */
     294                 :          0 :         index->last_unit_found = index->unit_count;
     295                 :            :     }
     296                 :            : 
     297         [ #  # ]:          0 :   if (version >= 5 || debug_types)
     298                 :            :     {
     299                 :            :       /* In DWARF 5 and in type units, the unit signature is available in the
     300                 :            :          unit header.  */
     301         [ #  # ]:          0 :       if (__libdw_dwp_unit_row (index, unit_id8, unit_rowp) != 0)
     302                 :            :         return -1;
     303                 :            :     }
     304                 :            :   else
     305                 :            :     {
     306                 :            :       /* In DWARF 4 compilation units, the unit signature is an attribute.  We
     307                 :            :          can't parse attributes in the split unit until we get the abbreviation
     308                 :            :          table offset from the package index, which is a chicken-and-egg
     309                 :            :          problem.  We could get the signature from the skeleton unit, but that
     310                 :            :          may not be available.
     311                 :            : 
     312                 :            :          Instead, we resort to a linear scan through the section offset table.
     313                 :            :          Finding all units is therefore quadratic in the number of units.
     314                 :            :          However, this will likely never be needed in practice because of the
     315                 :            :          sorted fast path above.  If this ceases to be the case, we can try to
     316                 :            :          plumb through the skeleton unit's signature when it is available, or
     317                 :            :          build a sorted lookup table for binary search.  */
     318         [ #  # ]:          0 :       if (index->sections[DW_SECT_INFO - 1] == UINT32_MAX)
     319                 :            :         {
     320                 :          0 :           __libdw_seterrno (DWARF_E_INVALID_DWARF);
     321                 :          0 :           return -1;
     322                 :            :         }
     323         [ #  # ]:          0 :       for (uint32_t i = 0; i < index->unit_count; i++)
     324                 :            :         {
     325                 :          0 :           Dwarf_Off offset, size;
     326                 :          0 :           __libdw_dwp_section_info (index, i + 1, DW_SECT_INFO, &offset,
     327                 :            :                                     &size);
     328   [ #  #  #  # ]:          0 :           if (offset <= off && off - offset < size)
     329                 :            :             {
     330                 :          0 :               *unit_rowp = i + 1;
     331                 :          0 :               goto done;
     332                 :            :             }
     333                 :            :         }
     334                 :          0 :       __libdw_seterrno (DWARF_E_INVALID_DWARF);
     335                 :          0 :       return -1;
     336                 :            :     }
     337                 :            : 
     338                 :         30 :  done:
     339                 :         30 :   return __libdw_dwp_section_info (index, *unit_rowp, DW_SECT_ABBREV,
     340                 :            :                                    abbrev_offsetp, NULL);
     341                 :            : }
     342                 :            : 
     343                 :            : int
     344                 :        240 : dwarf_cu_dwp_section_info (Dwarf_CU *cu, unsigned int section,
     345                 :            :                            Dwarf_Off *offsetp, Dwarf_Off *sizep)
     346                 :            : {
     347         [ -  + ]:        240 :   if (cu == NULL)
     348                 :            :     return -1;
     349         [ -  + ]:        240 :   if (section < DW_SECT_INFO || section > DW_SECT_RNGLISTS)
     350                 :            :     {
     351                 :          0 :       __libdw_seterrno (DWARF_E_UNKNOWN_SECTION);
     352                 :          0 :       return -1;
     353                 :            :     }
     354         [ -  + ]:        240 :   if (cu->dwp_row == 0)
     355                 :            :     {
     356         [ #  # ]:          0 :       if (offsetp != NULL)
     357                 :          0 :         *offsetp = 0;
     358         [ #  # ]:          0 :       if (sizep != NULL)
     359                 :          0 :         *sizep = 0;
     360                 :          0 :       return 0;
     361                 :            :     }
     362                 :            :   else
     363                 :            :     {
     364                 :        720 :       Dwarf_Package_Index *index
     365         [ +  + ]:        240 :         = cu->unit_type == DW_UT_split_compile
     366                 :        240 :         ? cu->dbg->cu_index : cu->dbg->tu_index;
     367                 :        240 :       return __libdw_dwp_section_info (index, cu->dwp_row, section, offsetp,
     368                 :            :                                        sizep);
     369                 :            :     }
     370                 :            : }
     371                 :            : INTDEF(dwarf_cu_dwp_section_info)

Generated by: LCOV version 1.16