244 lines
5.6 KiB
C
244 lines
5.6 KiB
C
/* Maintenance of module list in libdwfl.
|
|
Copyright (C) 2005, 2006, 2007, 2008, 2014, 2015 Red Hat, Inc.
|
|
This file is part of elfutils.
|
|
|
|
This file is free software; you can redistribute it and/or modify
|
|
it under the terms of either
|
|
|
|
* the GNU Lesser General Public License as published by the Free
|
|
Software Foundation; either version 3 of the License, or (at
|
|
your option) any later version
|
|
|
|
or
|
|
|
|
* the GNU General Public License as published by the Free
|
|
Software Foundation; either version 2 of the License, or (at
|
|
your option) any later version
|
|
|
|
or both in parallel, as here.
|
|
|
|
elfutils is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received copies of the GNU General Public License and
|
|
the GNU Lesser General Public License along with this program. If
|
|
not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include "libdwflP.h"
|
|
#include "../libdw/cfi.h"
|
|
#include <search.h>
|
|
#include <unistd.h>
|
|
|
|
static void
|
|
free_cu (struct dwfl_cu *cu)
|
|
{
|
|
if (cu->lines != NULL)
|
|
free (cu->lines);
|
|
free (cu);
|
|
}
|
|
|
|
static void
|
|
nofree (void *arg __attribute__ ((unused)))
|
|
{
|
|
}
|
|
|
|
static void
|
|
free_file (struct dwfl_file *file)
|
|
{
|
|
free (file->name);
|
|
|
|
/* Close the fd only on the last reference. */
|
|
if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1)
|
|
close (file->fd);
|
|
}
|
|
|
|
void
|
|
internal_function
|
|
__libdwfl_module_free (Dwfl_Module *mod)
|
|
{
|
|
if (mod->lazy_cu_root != NULL)
|
|
tdestroy (mod->lazy_cu_root, nofree);
|
|
|
|
if (mod->aranges != NULL)
|
|
free (mod->aranges);
|
|
|
|
if (mod->cu != NULL)
|
|
{
|
|
for (size_t i = 0; i < mod->ncu; ++i)
|
|
free_cu (mod->cu[i]);
|
|
free (mod->cu);
|
|
}
|
|
|
|
/* We might have primed the Dwarf_CFI ebl cache with our own ebl
|
|
in __libdwfl_set_cfi. Make sure we don't free it twice. */
|
|
if (mod->eh_cfi != NULL)
|
|
{
|
|
if (mod->eh_cfi->ebl != NULL && mod->eh_cfi->ebl == mod->ebl)
|
|
mod->eh_cfi->ebl = NULL;
|
|
dwarf_cfi_end (mod->eh_cfi);
|
|
}
|
|
|
|
if (mod->dwarf_cfi != NULL)
|
|
{
|
|
if (mod->dwarf_cfi->ebl != NULL && mod->dwarf_cfi->ebl == mod->ebl)
|
|
mod->dwarf_cfi->ebl = NULL;
|
|
/* We don't need to explicitly destroy the dwarf_cfi.
|
|
That will be done by dwarf_end. */
|
|
}
|
|
|
|
if (mod->dw != NULL)
|
|
{
|
|
INTUSE(dwarf_end) (mod->dw);
|
|
if (mod->alt != NULL)
|
|
{
|
|
INTUSE(dwarf_end) (mod->alt);
|
|
if (mod->alt_elf != NULL)
|
|
elf_end (mod->alt_elf);
|
|
if (mod->alt_fd != -1)
|
|
close (mod->alt_fd);
|
|
}
|
|
}
|
|
|
|
if (mod->ebl != NULL)
|
|
ebl_closebackend (mod->ebl);
|
|
|
|
if (mod->debug.elf != mod->main.elf)
|
|
free_file (&mod->debug);
|
|
free_file (&mod->main);
|
|
free_file (&mod->aux_sym);
|
|
|
|
if (mod->build_id_bits != NULL)
|
|
free (mod->build_id_bits);
|
|
|
|
if (mod->reloc_info != NULL)
|
|
free (mod->reloc_info);
|
|
|
|
free (mod->name);
|
|
free (mod->elfdir);
|
|
free (mod);
|
|
}
|
|
|
|
void
|
|
dwfl_report_begin_add (Dwfl *dwfl __attribute__ ((unused)))
|
|
{
|
|
/* The lookup table will be cleared on demand, there is nothing we need
|
|
to do here. */
|
|
}
|
|
INTDEF (dwfl_report_begin_add)
|
|
|
|
void
|
|
dwfl_report_begin (Dwfl *dwfl)
|
|
{
|
|
/* Clear the segment lookup table. */
|
|
dwfl->lookup_elts = 0;
|
|
|
|
for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
|
|
m->gc = true;
|
|
|
|
dwfl->offline_next_address = OFFLINE_REDZONE;
|
|
}
|
|
INTDEF (dwfl_report_begin)
|
|
|
|
static inline Dwfl_Module *
|
|
use (Dwfl_Module *mod, Dwfl_Module **tailp, Dwfl *dwfl)
|
|
{
|
|
mod->next = *tailp;
|
|
*tailp = mod;
|
|
|
|
if (unlikely (dwfl->lookup_module != NULL))
|
|
{
|
|
free (dwfl->lookup_module);
|
|
dwfl->lookup_module = NULL;
|
|
}
|
|
|
|
return mod;
|
|
}
|
|
|
|
/* Report that a module called NAME spans addresses [START, END).
|
|
Returns the module handle, either existing or newly allocated,
|
|
or returns a null pointer for an allocation error. */
|
|
Dwfl_Module *
|
|
dwfl_report_module (Dwfl *dwfl, const char *name,
|
|
GElf_Addr start, GElf_Addr end)
|
|
{
|
|
Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
|
|
|
|
for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
|
|
{
|
|
if (m->low_addr == start && m->high_addr == end
|
|
&& !strcmp (m->name, name))
|
|
{
|
|
/* This module is still here. Move it to the place in the list
|
|
after the last module already reported. */
|
|
*prevp = m->next;
|
|
m->gc = false;
|
|
return use (m, tailp, dwfl);
|
|
}
|
|
|
|
if (! m->gc)
|
|
tailp = &m->next;
|
|
}
|
|
|
|
Dwfl_Module *mod = calloc (1, sizeof *mod);
|
|
if (mod == NULL)
|
|
goto nomem;
|
|
|
|
mod->name = strdup (name);
|
|
if (mod->name == NULL)
|
|
{
|
|
free (mod);
|
|
nomem:
|
|
__libdwfl_seterrno (DWFL_E_NOMEM);
|
|
return NULL;
|
|
}
|
|
|
|
mod->low_addr = start;
|
|
mod->high_addr = end;
|
|
mod->dwfl = dwfl;
|
|
|
|
return use (mod, tailp, dwfl);
|
|
}
|
|
INTDEF (dwfl_report_module)
|
|
|
|
|
|
/* Finish reporting the current set of modules to the library.
|
|
If REMOVED is not null, it's called for each module that
|
|
existed before but was not included in the current report.
|
|
Returns a nonzero return value from the callback.
|
|
DWFL cannot be used until this function has returned zero. */
|
|
int
|
|
dwfl_report_end (Dwfl *dwfl,
|
|
int (*removed) (Dwfl_Module *, void *,
|
|
const char *, Dwarf_Addr,
|
|
void *arg),
|
|
void *arg)
|
|
{
|
|
Dwfl_Module **tailp = &dwfl->modulelist;
|
|
while (*tailp != NULL)
|
|
{
|
|
Dwfl_Module *m = *tailp;
|
|
if (m->gc && removed != NULL)
|
|
{
|
|
int result = (*removed) (MODCB_ARGS (m), arg);
|
|
if (result != 0)
|
|
return result;
|
|
}
|
|
if (m->gc)
|
|
{
|
|
*tailp = m->next;
|
|
__libdwfl_module_free (m);
|
|
}
|
|
else
|
|
tailp = &m->next;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
INTDEF (dwfl_report_end)
|