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