packaging: update homepage url
[platform/upstream/elfutils.git] / libelf / elf32_newphdr.c
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
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))