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
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 /* Create an entry for this CU. */
147 struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
148
149 newp->dbg = dbg;
150 newp->sec_idx = sec_idx;
151 newp->start = oldoff;
152 newp->end = *offsetp;
153 newp->address_size = address_size;
154 newp->offset_size = offset_size;
155 newp->version = version;
156 newp->unit_id8 = unit_id8;
157 newp->subdie_offset = subdie_offset;
158 Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
159 newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
160 newp->files = NULL;
161 newp->lines = NULL;
162 newp->locs = NULL;
163 newp->split = (Dwarf_CU *) -1;
164 newp->base_address = (Dwarf_Addr) -1;
165 newp->addr_base = (Dwarf_Off) -1;
166 newp->str_off_base = (Dwarf_Off) -1;
167 newp->ranges_base = (Dwarf_Off) -1;
168 newp->locs_base = (Dwarf_Off) -1;
169
170 newp->startp = data->d_buf + newp->start;
171 newp->endp = data->d_buf + newp->end;
172
173 /* v4 debug type units have version == 4 and unit_type == DW_UT_type. */
174 if (debug_types)
175 newp->unit_type = DW_UT_type;
176 else if (version < 5)
177 {
178 /* This is a reasonable guess (and needed to get the CUDIE). */
179 newp->unit_type = DW_UT_compile;
180
181 /* But set it correctly from the actual CUDIE tag. */
182 Dwarf_Die cudie = CUDIE (newp);
183 int tag = INTUSE(dwarf_tag) (&cudie);
184 if (tag == DW_TAG_compile_unit)
185 {
186 Dwarf_Attribute dwo_id;
187 if (INTUSE(dwarf_attr) (&cudie, DW_AT_GNU_dwo_id, &dwo_id) != NULL)
188 {
189 Dwarf_Word id8;
190 if (INTUSE(dwarf_formudata) (&dwo_id, &id8) == 0)
191 {
192 if (INTUSE(dwarf_haschildren) (&cudie) == 0
193 && INTUSE(dwarf_hasattr) (&cudie,
194 DW_AT_GNU_dwo_name) == 1)
195 newp->unit_type = DW_UT_skeleton;
196 else
197 newp->unit_type = DW_UT_split_compile;
198
199 newp->unit_id8 = id8;
200 }
201 }
202 }
203 else if (tag == DW_TAG_partial_unit)
204 newp->unit_type = DW_UT_partial;
205 else if (tag == DW_TAG_type_unit)
206 newp->unit_type = DW_UT_type;
207 }
208 else
209 newp->unit_type = unit_type;
210
211 /* Store a reference to any type unit ids in the hash for quick lookup. */
212 if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)
213 Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, unit_id8, newp);
214
215 /* Add the new entry to the search tree. */
216 if (tsearch (newp, tree, findcu_cb) == NULL)
217 {
218 /* Something went wrong. Undo the operation. */
219 *offsetp = oldoff;
220 __libdw_seterrno (DWARF_E_NOMEM);
221 return NULL;
222 }
223
224 return newp;
225 }
226
227 struct Dwarf_CU *
228 internal_function
__libdw_findcu(Dwarf * dbg,Dwarf_Off start,bool v4_debug_types)229 __libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool v4_debug_types)
230 {
231 void **tree = v4_debug_types ? &dbg->tu_tree : &dbg->cu_tree;
232 Dwarf_Off *next_offset
233 = v4_debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
234
235 /* Maybe we already know that CU. */
236 struct Dwarf_CU fake = { .start = start, .end = 0 };
237 struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
238 if (found != NULL)
239 return *found;
240
241 if (start < *next_offset)
242 {
243 __libdw_seterrno (DWARF_E_INVALID_DWARF);
244 return NULL;
245 }
246
247 /* No. Then read more CUs. */
248 while (1)
249 {
250 struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, v4_debug_types);
251 if (newp == NULL)
252 return NULL;
253
254 /* Is this the one we are looking for? */
255 if (start < *next_offset || start == newp->start)
256 return newp;
257 }
258 /* NOTREACHED */
259 }
260
261 struct Dwarf_CU *
262 internal_function
__libdw_findcu_addr(Dwarf * dbg,void * addr)263 __libdw_findcu_addr (Dwarf *dbg, void *addr)
264 {
265 void **tree;
266 Dwarf_Off start;
267 if (addr >= dbg->sectiondata[IDX_debug_info]->d_buf
268 && addr < (dbg->sectiondata[IDX_debug_info]->d_buf
269 + dbg->sectiondata[IDX_debug_info]->d_size))
270 {
271 tree = &dbg->cu_tree;
272 start = addr - dbg->sectiondata[IDX_debug_info]->d_buf;
273 }
274 else if (dbg->sectiondata[IDX_debug_types] != NULL
275 && addr >= dbg->sectiondata[IDX_debug_types]->d_buf
276 && addr < (dbg->sectiondata[IDX_debug_types]->d_buf
277 + dbg->sectiondata[IDX_debug_types]->d_size))
278 {
279 tree = &dbg->tu_tree;
280 start = addr - dbg->sectiondata[IDX_debug_types]->d_buf;
281 }
282 else
283 return NULL;
284
285 struct Dwarf_CU fake = { .start = start, .end = 0 };
286 struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
287
288 if (found != NULL)
289 return *found;
290
291 return NULL;
292 }
293
294 Dwarf *
295 internal_function
__libdw_find_split_dbg_addr(Dwarf * dbg,void * addr)296 __libdw_find_split_dbg_addr (Dwarf *dbg, void *addr)
297 {
298 /* XXX Assumes split DWARF only has CUs in main IDX_debug_info. */
299 Elf_Data fake_data = { .d_buf = addr, .d_size = 0 };
300 Dwarf fake = { .sectiondata[IDX_debug_info] = &fake_data };
301 Dwarf **found = tfind (&fake, &dbg->split_tree, __libdw_finddbg_cb);
302
303 if (found != NULL)
304 return *found;
305
306 return NULL;
307 }
308