Blame libdwfl/dwfl_module.c

Packit Service 97d2fb
/* Maintenance of module list in libdwfl.
Packit Service 97d2fb
   Copyright (C) 2005, 2006, 2007, 2008, 2014, 2015 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/cfi.h"
Packit Service 97d2fb
#include <search.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
free_cu (struct dwfl_cu *cu)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (cu->lines != NULL)
Packit Service 97d2fb
    free (cu->lines);
Packit Service 97d2fb
  free (cu);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
nofree (void *arg __attribute__ ((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
static void
Packit Service 97d2fb
free_file (struct dwfl_file *file)
Packit Service 97d2fb
{
Packit Service 97d2fb
  free (file->name);
Packit Service 97d2fb
Packit Service 97d2fb
  /* Close the fd only on the last reference.  */
Packit Service 97d2fb
  if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1)
Packit Service 97d2fb
    close (file->fd);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
void
Packit Service 97d2fb
internal_function
Packit Service 97d2fb
__libdwfl_module_free (Dwfl_Module *mod)
Packit Service 97d2fb
{
Packit Service 97d2fb
  if (mod->lazy_cu_root != NULL)
Packit Service 97d2fb
    tdestroy (mod->lazy_cu_root, nofree);
Packit Service 97d2fb
Packit Service 97d2fb
  if (mod->aranges != NULL)
Packit Service 97d2fb
    free (mod->aranges);
Packit Service 97d2fb
Packit Service 97d2fb
  if (mod->cu != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      for (size_t i = 0; i < mod->ncu; ++i)
Packit Service 97d2fb
	free_cu (mod->cu[i]);
Packit Service 97d2fb
      free (mod->cu);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* We might have primed the Dwarf_CFI ebl cache with our own ebl
Packit Service 97d2fb
     in __libdwfl_set_cfi. Make sure we don't free it twice.  */
Packit Service 97d2fb
  if (mod->eh_cfi != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (mod->eh_cfi->ebl != NULL && mod->eh_cfi->ebl == mod->ebl)
Packit Service 97d2fb
	mod->eh_cfi->ebl = NULL;
Packit Service 97d2fb
      dwarf_cfi_end (mod->eh_cfi);
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (mod->dwarf_cfi != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (mod->dwarf_cfi->ebl != NULL && mod->dwarf_cfi->ebl == mod->ebl)
Packit Service 97d2fb
	mod->dwarf_cfi->ebl = NULL;
Packit Service 97d2fb
      /* We don't need to explicitly destroy the dwarf_cfi.
Packit Service 97d2fb
	 That will be done by dwarf_end.  */
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (mod->dw != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      INTUSE(dwarf_end) (mod->dw);
Packit Service 97d2fb
      if (mod->alt != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  INTUSE(dwarf_end) (mod->alt);
Packit Service 97d2fb
	  if (mod->alt_elf != NULL)
Packit Service 97d2fb
	    elf_end (mod->alt_elf);
Packit Service 97d2fb
	  if (mod->alt_fd != -1)
Packit Service 97d2fb
	    close (mod->alt_fd);
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (mod->ebl != NULL)
Packit Service 97d2fb
    ebl_closebackend (mod->ebl);
Packit Service 97d2fb
Packit Service 97d2fb
  if (mod->debug.elf != mod->main.elf)
Packit Service 97d2fb
    free_file (&mod->debug);
Packit Service 97d2fb
  free_file (&mod->main);
Packit Service 97d2fb
  free_file (&mod->aux_sym);
Packit Service 97d2fb
Packit Service 97d2fb
  if (mod->build_id_bits != NULL)
Packit Service 97d2fb
    free (mod->build_id_bits);
Packit Service 97d2fb
Packit Service 97d2fb
  if (mod->reloc_info != NULL)
Packit Service 97d2fb
    free (mod->reloc_info);
Packit Service 97d2fb
Packit Service 97d2fb
  free (mod->name);
Packit Service 97d2fb
  free (mod->elfdir);
Packit Service 97d2fb
  free (mod);
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
void
Packit Service 97d2fb
dwfl_report_begin_add (Dwfl *dwfl __attribute__ ((unused)))
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* The lookup table will be cleared on demand, there is nothing we need
Packit Service 97d2fb
     to do here.  */
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF (dwfl_report_begin_add)
Packit Service 97d2fb
Packit Service 97d2fb
void
Packit Service 97d2fb
dwfl_report_begin (Dwfl *dwfl)
Packit Service 97d2fb
{
Packit Service 97d2fb
  /* Clear the segment lookup table.  */
Packit Service 97d2fb
  dwfl->lookup_elts = 0;
Packit Service 97d2fb
Packit Service 97d2fb
  for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
Packit Service 97d2fb
    m->gc = true;
Packit Service 97d2fb
Packit Service 97d2fb
  dwfl->offline_next_address = OFFLINE_REDZONE;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF (dwfl_report_begin)
Packit Service 97d2fb
Packit Service 97d2fb
static inline Dwfl_Module *
Packit Service 97d2fb
use (Dwfl_Module *mod, Dwfl_Module **tailp, Dwfl *dwfl)
Packit Service 97d2fb
{
Packit Service 97d2fb
  mod->next = *tailp;
Packit Service 97d2fb
  *tailp = mod;
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (dwfl->lookup_module != NULL))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      free (dwfl->lookup_module);
Packit Service 97d2fb
      dwfl->lookup_module = NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return mod;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
/* Report that a module called NAME spans addresses [START, END).
Packit Service 97d2fb
   Returns the module handle, either existing or newly allocated,
Packit Service 97d2fb
   or returns a null pointer for an allocation error.  */
Packit Service 97d2fb
Dwfl_Module *
Packit Service 97d2fb
dwfl_report_module (Dwfl *dwfl, const char *name,
Packit Service 97d2fb
		    GElf_Addr start, GElf_Addr end)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
Packit Service 97d2fb
Packit Service 97d2fb
  for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (m->low_addr == start && m->high_addr == end
Packit Service 97d2fb
	  && !strcmp (m->name, name))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* This module is still here.  Move it to the place in the list
Packit Service 97d2fb
	     after the last module already reported.  */
Packit Service 97d2fb
	  *prevp = m->next;
Packit Service 97d2fb
	  m->gc = false;
Packit Service 97d2fb
	  return use (m, tailp, dwfl);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (! m->gc)
Packit Service 97d2fb
	tailp = &m->next;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  Dwfl_Module *mod = calloc (1, sizeof *mod);
Packit Service 97d2fb
  if (mod == NULL)
Packit Service 97d2fb
    goto nomem;
Packit Service 97d2fb
Packit Service 97d2fb
  mod->name = strdup (name);
Packit Service 97d2fb
  if (mod->name == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      free (mod);
Packit Service 97d2fb
    nomem:
Packit Service 97d2fb
      __libdwfl_seterrno (DWFL_E_NOMEM);
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  mod->low_addr = start;
Packit Service 97d2fb
  mod->high_addr = end;
Packit Service 97d2fb
  mod->dwfl = dwfl;
Packit Service 97d2fb
Packit Service 97d2fb
  return use (mod, tailp, dwfl);
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF (dwfl_report_module)
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
/* Finish reporting the current set of modules to the library.
Packit Service 97d2fb
   If REMOVED is not null, it's called for each module that
Packit Service 97d2fb
   existed before but was not included in the current report.
Packit Service 97d2fb
   Returns a nonzero return value from the callback.
Packit Service 97d2fb
   DWFL cannot be used until this function has returned zero.  */
Packit Service 97d2fb
int
Packit Service 97d2fb
dwfl_report_end (Dwfl *dwfl,
Packit Service 97d2fb
		 int (*removed) (Dwfl_Module *, void *,
Packit Service 97d2fb
				 const char *, Dwarf_Addr,
Packit Service 97d2fb
				 void *arg),
Packit Service 97d2fb
		 void *arg)
Packit Service 97d2fb
{
Packit Service 97d2fb
  Dwfl_Module **tailp = &dwfl->modulelist;
Packit Service 97d2fb
  while (*tailp != NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      Dwfl_Module *m = *tailp;
Packit Service 97d2fb
      if (m->gc && removed != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  int result = (*removed) (MODCB_ARGS (m), arg);
Packit Service 97d2fb
	  if (result != 0)
Packit Service 97d2fb
	    return result;
Packit Service 97d2fb
	}
Packit Service 97d2fb
      if (m->gc)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  *tailp = m->next;
Packit Service 97d2fb
	  __libdwfl_module_free (m);
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	tailp = &m->next;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  return 0;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF (dwfl_report_end)