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