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