xref: /dflybsd-src/contrib/binutils-2.27/binutils/elfedit.c (revision e656dc90e3d65d744d534af2f5ea88cf8101ebcf)
1*a9fa9459Szrj /* elfedit.c -- Update the ELF header of an ELF format file
2*a9fa9459Szrj    Copyright (C) 2010-2016 Free Software Foundation, Inc.
3*a9fa9459Szrj 
4*a9fa9459Szrj    This file is part of GNU Binutils.
5*a9fa9459Szrj 
6*a9fa9459Szrj    This program is free software; you can redistribute it and/or modify
7*a9fa9459Szrj    it under the terms of the GNU General Public License as published by
8*a9fa9459Szrj    the Free Software Foundation; either version 3 of the License, or
9*a9fa9459Szrj    (at your option) any later version.
10*a9fa9459Szrj 
11*a9fa9459Szrj    This program is distributed in the hope that it will be useful,
12*a9fa9459Szrj    but WITHOUT ANY WARRANTY; without even the implied warranty of
13*a9fa9459Szrj    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*a9fa9459Szrj    GNU General Public License for more details.
15*a9fa9459Szrj 
16*a9fa9459Szrj    You should have received a copy of the GNU General Public License
17*a9fa9459Szrj    along with this program; if not, write to the Free Software
18*a9fa9459Szrj    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
19*a9fa9459Szrj    02110-1301, USA.  */
20*a9fa9459Szrj 
21*a9fa9459Szrj #include "sysdep.h"
22*a9fa9459Szrj #include <assert.h>
23*a9fa9459Szrj 
24*a9fa9459Szrj #if __GNUC__ >= 2
25*a9fa9459Szrj /* Define BFD64 here, even if our default architecture is 32 bit ELF
26*a9fa9459Szrj    as this will allow us to read in and parse 64bit and 32bit ELF files.
27*a9fa9459Szrj    Only do this if we believe that the compiler can support a 64 bit
28*a9fa9459Szrj    data type.  For now we only rely on GCC being able to do this.  */
29*a9fa9459Szrj #define BFD64
30*a9fa9459Szrj #endif
31*a9fa9459Szrj 
32*a9fa9459Szrj #include "bfd.h"
33*a9fa9459Szrj #include "elfcomm.h"
34*a9fa9459Szrj #include "bucomm.h"
35*a9fa9459Szrj 
36*a9fa9459Szrj #include "elf/common.h"
37*a9fa9459Szrj #include "elf/external.h"
38*a9fa9459Szrj #include "elf/internal.h"
39*a9fa9459Szrj 
40*a9fa9459Szrj #include "getopt.h"
41*a9fa9459Szrj #include "libiberty.h"
42*a9fa9459Szrj #include "safe-ctype.h"
43*a9fa9459Szrj #include "filenames.h"
44*a9fa9459Szrj 
45*a9fa9459Szrj char * program_name = "elfedit";
46*a9fa9459Szrj static long archive_file_offset;
47*a9fa9459Szrj static unsigned long archive_file_size;
48*a9fa9459Szrj static Elf_Internal_Ehdr elf_header;
49*a9fa9459Szrj static Elf32_External_Ehdr ehdr32;
50*a9fa9459Szrj static Elf64_External_Ehdr ehdr64;
51*a9fa9459Szrj static int input_elf_machine = -1;
52*a9fa9459Szrj static int output_elf_machine = -1;
53*a9fa9459Szrj static int input_elf_type = -1;
54*a9fa9459Szrj static int output_elf_type = -1;
55*a9fa9459Szrj static int input_elf_osabi = -1;
56*a9fa9459Szrj static int output_elf_osabi = -1;
57*a9fa9459Szrj enum elfclass
58*a9fa9459Szrj   {
59*a9fa9459Szrj     ELF_CLASS_UNKNOWN = -1,
60*a9fa9459Szrj     ELF_CLASS_NONE = ELFCLASSNONE,
61*a9fa9459Szrj     ELF_CLASS_32 = ELFCLASS32,
62*a9fa9459Szrj     ELF_CLASS_64 = ELFCLASS64,
63*a9fa9459Szrj     ELF_CLASS_BOTH
64*a9fa9459Szrj   };
65*a9fa9459Szrj static enum elfclass input_elf_class = ELF_CLASS_UNKNOWN;
66*a9fa9459Szrj static enum elfclass output_elf_class = ELF_CLASS_BOTH;
67*a9fa9459Szrj 
68*a9fa9459Szrj /* Return ELF class for a machine type, MACH.  */
69*a9fa9459Szrj 
70*a9fa9459Szrj static enum elfclass
elf_class(int mach)71*a9fa9459Szrj elf_class (int mach)
72*a9fa9459Szrj {
73*a9fa9459Szrj   switch (mach)
74*a9fa9459Szrj     {
75*a9fa9459Szrj     case EM_386:
76*a9fa9459Szrj     case EM_IAMCU:
77*a9fa9459Szrj       return ELF_CLASS_32;
78*a9fa9459Szrj     case EM_L1OM:
79*a9fa9459Szrj     case EM_K1OM:
80*a9fa9459Szrj       return ELF_CLASS_64;
81*a9fa9459Szrj     case EM_X86_64:
82*a9fa9459Szrj     case EM_NONE:
83*a9fa9459Szrj       return ELF_CLASS_BOTH;
84*a9fa9459Szrj     default:
85*a9fa9459Szrj       return ELF_CLASS_BOTH;
86*a9fa9459Szrj     }
87*a9fa9459Szrj }
88*a9fa9459Szrj 
89*a9fa9459Szrj static int
update_elf_header(const char * file_name,FILE * file)90*a9fa9459Szrj update_elf_header (const char *file_name, FILE *file)
91*a9fa9459Szrj {
92*a9fa9459Szrj   int class, machine, type, status, osabi;
93*a9fa9459Szrj 
94*a9fa9459Szrj   if (elf_header.e_ident[EI_MAG0] != ELFMAG0
95*a9fa9459Szrj       || elf_header.e_ident[EI_MAG1] != ELFMAG1
96*a9fa9459Szrj       || elf_header.e_ident[EI_MAG2] != ELFMAG2
97*a9fa9459Szrj       || elf_header.e_ident[EI_MAG3] != ELFMAG3)
98*a9fa9459Szrj     {
99*a9fa9459Szrj       error
100*a9fa9459Szrj 	(_("%s: Not an ELF file - wrong magic bytes at the start\n"),
101*a9fa9459Szrj 	 file_name);
102*a9fa9459Szrj       return 0;
103*a9fa9459Szrj     }
104*a9fa9459Szrj 
105*a9fa9459Szrj   if (elf_header.e_ident[EI_VERSION] != EV_CURRENT)
106*a9fa9459Szrj     {
107*a9fa9459Szrj       error
108*a9fa9459Szrj 	(_("%s: Unsupported EI_VERSION: %d is not %d\n"),
109*a9fa9459Szrj 	 file_name, elf_header.e_ident[EI_VERSION],
110*a9fa9459Szrj 	 EV_CURRENT);
111*a9fa9459Szrj       return 0;
112*a9fa9459Szrj     }
113*a9fa9459Szrj 
114*a9fa9459Szrj   /* Return if e_machine is the same as output_elf_machine.  */
115*a9fa9459Szrj   if (output_elf_machine == elf_header.e_machine)
116*a9fa9459Szrj     return 1;
117*a9fa9459Szrj 
118*a9fa9459Szrj   class = elf_header.e_ident[EI_CLASS];
119*a9fa9459Szrj   machine = elf_header.e_machine;
120*a9fa9459Szrj 
121*a9fa9459Szrj   /* Skip if class doesn't match. */
122*a9fa9459Szrj   if (input_elf_class == ELF_CLASS_UNKNOWN)
123*a9fa9459Szrj     input_elf_class = elf_class (machine);
124*a9fa9459Szrj 
125*a9fa9459Szrj   if (input_elf_class != ELF_CLASS_BOTH
126*a9fa9459Szrj       && (int) input_elf_class != class)
127*a9fa9459Szrj     {
128*a9fa9459Szrj       error
129*a9fa9459Szrj 	(_("%s: Unmatched input EI_CLASS: %d is not %d\n"),
130*a9fa9459Szrj 	 file_name, class, input_elf_class);
131*a9fa9459Szrj       return 0;
132*a9fa9459Szrj     }
133*a9fa9459Szrj 
134*a9fa9459Szrj   if (output_elf_class != ELF_CLASS_BOTH
135*a9fa9459Szrj       && (int) output_elf_class != class)
136*a9fa9459Szrj     {
137*a9fa9459Szrj       error
138*a9fa9459Szrj 	(_("%s: Unmatched output EI_CLASS: %d is not %d\n"),
139*a9fa9459Szrj 	 file_name, class, output_elf_class);
140*a9fa9459Szrj       return 0;
141*a9fa9459Szrj     }
142*a9fa9459Szrj 
143*a9fa9459Szrj   /* Skip if e_machine doesn't match. */
144*a9fa9459Szrj   if (input_elf_machine != -1 && machine != input_elf_machine)
145*a9fa9459Szrj     {
146*a9fa9459Szrj       error
147*a9fa9459Szrj 	(_("%s: Unmatched e_machine: %d is not %d\n"),
148*a9fa9459Szrj 	 file_name, machine, input_elf_machine);
149*a9fa9459Szrj       return 0;
150*a9fa9459Szrj     }
151*a9fa9459Szrj 
152*a9fa9459Szrj   type = elf_header.e_type;
153*a9fa9459Szrj 
154*a9fa9459Szrj   /* Skip if e_type doesn't match. */
155*a9fa9459Szrj   if (input_elf_type != -1 && type != input_elf_type)
156*a9fa9459Szrj     {
157*a9fa9459Szrj       error
158*a9fa9459Szrj 	(_("%s: Unmatched e_type: %d is not %d\n"),
159*a9fa9459Szrj 	 file_name, type, input_elf_type);
160*a9fa9459Szrj       return 0;
161*a9fa9459Szrj     }
162*a9fa9459Szrj 
163*a9fa9459Szrj   osabi = elf_header.e_ident[EI_OSABI];
164*a9fa9459Szrj 
165*a9fa9459Szrj   /* Skip if OSABI doesn't match. */
166*a9fa9459Szrj   if (input_elf_osabi != -1 && osabi != input_elf_osabi)
167*a9fa9459Szrj     {
168*a9fa9459Szrj       error
169*a9fa9459Szrj 	(_("%s: Unmatched EI_OSABI: %d is not %d\n"),
170*a9fa9459Szrj 	 file_name, osabi, input_elf_osabi);
171*a9fa9459Szrj       return 0;
172*a9fa9459Szrj     }
173*a9fa9459Szrj 
174*a9fa9459Szrj   /* Update e_machine, e_type and EI_OSABI.  */
175*a9fa9459Szrj   switch (class)
176*a9fa9459Szrj     {
177*a9fa9459Szrj     default:
178*a9fa9459Szrj       /* We should never get here.  */
179*a9fa9459Szrj       abort ();
180*a9fa9459Szrj       break;
181*a9fa9459Szrj     case ELFCLASS32:
182*a9fa9459Szrj       if (output_elf_machine != -1)
183*a9fa9459Szrj 	BYTE_PUT (ehdr32.e_machine, output_elf_machine);
184*a9fa9459Szrj       if (output_elf_type != -1)
185*a9fa9459Szrj 	BYTE_PUT (ehdr32.e_type, output_elf_type);
186*a9fa9459Szrj       if (output_elf_osabi != -1)
187*a9fa9459Szrj 	ehdr32.e_ident[EI_OSABI] = output_elf_osabi;
188*a9fa9459Szrj       status = fwrite (&ehdr32, sizeof (ehdr32), 1, file) == 1;
189*a9fa9459Szrj       break;
190*a9fa9459Szrj     case ELFCLASS64:
191*a9fa9459Szrj       if (output_elf_machine != -1)
192*a9fa9459Szrj 	BYTE_PUT (ehdr64.e_machine, output_elf_machine);
193*a9fa9459Szrj       if (output_elf_type != -1)
194*a9fa9459Szrj 	BYTE_PUT (ehdr64.e_type, output_elf_type);
195*a9fa9459Szrj       if (output_elf_osabi != -1)
196*a9fa9459Szrj 	ehdr64.e_ident[EI_OSABI] = output_elf_osabi;
197*a9fa9459Szrj       status = fwrite (&ehdr64, sizeof (ehdr64), 1, file) == 1;
198*a9fa9459Szrj       break;
199*a9fa9459Szrj     }
200*a9fa9459Szrj 
201*a9fa9459Szrj   if (status != 1)
202*a9fa9459Szrj     error (_("%s: Failed to update ELF header: %s\n"),
203*a9fa9459Szrj 	       file_name, strerror (errno));
204*a9fa9459Szrj 
205*a9fa9459Szrj   return status;
206*a9fa9459Szrj }
207*a9fa9459Szrj 
208*a9fa9459Szrj static int
get_file_header(FILE * file)209*a9fa9459Szrj get_file_header (FILE * file)
210*a9fa9459Szrj {
211*a9fa9459Szrj   /* Read in the identity array.  */
212*a9fa9459Szrj   if (fread (elf_header.e_ident, EI_NIDENT, 1, file) != 1)
213*a9fa9459Szrj     return 0;
214*a9fa9459Szrj 
215*a9fa9459Szrj   /* Determine how to read the rest of the header.  */
216*a9fa9459Szrj   switch (elf_header.e_ident[EI_DATA])
217*a9fa9459Szrj     {
218*a9fa9459Szrj     default: /* fall through */
219*a9fa9459Szrj     case ELFDATANONE: /* fall through */
220*a9fa9459Szrj     case ELFDATA2LSB:
221*a9fa9459Szrj       byte_get = byte_get_little_endian;
222*a9fa9459Szrj       byte_put = byte_put_little_endian;
223*a9fa9459Szrj       break;
224*a9fa9459Szrj     case ELFDATA2MSB:
225*a9fa9459Szrj       byte_get = byte_get_big_endian;
226*a9fa9459Szrj       byte_put = byte_put_big_endian;
227*a9fa9459Szrj       break;
228*a9fa9459Szrj     }
229*a9fa9459Szrj 
230*a9fa9459Szrj   /* Read in the rest of the header.  For now we only support 32 bit
231*a9fa9459Szrj      and 64 bit ELF files.  */
232*a9fa9459Szrj   switch (elf_header.e_ident[EI_CLASS])
233*a9fa9459Szrj     {
234*a9fa9459Szrj     default:
235*a9fa9459Szrj       error (_("Unsupported EI_CLASS: %d\n"),
236*a9fa9459Szrj 		 elf_header.e_ident[EI_CLASS]);
237*a9fa9459Szrj       return 0;
238*a9fa9459Szrj 
239*a9fa9459Szrj     case ELFCLASS32:
240*a9fa9459Szrj       if (fread (ehdr32.e_type, sizeof (ehdr32) - EI_NIDENT,
241*a9fa9459Szrj 		 1, file) != 1)
242*a9fa9459Szrj 	return 0;
243*a9fa9459Szrj 
244*a9fa9459Szrj       elf_header.e_type      = BYTE_GET (ehdr32.e_type);
245*a9fa9459Szrj       elf_header.e_machine   = BYTE_GET (ehdr32.e_machine);
246*a9fa9459Szrj       elf_header.e_version   = BYTE_GET (ehdr32.e_version);
247*a9fa9459Szrj       elf_header.e_entry     = BYTE_GET (ehdr32.e_entry);
248*a9fa9459Szrj       elf_header.e_phoff     = BYTE_GET (ehdr32.e_phoff);
249*a9fa9459Szrj       elf_header.e_shoff     = BYTE_GET (ehdr32.e_shoff);
250*a9fa9459Szrj       elf_header.e_flags     = BYTE_GET (ehdr32.e_flags);
251*a9fa9459Szrj       elf_header.e_ehsize    = BYTE_GET (ehdr32.e_ehsize);
252*a9fa9459Szrj       elf_header.e_phentsize = BYTE_GET (ehdr32.e_phentsize);
253*a9fa9459Szrj       elf_header.e_phnum     = BYTE_GET (ehdr32.e_phnum);
254*a9fa9459Szrj       elf_header.e_shentsize = BYTE_GET (ehdr32.e_shentsize);
255*a9fa9459Szrj       elf_header.e_shnum     = BYTE_GET (ehdr32.e_shnum);
256*a9fa9459Szrj       elf_header.e_shstrndx  = BYTE_GET (ehdr32.e_shstrndx);
257*a9fa9459Szrj 
258*a9fa9459Szrj       memcpy (&ehdr32, &elf_header, EI_NIDENT);
259*a9fa9459Szrj       break;
260*a9fa9459Szrj 
261*a9fa9459Szrj     case ELFCLASS64:
262*a9fa9459Szrj       /* If we have been compiled with sizeof (bfd_vma) == 4, then
263*a9fa9459Szrj 	 we will not be able to cope with the 64bit data found in
264*a9fa9459Szrj 	 64 ELF files.  Detect this now and abort before we start
265*a9fa9459Szrj 	 overwriting things.  */
266*a9fa9459Szrj       if (sizeof (bfd_vma) < 8)
267*a9fa9459Szrj 	{
268*a9fa9459Szrj 	  error (_("This executable has been built without support for a\n\
269*a9fa9459Szrj 64 bit data type and so it cannot process 64 bit ELF files.\n"));
270*a9fa9459Szrj 	  return 0;
271*a9fa9459Szrj 	}
272*a9fa9459Szrj 
273*a9fa9459Szrj       if (fread (ehdr64.e_type, sizeof (ehdr64) - EI_NIDENT,
274*a9fa9459Szrj 		 1, file) != 1)
275*a9fa9459Szrj 	return 0;
276*a9fa9459Szrj 
277*a9fa9459Szrj       elf_header.e_type      = BYTE_GET (ehdr64.e_type);
278*a9fa9459Szrj       elf_header.e_machine   = BYTE_GET (ehdr64.e_machine);
279*a9fa9459Szrj       elf_header.e_version   = BYTE_GET (ehdr64.e_version);
280*a9fa9459Szrj       elf_header.e_entry     = BYTE_GET (ehdr64.e_entry);
281*a9fa9459Szrj       elf_header.e_phoff     = BYTE_GET (ehdr64.e_phoff);
282*a9fa9459Szrj       elf_header.e_shoff     = BYTE_GET (ehdr64.e_shoff);
283*a9fa9459Szrj       elf_header.e_flags     = BYTE_GET (ehdr64.e_flags);
284*a9fa9459Szrj       elf_header.e_ehsize    = BYTE_GET (ehdr64.e_ehsize);
285*a9fa9459Szrj       elf_header.e_phentsize = BYTE_GET (ehdr64.e_phentsize);
286*a9fa9459Szrj       elf_header.e_phnum     = BYTE_GET (ehdr64.e_phnum);
287*a9fa9459Szrj       elf_header.e_shentsize = BYTE_GET (ehdr64.e_shentsize);
288*a9fa9459Szrj       elf_header.e_shnum     = BYTE_GET (ehdr64.e_shnum);
289*a9fa9459Szrj       elf_header.e_shstrndx  = BYTE_GET (ehdr64.e_shstrndx);
290*a9fa9459Szrj 
291*a9fa9459Szrj       memcpy (&ehdr64, &elf_header, EI_NIDENT);
292*a9fa9459Szrj       break;
293*a9fa9459Szrj     }
294*a9fa9459Szrj   return 1;
295*a9fa9459Szrj }
296*a9fa9459Szrj 
297*a9fa9459Szrj /* Process one ELF object file according to the command line options.
298*a9fa9459Szrj    This file may actually be stored in an archive.  The file is
299*a9fa9459Szrj    positioned at the start of the ELF object.  */
300*a9fa9459Szrj 
301*a9fa9459Szrj static int
process_object(const char * file_name,FILE * file)302*a9fa9459Szrj process_object (const char *file_name, FILE *file)
303*a9fa9459Szrj {
304*a9fa9459Szrj   /* Rememeber where we are.  */
305*a9fa9459Szrj   long offset = ftell (file);
306*a9fa9459Szrj 
307*a9fa9459Szrj   if (! get_file_header (file))
308*a9fa9459Szrj     {
309*a9fa9459Szrj       error (_("%s: Failed to read ELF header\n"), file_name);
310*a9fa9459Szrj       return 1;
311*a9fa9459Szrj     }
312*a9fa9459Szrj 
313*a9fa9459Szrj   /* Go to the position of the ELF header.  */
314*a9fa9459Szrj   if (fseek (file, offset, SEEK_SET) != 0)
315*a9fa9459Szrj     {
316*a9fa9459Szrj       error (_("%s: Failed to seek to ELF header\n"), file_name);
317*a9fa9459Szrj     }
318*a9fa9459Szrj 
319*a9fa9459Szrj   if (! update_elf_header (file_name, file))
320*a9fa9459Szrj     return 1;
321*a9fa9459Szrj 
322*a9fa9459Szrj   return 0;
323*a9fa9459Szrj }
324*a9fa9459Szrj 
325*a9fa9459Szrj /* Process an ELF archive.
326*a9fa9459Szrj    On entry the file is positioned just after the ARMAG string.  */
327*a9fa9459Szrj 
328*a9fa9459Szrj static int
process_archive(const char * file_name,FILE * file,bfd_boolean is_thin_archive)329*a9fa9459Szrj process_archive (const char * file_name, FILE * file,
330*a9fa9459Szrj 		 bfd_boolean is_thin_archive)
331*a9fa9459Szrj {
332*a9fa9459Szrj   struct archive_info arch;
333*a9fa9459Szrj   struct archive_info nested_arch;
334*a9fa9459Szrj   size_t got;
335*a9fa9459Szrj   int ret;
336*a9fa9459Szrj 
337*a9fa9459Szrj   /* The ARCH structure is used to hold information about this archive.  */
338*a9fa9459Szrj   arch.file_name = NULL;
339*a9fa9459Szrj   arch.file = NULL;
340*a9fa9459Szrj   arch.index_array = NULL;
341*a9fa9459Szrj   arch.sym_table = NULL;
342*a9fa9459Szrj   arch.longnames = NULL;
343*a9fa9459Szrj 
344*a9fa9459Szrj   /* The NESTED_ARCH structure is used as a single-item cache of information
345*a9fa9459Szrj      about a nested archive (when members of a thin archive reside within
346*a9fa9459Szrj      another regular archive file).  */
347*a9fa9459Szrj   nested_arch.file_name = NULL;
348*a9fa9459Szrj   nested_arch.file = NULL;
349*a9fa9459Szrj   nested_arch.index_array = NULL;
350*a9fa9459Szrj   nested_arch.sym_table = NULL;
351*a9fa9459Szrj   nested_arch.longnames = NULL;
352*a9fa9459Szrj 
353*a9fa9459Szrj   if (setup_archive (&arch, file_name, file, is_thin_archive, FALSE) != 0)
354*a9fa9459Szrj     {
355*a9fa9459Szrj       ret = 1;
356*a9fa9459Szrj       goto out;
357*a9fa9459Szrj     }
358*a9fa9459Szrj 
359*a9fa9459Szrj   ret = 0;
360*a9fa9459Szrj 
361*a9fa9459Szrj   while (1)
362*a9fa9459Szrj     {
363*a9fa9459Szrj       char * name;
364*a9fa9459Szrj       size_t namelen;
365*a9fa9459Szrj       char * qualified_name;
366*a9fa9459Szrj 
367*a9fa9459Szrj       /* Read the next archive header.  */
368*a9fa9459Szrj       if (fseek (file, arch.next_arhdr_offset, SEEK_SET) != 0)
369*a9fa9459Szrj         {
370*a9fa9459Szrj           error (_("%s: failed to seek to next archive header\n"),
371*a9fa9459Szrj 		     file_name);
372*a9fa9459Szrj           return 1;
373*a9fa9459Szrj         }
374*a9fa9459Szrj       got = fread (&arch.arhdr, 1, sizeof arch.arhdr, file);
375*a9fa9459Szrj       if (got != sizeof arch.arhdr)
376*a9fa9459Szrj         {
377*a9fa9459Szrj           if (got == 0)
378*a9fa9459Szrj 	    break;
379*a9fa9459Szrj           error (_("%s: failed to read archive header\n"),
380*a9fa9459Szrj 		     file_name);
381*a9fa9459Szrj           ret = 1;
382*a9fa9459Szrj           break;
383*a9fa9459Szrj         }
384*a9fa9459Szrj       if (memcmp (arch.arhdr.ar_fmag, ARFMAG, 2) != 0)
385*a9fa9459Szrj         {
386*a9fa9459Szrj           error (_("%s: did not find a valid archive header\n"),
387*a9fa9459Szrj 		     arch.file_name);
388*a9fa9459Szrj           ret = 1;
389*a9fa9459Szrj           break;
390*a9fa9459Szrj         }
391*a9fa9459Szrj 
392*a9fa9459Szrj       arch.next_arhdr_offset += sizeof arch.arhdr;
393*a9fa9459Szrj 
394*a9fa9459Szrj       archive_file_size = strtoul (arch.arhdr.ar_size, NULL, 10);
395*a9fa9459Szrj       if (archive_file_size & 01)
396*a9fa9459Szrj         ++archive_file_size;
397*a9fa9459Szrj 
398*a9fa9459Szrj       name = get_archive_member_name (&arch, &nested_arch);
399*a9fa9459Szrj       if (name == NULL)
400*a9fa9459Szrj 	{
401*a9fa9459Szrj 	  error (_("%s: bad archive file name\n"), file_name);
402*a9fa9459Szrj 	  ret = 1;
403*a9fa9459Szrj 	  break;
404*a9fa9459Szrj 	}
405*a9fa9459Szrj       namelen = strlen (name);
406*a9fa9459Szrj 
407*a9fa9459Szrj       qualified_name = make_qualified_name (&arch, &nested_arch, name);
408*a9fa9459Szrj       if (qualified_name == NULL)
409*a9fa9459Szrj 	{
410*a9fa9459Szrj 	  error (_("%s: bad archive file name\n"), file_name);
411*a9fa9459Szrj 	  ret = 1;
412*a9fa9459Szrj 	  break;
413*a9fa9459Szrj 	}
414*a9fa9459Szrj 
415*a9fa9459Szrj       if (is_thin_archive && arch.nested_member_origin == 0)
416*a9fa9459Szrj         {
417*a9fa9459Szrj           /* This is a proxy for an external member of a thin archive.  */
418*a9fa9459Szrj           FILE *member_file;
419*a9fa9459Szrj           char *member_file_name = adjust_relative_path (file_name,
420*a9fa9459Szrj 							 name, namelen);
421*a9fa9459Szrj           if (member_file_name == NULL)
422*a9fa9459Szrj             {
423*a9fa9459Szrj               ret = 1;
424*a9fa9459Szrj               break;
425*a9fa9459Szrj             }
426*a9fa9459Szrj 
427*a9fa9459Szrj           member_file = fopen (member_file_name, "r+b");
428*a9fa9459Szrj           if (member_file == NULL)
429*a9fa9459Szrj             {
430*a9fa9459Szrj               error (_("Input file '%s' is not readable\n"),
431*a9fa9459Szrj 			 member_file_name);
432*a9fa9459Szrj               free (member_file_name);
433*a9fa9459Szrj               ret = 1;
434*a9fa9459Szrj               break;
435*a9fa9459Szrj             }
436*a9fa9459Szrj 
437*a9fa9459Szrj           archive_file_offset = arch.nested_member_origin;
438*a9fa9459Szrj 
439*a9fa9459Szrj           ret |= process_object (qualified_name, member_file);
440*a9fa9459Szrj 
441*a9fa9459Szrj           fclose (member_file);
442*a9fa9459Szrj           free (member_file_name);
443*a9fa9459Szrj         }
444*a9fa9459Szrj       else if (is_thin_archive)
445*a9fa9459Szrj         {
446*a9fa9459Szrj           /* This is a proxy for a member of a nested archive.  */
447*a9fa9459Szrj           archive_file_offset = arch.nested_member_origin + sizeof arch.arhdr;
448*a9fa9459Szrj 
449*a9fa9459Szrj           /* The nested archive file will have been opened and setup by
450*a9fa9459Szrj              get_archive_member_name.  */
451*a9fa9459Szrj           if (fseek (nested_arch.file, archive_file_offset,
452*a9fa9459Szrj 		     SEEK_SET) != 0)
453*a9fa9459Szrj             {
454*a9fa9459Szrj               error (_("%s: failed to seek to archive member\n"),
455*a9fa9459Szrj 			 nested_arch.file_name);
456*a9fa9459Szrj               ret = 1;
457*a9fa9459Szrj               break;
458*a9fa9459Szrj             }
459*a9fa9459Szrj 
460*a9fa9459Szrj           ret |= process_object (qualified_name, nested_arch.file);
461*a9fa9459Szrj         }
462*a9fa9459Szrj       else
463*a9fa9459Szrj         {
464*a9fa9459Szrj           archive_file_offset = arch.next_arhdr_offset;
465*a9fa9459Szrj           arch.next_arhdr_offset += archive_file_size;
466*a9fa9459Szrj 
467*a9fa9459Szrj           ret |= process_object (qualified_name, file);
468*a9fa9459Szrj         }
469*a9fa9459Szrj 
470*a9fa9459Szrj       free (qualified_name);
471*a9fa9459Szrj     }
472*a9fa9459Szrj 
473*a9fa9459Szrj  out:
474*a9fa9459Szrj   if (nested_arch.file != NULL)
475*a9fa9459Szrj     fclose (nested_arch.file);
476*a9fa9459Szrj   release_archive (&nested_arch);
477*a9fa9459Szrj   release_archive (&arch);
478*a9fa9459Szrj 
479*a9fa9459Szrj   return ret;
480*a9fa9459Szrj }
481*a9fa9459Szrj 
482*a9fa9459Szrj static int
check_file(const char * file_name,struct stat * statbuf_p)483*a9fa9459Szrj check_file (const char *file_name, struct stat *statbuf_p)
484*a9fa9459Szrj {
485*a9fa9459Szrj   struct stat statbuf;
486*a9fa9459Szrj 
487*a9fa9459Szrj   if (statbuf_p == NULL)
488*a9fa9459Szrj     statbuf_p = &statbuf;
489*a9fa9459Szrj 
490*a9fa9459Szrj   if (stat (file_name, statbuf_p) < 0)
491*a9fa9459Szrj     {
492*a9fa9459Szrj       if (errno == ENOENT)
493*a9fa9459Szrj 	error (_("'%s': No such file\n"), file_name);
494*a9fa9459Szrj       else
495*a9fa9459Szrj 	error (_("Could not locate '%s'.  System error message: %s\n"),
496*a9fa9459Szrj 		   file_name, strerror (errno));
497*a9fa9459Szrj       return 1;
498*a9fa9459Szrj     }
499*a9fa9459Szrj 
500*a9fa9459Szrj   if (! S_ISREG (statbuf_p->st_mode))
501*a9fa9459Szrj     {
502*a9fa9459Szrj       error (_("'%s' is not an ordinary file\n"), file_name);
503*a9fa9459Szrj       return 1;
504*a9fa9459Szrj     }
505*a9fa9459Szrj 
506*a9fa9459Szrj   return 0;
507*a9fa9459Szrj }
508*a9fa9459Szrj 
509*a9fa9459Szrj static int
process_file(const char * file_name)510*a9fa9459Szrj process_file (const char *file_name)
511*a9fa9459Szrj {
512*a9fa9459Szrj   FILE * file;
513*a9fa9459Szrj   char armag[SARMAG];
514*a9fa9459Szrj   int ret;
515*a9fa9459Szrj 
516*a9fa9459Szrj   if (check_file (file_name, NULL))
517*a9fa9459Szrj     return 1;
518*a9fa9459Szrj 
519*a9fa9459Szrj   file = fopen (file_name, "r+b");
520*a9fa9459Szrj   if (file == NULL)
521*a9fa9459Szrj     {
522*a9fa9459Szrj       error (_("Input file '%s' is not readable\n"), file_name);
523*a9fa9459Szrj       return 1;
524*a9fa9459Szrj     }
525*a9fa9459Szrj 
526*a9fa9459Szrj   if (fread (armag, SARMAG, 1, file) != 1)
527*a9fa9459Szrj     {
528*a9fa9459Szrj       error (_("%s: Failed to read file's magic number\n"),
529*a9fa9459Szrj 		 file_name);
530*a9fa9459Szrj       fclose (file);
531*a9fa9459Szrj       return 1;
532*a9fa9459Szrj     }
533*a9fa9459Szrj 
534*a9fa9459Szrj   if (memcmp (armag, ARMAG, SARMAG) == 0)
535*a9fa9459Szrj     ret = process_archive (file_name, file, FALSE);
536*a9fa9459Szrj   else if (memcmp (armag, ARMAGT, SARMAG) == 0)
537*a9fa9459Szrj     ret = process_archive (file_name, file, TRUE);
538*a9fa9459Szrj   else
539*a9fa9459Szrj     {
540*a9fa9459Szrj       rewind (file);
541*a9fa9459Szrj       archive_file_size = archive_file_offset = 0;
542*a9fa9459Szrj       ret = process_object (file_name, file);
543*a9fa9459Szrj     }
544*a9fa9459Szrj 
545*a9fa9459Szrj   fclose (file);
546*a9fa9459Szrj 
547*a9fa9459Szrj   return ret;
548*a9fa9459Szrj }
549*a9fa9459Szrj 
550*a9fa9459Szrj static const struct
551*a9fa9459Szrj {
552*a9fa9459Szrj   int osabi;
553*a9fa9459Szrj   const char *name;
554*a9fa9459Szrj }
555*a9fa9459Szrj osabis[] =
556*a9fa9459Szrj {
557*a9fa9459Szrj   { ELFOSABI_NONE, "none" },
558*a9fa9459Szrj   { ELFOSABI_HPUX, "HPUX" },
559*a9fa9459Szrj   { ELFOSABI_NETBSD, "NetBSD" },
560*a9fa9459Szrj   { ELFOSABI_GNU, "GNU" },
561*a9fa9459Szrj   { ELFOSABI_GNU, "Linux" },
562*a9fa9459Szrj   { ELFOSABI_SOLARIS, "Solaris" },
563*a9fa9459Szrj   { ELFOSABI_AIX, "AIX" },
564*a9fa9459Szrj   { ELFOSABI_IRIX, "Irix" },
565*a9fa9459Szrj   { ELFOSABI_FREEBSD, "FreeBSD" },
566*a9fa9459Szrj   { ELFOSABI_TRU64, "TRU64" },
567*a9fa9459Szrj   { ELFOSABI_MODESTO, "Modesto" },
568*a9fa9459Szrj   { ELFOSABI_OPENBSD, "OpenBSD" },
569*a9fa9459Szrj   { ELFOSABI_OPENVMS, "OpenVMS" },
570*a9fa9459Szrj   { ELFOSABI_NSK, "NSK" },
571*a9fa9459Szrj   { ELFOSABI_AROS, "AROS" },
572*a9fa9459Szrj   { ELFOSABI_FENIXOS, "FenixOS" }
573*a9fa9459Szrj };
574*a9fa9459Szrj 
575*a9fa9459Szrj /* Return ELFOSABI_XXX for an OSABI string, OSABI.  */
576*a9fa9459Szrj 
577*a9fa9459Szrj static int
elf_osabi(const char * osabi)578*a9fa9459Szrj elf_osabi (const char *osabi)
579*a9fa9459Szrj {
580*a9fa9459Szrj   unsigned int i;
581*a9fa9459Szrj 
582*a9fa9459Szrj   for (i = 0; i < ARRAY_SIZE (osabis); i++)
583*a9fa9459Szrj     if (strcasecmp (osabi, osabis[i].name) == 0)
584*a9fa9459Szrj       return osabis[i].osabi;
585*a9fa9459Szrj 
586*a9fa9459Szrj   error (_("Unknown OSABI: %s\n"), osabi);
587*a9fa9459Szrj 
588*a9fa9459Szrj   return -1;
589*a9fa9459Szrj }
590*a9fa9459Szrj 
591*a9fa9459Szrj /* Return EM_XXX for a machine string, MACH.  */
592*a9fa9459Szrj 
593*a9fa9459Szrj static int
elf_machine(const char * mach)594*a9fa9459Szrj elf_machine (const char *mach)
595*a9fa9459Szrj {
596*a9fa9459Szrj   if (strcasecmp (mach, "i386") == 0)
597*a9fa9459Szrj     return EM_386;
598*a9fa9459Szrj   if (strcasecmp (mach, "iamcu") == 0)
599*a9fa9459Szrj     return EM_IAMCU;
600*a9fa9459Szrj   if (strcasecmp (mach, "l1om") == 0)
601*a9fa9459Szrj     return EM_L1OM;
602*a9fa9459Szrj   if (strcasecmp (mach, "k1om") == 0)
603*a9fa9459Szrj     return EM_K1OM;
604*a9fa9459Szrj   if (strcasecmp (mach, "x86_64") == 0)
605*a9fa9459Szrj     return EM_X86_64;
606*a9fa9459Szrj   if (strcasecmp (mach, "x86-64") == 0)
607*a9fa9459Szrj     return EM_X86_64;
608*a9fa9459Szrj   if (strcasecmp (mach, "none") == 0)
609*a9fa9459Szrj     return EM_NONE;
610*a9fa9459Szrj 
611*a9fa9459Szrj   error (_("Unknown machine type: %s\n"), mach);
612*a9fa9459Szrj 
613*a9fa9459Szrj   return -1;
614*a9fa9459Szrj }
615*a9fa9459Szrj 
616*a9fa9459Szrj /* Return ET_XXX for a type string, TYPE.  */
617*a9fa9459Szrj 
618*a9fa9459Szrj static int
elf_type(const char * type)619*a9fa9459Szrj elf_type (const char *type)
620*a9fa9459Szrj {
621*a9fa9459Szrj   if (strcasecmp (type, "rel") == 0)
622*a9fa9459Szrj     return ET_REL;
623*a9fa9459Szrj   if (strcasecmp (type, "exec") == 0)
624*a9fa9459Szrj     return ET_EXEC;
625*a9fa9459Szrj   if (strcasecmp (type, "dyn") == 0)
626*a9fa9459Szrj     return ET_DYN;
627*a9fa9459Szrj   if (strcasecmp (type, "none") == 0)
628*a9fa9459Szrj     return ET_NONE;
629*a9fa9459Szrj 
630*a9fa9459Szrj   error (_("Unknown type: %s\n"), type);
631*a9fa9459Szrj 
632*a9fa9459Szrj   return -1;
633*a9fa9459Szrj }
634*a9fa9459Szrj 
635*a9fa9459Szrj enum command_line_switch
636*a9fa9459Szrj   {
637*a9fa9459Szrj     OPTION_INPUT_MACH = 150,
638*a9fa9459Szrj     OPTION_OUTPUT_MACH,
639*a9fa9459Szrj     OPTION_INPUT_TYPE,
640*a9fa9459Szrj     OPTION_OUTPUT_TYPE,
641*a9fa9459Szrj     OPTION_INPUT_OSABI,
642*a9fa9459Szrj     OPTION_OUTPUT_OSABI
643*a9fa9459Szrj   };
644*a9fa9459Szrj 
645*a9fa9459Szrj static struct option options[] =
646*a9fa9459Szrj {
647*a9fa9459Szrj   {"input-mach",	required_argument, 0, OPTION_INPUT_MACH},
648*a9fa9459Szrj   {"output-mach",	required_argument, 0, OPTION_OUTPUT_MACH},
649*a9fa9459Szrj   {"input-type",	required_argument, 0, OPTION_INPUT_TYPE},
650*a9fa9459Szrj   {"output-type",	required_argument, 0, OPTION_OUTPUT_TYPE},
651*a9fa9459Szrj   {"input-osabi",	required_argument, 0, OPTION_INPUT_OSABI},
652*a9fa9459Szrj   {"output-osabi",	required_argument, 0, OPTION_OUTPUT_OSABI},
653*a9fa9459Szrj   {"version",		no_argument, 0, 'v'},
654*a9fa9459Szrj   {"help",		no_argument, 0, 'h'},
655*a9fa9459Szrj   {0,			no_argument, 0, 0}
656*a9fa9459Szrj };
657*a9fa9459Szrj 
658*a9fa9459Szrj static void
usage(FILE * stream,int exit_status)659*a9fa9459Szrj usage (FILE *stream, int exit_status)
660*a9fa9459Szrj {
661*a9fa9459Szrj   fprintf (stream, _("Usage: %s <option(s)> elffile(s)\n"),
662*a9fa9459Szrj 	   program_name);
663*a9fa9459Szrj   fprintf (stream, _(" Update the ELF header of ELF files\n"));
664*a9fa9459Szrj   fprintf (stream, _(" The options are:\n"));
665*a9fa9459Szrj   fprintf (stream, _("\
666*a9fa9459Szrj   --input-mach <machine>      Set input machine type to <machine>\n\
667*a9fa9459Szrj   --output-mach <machine>     Set output machine type to <machine>\n\
668*a9fa9459Szrj   --input-type <type>         Set input file type to <type>\n\
669*a9fa9459Szrj   --output-type <type>        Set output file type to <type>\n\
670*a9fa9459Szrj   --input-osabi <osabi>       Set input OSABI to <osabi>\n\
671*a9fa9459Szrj   --output-osabi <osabi>      Set output OSABI to <osabi>\n\
672*a9fa9459Szrj   -h --help                   Display this information\n\
673*a9fa9459Szrj   -v --version                Display the version number of %s\n\
674*a9fa9459Szrj "),
675*a9fa9459Szrj 	   program_name);
676*a9fa9459Szrj   if (REPORT_BUGS_TO[0] && exit_status == 0)
677*a9fa9459Szrj     fprintf (stream, _("Report bugs to %s\n"), REPORT_BUGS_TO);
678*a9fa9459Szrj   exit (exit_status);
679*a9fa9459Szrj }
680*a9fa9459Szrj 
681*a9fa9459Szrj int
main(int argc,char ** argv)682*a9fa9459Szrj main (int argc, char ** argv)
683*a9fa9459Szrj {
684*a9fa9459Szrj   int c, status;
685*a9fa9459Szrj 
686*a9fa9459Szrj #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
687*a9fa9459Szrj   setlocale (LC_MESSAGES, "");
688*a9fa9459Szrj #endif
689*a9fa9459Szrj #if defined (HAVE_SETLOCALE)
690*a9fa9459Szrj   setlocale (LC_CTYPE, "");
691*a9fa9459Szrj #endif
692*a9fa9459Szrj   bindtextdomain (PACKAGE, LOCALEDIR);
693*a9fa9459Szrj   textdomain (PACKAGE);
694*a9fa9459Szrj 
695*a9fa9459Szrj   expandargv (&argc, &argv);
696*a9fa9459Szrj 
697*a9fa9459Szrj   while ((c = getopt_long (argc, argv, "hv",
698*a9fa9459Szrj 			   options, (int *) 0)) != EOF)
699*a9fa9459Szrj     {
700*a9fa9459Szrj       switch (c)
701*a9fa9459Szrj 	{
702*a9fa9459Szrj 	case OPTION_INPUT_MACH:
703*a9fa9459Szrj 	  input_elf_machine = elf_machine (optarg);
704*a9fa9459Szrj 	  if (input_elf_machine < 0)
705*a9fa9459Szrj 	    return 1;
706*a9fa9459Szrj 	  input_elf_class = elf_class (input_elf_machine);
707*a9fa9459Szrj 	  if (input_elf_class == ELF_CLASS_UNKNOWN)
708*a9fa9459Szrj 	    return 1;
709*a9fa9459Szrj 	  break;
710*a9fa9459Szrj 
711*a9fa9459Szrj 	case OPTION_OUTPUT_MACH:
712*a9fa9459Szrj 	  output_elf_machine = elf_machine (optarg);
713*a9fa9459Szrj 	  if (output_elf_machine < 0)
714*a9fa9459Szrj 	    return 1;
715*a9fa9459Szrj 	  output_elf_class = elf_class (output_elf_machine);
716*a9fa9459Szrj 	  if (output_elf_class == ELF_CLASS_UNKNOWN)
717*a9fa9459Szrj 	    return 1;
718*a9fa9459Szrj 	  break;
719*a9fa9459Szrj 
720*a9fa9459Szrj 	case OPTION_INPUT_TYPE:
721*a9fa9459Szrj 	  input_elf_type = elf_type (optarg);
722*a9fa9459Szrj 	  if (input_elf_type < 0)
723*a9fa9459Szrj 	    return 1;
724*a9fa9459Szrj 	  break;
725*a9fa9459Szrj 
726*a9fa9459Szrj 	case OPTION_OUTPUT_TYPE:
727*a9fa9459Szrj 	  output_elf_type = elf_type (optarg);
728*a9fa9459Szrj 	  if (output_elf_type < 0)
729*a9fa9459Szrj 	    return 1;
730*a9fa9459Szrj 	  break;
731*a9fa9459Szrj 
732*a9fa9459Szrj 	case OPTION_INPUT_OSABI:
733*a9fa9459Szrj 	  input_elf_osabi = elf_osabi (optarg);
734*a9fa9459Szrj 	  if (input_elf_osabi < 0)
735*a9fa9459Szrj 	    return 1;
736*a9fa9459Szrj 	  break;
737*a9fa9459Szrj 
738*a9fa9459Szrj 	case OPTION_OUTPUT_OSABI:
739*a9fa9459Szrj 	  output_elf_osabi = elf_osabi (optarg);
740*a9fa9459Szrj 	  if (output_elf_osabi < 0)
741*a9fa9459Szrj 	    return 1;
742*a9fa9459Szrj 	  break;
743*a9fa9459Szrj 
744*a9fa9459Szrj 	case 'h':
745*a9fa9459Szrj 	  usage (stdout, 0);
746*a9fa9459Szrj 
747*a9fa9459Szrj 	case 'v':
748*a9fa9459Szrj 	  print_version (program_name);
749*a9fa9459Szrj 	  break;
750*a9fa9459Szrj 
751*a9fa9459Szrj 	default:
752*a9fa9459Szrj 	  usage (stderr, 1);
753*a9fa9459Szrj 	}
754*a9fa9459Szrj     }
755*a9fa9459Szrj 
756*a9fa9459Szrj   if (optind == argc
757*a9fa9459Szrj       || (output_elf_machine == -1
758*a9fa9459Szrj 	  && output_elf_type == -1
759*a9fa9459Szrj 	  && output_elf_osabi == -1))
760*a9fa9459Szrj     usage (stderr, 1);
761*a9fa9459Szrj 
762*a9fa9459Szrj   status = 0;
763*a9fa9459Szrj   while (optind < argc)
764*a9fa9459Szrj     status |= process_file (argv[optind++]);
765*a9fa9459Szrj 
766*a9fa9459Szrj   return status;
767*a9fa9459Szrj }
768