]> git.ipfire.org Git - thirdparty/elfutils.git/blame - libelf/elf_end.c
funcretval-struct
[thirdparty/elfutils.git] / libelf / elf_end.c
CommitLineData
b08d5a8f 1/* Free resources associated with Elf descriptor.
e93f2d80 2 Copyright (C) 1998,1999,2000,2001,2002,2004,2005,2007,2015,2016 Red Hat, Inc.
35e059b6 3 Copyright (C) 2023 Mark J. Wielaard <mark@klomp.org>
de2ed97f 4 This file is part of elfutils.
b08d5a8f
UD
5 Written by Ulrich Drepper <drepper@redhat.com>, 1998.
6
de2ed97f
MW
7 This file is free software; you can redistribute it and/or modify
8 it under the terms of either
b08d5a8f 9
de2ed97f
MW
10 * the GNU Lesser General Public License as published by the Free
11 Software Foundation; either version 3 of the License, or (at
12 your option) any later version
13
14 or
15
16 * the GNU General Public License as published by the Free
17 Software Foundation; either version 2 of the License, or (at
18 your option) any later version
19
20 or both in parallel, as here.
21
22 elfutils is distributed in the hope that it will be useful, but
361df7da
UD
23 WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 General Public License for more details.
b08d5a8f 26
de2ed97f
MW
27 You should have received copies of the GNU General Public License and
28 the GNU Lesser General Public License along with this program. If
29 not, see <http://www.gnu.org/licenses/>. */
b08d5a8f
UD
30
31#ifdef HAVE_CONFIG_H
32# include <config.h>
33#endif
34
35#include <assert.h>
35e059b6 36#include <search.h>
b08d5a8f
UD
37#include <stddef.h>
38#include <stdlib.h>
b08d5a8f
UD
39
40#include "libelfP.h"
41
42
35e059b6
MW
43static void
44free_chunk (void *n)
45{
46 Elf_Data_Chunk *rawchunk = (Elf_Data_Chunk *)n;
47 if (rawchunk->dummy_scn.flags & ELF_F_MALLOCED)
48 free (rawchunk->data.d.d_buf);
49 free (rawchunk);
50}
51
b08d5a8f 52int
1ccdfb68 53elf_end (Elf *elf)
b08d5a8f
UD
54{
55 Elf *parent;
56
57 if (elf == NULL)
58 /* This is allowed and is a no-op. */
59 return 0;
60
61 /* Make sure we are alone. */
b4d6f0f8 62 rwlock_wrlock (elf->lock);
b08d5a8f
UD
63
64 if (elf->ref_count != 0 && --elf->ref_count != 0)
65 {
66 /* Not yet the last activation. */
67 int result = elf->ref_count;
b4d6f0f8 68 rwlock_unlock (elf->lock);
b08d5a8f
UD
69 return result;
70 }
71
72 if (elf->kind == ELF_K_AR)
73 {
74 /* We cannot remove the descriptor now since we still have some
75 descriptors which depend on it. But we can free the archive
76 symbol table since this is only available via the archive ELF
77 descriptor. The long name table cannot be freed yet since
78 the archive headers for the ELF files in the archive point
79 into this array. */
59ea7f33
RM
80 if (elf->state.ar.ar_sym != (Elf_Arsym *) -1l)
81 free (elf->state.ar.ar_sym);
b08d5a8f
UD
82 elf->state.ar.ar_sym = NULL;
83
84 if (elf->state.ar.children != NULL)
10aa68e6
HM
85 {
86 rwlock_unlock(elf->lock);
87 return 0;
88 }
b08d5a8f
UD
89 }
90
91 /* Remove this structure from the children list. */
92 parent = elf->parent;
93 if (parent != NULL)
94 {
95 /* This is tricky. Lock must be acquire from the father to
96 the child but here we already have the child lock. We
97 solve this problem by giving free the child lock. The
98 state of REF_COUNT==0 is handled all over the library, so
99 this should be ok. */
b4d6f0f8
RM
100 rwlock_unlock (elf->lock);
101 rwlock_rdlock (parent->lock);
102 rwlock_wrlock (elf->lock);
b08d5a8f
UD
103
104 if (parent->state.ar.children == elf)
105 parent->state.ar.children = elf->next;
106 else
107 {
108 struct Elf *child = parent->state.ar.children;
109
110 while (child->next != elf)
111 child = child->next;
112
113 child->next = elf->next;
114 }
115
b4d6f0f8 116 rwlock_unlock (parent->lock);
b08d5a8f
UD
117 }
118
119 /* This was the last activation. Free all resources. */
120 switch (elf->kind)
121 {
122 case ELF_K_AR:
123 if (elf->state.ar.long_names != NULL)
124 free (elf->state.ar.long_names);
125 break;
126
127 case ELF_K_ELF:
128 {
35e059b6 129 void *rawchunks
59ea7f33
RM
130 = (elf->class == ELFCLASS32
131 || (offsetof (struct Elf, state.elf32.rawchunks)
132 == offsetof (struct Elf, state.elf64.rawchunks))
133 ? elf->state.elf32.rawchunks
134 : elf->state.elf64.rawchunks);
35e059b6 135 tdestroy (rawchunks, free_chunk);
59ea7f33 136
b08d5a8f
UD
137 Elf_ScnList *list = (elf->class == ELFCLASS32
138 || (offsetof (struct Elf, state.elf32.scns)
139 == offsetof (struct Elf, state.elf64.scns))
140 ? &elf->state.elf32.scns
141 : &elf->state.elf64.scns);
142
143 do
144 {
145 /* Free all separately allocated section headers. */
146 size_t cnt = list->max;
147
148 while (cnt-- > 0)
149 {
150 /* These pointers can be NULL; it's safe to use
151 'free' since it will check for this. */
152 Elf_Scn *scn = &list->data[cnt];
153 Elf_Data_List *runp;
154
155 if ((scn->shdr_flags & ELF_F_MALLOCED) != 0)
156 /* It doesn't matter which pointer. */
157 free (scn->shdr.e32);
158
272018bb
MW
159 /* Free zdata if uncompressed, but not yet used as
160 rawdata_base. If it is already used it will be
161 freed below. */
162 if (scn->zdata_base != scn->rawdata_base)
27a84961
MW
163 {
164 free (scn->zdata_base);
165 scn->zdata_base = NULL;
166 }
272018bb 167
b08d5a8f
UD
168 /* If the file has the same byte order and the
169 architecture doesn't require overly stringent
170 alignment the raw data buffer is the same as the
171 one used for presenting to the caller. */
172 if (scn->data_base != scn->rawdata_base)
173 free (scn->data_base);
174
175 /* The section data is allocated if we couldn't mmap
272018bb
MW
176 the file. Or if we had to decompress. */
177 if (elf->map_address == NULL
e93f2d80
MW
178 || scn->rawdata_base == scn->zdata_base
179 || (scn->flags & ELF_F_MALLOCED) != 0)
b08d5a8f
UD
180 free (scn->rawdata_base);
181
182 /* Free the list of data buffers for the section.
183 We don't free the buffers themselves since this
184 is the users job. */
185 runp = scn->data_list.next;
186 while (runp != NULL)
187 {
188 Elf_Data_List *oldp = runp;
189 runp = runp->next;
190 if ((oldp->flags & ELF_F_MALLOCED) != 0)
191 free (oldp);
192 }
193 }
194
195 /* Free the memory for the array. */
196 Elf_ScnList *oldp = list;
197 list = list->next;
198 assert (list == NULL || oldp->cnt == oldp->max);
199 if (oldp != (elf->class == ELFCLASS32
200 || (offsetof (struct Elf, state.elf32.scns)
201 == offsetof (struct Elf, state.elf64.scns))
202 ? &elf->state.elf32.scns
203 : &elf->state.elf64.scns))
204 free (oldp);
205 }
206 while (list != NULL);
207 }
208
209 /* Free the section header. */
210 if (elf->state.elf.shdr_malloced != 0)
211 free (elf->class == ELFCLASS32
212 || (offsetof (struct Elf, state.elf32.shdr)
213 == offsetof (struct Elf, state.elf64.shdr))
214 ? (void *) elf->state.elf32.shdr
215 : (void *) elf->state.elf64.shdr);
216
217 /* Free the program header. */
218 if ((elf->state.elf.phdr_flags & ELF_F_MALLOCED) != 0)
219 free (elf->class == ELFCLASS32
220 || (offsetof (struct Elf, state.elf32.phdr)
221 == offsetof (struct Elf, state.elf64.phdr))
222 ? (void *) elf->state.elf32.phdr
223 : (void *) elf->state.elf64.phdr);
224 break;
225
226 default:
227 break;
228 }
229
230 if (elf->map_address != NULL && parent == NULL)
231 {
232 /* The file was read or mapped for this descriptor. */
233 if ((elf->flags & ELF_F_MALLOCED) != 0)
234 free (elf->map_address);
235 else if ((elf->flags & ELF_F_MMAPPED) != 0)
236 munmap (elf->map_address, elf->maximum_size);
237 }
238
49550161 239 rwlock_unlock (elf->lock);
b08d5a8f
UD
240 rwlock_fini (elf->lock);
241
242 /* Finally the descriptor itself. */
243 free (elf);
244
245 return (parent != NULL && parent->ref_count == 0
246 ? INTUSE(elf_end) (parent) : 0);
247}
248INTDEF(elf_end)