Home | History | Annotate | Download | only in libelf
      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 (at) 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 
     30 int
     31 elf_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