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