]>
Commit | Line | Data |
---|---|---|
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 |
43 | static void |
44 | free_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 | 52 | int |
1ccdfb68 | 53 | elf_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 | } | |
248 | INTDEF(elf_end) |