blob: 3ac341e4aa91c3275d59443557c99011497e0e01 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Keeping track of DWARF compilation units in libdwfl.
Mark Wielaard975a37d2015-01-05 00:12:53 +01002 Copyright (C) 2005-2010, 2015 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004
Mark Wielaardde2ed972012-06-05 17:15:16 +02005 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00007
Mark Wielaardde2ed972012-06-05 17:15:16 +02008 * 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
Ulrich Drepper361df7d2006-04-04 21:38:57 +000021 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
Mark Wielaardde2ed972012-06-05 17:15:16 +020025 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/>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000028
29#include "libdwflP.h"
30#include "../libdw/libdwP.h"
31#include "../libdw/memory-access.h"
32#include <search.h>
33
34
35static inline Dwarf_Arange *
36dwar (Dwfl_Module *mod, unsigned int idx)
37{
38 return &mod->dw->aranges->info[mod->aranges[idx].arange];
39}
40
41
42static Dwfl_Error
43addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
44{
45 if (mod->aranges == NULL)
46 {
Ulrich Dreppere7a73172006-05-22 18:16:45 +000047 struct dwfl_arange *aranges = NULL;
48 Dwarf_Aranges *dwaranges = NULL;
49 size_t naranges;
50 if (INTUSE(dwarf_getaranges) (mod->dw, &dwaranges, &naranges) != 0)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000051 return DWFL_E_LIBDW;
52
Ulrich Dreppere7a73172006-05-22 18:16:45 +000053 /* If the module has no aranges (when no code is included) we
54 allocate nothing. */
55 if (naranges != 0)
56 {
57 aranges = malloc (naranges * sizeof *aranges);
58 if (unlikely (aranges == NULL))
59 return DWFL_E_NOMEM;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000060
Ulrich Dreppere7a73172006-05-22 18:16:45 +000061 /* 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. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000067
Ulrich Dreppere7a73172006-05-22 18:16:45 +000068 naranges = 0;
69 Dwarf_Off lastcu = 0;
70 for (size_t i = 0; i < dwaranges->naranges; ++i)
71 if (i == 0 || dwaranges->info[i].offset != lastcu)
72 {
73 aranges[naranges].arange = i;
74 aranges[naranges].cu = NULL;
75 ++naranges;
76 lastcu = dwaranges->info[i].offset;
77 }
78 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000079
80 /* Store the final array, which is probably much smaller than before. */
81 mod->naranges = naranges;
82 mod->aranges = (realloc (aranges, naranges * sizeof aranges[0])
83 ?: aranges);
84 mod->lazycu += naranges;
85 }
86
87 /* The address must be inside the module to begin with. */
Roland McGrath1743d7f2010-11-12 16:46:47 -080088 addr = dwfl_deadjust_dwarf_addr (mod, addr);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000089
90 /* The ranges are sorted by address, so we can use binary search. */
91 size_t l = 0, u = mod->naranges;
92 while (l < u)
93 {
94 size_t idx = (l + u) / 2;
95 Dwarf_Addr start = dwar (mod, idx)->addr;
96 if (addr < start)
97 {
98 u = idx;
99 continue;
100 }
101 else if (addr > start)
102 {
103 if (idx + 1 < mod->naranges)
104 {
105 if (addr >= dwar (mod, idx + 1)->addr)
106 {
107 l = idx + 1;
108 continue;
109 }
110 }
111 else
112 {
113 /* It might be in the last range. */
114 const Dwarf_Arange *last
115 = &mod->dw->aranges->info[mod->dw->aranges->naranges - 1];
116 if (addr > last->addr + last->length)
117 break;
118 }
119 }
120
121 *arange = &mod->aranges[idx];
122 return DWFL_E_NOERROR;
123 }
124
125 return DWFL_E_ADDR_OUTOFRANGE;
126}
127
128
129static void
130nofree (void *arg)
131{
132 struct dwfl_cu *cu = arg;
133 if (cu == (void *) -1l)
134 return;
135
136 assert (cu->mod->lazycu == 0);
137}
138
139/* One reason fewer to keep the lazy lookup table for CUs. */
140static inline void
141less_lazy (Dwfl_Module *mod)
142{
143 if (--mod->lazycu > 0)
144 return;
145
146 /* We know about all the CUs now, we don't need this table. */
147 tdestroy (mod->lazy_cu_root, nofree);
148 mod->lazy_cu_root = NULL;
149}
150
151static inline Dwarf_Off
152cudie_offset (const struct dwfl_cu *cu)
153{
Mark Wielaardea45ac82012-10-01 16:12:10 +0200154 /* 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. */
Roland McGrath3e0f7d12010-06-15 23:10:35 -0700158 return DIE_OFFSET_FROM_CU_OFFSET (cu->die.cu->start, cu->die.cu->offset_size,
Mark Wielaardea45ac82012-10-01 16:12:10 +0200159 0);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000160}
161
162static int
163compare_cukey (const void *a, const void *b)
164{
Mark Wielaard4a330f62014-12-14 00:09:29 +0100165 Dwarf_Off a_off = cudie_offset (a);
166 Dwarf_Off b_off = cudie_offset (b);
167 return (a_off < b_off) ? -1 : ((a_off > b_off) ? 1 : 0);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000168}
169
170/* Intern the CU if necessary. */
171static Dwfl_Error
172intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
173{
174 struct Dwarf_CU dwkey;
175 struct dwfl_cu key;
176 key.die.cu = &dwkey;
177 dwkey.offset_size = 0;
178 dwkey.start = cuoff - (3 * 0 - 4 + 3);
179 struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
180 if (unlikely (found == NULL))
181 return DWFL_E_NOMEM;
182
183 if (*found == &key || *found == NULL)
184 {
185 if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
186 {
187 /* This is the EOF marker. Now we have interned all the CUs.
188 One increment in MOD->lazycu counts not having hit EOF yet. */
Mark Wielaard975a37d2015-01-05 00:12:53 +0100189 *found = *result = (void *) -1;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000190 less_lazy (mod);
Mark Wielaard975a37d2015-01-05 00:12:53 +0100191 return DWFL_E_NOERROR;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000192 }
193 else
194 {
195 /* This is a new entry, meaning we haven't looked at this CU. */
196
197 *found = NULL;
198
199 struct dwfl_cu *cu = malloc (sizeof *cu);
200 if (unlikely (cu == NULL))
201 return DWFL_E_NOMEM;
202
203 cu->mod = mod;
204 cu->next = NULL;
205 cu->lines = NULL;
206
207 /* XXX use non-searching lookup */
Roland McGrath4959bf82005-08-09 10:31:08 +0000208 Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cu->die);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000209 if (die == NULL)
Mark Wielaardead7d192013-09-12 16:49:25 +0200210 {
211 free (cu);
212 return DWFL_E_LIBDW;
213 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000214 assert (die == &cu->die);
215
216 struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
217 * sizeof (mod->cu[0])));
218 if (newvec == NULL)
219 {
220 free (cu);
221 return DWFL_E_NOMEM;
222 }
223 mod->cu = newvec;
224
225 mod->cu[mod->ncu++] = cu;
226 if (cu->die.cu->start == 0)
227 mod->first_cu = cu;
228
229 *found = cu;
230 }
231 }
232
233 *result = *found;
234 return DWFL_E_NOERROR;
235}
236
237
238/* Traverse all the CUs in the module. */
239
240Dwfl_Error
Ulrich Drepper077c65f2006-07-12 19:54:51 +0000241internal_function
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000242__libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu,
243 struct dwfl_cu **cu)
244{
245 Dwarf_Off cuoff;
246 struct dwfl_cu **nextp;
247
248 if (lastcu == NULL)
249 {
250 /* Start the traversal. */
251 cuoff = 0;
252 nextp = &mod->first_cu;
253 }
254 else
255 {
256 /* Continue following LASTCU. */
257 cuoff = lastcu->die.cu->end;
258 nextp = &lastcu->next;
259 }
260
261 if (*nextp == NULL)
262 {
263 size_t cuhdrsz;
264 Dwarf_Off nextoff;
Roland McGrath995f92d2005-08-26 05:55:04 +0000265 int end = INTUSE(dwarf_nextcu) (mod->dw, cuoff, &nextoff, &cuhdrsz,
Roland McGrath3e0f7d12010-06-15 23:10:35 -0700266 NULL, NULL, NULL);
Roland McGrath995f92d2005-08-26 05:55:04 +0000267 if (end < 0)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000268 return DWFL_E_LIBDW;
Roland McGrath995f92d2005-08-26 05:55:04 +0000269 if (end > 0)
270 {
271 *cu = NULL;
272 return DWFL_E_NOERROR;
273 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000274
275 Dwfl_Error result = intern_cu (mod, cuoff + cuhdrsz, nextp);
276 if (result != DWFL_E_NOERROR)
277 return result;
278
Mark Wielaard975a37d2015-01-05 00:12:53 +0100279 if (*nextp != (void *) -1
280 && (*nextp)->next == NULL && nextoff == (Dwarf_Off) -1l)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000281 (*nextp)->next = (void *) -1l;
282 }
283
284 *cu = *nextp == (void *) -1l ? NULL : *nextp;
285 return DWFL_E_NOERROR;
286}
287
288
289/* Intern the CU arange points to, if necessary. */
290
291static Dwfl_Error
292arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu)
293{
294 if (arange->cu == NULL)
295 {
296 const Dwarf_Arange *dwarange = &mod->dw->aranges->info[arange->arange];
297 Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu);
298 if (result != DWFL_E_NOERROR)
299 return result;
300 assert (arange->cu != NULL && arange->cu != (void *) -1l);
301 less_lazy (mod); /* Each arange with null ->cu counts once. */
302 }
303
304 *cu = arange->cu;
305 return DWFL_E_NOERROR;
306}
307
308Dwfl_Error
Ulrich Drepper077c65f2006-07-12 19:54:51 +0000309internal_function
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000310__libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_cu **cu)
311{
312 struct dwfl_arange *arange;
313 return addrarange (mod, addr, &arange) ?: arangecu (mod, arange, cu);
314}