blob: be4cea03508db14bfb464d364c124fdd627b9482 [file] [log] [blame]
Ben Cheng25b3c042013-11-20 14:45:36 -08001/* Update data structures for changes.
2 Copyright (C) 2000-2010 Red Hat, Inc.
Elliott Hughes03333822015-02-18 22:19:45 -08003 This file is part of elfutils.
Ben Cheng25b3c042013-11-20 14:45:36 -08004 Written by Ulrich Drepper <drepper@redhat.com>, 2000.
5
Elliott Hughes03333822015-02-18 22:19:45 -08006 This file is free software; you can redistribute it and/or modify
7 it under the terms of either
Ben Cheng25b3c042013-11-20 14:45:36 -08008
Elliott Hughes03333822015-02-18 22:19:45 -08009 * 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
Ben Cheng25b3c042013-11-20 14:45:36 -080022 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
Elliott Hughes03333822015-02-18 22:19:45 -080026 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/>. */
Ben Cheng25b3c042013-11-20 14:45:36 -080029
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
50static int
51ELFW(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
113off_t
114internal_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}