]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - binutils/elfedit.c
Automatic date update in version.in
[thirdparty/binutils-gdb.git] / binutils / elfedit.c
CommitLineData
30fd33bb 1/* elfedit.c -- Update the ELF header of an ELF format file
fd67aa11 2 Copyright (C) 2010-2024 Free Software Foundation, Inc.
30fd33bb
L
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
19 02110-1301, USA. */
20\f
8a6b075b 21#include "config.h"
30fd33bb 22#include "sysdep.h"
9c905051 23#include "libiberty.h"
30fd33bb 24#include <assert.h>
30fd33bb
L
25
26#if __GNUC__ >= 2
27/* Define BFD64 here, even if our default architecture is 32 bit ELF
28 as this will allow us to read in and parse 64bit and 32bit ELF files.
29 Only do this if we believe that the compiler can support a 64 bit
30 data type. For now we only rely on GCC being able to do this. */
31#define BFD64
32#endif
33
34#include "bfd.h"
3284fe0c 35#include "elfcomm.h"
30fd33bb
L
36#include "bucomm.h"
37
38#include "elf/common.h"
39#include "elf/external.h"
40#include "elf/internal.h"
41
30fd33bb
L
42#include "getopt.h"
43#include "libiberty.h"
44#include "safe-ctype.h"
45#include "filenames.h"
46
47char * program_name = "elfedit";
48static long archive_file_offset;
49static unsigned long archive_file_size;
50static Elf_Internal_Ehdr elf_header;
51static Elf32_External_Ehdr ehdr32;
52static Elf64_External_Ehdr ehdr64;
53static int input_elf_machine = -1;
54static int output_elf_machine = -1;
dd35de74
L
55static int input_elf_type = -1;
56static int output_elf_type = -1;
d0514c49
L
57static int input_elf_osabi = -1;
58static int output_elf_osabi = -1;
c9dcc18f
L
59static int input_elf_abiversion = -1;
60static int output_elf_abiversion = -1;
6c14750f
L
61enum elfclass
62 {
63 ELF_CLASS_UNKNOWN = -1,
64 ELF_CLASS_NONE = ELFCLASSNONE,
65 ELF_CLASS_32 = ELFCLASS32,
66 ELF_CLASS_64 = ELFCLASS64,
67 ELF_CLASS_BOTH
68 };
69static enum elfclass input_elf_class = ELF_CLASS_UNKNOWN;
70static enum elfclass output_elf_class = ELF_CLASS_BOTH;
71
8a6b075b
L
72#ifdef HAVE_MMAP
73#include <sys/mman.h>
74
75static unsigned int enable_x86_features;
76static unsigned int disable_x86_features;
77
78static int
79update_gnu_property (const char *file_name, FILE *file)
80{
81 char *map;
82 Elf_Internal_Phdr *phdrs;
83 struct stat st_buf;
84 unsigned int i;
85 int ret;
86
87 if (!enable_x86_features && !disable_x86_features)
88 return 0;
89
90 if (elf_header.e_machine != EM_386
91 && elf_header.e_machine != EM_X86_64)
92 {
93 error (_("%s: Not an i386 nor x86-64 ELF file\n"), file_name);
94 return 0;
95 }
96
97 if (fstat (fileno (file), &st_buf) < 0)
98 {
99 error (_("%s: stat () failed\n"), file_name);
100 return 1;
101 }
102
103 map = mmap (NULL, st_buf.st_size, PROT_READ | PROT_WRITE,
104 MAP_SHARED, fileno (file), 0);
105 if (map == MAP_FAILED)
106 {
107 error (_("%s: mmap () failed\n"), file_name);
108 return 0;
109 }
110
111 phdrs = xmalloc (elf_header.e_phnum * sizeof (*phdrs));
112
113 if (elf_header.e_ident[EI_CLASS] == ELFCLASS32)
114 {
115 Elf32_External_Phdr *phdrs32
116 = (Elf32_External_Phdr *) (map + elf_header.e_phoff);
117 for (i = 0; i < elf_header.e_phnum; i++)
118 {
119 phdrs[i].p_type = BYTE_GET (phdrs32[i].p_type);
120 phdrs[i].p_offset = BYTE_GET (phdrs32[i].p_offset);
121 phdrs[i].p_vaddr = BYTE_GET (phdrs32[i].p_vaddr);
122 phdrs[i].p_paddr = BYTE_GET (phdrs32[i].p_paddr);
123 phdrs[i].p_filesz = BYTE_GET (phdrs32[i].p_filesz);
124 phdrs[i].p_memsz = BYTE_GET (phdrs32[i].p_memsz);
125 phdrs[i].p_flags = BYTE_GET (phdrs32[i].p_flags);
126 phdrs[i].p_align = BYTE_GET (phdrs32[i].p_align);
127 }
128 }
129 else
130 {
131 Elf64_External_Phdr *phdrs64
132 = (Elf64_External_Phdr *) (map + elf_header.e_phoff);
133 for (i = 0; i < elf_header.e_phnum; i++)
134 {
135 phdrs[i].p_type = BYTE_GET (phdrs64[i].p_type);
136 phdrs[i].p_offset = BYTE_GET (phdrs64[i].p_offset);
137 phdrs[i].p_vaddr = BYTE_GET (phdrs64[i].p_vaddr);
138 phdrs[i].p_paddr = BYTE_GET (phdrs64[i].p_paddr);
139 phdrs[i].p_filesz = BYTE_GET (phdrs64[i].p_filesz);
140 phdrs[i].p_memsz = BYTE_GET (phdrs64[i].p_memsz);
141 phdrs[i].p_flags = BYTE_GET (phdrs64[i].p_flags);
142 phdrs[i].p_align = BYTE_GET (phdrs64[i].p_align);
143 }
144 }
145
146 ret = 0;
147 for (i = 0; i < elf_header.e_phnum; i++)
148 if (phdrs[i].p_type == PT_NOTE)
149 {
150 size_t offset = phdrs[i].p_offset;
151 size_t size = phdrs[i].p_filesz;
152 size_t align = phdrs[i].p_align;
153 char *buf = map + offset;
154 char *p = buf;
155
156 while (p < buf + size)
157 {
158 Elf_External_Note *xnp = (Elf_External_Note *) p;
159 Elf_Internal_Note in;
160
161 if (offsetof (Elf_External_Note, name) > buf - p + size)
162 {
163 ret = 1;
164 goto out;
165 }
166
167 in.type = BYTE_GET (xnp->type);
168 in.namesz = BYTE_GET (xnp->namesz);
169 in.namedata = xnp->name;
170 if (in.namesz > buf - in.namedata + size)
171 {
172 ret = 1;
173 goto out;
174 }
175
176 in.descsz = BYTE_GET (xnp->descsz);
177 in.descdata = p + ELF_NOTE_DESC_OFFSET (in.namesz, align);
178 in.descpos = offset + (in.descdata - buf);
179 if (in.descsz != 0
180 && (in.descdata >= buf + size
181 || in.descsz > buf - in.descdata + size))
182 {
183 ret = 1;
184 goto out;
185 }
186
187 if (in.namesz == sizeof "GNU"
188 && strcmp (in.namedata, "GNU") == 0
189 && in.type == NT_GNU_PROPERTY_TYPE_0)
190 {
191 unsigned char *ptr;
192 unsigned char *ptr_end;
193
194 if (in.descsz < 8 || (in.descsz % align) != 0)
195 {
196 ret = 1;
197 goto out;
198 }
199
200 ptr = (unsigned char *) in.descdata;
201 ptr_end = ptr + in.descsz;
202
203 do
204 {
205 unsigned int type = byte_get (ptr, 4);
206 unsigned int datasz = byte_get (ptr + 4, 4);
207 unsigned int bitmask, old_bitmask;
208
209 ptr += 8;
210 if ((ptr + datasz) > ptr_end)
211 {
212 ret = 1;
213 goto out;
214 }
215
216 if (type == GNU_PROPERTY_X86_FEATURE_1_AND)
217 {
218 if (datasz != 4)
219 {
220 ret = 1;
221 goto out;
222 }
223
224 old_bitmask = byte_get (ptr, 4);
225 bitmask = old_bitmask;
226 if (enable_x86_features)
227 bitmask |= enable_x86_features;
228 if (disable_x86_features)
229 bitmask &= ~disable_x86_features;
230 if (old_bitmask != bitmask)
256878f3 231 byte_put (ptr, bitmask, 4);
8a6b075b
L
232 goto out;
233 }
234
235 ptr += ELF_ALIGN_UP (datasz, align);
236 }
237 while ((ptr_end - ptr) >= 8);
238 }
239
240 p += ELF_NOTE_NEXT_OFFSET (in.namesz, in.descsz, align);
241 }
242 }
243
dc1e8a47 244 out:
8a6b075b
L
245 if (ret != 0)
246 error (_("%s: Invalid PT_NOTE segment\n"), file_name);
247
248 free (phdrs);
249 munmap (map, st_buf.st_size);
250
251 return ret;
252}
253
254/* Set enable_x86_features and disable_x86_features for a feature
255 string, FEATURE. */
256
257static int
258elf_x86_feature (const char *feature, int enable)
259{
260 unsigned int x86_feature;
261 if (strcasecmp (feature, "ibt") == 0)
262 x86_feature = GNU_PROPERTY_X86_FEATURE_1_IBT;
263 else if (strcasecmp (feature, "shstk") == 0)
264 x86_feature = GNU_PROPERTY_X86_FEATURE_1_SHSTK;
279d901e
L
265 else if (strcasecmp (feature, "lam_u48") == 0)
266 x86_feature = GNU_PROPERTY_X86_FEATURE_1_LAM_U48;
267 else if (strcasecmp (feature, "lam_u57") == 0)
268 x86_feature = GNU_PROPERTY_X86_FEATURE_1_LAM_U57;
8a6b075b 269 else
760ddef4
L
270 {
271 error (_("Unknown x86 feature: %s\n"), feature);
272 return -1;
273 }
8a6b075b
L
274
275 if (enable)
276 {
277 enable_x86_features |= x86_feature;
278 disable_x86_features &= ~x86_feature;
279 }
280 else
281 {
282 disable_x86_features |= x86_feature;
283 enable_x86_features &= ~x86_feature;
284 }
285
286 return 0;
287}
288#endif
289
6c14750f
L
290/* Return ELF class for a machine type, MACH. */
291
292static enum elfclass
293elf_class (int mach)
294{
295 switch (mach)
296 {
297 case EM_386:
298 case EM_IAMCU:
299 return ELF_CLASS_32;
300 case EM_L1OM:
301 case EM_K1OM:
302 return ELF_CLASS_64;
303 case EM_X86_64:
304 case EM_NONE:
305 return ELF_CLASS_BOTH;
306 default:
aa9f7286 307 return ELF_CLASS_BOTH;
6c14750f
L
308 }
309}
30fd33bb 310
30fd33bb
L
311static int
312update_elf_header (const char *file_name, FILE *file)
313{
c9dcc18f 314 int class, machine, type, status, osabi, abiversion;
30fd33bb 315
30fd33bb
L
316 if (elf_header.e_ident[EI_VERSION] != EV_CURRENT)
317 {
3284fe0c 318 error
30fd33bb
L
319 (_("%s: Unsupported EI_VERSION: %d is not %d\n"),
320 file_name, elf_header.e_ident[EI_VERSION],
321 EV_CURRENT);
322 return 0;
323 }
324
2dc654c3
L
325 /* Return if e_machine is the same as output_elf_machine. */
326 if (output_elf_machine == elf_header.e_machine)
327 return 1;
328
329 class = elf_header.e_ident[EI_CLASS];
6c14750f 330 machine = elf_header.e_machine;
2dc654c3 331
30fd33bb 332 /* Skip if class doesn't match. */
6c14750f
L
333 if (input_elf_class == ELF_CLASS_UNKNOWN)
334 input_elf_class = elf_class (machine);
335
336 if (input_elf_class != ELF_CLASS_BOTH
337 && (int) input_elf_class != class)
30fd33bb 338 {
3284fe0c 339 error
6c14750f 340 (_("%s: Unmatched input EI_CLASS: %d is not %d\n"),
2dc654c3 341 file_name, class, input_elf_class);
30fd33bb
L
342 return 0;
343 }
344
6c14750f
L
345 if (output_elf_class != ELF_CLASS_BOTH
346 && (int) output_elf_class != class)
347 {
348 error
349 (_("%s: Unmatched output EI_CLASS: %d is not %d\n"),
350 file_name, class, output_elf_class);
351 return 0;
352 }
30fd33bb
L
353
354 /* Skip if e_machine doesn't match. */
2dc654c3 355 if (input_elf_machine != -1 && machine != input_elf_machine)
30fd33bb 356 {
3284fe0c 357 error
30fd33bb 358 (_("%s: Unmatched e_machine: %d is not %d\n"),
2dc654c3 359 file_name, machine, input_elf_machine);
30fd33bb
L
360 return 0;
361 }
362
dd35de74
L
363 type = elf_header.e_type;
364
365 /* Skip if e_type doesn't match. */
366 if (input_elf_type != -1 && type != input_elf_type)
367 {
3284fe0c 368 error
dd35de74
L
369 (_("%s: Unmatched e_type: %d is not %d\n"),
370 file_name, type, input_elf_type);
371 return 0;
372 }
373
d0514c49
L
374 osabi = elf_header.e_ident[EI_OSABI];
375
376 /* Skip if OSABI doesn't match. */
377 if (input_elf_osabi != -1 && osabi != input_elf_osabi)
378 {
3284fe0c 379 error
d0514c49
L
380 (_("%s: Unmatched EI_OSABI: %d is not %d\n"),
381 file_name, osabi, input_elf_osabi);
382 return 0;
383 }
384
c9dcc18f
L
385 abiversion = elf_header.e_ident[EI_ABIVERSION];
386
387 /* Skip if ABIVERSION doesn't match. */
388 if (input_elf_abiversion != -1
389 && abiversion != input_elf_abiversion)
390 {
391 error
392 (_("%s: Unmatched EI_ABIVERSION: %d is not %d\n"),
393 file_name, abiversion, input_elf_abiversion);
394 return 0;
395 }
396
d0514c49 397 /* Update e_machine, e_type and EI_OSABI. */
2dc654c3 398 switch (class)
30fd33bb
L
399 {
400 default:
401 /* We should never get here. */
402 abort ();
403 break;
404 case ELFCLASS32:
dd35de74
L
405 if (output_elf_machine != -1)
406 BYTE_PUT (ehdr32.e_machine, output_elf_machine);
407 if (output_elf_type != -1)
408 BYTE_PUT (ehdr32.e_type, output_elf_type);
d0514c49
L
409 if (output_elf_osabi != -1)
410 ehdr32.e_ident[EI_OSABI] = output_elf_osabi;
c9dcc18f
L
411 if (output_elf_abiversion != -1)
412 ehdr32.e_ident[EI_ABIVERSION] = output_elf_abiversion;
30fd33bb
L
413 status = fwrite (&ehdr32, sizeof (ehdr32), 1, file) == 1;
414 break;
415 case ELFCLASS64:
dd35de74
L
416 if (output_elf_machine != -1)
417 BYTE_PUT (ehdr64.e_machine, output_elf_machine);
418 if (output_elf_type != -1)
419 BYTE_PUT (ehdr64.e_type, output_elf_type);
d0514c49
L
420 if (output_elf_osabi != -1)
421 ehdr64.e_ident[EI_OSABI] = output_elf_osabi;
c9dcc18f
L
422 if (output_elf_abiversion != -1)
423 ehdr64.e_ident[EI_ABIVERSION] = output_elf_abiversion;
30fd33bb
L
424 status = fwrite (&ehdr64, sizeof (ehdr64), 1, file) == 1;
425 break;
426 }
427
428 if (status != 1)
3284fe0c 429 error (_("%s: Failed to update ELF header: %s\n"),
30fd33bb
L
430 file_name, strerror (errno));
431
432 return status;
433}
434
435static int
436get_file_header (FILE * file)
437{
438 /* Read in the identity array. */
439 if (fread (elf_header.e_ident, EI_NIDENT, 1, file) != 1)
440 return 0;
441
675accbd
L
442 if (elf_header.e_ident[EI_MAG0] != ELFMAG0
443 || elf_header.e_ident[EI_MAG1] != ELFMAG1
444 || elf_header.e_ident[EI_MAG2] != ELFMAG2
445 || elf_header.e_ident[EI_MAG3] != ELFMAG3)
446 return 0;
447
30fd33bb
L
448 /* Determine how to read the rest of the header. */
449 switch (elf_header.e_ident[EI_DATA])
450 {
451 default: /* fall through */
452 case ELFDATANONE: /* fall through */
453 case ELFDATA2LSB:
454 byte_get = byte_get_little_endian;
455 byte_put = byte_put_little_endian;
456 break;
457 case ELFDATA2MSB:
458 byte_get = byte_get_big_endian;
459 byte_put = byte_put_big_endian;
460 break;
461 }
462
463 /* Read in the rest of the header. For now we only support 32 bit
464 and 64 bit ELF files. */
465 switch (elf_header.e_ident[EI_CLASS])
466 {
467 default:
30fd33bb
L
468 return 0;
469
470 case ELFCLASS32:
471 if (fread (ehdr32.e_type, sizeof (ehdr32) - EI_NIDENT,
472 1, file) != 1)
473 return 0;
474
475 elf_header.e_type = BYTE_GET (ehdr32.e_type);
476 elf_header.e_machine = BYTE_GET (ehdr32.e_machine);
477 elf_header.e_version = BYTE_GET (ehdr32.e_version);
478 elf_header.e_entry = BYTE_GET (ehdr32.e_entry);
479 elf_header.e_phoff = BYTE_GET (ehdr32.e_phoff);
480 elf_header.e_shoff = BYTE_GET (ehdr32.e_shoff);
481 elf_header.e_flags = BYTE_GET (ehdr32.e_flags);
482 elf_header.e_ehsize = BYTE_GET (ehdr32.e_ehsize);
483 elf_header.e_phentsize = BYTE_GET (ehdr32.e_phentsize);
484 elf_header.e_phnum = BYTE_GET (ehdr32.e_phnum);
485 elf_header.e_shentsize = BYTE_GET (ehdr32.e_shentsize);
486 elf_header.e_shnum = BYTE_GET (ehdr32.e_shnum);
487 elf_header.e_shstrndx = BYTE_GET (ehdr32.e_shstrndx);
488
489 memcpy (&ehdr32, &elf_header, EI_NIDENT);
490 break;
491
492 case ELFCLASS64:
493 /* If we have been compiled with sizeof (bfd_vma) == 4, then
494 we will not be able to cope with the 64bit data found in
495 64 ELF files. Detect this now and abort before we start
496 overwriting things. */
497 if (sizeof (bfd_vma) < 8)
498 {
3284fe0c 499 error (_("This executable has been built without support for a\n\
30fd33bb
L
50064 bit data type and so it cannot process 64 bit ELF files.\n"));
501 return 0;
502 }
503
504 if (fread (ehdr64.e_type, sizeof (ehdr64) - EI_NIDENT,
505 1, file) != 1)
506 return 0;
507
508 elf_header.e_type = BYTE_GET (ehdr64.e_type);
509 elf_header.e_machine = BYTE_GET (ehdr64.e_machine);
510 elf_header.e_version = BYTE_GET (ehdr64.e_version);
511 elf_header.e_entry = BYTE_GET (ehdr64.e_entry);
512 elf_header.e_phoff = BYTE_GET (ehdr64.e_phoff);
513 elf_header.e_shoff = BYTE_GET (ehdr64.e_shoff);
514 elf_header.e_flags = BYTE_GET (ehdr64.e_flags);
515 elf_header.e_ehsize = BYTE_GET (ehdr64.e_ehsize);
516 elf_header.e_phentsize = BYTE_GET (ehdr64.e_phentsize);
517 elf_header.e_phnum = BYTE_GET (ehdr64.e_phnum);
518 elf_header.e_shentsize = BYTE_GET (ehdr64.e_shentsize);
519 elf_header.e_shnum = BYTE_GET (ehdr64.e_shnum);
520 elf_header.e_shstrndx = BYTE_GET (ehdr64.e_shstrndx);
521
522 memcpy (&ehdr64, &elf_header, EI_NIDENT);
523 break;
524 }
525 return 1;
526}
527
528/* Process one ELF object file according to the command line options.
529 This file may actually be stored in an archive. The file is
530 positioned at the start of the ELF object. */
531
532static int
533process_object (const char *file_name, FILE *file)
534{
535 /* Rememeber where we are. */
536 long offset = ftell (file);
537
538 if (! get_file_header (file))
539 {
3284fe0c 540 error (_("%s: Failed to read ELF header\n"), file_name);
30fd33bb
L
541 return 1;
542 }
543
544 /* Go to the position of the ELF header. */
545 if (fseek (file, offset, SEEK_SET) != 0)
546 {
3284fe0c 547 error (_("%s: Failed to seek to ELF header\n"), file_name);
30fd33bb
L
548 }
549
550 if (! update_elf_header (file_name, file))
551 return 1;
552
553 return 0;
554}
555
30fd33bb
L
556/* Process an ELF archive.
557 On entry the file is positioned just after the ARMAG string. */
558
559static int
560process_archive (const char * file_name, FILE * file,
015dc7e1 561 bool is_thin_archive)
30fd33bb
L
562{
563 struct archive_info arch;
564 struct archive_info nested_arch;
565 size_t got;
30fd33bb 566 int ret;
780f96ae 567 struct stat statbuf;
30fd33bb
L
568
569 /* The ARCH structure is used to hold information about this archive. */
570 arch.file_name = NULL;
571 arch.file = NULL;
572 arch.index_array = NULL;
573 arch.sym_table = NULL;
574 arch.longnames = NULL;
575
576 /* The NESTED_ARCH structure is used as a single-item cache of information
577 about a nested archive (when members of a thin archive reside within
578 another regular archive file). */
579 nested_arch.file_name = NULL;
580 nested_arch.file = NULL;
581 nested_arch.index_array = NULL;
582 nested_arch.sym_table = NULL;
583 nested_arch.longnames = NULL;
584
780f96ae
AM
585 if (fstat (fileno (file), &statbuf) < 0
586 || setup_archive (&arch, file_name, file, statbuf.st_size,
015dc7e1 587 is_thin_archive, false) != 0)
30fd33bb
L
588 {
589 ret = 1;
590 goto out;
591 }
592
30fd33bb
L
593 ret = 0;
594
595 while (1)
596 {
597 char * name;
598 size_t namelen;
599 char * qualified_name;
600
601 /* Read the next archive header. */
602 if (fseek (file, arch.next_arhdr_offset, SEEK_SET) != 0)
603 {
3284fe0c 604 error (_("%s: failed to seek to next archive header\n"),
30fd33bb
L
605 file_name);
606 return 1;
607 }
608 got = fread (&arch.arhdr, 1, sizeof arch.arhdr, file);
609 if (got != sizeof arch.arhdr)
610 {
611 if (got == 0)
612 break;
3284fe0c 613 error (_("%s: failed to read archive header\n"),
30fd33bb
L
614 file_name);
615 ret = 1;
616 break;
617 }
618 if (memcmp (arch.arhdr.ar_fmag, ARFMAG, 2) != 0)
619 {
3284fe0c 620 error (_("%s: did not find a valid archive header\n"),
30fd33bb
L
621 arch.file_name);
622 ret = 1;
623 break;
624 }
625
626 arch.next_arhdr_offset += sizeof arch.arhdr;
627
628 archive_file_size = strtoul (arch.arhdr.ar_size, NULL, 10);
629 if (archive_file_size & 01)
630 ++archive_file_size;
631
632 name = get_archive_member_name (&arch, &nested_arch);
633 if (name == NULL)
634 {
3284fe0c 635 error (_("%s: bad archive file name\n"), file_name);
30fd33bb
L
636 ret = 1;
637 break;
638 }
639 namelen = strlen (name);
640
641 qualified_name = make_qualified_name (&arch, &nested_arch, name);
642 if (qualified_name == NULL)
643 {
3284fe0c 644 error (_("%s: bad archive file name\n"), file_name);
fd486f32 645 free (name);
30fd33bb
L
646 ret = 1;
647 break;
648 }
649
650 if (is_thin_archive && arch.nested_member_origin == 0)
651 {
652 /* This is a proxy for an external member of a thin archive. */
653 FILE *member_file;
654 char *member_file_name = adjust_relative_path (file_name,
655 name, namelen);
fd486f32 656 free (name);
30fd33bb
L
657 if (member_file_name == NULL)
658 {
fd486f32 659 free (qualified_name);
30fd33bb
L
660 ret = 1;
661 break;
662 }
663
664 member_file = fopen (member_file_name, "r+b");
665 if (member_file == NULL)
666 {
3284fe0c 667 error (_("Input file '%s' is not readable\n"),
30fd33bb
L
668 member_file_name);
669 free (member_file_name);
fd486f32 670 free (qualified_name);
30fd33bb
L
671 ret = 1;
672 break;
673 }
674
675 archive_file_offset = arch.nested_member_origin;
676
677 ret |= process_object (qualified_name, member_file);
678
679 fclose (member_file);
680 free (member_file_name);
681 }
682 else if (is_thin_archive)
683 {
fd486f32
AM
684 free (name);
685
30fd33bb
L
686 /* This is a proxy for a member of a nested archive. */
687 archive_file_offset = arch.nested_member_origin + sizeof arch.arhdr;
688
689 /* The nested archive file will have been opened and setup by
690 get_archive_member_name. */
691 if (fseek (nested_arch.file, archive_file_offset,
692 SEEK_SET) != 0)
693 {
3284fe0c 694 error (_("%s: failed to seek to archive member\n"),
30fd33bb 695 nested_arch.file_name);
fd486f32 696 free (qualified_name);
30fd33bb
L
697 ret = 1;
698 break;
699 }
700
701 ret |= process_object (qualified_name, nested_arch.file);
702 }
703 else
704 {
fd486f32 705 free (name);
30fd33bb
L
706 archive_file_offset = arch.next_arhdr_offset;
707 arch.next_arhdr_offset += archive_file_size;
708
709 ret |= process_object (qualified_name, file);
710 }
711
712 free (qualified_name);
713 }
714
715 out:
716 if (nested_arch.file != NULL)
717 fclose (nested_arch.file);
718 release_archive (&nested_arch);
719 release_archive (&arch);
720
721 return ret;
722}
723
724static int
725check_file (const char *file_name, struct stat *statbuf_p)
726{
727 struct stat statbuf;
728
729 if (statbuf_p == NULL)
730 statbuf_p = &statbuf;
731
732 if (stat (file_name, statbuf_p) < 0)
733 {
734 if (errno == ENOENT)
3284fe0c 735 error (_("'%s': No such file\n"), file_name);
30fd33bb 736 else
3284fe0c 737 error (_("Could not locate '%s'. System error message: %s\n"),
30fd33bb
L
738 file_name, strerror (errno));
739 return 1;
740 }
741
a7ad3cb1
EZ
742#if defined (_WIN32) && !defined (__CYGWIN__)
743 else if (statbuf_p->st_size == 0)
744 {
887854ba
EZ
745 /* MS-Windows 'stat' reports the null device as a regular file;
746 fix that. */
a7ad3cb1
EZ
747 int fd = open (file_name, O_RDONLY | O_BINARY);
748 if (isatty (fd))
749 {
750 statbuf_p->st_mode &= ~S_IFREG;
751 statbuf_p->st_mode |= S_IFCHR;
752 }
753 }
754#endif
755
30fd33bb
L
756 if (! S_ISREG (statbuf_p->st_mode))
757 {
3284fe0c 758 error (_("'%s' is not an ordinary file\n"), file_name);
30fd33bb
L
759 return 1;
760 }
761
762 return 0;
763}
764
765static int
766process_file (const char *file_name)
767{
768 FILE * file;
769 char armag[SARMAG];
770 int ret;
771
772 if (check_file (file_name, NULL))
773 return 1;
774
775 file = fopen (file_name, "r+b");
776 if (file == NULL)
777 {
3284fe0c 778 error (_("Input file '%s' is not readable\n"), file_name);
30fd33bb
L
779 return 1;
780 }
781
782 if (fread (armag, SARMAG, 1, file) != 1)
783 {
3284fe0c 784 error (_("%s: Failed to read file's magic number\n"),
30fd33bb
L
785 file_name);
786 fclose (file);
787 return 1;
788 }
789
790 if (memcmp (armag, ARMAG, SARMAG) == 0)
015dc7e1 791 ret = process_archive (file_name, file, false);
30fd33bb 792 else if (memcmp (armag, ARMAGT, SARMAG) == 0)
015dc7e1 793 ret = process_archive (file_name, file, true);
30fd33bb
L
794 else
795 {
796 rewind (file);
797 archive_file_size = archive_file_offset = 0;
798 ret = process_object (file_name, file);
8a6b075b
L
799#ifdef HAVE_MMAP
800 if (!ret
801 && (elf_header.e_type == ET_EXEC
802 || elf_header.e_type == ET_DYN))
803 ret = update_gnu_property (file_name, file);
804#endif
30fd33bb
L
805 }
806
807 fclose (file);
808
809 return ret;
810}
811
d0514c49
L
812static const struct
813{
814 int osabi;
815 const char *name;
816}
817osabis[] =
818{
819 { ELFOSABI_NONE, "none" },
820 { ELFOSABI_HPUX, "HPUX" },
821 { ELFOSABI_NETBSD, "NetBSD" },
9c55345c
TS
822 { ELFOSABI_GNU, "GNU" },
823 { ELFOSABI_GNU, "Linux" },
d0514c49
L
824 { ELFOSABI_SOLARIS, "Solaris" },
825 { ELFOSABI_AIX, "AIX" },
826 { ELFOSABI_IRIX, "Irix" },
827 { ELFOSABI_FREEBSD, "FreeBSD" },
828 { ELFOSABI_TRU64, "TRU64" },
829 { ELFOSABI_MODESTO, "Modesto" },
830 { ELFOSABI_OPENBSD, "OpenBSD" },
831 { ELFOSABI_OPENVMS, "OpenVMS" },
832 { ELFOSABI_NSK, "NSK" },
833 { ELFOSABI_AROS, "AROS" },
834 { ELFOSABI_FENIXOS, "FenixOS" }
835};
836
837/* Return ELFOSABI_XXX for an OSABI string, OSABI. */
838
839static int
840elf_osabi (const char *osabi)
841{
842 unsigned int i;
843
844 for (i = 0; i < ARRAY_SIZE (osabis); i++)
845 if (strcasecmp (osabi, osabis[i].name) == 0)
846 return osabis[i].osabi;
847
3284fe0c 848 error (_("Unknown OSABI: %s\n"), osabi);
d0514c49
L
849
850 return -1;
851}
852
30fd33bb
L
853/* Return EM_XXX for a machine string, MACH. */
854
855static int
856elf_machine (const char *mach)
857{
6c14750f
L
858 if (strcasecmp (mach, "i386") == 0)
859 return EM_386;
860 if (strcasecmp (mach, "iamcu") == 0)
861 return EM_IAMCU;
30fd33bb
L
862 if (strcasecmp (mach, "l1om") == 0)
863 return EM_L1OM;
7a9068fe
L
864 if (strcasecmp (mach, "k1om") == 0)
865 return EM_K1OM;
30fd33bb
L
866 if (strcasecmp (mach, "x86_64") == 0)
867 return EM_X86_64;
868 if (strcasecmp (mach, "x86-64") == 0)
869 return EM_X86_64;
870 if (strcasecmp (mach, "none") == 0)
871 return EM_NONE;
872
3284fe0c 873 error (_("Unknown machine type: %s\n"), mach);
30fd33bb
L
874
875 return -1;
876}
877
dd35de74
L
878/* Return ET_XXX for a type string, TYPE. */
879
880static int
881elf_type (const char *type)
882{
883 if (strcasecmp (type, "rel") == 0)
884 return ET_REL;
885 if (strcasecmp (type, "exec") == 0)
886 return ET_EXEC;
887 if (strcasecmp (type, "dyn") == 0)
888 return ET_DYN;
889 if (strcasecmp (type, "none") == 0)
890 return ET_NONE;
891
3284fe0c 892 error (_("Unknown type: %s\n"), type);
dd35de74
L
893
894 return -1;
895}
896
30fd33bb
L
897enum command_line_switch
898 {
899 OPTION_INPUT_MACH = 150,
dd35de74
L
900 OPTION_OUTPUT_MACH,
901 OPTION_INPUT_TYPE,
d0514c49
L
902 OPTION_OUTPUT_TYPE,
903 OPTION_INPUT_OSABI,
8a6b075b 904 OPTION_OUTPUT_OSABI,
c9dcc18f
L
905 OPTION_INPUT_ABIVERSION,
906 OPTION_OUTPUT_ABIVERSION,
8a6b075b
L
907#ifdef HAVE_MMAP
908 OPTION_ENABLE_X86_FEATURE,
909 OPTION_DISABLE_X86_FEATURE,
910#endif
30fd33bb
L
911 };
912
913static struct option options[] =
914{
915 {"input-mach", required_argument, 0, OPTION_INPUT_MACH},
916 {"output-mach", required_argument, 0, OPTION_OUTPUT_MACH},
dd35de74
L
917 {"input-type", required_argument, 0, OPTION_INPUT_TYPE},
918 {"output-type", required_argument, 0, OPTION_OUTPUT_TYPE},
d0514c49
L
919 {"input-osabi", required_argument, 0, OPTION_INPUT_OSABI},
920 {"output-osabi", required_argument, 0, OPTION_OUTPUT_OSABI},
c9dcc18f
L
921 {"input-abiversion", required_argument, 0, OPTION_INPUT_ABIVERSION},
922 {"output-abiversion", required_argument, 0, OPTION_OUTPUT_ABIVERSION},
8a6b075b
L
923#ifdef HAVE_MMAP
924 {"enable-x86-feature",
925 required_argument, 0, OPTION_ENABLE_X86_FEATURE},
926 {"disable-x86-feature",
927 required_argument, 0, OPTION_DISABLE_X86_FEATURE},
928#endif
30fd33bb
L
929 {"version", no_argument, 0, 'v'},
930 {"help", no_argument, 0, 'h'},
931 {0, no_argument, 0, 0}
932};
933
1e0f0b4d 934ATTRIBUTE_NORETURN static void
30fd33bb
L
935usage (FILE *stream, int exit_status)
936{
9c905051 937 unsigned int i;
a4e91c46 938 char *osabi = concat (osabis[0].name, NULL);
9c905051 939
a4e91c46 940 for (i = 1; i < ARRAY_SIZE (osabis); i++)
2e635a01 941 osabi = reconcat (osabi, osabi, "|", osabis[i].name, NULL);
9c905051 942
d0514c49 943 fprintf (stream, _("Usage: %s <option(s)> elffile(s)\n"),
30fd33bb
L
944 program_name);
945 fprintf (stream, _(" Update the ELF header of ELF files\n"));
946 fprintf (stream, _(" The options are:\n"));
947 fprintf (stream, _("\
9c905051
L
948 --input-mach [none|i386|iamcu|l1om|k1om|x86_64]\n\
949 Set input machine type\n\
950 --output-mach [none|i386|iamcu|l1om|k1om|x86_64]\n\
951 Set output machine type\n\
952 --input-type [none|rel|exec|dyn]\n\
953 Set input file type\n\
954 --output-type [none|rel|exec|dyn]\n\
955 Set output file type\n\
956 --input-osabi [%s]\n\
957 Set input OSABI\n\
958 --output-osabi [%s]\n\
c9dcc18f 959 Set output OSABI\n\
b6e7fb95
L
960 --input-abiversion [0-255] Set input ABIVERSION\n\
961 --output-abiversion [0-255] Set output ABIVERSION\n"),
9c905051 962 osabi, osabi);
8a6b075b
L
963#ifdef HAVE_MMAP
964 fprintf (stream, _("\
279d901e 965 --enable-x86-feature [ibt|shstk|lam_u48|lam_u57]\n\
9c905051 966 Enable x86 feature\n\
279d901e 967 --disable-x86-feature [ibt|shstk|lam_u48|lam_u57]\n\
9c905051 968 Disable x86 feature\n"));
8a6b075b
L
969#endif
970 fprintf (stream, _("\
30fd33bb
L
971 -h --help Display this information\n\
972 -v --version Display the version number of %s\n\
973"),
974 program_name);
975 if (REPORT_BUGS_TO[0] && exit_status == 0)
976 fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
9c905051 977 free (osabi);
30fd33bb
L
978 exit (exit_status);
979}
980
981int
982main (int argc, char ** argv)
983{
984 int c, status;
c9dcc18f 985 char *end;
30fd33bb 986
87b9f255 987#ifdef HAVE_LC_MESSAGES
30fd33bb
L
988 setlocale (LC_MESSAGES, "");
989#endif
30fd33bb 990 setlocale (LC_CTYPE, "");
30fd33bb
L
991 bindtextdomain (PACKAGE, LOCALEDIR);
992 textdomain (PACKAGE);
993
994 expandargv (&argc, &argv);
995
996 while ((c = getopt_long (argc, argv, "hv",
997 options, (int *) 0)) != EOF)
998 {
999 switch (c)
1000 {
1001 case OPTION_INPUT_MACH:
1002 input_elf_machine = elf_machine (optarg);
1003 if (input_elf_machine < 0)
1004 return 1;
1005 input_elf_class = elf_class (input_elf_machine);
6c14750f 1006 if (input_elf_class == ELF_CLASS_UNKNOWN)
30fd33bb
L
1007 return 1;
1008 break;
1009
1010 case OPTION_OUTPUT_MACH:
1011 output_elf_machine = elf_machine (optarg);
1012 if (output_elf_machine < 0)
1013 return 1;
6c14750f
L
1014 output_elf_class = elf_class (output_elf_machine);
1015 if (output_elf_class == ELF_CLASS_UNKNOWN)
1016 return 1;
30fd33bb
L
1017 break;
1018
dd35de74
L
1019 case OPTION_INPUT_TYPE:
1020 input_elf_type = elf_type (optarg);
1021 if (input_elf_type < 0)
1022 return 1;
1023 break;
1024
1025 case OPTION_OUTPUT_TYPE:
1026 output_elf_type = elf_type (optarg);
1027 if (output_elf_type < 0)
1028 return 1;
1029 break;
1030
d0514c49
L
1031 case OPTION_INPUT_OSABI:
1032 input_elf_osabi = elf_osabi (optarg);
1033 if (input_elf_osabi < 0)
1034 return 1;
1035 break;
1036
1037 case OPTION_OUTPUT_OSABI:
1038 output_elf_osabi = elf_osabi (optarg);
1039 if (output_elf_osabi < 0)
1040 return 1;
1041 break;
1042
c9dcc18f
L
1043 case OPTION_INPUT_ABIVERSION:
1044 input_elf_abiversion = strtoul (optarg, &end, 0);
1045 if (*end != '\0'
1046 || input_elf_abiversion < 0
1047 || input_elf_abiversion > 255)
1048 {
1049 error (_("Invalid ABIVERSION: %s\n"), optarg);
1050 return 1;
1051 }
1052 break;
1053
1054 case OPTION_OUTPUT_ABIVERSION:
1055 output_elf_abiversion = strtoul (optarg, &end, 0);
1056 if (*end != '\0'
1057 || output_elf_abiversion < 0
1058 || output_elf_abiversion > 255)
1059 {
1060 error (_("Invalid ABIVERSION: %s\n"), optarg);
1061 return 1;
1062 }
1063 break;
1064
8a6b075b
L
1065#ifdef HAVE_MMAP
1066 case OPTION_ENABLE_X86_FEATURE:
1067 if (elf_x86_feature (optarg, 1) < 0)
1068 return 1;
1069 break;
1070
1071 case OPTION_DISABLE_X86_FEATURE:
1072 if (elf_x86_feature (optarg, 0) < 0)
1073 return 1;
1074 break;
1075#endif
1076
30fd33bb
L
1077 case 'h':
1078 usage (stdout, 0);
1079
1080 case 'v':
1081 print_version (program_name);
1082 break;
1083
1084 default:
1085 usage (stderr, 1);
1086 }
1087 }
1088
dd35de74
L
1089 if (optind == argc
1090 || (output_elf_machine == -1
8a6b075b
L
1091#ifdef HAVE_MMAP
1092 && ! enable_x86_features
1093 && ! disable_x86_features
1094#endif
d0514c49 1095 && output_elf_type == -1
c9dcc18f
L
1096 && output_elf_osabi == -1
1097 && output_elf_abiversion == -1))
30fd33bb
L
1098 usage (stderr, 1);
1099
1100 status = 0;
1101 while (optind < argc)
1102 status |= process_file (argv[optind++]);
1103
1104 return status;
1105}