blob: 94bfad8df22303109f0d94c5cf07891df1e6985d [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Keeping track of DWARF compilation units in libdwfl.
Mark Wielaard532ab1e2018-01-29 15:59:05 +01002 Copyright (C) 2005-2010, 2015, 2016, 2017 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
Ulf Hermann575198c2017-04-20 16:31:02 +020029#ifdef HAVE_CONFIG_H
30# include <config.h>
31#endif
32
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000033#include "libdwflP.h"
34#include "../libdw/libdwP.h"
35#include "../libdw/memory-access.h"
36#include <search.h>
37
38
39static inline Dwarf_Arange *
40dwar (Dwfl_Module *mod, unsigned int idx)
41{
42 return &mod->dw->aranges->info[mod->aranges[idx].arange];
43}
44
45
46static Dwfl_Error
47addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
48{
49 if (mod->aranges == NULL)
50 {
Ulrich Dreppere7a73172006-05-22 18:16:45 +000051 struct dwfl_arange *aranges = NULL;
52 Dwarf_Aranges *dwaranges = NULL;
53 size_t naranges;
54 if (INTUSE(dwarf_getaranges) (mod->dw, &dwaranges, &naranges) != 0)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000055 return DWFL_E_LIBDW;
56
Ulrich Dreppere7a73172006-05-22 18:16:45 +000057 /* If the module has no aranges (when no code is included) we
58 allocate nothing. */
59 if (naranges != 0)
60 {
61 aranges = malloc (naranges * sizeof *aranges);
62 if (unlikely (aranges == NULL))
63 return DWFL_E_NOMEM;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000064
Ulrich Dreppere7a73172006-05-22 18:16:45 +000065 /* 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. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000071
Ulrich Dreppere7a73172006-05-22 18:16:45 +000072 naranges = 0;
73 Dwarf_Off lastcu = 0;
74 for (size_t i = 0; i < dwaranges->naranges; ++i)
75 if (i == 0 || dwaranges->info[i].offset != lastcu)
76 {
77 aranges[naranges].arange = i;
78 aranges[naranges].cu = NULL;
79 ++naranges;
80 lastcu = dwaranges->info[i].offset;
81 }
82 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000083
84 /* Store the final array, which is probably much smaller than before. */
85 mod->naranges = naranges;
86 mod->aranges = (realloc (aranges, naranges * sizeof aranges[0])
87 ?: aranges);
88 mod->lazycu += naranges;
89 }
90
91 /* The address must be inside the module to begin with. */
Roland McGrath1743d7f2010-11-12 16:46:47 -080092 addr = dwfl_deadjust_dwarf_addr (mod, addr);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000093
94 /* The ranges are sorted by address, so we can use binary search. */
95 size_t l = 0, u = mod->naranges;
96 while (l < u)
97 {
98 size_t idx = (l + u) / 2;
99 Dwarf_Addr start = dwar (mod, idx)->addr;
100 if (addr < start)
101 {
102 u = idx;
103 continue;
104 }
105 else if (addr > start)
106 {
107 if (idx + 1 < mod->naranges)
108 {
109 if (addr >= dwar (mod, idx + 1)->addr)
110 {
111 l = idx + 1;
112 continue;
113 }
114 }
115 else
116 {
117 /* It might be in the last range. */
118 const Dwarf_Arange *last
119 = &mod->dw->aranges->info[mod->dw->aranges->naranges - 1];
120 if (addr > last->addr + last->length)
121 break;
122 }
123 }
124
125 *arange = &mod->aranges[idx];
126 return DWFL_E_NOERROR;
127 }
128
129 return DWFL_E_ADDR_OUTOFRANGE;
130}
131
132
133static void
134nofree (void *arg)
135{
136 struct dwfl_cu *cu = arg;
137 if (cu == (void *) -1l)
138 return;
139
140 assert (cu->mod->lazycu == 0);
141}
142
143/* One reason fewer to keep the lazy lookup table for CUs. */
144static inline void
145less_lazy (Dwfl_Module *mod)
146{
147 if (--mod->lazycu > 0)
148 return;
149
150 /* We know about all the CUs now, we don't need this table. */
151 tdestroy (mod->lazy_cu_root, nofree);
152 mod->lazy_cu_root = NULL;
153}
154
155static inline Dwarf_Off
156cudie_offset (const struct dwfl_cu *cu)
157{
Mark Wielaard532ab1e2018-01-29 15:59:05 +0100158 return __libdw_first_die_off_from_cu (cu->die.cu);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000159}
160
161static int
162compare_cukey (const void *a, const void *b)
163{
Mark Wielaard4a330f62014-12-14 00:09:29 +0100164 Dwarf_Off a_off = cudie_offset (a);
165 Dwarf_Off b_off = cudie_offset (b);
166 return (a_off < b_off) ? -1 : ((a_off > b_off) ? 1 : 0);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000167}
168
169/* Intern the CU if necessary. */
170static Dwfl_Error
171intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
172{
Mark Wielaardf0855402015-05-07 18:35:48 +0200173 if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
174 {
175 if (likely (mod->lazycu == 1))
176 {
177 /* This is the EOF marker. Now we have interned all the CUs.
178 One increment in MOD->lazycu counts not having hit EOF yet. */
179 *result = (void *) -1;
180 less_lazy (mod);
181 return DWFL_E_NOERROR;
182 }
183 else
184 {
185 /* Unexpected EOF, most likely a bogus aranges. */
186 return (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
187 }
188 }
189
190 /* Make sure the cuoff points to a real DIE. */
191 Dwarf_Die cudie;
192 Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cudie);
193 if (die == NULL)
194 return DWFL_E_LIBDW;
195
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000196 struct dwfl_cu key;
Mark Wielaard532ab1e2018-01-29 15:59:05 +0100197 key.die.cu = die->cu;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000198 struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
199 if (unlikely (found == NULL))
200 return DWFL_E_NOMEM;
201
202 if (*found == &key || *found == NULL)
203 {
Mark Wielaardf0855402015-05-07 18:35:48 +0200204 /* This is a new entry, meaning we haven't looked at this CU. */
205
206 *found = NULL;
207
208 struct dwfl_cu *cu = malloc (sizeof *cu);
209 if (unlikely (cu == NULL))
210 return DWFL_E_NOMEM;
211
212 cu->mod = mod;
213 cu->next = NULL;
214 cu->lines = NULL;
215 cu->die = cudie;
216
217 struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
218 * sizeof (mod->cu[0])));
219 if (newvec == NULL)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000220 {
Mark Wielaardf0855402015-05-07 18:35:48 +0200221 free (cu);
222 return DWFL_E_NOMEM;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000223 }
Mark Wielaardf0855402015-05-07 18:35:48 +0200224 mod->cu = newvec;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000225
Mark Wielaardf0855402015-05-07 18:35:48 +0200226 mod->cu[mod->ncu++] = cu;
227 if (cu->die.cu->start == 0)
228 mod->first_cu = cu;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000229
Mark Wielaardf0855402015-05-07 18:35:48 +0200230 *found = cu;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000231 }
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}