Adjust for monotone.
[platform/upstream/elfutils.git] / libdwfl / dwfl_module.c
1 /* Maintenance of module list in libdwfl.
2    Copyright (C) 2005 Red Hat, Inc.
3
4    This program is Open Source software; you can redistribute it and/or
5    modify it under the terms of the Open Software License version 1.0 as
6    published by the Open Source Initiative.
7
8    You should have received a copy of the Open Software License along
9    with this program; if not, you may obtain a copy of the Open Software
10    License version 1.0 from http://www.opensource.org/licenses/osl.php or
11    by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
12    3001 King Ranch Road, Ukiah, CA 95482.   */
13
14 #include "libdwflP.h"
15 #include <search.h>
16
17 static void
18 free_cu (struct dwfl_cu *cu)
19 {
20   if (cu->lines != NULL)
21     free (cu->lines);
22   free (cu);
23 }
24
25 static void
26 nofree (void *arg __attribute__ ((unused)))
27 {
28 }
29
30 void
31 internal_function_def
32 __libdwfl_module_free (Dwfl_Module *mod)
33 {
34   if (mod->lazy_cu_root != NULL)
35     tdestroy (mod->lazy_cu_root, nofree);
36
37   if (mod->aranges != NULL)
38     free (mod->aranges);
39
40   if (mod->cu != NULL)
41     {
42       for (size_t i = 0; i < mod->ncu; ++i)
43         free_cu (mod->cu[i]);
44       free (mod->cu);
45     }
46
47   if (mod->dw != NULL)
48     dwarf_end (mod->dw);
49
50   if (mod->ebl != NULL)
51     ebl_closebackend (mod->ebl);
52
53   if (mod->debug.elf != mod->main.elf && mod->debug.elf != NULL)
54     elf_end (mod->debug.elf);
55   if (mod->main.elf != NULL)
56     elf_end (mod->main.elf);
57
58   free (mod->name);
59 }
60
61 void
62 dwfl_report_begin (Dwfl *dwfl)
63 {
64   for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
65     m->gc = true;
66
67   if (dwfl->modules != NULL)
68     free (dwfl->modules);
69   dwfl->modules = NULL;
70   dwfl->nmodules = 0;
71 }
72 INTDEF (dwfl_report_begin)
73
74 /* Report that a module called NAME pans addresses [START, END).
75    Returns the module handle, either existing or newly allocated,
76    or returns a null pointer for an allocation error.  */
77 Dwfl_Module *
78 dwfl_report_module (Dwfl *dwfl, const char *name,
79                     GElf_Addr start, GElf_Addr end)
80 {
81   Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
82   for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
83     {
84       if (m->low_addr == start && m->high_addr == end
85           && !strcmp (m->name, name))
86         {
87           /* This module is still here.  Move it to the place in the list
88              after the last module already reported.  */
89
90           *prevp = m->next;
91           m->next = *tailp;
92           m->gc = false;
93           *tailp = m;
94           return m;
95         }
96
97       if (! m->gc)
98         tailp = &m->next;
99     }
100
101   Dwfl_Module *mod = calloc (1, sizeof *mod);
102   if (mod == NULL)
103     goto nomem;
104
105   mod->name = strdup (name);
106   if (mod->name == NULL)
107     {
108       free (mod);
109     nomem:
110       __libdwfl_seterrno (DWFL_E_NOMEM);
111       return NULL;
112     }
113
114   mod->low_addr = start;
115   mod->high_addr = end;
116   mod->dwfl = dwfl;
117
118   mod->next = *tailp;
119   *tailp = mod;
120   ++dwfl->nmodules;
121
122   return mod;
123 }
124 INTDEF (dwfl_report_module)
125
126 static int
127 compare_modules (const void *a, const void *b)
128 {
129   Dwfl_Module *const *p1 = a, *const *p2 = b;
130   const Dwfl_Module *m1 = *p1, *m2 = *p2;
131   if (m1 == NULL)
132     return -1;
133   if (m2 == NULL)
134     return 1;
135   return (GElf_Sxword) (m1->low_addr - m2->low_addr);
136 }
137
138
139 /* Finish reporting the current set of modules to the library.
140    If REMOVED is not null, it's called for each module that
141    existed before but was not included in the current report.
142    Returns a nonzero return value from the callback.
143    DWFL cannot be used until this function has returned zero.  */
144 int dwfl_report_end (Dwfl *dwfl,
145                      int (*removed) (Dwfl_Module *, void *,
146                                      const char *, Dwarf_Addr,
147                                      void *arg),
148                      void *arg)
149 {
150   assert (dwfl->modules == NULL);
151
152   Dwfl_Module **tailp = &dwfl->modulelist;
153   while (*tailp != NULL)
154     {
155       Dwfl_Module *m = *tailp;
156       if (m->gc && removed != NULL)
157         {
158           int result = (*removed) (MODCB_ARGS (m), arg);
159           if (result != 0)
160             return result;
161         }
162       if (m->gc)
163         {
164           *tailp = m->next;
165           __libdwfl_module_free (m);
166         }
167       else
168         tailp = &m->next;
169     }
170
171   dwfl->modules = malloc (dwfl->nmodules * sizeof dwfl->modules[0]);
172   if (dwfl->modules == NULL && dwfl->nmodules != 0)
173     return -1;
174
175   size_t i = 0;
176   for (Dwfl_Module *m = dwfl->modulelist; m != NULL; m = m->next)
177     {
178       assert (! m->gc);
179       dwfl->modules[i++] = m;
180     }
181   assert (i == dwfl->nmodules);
182
183   qsort (dwfl->modules, dwfl->nmodules, sizeof dwfl->modules[0],
184          &compare_modules);
185
186   return 0;
187 }
188 INTDEF (dwfl_report_end)