1 /* Keeping track of DWARF compilation units in libdwfl.
2 Copyright (C) 2005-2010, 2015 Red Hat, Inc.
3 This file is part of elfutils.
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
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
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
18 or both in parallel, as here.
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.
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/>. */
30 #include "../libdw/libdwP.h"
31 #include "../libdw/memory-access.h"
35 static inline Dwarf_Arange *
36 dwar (Dwfl_Module *mod, unsigned int idx)
38 return &mod->dw->aranges->info[mod->aranges[idx].arange];
43 addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
45 if (mod->aranges == NULL)
47 struct dwfl_arange *aranges = NULL;
48 Dwarf_Aranges *dwaranges = NULL;
50 if (INTUSE(dwarf_getaranges) (mod->dw, &dwaranges, &naranges) != 0)
53 /* If the module has no aranges (when no code is included) we
57 aranges = malloc (naranges * sizeof *aranges);
58 if (unlikely (aranges == NULL))
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. */
70 for (size_t i = 0; i < dwaranges->naranges; ++i)
71 if (i == 0 || dwaranges->info[i].offset != lastcu)
73 aranges[naranges].arange = i;
74 aranges[naranges].cu = NULL;
76 lastcu = dwaranges->info[i].offset;
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])
84 mod->lazycu += naranges;
87 /* The address must be inside the module to begin with. */
88 addr = dwfl_deadjust_dwarf_addr (mod, addr);
90 /* The ranges are sorted by address, so we can use binary search. */
91 size_t l = 0, u = mod->naranges;
94 size_t idx = (l + u) / 2;
95 Dwarf_Addr start = dwar (mod, idx)->addr;
101 else if (addr > start)
103 if (idx + 1 < mod->naranges)
105 if (addr >= dwar (mod, idx + 1)->addr)
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)
121 *arange = &mod->aranges[idx];
122 return DWFL_E_NOERROR;
125 return DWFL_E_ADDR_OUTOFRANGE;
132 struct dwfl_cu *cu = arg;
133 if (cu == (void *) -1l)
136 assert (cu->mod->lazycu == 0);
139 /* One reason fewer to keep the lazy lookup table for CUs. */
141 less_lazy (Dwfl_Module *mod)
143 if (--mod->lazycu > 0)
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;
151 static inline Dwarf_Off
152 cudie_offset (const struct dwfl_cu *cu)
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 return DIE_OFFSET_FROM_CU_OFFSET (cu->die.cu->start, cu->die.cu->offset_size,
163 compare_cukey (const void *a, const void *b)
165 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);
170 /* Intern the CU if necessary. */
172 intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
174 if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
176 if (likely (mod->lazycu == 1))
178 /* This is the EOF marker. Now we have interned all the CUs.
179 One increment in MOD->lazycu counts not having hit EOF yet. */
180 *result = (void *) -1;
182 return DWFL_E_NOERROR;
186 /* Unexpected EOF, most likely a bogus aranges. */
187 return (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
191 /* Make sure the cuoff points to a real DIE. */
193 Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cudie);
197 struct Dwarf_CU dwkey;
200 dwkey.offset_size = 0;
201 dwkey.start = cuoff - (3 * 0 - 4 + 3);
202 struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
203 if (unlikely (found == NULL))
206 if (*found == &key || *found == NULL)
208 /* This is a new entry, meaning we haven't looked at this CU. */
212 struct dwfl_cu *cu = malloc (sizeof *cu);
213 if (unlikely (cu == NULL))
221 struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
222 * sizeof (mod->cu[0])));
230 mod->cu[mod->ncu++] = cu;
231 if (cu->die.cu->start == 0)
238 return DWFL_E_NOERROR;
242 /* Traverse all the CUs in the module. */
246 __libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu,
250 struct dwfl_cu **nextp;
254 /* Start the traversal. */
256 nextp = &mod->first_cu;
260 /* Continue following LASTCU. */
261 cuoff = lastcu->die.cu->end;
262 nextp = &lastcu->next;
269 int end = INTUSE(dwarf_nextcu) (mod->dw, cuoff, &nextoff, &cuhdrsz,
276 return DWFL_E_NOERROR;
279 Dwfl_Error result = intern_cu (mod, cuoff + cuhdrsz, nextp);
280 if (result != DWFL_E_NOERROR)
283 if (*nextp != (void *) -1
284 && (*nextp)->next == NULL && nextoff == (Dwarf_Off) -1l)
285 (*nextp)->next = (void *) -1l;
288 *cu = *nextp == (void *) -1l ? NULL : *nextp;
289 return DWFL_E_NOERROR;
293 /* Intern the CU arange points to, if necessary. */
296 arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu)
298 if (arange->cu == NULL)
300 const Dwarf_Arange *dwarange = &mod->dw->aranges->info[arange->arange];
301 Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu);
302 if (result != DWFL_E_NOERROR)
304 assert (arange->cu != NULL && arange->cu != (void *) -1l);
305 less_lazy (mod); /* Each arange with null ->cu counts once. */
309 return DWFL_E_NOERROR;
314 __libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_cu **cu)
316 struct dwfl_arange *arange;
317 return addrarange (mod, addr, &arange) ?: arangecu (mod, arange, cu);