Coverage Report

Created: 2026-02-24 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/elfutils/libdw/dwarf_formudata.c
Line
Count
Source
1
/* Return unsigned constant represented by attribute.
2
   Copyright (C) 2003-2012, 2014, 2017 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 <dwarf.h>
35
#include "libdwP.h"
36
37
internal_function const unsigned char *
38
__libdw_formptr (Dwarf_Attribute *attr, int sec_index,
39
     int err_nodata, const unsigned char **endpp,
40
     Dwarf_Off *offsetp)
41
0
{
42
0
  if (attr == NULL)
43
0
    return NULL;
44
45
0
  const Elf_Data *d = attr->cu->dbg->sectiondata[sec_index];
46
0
  Dwarf_CU *skel = NULL; /* See below, needed for GNU DebugFission.  */
47
0
  if (unlikely (d == NULL
48
0
    && sec_index == IDX_debug_ranges
49
0
    && attr->cu->version < 5
50
0
    && attr->cu->unit_type == DW_UT_split_compile))
51
0
    {
52
0
      skel = __libdw_find_split_unit (attr->cu);
53
0
      if (skel != NULL)
54
0
  d = skel->dbg->sectiondata[IDX_debug_ranges];
55
0
    }
56
57
0
  if (unlikely (d == NULL))
58
0
    {
59
0
      __libdw_seterrno (err_nodata);
60
0
      return NULL;
61
0
    }
62
63
0
  Dwarf_Word offset;
64
0
  if (attr->form == DW_FORM_sec_offset)
65
0
    {
66
      /* GNU DebugFission is slightly odd.  It uses DW_FORM_sec_offset
67
   in split units, but they are really (unrelocated) offsets
68
   from the skeleton DW_AT_GNU_ranges_base (which is only used
69
   for the split unit, not the skeleton ranges itself, see also
70
   DW_AT_rnglists_base, which is used in DWARF5 for both, but
71
   points to the offsets index).  So it isn't really a formptr,
72
   but an offset + base calculation.  */
73
0
      if (unlikely (skel != NULL))
74
0
  {
75
0
    Elf_Data *data = attr->cu->dbg->sectiondata[cu_sec_idx (attr->cu)];
76
0
    const unsigned char *datap = attr->valp;
77
0
    size_t size = attr->cu->offset_size;
78
0
    if (unlikely (data == NULL
79
0
      || datap < (const unsigned char *) data->d_buf
80
0
      || data->d_size < size
81
0
      || ((size_t) (datap
82
0
              - (const unsigned char *) data->d_buf)
83
0
          > data->d_size - size)))
84
0
      goto invalid;
85
86
0
    if (size == 4)
87
0
      offset = read_4ubyte_unaligned (attr->cu->dbg, datap);
88
0
    else
89
0
      offset = read_8ubyte_unaligned (attr->cu->dbg, datap);
90
91
0
    offset += __libdw_cu_ranges_base (skel);
92
0
  }
93
0
      else
94
0
  {
95
0
    if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg,
96
0
           cu_sec_idx (attr->cu), attr->valp,
97
0
           attr->cu->offset_size, &offset,
98
0
           sec_index, 0))
99
0
      return NULL;
100
0
  }
101
0
    }
102
0
  else if (attr->cu->version > 3)
103
0
    goto invalid;
104
0
  else
105
0
    switch (attr->form)
106
0
      {
107
0
      case DW_FORM_data4:
108
0
      case DW_FORM_data8:
109
0
  if (__libdw_read_offset (attr->cu->dbg, attr->cu->dbg,
110
0
         cu_sec_idx (attr->cu),
111
0
         attr->valp,
112
0
         attr->form == DW_FORM_data4 ? 4 : 8,
113
0
         &offset, sec_index, 0))
114
0
    return NULL;
115
0
  break;
116
117
0
      default:
118
0
  if (INTUSE(dwarf_formudata) (attr, &offset))
119
0
    return NULL;
120
0
      };
121
122
0
  unsigned char *readp = d->d_buf + offset;
123
0
  unsigned char *endp = d->d_buf + d->d_size;
124
0
  if (unlikely (readp >= endp))
125
0
    {
126
0
    invalid:
127
0
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
128
0
      return NULL;
129
0
    }
130
131
0
  if (endpp != NULL)
132
0
    *endpp = endp;
133
0
  if (offsetp != NULL)
134
0
    *offsetp = offset;
135
0
  return readp;
136
0
}
137
138
int
139
dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval)
140
0
{
141
0
  if (attr == NULL)
142
0
    return -1;
143
144
0
  const unsigned char *datap = attr->valp;
145
0
  const unsigned char *endp = attr->cu->endp;
146
147
0
  switch (attr->form)
148
0
    {
149
0
    case DW_FORM_data1:
150
0
      if (datap + 1 > endp)
151
0
  {
152
0
  invalid:
153
0
    __libdw_seterrno (DWARF_E_INVALID_DWARF);
154
0
    return -1;
155
0
  }
156
0
      *return_uval = *attr->valp;
157
0
      break;
158
159
0
    case DW_FORM_data2:
160
0
      if (datap + 2 > endp)
161
0
  goto invalid;
162
0
      *return_uval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp);
163
0
      break;
164
165
0
    case DW_FORM_data4:
166
0
    case DW_FORM_data8:
167
0
    case DW_FORM_sec_offset:
168
      /* Before DWARF4 data4 and data8 are pure constants unless the
169
   attribute also allows offsets (*ptr classes), since DWARF4
170
   they are always just constants (start_scope is special though,
171
   since it only could express a rangelist since DWARF4).  */
172
0
      if (attr->form == DW_FORM_sec_offset
173
0
    || (attr->cu->version < 4 && attr->code != DW_AT_start_scope))
174
0
  {
175
0
    switch (attr->code)
176
0
      {
177
0
      case DW_AT_data_member_location:
178
0
      case DW_AT_frame_base:
179
0
      case DW_AT_location:
180
0
      case DW_AT_return_addr:
181
0
      case DW_AT_segment:
182
0
      case DW_AT_static_link:
183
0
      case DW_AT_string_length:
184
0
      case DW_AT_use_location:
185
0
      case DW_AT_vtable_elem_location:
186
0
      case DW_AT_GNU_locviews:
187
0
      case DW_AT_loclists_base:
188
0
        if (attr->cu->version < 5)
189
0
    {
190
      /* loclistptr */
191
0
      if (__libdw_formptr (attr, IDX_debug_loc,
192
0
               DWARF_E_NO_DEBUG_LOC, NULL,
193
0
               return_uval) == NULL)
194
0
        return -1;
195
0
    }
196
0
        else
197
0
    {
198
      /* loclist, loclistsptr */
199
0
      if (__libdw_formptr (attr, IDX_debug_loclists,
200
0
               DWARF_E_NO_DEBUG_LOCLISTS, NULL,
201
0
               return_uval) == NULL)
202
0
        return -1;
203
0
    }
204
0
        break;
205
206
0
      case DW_AT_macro_info:
207
        /* macptr into .debug_macinfo */
208
0
        if (__libdw_formptr (attr, IDX_debug_macinfo,
209
0
           DWARF_E_NO_ENTRY, NULL,
210
0
           return_uval) == NULL)
211
0
    return -1;
212
0
        break;
213
214
0
      case DW_AT_GNU_macros:
215
0
      case DW_AT_macros:
216
        /* macptr into .debug_macro */
217
0
        if (__libdw_formptr (attr, IDX_debug_macro,
218
0
           DWARF_E_NO_ENTRY, NULL,
219
0
           return_uval) == NULL)
220
0
    return -1;
221
0
        break;
222
223
0
      case DW_AT_ranges:
224
0
      case DW_AT_start_scope:
225
0
      case DW_AT_GNU_ranges_base:
226
0
      case DW_AT_rnglists_base:
227
0
        if (attr->cu->version < 5)
228
0
    {
229
      /* rangelistptr */
230
0
      if (__libdw_formptr (attr, IDX_debug_ranges,
231
0
               DWARF_E_NO_DEBUG_RANGES, NULL,
232
0
               return_uval) == NULL)
233
0
        return -1;
234
0
    }
235
0
        else
236
0
    {
237
      /* rnglistsptr */
238
0
      if (__libdw_formptr (attr, IDX_debug_rnglists,
239
0
               DWARF_E_NO_DEBUG_RNGLISTS, NULL,
240
0
               return_uval) == NULL)
241
0
        return -1;
242
0
    }
243
0
        break;
244
245
0
      case DW_AT_stmt_list:
246
        /* lineptr */
247
0
        if (__libdw_formptr (attr, IDX_debug_line,
248
0
           DWARF_E_NO_DEBUG_LINE, NULL,
249
0
           return_uval) == NULL)
250
0
    return -1;
251
0
        break;
252
253
0
      case DW_AT_addr_base:
254
0
      case DW_AT_GNU_addr_base:
255
        /* addrptr */
256
0
        if (__libdw_formptr (attr, IDX_debug_addr,
257
0
           DWARF_E_NO_DEBUG_ADDR, NULL,
258
0
           return_uval) == NULL)
259
0
    return -1;
260
0
        break;
261
262
0
      case DW_AT_str_offsets_base:
263
        /* stroffsetsptr */
264
0
        if (__libdw_formptr (attr, IDX_debug_str_offsets,
265
0
           DWARF_E_NO_STR_OFFSETS, NULL,
266
0
           return_uval) == NULL)
267
0
    return -1;
268
0
        break;
269
270
0
      default:
271
        /* sec_offset can only be used by one of the above attrs.  */
272
0
        if (attr->form == DW_FORM_sec_offset)
273
0
    {
274
0
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
275
0
      return -1;
276
0
    }
277
278
        /* Not one of the special attributes, just a constant.  */
279
0
        if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
280
0
          attr->valp,
281
0
          attr->form == DW_FORM_data4 ? 4 : 8,
282
0
          return_uval))
283
0
    return -1;
284
0
        break;
285
0
      }
286
0
  }
287
0
      else
288
0
  {
289
    /* We are dealing with a constant data4 or data8.  */
290
0
    if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu),
291
0
            attr->valp,
292
0
            attr->form == DW_FORM_data4 ? 4 : 8,
293
0
            return_uval))
294
0
      return -1;
295
0
  }
296
0
      break;
297
298
0
    case DW_FORM_sdata:
299
0
      if (datap + 1 > endp)
300
0
  goto invalid;
301
0
      get_sleb128 (*return_uval, datap, endp);
302
0
      break;
303
304
0
    case DW_FORM_udata:
305
0
    case DW_FORM_rnglistx:
306
0
    case DW_FORM_loclistx:
307
0
      if (datap + 1 > endp)
308
0
  goto invalid;
309
0
      get_uleb128 (*return_uval, datap, endp);
310
0
      break;
311
312
0
    case DW_FORM_implicit_const:
313
      // The data comes from the abbrev, which has been bounds checked.
314
0
      get_sleb128_unchecked (*return_uval, datap);
315
0
      break;
316
317
    /* These are indexes into the .debug_addr section, normally resolved
318
       with dwarf_formaddr.  Here treat as constants.  */
319
0
    case DW_FORM_GNU_addr_index:
320
0
    case DW_FORM_addrx:
321
0
      if (datap >= endp)
322
0
  goto invalid;
323
0
      get_uleb128 (*return_uval, datap, endp);
324
0
      break;
325
326
0
    case DW_FORM_addrx1:
327
0
      if (datap >= endp - 1)
328
0
  goto invalid;
329
0
      *return_uval = *datap;
330
0
      break;
331
332
0
    case DW_FORM_addrx2:
333
0
      if (datap >= endp - 2)
334
0
  goto invalid;
335
0
      *return_uval = read_2ubyte_unaligned (attr->cu->dbg, datap);
336
0
      break;
337
338
0
    case DW_FORM_addrx3:
339
0
      if (datap >= endp - 3)
340
0
  goto invalid;
341
0
      *return_uval = read_3ubyte_unaligned (attr->cu->dbg, datap);
342
0
      break;
343
344
0
    case DW_FORM_addrx4:
345
0
      if (datap >= endp - 4)
346
0
  goto invalid;
347
0
      *return_uval = read_4ubyte_unaligned (attr->cu->dbg, datap);
348
0
      break;
349
350
0
    default:
351
0
      __libdw_seterrno (DWARF_E_NO_CONSTANT);
352
0
      return -1;
353
0
    }
354
355
0
  return 0;
356
0
}
357
INTDEF(dwarf_formudata)