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