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 : 14712850 : findcu_cb (const void *arg1, const void *arg2)
40 : : {
41 : 14712850 : struct Dwarf_CU *cu1 = (struct Dwarf_CU *) arg1;
42 : 14712850 : 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 [ + + ]: 14712850 : if (cu1->end == 0)
47 : : {
48 [ + + ]: 13843542 : if (cu1->start < cu2->start)
49 : : return -1;
50 [ + + ]: 13816376 : if (cu1->start >= cu2->end)
51 : 12488430 : return 1;
52 : : }
53 : : else
54 : : {
55 [ - + ]: 869308 : 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 [ + - ]: 8 : if (dbg2_start >= dbg1_start + dbg1_size)
92 : 8 : return -1;
93 : : }
94 : :
95 : : return 0;
96 : : }
97 : :
98 : : struct Dwarf_CU *
99 : : internal_function
100 : 79036 : __libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
101 : : {
102 : 158072 : Dwarf_Off *const offsetp
103 [ + + ]: 79036 : = debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
104 : 79036 : void **tree = debug_types ? &dbg->tu_tree : &dbg->cu_tree;
105 : :
106 : 79036 : Dwarf_Off oldoff = *offsetp;
107 : 79036 : uint16_t version;
108 : 79036 : uint8_t unit_type;
109 : 79036 : uint8_t address_size;
110 : 79036 : uint8_t offset_size;
111 : 79036 : Dwarf_Off abbrev_offset;
112 : 79036 : uint64_t unit_id8;
113 : 79036 : Dwarf_Off subdie_offset;
114 : :
115 [ + + ]: 79036 : 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 [ + - + - ]: 79026 : if (unlikely (version < 2) || unlikely (version > 5)
125 [ + + - + ]: 79026 : || (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 [ - + ]: 79026 : if (unlikely (address_size != 4 && address_size != 8))
136 : 0 : address_size = 8;
137 [ - + ]: 79026 : if (unlikely (offset_size != 4 && offset_size != 8))
138 : 0 : offset_size = 8;
139 : :
140 : : /* Invalid or truncated debug section data? */
141 : 79026 : size_t sec_idx = debug_types ? IDX_debug_types : IDX_debug_info;
142 : 79026 : Elf_Data *data = dbg->sectiondata[sec_idx];
143 [ - + ]: 79026 : if (unlikely (*offsetp > data->d_size))
144 : 0 : *offsetp = data->d_size;
145 : :
146 : 79026 : uint32_t dwp_row;
147 : 79026 : Dwarf_Off dwp_abbrev_offset;
148 [ - + ]: 79026 : 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 : 79026 : abbrev_offset += dwp_abbrev_offset;
152 : :
153 : : /* Create an entry for this CU. */
154 [ + + ]: 79026 : struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
155 : :
156 : 79026 : newp->dbg = dbg;
157 : 79026 : newp->sec_idx = sec_idx;
158 : 79026 : newp->start = oldoff;
159 : 79026 : newp->end = *offsetp;
160 : 79026 : newp->dwp_row = dwp_row;
161 : 79026 : newp->address_size = address_size;
162 : 79026 : newp->offset_size = offset_size;
163 : 79026 : newp->version = version;
164 : 79026 : newp->unit_id8 = unit_id8;
165 : 79026 : newp->subdie_offset = subdie_offset;
166 : 79026 : Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
167 : 79026 : newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
168 : 79026 : newp->files = NULL;
169 : 79026 : newp->lines = NULL;
170 : 79026 : newp->locs = NULL;
171 : 79026 : newp->split = (Dwarf_CU *) -1;
172 : 79026 : newp->base_address = (Dwarf_Addr) -1;
173 : 79026 : newp->addr_base = (Dwarf_Off) -1;
174 : 79026 : newp->str_off_base = (Dwarf_Off) -1;
175 : 79026 : newp->ranges_base = (Dwarf_Off) -1;
176 : 79026 : newp->locs_base = (Dwarf_Off) -1;
177 : :
178 : 79026 : newp->startp = data->d_buf + newp->start;
179 : 79026 : newp->endp = data->d_buf + newp->end;
180 : :
181 : : /* v4 debug type units have version == 4 and unit_type == DW_UT_type. */
182 [ + + ]: 79026 : if (debug_types)
183 : 44 : newp->unit_type = DW_UT_type;
184 [ + + ]: 78982 : else if (version < 5)
185 : : {
186 : : /* This is a reasonable guess (and needed to get the CUDIE). */
187 : 1258 : newp->unit_type = DW_UT_compile;
188 : :
189 : : /* But set it correctly from the actual CUDIE tag. */
190 : 1258 : Dwarf_Die cudie = CUDIE (newp);
191 : 1258 : int tag = INTUSE(dwarf_tag) (&cudie);
192 [ + + ]: 1258 : if (tag == DW_TAG_compile_unit)
193 : : {
194 : 1208 : Dwarf_Attribute dwo_id;
195 [ + + ]: 1208 : if (INTUSE(dwarf_attr) (&cudie, DW_AT_GNU_dwo_id, &dwo_id) != NULL)
196 : : {
197 : 154 : Dwarf_Word id8;
198 [ + - ]: 154 : if (INTUSE(dwarf_formudata) (&dwo_id, &id8) == 0)
199 : : {
200 [ + + ]: 154 : if (INTUSE(dwarf_haschildren) (&cudie) == 0
201 [ + - ]: 68 : && INTUSE(dwarf_hasattr) (&cudie,
202 : : DW_AT_GNU_dwo_name) == 1)
203 : 68 : newp->unit_type = DW_UT_skeleton;
204 : : else
205 : 86 : newp->unit_type = DW_UT_split_compile;
206 : :
207 : 154 : newp->unit_id8 = id8;
208 : : }
209 : : }
210 : : }
211 [ + + ]: 50 : else if (tag == DW_TAG_partial_unit)
212 : 46 : newp->unit_type = DW_UT_partial;
213 [ - + ]: 4 : else if (tag == DW_TAG_type_unit)
214 : 0 : newp->unit_type = DW_UT_type;
215 : : }
216 : : else
217 : 77724 : newp->unit_type = unit_type;
218 : :
219 : : /* Store a reference to any type unit ids in the hash for quick lookup. */
220 [ + + ]: 79026 : if (unit_type == DW_UT_type || unit_type == DW_UT_split_type)
221 : 50 : Dwarf_Sig8_Hash_insert (&dbg->sig8_hash, unit_id8, newp);
222 : :
223 : : /* Add the new entry to the search tree. */
224 [ - + ]: 79026 : if (tsearch (newp, tree, findcu_cb) == NULL)
225 : : {
226 : : /* Something went wrong. Undo the operation. */
227 : 0 : *offsetp = oldoff;
228 : 0 : __libdw_seterrno (DWARF_E_NOMEM);
229 : 0 : return NULL;
230 : : }
231 : :
232 : : return newp;
233 : : }
234 : :
235 : : struct Dwarf_CU *
236 : : internal_function
237 : 108152 : __libdw_findcu (Dwarf *dbg, Dwarf_Off start, bool v4_debug_types)
238 : : {
239 [ + + ]: 108152 : void **tree = v4_debug_types ? &dbg->tu_tree : &dbg->cu_tree;
240 : 216304 : Dwarf_Off *next_offset
241 : 108152 : = v4_debug_types ? &dbg->next_tu_offset : &dbg->next_cu_offset;
242 : :
243 : : /* Maybe we already know that CU. */
244 : 108152 : struct Dwarf_CU fake = { .start = start, .end = 0 };
245 : 108152 : struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
246 [ + + ]: 108152 : if (found != NULL)
247 : 29120 : return *found;
248 : :
249 [ + + ]: 79032 : if (start < *next_offset)
250 : : {
251 : 10 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
252 : 10 : return NULL;
253 : : }
254 : :
255 : : /* No. Then read more CUs. */
256 : 79032 : while (1)
257 : : {
258 : 79032 : struct Dwarf_CU *newp = __libdw_intern_next_unit (dbg, v4_debug_types);
259 [ + + ]: 79032 : if (newp == NULL)
260 : : return NULL;
261 : :
262 : : /* Is this the one we are looking for? */
263 [ + + + - ]: 79024 : if (start < *next_offset || start == newp->start)
264 : 79014 : return newp;
265 : : }
266 : : /* NOTREACHED */
267 : : }
268 : :
269 : : struct Dwarf_CU *
270 : : internal_function
271 : 1299152 : __libdw_findcu_addr (Dwarf *dbg, void *addr)
272 : : {
273 : 1299152 : void **tree;
274 : 1299152 : Dwarf_Off start;
275 [ + + ]: 1299152 : if (addr >= dbg->sectiondata[IDX_debug_info]->d_buf
276 : 1298826 : && addr < (dbg->sectiondata[IDX_debug_info]->d_buf
277 [ + + ]: 1298826 : + dbg->sectiondata[IDX_debug_info]->d_size))
278 : : {
279 : 1298794 : tree = &dbg->cu_tree;
280 : 1298794 : start = addr - dbg->sectiondata[IDX_debug_info]->d_buf;
281 : : }
282 [ + + ]: 358 : else if (dbg->sectiondata[IDX_debug_types] != NULL
283 [ + - ]: 32 : && addr >= dbg->sectiondata[IDX_debug_types]->d_buf
284 : 32 : && addr < (dbg->sectiondata[IDX_debug_types]->d_buf
285 [ + - ]: 32 : + dbg->sectiondata[IDX_debug_types]->d_size))
286 : : {
287 : 32 : tree = &dbg->tu_tree;
288 : 32 : start = addr - dbg->sectiondata[IDX_debug_types]->d_buf;
289 : : }
290 : : else
291 : : return NULL;
292 : :
293 : 1298826 : struct Dwarf_CU fake = { .start = start, .end = 0 };
294 : 1298826 : struct Dwarf_CU **found = tfind (&fake, tree, findcu_cb);
295 : :
296 [ - + ]: 1298826 : if (found != NULL)
297 : 1298826 : return *found;
298 : :
299 : : return NULL;
300 : : }
301 : :
302 : : Dwarf *
303 : : internal_function
304 : 296 : __libdw_find_split_dbg_addr (Dwarf *dbg, void *addr)
305 : : {
306 : : /* XXX Assumes split DWARF only has CUs in main IDX_debug_info. */
307 : 296 : Elf_Data fake_data = { .d_buf = addr, .d_size = 0 };
308 : 296 : Dwarf fake = { .sectiondata[IDX_debug_info] = &fake_data };
309 : 296 : Dwarf **found = tfind (&fake, &dbg->split_tree, __libdw_finddbg_cb);
310 : :
311 [ + - ]: 296 : if (found != NULL)
312 : 296 : return *found;
313 : :
314 : : return NULL;
315 : : }
|