xref: /aosp_15_r20/external/elfutils/libelf/elf_end.c (revision 7304104da70ce23c86437a01be71edd1a2d7f37e)
1 /* Free resources associated with Elf descriptor.
2    Copyright (C) 1998,1999,2000,2001,2002,2004,2005,2007,2015,2016 Red Hat, Inc.
3    Copyright (C) 2023 Mark J. Wielaard <[email protected]>
4    This file is part of elfutils.
5    Written by Ulrich Drepper <[email protected]>, 1998.
6 
7    This file is free software; you can redistribute it and/or modify
8    it under the terms of either
9 
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
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.
26 
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/>.  */
30 
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
34 
35 #include <assert.h>
36 #include <search.h>
37 #include <stddef.h>
38 #include <stdlib.h>
39 
40 #include "libelfP.h"
41 
42 
43 static void
free_chunk(void * n)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 
52 int
elf_end(Elf * elf)53 elf_end (Elf *elf)
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.  */
62   rwlock_wrlock (elf->lock);
63 
64   if (elf->ref_count != 0 && --elf->ref_count != 0)
65     {
66       /* Not yet the last activation.  */
67       int result = elf->ref_count;
68       rwlock_unlock (elf->lock);
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.  */
80       if (elf->state.ar.ar_sym != (Elf_Arsym *) -1l)
81 	free (elf->state.ar.ar_sym);
82       elf->state.ar.ar_sym = NULL;
83 
84       if (elf->state.ar.children != NULL)
85 	{
86 	  rwlock_unlock(elf->lock);
87 	  return 0;
88 	}
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.  */
100       rwlock_unlock (elf->lock);
101       rwlock_rdlock (parent->lock);
102       rwlock_wrlock (elf->lock);
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 
116       rwlock_unlock (parent->lock);
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       {
129 	void *rawchunks
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);
135 	tdestroy (rawchunks, free_chunk);
136 
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 
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)
163 		  {
164 		    free (scn->zdata_base);
165 		    scn->zdata_base = NULL;
166 		  }
167 
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
176 		   the file.  Or if we had to decompress.  */
177 		if (elf->map_address == NULL
178 		    || scn->rawdata_base == scn->zdata_base
179 		    || (scn->flags & ELF_F_MALLOCED) != 0)
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 
239   rwlock_unlock (elf->lock);
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)
249