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