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