gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / binutils / elfedit.c
index b71990ce2616dd00fd01f64831f7d700de634fc4..d0e4e95f4d6ebdfbb88cba87434306ccd8a420bd 100644 (file)
@@ -1,6 +1,5 @@
 /* elfedit.c -- Update the ELF header of an ELF format file
-   Copyright 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 2010-2020 Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
@@ -22,7 +21,6 @@
 #include "config.h"
 #include "sysdep.h"
 #include <assert.h>
-#include <sys/stat.h>
 
 #if __GNUC__ >= 2
 /* Define BFD64 here, even if our default architecture is 32 bit ELF
 #endif
 
 #include "bfd.h"
+#include "elfcomm.h"
 #include "bucomm.h"
 
 #include "elf/common.h"
 #include "elf/external.h"
 #include "elf/internal.h"
 
-
-#include "aout/ar.h"
-
 #include "getopt.h"
 #include "libiberty.h"
 #include "safe-ctype.h"
@@ -57,195 +53,262 @@ static int input_elf_machine = -1;
 static int output_elf_machine = -1;
 static int input_elf_type = -1;
 static int output_elf_type = -1;
-static int input_elf_class = -1;
+static int input_elf_osabi = -1;
+static int output_elf_osabi = -1;
+enum elfclass
+  {
+    ELF_CLASS_UNKNOWN = -1,
+    ELF_CLASS_NONE = ELFCLASSNONE,
+    ELF_CLASS_32 = ELFCLASS32,
+    ELF_CLASS_64 = ELFCLASS64,
+    ELF_CLASS_BOTH
+  };
+static enum elfclass input_elf_class = ELF_CLASS_UNKNOWN;
+static enum elfclass output_elf_class = ELF_CLASS_BOTH;
 
-#define streq(a,b)       (strcmp ((a), (b)) == 0)
-#define strneq(a,b,n)    (strncmp ((a), (b), (n)) == 0)
-#define const_strneq(a,b) (strncmp ((a), (b), sizeof (b) - 1) == 0)
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
 
-void
-non_fatal (const char *message, ...)
-{
-  va_list args;
+static unsigned int enable_x86_features;
+static unsigned int disable_x86_features;
 
-  va_start (args, message);
-  fprintf (stderr, _("%s: Error: "), program_name);
-  vfprintf (stderr, message, args);
-  va_end (args);
-}
+static int
+update_gnu_property (const char *file_name, FILE *file)
+{
+  char *map;
+  Elf_Internal_Phdr *phdrs;
+  struct stat st_buf;
+  unsigned int i;
+  int ret;
 
-#define BYTE_GET(field)                byte_get (field, sizeof (field))
-#define BYTE_PUT(field, val)   byte_put (field, val, sizeof (field))
+  if (!enable_x86_features && !disable_x86_features)
+    return 0;
 
-static bfd_vma (*byte_get) (unsigned char *, int);
-static void (*byte_put) (unsigned char *, bfd_vma, int);
+  if (elf_header.e_machine != EM_386
+      && elf_header.e_machine != EM_X86_64)
+    {
+      error (_("%s: Not an i386 nor x86-64 ELF file\n"), file_name);
+      return 0;
+    }
 
-static bfd_vma
-byte_get_little_endian (unsigned char *field, int size)
-{
-  switch (size)
+  if (fstat (fileno (file), &st_buf) < 0)
     {
-    case 1:
-      return *field;
-
-    case 2:
-      return  ((unsigned int) (field[0]))
-       |    (((unsigned int) (field[1])) << 8);
-
-    case 4:
-      return  ((unsigned long) (field[0]))
-       |    (((unsigned long) (field[1])) << 8)
-       |    (((unsigned long) (field[2])) << 16)
-       |    (((unsigned long) (field[3])) << 24);
-
-    case 8:
-      if (sizeof (bfd_vma) == 8)
-       return  ((bfd_vma) (field[0]))
-         |    (((bfd_vma) (field[1])) << 8)
-         |    (((bfd_vma) (field[2])) << 16)
-         |    (((bfd_vma) (field[3])) << 24)
-         |    (((bfd_vma) (field[4])) << 32)
-         |    (((bfd_vma) (field[5])) << 40)
-         |    (((bfd_vma) (field[6])) << 48)
-         |    (((bfd_vma) (field[7])) << 56);
-      else if (sizeof (bfd_vma) == 4)
-       /* We want to extract data from an 8 byte wide field and
-          place it into a 4 byte wide field.  Since this is a little
-          endian source we can just use the 4 byte extraction code.  */
-       return  ((unsigned long) (field[0]))
-         |    (((unsigned long) (field[1])) << 8)
-         |    (((unsigned long) (field[2])) << 16)
-         |    (((unsigned long) (field[3])) << 24);
+      error (_("%s: stat () failed\n"), file_name);
+      return 1;
+    }
 
-    default:
-      non_fatal (_("Unhandled data length: %d\n"), size);
-      abort ();
+  map = mmap (NULL, st_buf.st_size, PROT_READ | PROT_WRITE,
+             MAP_SHARED, fileno (file), 0);
+  if (map == MAP_FAILED)
+    {
+      error (_("%s: mmap () failed\n"), file_name);
+      return 0;
     }
-}
 
-static bfd_vma
-byte_get_big_endian (unsigned char *field, int size)
-{
-  switch (size)
+  phdrs = xmalloc (elf_header.e_phnum * sizeof (*phdrs));
+
+  if (elf_header.e_ident[EI_CLASS] == ELFCLASS32)
     {
-    case 1:
-      return *field;
-
-    case 2:
-      return ((unsigned int) (field[1])) | (((int) (field[0])) << 8);
-
-    case 4:
-      return ((unsigned long) (field[3]))
-       |   (((unsigned long) (field[2])) << 8)
-       |   (((unsigned long) (field[1])) << 16)
-       |   (((unsigned long) (field[0])) << 24);
-
-    case 8:
-      if (sizeof (bfd_vma) == 8)
-       return ((bfd_vma) (field[7]))
-         |   (((bfd_vma) (field[6])) << 8)
-         |   (((bfd_vma) (field[5])) << 16)
-         |   (((bfd_vma) (field[4])) << 24)
-         |   (((bfd_vma) (field[3])) << 32)
-         |   (((bfd_vma) (field[2])) << 40)
-         |   (((bfd_vma) (field[1])) << 48)
-         |   (((bfd_vma) (field[0])) << 56);
-      else if (sizeof (bfd_vma) == 4)
+      Elf32_External_Phdr *phdrs32
+       = (Elf32_External_Phdr *) (map + elf_header.e_phoff);
+      for (i = 0; i < elf_header.e_phnum; i++)
        {
-         /* Although we are extracing data from an 8 byte wide field,
-            we are returning only 4 bytes of data.  */
-         field += 4;
-         return ((unsigned long) (field[3]))
-           |   (((unsigned long) (field[2])) << 8)
-           |   (((unsigned long) (field[1])) << 16)
-           |   (((unsigned long) (field[0])) << 24);
+         phdrs[i].p_type = BYTE_GET (phdrs32[i].p_type);
+         phdrs[i].p_offset = BYTE_GET (phdrs32[i].p_offset);
+         phdrs[i].p_vaddr = BYTE_GET (phdrs32[i].p_vaddr);
+         phdrs[i].p_paddr = BYTE_GET (phdrs32[i].p_paddr);
+         phdrs[i].p_filesz = BYTE_GET (phdrs32[i].p_filesz);
+         phdrs[i].p_memsz = BYTE_GET (phdrs32[i].p_memsz);
+         phdrs[i].p_flags = BYTE_GET (phdrs32[i].p_flags);
+         phdrs[i].p_align = BYTE_GET (phdrs32[i].p_align);
+       }
+    }
+  else
+    {
+      Elf64_External_Phdr *phdrs64
+       = (Elf64_External_Phdr *) (map + elf_header.e_phoff);
+      for (i = 0; i < elf_header.e_phnum; i++)
+       {
+         phdrs[i].p_type = BYTE_GET (phdrs64[i].p_type);
+         phdrs[i].p_offset = BYTE_GET (phdrs64[i].p_offset);
+         phdrs[i].p_vaddr = BYTE_GET (phdrs64[i].p_vaddr);
+         phdrs[i].p_paddr = BYTE_GET (phdrs64[i].p_paddr);
+         phdrs[i].p_filesz = BYTE_GET (phdrs64[i].p_filesz);
+         phdrs[i].p_memsz = BYTE_GET (phdrs64[i].p_memsz);
+         phdrs[i].p_flags = BYTE_GET (phdrs64[i].p_flags);
+         phdrs[i].p_align = BYTE_GET (phdrs64[i].p_align);
        }
-
-    default:
-      non_fatal (_("Unhandled data length: %d\n"), size);
-      abort ();
     }
+
+  ret = 0;
+  for (i = 0; i < elf_header.e_phnum; i++)
+    if (phdrs[i].p_type == PT_NOTE)
+      {
+       size_t offset = phdrs[i].p_offset;
+       size_t size = phdrs[i].p_filesz;
+       size_t align = phdrs[i].p_align;
+       char *buf = map + offset;
+       char *p = buf;
+
+       while (p < buf + size)
+         {
+           Elf_External_Note *xnp = (Elf_External_Note *) p;
+           Elf_Internal_Note in;
+
+           if (offsetof (Elf_External_Note, name) > buf - p + size)
+             {
+               ret = 1;
+               goto out;
+             }
+
+           in.type = BYTE_GET (xnp->type);
+           in.namesz = BYTE_GET (xnp->namesz);
+           in.namedata = xnp->name;
+           if (in.namesz > buf - in.namedata + size)
+             {
+               ret = 1;
+               goto out;
+             }
+
+           in.descsz = BYTE_GET (xnp->descsz);
+           in.descdata = p + ELF_NOTE_DESC_OFFSET (in.namesz, align);
+           in.descpos = offset + (in.descdata - buf);
+           if (in.descsz != 0
+               && (in.descdata >= buf + size
+                   || in.descsz > buf - in.descdata + size))
+             {
+               ret = 1;
+               goto out;
+             }
+
+           if (in.namesz == sizeof "GNU"
+               && strcmp (in.namedata, "GNU") == 0
+               && in.type == NT_GNU_PROPERTY_TYPE_0)
+             {
+               unsigned char *ptr;
+               unsigned char *ptr_end;
+
+               if (in.descsz < 8 || (in.descsz % align) != 0)
+                 {
+                   ret = 1;
+                   goto out;
+                 }
+
+               ptr = (unsigned char *) in.descdata;
+               ptr_end = ptr + in.descsz;
+
+               do
+                 {
+                   unsigned int type = byte_get (ptr, 4);
+                   unsigned int datasz = byte_get (ptr + 4, 4);
+                   unsigned int bitmask, old_bitmask;
+
+                   ptr += 8;
+                   if ((ptr + datasz) > ptr_end)
+                     {
+                       ret = 1;
+                       goto out;
+                     }
+
+                   if (type == GNU_PROPERTY_X86_FEATURE_1_AND)
+                     {
+                       if (datasz != 4)
+                         {
+                           ret = 1;
+                           goto out;
+                         }
+
+                       old_bitmask = byte_get (ptr, 4);
+                       bitmask = old_bitmask;
+                       if (enable_x86_features)
+                         bitmask |= enable_x86_features;
+                       if (disable_x86_features)
+                         bitmask &= ~disable_x86_features;
+                       if (old_bitmask != bitmask)
+                         byte_put (ptr, bitmask, 4);
+                       goto out;
+                     }
+
+                   ptr += ELF_ALIGN_UP (datasz, align);
+                 }
+               while ((ptr_end - ptr) >= 8);
+             }
+
+           p += ELF_NOTE_NEXT_OFFSET (in.namesz, in.descsz, align);
+         }
+      }
+
+ out:
+  if (ret != 0)
+    error (_("%s: Invalid PT_NOTE segment\n"), file_name);
+
+  free (phdrs);
+  munmap (map, st_buf.st_size);
+
+  return ret;
 }
 
-static void
-byte_put_little_endian (unsigned char * field, bfd_vma value, int size)
+/* Set enable_x86_features and disable_x86_features for a feature
+   string, FEATURE.  */
+
+static int
+elf_x86_feature (const char *feature, int enable)
 {
-  switch (size)
+  unsigned int x86_feature;
+  if (strcasecmp (feature, "ibt") == 0)
+    x86_feature = GNU_PROPERTY_X86_FEATURE_1_IBT;
+  else if (strcasecmp (feature, "shstk") == 0)
+    x86_feature = GNU_PROPERTY_X86_FEATURE_1_SHSTK;
+  else
     {
-    case 8:
-      field[7] = (((value >> 24) >> 24) >> 8) & 0xff;
-      field[6] = ((value >> 24) >> 24) & 0xff;
-      field[5] = ((value >> 24) >> 16) & 0xff;
-      field[4] = ((value >> 24) >> 8) & 0xff;
-      /* Fall through.  */
-    case 4:
-      field[3] = (value >> 24) & 0xff;
-      field[2] = (value >> 16) & 0xff;
-      /* Fall through.  */
-    case 2:
-      field[1] = (value >> 8) & 0xff;
-      /* Fall through.  */
-    case 1:
-      field[0] = value & 0xff;
-      break;
+      error (_("Unknown x86 feature: %s\n"), feature);
+      return -1;
+    }
 
-    default:
-      non_fatal (_("Unhandled data length: %d\n"), size);
-      abort ();
+  if (enable)
+    {
+      enable_x86_features |= x86_feature;
+      disable_x86_features &= ~x86_feature;
     }
+  else
+    {
+      disable_x86_features |= x86_feature;
+      enable_x86_features &= ~x86_feature;
+    }
+
+  return 0;
 }
+#endif
+
+/* Return ELF class for a machine type, MACH.  */
 
-static void
-byte_put_big_endian (unsigned char * field, bfd_vma value, int size)
+static enum elfclass
+elf_class (int mach)
 {
-  switch (size)
+  switch (mach)
     {
-    case 8:
-      field[7] = value & 0xff;
-      field[6] = (value >> 8) & 0xff;
-      field[5] = (value >> 16) & 0xff;
-      field[4] = (value >> 24) & 0xff;
-      value >>= 16;
-      value >>= 16;
-      /* Fall through.  */
-    case 4:
-      field[3] = value & 0xff;
-      field[2] = (value >> 8) & 0xff;
-      value >>= 16;
-      /* Fall through.  */
-    case 2:
-      field[1] = value & 0xff;
-      value >>= 8;
-      /* Fall through.  */
-    case 1:
-      field[0] = value & 0xff;
-      break;
-
+    case EM_386:
+    case EM_IAMCU:
+      return ELF_CLASS_32;
+    case EM_L1OM:
+    case EM_K1OM:
+      return ELF_CLASS_64;
+    case EM_X86_64:
+    case EM_NONE:
+      return ELF_CLASS_BOTH;
     default:
-      non_fatal (_("Unhandled data length: %d\n"), size);
-      abort ();
+      return ELF_CLASS_BOTH;
     }
 }
 
 static int
 update_elf_header (const char *file_name, FILE *file)
 {
-  int class, machine, type, status;
-
-  if (elf_header.e_ident[EI_MAG0] != ELFMAG0
-      || elf_header.e_ident[EI_MAG1] != ELFMAG1
-      || elf_header.e_ident[EI_MAG2] != ELFMAG2
-      || elf_header.e_ident[EI_MAG3] != ELFMAG3)
-    {
-      non_fatal
-       (_("%s: Not an ELF file - wrong magic bytes at the start\n"),
-        file_name);
-      return 0;
-    }
+  int class, machine, type, status, osabi;
 
   if (elf_header.e_ident[EI_VERSION] != EV_CURRENT)
     {
-      non_fatal
+      error
        (_("%s: Unsupported EI_VERSION: %d is not %d\n"),
         file_name, elf_header.e_ident[EI_VERSION],
         EV_CURRENT);
@@ -257,22 +320,34 @@ update_elf_header (const char *file_name, FILE *file)
     return 1;
 
   class = elf_header.e_ident[EI_CLASS];
+  machine = elf_header.e_machine;
 
   /* Skip if class doesn't match. */
-  if (input_elf_class != -1 && class != input_elf_class)
+  if (input_elf_class == ELF_CLASS_UNKNOWN)
+    input_elf_class = elf_class (machine);
+
+  if (input_elf_class != ELF_CLASS_BOTH
+      && (int) input_elf_class != class)
     {
-      non_fatal
-       (_("%s: Unmatched EI_CLASS: %d is not %d\n"),
+      error
+       (_("%s: Unmatched input EI_CLASS: %d is not %d\n"),
         file_name, class, input_elf_class);
       return 0;
     }
 
-  machine = elf_header.e_machine;
+  if (output_elf_class != ELF_CLASS_BOTH
+      && (int) output_elf_class != class)
+    {
+      error
+       (_("%s: Unmatched output EI_CLASS: %d is not %d\n"),
+        file_name, class, output_elf_class);
+      return 0;
+    }
 
   /* Skip if e_machine doesn't match. */
   if (input_elf_machine != -1 && machine != input_elf_machine)
     {
-      non_fatal
+      error
        (_("%s: Unmatched e_machine: %d is not %d\n"),
         file_name, machine, input_elf_machine);
       return 0;
@@ -283,13 +358,24 @@ update_elf_header (const char *file_name, FILE *file)
   /* Skip if e_type doesn't match. */
   if (input_elf_type != -1 && type != input_elf_type)
     {
-      non_fatal
+      error
        (_("%s: Unmatched e_type: %d is not %d\n"),
         file_name, type, input_elf_type);
       return 0;
     }
 
-  /* Update e_machine and e_type.  */
+  osabi = elf_header.e_ident[EI_OSABI];
+
+  /* Skip if OSABI doesn't match. */
+  if (input_elf_osabi != -1 && osabi != input_elf_osabi)
+    {
+      error
+       (_("%s: Unmatched EI_OSABI: %d is not %d\n"),
+        file_name, osabi, input_elf_osabi);
+      return 0;
+    }
+
+  /* Update e_machine, e_type and EI_OSABI.  */
   switch (class)
     {
     default:
@@ -301,6 +387,8 @@ update_elf_header (const char *file_name, FILE *file)
        BYTE_PUT (ehdr32.e_machine, output_elf_machine);
       if (output_elf_type != -1)
        BYTE_PUT (ehdr32.e_type, output_elf_type);
+      if (output_elf_osabi != -1)
+       ehdr32.e_ident[EI_OSABI] = output_elf_osabi;
       status = fwrite (&ehdr32, sizeof (ehdr32), 1, file) == 1;
       break;
     case ELFCLASS64:
@@ -308,12 +396,14 @@ update_elf_header (const char *file_name, FILE *file)
        BYTE_PUT (ehdr64.e_machine, output_elf_machine);
       if (output_elf_type != -1)
        BYTE_PUT (ehdr64.e_type, output_elf_type);
+      if (output_elf_osabi != -1)
+       ehdr64.e_ident[EI_OSABI] = output_elf_osabi;
       status = fwrite (&ehdr64, sizeof (ehdr64), 1, file) == 1;
       break;
     }
 
   if (status != 1)
-    non_fatal (_("%s: Failed to update ELF header: %s\n"),
+    error (_("%s: Failed to update ELF header: %s\n"),
               file_name, strerror (errno));
 
   return status;
@@ -326,6 +416,12 @@ get_file_header (FILE * file)
   if (fread (elf_header.e_ident, EI_NIDENT, 1, file) != 1)
     return 0;
 
+  if (elf_header.e_ident[EI_MAG0] != ELFMAG0
+      || elf_header.e_ident[EI_MAG1] != ELFMAG1
+      || elf_header.e_ident[EI_MAG2] != ELFMAG2
+      || elf_header.e_ident[EI_MAG3] != ELFMAG3)
+    return 0;
+
   /* Determine how to read the rest of the header.  */
   switch (elf_header.e_ident[EI_DATA])
     {
@@ -346,8 +442,6 @@ get_file_header (FILE * file)
   switch (elf_header.e_ident[EI_CLASS])
     {
     default:
-      non_fatal (_("Unsupported EI_CLASS: %d\n"),
-                elf_header.e_ident[EI_CLASS]);
       return 0;
 
     case ELFCLASS32:
@@ -379,7 +473,7 @@ get_file_header (FILE * file)
         overwriting things.  */
       if (sizeof (bfd_vma) < 8)
        {
-         non_fatal (_("This executable has been built without support for a\n\
+         error (_("This executable has been built without support for a\n\
 64 bit data type and so it cannot process 64 bit ELF files.\n"));
          return 0;
        }
@@ -420,14 +514,14 @@ process_object (const char *file_name, FILE *file)
 
   if (! get_file_header (file))
     {
-      non_fatal (_("%s: Failed to read ELF header\n"), file_name);
+      error (_("%s: Failed to read ELF header\n"), file_name);
       return 1;
     }
 
   /* Go to the position of the ELF header.  */
   if (fseek (file, offset, SEEK_SET) != 0)
     {
-      non_fatal (_("%s: Failed to seek to ELF header\n"), file_name);
+      error (_("%s: Failed to seek to ELF header\n"), file_name);
     }
 
   if (! update_elf_header (file_name, file))
@@ -436,340 +530,6 @@ process_object (const char *file_name, FILE *file)
   return 0;
 }
 
-/* Return the path name for a proxy entry in a thin archive, adjusted relative
-   to the path name of the thin archive itself if necessary.  Always returns
-   a pointer to malloc'ed memory.  */
-
-static char *
-adjust_relative_path (const char *file_name, char * name, int name_len)
-{
-  char * member_file_name;
-  const char * base_name = lbasename (file_name);
-
-  /* This is a proxy entry for a thin archive member.
-     If the extended name table contains an absolute path
-     name, or if the archive is in the current directory,
-     use the path name as given.  Otherwise, we need to
-     find the member relative to the directory where the
-     archive is located.  */
-  if (IS_ABSOLUTE_PATH (name) || base_name == file_name)
-    {
-      member_file_name = malloc (name_len + 1);
-      if (member_file_name == NULL)
-        {
-          non_fatal (_("Out of memory\n"));
-          return NULL;
-        }
-      memcpy (member_file_name, name, name_len);
-      member_file_name[name_len] = '\0';
-    }
-  else
-    {
-      /* Concatenate the path components of the archive file name
-         to the relative path name from the extended name table.  */
-      size_t prefix_len = base_name - file_name;
-      member_file_name = malloc (prefix_len + name_len + 1);
-      if (member_file_name == NULL)
-        {
-          non_fatal (_("Out of memory\n"));
-          return NULL;
-        }
-      memcpy (member_file_name, file_name, prefix_len);
-      memcpy (member_file_name + prefix_len, name, name_len);
-      member_file_name[prefix_len + name_len] = '\0';
-    }
-  return member_file_name;
-}
-
-/* Structure to hold information about an archive file.  */
-
-struct archive_info
-{
-  char * file_name;                     /* Archive file name.  */
-  FILE * file;                          /* Open file descriptor.  */
-  unsigned long index_num;              /* Number of symbols in table.  */
-  unsigned long * index_array;          /* The array of member offsets.  */
-  char * sym_table;                     /* The symbol table.  */
-  unsigned long sym_size;               /* Size of the symbol table.  */
-  char * longnames;                     /* The long file names table.  */
-  unsigned long longnames_size;         /* Size of the long file names table.  */
-  unsigned long nested_member_origin;   /* Origin in the nested archive of the current member.  */
-  unsigned long next_arhdr_offset;      /* Offset of the next archive header.  */
-  bfd_boolean is_thin_archive;          /* TRUE if this is a thin archive.  */
-  struct ar_hdr arhdr;                  /* Current archive header.  */
-};
-
-/* Read the symbol table and long-name table from an archive.  */
-
-static int
-setup_archive (struct archive_info * arch, const char * file_name,
-              FILE * file, bfd_boolean is_thin_archive)
-{
-  size_t got;
-  unsigned long size;
-
-  arch->file_name = strdup (file_name);
-  arch->file = file;
-  arch->index_num = 0;
-  arch->index_array = NULL;
-  arch->sym_table = NULL;
-  arch->sym_size = 0;
-  arch->longnames = NULL;
-  arch->longnames_size = 0;
-  arch->nested_member_origin = 0;
-  arch->is_thin_archive = is_thin_archive;
-  arch->next_arhdr_offset = SARMAG;
-
-  /* Read the first archive member header.  */
-  if (fseek (file, SARMAG, SEEK_SET) != 0)
-    {
-      non_fatal (_("%s: failed to seek to first archive header\n"),
-                file_name);
-      return 1;
-    }
-  got = fread (&arch->arhdr, 1, sizeof arch->arhdr, file);
-  if (got != sizeof arch->arhdr)
-    {
-      if (got == 0)
-       return 0;
-
-      non_fatal (_("%s: failed to read archive header\n"), file_name);
-      return 1;
-    }
-
-  /* See if this is the archive symbol table.  */
-  if (const_strneq (arch->arhdr.ar_name, "/               ")
-      || const_strneq (arch->arhdr.ar_name, "/SYM64/         "))
-    {
-      size = strtoul (arch->arhdr.ar_size, NULL, 10);
-      size = size + (size & 1);
-
-      arch->next_arhdr_offset += sizeof arch->arhdr + size;
-
-      if (fseek (file, size, SEEK_CUR) != 0)
-       {
-         non_fatal (_("%s: failed to skip archive symbol table\n"),
-                    file_name);
-         return 1;
-       }
-
-      /* Read the next archive header.  */
-      got = fread (&arch->arhdr, 1, sizeof arch->arhdr, file);
-      if (got != sizeof arch->arhdr)
-       {
-         if (got == 0)
-            return 0;
-         non_fatal (_("%s: failed to read archive header following archive index\n"),
-                    file_name);
-         return 1;
-       }
-    }
-
-  if (const_strneq (arch->arhdr.ar_name, "//              "))
-    {
-      /* This is the archive string table holding long member names.  */
-      arch->longnames_size = strtoul (arch->arhdr.ar_size, NULL, 10);
-      arch->next_arhdr_offset += sizeof arch->arhdr + arch->longnames_size;
-
-      arch->longnames = malloc (arch->longnames_size);
-      if (arch->longnames == NULL)
-       {
-         non_fatal (_("Out of memory reading long symbol names in archive\n"));
-         return 1;
-       }
-
-      if (fread (arch->longnames, arch->longnames_size, 1, file) != 1)
-       {
-         free (arch->longnames);
-         arch->longnames = NULL;
-         non_fatal (_("%s: failed to read long symbol name string table\n")
-                    , file_name);
-         return 1;
-       }
-
-      if ((arch->longnames_size & 1) != 0)
-       getc (file);
-    }
-
-  return 0;
-}
-
-/* Release the memory used for the archive information.  */
-
-static void
-release_archive (struct archive_info * arch)
-{
-  if (arch->file_name != NULL)
-    free (arch->file_name);
-  if (arch->index_array != NULL)
-    free (arch->index_array);
-  if (arch->sym_table != NULL)
-    free (arch->sym_table);
-  if (arch->longnames != NULL)
-    free (arch->longnames);
-}
-
-/* Open and setup a nested archive, if not already open.  */
-
-static int
-setup_nested_archive (struct archive_info * nested_arch, char * member_file_name)
-{
-  FILE * member_file;
-
-  /* Have we already setup this archive?  */
-  if (nested_arch->file_name != NULL
-      && streq (nested_arch->file_name, member_file_name))
-    return 0;
-
-  /* Close previous file and discard cached information.  */
-  if (nested_arch->file != NULL)
-    fclose (nested_arch->file);
-  release_archive (nested_arch);
-
-  member_file = fopen (member_file_name, "r+b");
-  if (member_file == NULL)
-    return 1;
-  return setup_archive (nested_arch, member_file_name, member_file,
-                       FALSE);
-}
-
-static char *
-get_archive_member_name_at (struct archive_info *  arch,
-                           unsigned long          offset,
-                           struct archive_info *  nested_arch);
-
-/* Get the name of an archive member from the current archive header.
-   For simple names, this will modify the ar_name field of the current
-   archive header.  For long names, it will return a pointer to the
-   longnames table.  For nested archives, it will open the nested archive
-   and get the name recursively.  NESTED_ARCH is a single-entry cache so
-   we don't keep rereading the same information from a nested archive.  */
-
-static char *
-get_archive_member_name (struct archive_info *  arch,
-                         struct archive_info *  nested_arch)
-{
-  unsigned long j, k;
-
-  if (arch->arhdr.ar_name[0] == '/')
-    {
-      /* We have a long name.  */
-      char * endp;
-      char * member_file_name;
-      char * member_name;
-
-      arch->nested_member_origin = 0;
-      k = j = strtoul (arch->arhdr.ar_name + 1, &endp, 10);
-      if (arch->is_thin_archive && endp != NULL && * endp == ':')
-        arch->nested_member_origin = strtoul (endp + 1, NULL, 10);
-
-      while ((j < arch->longnames_size)
-             && (arch->longnames[j] != '\n')
-             && (arch->longnames[j] != '\0'))
-        j++;
-      if (arch->longnames[j-1] == '/')
-        j--;
-      arch->longnames[j] = '\0';
-
-      if (!arch->is_thin_archive || arch->nested_member_origin == 0)
-        return arch->longnames + k;
-
-      /* This is a proxy for a member of a nested archive.
-         Find the name of the member in that archive.  */
-      member_file_name = adjust_relative_path (arch->file_name,
-                                              arch->longnames + k,
-                                              j - k);
-      if (member_file_name != NULL
-          && setup_nested_archive (nested_arch, member_file_name) == 0
-          && (member_name = get_archive_member_name_at (nested_arch,
-                                                       arch->nested_member_origin,
-                                                       NULL)) != NULL)
-        {
-          free (member_file_name);
-          return member_name;
-        }
-      free (member_file_name);
-
-      /* Last resort: just return the name of the nested archive.  */
-      return arch->longnames + k;
-    }
-
-  /* We have a normal (short) name.  */
-  j = 0;
-  while ((arch->arhdr.ar_name[j] != '/') && (j < 16))
-    j++;
-  arch->arhdr.ar_name[j] = '\0';
-  return arch->arhdr.ar_name;
-}
-
-/* Get the name of an archive member at a given OFFSET within an
-   archive ARCH.  */
-
-static char *
-get_archive_member_name_at (struct archive_info * arch,
-                            unsigned long         offset,
-                           struct archive_info * nested_arch)
-{
-  size_t got;
-
-  if (fseek (arch->file, offset, SEEK_SET) != 0)
-    {
-      non_fatal (_("%s: failed to seek to next file name\n"),
-                arch->file_name);
-      return NULL;
-    }
-  got = fread (&arch->arhdr, 1, sizeof arch->arhdr, arch->file);
-  if (got != sizeof arch->arhdr)
-    {
-      non_fatal (_("%s: failed to read archive header\n"),
-                arch->file_name);
-      return NULL;
-    }
-  if (memcmp (arch->arhdr.ar_fmag, ARFMAG, 2) != 0)
-    {
-      non_fatal (_("%s: did not find a valid archive header\n"),
-                arch->file_name);
-      return NULL;
-    }
-
-  return get_archive_member_name (arch, nested_arch);
-}
-
-/* Construct a string showing the name of the archive member, qualified
-   with the name of the containing archive file.  For thin archives, we
-   use square brackets to denote the indirection.  For nested archives,
-   we show the qualified name of the external member inside the square
-   brackets (e.g., "thin.a[normal.a(foo.o)]").  */
-
-static char *
-make_qualified_name (struct archive_info * arch,
-                     struct archive_info * nested_arch,
-                     char * member_name)
-{
-  size_t len;
-  char * name;
-
-  len = strlen (arch->file_name) + strlen (member_name) + 3;
-  if (arch->is_thin_archive && arch->nested_member_origin != 0)
-    len += strlen (nested_arch->file_name) + 2;
-
-  name = malloc (len);
-  if (name == NULL)
-    {
-      non_fatal (_("Out of memory\n"));
-      return NULL;
-    }
-
-  if (arch->is_thin_archive && arch->nested_member_origin != 0)
-    snprintf (name, len, "%s[%s(%s)]", arch->file_name, nested_arch->file_name, member_name);
-  else if (arch->is_thin_archive)
-    snprintf (name, len, "%s[%s]", arch->file_name, member_name);
-  else
-    snprintf (name, len, "%s(%s)", arch->file_name, member_name);
-
-  return name;
-}
-
 /* Process an ELF archive.
    On entry the file is positioned just after the ARMAG string.  */
 
@@ -780,8 +540,8 @@ process_archive (const char * file_name, FILE * file,
   struct archive_info arch;
   struct archive_info nested_arch;
   size_t got;
-  size_t file_name_size;
   int ret;
+  struct stat statbuf;
 
   /* The ARCH structure is used to hold information about this archive.  */
   arch.file_name = NULL;
@@ -799,13 +559,14 @@ process_archive (const char * file_name, FILE * file,
   nested_arch.sym_table = NULL;
   nested_arch.longnames = NULL;
 
-  if (setup_archive (&arch, file_name, file, is_thin_archive) != 0)
+  if (fstat (fileno (file), &statbuf) < 0
+      || setup_archive (&arch, file_name, file, statbuf.st_size,
+                       is_thin_archive, FALSE) != 0)
     {
       ret = 1;
       goto out;
     }
 
-  file_name_size = strlen (file_name);
   ret = 0;
 
   while (1)
@@ -817,7 +578,7 @@ process_archive (const char * file_name, FILE * file,
       /* Read the next archive header.  */
       if (fseek (file, arch.next_arhdr_offset, SEEK_SET) != 0)
         {
-          non_fatal (_("%s: failed to seek to next archive header\n"),
+          error (_("%s: failed to seek to next archive header\n"),
                     file_name);
           return 1;
         }
@@ -826,14 +587,14 @@ process_archive (const char * file_name, FILE * file,
         {
           if (got == 0)
            break;
-          non_fatal (_("%s: failed to read archive header\n"),
+          error (_("%s: failed to read archive header\n"),
                     file_name);
           ret = 1;
           break;
         }
       if (memcmp (arch.arhdr.ar_fmag, ARFMAG, 2) != 0)
         {
-          non_fatal (_("%s: did not find a valid archive header\n"),
+          error (_("%s: did not find a valid archive header\n"),
                     arch.file_name);
           ret = 1;
           break;
@@ -848,7 +609,7 @@ process_archive (const char * file_name, FILE * file,
       name = get_archive_member_name (&arch, &nested_arch);
       if (name == NULL)
        {
-         non_fatal (_("%s: bad archive file name\n"), file_name);
+         error (_("%s: bad archive file name\n"), file_name);
          ret = 1;
          break;
        }
@@ -857,7 +618,8 @@ process_archive (const char * file_name, FILE * file,
       qualified_name = make_qualified_name (&arch, &nested_arch, name);
       if (qualified_name == NULL)
        {
-         non_fatal (_("%s: bad archive file name\n"), file_name);
+         error (_("%s: bad archive file name\n"), file_name);
+         free (name);
          ret = 1;
          break;
        }
@@ -868,8 +630,10 @@ process_archive (const char * file_name, FILE * file,
           FILE *member_file;
           char *member_file_name = adjust_relative_path (file_name,
                                                         name, namelen);
+         free (name);
           if (member_file_name == NULL)
             {
+             free (qualified_name);
               ret = 1;
               break;
             }
@@ -877,9 +641,10 @@ process_archive (const char * file_name, FILE * file,
           member_file = fopen (member_file_name, "r+b");
           if (member_file == NULL)
             {
-              non_fatal (_("Input file '%s' is not readable\n"),
+              error (_("Input file '%s' is not readable\n"),
                         member_file_name);
               free (member_file_name);
+             free (qualified_name);
               ret = 1;
               break;
             }
@@ -890,9 +655,12 @@ process_archive (const char * file_name, FILE * file,
 
           fclose (member_file);
           free (member_file_name);
+         free (qualified_name);
         }
       else if (is_thin_archive)
         {
+         free (name);
+
           /* This is a proxy for a member of a nested archive.  */
           archive_file_offset = arch.nested_member_origin + sizeof arch.arhdr;
 
@@ -901,8 +669,9 @@ process_archive (const char * file_name, FILE * file,
           if (fseek (nested_arch.file, archive_file_offset,
                     SEEK_SET) != 0)
             {
-              non_fatal (_("%s: failed to seek to archive member\n"),
+              error (_("%s: failed to seek to archive member\n"),
                         nested_arch.file_name);
+             free (qualified_name);
               ret = 1;
               break;
             }
@@ -911,6 +680,7 @@ process_archive (const char * file_name, FILE * file,
         }
       else
         {
+         free (name);
           archive_file_offset = arch.next_arhdr_offset;
           arch.next_arhdr_offset += archive_file_size;
 
@@ -940,16 +710,16 @@ check_file (const char *file_name, struct stat *statbuf_p)
   if (stat (file_name, statbuf_p) < 0)
     {
       if (errno == ENOENT)
-       non_fatal (_("'%s': No such file\n"), file_name);
+       error (_("'%s': No such file\n"), file_name);
       else
-       non_fatal (_("Could not locate '%s'.  System error message: %s\n"),
+       error (_("Could not locate '%s'.  System error message: %s\n"),
                   file_name, strerror (errno));
       return 1;
     }
 
   if (! S_ISREG (statbuf_p->st_mode))
     {
-      non_fatal (_("'%s' is not an ordinary file\n"), file_name);
+      error (_("'%s' is not an ordinary file\n"), file_name);
       return 1;
     }
 
@@ -969,13 +739,13 @@ process_file (const char *file_name)
   file = fopen (file_name, "r+b");
   if (file == NULL)
     {
-      non_fatal (_("Input file '%s' is not readable\n"), file_name);
+      error (_("Input file '%s' is not readable\n"), file_name);
       return 1;
     }
 
   if (fread (armag, SARMAG, 1, file) != 1)
     {
-      non_fatal (_("%s: Failed to read file's magic number\n"),
+      error (_("%s: Failed to read file's magic number\n"),
                 file_name);
       fclose (file);
       return 1;
@@ -990,6 +760,12 @@ process_file (const char *file_name)
       rewind (file);
       archive_file_size = archive_file_offset = 0;
       ret = process_object (file_name, file);
+#ifdef HAVE_MMAP
+      if (!ret
+         && (elf_header.e_type == ET_EXEC
+             || elf_header.e_type == ET_DYN))
+       ret = update_gnu_property (file_name, file);
+#endif
     }
 
   fclose (file);
@@ -997,13 +773,60 @@ process_file (const char *file_name)
   return ret;
 }
 
+static const struct
+{
+  int osabi;
+  const char *name;
+}
+osabis[] =
+{
+  { ELFOSABI_NONE, "none" },
+  { ELFOSABI_HPUX, "HPUX" },
+  { ELFOSABI_NETBSD, "NetBSD" },
+  { ELFOSABI_GNU, "GNU" },
+  { ELFOSABI_GNU, "Linux" },
+  { ELFOSABI_SOLARIS, "Solaris" },
+  { ELFOSABI_AIX, "AIX" },
+  { ELFOSABI_IRIX, "Irix" },
+  { ELFOSABI_FREEBSD, "FreeBSD" },
+  { ELFOSABI_TRU64, "TRU64" },
+  { ELFOSABI_MODESTO, "Modesto" },
+  { ELFOSABI_OPENBSD, "OpenBSD" },
+  { ELFOSABI_OPENVMS, "OpenVMS" },
+  { ELFOSABI_NSK, "NSK" },
+  { ELFOSABI_AROS, "AROS" },
+  { ELFOSABI_FENIXOS, "FenixOS" }
+};
+
+/* Return ELFOSABI_XXX for an OSABI string, OSABI.  */
+
+static int
+elf_osabi (const char *osabi)
+{
+  unsigned int i;
+
+  for (i = 0; i < ARRAY_SIZE (osabis); i++)
+    if (strcasecmp (osabi, osabis[i].name) == 0)
+      return osabis[i].osabi;
+
+  error (_("Unknown OSABI: %s\n"), osabi);
+
+  return -1;
+}
+
 /* Return EM_XXX for a machine string, MACH.  */
 
 static int
 elf_machine (const char *mach)
 {
+  if (strcasecmp (mach, "i386") == 0)
+    return EM_386;
+  if (strcasecmp (mach, "iamcu") == 0)
+    return EM_IAMCU;
   if (strcasecmp (mach, "l1om") == 0)
     return EM_L1OM;
+  if (strcasecmp (mach, "k1om") == 0)
+    return EM_K1OM;
   if (strcasecmp (mach, "x86_64") == 0)
     return EM_X86_64;
   if (strcasecmp (mach, "x86-64") == 0)
@@ -1011,29 +834,11 @@ elf_machine (const char *mach)
   if (strcasecmp (mach, "none") == 0)
     return EM_NONE;
 
-  non_fatal (_("Unknown machine type: %s\n"), mach);
+  error (_("Unknown machine type: %s\n"), mach);
 
   return -1;
 }
 
-/* Return ELF class for a machine type, MACH.  */
-
-static int
-elf_class (int mach)
-{
-  switch (mach)
-    {
-    case EM_L1OM:
-    case EM_X86_64:
-      return ELFCLASS64;
-    case EM_NONE:
-      return ELFCLASSNONE;
-    default:
-      non_fatal (_("Unknown machine type: %d\n"), mach);
-      return -1;
-    }
-}
-
 /* Return ET_XXX for a type string, TYPE.  */
 
 static int
@@ -1048,7 +853,7 @@ elf_type (const char *type)
   if (strcasecmp (type, "none") == 0)
     return ET_NONE;
 
-  non_fatal (_("Unknown type: %s\n"), type);
+  error (_("Unknown type: %s\n"), type);
 
   return -1;
 }
@@ -1058,7 +863,13 @@ enum command_line_switch
     OPTION_INPUT_MACH = 150,
     OPTION_OUTPUT_MACH,
     OPTION_INPUT_TYPE,
-    OPTION_OUTPUT_TYPE
+    OPTION_OUTPUT_TYPE,
+    OPTION_INPUT_OSABI,
+    OPTION_OUTPUT_OSABI,
+#ifdef HAVE_MMAP
+    OPTION_ENABLE_X86_FEATURE,
+    OPTION_DISABLE_X86_FEATURE,
+#endif
   };
 
 static struct option options[] =
@@ -1067,15 +878,23 @@ static struct option options[] =
   {"output-mach",      required_argument, 0, OPTION_OUTPUT_MACH},
   {"input-type",       required_argument, 0, OPTION_INPUT_TYPE},
   {"output-type",      required_argument, 0, OPTION_OUTPUT_TYPE},
+  {"input-osabi",      required_argument, 0, OPTION_INPUT_OSABI},
+  {"output-osabi",     required_argument, 0, OPTION_OUTPUT_OSABI},
+#ifdef HAVE_MMAP
+  {"enable-x86-feature",
+                       required_argument, 0, OPTION_ENABLE_X86_FEATURE},
+  {"disable-x86-feature",
+                       required_argument, 0, OPTION_DISABLE_X86_FEATURE},
+#endif
   {"version",          no_argument, 0, 'v'},
   {"help",             no_argument, 0, 'h'},
   {0,                  no_argument, 0, 0}
 };
 
-static void
+ATTRIBUTE_NORETURN static void
 usage (FILE *stream, int exit_status)
 {
-  fprintf (stream, _("Usage: %s [option(s)] {--output-mach <machine>|--output-type <type>} elffile(s)\n"),
+  fprintf (stream, _("Usage: %s <option(s)> elffile(s)\n"),
           program_name);
   fprintf (stream, _(" Update the ELF header of ELF files\n"));
   fprintf (stream, _(" The options are:\n"));
@@ -1084,6 +903,16 @@ usage (FILE *stream, int exit_status)
   --output-mach <machine>     Set output machine type to <machine>\n\
   --input-type <type>         Set input file type to <type>\n\
   --output-type <type>        Set output file type to <type>\n\
+  --input-osabi <osabi>       Set input OSABI to <osabi>\n\
+  --output-osabi <osabi>      Set output OSABI to <osabi>\n"));
+#ifdef HAVE_MMAP
+  fprintf (stream, _("\
+  --enable-x86-feature <feature>\n\
+                              Enable x86 feature <feature>\n\
+  --disable-x86-feature <feature>\n\
+                              Disable x86 feature <feature>\n"));
+#endif
+  fprintf (stream, _("\
   -h --help                   Display this information\n\
   -v --version                Display the version number of %s\n\
 "),
@@ -1119,7 +948,7 @@ main (int argc, char ** argv)
          if (input_elf_machine < 0)
            return 1;
          input_elf_class = elf_class (input_elf_machine);
-         if (input_elf_class < 0)
+         if (input_elf_class == ELF_CLASS_UNKNOWN)
            return 1;
          break;
 
@@ -1127,6 +956,9 @@ main (int argc, char ** argv)
          output_elf_machine = elf_machine (optarg);
          if (output_elf_machine < 0)
            return 1;
+         output_elf_class = elf_class (output_elf_machine);
+         if (output_elf_class == ELF_CLASS_UNKNOWN)
+           return 1;
          break;
 
        case OPTION_INPUT_TYPE:
@@ -1141,6 +973,30 @@ main (int argc, char ** argv)
            return 1;
          break;
 
+       case OPTION_INPUT_OSABI:
+         input_elf_osabi = elf_osabi (optarg);
+         if (input_elf_osabi < 0)
+           return 1;
+         break;
+
+       case OPTION_OUTPUT_OSABI:
+         output_elf_osabi = elf_osabi (optarg);
+         if (output_elf_osabi < 0)
+           return 1;
+         break;
+
+#ifdef HAVE_MMAP
+       case OPTION_ENABLE_X86_FEATURE:
+         if (elf_x86_feature (optarg, 1) < 0)
+           return 1;
+         break;
+
+       case OPTION_DISABLE_X86_FEATURE:
+         if (elf_x86_feature (optarg, 0) < 0)
+           return 1;
+         break;
+#endif
+
        case 'h':
          usage (stdout, 0);
 
@@ -1155,7 +1011,12 @@ main (int argc, char ** argv)
 
   if (optind == argc
       || (output_elf_machine == -1
-         && output_elf_type == -1))
+#ifdef HAVE_MMAP
+        && ! enable_x86_features
+        && ! disable_x86_features
+#endif
+         && output_elf_type == -1
+         && output_elf_osabi == -1))
     usage (stderr, 1);
 
   status = 0;
This page took 0.038318 seconds and 4 git commands to generate.