Blame libdwfl/dwfl_module.c

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