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