Imported Upstream version 0.155
[platform/upstream/elfutils.git] / libdwfl / dwfl_module.c
1 /* Maintenance of module list in libdwfl.
2    Copyright (C) 2005, 2006, 2007, 2008 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     INTUSE(dwarf_end) (mod->dw);
75
76   if (mod->ebl != NULL)
77     ebl_closebackend (mod->ebl);
78
79   if (mod->debug.elf != mod->main.elf)
80     free_file (&mod->debug);
81   free_file (&mod->main);
82
83   if (mod->build_id_bits != NULL)
84     free (mod->build_id_bits);
85
86   free (mod->name);
87   free (mod);
88 }
89
90 void
91 dwfl_report_begin_add (Dwfl *dwfl __attribute__ ((unused)))
92 {
93   /* The lookup table will be cleared on demand, there is nothing we need
94      to do here.  */
95 }
96 INTDEF (dwfl_report_begin_add)
97
98 void
99 dwfl_report_begin (Dwfl *dwfl)
100 {
101   /* Clear the segment lookup table.  */
102   dwfl->lookup_elts = 0;
103
104   for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
105     m->gc = true;
106
107   dwfl->offline_next_address = OFFLINE_REDZONE;
108 }
109 INTDEF (dwfl_report_begin)
110
111 /* Report that a module called NAME spans addresses [START, END).
112    Returns the module handle, either existing or newly allocated,
113    or returns a null pointer for an allocation error.  */
114 Dwfl_Module *
115 dwfl_report_module (Dwfl *dwfl, const char *name,
116                     GElf_Addr start, GElf_Addr end)
117 {
118   Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
119
120   inline Dwfl_Module *use (Dwfl_Module *mod)
121   {
122     mod->next = *tailp;
123     *tailp = mod;
124
125     if (unlikely (dwfl->lookup_module != NULL))
126       {
127         free (dwfl->lookup_module);
128         dwfl->lookup_module = NULL;
129       }
130
131     return mod;
132   }
133
134   for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
135     {
136       if (m->low_addr == start && m->high_addr == end
137           && !strcmp (m->name, name))
138         {
139           /* This module is still here.  Move it to the place in the list
140              after the last module already reported.  */
141           *prevp = m->next;
142           m->gc = false;
143           return use (m);
144         }
145
146       if (! m->gc)
147         tailp = &m->next;
148     }
149
150   Dwfl_Module *mod = calloc (1, sizeof *mod);
151   if (mod == NULL)
152     goto nomem;
153
154   mod->name = strdup (name);
155   if (mod->name == NULL)
156     {
157       free (mod);
158     nomem:
159       __libdwfl_seterrno (DWFL_E_NOMEM);
160       return NULL;
161     }
162
163   mod->low_addr = start;
164   mod->high_addr = end;
165   mod->dwfl = dwfl;
166
167   return use (mod);
168 }
169 INTDEF (dwfl_report_module)
170
171
172 /* Finish reporting the current set of modules to the library.
173    If REMOVED is not null, it's called for each module that
174    existed before but was not included in the current report.
175    Returns a nonzero return value from the callback.
176    DWFL cannot be used until this function has returned zero.  */
177 int
178 dwfl_report_end (Dwfl *dwfl,
179                  int (*removed) (Dwfl_Module *, void *,
180                                  const char *, Dwarf_Addr,
181                                  void *arg),
182                  void *arg)
183 {
184   Dwfl_Module **tailp = &dwfl->modulelist;
185   while (*tailp != NULL)
186     {
187       Dwfl_Module *m = *tailp;
188       if (m->gc && removed != NULL)
189         {
190           int result = (*removed) (MODCB_ARGS (m), arg);
191           if (result != 0)
192             return result;
193         }
194       if (m->gc)
195         {
196           *tailp = m->next;
197           __libdwfl_module_free (m);
198         }
199       else
200         tailp = &m->next;
201     }
202
203   return 0;
204 }
205 INTDEF (dwfl_report_end)