Home | History | Annotate | Download | only in libdwfl
      1 /* Maintenance of module list in libdwfl.
      2    Copyright (C) 2005, 2006, 2007, 2008, 2014, 2015 Red Hat, Inc.
      3    This file is part of elfutils.
      4 
      5    This file is free software; you can redistribute it and/or modify
      6    it under the terms of either
      7 
      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
     11 
     12    or
     13 
     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
     17 
     18    or both in parallel, as here.
     19 
     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.
     24 
     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/>.  */
     28 
     29 #ifdef HAVE_CONFIG_H
     30 # include <config.h>
     31 #endif
     32 
     33 #include "libdwflP.h"
     34 #include "../libdw/cfi.h"
     35 #include <search.h>
     36 #include <unistd.h>
     37 
     38 static void
     39 free_cu (struct dwfl_cu *cu)
     40 {
     41   if (cu->lines != NULL)
     42     free (cu->lines);
     43   free (cu);
     44 }
     45 
     46 static void
     47 nofree (void *arg __attribute__ ((unused)))
     48 {
     49 }
     50 
     51 static void
     52 free_file (struct dwfl_file *file)
     53 {
     54   free (file->name);
     55 
     56   /* Close the fd only on the last reference.  */
     57   if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1)
     58     close (file->fd);
     59 }
     60 
     61 void
     62 internal_function
     63 __libdwfl_module_free (Dwfl_Module *mod)
     64 {
     65   if (mod->lazy_cu_root != NULL)
     66     tdestroy (mod->lazy_cu_root, nofree);
     67 
     68   if (mod->aranges != NULL)
     69     free (mod->aranges);
     70 
     71   if (mod->cu != NULL)
     72     {
     73       for (size_t i = 0; i < mod->ncu; ++i)
     74 	free_cu (mod->cu[i]);
     75       free (mod->cu);
     76     }
     77 
     78   /* We might have primed the Dwarf_CFI ebl cache with our own ebl
     79      in __libdwfl_set_cfi. Make sure we don't free it twice.  */
     80   if (mod->eh_cfi != NULL)
     81     {
     82       if (mod->eh_cfi->ebl != NULL && mod->eh_cfi->ebl == mod->ebl)
     83 	mod->eh_cfi->ebl = NULL;
     84       dwarf_cfi_end (mod->eh_cfi);
     85     }
     86 
     87   if (mod->dwarf_cfi != NULL)
     88     {
     89       if (mod->dwarf_cfi->ebl != NULL && mod->dwarf_cfi->ebl == mod->ebl)
     90 	mod->dwarf_cfi->ebl = NULL;
     91       /* We don't need to explicitly destroy the dwarf_cfi.
     92 	 That will be done by dwarf_end.  */
     93     }
     94 
     95   if (mod->dw != NULL)
     96     {
     97       INTUSE(dwarf_end) (mod->dw);
     98       if (mod->alt != NULL)
     99 	{
    100 	  INTUSE(dwarf_end) (mod->alt);
    101 	  if (mod->alt_elf != NULL)
    102 	    elf_end (mod->alt_elf);
    103 	  if (mod->alt_fd != -1)
    104 	    close (mod->alt_fd);
    105 	}
    106     }
    107 
    108   if (mod->ebl != NULL)
    109     ebl_closebackend (mod->ebl);
    110 
    111   if (mod->debug.elf != mod->main.elf)
    112     free_file (&mod->debug);
    113   free_file (&mod->main);
    114   free_file (&mod->aux_sym);
    115 
    116   if (mod->build_id_bits != NULL)
    117     free (mod->build_id_bits);
    118 
    119   if (mod->reloc_info != NULL)
    120     free (mod->reloc_info);
    121 
    122   free (mod->name);
    123   free (mod->elfdir);
    124   free (mod);
    125 }
    126 
    127 void
    128 dwfl_report_begin_add (Dwfl *dwfl __attribute__ ((unused)))
    129 {
    130   /* The lookup table will be cleared on demand, there is nothing we need
    131      to do here.  */
    132 }
    133 INTDEF (dwfl_report_begin_add)
    134 
    135 void
    136 dwfl_report_begin (Dwfl *dwfl)
    137 {
    138   /* Clear the segment lookup table.  */
    139   dwfl->lookup_elts = 0;
    140 
    141   for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
    142     m->gc = true;
    143 
    144   dwfl->offline_next_address = OFFLINE_REDZONE;
    145 }
    146 INTDEF (dwfl_report_begin)
    147 
    148 static inline Dwfl_Module *
    149 use (Dwfl_Module *mod, Dwfl_Module **tailp, Dwfl *dwfl)
    150 {
    151   mod->next = *tailp;
    152   *tailp = mod;
    153 
    154   if (unlikely (dwfl->lookup_module != NULL))
    155     {
    156       free (dwfl->lookup_module);
    157       dwfl->lookup_module = NULL;
    158     }
    159 
    160   return mod;
    161 }
    162 
    163 /* Report that a module called NAME spans addresses [START, END).
    164    Returns the module handle, either existing or newly allocated,
    165    or returns a null pointer for an allocation error.  */
    166 Dwfl_Module *
    167 dwfl_report_module (Dwfl *dwfl, const char *name,
    168 		    GElf_Addr start, GElf_Addr end)
    169 {
    170   Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
    171 
    172   for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
    173     {
    174       if (m->low_addr == start && m->high_addr == end
    175 	  && !strcmp (m->name, name))
    176 	{
    177 	  /* This module is still here.  Move it to the place in the list
    178 	     after the last module already reported.  */
    179 	  *prevp = m->next;
    180 	  m->gc = false;
    181 	  return use (m, tailp, dwfl);
    182 	}
    183 
    184       if (! m->gc)
    185 	tailp = &m->next;
    186     }
    187 
    188   Dwfl_Module *mod = calloc (1, sizeof *mod);
    189   if (mod == NULL)
    190     goto nomem;
    191 
    192   mod->name = strdup (name);
    193   if (mod->name == NULL)
    194     {
    195       free (mod);
    196     nomem:
    197       __libdwfl_seterrno (DWFL_E_NOMEM);
    198       return NULL;
    199     }
    200 
    201   mod->low_addr = start;
    202   mod->high_addr = end;
    203   mod->dwfl = dwfl;
    204 
    205   return use (mod, tailp, dwfl);
    206 }
    207 INTDEF (dwfl_report_module)
    208 
    209 
    210 /* Finish reporting the current set of modules to the library.
    211    If REMOVED is not null, it's called for each module that
    212    existed before but was not included in the current report.
    213    Returns a nonzero return value from the callback.
    214    DWFL cannot be used until this function has returned zero.  */
    215 int
    216 dwfl_report_end (Dwfl *dwfl,
    217 		 int (*removed) (Dwfl_Module *, void *,
    218 				 const char *, Dwarf_Addr,
    219 				 void *arg),
    220 		 void *arg)
    221 {
    222   Dwfl_Module **tailp = &dwfl->modulelist;
    223   while (*tailp != NULL)
    224     {
    225       Dwfl_Module *m = *tailp;
    226       if (m->gc && removed != NULL)
    227 	{
    228 	  int result = (*removed) (MODCB_ARGS (m), arg);
    229 	  if (result != 0)
    230 	    return result;
    231 	}
    232       if (m->gc)
    233 	{
    234 	  *tailp = m->next;
    235 	  __libdwfl_module_free (m);
    236 	}
    237       else
    238 	tailp = &m->next;
    239     }
    240 
    241   return 0;
    242 }
    243 INTDEF (dwfl_report_end)
    244