xref: /aosp_15_r20/external/elfutils/libelf/elf_end.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
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