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 "libdwflP.h"
34 : #include "../libdw/libdwP.h"
35 : #include "../libdw/memory-access.h"
36 : #include <search.h>
37 :
38 :
39 : static inline Dwarf_Arange *
40 0 : dwar (Dwfl_Module *mod, unsigned int idx)
41 : {
42 414 : return &mod->dw->aranges->info[mod->aranges[idx].arange];
43 : }
44 :
45 :
46 : static Dwfl_Error
47 345 : addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
48 : {
49 345 : if (mod->aranges == NULL)
50 : {
51 62 : struct dwfl_arange *aranges = NULL;
52 62 : Dwarf_Aranges *dwaranges = NULL;
53 62 : size_t naranges;
54 62 : if (INTUSE(dwarf_getaranges) (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 62 : if (naranges != 0)
60 : {
61 54 : aranges = malloc (naranges * sizeof *aranges);
62 54 : 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 54 : naranges = 0;
73 54 : Dwarf_Off lastcu = 0;
74 135 : for (size_t i = 0; i < dwaranges->naranges; ++i)
75 81 : if (i == 0 || dwaranges->info[i].offset != lastcu)
76 : {
77 73 : aranges[naranges].arange = i;
78 73 : aranges[naranges].cu = NULL;
79 73 : ++naranges;
80 73 : lastcu = dwaranges->info[i].offset;
81 : }
82 : }
83 :
84 : /* Store the final array, which is probably much smaller than before. */
85 62 : mod->naranges = naranges;
86 62 : if (naranges > 0)
87 54 : mod->aranges = (realloc (aranges, naranges * sizeof aranges[0])
88 54 : ?: aranges);
89 8 : else if (aranges != NULL)
90 0 : free (aranges);
91 62 : mod->lazycu += naranges;
92 : }
93 :
94 : /* The address must be inside the module to begin with. */
95 345 : addr = dwfl_deadjust_dwarf_addr (mod, addr);
96 :
97 : /* The ranges are sorted by address, so we can use binary search. */
98 345 : size_t l = 0, u = mod->naranges;
99 383 : while (l < u)
100 : {
101 375 : size_t idx = (l + u) / 2;
102 750 : Dwarf_Addr start = dwar (mod, idx)->addr;
103 375 : if (addr < start)
104 : {
105 : u = idx;
106 : continue;
107 : }
108 375 : else if (addr > start)
109 : {
110 268 : if (idx + 1 < mod->naranges)
111 : {
112 39 : if (addr >= dwar (mod, idx + 1)->addr)
113 : {
114 : l = idx + 1;
115 : continue;
116 : }
117 : }
118 : else
119 : {
120 : /* It might be in the last range. */
121 458 : const Dwarf_Arange *last
122 229 : = &mod->dw->aranges->info[mod->dw->aranges->naranges - 1];
123 229 : if (addr > last->addr + last->length)
124 : break;
125 : }
126 : }
127 :
128 337 : *arange = &mod->aranges[idx];
129 337 : 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 0 : less_lazy (Dwfl_Module *mod)
149 : {
150 0 : if (--mod->lazycu > 0)
151 0 : return;
152 :
153 : /* We know about all the CUs now, we don't need this table. */
154 0 : tdestroy (mod->lazy_cu_root, nofree);
155 0 : mod->lazy_cu_root = NULL;
156 : }
157 :
158 : static inline Dwarf_Off
159 0 : cudie_offset (const struct dwfl_cu *cu)
160 : {
161 384248 : return __libdw_first_die_off_from_cu (cu->die.cu);
162 : }
163 :
164 : static int
165 96062 : compare_cukey (const void *a, const void *b)
166 : {
167 96062 : Dwarf_Off a_off = cudie_offset (a);
168 96062 : Dwarf_Off b_off = cudie_offset (b);
169 96062 : return (a_off < b_off) ? -1 : ((a_off > b_off) ? 1 : 0);
170 : }
171 :
172 : /* Intern the CU if necessary. */
173 : static Dwfl_Error
174 8665 : intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
175 : {
176 8665 : if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
177 : {
178 0 : if (likely (mod->lazycu == 1))
179 : {
180 : /* This is the EOF marker. Now we have interned all the CUs.
181 : One increment in MOD->lazycu counts not having hit EOF yet. */
182 0 : *result = (void *) -1;
183 0 : less_lazy (mod);
184 0 : return DWFL_E_NOERROR;
185 : }
186 : else
187 : {
188 : /* Unexpected EOF, most likely a bogus aranges. */
189 : return (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
190 : }
191 : }
192 :
193 : /* Make sure the cuoff points to a real DIE. */
194 8665 : Dwarf_Die cudie;
195 8665 : Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cudie);
196 8665 : if (die == NULL)
197 : return DWFL_E_LIBDW;
198 :
199 8665 : struct dwfl_cu key;
200 8665 : key.die.cu = die->cu;
201 8665 : struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
202 8665 : if (unlikely (found == NULL))
203 : return DWFL_E_NOMEM;
204 :
205 8665 : if (*found == &key || *found == NULL)
206 : {
207 : /* This is a new entry, meaning we haven't looked at this CU. */
208 :
209 8664 : *found = NULL;
210 :
211 8664 : struct dwfl_cu *cu = malloc (sizeof *cu);
212 8664 : if (unlikely (cu == NULL))
213 : return DWFL_E_NOMEM;
214 :
215 8664 : cu->mod = mod;
216 8664 : cu->next = NULL;
217 8664 : cu->lines = NULL;
218 8664 : cu->die = cudie;
219 :
220 8664 : struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
221 : * sizeof (mod->cu[0])));
222 8664 : if (newvec == NULL)
223 : {
224 0 : free (cu);
225 0 : return DWFL_E_NOMEM;
226 : }
227 8664 : mod->cu = newvec;
228 :
229 8664 : mod->cu[mod->ncu++] = cu;
230 8664 : if (cu->die.cu->start == 0)
231 129 : mod->first_cu = cu;
232 :
233 8664 : *found = cu;
234 : }
235 :
236 8665 : *result = *found;
237 8665 : return DWFL_E_NOERROR;
238 : }
239 :
240 :
241 : /* Traverse all the CUs in the module. */
242 :
243 : Dwfl_Error
244 : internal_function
245 8722 : __libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu,
246 : struct dwfl_cu **cu)
247 : {
248 8722 : Dwarf_Off cuoff;
249 8722 : struct dwfl_cu **nextp;
250 :
251 8722 : if (lastcu == NULL)
252 : {
253 : /* Start the traversal. */
254 94 : cuoff = 0;
255 94 : nextp = &mod->first_cu;
256 : }
257 : else
258 : {
259 : /* Continue following LASTCU. */
260 8628 : cuoff = lastcu->die.cu->end;
261 8628 : nextp = &lastcu->next;
262 : }
263 :
264 8722 : if (*nextp == NULL)
265 : {
266 8700 : size_t cuhdrsz;
267 8700 : Dwarf_Off nextoff;
268 8700 : int end = INTUSE(dwarf_nextcu) (mod->dw, cuoff, &nextoff, &cuhdrsz,
269 : NULL, NULL, NULL);
270 8700 : if (end < 0)
271 94 : return DWFL_E_LIBDW;
272 8700 : if (end > 0)
273 : {
274 94 : *cu = NULL;
275 94 : return DWFL_E_NOERROR;
276 : }
277 :
278 8606 : Dwfl_Error result = intern_cu (mod, cuoff + cuhdrsz, nextp);
279 8606 : if (result != DWFL_E_NOERROR)
280 : return result;
281 :
282 8606 : if (*nextp != (void *) -1
283 8606 : && (*nextp)->next == NULL && nextoff == (Dwarf_Off) -1l)
284 0 : (*nextp)->next = (void *) -1l;
285 : }
286 :
287 8628 : *cu = *nextp == (void *) -1l ? NULL : *nextp;
288 8628 : return DWFL_E_NOERROR;
289 : }
290 :
291 :
292 : /* Intern the CU arange points to, if necessary. */
293 :
294 : static Dwfl_Error
295 337 : arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu)
296 : {
297 337 : if (arange->cu == NULL)
298 : {
299 59 : const Dwarf_Arange *dwarange = &mod->dw->aranges->info[arange->arange];
300 59 : Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu);
301 59 : if (result != DWFL_E_NOERROR)
302 : return result;
303 59 : assert (arange->cu != NULL && arange->cu != (void *) -1l);
304 59 : less_lazy (mod); /* Each arange with null ->cu counts once. */
305 : }
306 :
307 337 : *cu = arange->cu;
308 337 : return DWFL_E_NOERROR;
309 : }
310 :
311 : Dwfl_Error
312 : internal_function
313 345 : __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_cu **cu)
314 : {
315 345 : struct dwfl_arange *arange;
316 345 : return addrarange (mod, addr, &arange) ?: arangecu (mod, arange, cu);
317 : }
|