1 /* Create new ELF program header table. 2 Copyright (C) 1999-2010, 2014 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 <stdlib.h> 36 #include <string.h> 37 38 #include "libelfP.h" 39 40 #ifndef LIBELFBITS 41 # define LIBELFBITS 32 42 #endif 43 44 45 ElfW2(LIBELFBITS,Phdr) * 46 elfw2(LIBELFBITS,newphdr) (elf, count) 47 Elf *elf; 48 size_t count; 49 { ElfW2(LIBELFBITS,Phdr)50 ElfW2(LIBELFBITS,Phdr) *result; 51 52 if (elf == NULL) 53 return NULL; 54 55 if (unlikely (elf->kind != ELF_K_ELF)) 56 { 57 __libelf_seterrno (ELF_E_INVALID_HANDLE); 58 return NULL; 59 } 60 61 if (unlikely ((ElfW2(LIBELFBITS,Word)) count != count)) 62 { 63 __libelf_seterrno (ELF_E_INVALID_OPERAND); 64 return NULL; 65 } 66 67 rwlock_wrlock (elf->lock); 68 69 if (elf->class == 0) 70 elf->class = ELFW(ELFCLASS,LIBELFBITS); 71 else if (unlikely (elf->class != ELFW(ELFCLASS,LIBELFBITS))) 72 { 73 __libelf_seterrno (ELF_E_INVALID_CLASS); 74 result = NULL; 75 goto out; 76 } 77 78 if (unlikely (elf->state.ELFW(elf,LIBELFBITS).ehdr == NULL)) 79 { 80 __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); 81 result = NULL; 82 goto out; 83 } 84 85 /* A COUNT of zero means remove existing table. */ 86 if (count == 0) 87 { 88 /* Free the old program header. */ 89 if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL) 90 { 91 if (elf->state.ELFW(elf,LIBELFBITS).phdr_flags & ELF_F_MALLOCED) 92 free (elf->state.ELFW(elf,LIBELFBITS).phdr); 93 94 /* Set the pointer to NULL. */ 95 elf->state.ELFW(elf,LIBELFBITS).phdr = NULL; 96 /* Set the `e_phnum' member to the new value. */ 97 elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = 0; 98 /* Also clear any old PN_XNUM extended value. */ 99 if (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0) 100 elf->state.ELFW(elf,LIBELFBITS).scns.data[0] 101 .shdr.ELFW(e,LIBELFBITS)->sh_info = 0; 102 /* Also set the size. */ 103 elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize = 104 sizeof (ElfW2(LIBELFBITS,Phdr)); 105 106 elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_DIRTY; 107 elf->flags |= ELF_F_DIRTY; 108 __libelf_seterrno (ELF_E_NOERROR); 109 } 110 111 result = NULL; 112 } 113 else if (elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum != count 114 || count == PN_XNUM 115 || elf->state.ELFW(elf,LIBELFBITS).phdr == NULL) 116 { 117 if (unlikely (count > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Phdr)))) 118 { 119 result = NULL; 120 goto out; 121 } 122 123 /* Allocate a new program header with the appropriate number of 124 elements. */ 125 result = (ElfW2(LIBELFBITS,Phdr) *) 126 realloc (elf->state.ELFW(elf,LIBELFBITS).phdr, 127 count * sizeof (ElfW2(LIBELFBITS,Phdr))); 128 if (result == NULL) 129 __libelf_seterrno (ELF_E_NOMEM); 130 else 131 { 132 /* Now set the result. */ 133 elf->state.ELFW(elf,LIBELFBITS).phdr = result; 134 if (count >= PN_XNUM) 135 { 136 /* We have to write COUNT into the zeroth section's sh_info. */ 137 Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0]; 138 if (elf->state.ELFW(elf,LIBELFBITS).scns.cnt == 0) 139 { 140 assert (elf->state.ELFW(elf,LIBELFBITS).scns.max > 0); 141 elf->state.ELFW(elf,LIBELFBITS).scns.cnt = 1; 142 } 143 scn0->shdr.ELFW(e,LIBELFBITS)->sh_info = count; 144 scn0->shdr_flags |= ELF_F_DIRTY; 145 elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = PN_XNUM; 146 } 147 else 148 /* Set the `e_phnum' member to the new value. */ 149 elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = count; 150 /* Clear the whole memory. */ 151 memset (result, '\0', count * sizeof (ElfW2(LIBELFBITS,Phdr))); 152 /* Also set the size. */ 153 elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize = 154 elf_typesize (LIBELFBITS, ELF_T_PHDR, 1); 155 /* Remember we allocated the array and mark the structure is 156 modified. */ 157 elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= 158 ELF_F_DIRTY | ELF_F_MALLOCED; 159 /* We have to rewrite the entire file if the size of the 160 program header is changed. */ 161 elf->flags |= ELF_F_DIRTY; 162 } 163 } 164 else 165 { 166 /* We have the same number of entries. Just clear the array. */ 167 assert (elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize 168 == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1)); 169 170 /* Mark the structure as modified. */ 171 elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_DIRTY; 172 173 result = elf->state.ELFW(elf,LIBELFBITS).phdr; 174 memset (result, '\0', count * sizeof (ElfW2(LIBELFBITS,Phdr))); 175 } 176 177 out: 178 rwlock_unlock (elf->lock); 179 180 return result; 181 } 182 INTDEF(elfw2(LIBELFBITS,newphdr)) 183