Coverage Report

Created: 2026-08-30 07:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/elfutils/libdw/libdw_findcu.c
Line
Count
Source
1
/* Find CU for given offset.
2
   Copyright (C) 2003-2010, 2014, 2016, 2017, 2018 Red Hat, Inc.
3
   This file is part of elfutils.
4
   Written by Ulrich Drepper <drepper@redhat.com>, 2003.
5
6
   This file is free software; you can redistribute it and/or modify
7
   it under the terms of either
8
9
     * the GNU Lesser General Public License as published by the Free
10
       Software Foundation; either version 3 of the License, or (at
11
       your option) any later version
12
13
   or
14
15
     * the GNU General Public License as published by the Free
16
       Software Foundation; either version 2 of the License, or (at
17
       your option) any later version
18
19
   or both in parallel, as here.
20
21
   elfutils is distributed in the hope that it will be useful, but
22
   WITHOUT ANY WARRANTY; without even the implied warranty of
23
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24
   General Public License for more details.
25
26
   You should have received copies of the GNU General Public License and
27
   the GNU Lesser General Public License along with this program.  If
28
   not, see <http://www.gnu.org/licenses/>.  */
29
30
#ifdef HAVE_CONFIG_H
31
# include <config.h>
32
#endif
33
34
#include <assert.h>
35
#include <search.h>
36
#include "libdwP.h"
37
38
static int
39
findcu_cb (const void *arg1, const void *arg2)
40
0
{
41
0
  struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1;
42
0
  struct Dwarf_CU *cu2 = (struct Dwarf_CU *) arg2;
43
44
  /* Find out which of the two arguments is the search value.  It has
45
     end offset 0.  */
46
0
  if (cu1->end == 0)
47
0
    {
48
0
      if (cu1->start < cu2->start)
49
0
  return -1;
50
0
      if (cu1->start >= cu2->end)
51
0
  return 1;
52
0
    }
53
0
  else
54
0
    {
55
0
      if (cu2->start < cu1->start)
56
0
  return 1;
57
0
      if (cu2->start >= cu1->end)
58
0
  return -1;
59
0
    }
60
61
0
  return 0;
62
0
}
63
64
int
65
__libdw_finddbg_cb (const void *arg1, const void *arg2)
66
0
{
67
0
  Dwarf *dbg1 = (Dwarf *) arg1;
68
0
  Dwarf *dbg2 = (Dwarf *) arg2;
69
70
0
  Elf_Data *dbg1_data = dbg1->sectiondata[IDX_debug_info];
71
0
  unsigned char *dbg1_start = dbg1_data->d_buf;
72
0
  size_t dbg1_size = dbg1_data->d_size;
73
74
0
  Elf_Data *dbg2_data = dbg2->sectiondata[IDX_debug_info];
75
0
  unsigned char *dbg2_start = dbg2_data->d_buf;
76
0
  size_t dbg2_size = dbg2_data->d_size;
77
78
  /* Find out which of the two arguments is the search value.  It has
79
     a size of 0.  */
80
0
  if (dbg1_size == 0)
81
0
    {
82
0
      if (dbg1_start < dbg2_start)
83
0
  return -1;
84
0
      if (dbg1_start >= dbg2_start + dbg2_size)
85
0
  return 1;
86
0
    }
87
0
  else
88
0
    {
89
0
      if (dbg2_start < dbg1_start)
90
0
  return 1;
91
0
      if (dbg2_start >= dbg1_start + dbg1_size)
92
0
  return -1;
93
0
    }
94
95
0
  return 0;
96
0
}
97
98
struct Dwarf_CU *
99
internal_function
100
__libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
101
0
{
102
0
  Dwarf_Off *const offsetp
103
0
    = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
104
0
  void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
105
106
0
  Dwarf_Off oldoff = *offsetp;
107
0
  uint16_t version;
108
0
  uint8_t unit_type;
109
0
  uint8_t address_size;
110
0
  uint8_t offset_size;
111
0
  Dwarf_Off abbrev_offset;
112
0
  uint64_t unit_id8;
113
0
  Dwarf_Off subdie_offset;
114
115
0
  if (__libdw_next_unit (dbg, debug_types, oldoff, offsetp, NULL,
116
0
       &version, &unit_type, &abbrev_offset,
117
0
       &address_size, &offset_size,
118
0
       &unit_id8, &subdie_offset) != 0)
119
    /* No more entries.  */
120
0
    return NULL;
121
122
  /* We only know how to handle the DWARF version 2 through 5 formats.
123
     For v4 debug types we only handle version 4.  */
124
0
  if (unlikely (version < 2) || unlikely (version > 5)
125
0
      || (debug_types && unlikely (version != 4)))
126
0
    {
127
0
      __libdw_seterrno (DWARF_E_VERSION);
128
0
      return NULL;
129
0
    }
130
131
  /* We only handle 32 or 64 bit (4 or 8 byte) addresses and offsets.
132
     Just assume we are dealing with 64bit in case the size is "unknown".
133
     Too much code assumes if it isn't 4 then it is 8 (or the other way
134
     around).  */
135
0
  if (unlikely (address_size != 4 && address_size != 8))
136
0
    address_size = 8;
137
0
  if (unlikely (offset_size != 4 && offset_size != 8))
138
0
    offset_size = 8;
139
140
  /* Invalid or truncated debug section data?  */
141
0
  size_t sec_idx = debug_types ? IDX_debug_types : IDX_debug_info;
142
0
  Elf_Data *data = dbg->sectiondata[sec_idx];
143
0
  if (unlikely (*offsetp > data->d_size))
144
0
    *offsetp = data->d_size;
145
146
  /* Create an entry for this CU.  */
147
0
  struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
148
149
0
  newp->dbg = dbg;
150
0
  newp->sec_idx = sec_idx;
151
0
  newp->start = oldoff;
152
0
  newp->end = *offsetp;
153
0
  newp->address_size = address_size;
154
0
  newp->offset_size = offset_size;
155
0
  newp->version = version;
156
0
  newp->unit_id8 = unit_id8;
157
0
  newp->subdie_offset = subdie_offset;
158
0
  Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
159
0
  newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
160
0
  newp->files = NULL;
161
0
  newp->lines = NULL;
162
0
  newp->locs = NULL;
163
0
  newp->split = (Dwarf_CU *) -1;
164
0
  newp->base_address = (Dwarf_Addr) -1;
165
0
  newp->addr_base = (Dwarf_Off) -1;
166
0
  newp->str_off_base = (Dwarf_Off) -1;
167
0
  newp->ranges_base = (Dwarf_Off) -1;
168
0
  newp->locs_base = (Dwarf_Off) -1;
169
170
0
  newp->startp = data->d_buf + newp->start;
171
0
  newp->endp = data->d_buf + newp->end;
172
173
  /* v4 debug type units have version == 4 and unit_type == DW_UT_type.  */
174
0
  if (debug_types)
175
0
    newp->unit_type = DW_UT_type;
176
0
  else if (version < 5)
177
0
    {
178
      /* This is a reasonable guess (and needed to get the CUDIE).  */
179
0
      newp->unit_type = DW_UT_compile;
180
181
      /* But set it correctly from the actual CUDIE tag.  */
182
0
      Dwarf_Die cudie = CUDIE (newp);
183
0
      int tag = INTUSE(dwarf_tag) (&cudie);
184
0
      if (tag == DW_TAG_compile_unit)
185
0
  {
186
0
    Dwarf_Attribute dwo_id;
187
0
    if (INTUSE(dwarf_attr) (&cudie, DW_AT_GNU_dwo_id, &dwo_id) != NULL)
188
0
      {
189
0
        Dwarf_Word id8;
190
0
        if (INTUSE(dwarf_formudata) (&dwo_id, &id8) == 0)
191
0
    {
192
0
      if (INTUSE(dwarf_haschildren) (&cudie) == 0
193
0
          && INTUSE(dwarf_hasattr) (&cudie,
194
0
            DW_AT_GNU_dwo_name) == 1)
195
0
        newp->unit_type = DW_UT_skeleton;
196
0
      else
197
0
        newp->unit_type = DW_UT_split_compile;
198
199
0
      newp->unit_id8 = id8;
200
0
    }
201
0
      }
202
0
  }
203
0
      else if (tag == DW_TAG_partial_unit)
204
0
  newp->unit_type = DW_UT_partial;
205
0
      else if (tag == DW_TAG_type_unit)
206
0
  newp->unit_type = DW_UT_type;
207
0
    }
208
0
  else
209
0
    newp->unit_type = unit_type;
210
211
  /* Store a reference to any type unit ids in the hash for quick lookup.  */
212
0
  if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)
213
0
    Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, unit_id8, newp);
214
215
  /* Add the new entry to the search tree.  */
216
0
  if (tsearch (newp, tree, findcu_cb) == NULL)
217
0
    {
218
      /* Something went wrong.  Undo the operation.  */
219
0
      *offsetp = oldoff;
220
0
      __libdw_seterrno (DWARF_E_NOMEM);
221
0
      return NULL;
222
0
    }
223
224
0
  return newp;
225
0
}
226
227
struct Dwarf_CU *
228
internal_function
229
__libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool v4_debug_types)
230
0
{
231
0
  void **tree = v4_debug_types ? &dbg->tu_tree : &dbg->cu_tree;
232
0
  Dwarf_Off *next_offset
233
0
    = v4_debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
234
235
  /* Maybe we already know that CU.  */
236
0
  struct Dwarf_CU fake = { .start = start, .end = 0 };
237
0
  struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
238
0
  if (found != NULL)
239
0
    return *found;
240
241
0
  if (start < *next_offset)
242
0
    {
243
0
      __libdw_seterrno (DWARF_E_INVALID_DWARF);
244
0
      return NULL;
245
0
    }
246
247
  /* No.  Then read more CUs.  */
248
0
  while (1)
249
0
    {
250
0
      struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, v4_debug_types);
251
0
      if (newp == NULL)
252
0
  return NULL;
253
254
      /* Is this the one we are looking for?  */
255
0
      if (start < *next_offset || start == newp->start)
256
0
  return newp;
257
0
    }
258
  /* NOTREACHED */
259
0
}
260
261
struct Dwarf_CU *
262
internal_function
263
__libdw_findcu_addr (Dwarf *dbg, void *addr)
264
0
{
265
0
  void **tree;
266
0
  Dwarf_Off start;
267
0
  if (addr >= dbg->sectiondata[IDX_debug_info]->d_buf
268
0
      && addr < (dbg->sectiondata[IDX_debug_info]->d_buf
269
0
     + dbg->sectiondata[IDX_debug_info]->d_size))
270
0
    {
271
0
      tree = &dbg->cu_tree;
272
0
      start = addr - dbg->sectiondata[IDX_debug_info]->d_buf;
273
0
    }
274
0
  else if (dbg->sectiondata[IDX_debug_types] != NULL
275
0
     && addr >= dbg->sectiondata[IDX_debug_types]->d_buf
276
0
     && addr < (dbg->sectiondata[IDX_debug_types]->d_buf
277
0
          + dbg->sectiondata[IDX_debug_types]->d_size))
278
0
    {
279
0
      tree = &dbg->tu_tree;
280
0
      start = addr - dbg->sectiondata[IDX_debug_types]->d_buf;
281
0
    }
282
0
  else
283
0
    return NULL;
284
285
0
  struct Dwarf_CU fake = { .start = start, .end = 0 };
286
0
  struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
287
288
0
  if (found != NULL)
289
0
    return *found;
290
291
0
  return NULL;
292
0
}
293
294
Dwarf *
295
internal_function
296
__libdw_find_split_dbg_addr (Dwarf *dbg, void *addr)
297
0
{
298
  /* XXX Assumes split DWARF only has CUs in main IDX_debug_info.  */
299
0
  Elf_Data fake_data = { .d_buf = addr, .d_size = 0 };
300
0
  Dwarf fake = { .sectiondata[IDX_debug_info] = &fake_data };
301
0
  Dwarf **found = tfind (&fake, &dbg->split_tree, __libdw_finddbg_cb);
302
303
0
  if (found != NULL)
304
0
    return *found;
305
306
0
  return NULL;
307
0
}