5ce8bbc948e9bda0524ddd2f564fcf0a283ee7c0
[platform/upstream/elfutils.git] / libelf / elf32_updatenull.c
1 /* Update data structures for changes.
2    Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 Red Hat, Inc.
3    This file is part of Red Hat elfutils.
4    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5
6    Red Hat elfutils is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by the
8    Free Software Foundation; version 2 of the License.
9
10    Red Hat elfutils is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License along
16    with Red Hat elfutils; if not, write to the Free Software Foundation,
17    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
18
19    In addition, as a special exception, Red Hat, Inc. gives You the
20    additional right to link the code of Red Hat elfutils with code licensed
21    under any Open Source Initiative certified open source license
22    (http://www.opensource.org/licenses/index.php) which requires the
23    distribution of source code with any binary distribution and to
24    distribute linked combinations of the two.  Non-GPL Code permitted under
25    this exception must only link to the code of Red Hat elfutils through
26    those well defined interfaces identified in the file named EXCEPTION
27    found in the source code files (the "Approved Interfaces").  The files
28    of Non-GPL Code may instantiate templates or use macros or inline
29    functions from the Approved Interfaces without causing the resulting
30    work to be covered by the GNU General Public License.  Only Red Hat,
31    Inc. may make changes or additions to the list of Approved Interfaces.
32    Red Hat's grant of this exception is conditioned upon your not adding
33    any new exceptions.  If you wish to add a new Approved Interface or
34    exception, please contact Red Hat.  You must obey the GNU General Public
35    License in all respects for all of the Red Hat elfutils code and other
36    code used in conjunction with Red Hat elfutils except the Non-GPL Code
37    covered by this exception.  If you modify this file, you may extend this
38    exception to your version of the file, but you are not obligated to do
39    so.  If you do not wish to provide this exception without modification,
40    you must delete this exception statement from your version and license
41    this file solely under the GPL without exception.
42
43    Red Hat elfutils is an included package of the Open Invention Network.
44    An included package of the Open Invention Network is a package for which
45    Open Invention Network licensees cross-license their patents.  No patent
46    license is granted, either expressly or impliedly, by designation as an
47    included package.  Should you wish to participate in the Open Invention
48    Network licensing program, please visit www.openinventionnetwork.com
49    <http://www.openinventionnetwork.com>.  */
50
51 #ifdef HAVE_CONFIG_H
52 # include <config.h>
53 #endif
54
55 #include <assert.h>
56 #include <endian.h>
57 #include <libelf.h>
58 #include <stdbool.h>
59 #include <string.h>
60 #include <sys/param.h>
61
62 #include "libelfP.h"
63 #include "elf-knowledge.h"
64
65 #ifndef LIBELFBITS
66 # define LIBELFBITS 32
67 #endif
68
69
70
71 static int
72 ELFW(default_ehdr,LIBELFBITS) (Elf *elf, ElfW2(LIBELFBITS,Ehdr) *ehdr,
73                                size_t shnum, int *change_bop)
74 {
75   /* Always write the magic bytes.  */
76   if (memcmp (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG) != 0)
77     {
78       memcpy (&ehdr->e_ident[EI_MAG0], ELFMAG, SELFMAG);
79       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
80     }
81
82   /* Always set the file class.  */
83   update_if_changed (ehdr->e_ident[EI_CLASS], ELFW(ELFCLASS,LIBELFBITS),
84                      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
85
86   /* Set the data encoding if necessary.  */
87   if (unlikely (ehdr->e_ident[EI_DATA] == ELFDATANONE))
88     {
89       ehdr->e_ident[EI_DATA] =
90         BYTE_ORDER == BIG_ENDIAN ? ELFDATA2MSB : ELFDATA2LSB;
91       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
92     }
93   else if (unlikely (ehdr->e_ident[EI_DATA] >= ELFDATANUM))
94     {
95       __libelf_seterrno (ELF_E_DATA_ENCODING);
96       return 1;
97     }
98   else
99     *change_bop = ((BYTE_ORDER == LITTLE_ENDIAN
100                     && ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
101                    || (BYTE_ORDER == BIG_ENDIAN
102                        && ehdr->e_ident[EI_DATA] != ELFDATA2MSB));
103
104   /* Unconditionally overwrite the ELF version.  */
105   update_if_changed (ehdr->e_ident[EI_VERSION], EV_CURRENT,
106                      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
107
108   if (unlikely (ehdr->e_version == EV_NONE)
109       || unlikely (ehdr->e_version >= EV_NUM))
110     {
111       __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
112       return 1;
113     }
114
115   if (unlikely (shnum >= SHN_LORESERVE))
116     {
117       update_if_changed (ehdr->e_shnum, 0,
118                          elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
119     }
120   else
121     update_if_changed (ehdr->e_shnum, shnum,
122                        elf->state.ELFW(elf,LIBELFBITS).ehdr_flags);
123
124   if (unlikely (ehdr->e_ehsize != elf_typesize (LIBELFBITS, ELF_T_EHDR, 1)))
125     {
126       ehdr->e_ehsize = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
127       elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ELF_F_DIRTY;
128     }
129
130   return 0;
131 }
132
133
134 off_t
135 internal_function
136 __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
137 {
138   ElfW2(LIBELFBITS,Ehdr) *ehdr;
139   int changed = 0;
140   int ehdr_flags = 0;
141
142   ehdr = __elfw2(LIBELFBITS,getehdr_wrlock) (elf);
143
144   /* Set the default values.  */
145   if (ELFW(default_ehdr,LIBELFBITS) (elf, ehdr, shnum, change_bop) != 0)
146     return -1;
147
148   /* At least the ELF header is there.  */
149   off_t size = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
150
151   /* Set the program header position.  */
152   if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL
153       && (ehdr->e_type == ET_EXEC || ehdr->e_type == ET_DYN
154           || ehdr->e_type == ET_CORE))
155     (void) __elfw2(LIBELFBITS,getphdr_wrlock) (elf);
156   if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
157     {
158       /* Only executables, shared objects, and core files have a program
159          header.  */
160       if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN
161           && unlikely (ehdr->e_type != ET_CORE))
162         {
163           __libelf_seterrno (ELF_E_INVALID_PHDR);
164           return -1;
165         }
166
167       if (elf->flags & ELF_F_LAYOUT)
168         {
169           /* The user is supposed to fill out e_phoff.  Use it and
170              e_phnum to determine the maximum extend.  */
171           size = MAX ((size_t) size,
172                       ehdr->e_phoff
173                       + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum));
174         }
175       else
176         {
177           update_if_changed (ehdr->e_phoff,
178                              elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
179                              ehdr_flags);
180
181           /* We need no alignment here.  */
182           size += elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum);
183         }
184     }
185
186   if (shnum > 0)
187     {
188       Elf_ScnList *list;
189       bool first = true;
190
191       assert (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0);
192
193       if (shnum >= SHN_LORESERVE)
194         {
195           /* We have to  fill in the number of sections in the header
196              of the zeroth section.  */
197           Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0];
198
199           update_if_changed (scn0->shdr.ELFW(e,LIBELFBITS)->sh_size,
200                              shnum, scn0->shdr_flags);
201         }
202
203       /* Go over all sections and find out how large they are.  */
204       list = &elf->state.ELFW(elf,LIBELFBITS).scns;
205
206       /* Load the section headers if necessary.  This loads the
207          headers for all sections.  */
208       if (list->data[1].shdr.ELFW(e,LIBELFBITS) == NULL)
209         (void) __elfw2(LIBELFBITS,getshdr_wrlock) (&list->data[1]);
210
211       do
212         {
213           for (size_t cnt = first == true; cnt < list->cnt; ++cnt)
214             {
215               Elf_Scn *scn = &list->data[cnt];
216               ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
217               off_t offset = 0;
218
219               assert (shdr != NULL);
220               ElfW2(LIBELFBITS,Word) sh_entsize = shdr->sh_entsize;
221               ElfW2(LIBELFBITS,Word) sh_align = shdr->sh_addralign ?: 1;
222
223               /* Set the sh_entsize value if we can reliably detect it.  */
224               switch (shdr->sh_type)
225                 {
226                 case SHT_SYMTAB:
227                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
228                   break;
229                 case SHT_RELA:
230                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_RELA, 1);
231                   break;
232                 case SHT_GROUP:
233                   /* Only relocatable files can contain section groups.  */
234                   if (ehdr->e_type != ET_REL)
235                     {
236                       __libelf_seterrno (ELF_E_GROUP_NOT_REL);
237                       return -1;
238                     }
239                   /* FALLTHROUGH */
240                 case SHT_SYMTAB_SHNDX:
241                   sh_entsize = elf_typesize (32, ELF_T_WORD, 1);
242                   break;
243                 case SHT_HASH:
244                   sh_entsize = SH_ENTSIZE_HASH (ehdr);
245                   break;
246                 case SHT_DYNAMIC:
247                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_DYN, 1);
248                   break;
249                 case SHT_REL:
250                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_REL, 1);
251                   break;
252                 case SHT_DYNSYM:
253                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYM, 1);
254                   break;
255                 case SHT_SUNW_move:
256                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_MOVE, 1);
257                   break;
258                 case SHT_SUNW_syminfo:
259                   sh_entsize = elf_typesize (LIBELFBITS, ELF_T_SYMINFO, 1);
260                   break;
261                 default:
262                   break;
263                 }
264
265               /* If the section header contained the wrong entry size
266                  correct it and mark the header as modified.  */
267               update_if_changed (shdr->sh_entsize, sh_entsize,
268                                  scn->shdr_flags);
269
270               if (scn->data_read == 0
271                   && __libelf_set_rawdata_wrlock (scn) != 0)
272                 /* Something went wrong.  The error value is already set.  */
273                 return -1;
274
275               /* Iterate over all data blocks.  */
276               if (list->data[cnt].data_list_rear != NULL)
277                 {
278                   Elf_Data_List *dl = &scn->data_list;
279
280                   while (dl != NULL)
281                     {
282                       Elf_Data *data = &dl->data.d;
283                       if (dl == &scn->data_list && data->d_buf == NULL
284                           && scn->rawdata.d.d_buf != NULL)
285                         data = &scn->rawdata.d;
286
287                       if (unlikely (data->d_version == EV_NONE)
288                           || unlikely (data->d_version >= EV_NUM))
289                         {
290                           __libelf_seterrno (ELF_E_UNKNOWN_VERSION);
291                           return -1;
292                         }
293
294                       if (unlikely (! powerof2 (data->d_align)))
295                         {
296                           __libelf_seterrno (ELF_E_INVALID_ALIGN);
297                           return -1;
298                         }
299
300                       sh_align = MAX (sh_align, data->d_align);
301
302                       if (elf->flags & ELF_F_LAYOUT)
303                         {
304                           /* The user specified the offset and the size.
305                              All we have to do is check whether this block
306                              fits in the size specified for the section.  */
307                           if (unlikely ((GElf_Word) (data->d_off
308                                                      + data->d_size)
309                                         > shdr->sh_size))
310                             {
311                               __libelf_seterrno (ELF_E_SECTION_TOO_SMALL);
312                               return -1;
313                             }
314                         }
315                       else
316                         {
317                           /* Determine the padding.  */
318                           offset = ((offset + data->d_align - 1)
319                                     & ~(data->d_align - 1));
320
321                           update_if_changed (data->d_off, offset, changed);
322
323                           offset += data->d_size;
324                         }
325
326                       /* Next data block.  */
327                       dl = dl->next;
328                     }
329                 }
330               else
331                 /* Get the size of the section from the raw data.  If
332                    none is available the value is zero.  */
333                 offset += scn->rawdata.d.d_size;
334
335               if (elf->flags & ELF_F_LAYOUT)
336                 {
337                   size = MAX ((GElf_Word) size,
338                               shdr->sh_offset
339                               + (shdr->sh_type != SHT_NOBITS
340                                  ? shdr->sh_size : 0));
341
342                   /* The alignment must be a power of two.  This is a
343                      requirement from the ELF specification.  Additionally
344                      we test for the alignment of the section being large
345                      enough for the largest alignment required by a data
346                      block.  */
347                   if (unlikely (! powerof2 (shdr->sh_addralign))
348                       || unlikely (shdr->sh_addralign < sh_align))
349                     {
350                       __libelf_seterrno (ELF_E_INVALID_ALIGN);
351                       return -1;
352                     }
353                 }
354               else
355                 {
356                   /* How much alignment do we need for this section.  */
357                   update_if_changed (shdr->sh_addralign, sh_align,
358                                      scn->shdr_flags);
359
360                   size = (size + sh_align - 1) & ~(sh_align - 1);
361                   int offset_changed = 0;
362                   update_if_changed (shdr->sh_offset, (GElf_Word) size,
363                                      offset_changed);
364                   changed |= offset_changed;
365
366                   if (offset_changed && scn->data_list_rear == NULL)
367                     {
368                       /* The position of the section in the file
369                          changed.  Create the section data list.  */
370                       if (__elf_getdata_rdlock (scn, NULL) == NULL)
371                         return -1;
372                     }
373
374                   /* See whether the section size is correct.  */
375                   update_if_changed (shdr->sh_size, (GElf_Word) offset,
376                                      changed);
377
378                   if (shdr->sh_type != SHT_NOBITS)
379                     size += offset;
380
381                   scn->flags |= changed;
382                 }
383
384               /* Check that the section size is actually a multiple of
385                  the entry size.  */
386               if (shdr->sh_entsize != 0
387                   && unlikely (shdr->sh_size % shdr->sh_entsize != 0)
388                   && (elf->flags & ELF_F_PERMISSIVE) == 0)
389                 {
390                   __libelf_seterrno (ELF_E_INVALID_SHENTSIZE);
391                   return -1;
392                 }
393             }
394
395           assert (list->next == NULL || list->cnt == list->max);
396
397           first = false;
398         }
399       while ((list = list->next) != NULL);
400
401       /* Store section information.  */
402       if (elf->flags & ELF_F_LAYOUT)
403         {
404           /* The user is supposed to fill out e_shoff.  Use it and
405              e_shnum (or sh_size of the dummy, first section header)
406              to determine the maximum extend.  */
407           size = MAX ((GElf_Word) size,
408                       (ehdr->e_shoff
409                        + (elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum))));
410         }
411       else
412         {
413           /* Align for section header table.
414
415              Yes, we use `sizeof' and not `__alignof__' since we do not
416              want to be surprised by architectures with less strict
417              alignment rules.  */
418 #define SHDR_ALIGN sizeof (ElfW2(LIBELFBITS,Off))
419           size = (size + SHDR_ALIGN - 1) & ~(SHDR_ALIGN - 1);
420
421           update_if_changed (ehdr->e_shoff, (GElf_Word) size, elf->flags);
422           update_if_changed (ehdr->e_shentsize,
423                              elf_typesize (LIBELFBITS, ELF_T_SHDR, 1),
424                              ehdr_flags);
425
426           /* Account for the section header size.  */
427           size += elf_typesize (LIBELFBITS, ELF_T_SHDR, shnum);
428         }
429     }
430
431   elf->state.ELFW(elf,LIBELFBITS).ehdr_flags |= ehdr_flags;
432
433   return size;
434 }