propagate from branch 'com.redhat.elfutils.roland.pending' (head e5cfdd13aa39dfae16b9...
[platform/upstream/elfutils.git] / libdwfl / dwfl_module.c
1 /* Maintenance of module list in libdwfl.
2    Copyright (C) 2005, 2006 Red Hat, Inc.
3    This file is part of Red Hat elfutils.
4
5    Red Hat elfutils is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by the
7    Free Software Foundation; version 2 of the License.
8
9    Red Hat elfutils is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    General Public License for more details.
13
14    You should have received a copy of the GNU General Public License along
15    with Red Hat elfutils; if not, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
17
18    In addition, as a special exception, Red Hat, Inc. gives You the
19    additional right to link the code of Red Hat elfutils with code licensed
20    under any Open Source Initiative certified open source license
21    (http://www.opensource.org/licenses/index.php) which requires the
22    distribution of source code with any binary distribution and to
23    distribute linked combinations of the two.  Non-GPL Code permitted under
24    this exception must only link to the code of Red Hat elfutils through
25    those well defined interfaces identified in the file named EXCEPTION
26    found in the source code files (the "Approved Interfaces").  The files
27    of Non-GPL Code may instantiate templates or use macros or inline
28    functions from the Approved Interfaces without causing the resulting
29    work to be covered by the GNU General Public License.  Only Red Hat,
30    Inc. may make changes or additions to the list of Approved Interfaces.
31    Red Hat's grant of this exception is conditioned upon your not adding
32    any new exceptions.  If you wish to add a new Approved Interface or
33    exception, please contact Red Hat.  You must obey the GNU General Public
34    License in all respects for all of the Red Hat elfutils code and other
35    code used in conjunction with Red Hat elfutils except the Non-GPL Code
36    covered by this exception.  If you modify this file, you may extend this
37    exception to your version of the file, but you are not obligated to do
38    so.  If you do not wish to provide this exception without modification,
39    you must delete this exception statement from your version and license
40    this file solely under the GPL without exception.
41
42    Red Hat elfutils is an included package of the Open Invention Network.
43    An included package of the Open Invention Network is a package for which
44    Open Invention Network licensees cross-license their patents.  No patent
45    license is granted, either expressly or impliedly, by designation as an
46    included package.  Should you wish to participate in the Open Invention
47    Network licensing program, please visit www.openinventionnetwork.com
48    <http://www.openinventionnetwork.com>.  */
49
50 #include "libdwflP.h"
51 #include <search.h>
52
53 static void
54 free_cu (struct dwfl_cu *cu)
55 {
56   if (cu->lines != NULL)
57     free (cu->lines);
58   free (cu);
59 }
60
61 static void
62 nofree (void *arg __attribute__ ((unused)))
63 {
64 }
65
66 void
67 internal_function_def
68 __libdwfl_module_free (Dwfl_Module *mod)
69 {
70   if (mod->lazy_cu_root != NULL)
71     tdestroy (mod->lazy_cu_root, nofree);
72
73   if (mod->aranges != NULL)
74     free (mod->aranges);
75
76   if (mod->cu != NULL)
77     {
78       for (size_t i = 0; i < mod->ncu; ++i)
79         free_cu (mod->cu[i]);
80       free (mod->cu);
81     }
82
83   if (mod->dw != NULL)
84     INTUSE(dwarf_end) (mod->dw);
85
86   if (mod->ebl != NULL)
87     ebl_closebackend (mod->ebl);
88
89   if (mod->debug.elf != mod->main.elf && mod->debug.elf != NULL)
90     elf_end (mod->debug.elf);
91   if (mod->main.elf != NULL)
92     elf_end (mod->main.elf);
93
94   free (mod->name);
95 }
96
97 void
98 dwfl_report_begin (Dwfl *dwfl)
99 {
100   for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
101     m->gc = true;
102
103   if (dwfl->modules != NULL)
104     free (dwfl->modules);
105   dwfl->modules = NULL;
106   dwfl->nmodules = 0;
107
108   dwfl->offline_next_address = OFFLINE_REDZONE;
109 }
110 INTDEF (dwfl_report_begin)
111
112 /* Report that a module called NAME pans addresses [START, END).
113    Returns the module handle, either existing or newly allocated,
114    or returns a null pointer for an allocation error.  */
115 Dwfl_Module *
116 dwfl_report_module (Dwfl *dwfl, const char *name,
117                     GElf_Addr start, GElf_Addr end)
118 {
119   Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
120   for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
121     {
122       if (m->low_addr == start && m->high_addr == end
123           && !strcmp (m->name, name))
124         {
125           /* This module is still here.  Move it to the place in the list
126              after the last module already reported.  */
127
128           *prevp = m->next;
129           m->next = *tailp;
130           m->gc = false;
131           *tailp = m;
132           return m;
133         }
134
135       if (! m->gc)
136         tailp = &m->next;
137     }
138
139   Dwfl_Module *mod = calloc (1, sizeof *mod);
140   if (mod == NULL)
141     goto nomem;
142
143   mod->name = strdup (name);
144   if (mod->name == NULL)
145     {
146       free (mod);
147     nomem:
148       __libdwfl_seterrno (DWFL_E_NOMEM);
149       return NULL;
150     }
151
152   mod->low_addr = start;
153   mod->high_addr = end;
154   mod->dwfl = dwfl;
155
156   mod->next = *tailp;
157   *tailp = mod;
158   ++dwfl->nmodules;
159
160   return mod;
161 }
162 INTDEF (dwfl_report_module)
163
164
165 static int
166 compare_modules (const void *a, const void *b)
167 {
168   Dwfl_Module *const *p1 = a, *const *p2 = b;
169   const Dwfl_Module *m1 = *p1, *m2 = *p2;
170   if (m1 == NULL)
171     return -1;
172   if (m2 == NULL)
173     return 1;
174
175   GElf_Sxword diff = m1->low_addr - m2->low_addr;
176   if (diff < 0)
177     return -1;
178   if (diff > 0)
179     return 1;
180   return 0;
181 }
182
183
184 /* Finish reporting the current set of modules to the library.
185    If REMOVED is not null, it's called for each module that
186    existed before but was not included in the current report.
187    Returns a nonzero return value from the callback.
188    DWFL cannot be used until this function has returned zero.  */
189 int
190 dwfl_report_end (Dwfl *dwfl,
191                  int (*removed) (Dwfl_Module *, void *,
192                                  const char *, Dwarf_Addr,
193                                  void *arg),
194                  void *arg)
195 {
196   assert (dwfl->modules == NULL);
197
198   Dwfl_Module **tailp = &dwfl->modulelist;
199   while (*tailp != NULL)
200     {
201       Dwfl_Module *m = *tailp;
202       if (m->gc && removed != NULL)
203         {
204           int result = (*removed) (MODCB_ARGS (m), arg);
205           if (result != 0)
206             return result;
207         }
208       if (m->gc)
209         {
210           *tailp = m->next;
211           __libdwfl_module_free (m);
212         }
213       else
214         tailp = &m->next;
215     }
216
217   dwfl->modules = malloc (dwfl->nmodules * sizeof dwfl->modules[0]);
218   if (dwfl->modules == NULL && dwfl->nmodules != 0)
219     return -1;
220
221   size_t i = 0;
222   for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
223     {
224       assert (! m->gc);
225       dwfl->modules[i++] = m;
226     }
227   assert (i == dwfl->nmodules);
228
229   qsort (dwfl->modules, dwfl->nmodules, sizeof dwfl->modules[0],
230          &compare_modules);
231
232   return 0;
233 }
234 INTDEF (dwfl_report_end)