Imported Upstream version 0.155
[platform/upstream/elfutils.git] / libelf / elf32_updatenull.c
1 /* Update data structures for changes.
2    Copyright (C) 2000-2010 Red Hat, Inc.
3    This file is part of elfutils.
4    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
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 <endian.h>
36 #include <libelf.h>
37 #include <stdbool.h>
38 #include <string.h>
39 #include <sys/param.h>
40
41 #include "libelfP.h"
42 #include "elf-knowledge.h"
43
44 #ifndef LIBELFBITS
45 # define LIBELFBITS 32
46 #endif
47
48
49
50 static int
51 ELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr,
52                                size_t shnum, int *change_bop)
53 {
54   /* Always write the magic bytes.  */
55   if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
56     {
57       memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG);
58       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
59     }
60
61   /* Always set the file class.  */
62   update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS),
63                      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
64
65   /* Set the data encoding if necessary.  */
66   if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE))
67     {
68       ehdr->e_ident[EI_DATA] =
69         BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB;
70       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
71     }
72   else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM))
73     {
74       __libelf_seterrno (ELF_E_DATA_ENCODING);
75       return 1;
76     }
77   else
78     *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN
79                     && ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
80                    || (BYTE_ORDER == BIG_ENDIAN
81                        && ehdr->e_ident[EI_DATA] != ELFDATA2MSB));
82
83   /* Unconditionally overwrite the ELF version.  */
84   update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT,
85                      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
86
87   if (unlikely (ehdr->e_version == EV_NONE)
88       || unlikely (ehdr->e_version >= EV_NUM))
89     {
90       __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
91       return 1;
92     }
93
94   if (unlikely (shnum >= SHN_LORESERVE))
95     {
96       update_if_changed (ehdr->e_shnum, 0,
97                          elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
98     }
99   else
100     update_if_changed (ehdr->e_shnum, shnum,
101                        elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
102
103   if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)))
104     {
105       ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
106       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
107     }
108
109   return 0;
110 }
111
112
113 off_t
114 internal_function
115 __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
116 {
117   ElfW2(LIBELFBITS,Ehdr) *ehdr;
118   int changed = 0;
119   int ehdr_flags = 0;
120
121   ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf);
122
123   /* Set the default values.  */
124   if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
125     return -1;
126
127   /* At least the ELF header is there.  */
128   off_t size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
129
130   /* Set the program header position.  */
131   if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL
132       && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN
133           || ehdr->e_type == ET_CORE))
134     (void) __elfw2(LIBELFBITS,getphdr_wrlock) (elf);
135   if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
136     {
137       /* Only executables, shared objects, and core files have a program
138          header.  */
139       if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN
140           && unlikely (ehdr->e_type != ET_CORE))
141         {
142           __libelf_seterrno (ELF_E_INVALID_PHDR);
143           return -1;
144         }
145
146       size_t phnum;
147       if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
148         return -1;
149
150       if (elf->flags & ELF_F_LAYOUT)
151         {
152           /* The user is supposed to fill out e_phoff.  Use it and
153              e_phnum to determine the maximum extend.  */
154           size = MAX ((size_t) size,
155                       ehdr->e_phoff
156                       + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
157         }
158       else
159         {
160           update_if_changed (ehdr->e_phoff,
161                              elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
162                              ehdr_flags);
163
164           /* We need no alignment here.  */
165           size += elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum);
166         }
167     }
168
169   if (shnum > 0)
170     {
171       Elf_ScnList *list;
172       bool first = true;
173
174       assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0);
175
176       if (shnum >= SHN_LORESERVE)
177         {
178           /* We have to  fill in the number of sections in the header
179              of the zeroth section.  */
180           Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0];
181
182           update_if_changed (scn0->shdr.ELFW(e,LIBELFBITS)->sh_size,
183                              shnum, scn0->shdr_flags);
184         }
185
186       /* Go over all sections and find out how large they are.  */
187       list = &elf->state.ELFW(elf,LIBELFBITS).scns;
188
189       /* Load the section headers if necessary.  This loads the
190          headers for all sections.  */
191       if (list->data[1].shdr.ELFW(e,LIBELFBITS) == NULL)
192         (void) __elfw2(LIBELFBITS,getshdr_wrlock) (&list->data[1]);
193
194       do
195         {
196           for (size_t cnt = first == true; cnt < list->cnt; ++cnt)
197             {
198               Elf_Scn *scn = &list->data[cnt];
199               ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
200               off_t offset = 0;
201
202               assert (shdr != NULL);
203               ElfW2(LIBELFBITS,Word) sh_entsize = shdr->sh_entsize;
204               ElfW2(LIBELFBITS,Word) sh_align = shdr->sh_addralign ?: 1;
205
206               /* Set the sh_entsize value if we can reliably detect it.  */
207               switch (shdr->sh_type)
208                 {
209                 case SHT_SYMTAB:
210                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
211                   break;
212                 case SHT_RELA:
213                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1);
214                   break;
215                 case SHT_GROUP:
216                   /* Only relocatable files can contain section groups.  */
217                   if (ehdr->e_type != ET_REL)
218                     {
219                       __libelf_seterrno (ELF_E_GROUP_NOT_REL);
220                       return -1;
221                     }
222                   /* FALLTHROUGH */
223                 case SHT_SYMTAB_SHNDX:
224                   sh_entsize = elf_typesize (32, ELF_T_WORD, 1);
225                   break;
226                 case SHT_HASH:
227                   sh_entsize = SH_ENTSIZE_HASH (ehdr);
228                   break;
229                 case SHT_DYNAMIC:
230                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1);
231                   break;
232                 case SHT_REL:
233                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1);
234                   break;
235                 case SHT_DYNSYM:
236                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
237                   break;
238                 case SHT_SUNW_move:
239                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1);
240                   break;
241                 case SHT_SUNW_syminfo:
242                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1);
243                   break;
244                 default:
245                   break;
246                 }
247
248               /* If the section header contained the wrong entry size
249                  correct it and mark the header as modified.  */
250               update_if_changed (shdr->sh_entsize, sh_entsize,
251                                  scn->shdr_flags);
252
253               if (scn->data_read == 0
254                   && __libelf_set_rawdata_wrlock (scn) != 0)
255                 /* Something went wrong.  The error value is already set.  */
256                 return -1;
257
258               /* Iterate over all data blocks.  */
259               if (list->data[cnt].data_list_rear != NULL)
260                 {
261                   Elf_Data_List *dl = &scn->data_list;
262
263                   while (dl != NULL)
264                     {
265                       Elf_Data *data = &dl->data.d;
266                       if (dl == &scn->data_list && data->d_buf == NULL
267                           && scn->rawdata.d.d_buf != NULL)
268                         data = &scn->rawdata.d;
269
270                       if (unlikely (data->d_version == EV_NONE)
271                           || unlikely (data->d_version >= EV_NUM))
272                         {
273                           __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
274                           return -1;
275                         }
276
277                       if (unlikely (! powerof2 (data->d_align)))
278                         {
279                           __libelf_seterrno (ELF_E_INVALID_ALIGN);
280                           return -1;
281                         }
282
283                       sh_align = MAX (sh_align, data->d_align);
284
285                       if (elf->flags & ELF_F_LAYOUT)
286                         {
287                           /* The user specified the offset and the size.
288                              All we have to do is check whether this block
289                              fits in the size specified for the section.  */
290                           if (unlikely ((GElf_Word) (data->d_off
291                                                      + data->d_size)
292                                         > shdr->sh_size))
293                             {
294                               __libelf_seterrno (ELF_E_SECTION_TOO_SMALL);
295                               return -1;
296                             }
297                         }
298                       else
299                         {
300                           /* Determine the padding.  */
301                           offset = ((offset + data->d_align - 1)
302                                     & ~(data->d_align - 1));
303
304                           update_if_changed (data->d_off, offset, changed);
305
306                           offset += data->d_size;
307                         }
308
309                       /* Next data block.  */
310                       dl = dl->next;
311                     }
312                 }
313               else
314                 /* Get the size of the section from the raw data.  If
315                    none is available the value is zero.  */
316                 offset += scn->rawdata.d.d_size;
317
318               if (elf->flags & ELF_F_LAYOUT)
319                 {
320                   size = MAX ((GElf_Word) size,
321                               shdr->sh_offset
322                               + (shdr->sh_type != SHT_NOBITS
323                                  ? shdr->sh_size : 0));
324
325                   /* The alignment must be a power of two.  This is a
326                      requirement from the ELF specification.  Additionally
327                      we test for the alignment of the section being large
328                      enough for the largest alignment required by a data
329                      block.  */
330                   if (unlikely (! powerof2 (shdr->sh_addralign))
331                       || unlikely (shdr->sh_addralign < sh_align))
332                     {
333                       __libelf_seterrno (ELF_E_INVALID_ALIGN);
334                       return -1;
335                     }
336                 }
337               else
338                 {
339                   /* How much alignment do we need for this section.  */
340                   update_if_changed (shdr->sh_addralign, sh_align,
341                                      scn->shdr_flags);
342
343                   size = (size + sh_align - 1) & ~(sh_align - 1);
344                   int offset_changed = 0;
345                   update_if_changed (shdr->sh_offset, (GElf_Word) size,
346                                      offset_changed);
347                   changed |= offset_changed;
348
349                   if (offset_changed && scn->data_list_rear == NULL)
350                     {
351                       /* The position of the section in the file
352                          changed.  Create the section data list.  */
353                       if (__elf_getdata_rdlock (scn, NULL) == NULL)
354                         return -1;
355                     }
356
357                   /* See whether the section size is correct.  */
358                   update_if_changed (shdr->sh_size, (GElf_Word) offset,
359                                      changed);
360
361                   if (shdr->sh_type != SHT_NOBITS)
362                     size += offset;
363
364                   scn->flags |= changed;
365                 }
366
367               /* Check that the section size is actually a multiple of
368                  the entry size.  */
369               if (shdr->sh_entsize != 0
370                   && unlikely (shdr->sh_size % shdr->sh_entsize != 0)
371                   && (elf->flags & ELF_F_PERMISSIVE) == 0)
372                 {
373                   __libelf_seterrno (ELF_E_INVALID_SHENTSIZE);
374                   return -1;
375                 }
376             }
377
378           assert (list->next == NULL || list->cnt == list->max);
379
380           first = false;
381         }
382       while ((list = list->next) != NULL);
383
384       /* Store section information.  */
385       if (elf->flags & ELF_F_LAYOUT)
386         {
387           /* The user is supposed to fill out e_shoff.  Use it and
388              e_shnum (or sh_size of the dummy, first section header)
389              to determine the maximum extend.  */
390           size = MAX ((GElf_Word) size,
391                       (ehdr->e_shoff
392                        + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum))));
393         }
394       else
395         {
396           /* Align for section header table.
397
398              Yes, we use `sizeof' and not `__alignof__' since we do not
399              want to be surprised by architectures with less strict
400              alignment rules.  */
401 #define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off))
402           size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1);
403
404           update_if_changed (ehdr->e_shoff, (GElf_Word) size, elf->flags);
405           update_if_changed (ehdr->e_shentsize,
406                              elf_typesize (LIBELFBITS, ELF_T_SHDR, 1),
407                              ehdr_flags);
408
409           /* Account for the section header size.  */
410           size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum);
411         }
412     }
413
414   elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags;
415
416   return size;
417 }