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