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