|
Packit Service |
97d2fb |
/* Keeping track of DWARF compilation units in libdwfl.
|
|
Packit Service |
97d2fb |
Copyright (C) 2005-2010, 2015, 2016, 2017 Red Hat, Inc.
|
|
Packit Service |
97d2fb |
This file is part of elfutils.
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
This file is free software; you can redistribute it and/or modify
|
|
Packit Service |
97d2fb |
it under the terms of either
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
* the GNU Lesser General Public License as published by the Free
|
|
Packit Service |
97d2fb |
Software Foundation; either version 3 of the License, or (at
|
|
Packit Service |
97d2fb |
your option) any later version
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
or
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
* the GNU General Public License as published by the Free
|
|
Packit Service |
97d2fb |
Software Foundation; either version 2 of the License, or (at
|
|
Packit Service |
97d2fb |
your option) any later version
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
or both in parallel, as here.
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
elfutils is distributed in the hope that it will be useful, but
|
|
Packit Service |
97d2fb |
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
97d2fb |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
97d2fb |
General Public License for more details.
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
You should have received copies of the GNU General Public License and
|
|
Packit Service |
97d2fb |
the GNU Lesser General Public License along with this program. If
|
|
Packit Service |
97d2fb |
not, see <http://www.gnu.org/licenses/>. */
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#ifdef HAVE_CONFIG_H
|
|
Packit Service |
97d2fb |
# include <config.h>
|
|
Packit Service |
97d2fb |
#endif
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
#include "libdwflP.h"
|
|
Packit Service |
97d2fb |
#include "../libdw/libdwP.h"
|
|
Packit Service |
97d2fb |
#include "../libdw/memory-access.h"
|
|
Packit Service |
97d2fb |
#include <search.h>
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static inline Dwarf_Arange *
|
|
Packit Service |
97d2fb |
dwar (Dwfl_Module *mod, unsigned int idx)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
return &mod->dw->aranges->info[mod->aranges[idx].arange];
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static Dwfl_Error
|
|
Packit Service |
97d2fb |
addrarange (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_arange **arange)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (mod->aranges == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
struct dwfl_arange *aranges = NULL;
|
|
Packit Service |
97d2fb |
Dwarf_Aranges *dwaranges = NULL;
|
|
Packit Service |
97d2fb |
size_t naranges;
|
|
Packit Service |
97d2fb |
if (INTUSE(dwarf_getaranges) (mod->dw, &dwaranges, &naranges) != 0)
|
|
Packit Service |
97d2fb |
return DWFL_E_LIBDW;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* If the module has no aranges (when no code is included) we
|
|
Packit Service |
97d2fb |
allocate nothing. */
|
|
Packit Service |
97d2fb |
if (naranges != 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
aranges = malloc (naranges * sizeof *aranges);
|
|
Packit Service |
97d2fb |
if (unlikely (aranges == NULL))
|
|
Packit Service |
97d2fb |
return DWFL_E_NOMEM;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* libdw has sorted its list by address, which is how we want it.
|
|
Packit Service |
97d2fb |
But the sorted list is full of not-quite-contiguous runs pointing
|
|
Packit Service |
97d2fb |
to the same CU. We don't care about the little gaps inside the
|
|
Packit Service |
97d2fb |
module, we'll consider them part of the surrounding CU anyway.
|
|
Packit Service |
97d2fb |
Collect our own array with just one record for each run of ranges
|
|
Packit Service |
97d2fb |
pointing to one CU. */
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
naranges = 0;
|
|
Packit Service |
97d2fb |
Dwarf_Off lastcu = 0;
|
|
Packit Service |
97d2fb |
for (size_t i = 0; i < dwaranges->naranges; ++i)
|
|
Packit Service |
97d2fb |
if (i == 0 || dwaranges->info[i].offset != lastcu)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
aranges[naranges].arange = i;
|
|
Packit Service |
97d2fb |
aranges[naranges].cu = NULL;
|
|
Packit Service |
97d2fb |
++naranges;
|
|
Packit Service |
97d2fb |
lastcu = dwaranges->info[i].offset;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Store the final array, which is probably much smaller than before. */
|
|
Packit Service |
97d2fb |
mod->naranges = naranges;
|
|
Packit Service |
97d2fb |
if (naranges > 0)
|
|
Packit Service |
97d2fb |
mod->aranges = (realloc (aranges, naranges * sizeof aranges[0])
|
|
Packit Service |
97d2fb |
?: aranges);
|
|
Packit Service |
97d2fb |
else if (aranges != NULL)
|
|
Packit Service |
97d2fb |
free (aranges);
|
|
Packit Service |
97d2fb |
mod->lazycu += naranges;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* The address must be inside the module to begin with. */
|
|
Packit Service |
97d2fb |
addr = dwfl_deadjust_dwarf_addr (mod, addr);
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* The ranges are sorted by address, so we can use binary search. */
|
|
Packit Service |
97d2fb |
size_t l = 0, u = mod->naranges;
|
|
Packit Service |
97d2fb |
while (l < u)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
size_t idx = (l + u) / 2;
|
|
Packit Service |
97d2fb |
Dwarf_Addr start = dwar (mod, idx)->addr;
|
|
Packit Service |
97d2fb |
if (addr < start)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
u = idx;
|
|
Packit Service |
97d2fb |
continue;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
else if (addr > start)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (idx + 1 < mod->naranges)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (addr >= dwar (mod, idx + 1)->addr)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
l = idx + 1;
|
|
Packit Service |
97d2fb |
continue;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* It might be in the last range. */
|
|
Packit Service |
97d2fb |
const Dwarf_Arange *last
|
|
Packit Service |
97d2fb |
= &mod->dw->aranges->info[mod->dw->aranges->naranges - 1];
|
|
Packit Service |
97d2fb |
if (addr > last->addr + last->length)
|
|
Packit Service |
97d2fb |
break;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
*arange = &mod->aranges[idx];
|
|
Packit Service |
97d2fb |
return DWFL_E_NOERROR;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
return DWFL_E_ADDR_OUTOFRANGE;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static void
|
|
Packit Service |
97d2fb |
nofree (void *arg)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
struct dwfl_cu *cu = arg;
|
|
Packit Service |
97d2fb |
if (cu == (void *) -1l)
|
|
Packit Service |
97d2fb |
return;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
assert (cu->mod->lazycu == 0);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* One reason fewer to keep the lazy lookup table for CUs. */
|
|
Packit Service |
97d2fb |
static inline void
|
|
Packit Service |
97d2fb |
less_lazy (Dwfl_Module *mod)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (--mod->lazycu > 0)
|
|
Packit Service |
97d2fb |
return;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* We know about all the CUs now, we don't need this table. */
|
|
Packit Service |
97d2fb |
tdestroy (mod->lazy_cu_root, nofree);
|
|
Packit Service |
97d2fb |
mod->lazy_cu_root = NULL;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static inline Dwarf_Off
|
|
Packit Service |
97d2fb |
cudie_offset (const struct dwfl_cu *cu)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
return __libdw_first_die_off_from_cu (cu->die.cu);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static int
|
|
Packit Service |
97d2fb |
compare_cukey (const void *a, const void *b)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
Dwarf_Off a_off = cudie_offset (a);
|
|
Packit Service |
97d2fb |
Dwarf_Off b_off = cudie_offset (b);
|
|
Packit Service |
97d2fb |
return (a_off < b_off) ? -1 : ((a_off > b_off) ? 1 : 0);
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Intern the CU if necessary. */
|
|
Packit Service |
97d2fb |
static Dwfl_Error
|
|
Packit Service |
97d2fb |
intern_cu (Dwfl_Module *mod, Dwarf_Off cuoff, struct dwfl_cu **result)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (unlikely (cuoff + 4 >= mod->dw->sectiondata[IDX_debug_info]->d_size))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (likely (mod->lazycu == 1))
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* This is the EOF marker. Now we have interned all the CUs.
|
|
Packit Service |
97d2fb |
One increment in MOD->lazycu counts not having hit EOF yet. */
|
|
Packit Service |
97d2fb |
*result = (void *) -1;
|
|
Packit Service |
97d2fb |
less_lazy (mod);
|
|
Packit Service |
97d2fb |
return DWFL_E_NOERROR;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* Unexpected EOF, most likely a bogus aranges. */
|
|
Packit Service |
97d2fb |
return (DWFL_E (LIBDW, DWARF_E_INVALID_DWARF));
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Make sure the cuoff points to a real DIE. */
|
|
Packit Service |
97d2fb |
Dwarf_Die cudie;
|
|
Packit Service |
97d2fb |
Dwarf_Die *die = INTUSE(dwarf_offdie) (mod->dw, cuoff, &cudie);
|
|
Packit Service |
97d2fb |
if (die == NULL)
|
|
Packit Service |
97d2fb |
return DWFL_E_LIBDW;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
struct dwfl_cu key;
|
|
Packit Service |
97d2fb |
key.die.cu = die->cu;
|
|
Packit Service |
97d2fb |
struct dwfl_cu **found = tsearch (&key, &mod->lazy_cu_root, &compare_cukey);
|
|
Packit Service |
97d2fb |
if (unlikely (found == NULL))
|
|
Packit Service |
97d2fb |
return DWFL_E_NOMEM;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (*found == &key || *found == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* This is a new entry, meaning we haven't looked at this CU. */
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
*found = NULL;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
struct dwfl_cu *cu = malloc (sizeof *cu);
|
|
Packit Service |
97d2fb |
if (unlikely (cu == NULL))
|
|
Packit Service |
97d2fb |
return DWFL_E_NOMEM;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
cu->mod = mod;
|
|
Packit Service |
97d2fb |
cu->next = NULL;
|
|
Packit Service |
97d2fb |
cu->lines = NULL;
|
|
Packit Service |
97d2fb |
cu->die = cudie;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
struct dwfl_cu **newvec = realloc (mod->cu, ((mod->ncu + 1)
|
|
Packit Service |
97d2fb |
* sizeof (mod->cu[0])));
|
|
Packit Service |
97d2fb |
if (newvec == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
free (cu);
|
|
Packit Service |
97d2fb |
return DWFL_E_NOMEM;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
mod->cu = newvec;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
mod->cu[mod->ncu++] = cu;
|
|
Packit Service |
97d2fb |
if (cu->die.cu->start == 0)
|
|
Packit Service |
97d2fb |
mod->first_cu = cu;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
*found = cu;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
*result = *found;
|
|
Packit Service |
97d2fb |
return DWFL_E_NOERROR;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Traverse all the CUs in the module. */
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
Dwfl_Error
|
|
Packit Service |
97d2fb |
internal_function
|
|
Packit Service |
97d2fb |
__libdwfl_nextcu (Dwfl_Module *mod, struct dwfl_cu *lastcu,
|
|
Packit Service |
97d2fb |
struct dwfl_cu **cu)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
Dwarf_Off cuoff;
|
|
Packit Service |
97d2fb |
struct dwfl_cu **nextp;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (lastcu == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* Start the traversal. */
|
|
Packit Service |
97d2fb |
cuoff = 0;
|
|
Packit Service |
97d2fb |
nextp = &mod->first_cu;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
else
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
/* Continue following LASTCU. */
|
|
Packit Service |
97d2fb |
cuoff = lastcu->die.cu->end;
|
|
Packit Service |
97d2fb |
nextp = &lastcu->next;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (*nextp == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
size_t cuhdrsz;
|
|
Packit Service |
97d2fb |
Dwarf_Off nextoff;
|
|
Packit Service |
97d2fb |
int end = INTUSE(dwarf_nextcu) (mod->dw, cuoff, &nextoff, &cuhdrsz,
|
|
Packit Service |
97d2fb |
NULL, NULL, NULL);
|
|
Packit Service |
97d2fb |
if (end < 0)
|
|
Packit Service |
97d2fb |
return DWFL_E_LIBDW;
|
|
Packit Service |
97d2fb |
if (end > 0)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
*cu = NULL;
|
|
Packit Service |
97d2fb |
return DWFL_E_NOERROR;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
Dwfl_Error result = intern_cu (mod, cuoff + cuhdrsz, nextp);
|
|
Packit Service |
97d2fb |
if (result != DWFL_E_NOERROR)
|
|
Packit Service |
97d2fb |
return result;
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
if (*nextp != (void *) -1
|
|
Packit Service |
97d2fb |
&& (*nextp)->next == NULL && nextoff == (Dwarf_Off) -1l)
|
|
Packit Service |
97d2fb |
(*nextp)->next = (void *) -1l;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
*cu = *nextp == (void *) -1l ? NULL : *nextp;
|
|
Packit Service |
97d2fb |
return DWFL_E_NOERROR;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
/* Intern the CU arange points to, if necessary. */
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
static Dwfl_Error
|
|
Packit Service |
97d2fb |
arangecu (Dwfl_Module *mod, struct dwfl_arange *arange, struct dwfl_cu **cu)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
if (arange->cu == NULL)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
const Dwarf_Arange *dwarange = &mod->dw->aranges->info[arange->arange];
|
|
Packit Service |
97d2fb |
Dwfl_Error result = intern_cu (mod, dwarange->offset, &arange->cu);
|
|
Packit Service |
97d2fb |
if (result != DWFL_E_NOERROR)
|
|
Packit Service |
97d2fb |
return result;
|
|
Packit Service |
97d2fb |
assert (arange->cu != NULL && arange->cu != (void *) -1l);
|
|
Packit Service |
97d2fb |
less_lazy (mod); /* Each arange with null ->cu counts once. */
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
*cu = arange->cu;
|
|
Packit Service |
97d2fb |
return DWFL_E_NOERROR;
|
|
Packit Service |
97d2fb |
}
|
|
Packit Service |
97d2fb |
|
|
Packit Service |
97d2fb |
Dwfl_Error
|
|
Packit Service |
97d2fb |
internal_function
|
|
Packit Service |
97d2fb |
__libdwfl_addrcu (Dwfl_Module *mod, Dwarf_Addr addr, struct dwfl_cu **cu)
|
|
Packit Service |
97d2fb |
{
|
|
Packit Service |
97d2fb |
struct dwfl_arange *arange;
|
|
Packit Service |
97d2fb |
return addrarange (mod, addr, &arange) ?: arangecu (mod, arange, cu);
|
|
Packit Service |
97d2fb |
}
|