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