Imported Upstream version 0.155
[platform/upstream/elfutils.git] / libelf / elf_end.c
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
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)