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