Branch data Line data Source code
1 : : /* Keeping track of DWARF compilation units in libdwfl.
2 : : Copyright (C) 2005-2010, 2015, 2016, 2017 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : :
5 : : This file is free software; you can redistribute it and/or modify
6 : : it under the terms of either
7 : :
8 : : * the GNU Lesser General Public License as published by the Free
9 : : Software Foundation; either version 3 of the License, or (at
10 : : your option) any later version
11 : :
12 : : or
13 : :
14 : : * the GNU General Public License as published by the Free
15 : : Software Foundation; either version 2 of the License, or (at
16 : : your option) any later version
17 : :
18 : : or both in parallel, as here.
19 : :
20 : : elfutils is distributed in the hope that it will be useful, but
21 : : WITHOUT ANY WARRANTY; without even the implied warranty of
22 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 : : General Public License for more details.
24 : :
25 : : You should have received copies of the GNU General Public License and
26 : : the GNU Lesser General Public License along with this program. If
27 : : not, see <http://www.gnu.org/licenses/>. */
28 : :
29 : : #ifdef HAVE_CONFIG_H
30 : : # include <config.h>
31 : : #endif
32 : :
33 : : #include "eu-search.h"
34 : : #include "libdwflP.h"
35 : : #include "libdwP.h"
36 : : #include "memory-access.h"
37 : :
38 : :
39 : : static inline Dwarf_Arange *
40 : 1052 : dwar (Dwfl_Module *mod, unsigned int idx)
41 : : {
42 : 1052 : return &mod->dw->dieranges->info[mod->aranges[idx].arange];
43 : : }
44 : :
45 : :
46 : : static Dwfl_Error
47 : 900 : addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
48 : : {
49 [ + + ]: 900 : if (mod->aranges == NULL)
50 : : {
51 : 124 : struct dwfl_arange *aranges = NULL;
52 : 124 : Dwarf_Aranges *dwaranges = NULL;
53 : 124 : size_t naranges;
54 [ + - ]: 124 : if (__libdw_getdieranges (mod->dw, &dwaranges, &naranges) != 0)
55 : 0 : return DWFL_E_LIBDW;
56 : :
57 : : /* If the module has no aranges (when no code is included) we
58 : : allocate nothing. */
59 [ + - ]: 124 : if (naranges != 0)
60 : : {
61 : 124 : aranges = malloc (naranges * sizeof *aranges);
62 [ + - ]: 124 : if (unlikely (aranges == NULL))
63 : : return DWFL_E_NOMEM;
64 : :
65 : : /* libdw has sorted its list by address, which is how we want it.
66 : : But the sorted list is full of not-quite-contiguous runs pointing
67 : : to the same CU. We don't care about the little gaps inside the
68 : : module, we'll consider them part of the surrounding CU anyway.
69 : : Collect our own array with just one record for each run of ranges
70 : : pointing to one CU. */
71 : :
72 : 124 : naranges = 0;
73 : 124 : Dwarf_Off lastcu = 0;
74 [ + + ]: 292 : for (size_t i = 0; i < dwaranges->naranges; ++i)
75 [ + + + + ]: 168 : if (i == 0 || dwaranges->info[i].offset != lastcu)
76 : : {
77 : 152 : aranges[naranges].arange = i;
78 : 152 : aranges[naranges].cu = NULL;
79 : 152 : ++naranges;
80 : 152 : lastcu = dwaranges->info[i].offset;
81 : : }
82 : : }
83 : :
84 : : /* Store the final array, which is probably much smaller than before. */
85 : 124 : mod->naranges = naranges;
86 [ + - ]: 124 : if (naranges > 0)
87 : 124 : mod->aranges = (realloc (aranges, naranges * sizeof aranges[0])
88 [ - + ]: 124 : ?: aranges);
89 [ # # ]: 0 : else if (aranges != NULL)
90 : 0 : free (aranges);
91 : 124 : mod->lazycu += naranges;
92 : : }
93 : :
94 : : /* The address must be inside the module to begin with. */
95 : 900 : addr = dwfl_deadjust_dwarf_addr (mod, addr);
96 : :
97 : : /* The ranges are sorted by address, so we can use binary search. */
98 : 900 : size_t l = 0, u = mod->naranges;
99 [ + - ]: 976 : while (l < u)
100 : : {
101 : 976 : size_t idx = (l + u) / 2;
102 : 976 : Dwarf_Addr start = dwar (mod, idx)->addr;
103 [ - + ]: 976 : if (addr < start)
104 : : {
105 : 0 : u = idx;
106 : 0 : continue;
107 : : }
108 [ + + ]: 976 : else if (addr > start)
109 : : {
110 [ + + ]: 740 : if (idx + 1 < mod->naranges)
111 : : {
112 [ + - ]: 76 : if (addr >= dwar (mod, idx + 1)->addr)
113 : : {
114 : 76 : l = idx + 1;
115 : 76 : continue;
116 : : }
117 : : }
118 : : else
119 : : {
120 : : /* It might be in the last range. */
121 : 664 : const Dwarf_Arange *last
122 : 664 : = &mod->dw->dieranges->info[mod->dw->dieranges->naranges - 1];
123 [ + + ]: 664 : if (addr > last->addr + last->length)
124 : : break;
125 : : }
126 : : }
127 : :
128 : 888 : *arange = &mod->aranges[idx];
129 : 888 : return DWFL_E_NOERROR;
130 : : }
131 : :
132 : : return DWFL_E_ADDR_OUTOFRANGE;
133 : : }
134 : :
135 : :
136 : : static void
137 : 0 : nofree (void *arg)
138 : : {
139 : 0 : struct dwfl_cu *cu = arg;
140 [ # # ]: 0 : if (cu == (void *) -1l)
141 : : return;
142 : :
143 [ # # ]: 0 : assert (cu->mod->lazycu == 0);
144 : : }
145 : :
146 : : /* One reason fewer to keep the lazy lookup table for CUs. */
147 : : static inline void
148 : 130 : less_lazy (Dwfl_Module *mod)
149 : : {
150 [ - + ]: 130 : if (--mod->lazycu > 0)
151 : : return;
152 : :
153 : : /* We know about all the CUs now, we don't need this table. */
154 : 0 : eu_tdestroy (&mod->lazy_cu_tree, nofree);
155 : : }
156 : :
157 : : static inline Dwarf_Off
158 : 227456 : cudie_offset (const struct dwfl_cu *cu)
159 : : {
160 : 227456 : return __libdw_first_die_off_from_cu (cu->die.cu);
161 : : }
162 : :
163 : : static int
164 : 227456 : compare_cukey (const void *a, const void *b)
165 : : {
166 : 227456 : Dwarf_Off a_off = cudie_offset (a);
167 : 227456 : Dwarf_Off b_off = cudie_offset (b);
168 [ + + ]: 227456 : return (a_off < b_off) ? -1 : ((a_off > b_off) ? 1 : 0);
169 : : }
170 : :
171 : : /* Intern the CU if necessary. */
172 : : static Dwfl_Error
173 : 19640 : intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
174 : : {
175 [ - + ]: 19640 : if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
176 : : {
177 [ # # ]: 0 : if (likely (mod->lazycu == 1))
178 : : {
179 : : /* This is the EOF marker. Now we have interned all the CUs.
180 : : One increment in MOD->lazycu counts not having hit EOF yet. */
181 : 0 : *result = (void *) -1;
182 : 0 : less_lazy (mod);
183 : 0 : return DWFL_E_NOERROR;
184 : : }
185 : : else
186 : : {
187 : : /* Unexpected EOF, most likely a bogus aranges. */
188 : : return (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
189 : : }
190 : : }
191 : :
192 : : /* Make sure the cuoff points to a real DIE. */
193 : 19640 : Dwarf_Die cudie;
194 : 19640 : Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cudie);
195 [ + - ]: 19640 : if (die == NULL)
196 : : return DWFL_E_LIBDW;
197 : :
198 : 19640 : struct dwfl_cu key;
199 : 19640 : key.die.cu = die->cu;
200 : 19640 : struct dwfl_cu **found = eu_tsearch (&key, &mod->lazy_cu_tree,
201 : : &compare_cukey);
202 [ + - ]: 19640 : if (unlikely (found == NULL))
203 : : return DWFL_E_NOMEM;
204 : :
205 [ + + - + ]: 19640 : if (*found == &key || *found == NULL)
206 : : {
207 : : /* This is a new entry, meaning we haven't looked at this CU. */
208 : :
209 : 19638 : *found = NULL;
210 : :
211 : 19638 : struct dwfl_cu *cu = malloc (sizeof *cu);
212 [ + - ]: 19638 : if (unlikely (cu == NULL))
213 : : return DWFL_E_NOMEM;
214 : :
215 : 19638 : cu->mod = mod;
216 : 19638 : cu->next = NULL;
217 : 19638 : cu->lines = NULL;
218 : 19638 : cu->die = cudie;
219 : :
220 : 19638 : struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
221 : : * sizeof (mod->cu[0])));
222 [ - + ]: 19638 : if (newvec == NULL)
223 : : {
224 : 0 : free (cu);
225 : 0 : return DWFL_E_NOMEM;
226 : : }
227 : 19638 : mod->cu = newvec;
228 : :
229 : 19638 : mod->cu[mod->ncu++] = cu;
230 [ + + ]: 19638 : if (cu->die.cu->start == 0)
231 : 288 : mod->first_cu = cu;
232 : :
233 : 19638 : *found = cu;
234 : : }
235 : :
236 : 19640 : *result = *found;
237 : 19640 : return DWFL_E_NOERROR;
238 : : }
239 : :
240 : :
241 : : /* Traverse all the CUs in the module. */
242 : :
243 : : Dwfl_Error
244 : : internal_function
245 : 19728 : __libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu,
246 : : struct dwfl_cu **cu)
247 : : {
248 : 19728 : Dwarf_Off cuoff;
249 : 19728 : struct dwfl_cu **nextp;
250 : :
251 [ + + ]: 19728 : if (lastcu == NULL)
252 : : {
253 : : /* Start the traversal. */
254 : 196 : cuoff = 0;
255 : 196 : nextp = &mod->first_cu;
256 : : }
257 : : else
258 : : {
259 : : /* Continue following LASTCU. */
260 : 19532 : cuoff = lastcu->die.cu->end;
261 : 19532 : nextp = &lastcu->next;
262 : : }
263 : :
264 [ + + ]: 19728 : if (*nextp == NULL)
265 : : {
266 : 19706 : size_t cuhdrsz;
267 : 19706 : Dwarf_Off nextoff;
268 : 19706 : int end = INTUSE(dwarf_nextcu) (mod->dw, cuoff, &nextoff, &cuhdrsz,
269 : : NULL, NULL, NULL);
270 [ + - ]: 19706 : if (end < 0)
271 : 196 : return DWFL_E_LIBDW;
272 [ + + ]: 19706 : if (end > 0)
273 : : {
274 : 196 : *cu = NULL;
275 : 196 : return DWFL_E_NOERROR;
276 : : }
277 : :
278 : 19510 : Dwfl_Error result = intern_cu (mod, cuoff + cuhdrsz, nextp);
279 [ + - ]: 19510 : if (result != DWFL_E_NOERROR)
280 : : return result;
281 : :
282 [ + - ]: 19510 : if (*nextp != (void *) -1
283 [ + - - + ]: 19510 : && (*nextp)->next == NULL && nextoff == (Dwarf_Off) -1l)
284 : 0 : (*nextp)->next = (void *) -1l;
285 : : }
286 : :
287 [ + - ]: 19532 : *cu = *nextp == (void *) -1l ? NULL : *nextp;
288 : 19532 : return DWFL_E_NOERROR;
289 : : }
290 : :
291 : :
292 : : /* Intern the CU arange points to, if necessary. */
293 : :
294 : : static Dwfl_Error
295 : 888 : arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu)
296 : : {
297 [ + + ]: 888 : if (arange->cu == NULL)
298 : : {
299 : 130 : const Dwarf_Arange *dwarange = &mod->dw->dieranges->info[arange->arange];
300 : 130 : Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu);
301 [ + - ]: 130 : if (result != DWFL_E_NOERROR)
302 : : return result;
303 [ - + ]: 130 : assert (arange->cu != NULL && arange->cu != (void *) -1l);
304 : 130 : less_lazy (mod); /* Each arange with null ->cu counts once. */
305 : : }
306 : :
307 : 888 : *cu = arange->cu;
308 : 888 : return DWFL_E_NOERROR;
309 : : }
310 : :
311 : : Dwfl_Error
312 : : internal_function
313 : 900 : __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_cu **cu)
314 : : {
315 : 900 : struct dwfl_arange *arange;
316 [ + + ]: 900 : return addrarange (mod, addr, &arange) ?: arangecu (mod, arange, cu);
317 : : }
|