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 <[email protected]>, 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
findcu_cb(const void * arg1,const void * arg2)39 findcu_cb (const void *arg1, const void *arg2)
40 {
41 struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1;
42 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 if (cu1->end == 0)
47 {
48 if (cu1->start < cu2->start)
49 return -1;
50 if (cu1->start >= cu2->end)
51 return 1;
52 }
53 else
54 {
55 if (cu2->start < cu1->start)
56 return 1;
57 if (cu2->start >= cu1->end)
58 return -1;
59 }
60
61 return 0;
62 }
63
64 int
__libdw_finddbg_cb(const void * arg1,const void * arg2)65 __libdw_finddbg_cb (const void *arg1, const void *arg2)
66 {
67 Dwarf *dbg1 = (Dwarf *) arg1;
68 Dwarf *dbg2 = (Dwarf *) arg2;
69
70 Elf_Data *dbg1_data = dbg1->sectiondata[IDX_debug_info];
71 unsigned char *dbg1_start = dbg1_data->d_buf;
72 size_t dbg1_size = dbg1_data->d_size;
73
74 Elf_Data *dbg2_data = dbg2->sectiondata[IDX_debug_info];
75 unsigned char *dbg2_start = dbg2_data->d_buf;
76 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 if (dbg1_size == 0)
81 {
82 if (dbg1_start < dbg2_start)
83 return -1;
84 if (dbg1_start >= dbg2_start + dbg2_size)
85 return 1;
86 }
87 else
88 {
89 if (dbg2_start < dbg1_start)
90 return 1;
91 if (dbg2_start >= dbg1_start + dbg1_size)
92 return -1;
93 }
94
95 return 0;
96 }
97
98 struct Dwarf_CU *
99 internal_function
__libdw_intern_next_unit(Dwarf * dbg,bool debug_types)100 __libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
101 {
102 Dwarf_Off *const offsetp
103 = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
104 void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
105
106 Dwarf_Off oldoff = *offsetp;
107 uint16_t version;
108 uint8_t unit_type;
109 uint8_t address_size;
110 uint8_t offset_size;
111 Dwarf_Off abbrev_offset;
112 uint64_t unit_id8;
113 Dwarf_Off subdie_offset;
114
115 if (__libdw_next_unit (dbg, debug_types, oldoff, offsetp, NULL,
116 &version, &unit_type, &abbrev_offset,
117 &address_size, &offset_size,
118 &unit_id8, &subdie_offset) != 0)
119 /* No more entries. */
120 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 if (unlikely (version < 2) || unlikely (version > 5)
125 || (debug_types && unlikely (version != 4)))
126 {
127 __libdw_seterrno (DWARF_E_VERSION);
128 return NULL;
129 }
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 if (unlikely (address_size != 4 && address_size != 8))
136 address_size = 8;
137 if (unlikely (offset_size != 4 && offset_size != 8))
138 offset_size = 8;
139
140 /* Invalid or truncated debug section data? */
141 size_t sec_idx = debug_types ? IDX_debug_types : IDX_debug_info;
142 Elf_Data *data = dbg->sectiondata[sec_idx];
143 if (unlikely (*offsetp > data->d_size))
144 *offsetp = data->d_size;
145
146 uint32_t dwp_row;
147 Dwarf_Off dwp_abbrev_offset;
148 if (__libdw_dwp_find_unit (dbg, debug_types, oldoff, version, unit_type,
149 unit_id8, &dwp_row, &dwp_abbrev_offset) != 0)
150 return NULL;
151 abbrev_offset += dwp_abbrev_offset;
152
153 /* Create an entry for this CU. */
154 struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
155
156 newp->dbg = dbg;
157 newp->sec_idx = sec_idx;
158 newp->start = oldoff;
159 newp->end = *offsetp;
160 newp->dwp_row = dwp_row;
161 newp->address_size = address_size;
162 newp->offset_size = offset_size;
163 newp->version = version;
164 newp->unit_id8 = unit_id8;
165 newp->subdie_offset = subdie_offset;
166 Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
167 newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
168 newp->files = NULL;
169 newp->lines = NULL;
170 newp->locs = NULL;
171 newp->split = (Dwarf_CU *) -1;
172 newp->base_address = (Dwarf_Addr) -1;
173 newp->addr_base = (Dwarf_Off) -1;
174 newp->str_off_base = (Dwarf_Off) -1;
175 newp->ranges_base = (Dwarf_Off) -1;
176 newp->locs_base = (Dwarf_Off) -1;
177
178 newp->startp = data->d_buf + newp->start;
179 newp->endp = data->d_buf + newp->end;
180
181 /* v4 debug type units have version == 4 and unit_type == DW_UT_type. */
182 if (debug_types)
183 newp->unit_type = DW_UT_type;
184 else if (version < 5)
185 {
186 /* This is a reasonable guess (and needed to get the CUDIE). */
187 newp->unit_type = DW_UT_compile;
188
189 /* But set it correctly from the actual CUDIE tag. */
190 Dwarf_Die cudie = CUDIE (newp);
191 int tag = INTUSE(dwarf_tag) (&cudie);
192 if (tag == DW_TAG_compile_unit)
193 {
194 Dwarf_Attribute dwo_id;
195 if (INTUSE(dwarf_attr) (&cudie, DW_AT_GNU_dwo_id, &dwo_id) != NULL)
196 {
197 Dwarf_Word id8;
198 if (INTUSE(dwarf_formudata) (&dwo_id, &id8) == 0)
199 {
200 if (INTUSE(dwarf_haschildren) (&cudie) == 0
201 && INTUSE(dwarf_hasattr) (&cudie,
202 DW_AT_GNU_dwo_name) == 1)
203 newp->unit_type = DW_UT_skeleton;
204 else
205 newp->unit_type = DW_UT_split_compile;
206
207 newp->unit_id8 = id8;
208 }
209 }
210 }
211 else if (tag == DW_TAG_partial_unit)
212 newp->unit_type = DW_UT_partial;
213 else if (tag == DW_TAG_type_unit)
214 newp->unit_type = DW_UT_type;
215 }
216 else
217 newp->unit_type = unit_type;
218
219 /* Store a reference to any type unit ids in the hash for quick lookup. */
220 if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)
221 Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, unit_id8, newp);
222
223 /* Add the new entry to the search tree. */
224 if (tsearch (newp, tree, findcu_cb) == NULL)
225 {
226 /* Something went wrong. Undo the operation. */
227 *offsetp = oldoff;
228 __libdw_seterrno (DWARF_E_NOMEM);
229 return NULL;
230 }
231
232 return newp;
233 }
234
235 struct Dwarf_CU *
236 internal_function
__libdw_findcu(Dwarf * dbg,Dwarf_Off start,bool v4_debug_types)237 __libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool v4_debug_types)
238 {
239 void **tree = v4_debug_types ? &dbg->tu_tree : &dbg->cu_tree;
240 Dwarf_Off *next_offset
241 = v4_debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
242
243 /* Maybe we already know that CU. */
244 struct Dwarf_CU fake = { .start = start, .end = 0 };
245 struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
246 if (found != NULL)
247 return *found;
248
249 if (start < *next_offset)
250 {
251 __libdw_seterrno (DWARF_E_INVALID_DWARF);
252 return NULL;
253 }
254
255 /* No. Then read more CUs. */
256 while (1)
257 {
258 struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, v4_debug_types);
259 if (newp == NULL)
260 return NULL;
261
262 /* Is this the one we are looking for? */
263 if (start < *next_offset || start == newp->start)
264 return newp;
265 }
266 /* NOTREACHED */
267 }
268
269 struct Dwarf_CU *
270 internal_function
__libdw_findcu_addr(Dwarf * dbg,void * addr)271 __libdw_findcu_addr (Dwarf *dbg, void *addr)
272 {
273 void **tree;
274 Dwarf_Off start;
275 if (addr >= dbg->sectiondata[IDX_debug_info]->d_buf
276 && addr < (dbg->sectiondata[IDX_debug_info]->d_buf
277 + dbg->sectiondata[IDX_debug_info]->d_size))
278 {
279 tree = &dbg->cu_tree;
280 start = addr - dbg->sectiondata[IDX_debug_info]->d_buf;
281 }
282 else if (dbg->sectiondata[IDX_debug_types] != NULL
283 && addr >= dbg->sectiondata[IDX_debug_types]->d_buf
284 && addr < (dbg->sectiondata[IDX_debug_types]->d_buf
285 + dbg->sectiondata[IDX_debug_types]->d_size))
286 {
287 tree = &dbg->tu_tree;
288 start = addr - dbg->sectiondata[IDX_debug_types]->d_buf;
289 }
290 else
291 return NULL;
292
293 struct Dwarf_CU fake = { .start = start, .end = 0 };
294 struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
295
296 if (found != NULL)
297 return *found;
298
299 return NULL;
300 }
301
302 Dwarf *
303 internal_function
__libdw_find_split_dbg_addr(Dwarf * dbg,void * addr)304 __libdw_find_split_dbg_addr (Dwarf *dbg, void *addr)
305 {
306 /* XXX Assumes split DWARF only has CUs in main IDX_debug_info. */
307 Elf_Data fake_data = { .d_buf = addr, .d_size = 0 };
308 Dwarf fake = { .sectiondata[IDX_debug_info] = &fake_data };
309 Dwarf **found = tfind (&fake, &dbg->split_tree, __libdw_finddbg_cb);
310
311 if (found != NULL)
312 return *found;
313
314 return NULL;
315 }
316