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