Branch data Line data Source code
1 : : /* Keeping track of DWARF compilation units in libdwfl.
2 : : Copyright (C) 2005-2010 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 : : #include "libdwflP.h"
30 : : #include "../libdw/libdwP.h"
31 : : #include "../libdw/memory-access.h"
32 : : #include <search.h>
33 : :
34 : :
35 : : static inline Dwarf_Arange *
36 : : dwar (Dwfl_Module *mod, unsigned int idx)
37 : : {
38 : 39 : return &mod->dw->aranges->info[mod->aranges[idx].arange];
39 : : }
40 : :
41 : :
42 : : static Dwfl_Error
43 : 46 : addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
44 : : {
45 [ + + ]: 46 : if (mod->aranges == NULL)
46 : : {
47 : 23 : struct dwfl_arange *aranges = NULL;
48 : 23 : Dwarf_Aranges *dwaranges = NULL;
49 : : size_t naranges;
50 [ + - ]: 23 : if (INTUSE(dwarf_getaranges) (mod->dw, &dwaranges, &naranges) != 0)
51 : : return DWFL_E_LIBDW;
52 : :
53 : : /* If the module has no aranges (when no code is included) we
54 : : allocate nothing. */
55 [ + + ]: 23 : if (naranges != 0)
56 : : {
57 : 19 : aranges = malloc (naranges * sizeof *aranges);
58 [ + - ]: 19 : if (unlikely (aranges == NULL))
59 : : return DWFL_E_NOMEM;
60 : :
61 : : /* libdw has sorted its list by address, which is how we want it.
62 : : But the sorted list is full of not-quite-contiguous runs pointing
63 : : to the same CU. We don't care about the little gaps inside the
64 : : module, we'll consider them part of the surrounding CU anyway.
65 : : Collect our own array with just one record for each run of ranges
66 : : pointing to one CU. */
67 : :
68 : 19 : naranges = 0;
69 : 19 : Dwarf_Off lastcu = 0;
70 [ + + ]: 43 : for (size_t i = 0; i < dwaranges->naranges; ++i)
71 [ + + ][ + - ]: 24 : if (i == 0 || dwaranges->info[i].offset != lastcu)
72 : : {
73 : 24 : aranges[naranges].arange = i;
74 : 24 : aranges[naranges].cu = NULL;
75 : 24 : ++naranges;
76 : 24 : lastcu = dwaranges->info[i].offset;
77 : : }
78 : : }
79 : :
80 : : /* Store the final array, which is probably much smaller than before. */
81 : 23 : mod->naranges = naranges;
82 : 46 : mod->aranges = (realloc (aranges, naranges * sizeof aranges[0])
83 [ - + ]: 23 : ?: aranges);
84 : 23 : mod->lazycu += naranges;
85 : : }
86 : :
87 : : /* The address must be inside the module to begin with. */
88 : 46 : addr = dwfl_deadjust_dwarf_addr (mod, addr);
89 : :
90 : : /* The ranges are sorted by address, so we can use binary search. */
91 : 46 : size_t l = 0, u = mod->naranges;
92 [ + + ]: 84 : while (l < u)
93 : : {
94 : 38 : size_t idx = (l + u) / 2;
95 : 114 : Dwarf_Addr start = dwar (mod, idx)->addr;
96 [ - + ]: 38 : if (addr < start)
97 : : {
98 : 0 : u = idx;
99 : 0 : continue;
100 : : }
101 [ + + ]: 38 : else if (addr > start)
102 : : {
103 [ + + ]: 27 : if (idx + 1 < mod->naranges)
104 : : {
105 [ - + ]: 1 : if (addr >= dwar (mod, idx + 1)->addr)
106 : : {
107 : 0 : l = idx + 1;
108 : 0 : continue;
109 : : }
110 : : }
111 : : else
112 : : {
113 : : /* It might be in the last range. */
114 : 26 : const Dwarf_Arange *last
115 : 26 : = &mod->dw->aranges->info[mod->dw->aranges->naranges - 1];
116 [ + - ]: 26 : if (addr > last->addr + last->length)
117 : : break;
118 : : }
119 : : }
120 : :
121 : 38 : *arange = &mod->aranges[idx];
122 : 38 : return DWFL_E_NOERROR;
123 : : }
124 : :
125 : : return DWFL_E_ADDR_OUTOFRANGE;
126 : : }
127 : :
128 : :
129 : : static void
130 : 0 : nofree (void *arg)
131 : : {
132 : 0 : struct dwfl_cu *cu = arg;
133 [ # # ]: 0 : if (cu == (void *) -1l)
134 : 0 : return;
135 : :
136 [ # # ]: 0 : assert (cu->mod->lazycu == 0);
137 : : }
138 : :
139 : : /* One reason fewer to keep the lazy lookup table for CUs. */
140 : : static inline void
141 : 19 : less_lazy (Dwfl_Module *mod)
142 : : {
143 [ - + ]: 19 : if (--mod->lazycu > 0)
144 : 19 : return;
145 : :
146 : : /* We know about all the CUs now, we don't need this table. */
147 : 0 : tdestroy (mod->lazy_cu_root, nofree);
148 : 0 : mod->lazy_cu_root = NULL;
149 : : }
150 : :
151 : : static inline Dwarf_Off
152 : : cudie_offset (const struct dwfl_cu *cu)
153 : : {
154 : : /* These are real CUs, so there never is a type_sig8. Note
155 : : initialization of dwkey.start and offset_size in intern_cu ()
156 : : to see why this calculates the same value for both key and
157 : : die.cu search items. */
158 : 90360 : return DIE_OFFSET_FROM_CU_OFFSET (cu->die.cu->start, cu->die.cu->offset_size,
159 : : 0);
160 : : }
161 : :
162 : : static int
163 : 45180 : compare_cukey (const void *a, const void *b)
164 : : {
165 : 45180 : return cudie_offset (a) - cudie_offset (b);
166 : : }
167 : :
168 : : /* Intern the CU if necessary. */
169 : : static Dwfl_Error
170 : 3725 : intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
171 : : {
172 : : struct Dwarf_CU dwkey;
173 : : struct dwfl_cu key;
174 : 3725 : key.die.cu = &dwkey;
175 : 3725 : dwkey.offset_size = 0;
176 : 3725 : dwkey.start = cuoff - (3 * 0 - 4 + 3);
177 : 3725 : struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
178 [ + - ]: 3725 : if (unlikely (found == NULL))
179 : : return DWFL_E_NOMEM;
180 : :
181 [ + + ][ - + ]: 3725 : if (*found == &key || *found == NULL)
182 : : {
183 [ - + ]: 3724 : if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
184 : : {
185 : : /* This is the EOF marker. Now we have interned all the CUs.
186 : : One increment in MOD->lazycu counts not having hit EOF yet. */
187 : 0 : *found = (void *) -1l;
188 : 0 : less_lazy (mod);
189 : : }
190 : : else
191 : : {
192 : : /* This is a new entry, meaning we haven't looked at this CU. */
193 : :
194 : 3724 : *found = NULL;
195 : :
196 : 3724 : struct dwfl_cu *cu = malloc (sizeof *cu);
197 [ + - ]: 3724 : if (unlikely (cu == NULL))
198 : : return DWFL_E_NOMEM;
199 : :
200 : 3724 : cu->mod = mod;
201 : 3724 : cu->next = NULL;
202 : 3724 : cu->lines = NULL;
203 : :
204 : : /* XXX use non-searching lookup */
205 : 3724 : Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cu->die);
206 [ + - ]: 3724 : if (die == NULL)
207 : : return DWFL_E_LIBDW;
208 [ - + ]: 3724 : assert (die == &cu->die);
209 : :
210 : 3724 : struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
211 : : * sizeof (mod->cu[0])));
212 [ - + ]: 3724 : if (newvec == NULL)
213 : : {
214 : 0 : free (cu);
215 : : return DWFL_E_NOMEM;
216 : : }
217 : 3724 : mod->cu = newvec;
218 : :
219 : 3724 : mod->cu[mod->ncu++] = cu;
220 [ + + ]: 3724 : if (cu->die.cu->start == 0)
221 : 48 : mod->first_cu = cu;
222 : :
223 : 3724 : *found = cu;
224 : : }
225 : : }
226 : :
227 : 3725 : *result = *found;
228 : : return DWFL_E_NOERROR;
229 : : }
230 : :
231 : :
232 : : /* Traverse all the CUs in the module. */
233 : :
234 : : Dwfl_Error
235 : : internal_function
236 : 3753 : __libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu,
237 : : struct dwfl_cu **cu)
238 : : {
239 : : Dwarf_Off cuoff;
240 : : struct dwfl_cu **nextp;
241 : :
242 [ + + ]: 3753 : if (lastcu == NULL)
243 : : {
244 : : /* Start the traversal. */
245 : 36 : cuoff = 0;
246 : 36 : nextp = &mod->first_cu;
247 : : }
248 : : else
249 : : {
250 : : /* Continue following LASTCU. */
251 : 3717 : cuoff = lastcu->die.cu->end;
252 : 3717 : nextp = &lastcu->next;
253 : : }
254 : :
255 [ + + ]: 3753 : if (*nextp == NULL)
256 : : {
257 : : size_t cuhdrsz;
258 : : Dwarf_Off nextoff;
259 : 3742 : int end = INTUSE(dwarf_nextcu) (mod->dw, cuoff, &nextoff, &cuhdrsz,
260 : : NULL, NULL, NULL);
261 [ + - ]: 3742 : if (end < 0)
262 : : return DWFL_E_LIBDW;
263 [ + + ]: 3742 : if (end > 0)
264 : : {
265 : 36 : *cu = NULL;
266 : : return DWFL_E_NOERROR;
267 : : }
268 : :
269 : 3706 : Dwfl_Error result = intern_cu (mod, cuoff + cuhdrsz, nextp);
270 [ + - ]: 3706 : if (result != DWFL_E_NOERROR)
271 : : return result;
272 : :
273 [ + - ][ - + ]: 3706 : if ((*nextp)->next == NULL && nextoff == (Dwarf_Off) -1l)
274 : 3742 : (*nextp)->next = (void *) -1l;
275 : : }
276 : :
277 [ + - ]: 3717 : *cu = *nextp == (void *) -1l ? NULL : *nextp;
278 : 3753 : return DWFL_E_NOERROR;
279 : : }
280 : :
281 : :
282 : : /* Intern the CU arange points to, if necessary. */
283 : :
284 : : static Dwfl_Error
285 : 38 : arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu)
286 : : {
287 [ + + ]: 38 : if (arange->cu == NULL)
288 : : {
289 : 19 : const Dwarf_Arange *dwarange = &mod->dw->aranges->info[arange->arange];
290 : 19 : Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu);
291 [ + - ]: 19 : if (result != DWFL_E_NOERROR)
292 : : return result;
293 [ - + ]: 19 : assert (arange->cu != NULL && arange->cu != (void *) -1l);
294 : 19 : less_lazy (mod); /* Each arange with null ->cu counts once. */
295 : : }
296 : :
297 : 38 : *cu = arange->cu;
298 : 38 : return DWFL_E_NOERROR;
299 : : }
300 : :
301 : : Dwfl_Error
302 : : internal_function
303 : 46 : __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_cu **cu)
304 : : {
305 : : struct dwfl_arange *arange;
306 [ + + ]: 46 : return addrarange (mod, addr, &arange) ?: arangecu (mod, arange, cu);
307 : 90520 : }
|