LCOV - code coverage report
Current view: top level - libdw - dwarf_getmacros.c (source / functions) Coverage Total Hit
Test: elfutils-0.195 Lines: 82.7 % 260 215
Test Date: 2026-06-22 17:21:32 Functions: 100.0 % 13 13
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 66.3 % 166 110

             Branch data     Line data    Source code
       1                 :             : /* Get macro information.
       2                 :             :    Copyright (C) 2002-2009, 2014, 2017, 2018 Red Hat, Inc.
       3                 :             :    This file is part of elfutils.
       4                 :             : 
       5                 :             :    This file is free software; you can redistribute it and/or modify
       6                 :             :    it under the terms of either
       7                 :             : 
       8                 :             :      * the GNU Lesser General Public License as published by the Free
       9                 :             :        Software Foundation; either version 3 of the License, or (at
      10                 :             :        your option) any later version
      11                 :             : 
      12                 :             :    or
      13                 :             : 
      14                 :             :      * the GNU General Public License as published by the Free
      15                 :             :        Software Foundation; either version 2 of the License, or (at
      16                 :             :        your option) any later version
      17                 :             : 
      18                 :             :    or both in parallel, as here.
      19                 :             : 
      20                 :             :    elfutils is distributed in the hope that it will be useful, but
      21                 :             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      22                 :             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      23                 :             :    General Public License for more details.
      24                 :             : 
      25                 :             :    You should have received copies of the GNU General Public License and
      26                 :             :    the GNU Lesser General Public License along with this program.  If
      27                 :             :    not, see <http://www.gnu.org/licenses/>.  */
      28                 :             : 
      29                 :             : #ifdef HAVE_CONFIG_H
      30                 :             : # include <config.h>
      31                 :             : #endif
      32                 :             : 
      33                 :             : #include <assert.h>
      34                 :             : #include <dwarf.h>
      35                 :             : #include <stdlib.h>
      36                 :             : #include <string.h>
      37                 :             : 
      38                 :             : #include <libdwP.h>
      39                 :             : #include "eu-search.h"
      40                 :             : 
      41                 :             : static int
      42                 :        9478 : get_offset_from (Dwarf_Die *die, int name, Dwarf_Word *retp)
      43                 :             : {
      44                 :             :   /* Get the appropriate attribute.  */
      45                 :        9478 :   Dwarf_Attribute attr;
      46         [ +  + ]:        9478 :   if (INTUSE(dwarf_attr) (die, name, &attr) == NULL)
      47                 :             :     return -1;
      48                 :             : 
      49                 :             :   /* Offset into the corresponding section.  */
      50         [ -  + ]:        6676 :   if (INTUSE(dwarf_formudata) (&attr, retp) != 0)
      51                 :             :     return -1;
      52                 :             : 
      53                 :        6676 :   Dwarf_Off offset;
      54         [ -  + ]:        6676 :   if (INTUSE(dwarf_cu_dwp_section_info) (die->cu, DW_SECT_MACRO, &offset, NULL)
      55                 :             :       != 0)
      56                 :             :     return -1;
      57                 :        6676 :   *retp += offset;
      58                 :        6676 :   return 0;
      59                 :             : }
      60                 :             : 
      61                 :             : static int
      62                 :       11680 : macro_op_compare (const void *p1, const void *p2)
      63                 :             : {
      64                 :       11680 :   const Dwarf_Macro_Op_Table *t1 = (const Dwarf_Macro_Op_Table *) p1;
      65                 :       11680 :   const Dwarf_Macro_Op_Table *t2 = (const Dwarf_Macro_Op_Table *) p2;
      66                 :             : 
      67         [ +  + ]:       11680 :   if (t1->offset < t2->offset)
      68                 :             :     return -1;
      69         [ +  + ]:       11600 :   if (t1->offset > t2->offset)
      70                 :             :     return 1;
      71                 :             : 
      72         [ +  - ]:        6986 :   if (t1->sec_index < t2->sec_index)
      73                 :             :     return -1;
      74         [ -  + ]:        6986 :   if (t1->sec_index > t2->sec_index)
      75                 :           0 :     return 1;
      76                 :             : 
      77                 :             :   return 0;
      78                 :             : }
      79                 :             : 
      80                 :             : static void
      81                 :          47 : build_table (Dwarf_Macro_Op_Table *table,
      82                 :             :              Dwarf_Macro_Op_Proto op_protos[static 255])
      83                 :             : {
      84                 :          47 :   unsigned ct = 0;
      85         [ +  + ]:       12032 :   for (unsigned i = 1; i < 256; ++i)
      86         [ +  + ]:       11985 :     if (op_protos[i - 1].forms != NULL)
      87                 :         449 :       table->table[table->opcodes[i - 1] = ct++] = op_protos[i - 1];
      88                 :             :     else
      89                 :       11536 :       table->opcodes[i - 1] = 0xff;
      90                 :          47 : }
      91                 :             : 
      92                 :             : #define MACRO_PROTO(NAME, ...)                                  \
      93                 :             :   Dwarf_Macro_Op_Proto NAME = ({                                \
      94                 :             :       static const uint8_t proto[] = {__VA_ARGS__};             \
      95                 :             :       (Dwarf_Macro_Op_Proto) {sizeof proto, proto};             \
      96                 :             :     })
      97                 :             : 
      98                 :             : enum { macinfo_data_size = offsetof (Dwarf_Macro_Op_Table, table[5]) };
      99                 :             : static unsigned char macinfo_data[macinfo_data_size]
     100                 :             :         __attribute__ ((aligned (__alignof (Dwarf_Macro_Op_Table))));
     101                 :             : 
     102                 :             : static __attribute__ ((constructor)) void
     103                 :          17 : init_macinfo_table (void)
     104                 :             : {
     105                 :          17 :   MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
     106                 :          17 :   MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
     107                 :          17 :   MACRO_PROTO (p_none);
     108                 :             : 
     109                 :          17 :   Dwarf_Macro_Op_Proto op_protos[255] =
     110                 :             :     {
     111                 :             :       [DW_MACINFO_define - 1] = p_udata_str,
     112                 :             :       [DW_MACINFO_undef - 1] = p_udata_str,
     113                 :             :       [DW_MACINFO_vendor_ext - 1] = p_udata_str,
     114                 :             :       [DW_MACINFO_start_file - 1] = p_udata_udata,
     115                 :             :       [DW_MACINFO_end_file - 1] = p_none,
     116                 :             :       /* If you are adding more elements to this array, increase
     117                 :             :          MACINFO_DATA_SIZE above.  */
     118                 :             :     };
     119                 :             : 
     120                 :          17 :   Dwarf_Macro_Op_Table *macinfo_table = (void *) macinfo_data;
     121                 :          17 :   memset (macinfo_table, 0, sizeof macinfo_data);
     122                 :          17 :   build_table (macinfo_table, op_protos);
     123                 :          17 :   macinfo_table->sec_index = IDX_debug_macinfo;
     124                 :          17 : }
     125                 :             : 
     126                 :             : static Dwarf_Macro_Op_Table *
     127                 :          10 : get_macinfo_table (Dwarf *dbg, Dwarf_Word macoff, Dwarf_Die *cudie)
     128                 :             : {
     129         [ -  + ]:          10 :   assert (cudie != NULL);
     130                 :             : 
     131                 :          10 :   Dwarf_Attribute attr_mem, *attr
     132                 :          10 :     = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem);
     133                 :          10 :   Dwarf_Off line_offset = (Dwarf_Off) -1;
     134         [ +  + ]:          10 :   if (attr != NULL)
     135                 :             :     {
     136         [ -  + ]:           4 :       if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
     137                 :             :         return NULL;
     138                 :             :     }
     139         [ +  - ]:           6 :   else if (cudie->cu->unit_type == DW_UT_split_compile
     140         [ +  - ]:           6 :            && dbg->sectiondata[IDX_debug_line] != NULL)
     141                 :           6 :     line_offset = 0;
     142         [ +  - ]:          10 :   if (line_offset != (Dwarf_Off) -1)
     143                 :             :     {
     144                 :          10 :       Dwarf_Off dwp_offset;
     145         [ -  + ]:          10 :       if (INTUSE(dwarf_cu_dwp_section_info) (cudie->cu, DW_SECT_LINE,
     146                 :             :                                              &dwp_offset, NULL) != 0)
     147                 :           0 :         return NULL;
     148                 :          10 :       line_offset += dwp_offset;
     149                 :             :     }
     150                 :             : 
     151         [ -  + ]:          10 :   Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
     152                 :             :                                              macinfo_data_size, 1);
     153                 :          10 :   memcpy (table, macinfo_data, macinfo_data_size);
     154                 :             : 
     155                 :          10 :   table->dbg = dbg;
     156                 :          10 :   table->offset = macoff;
     157                 :          10 :   table->sec_index = IDX_debug_macinfo;
     158                 :          10 :   table->line_offset = line_offset;
     159                 :          10 :   table->address_size = cudie->cu->address_size;
     160                 :          10 :   table->offset_size = cudie->cu->offset_size;
     161                 :          10 :   table->comp_dir = __libdw_getcompdir (cudie);
     162                 :             : 
     163                 :          10 :   return table;
     164                 :             : }
     165                 :             : 
     166                 :             : static Dwarf_Macro_Op_Table *
     167                 :          32 : get_table_for_offset (Dwarf *dbg, Dwarf_Word macoff,
     168                 :             :                       const unsigned char *readp,
     169                 :             :                       const unsigned char *const endp,
     170                 :             :                       Dwarf_Die *cudie)
     171                 :             : {
     172                 :          32 :   const unsigned char *startp = readp;
     173                 :             : 
     174                 :             :   /* Request at least 3 bytes for header.  */
     175         [ -  + ]:          32 :   if (readp + 3 > endp)
     176                 :             :     {
     177                 :           0 :     invalid_dwarf:
     178                 :           0 :       __libdw_seterrno (DWARF_E_INVALID_DWARF);
     179                 :           0 :       return NULL;
     180                 :             :     }
     181                 :             : 
     182         [ -  + ]:          32 :   uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
     183         [ -  + ]:          32 :   if (version != 4 && version != 5)
     184                 :             :     {
     185                 :           0 :       __libdw_seterrno (DWARF_E_INVALID_VERSION);
     186                 :           0 :       return NULL;
     187                 :             :     }
     188                 :             : 
     189                 :          32 :   uint8_t flags = *readp++;
     190                 :          32 :   bool is_64bit = (flags & 0x1) != 0;
     191                 :             : 
     192                 :          32 :   Dwarf_Off line_offset = (Dwarf_Off) -1;
     193         [ +  + ]:          32 :   if ((flags & 0x2) != 0)
     194                 :             :     {
     195   [ +  -  -  +  :          12 :       line_offset = read_addr_unaligned_inc (is_64bit ? 8 : 4, dbg, readp);
                   -  - ]
     196         [ -  + ]:          12 :       if (readp > endp)
     197                 :           0 :         goto invalid_dwarf;
     198                 :             :     }
     199         [ +  + ]:          20 :   else if (cudie != NULL)
     200                 :             :     {
     201                 :           2 :       Dwarf_Attribute attr_mem, *attr
     202                 :           2 :         = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem);
     203         [ -  + ]:           2 :       if (attr != NULL)
     204         [ #  # ]:           0 :         if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
     205                 :           0 :           return NULL;
     206                 :             :     }
     207   [ +  +  +  - ]:          32 :   if (line_offset != (Dwarf_Off) -1 && cudie != NULL)
     208                 :             :     {
     209                 :          12 :       Dwarf_Off dwp_offset;
     210         [ -  + ]:          12 :       if (INTUSE(dwarf_cu_dwp_section_info) (cudie->cu, DW_SECT_LINE,
     211                 :             :                                              &dwp_offset, NULL) != 0)
     212                 :           0 :         return NULL;
     213                 :          12 :       line_offset += dwp_offset;
     214                 :             :     }
     215                 :             : 
     216                 :          32 :   uint8_t address_size;
     217         [ +  + ]:          32 :   if (cudie != NULL)
     218                 :          14 :     address_size = cudie->cu->address_size;
     219                 :             :   else
     220                 :             :     {
     221                 :          18 :       char *ident = elf_getident (dbg->elf, NULL);
     222         [ +  - ]:          18 :       address_size = ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
     223                 :             :     }
     224                 :             : 
     225                 :             :   /* """The macinfo entry types defined in this standard may, but
     226                 :             :      might not, be described in the table""".
     227                 :             : 
     228                 :             :      I.e. these may be present.  It's tempting to simply skip them,
     229                 :             :      but it's probably more correct to tolerate that a producer tweaks
     230                 :             :      the way certain opcodes are encoded, for whatever reasons.  */
     231                 :             : 
     232                 :          32 :   MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
     233                 :          32 :   MACRO_PROTO (p_udata_strp, DW_FORM_udata, DW_FORM_strp);
     234                 :          32 :   MACRO_PROTO (p_udata_strsup, DW_FORM_udata, DW_FORM_strp_sup);
     235                 :          32 :   MACRO_PROTO (p_udata_strx, DW_FORM_udata, DW_FORM_strx);
     236                 :          32 :   MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
     237                 :          32 :   MACRO_PROTO (p_secoffset, DW_FORM_sec_offset);
     238                 :          32 :   MACRO_PROTO (p_none);
     239                 :             : 
     240                 :          32 :   Dwarf_Macro_Op_Proto op_protos[255] =
     241                 :             :     {
     242                 :             :       [DW_MACRO_define - 1] = p_udata_str,
     243                 :             :       [DW_MACRO_undef - 1] = p_udata_str,
     244                 :             :       [DW_MACRO_define_strp - 1] = p_udata_strp,
     245                 :             :       [DW_MACRO_undef_strp - 1] = p_udata_strp,
     246                 :             :       [DW_MACRO_start_file - 1] = p_udata_udata,
     247                 :             :       [DW_MACRO_end_file - 1] = p_none,
     248                 :             :       [DW_MACRO_import - 1] = p_secoffset,
     249                 :             :       [DW_MACRO_define_sup - 1] = p_udata_strsup,
     250                 :             :       [DW_MACRO_undef_sup - 1] = p_udata_strsup,
     251                 :             :       [DW_MACRO_import_sup - 1] = p_secoffset, /* XXX - but in sup!. */
     252                 :             :       [DW_MACRO_define_strx - 1] = p_udata_strx,
     253                 :             :       [DW_MACRO_undef_strx - 1] = p_udata_strx,
     254                 :             :     };
     255                 :             : 
     256         [ +  + ]:          32 :   if ((flags & 0x4) != 0)
     257                 :             :     {
     258         [ -  + ]:           6 :       if (readp >= endp)
     259                 :           0 :         goto invalid_dwarf;
     260                 :           6 :       unsigned count = *readp++;
     261         [ +  + ]:          10 :       for (unsigned i = 0; i < count; ++i)
     262                 :             :         {
     263         [ -  + ]:           6 :           if (readp >= endp)
     264                 :           0 :             goto invalid;
     265                 :           6 :           unsigned opcode = *readp++;
     266                 :             : 
     267                 :             :           /* Opcode 0 is not allocated (and 0xff means "not stored").
     268                 :             :              Reject it here: without this check the unsigned expression
     269                 :             :              opcode - 1 wraps to UINT_MAX for opcode == 0, and the
     270                 :             :              assignment below would write a Dwarf_Macro_Op_Proto far out
     271                 :             :              of the bounds of the op_protos[255] stack array.  */
     272         [ +  + ]:           6 :           if (opcode == 0)
     273                 :           2 :             goto invalid;
     274                 :             : 
     275                 :           4 :           Dwarf_Macro_Op_Proto e;
     276         [ -  + ]:           4 :           if (readp >= endp)
     277                 :           0 :             goto invalid;
     278                 :           4 :           get_uleb128 (e.nforms, readp, endp);
     279                 :           4 :           e.forms = readp;
     280                 :           4 :           op_protos[opcode - 1] = e;
     281                 :             : 
     282                 :           4 :           readp += e.nforms;
     283         [ -  + ]:           4 :           if (readp > endp)
     284                 :             :             {
     285                 :           0 :             invalid:
     286                 :           2 :               __libdw_seterrno (DWARF_E_INVALID_DWARF);
     287                 :           2 :               return NULL;
     288                 :             :             }
     289                 :             :         }
     290                 :             :     }
     291                 :             : 
     292                 :          30 :   size_t ct = 0;
     293         [ +  + ]:        7680 :   for (unsigned i = 1; i < 256; ++i)
     294         [ +  + ]:        7650 :     if (op_protos[i - 1].forms != NULL)
     295                 :         364 :       ++ct;
     296                 :             : 
     297                 :             :   /* We support at most 0xfe opcodes defined in the table, as 0xff is
     298                 :             :      a value that means that given opcode is not stored at all.  But
     299                 :             :      that should be fine, as opcode 0 is not allocated.  */
     300         [ -  + ]:          30 :   assert (ct < 0xff);
     301                 :             : 
     302                 :          30 :   size_t macop_table_size = offsetof (Dwarf_Macro_Op_Table, table[ct]);
     303                 :             : 
     304         [ +  + ]:          30 :   Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
     305                 :             :                                              macop_table_size, 1);
     306                 :             : 
     307                 :          90 :   *table = (Dwarf_Macro_Op_Table) {
     308                 :             :     .dbg = dbg,
     309                 :             :     .offset = macoff,
     310                 :             :     .sec_index = IDX_debug_macro,
     311                 :             :     .line_offset = line_offset,
     312         [ +  - ]:          30 :     .header_len = readp - startp,
     313                 :             :     .version = version,
     314                 :             :     .address_size = address_size,
     315                 :             :     .offset_size = is_64bit ? 8 : 4,
     316                 :             : 
     317                 :             :     /* NULL if CUDIE is NULL or DW_AT_comp_dir is absent.  */
     318                 :          30 :     .comp_dir = __libdw_getcompdir (cudie),
     319                 :             :   };
     320                 :          30 :   build_table (table, op_protos);
     321                 :             : 
     322                 :          30 :   return table;
     323                 :             : }
     324                 :             : 
     325                 :             : static Dwarf_Macro_Op_Table *
     326                 :        7028 : cache_op_table (Dwarf *dbg, int sec_index, Dwarf_Off macoff,
     327                 :             :                 const unsigned char *startp,
     328                 :             :                 const unsigned char *const endp,
     329                 :             :                 Dwarf_Die *cudie)
     330                 :             : {
     331                 :        7028 :   Dwarf_Macro_Op_Table fake = { .offset = macoff, .sec_index = sec_index };
     332                 :        7028 :   Dwarf_Macro_Op_Table **found = eu_tfind (&fake, &dbg->macro_ops_tree,
     333                 :             :                                         macro_op_compare);
     334         [ +  + ]:        7028 :   if (found != NULL)
     335                 :        6986 :     return *found;
     336                 :             : 
     337                 :          42 :   mutex_lock (dbg->macro_lock);
     338                 :             : 
     339                 :          42 :   found = eu_tfind_nolock (&fake, &dbg->macro_ops_tree, macro_op_compare);
     340         [ -  + ]:          42 :   if (found != NULL)
     341                 :             :     {
     342                 :           0 :       mutex_unlock (dbg->macro_lock);
     343                 :           0 :       return *found;
     344                 :             :     }
     345                 :             : 
     346                 :          84 :   Dwarf_Macro_Op_Table *table = sec_index == IDX_debug_macro
     347                 :          32 :     ? get_table_for_offset (dbg, macoff, startp, endp, cudie)
     348         [ +  + ]:          42 :     : get_macinfo_table (dbg, macoff, cudie);
     349                 :             : 
     350         [ +  + ]:          42 :   if (table == NULL)
     351                 :             :     {
     352                 :             :       mutex_unlock (dbg->macro_lock);
     353                 :             :       return NULL;
     354                 :             :     }
     355                 :             : 
     356                 :          40 :   Dwarf_Macro_Op_Table **ret = eu_tsearch_nolock (table, &dbg->macro_ops_tree,
     357                 :             :                                                   macro_op_compare);
     358                 :          40 :   mutex_unlock (dbg->macro_lock);
     359                 :             : 
     360         [ -  + ]:          40 :   if (unlikely (ret == NULL))
     361                 :             :     {
     362                 :           0 :       __libdw_seterrno (DWARF_E_NOMEM);
     363                 :           0 :       return NULL;
     364                 :             :     }
     365                 :             : 
     366                 :          40 :   return *ret;
     367                 :             : }
     368                 :             : 
     369                 :             : static ptrdiff_t
     370                 :        7028 : read_macros (Dwarf *dbg, int sec_index,
     371                 :             :              Dwarf_Off macoff, int (*callback) (Dwarf_Macro *, void *),
     372                 :             :              void *arg, ptrdiff_t offset, bool accept_0xff,
     373                 :             :              Dwarf_Die *cudie)
     374                 :             : {
     375                 :        7028 :   Elf_Data *d = dbg->sectiondata[sec_index];
     376   [ +  -  -  + ]:        7028 :   if (unlikely (d == NULL || d->d_buf == NULL))
     377                 :             :     {
     378                 :           0 :       __libdw_seterrno (DWARF_E_NO_ENTRY);
     379                 :           0 :       return -1;
     380                 :             :     }
     381                 :             : 
     382         [ -  + ]:        7028 :   if (unlikely (macoff >= d->d_size))
     383                 :             :     {
     384                 :           0 :       __libdw_seterrno (DWARF_E_INVALID_DWARF);
     385                 :           0 :       return -1;
     386                 :             :     }
     387                 :             : 
     388                 :        7028 :   const unsigned char *const startp = d->d_buf + macoff;
     389                 :        7028 :   const unsigned char *const endp = d->d_buf + d->d_size;
     390                 :             : 
     391                 :        7028 :   Dwarf_Macro_Op_Table *table = cache_op_table (dbg, sec_index, macoff,
     392                 :             :                                                 startp, endp, cudie);
     393         [ +  + ]:        7028 :   if (table == NULL)
     394                 :             :     return -1;
     395                 :             : 
     396         [ +  + ]:        7026 :   if (offset == 0)
     397                 :          40 :     offset = table->header_len;
     398                 :             : 
     399         [ -  + ]:        7026 :   assert (offset >= 0);
     400         [ -  + ]:        7026 :   assert (offset < endp - startp);
     401                 :        7026 :   const unsigned char *readp = startp + offset;
     402                 :             : 
     403         [ +  - ]:        7026 :   while (readp < endp)
     404                 :             :     {
     405                 :        7026 :       unsigned int opcode = *readp++;
     406         [ +  + ]:        7026 :       if (opcode == 0)
     407                 :             :         /* Nothing more to do.  */
     408                 :        7026 :         return 0;
     409                 :             : 
     410         [ +  + ]:        6988 :       if (unlikely (opcode == 0xff && ! accept_0xff))
     411                 :             :         {
     412                 :             :           /* See comment below at dwarf_getmacros for explanation of
     413                 :             :              why we are doing this.  */
     414                 :           2 :           __libdw_seterrno (DWARF_E_INVALID_OPCODE);
     415                 :           2 :           return -1;
     416                 :             :         }
     417                 :             : 
     418                 :        6986 :       unsigned int idx = table->opcodes[opcode - 1];
     419         [ -  + ]:        6986 :       if (idx == 0xff)
     420                 :             :         {
     421                 :           0 :           __libdw_seterrno (DWARF_E_INVALID_OPCODE);
     422                 :           0 :           return -1;
     423                 :             :         }
     424                 :             : 
     425                 :        6986 :       Dwarf_Macro_Op_Proto *proto = &table->table[idx];
     426                 :             : 
     427                 :             :       /* A fake CU with bare minimum data to fool dwarf_formX into
     428                 :             :          doing the right thing with the attributes that we put out.
     429                 :             :          We pretend it is the same version as the actual table.
     430                 :             :          Version 4 for the old GNU extension, version 5 for DWARF5.
     431                 :             :          To handle DW_FORM_strx[1234] we set the .str_offsets_base
     432                 :             :          from the given CU.
     433                 :             :          XXX We will need to deal with DW_MACRO_import_sup and change
     434                 :             :          out the dbg somehow for the DW_FORM_sec_offset to make sense.  */
     435                 :       13972 :       Dwarf_CU fake_cu = {
     436                 :             :         .dbg = dbg,
     437                 :             :         .sec_idx = sec_index,
     438                 :        6986 :         .version = table->version,
     439                 :        6986 :         .offset_size = table->offset_size,
     440         [ +  + ]:        6986 :         .str_off_base = str_offsets_base_off (dbg, (cudie != NULL
     441                 :             :                                                     ? cudie->cu: NULL)),
     442                 :             :         .startp = (void *) startp + offset,
     443                 :             :         .endp = (void *) endp,
     444                 :             :       };
     445                 :             : 
     446                 :        6986 :       Dwarf_Attribute *attributes;
     447                 :        6986 :       Dwarf_Attribute *attributesp = NULL;
     448                 :        6986 :       Dwarf_Attribute nattributes[8];
     449         [ -  + ]:        6986 :       if (unlikely (proto->nforms > 8))
     450                 :             :         {
     451                 :           0 :           attributesp = malloc (sizeof (Dwarf_Attribute) * proto->nforms);
     452         [ #  # ]:           0 :           if (attributesp == NULL)
     453                 :             :             {
     454                 :           0 :               __libdw_seterrno (DWARF_E_NOMEM);
     455                 :           0 :               return -1;
     456                 :             :             }
     457                 :             :           attributes = attributesp;
     458                 :             :         }
     459                 :             :       else
     460                 :             :         attributes = &nattributes[0];
     461                 :             : 
     462         [ +  + ]:       20812 :       for (Dwarf_Word i = 0; i < proto->nforms; ++i)
     463                 :             :         {
     464                 :             :           /* We pretend this is a DW_AT[_GNU]_macros attribute so that
     465                 :             :              DW_FORM_sec_offset forms get correctly interpreted as
     466                 :             :              offset into .debug_macro.  XXX Deal with DW_MACRO_import_sup
     467                 :             :              (swap .dbg) for DW_FORM_sec_offset? */
     468                 :       27652 :           attributes[i].code = (fake_cu.version == 4 ? DW_AT_GNU_macros
     469         [ +  + ]:       13826 :                                                      : DW_AT_macros);
     470                 :       13826 :           attributes[i].form = proto->forms[i];
     471                 :       13826 :           attributes[i].valp = (void *) readp;
     472                 :       13826 :           attributes[i].cu = &fake_cu;
     473                 :             : 
     474                 :             :           /* We don't want forms that aren't allowed because they could
     475                 :             :              read from the "abbrev" like DW_FORM_implicit_const.  */
     476         [ -  + ]:       13826 :           if (! libdw_valid_user_form (attributes[i].form))
     477                 :             :             {
     478                 :           0 :               __libdw_seterrno (DWARF_E_INVALID_DWARF);
     479                 :           0 :               free (attributesp);
     480                 :           0 :               return -1;
     481                 :             :             }
     482                 :             : 
     483                 :       13826 :           size_t len = __libdw_form_val_len (&fake_cu, proto->forms[i], readp);
     484         [ -  + ]:       13826 :           if (unlikely (len == (size_t) -1))
     485                 :             :             {
     486                 :           0 :               free (attributesp);
     487                 :           0 :               return -1;
     488                 :             :             }
     489                 :             : 
     490                 :       13826 :           readp += len;
     491                 :             :         }
     492                 :             : 
     493                 :        6986 :       Dwarf_Macro macro = {
     494                 :             :         .table = table,
     495                 :             :         .opcode = opcode,
     496                 :             :         .attributes = attributes,
     497                 :             :       };
     498                 :             : 
     499                 :        6986 :       int res = callback (&macro, arg);
     500         [ -  + ]:        6986 :       if (unlikely (attributesp != NULL))
     501                 :           0 :         free (attributesp);
     502                 :             : 
     503         [ +  - ]:        6986 :       if (res != DWARF_CB_OK)
     504                 :        6986 :         return readp - startp;
     505                 :             :     }
     506                 :             : 
     507                 :             :   return 0;
     508                 :             : }
     509                 :             : 
     510                 :             : /* Token layout:
     511                 :             : 
     512                 :             :    - The highest bit is used for distinguishing between callers that
     513                 :             :      know that opcode 0xff may have one of two incompatible meanings.
     514                 :             :      The mask that we use for selecting this bit is
     515                 :             :      DWARF_GETMACROS_START.
     516                 :             : 
     517                 :             :    - The rest of the token (31 or 63 bits) encodes address inside the
     518                 :             :      macro unit.
     519                 :             : 
     520                 :             :    Besides, token value of 0 signals end of iteration and -1 is
     521                 :             :    reserved for signaling errors.  That means it's impossible to
     522                 :             :    represent maximum offset of a .debug_macro unit to new-style
     523                 :             :    callers (which in practice decreases the permissible macro unit
     524                 :             :    size by another 1 byte).  */
     525                 :             : 
     526                 :             : static ptrdiff_t
     527                 :        7028 : token_from_offset (ptrdiff_t offset, bool accept_0xff)
     528                 :             : {
     529         [ +  + ]:        7028 :   if (offset == -1 || offset == 0)
     530                 :             :     return offset;
     531                 :             : 
     532                 :             :   /* Make sure the offset didn't overflow into the flag bit.  */
     533         [ -  + ]:        6986 :   if ((offset & DWARF_GETMACROS_START) != 0)
     534                 :             :     {
     535                 :           0 :       __libdw_seterrno (DWARF_E_TOO_BIG);
     536                 :           0 :       return -1;
     537                 :             :     }
     538                 :             : 
     539         [ +  + ]:        6986 :   if (accept_0xff)
     540                 :        5934 :     offset |= DWARF_GETMACROS_START;
     541                 :             : 
     542                 :             :   return offset;
     543                 :             : }
     544                 :             : 
     545                 :             : static ptrdiff_t
     546                 :        7028 : offset_from_token (ptrdiff_t token, bool *accept_0xffp)
     547                 :             : {
     548                 :        7028 :   *accept_0xffp = (token & DWARF_GETMACROS_START) != 0;
     549                 :        7028 :   token &= ~DWARF_GETMACROS_START;
     550                 :             : 
     551                 :        7028 :   return token;
     552                 :             : }
     553                 :             : 
     554                 :             : static ptrdiff_t
     555                 :        3694 : gnu_macros_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
     556                 :             :                           int (*callback) (Dwarf_Macro *, void *),
     557                 :             :                           void *arg, ptrdiff_t offset, bool accept_0xff,
     558                 :             :                           Dwarf_Die *cudie)
     559                 :             : {
     560         [ -  + ]:        3694 :   assert (offset >= 0);
     561                 :             : 
     562         [ -  + ]:        3694 :   if (macoff >= dbg->sectiondata[IDX_debug_macro]->d_size)
     563                 :             :     {
     564                 :           0 :       __libdw_seterrno (DWARF_E_INVALID_OFFSET);
     565                 :           0 :       return -1;
     566                 :             :     }
     567                 :             : 
     568                 :        3694 :   return read_macros (dbg, IDX_debug_macro, macoff,
     569                 :             :                       callback, arg, offset, accept_0xff, cudie);
     570                 :             : }
     571                 :             : 
     572                 :             : static ptrdiff_t
     573                 :        3334 : macro_info_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
     574                 :             :                           int (*callback) (Dwarf_Macro *, void *),
     575                 :             :                           void *arg, ptrdiff_t offset, Dwarf_Die *cudie)
     576                 :             : {
     577         [ -  + ]:        3334 :   assert (offset >= 0);
     578                 :             : 
     579                 :        3334 :   return read_macros (dbg, IDX_debug_macinfo, macoff,
     580                 :             :                       callback, arg, offset, true, cudie);
     581                 :             : }
     582                 :             : 
     583                 :             : ptrdiff_t
     584                 :         352 : dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
     585                 :             :                      int (*callback) (Dwarf_Macro *, void *),
     586                 :             :                      void *arg, ptrdiff_t token)
     587                 :             : {
     588         [ -  + ]:         352 :   if (dbg == NULL)
     589                 :             :     {
     590                 :           0 :       __libdw_seterrno (DWARF_E_NO_DWARF);
     591                 :           0 :       return -1;
     592                 :             :     }
     593                 :             : 
     594                 :         352 :   bool accept_0xff;
     595                 :         352 :   ptrdiff_t offset = offset_from_token (token, &accept_0xff);
     596         [ -  + ]:         352 :   assert (accept_0xff);
     597                 :             : 
     598                 :         352 :   offset = gnu_macros_getmacros_off (dbg, macoff, callback, arg, offset,
     599                 :             :                                      accept_0xff, NULL);
     600                 :             : 
     601                 :         352 :   return token_from_offset (offset, accept_0xff);
     602                 :             : }
     603                 :             : 
     604                 :             : ptrdiff_t
     605                 :        6676 : dwarf_getmacros (Dwarf_Die *cudie, int (*callback) (Dwarf_Macro *, void *),
     606                 :             :                  void *arg, ptrdiff_t token)
     607                 :             : {
     608         [ -  + ]:        6676 :   if (cudie == NULL)
     609                 :             :     {
     610                 :           0 :       __libdw_seterrno (DWARF_E_NO_DWARF);
     611                 :           0 :       return -1;
     612                 :             :     }
     613                 :             : 
     614                 :             :   /* This function might be called from a code that expects to see
     615                 :             :      DW_MACINFO_* opcodes, not DW_MACRO_{GNU_,}* ones.  It is fine to
     616                 :             :      serve most DW_MACRO_{GNU_,}* opcodes to such code, because those
     617                 :             :      whose values are the same as DW_MACINFO_* ones also have the same
     618                 :             :      behavior.  It is not very likely that a .debug_macro section
     619                 :             :      would only use the part of opcode space that it shares with
     620                 :             :      .debug_macinfo, but it is possible.  Serving the opcodes that are
     621                 :             :      only valid in DW_MACRO_{GNU_,}* domain is OK as well, because
     622                 :             :      clients in general need to be ready that newer standards define
     623                 :             :      more opcodes, and have coping mechanisms for unfamiliar opcodes.
     624                 :             : 
     625                 :             :      The one exception to the above rule is opcode 0xff, which has
     626                 :             :      concrete semantics in .debug_macinfo, but falls into vendor block
     627                 :             :      in .debug_macro, and can be assigned to do whatever.  There is
     628                 :             :      some small probability that the two opcodes would look
     629                 :             :      superficially similar enough that a client would be confused and
     630                 :             :      misbehave as a result.  For this reason, we refuse to serve
     631                 :             :      through this interface 0xff's originating from .debug_macro
     632                 :             :      unless the TOKEN that we obtained indicates the call originates
     633                 :             :      from a new-style caller.  See above for details on what
     634                 :             :      information is encoded into tokens.  */
     635                 :             : 
     636                 :        6676 :   bool accept_0xff;
     637                 :        6676 :   ptrdiff_t offset = offset_from_token (token, &accept_0xff);
     638                 :             : 
     639                 :             :   /* DW_AT_macro_info */
     640         [ +  + ]:        6676 :   if (dwarf_hasattr (cudie, DW_AT_macro_info))
     641                 :             :     {
     642                 :        3334 :       Dwarf_Word macoff;
     643         [ -  + ]:        3334 :       if (get_offset_from (cudie, DW_AT_macro_info, &macoff) != 0)
     644                 :           0 :         return -1;
     645                 :        3334 :       offset = macro_info_getmacros_off (cudie->cu->dbg, macoff,
     646                 :             :                                          callback, arg, offset, cudie);
     647                 :             :     }
     648                 :             :   else
     649                 :             :     {
     650                 :             :       /* DW_AT_GNU_macros, DW_AT_macros */
     651                 :        3342 :       Dwarf_Word macoff;
     652         [ +  + ]:        3342 :       if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0
     653         [ -  + ]:        2802 :           && get_offset_from (cudie, DW_AT_macros, &macoff) != 0)
     654                 :           0 :         return -1;
     655                 :        3342 :       offset = gnu_macros_getmacros_off (cudie->cu->dbg, macoff,
     656                 :             :                                          callback, arg, offset, accept_0xff,
     657                 :             :                                          cudie);
     658                 :             :     }
     659                 :             : 
     660                 :        6676 :   return token_from_offset (offset, accept_0xff);
     661                 :             : }
        

Generated by: LCOV version 2.0-1