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