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