Coverage Report

Created: 2025-08-29 06:10

/src/elfutils/libdw/dwarf_nextcu.c
Line
Count
Source (jump to first uncovered line)
1
/* Advance to next CU header.
2
   Copyright (C) 2002-2010, 2016, 2017 Red Hat, Inc.
3
   This file is part of elfutils.
4
   Written by Ulrich Drepper <drepper@redhat.com>, 2002.
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 <libdwP.h>
35
#include <dwarf.h>
36
37
38
int
39
dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
40
     size_t *header_sizep, Dwarf_Half *versionp,
41
     Dwarf_Off *abbrev_offsetp, uint8_t *address_sizep,
42
     uint8_t *offset_sizep, uint64_t *v4_type_signaturep,
43
     Dwarf_Off *v4_type_offsetp)
44
0
{
45
0
  const bool v4_debug_types = v4_type_signaturep != NULL;
46
0
  return __libdw_next_unit (dwarf, v4_debug_types, off, next_off,
47
0
           header_sizep, versionp, NULL,
48
0
           abbrev_offsetp, address_sizep, offset_sizep,
49
0
           v4_type_signaturep, v4_type_offsetp);
50
0
}
51
INTDEF(dwarf_next_unit)
52
53
int
54
internal_function
55
__libdw_next_unit (Dwarf *dwarf, bool v4_debug_types, Dwarf_Off off,
56
       Dwarf_Off *next_off, size_t *header_sizep,
57
       Dwarf_Half *versionp, uint8_t *unit_typep,
58
       Dwarf_Off *abbrev_offsetp, uint8_t *address_sizep,
59
       uint8_t *offset_sizep, uint64_t *unit_id8p,
60
       Dwarf_Off *subdie_offsetp)
61
0
{
62
  /* Note that debug_type units come from .debug_types in DWARF < 5 and
63
     from .debug_info in DWARF >= 5.  If the user requested the
64
     v4_type_signature we return from .debug_types always.  If no signature
65
     is requested we return units (any type) from .debug_info.  */
66
0
  const size_t sec_idx = v4_debug_types ? IDX_debug_types : IDX_debug_info;
67
68
  /* Maybe there has been an error before.  */
69
0
  if (dwarf == NULL)
70
0
    return -1;
71
72
  /* If we reached the end before don't do anything.  */
73
0
  if (off == (Dwarf_Off) -1l
74
0
      || unlikely (dwarf->sectiondata[sec_idx] == NULL)
75
      /* Make sure there is enough space in the .debug_info section
76
   for at least the initial word.  We cannot test the rest since
77
   we don't know yet whether this is a 64-bit object or not.  */
78
0
      || unlikely (off + 4 >= dwarf->sectiondata[sec_idx]->d_size))
79
0
    {
80
0
      *next_off = (Dwarf_Off) -1l;
81
0
      return 1;
82
0
    }
83
84
  /* This points into the .debug_info or .debug_types section to the
85
     beginning of the CU entry.  */
86
0
  const unsigned char *data = dwarf->sectiondata[sec_idx]->d_buf;
87
0
  const unsigned char *bytes = data + off;
88
0
  const unsigned char *bytes_end = data + dwarf->sectiondata[sec_idx]->d_size;
89
90
  /* The format of the CU header is described in dwarf2p1 7.5.1 and
91
     changed in DWARFv5 (to include unit type, switch location of some
92
     fields and add some optional fields).
93
94
     1.  A 4-byte or 12-byte unsigned integer representing the length
95
   of the .debug_info contribution for that compilation unit, not
96
   including the length field itself. In the 32-bit DWARF format,
97
   this is a 4-byte unsigned integer (which must be less than
98
   0xfffffff0); in the 64-bit DWARF format, this consists of the
99
   4-byte value 0xffffffff followed by an 8-byte unsigned integer
100
   that gives the actual length (see Section 7.2.2). This field
101
   indicates whether this unit is 32-bit of 64-bit DWARF, which
102
   affects all other offset fields in this header.
103
104
      2. A 2-byte unsigned integer representing the version of the
105
   DWARF information for that compilation unit. For DWARF Version
106
   2.1, the value in this field is 2 (3 for v3, 4 for v4, 5 for v5).
107
   This fields determines the order of the next fields and whether
108
   there are any optional fields in this header.
109
110
      3. For DWARF 2, 3 and 4 (including v4 type units):
111
         A 4-byte or 8-byte unsigned offset into the .debug_abbrev
112
   section. This offset associates the compilation unit with a
113
   particular set of debugging information entry abbreviations. In
114
   the 32-bit DWARF format, this is a 4-byte unsigned length; in
115
   the 64-bit DWARF format, this is an 8-byte unsigned length (see
116
   Section 7.4).
117
118
   For DWARF 5:
119
   A 1-byte unsigned integer representing the unit (header) type.
120
   This field determines what the optional fields in the header
121
   represent.  If this is an unknown unit type then we cannot
122
   assume anything about the rest of the unit (header).
123
124
      4. For all DWARF versions (including v4 type units):
125
         A 1-byte unsigned integer representing the size in bytes of
126
   an address on the target architecture. If the system uses
127
   segmented addressing, this value represents the size of the
128
   offset portion of an address. This is the last field in the header
129
   for DWARF versions 2, 3 and 4 (except for v4 type units).
130
131
      5. For DWARF 5 only (this is field 3 for DWARF 2, 3, 4 and v4 types):
132
         A 4-byte or 8-byte unsigned offset into the .debug_abbrev
133
   section. This offset associates the compilation unit with a
134
   particular set of debugging information entry abbreviations. In
135
   the 32-bit DWARF format, this is a 4-byte unsigned length; in
136
   the 64-bit DWARF format, this is an 8-byte unsigned length.
137
138
      6. For v4 type units (this is really field 5 for v4 types) and
139
         DWARF 5 optional (skeleton, split_compile, type and
140
         split_type): An 8 byte (opaque) integer constant value. For
141
         v4 and v5 type units this is the type signature. For skeleton
142
         and split compile units this is the compilation ID.
143
144
      7. For v4 type units (this is really field 6 for v4 types) and
145
         DWARF 5 optional (type and split_type) and v4 type units:
146
         A 4-byte or 8-byte unsigned offset. In the 32-bit DWARF format,
147
         this is a 4-byte unsigned length; in the 64-bit DWARF format,
148
         this is an 8-byte unsigned length. This is the type DIE offset
149
   (which is not necessarily the first DIE in the unit).
150
  */
151
152
0
  uint64_t length = read_4ubyte_unaligned_inc (dwarf, bytes);
153
0
  size_t offset_size = 4;
154
  /* Lengths of 0xfffffff0 - 0xffffffff are escape codes.  Oxffffffff is
155
     used to indicate that 64-bit dwarf information is being used, the
156
     other values are currently reserved.  */
157
0
  if (length == DWARF3_LENGTH_64_BIT)
158
0
    offset_size = 8;
159
0
  else if (unlikely (length >= DWARF3_LENGTH_MIN_ESCAPE_CODE
160
0
         && length <= DWARF3_LENGTH_MAX_ESCAPE_CODE))
161
0
    {
162
0
    invalid:
163
0
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
164
0
      return -1;
165
0
    }
166
167
0
  if (length == DWARF3_LENGTH_64_BIT)
168
0
    {
169
      /* This is a 64-bit DWARF format.  */
170
0
      if (bytes_end - bytes < 8)
171
0
  goto invalid;
172
0
      length = read_8ubyte_unaligned_inc (dwarf, bytes);
173
0
    }
174
175
  /* Read the version stamp.  Always a 16-bit value.  */
176
0
  if (bytes_end - bytes < 2)
177
0
    goto invalid;
178
0
  uint_fast16_t version = read_2ubyte_unaligned_inc (dwarf, bytes);
179
180
  /* We keep unit_type at zero for older DWARF since we cannot
181
     easily guess whether it is a compile or partial unit.  */
182
0
  uint8_t unit_type = 0;
183
0
  if (version >= 5)
184
0
    {
185
0
      if (bytes_end - bytes < 1)
186
0
  goto invalid;
187
0
      unit_type = *bytes++;
188
0
    }
189
190
  /* All these are optional.  */
191
0
  Dwarf_Off subdie_off = 0;
192
0
  uint64_t sig_id = 0;
193
0
  Dwarf_Off abbrev_offset = 0;
194
0
  uint8_t address_size = 0;
195
196
0
  if (version < 2 || version > 5
197
0
      || (version == 5 && ! (unit_type == DW_UT_compile
198
0
           || unit_type == DW_UT_partial
199
0
           || unit_type == DW_UT_skeleton
200
0
           || unit_type == DW_UT_split_compile
201
0
           || unit_type == DW_UT_type
202
0
           || unit_type == DW_UT_split_type)))
203
0
    {
204
      /* We cannot really know more about the header.  Just report
205
   the length of the unit, version and unit type.  */
206
0
      goto done;
207
0
    }
208
209
  /* We have to guess the unit_type. But we don't have a real CUDIE.  */
210
0
  if (version < 5)
211
0
    unit_type = v4_debug_types ? DW_UT_type : DW_UT_compile;
212
213
  /* Now we know how large the header is (should be).  */
214
0
  if (unlikely (__libdw_first_die_from_cu_start (off, offset_size, version,
215
0
             unit_type)
216
0
    >= dwarf->sectiondata[sec_idx]->d_size))
217
0
    {
218
0
      *next_off = -1;
219
0
      return 1;
220
0
    }
221
222
  /* The address size.  Always an 8-bit value.
223
     Comes after abbrev_offset for version < 5, otherwise unit type
224
     and address size (if a known unit type) comes before abbrev_offset.  */
225
0
  if (version >= 5)
226
0
    address_size = *bytes++;
227
228
  /* Get offset in .debug_abbrev.  Note that the size of the entry
229
     depends on whether this is a 32-bit or 64-bit DWARF definition.  */
230
0
  if (__libdw_read_offset_inc (dwarf, sec_idx, &bytes, offset_size,
231
0
             &abbrev_offset, IDX_debug_abbrev, 0))
232
0
    return -1;
233
234
0
  if (version < 5)
235
0
    address_size = *bytes++;
236
237
  /* Extra fields, signature/id and type offset/padding.  */
238
0
  if (v4_debug_types
239
0
      || (version >= 5
240
0
    && (unit_type == DW_UT_skeleton || unit_type == DW_UT_split_compile
241
0
        || unit_type == DW_UT_type || unit_type == DW_UT_split_type)))
242
0
    {
243
0
      sig_id = read_8ubyte_unaligned_inc (dwarf, bytes);
244
245
0
      if ((v4_debug_types
246
0
     || unit_type == DW_UT_type || unit_type == DW_UT_split_type))
247
0
  {
248
0
    if (__libdw_read_offset_inc (dwarf, sec_idx, &bytes, offset_size,
249
0
               &subdie_off, sec_idx, 0))
250
0
      return -1;
251
252
    /* Validate that the TYPE_OFFSET points past the header.  */
253
0
    if (unlikely (subdie_off < (size_t) (bytes - (data + off))))
254
0
      goto invalid;
255
0
  }
256
0
    }
257
258
0
 done:
259
0
  if (unit_id8p != NULL)
260
0
    *unit_id8p = sig_id;
261
262
0
  if (subdie_offsetp != NULL)
263
0
    *subdie_offsetp = subdie_off;
264
265
  /* Store the header length.  This is really how much we have read
266
     from the header.  If we didn't recognize the unit type the
267
     header might actually be bigger.  */
268
0
  if (header_sizep != NULL)
269
0
    *header_sizep = bytes - (data + off);
270
271
0
  if (versionp != NULL)
272
0
    *versionp = version;
273
274
0
  if (unit_typep != NULL)
275
0
    *unit_typep = unit_type;
276
277
0
  if (abbrev_offsetp != NULL)
278
0
    *abbrev_offsetp = abbrev_offset;
279
280
0
  if (address_sizep != NULL)
281
0
    *address_sizep = address_size;
282
283
  /* Store the offset size.  */
284
0
  if (offset_sizep != NULL)
285
0
    *offset_sizep = offset_size;
286
287
  /* The length of the unit doesn't include the length field itself.
288
     The length field is either, with offset == 4: 2 * 4 - 4 == 4,
289
     or with offset == 8: 2 * 8 - 4 == 12.  */
290
0
  *next_off = off + 2 * offset_size - 4 + length;
291
292
  /* This means that the length field is bogus, but return the CU anyway.
293
     We just won't return anything after this.  */
294
0
  if (*next_off <= off)
295
0
    *next_off = (Dwarf_Off) -1;
296
297
0
  return 0;
298
0
}
299
300
int
301
dwarf_nextcu (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
302
        size_t *header_sizep, Dwarf_Off *abbrev_offsetp,
303
        uint8_t *address_sizep, uint8_t *offset_sizep)
304
0
{
305
0
  return INTUSE(dwarf_next_unit) (dwarf, off, next_off, header_sizep, NULL,
306
0
          abbrev_offsetp, address_sizep, offset_sizep,
307
0
          NULL, NULL);
308
0
}
309
INTDEF(dwarf_nextcu)