[ARC] Add JLI support.
[deliverable/binutils-gdb.git] / bfd / bfd.c
index 771989b75899383357744d03a6ba63dbf14c0d92..665f182559b37b4b9f61fdac19eb117badb9d0d8 100644 (file)
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -1,7 +1,5 @@
 /* Generic BFD library interface and support routines.
 /* Generic BFD library interface and support routines.
-   Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
-   Free Software Foundation, Inc.
+   Copyright (C) 1990-2017 Free Software Foundation, Inc.
    Written by Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
    Written by Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -22,6 +20,9 @@
    MA 02110-1301, USA.  */
 
 /*
    MA 02110-1301, USA.  */
 
 /*
+INODE
+typedef bfd, Error reporting, BFD front end, BFD front end
+
 SECTION
        <<typedef bfd>>
 
 SECTION
        <<typedef bfd>>
 
@@ -43,11 +44,21 @@ CODE_FRAGMENT
 .    both_direction = 3
 .  };
 .
 .    both_direction = 3
 .  };
 .
+.enum bfd_plugin_format
+.  {
+.    bfd_plugin_unknown = 0,
+.    bfd_plugin_yes = 1,
+.    bfd_plugin_no = 2
+.  };
+.
+.struct bfd_build_id
+.  {
+.    bfd_size_type size;
+.    bfd_byte data[1];
+.  };
+.
 .struct bfd
 .{
 .struct bfd
 .{
-.  {* A unique identifier of the BFD  *}
-.  unsigned int id;
-.
 .  {* The filename the application opened the BFD with.  *}
 .  const char *filename;
 .
 .  {* The filename the application opened the BFD with.  *}
 .  const char *filename;
 .
@@ -70,17 +81,17 @@ CODE_FRAGMENT
 .  {* File modified time, if mtime_set is TRUE.  *}
 .  long mtime;
 .
 .  {* File modified time, if mtime_set is TRUE.  *}
 .  long mtime;
 .
-.  {* Reserved for an unimplemented file locking extension.  *}
-.  int ifd;
+.  {* A unique identifier of the BFD  *}
+.  unsigned int id;
 .
 .  {* The format which belongs to the BFD. (object, core, etc.)  *}
 .
 .  {* The format which belongs to the BFD. (object, core, etc.)  *}
-.  bfd_format format;
+.  ENUM_BITFIELD (bfd_format) format : 3;
 .
 .  {* The direction with which the BFD was opened.  *}
 .
 .  {* The direction with which the BFD was opened.  *}
-.  enum bfd_direction direction;
+.  ENUM_BITFIELD (bfd_direction) direction : 2;
 .
 .  {* Format_specific flags.  *}
 .
 .  {* Format_specific flags.  *}
-.  flagword flags;
+.  flagword flags : 20;
 .
 .  {* Values that may appear in the flags field of a BFD.  These also
 .     appear in the object_flags field of the bfd_target structure, where
 .
 .  {* Values that may appear in the flags field of a BFD.  These also
 .     appear in the object_flags field of the bfd_target structure, where
@@ -139,17 +150,94 @@ CODE_FRAGMENT
 .     struct.  *}
 .#define BFD_IN_MEMORY 0x800
 .
 .     struct.  *}
 .#define BFD_IN_MEMORY 0x800
 .
-.  {* The sections in this BFD specify a memory page.  *}
-.#define HAS_LOAD_PAGE 0x1000
-.
 .  {* This BFD has been created by the linker and doesn't correspond
 .     to any input file.  *}
 .  {* This BFD has been created by the linker and doesn't correspond
 .     to any input file.  *}
-.#define BFD_LINKER_CREATED 0x2000
+.#define BFD_LINKER_CREATED 0x1000
 .
 .  {* This may be set before writing out a BFD to request that it
 .     be written using values for UIDs, GIDs, timestamps, etc. that
 .     will be consistent from run to run.  *}
 .
 .  {* This may be set before writing out a BFD to request that it
 .     be written using values for UIDs, GIDs, timestamps, etc. that
 .     will be consistent from run to run.  *}
-.#define BFD_DETERMINISTIC_OUTPUT 0x4000
+.#define BFD_DETERMINISTIC_OUTPUT 0x2000
+.
+.  {* Compress sections in this BFD.  *}
+.#define BFD_COMPRESS 0x4000
+.
+.  {* Decompress sections in this BFD.  *}
+.#define BFD_DECOMPRESS 0x8000
+.
+.  {* BFD is a dummy, for plugins.  *}
+.#define BFD_PLUGIN 0x10000
+.
+.  {* Compress sections in this BFD with SHF_COMPRESSED from gABI.  *}
+.#define BFD_COMPRESS_GABI 0x20000
+.
+.  {* Convert ELF common symbol type to STT_COMMON or STT_OBJECT in this
+.     BFD.  *}
+.#define BFD_CONVERT_ELF_COMMON 0x40000
+.
+.  {* Use the ELF STT_COMMON type in this BFD.  *}
+.#define BFD_USE_ELF_STT_COMMON 0x80000
+.
+.  {* Flags bits to be saved in bfd_preserve_save.  *}
+.#define BFD_FLAGS_SAVED \
+.  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
+.   | BFD_PLUGIN | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON \
+.   | BFD_USE_ELF_STT_COMMON)
+.
+.  {* Flags bits which are for BFD use only.  *}
+.#define BFD_FLAGS_FOR_BFD_USE_MASK \
+.  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_LINKER_CREATED \
+.   | BFD_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT \
+.   | BFD_COMPRESS_GABI | BFD_CONVERT_ELF_COMMON | BFD_USE_ELF_STT_COMMON)
+.
+.  {* Is the file descriptor being cached?  That is, can it be closed as
+.     needed, and re-opened when accessed later?  *}
+.  unsigned int cacheable : 1;
+.
+.  {* Marks whether there was a default target specified when the
+.     BFD was opened. This is used to select which matching algorithm
+.     to use to choose the back end.  *}
+.  unsigned int target_defaulted : 1;
+.
+.  {* ... and here: (``once'' means at least once).  *}
+.  unsigned int opened_once : 1;
+.
+.  {* Set if we have a locally maintained mtime value, rather than
+.     getting it from the file each time.  *}
+.  unsigned int mtime_set : 1;
+.
+.  {* Flag set if symbols from this BFD should not be exported.  *}
+.  unsigned int no_export : 1;
+.
+.  {* Remember when output has begun, to stop strange things
+.     from happening.  *}
+.  unsigned int output_has_begun : 1;
+.
+.  {* Have archive map.  *}
+.  unsigned int has_armap : 1;
+.
+.  {* Set if this is a thin archive.  *}
+.  unsigned int is_thin_archive : 1;
+.
+.  {* Set if only required symbols should be added in the link hash table for
+.     this object.  Used by VMS linkers.  *}
+.  unsigned int selective_search : 1;
+.
+.  {* Set if this is the linker output BFD.  *}
+.  unsigned int is_linker_output : 1;
+.
+.  {* Set if this is the linker input BFD.  *}
+.  unsigned int is_linker_input : 1;
+.
+.  {* If this is an input for a compiler plug-in library.  *}
+.  ENUM_BITFIELD (bfd_plugin_format) plugin_format : 2;
+.
+.  {* Set if this is a plugin output file.  *}
+.  unsigned int lto_output : 1;
+.
+.  {* Set to dummy BFD created when claimed by a compiler plug-in
+.     library.  *}
+.  bfd *plugin_dummy_bfd;
 .
 .  {* Currently my_archive is tested before adding origin to
 .     anything. I believe that this can become always an add of
 .
 .  {* Currently my_archive is tested before adding origin to
 .     anything. I believe that this can become always an add of
@@ -175,17 +263,21 @@ CODE_FRAGMENT
 .  {* The number of sections.  *}
 .  unsigned int section_count;
 .
 .  {* The number of sections.  *}
 .  unsigned int section_count;
 .
+.  {* A field used by _bfd_generic_link_add_archive_symbols.  This will
+.     be used only for archive elements.  *}
+.  int archive_pass;
+.
 .  {* Stuff only useful for object files:
 .     The start address.  *}
 .  bfd_vma start_address;
 .
 .  {* Stuff only useful for object files:
 .     The start address.  *}
 .  bfd_vma start_address;
 .
-.  {* Used for input and output.  *}
-.  unsigned int symcount;
-.
 .  {* Symbol table for output BFD (with symcount entries).
 .     Also used by the linker to cache input BFD symbols.  *}
 .  struct bfd_symbol  **outsymbols;
 .
 .  {* Symbol table for output BFD (with symcount entries).
 .     Also used by the linker to cache input BFD symbols.  *}
 .  struct bfd_symbol  **outsymbols;
 .
+.  {* Used for input and output.  *}
+.  unsigned int symcount;
+.
 .  {* Used for slurped dynamic symbol tables.  *}
 .  unsigned int dynsymcount;
 .
 .  {* Used for slurped dynamic symbol tables.  *}
 .  unsigned int dynsymcount;
 .
@@ -200,12 +292,12 @@ CODE_FRAGMENT
 .  struct bfd *nested_archives; {* List of nested archive in a flattened
 .                                  thin archive.  *}
 .
 .  struct bfd *nested_archives; {* List of nested archive in a flattened
 .                                  thin archive.  *}
 .
-.  {* A chain of BFD structures involved in a link.  *}
-.  struct bfd *link_next;
-.
-.  {* A field used by _bfd_generic_link_add_archive_symbols.  This will
-.     be used only for archive elements.  *}
-.  int archive_pass;
+.  union {
+.    {* For input BFDs, a chain of BFDs involved in a link.  *}
+.    struct bfd *next;
+.    {* For output BFD, the linker hash table.  *}
+.    struct bfd_link_hash_table *hash;
+.  } link;
 .
 .  {* Used by the back end to hold private data.  *}
 .  union
 .
 .  {* Used by the back end to hold private data.  *}
 .  union
@@ -258,40 +350,18 @@ CODE_FRAGMENT
 .     of objalloc.h.  *}
 .  void *memory;
 .
 .     of objalloc.h.  *}
 .  void *memory;
 .
-.  {* Is the file descriptor being cached?  That is, can it be closed as
-.     needed, and re-opened when accessed later?  *}
-.  unsigned int cacheable : 1;
-.
-.  {* Marks whether there was a default target specified when the
-.     BFD was opened. This is used to select which matching algorithm
-.     to use to choose the back end.  *}
-.  unsigned int target_defaulted : 1;
-.
-.  {* ... and here: (``once'' means at least once).  *}
-.  unsigned int opened_once : 1;
-.
-.  {* Set if we have a locally maintained mtime value, rather than
-.     getting it from the file each time.  *}
-.  unsigned int mtime_set : 1;
-.
-.  {* Flag set if symbols from this BFD should not be exported.  *}
-.  unsigned int no_export : 1;
-.
-.  {* Remember when output has begun, to stop strange things
-.     from happening.  *}
-.  unsigned int output_has_begun : 1;
-.
-.  {* Have archive map.  *}
-.  unsigned int has_armap : 1;
-.
-.  {* Set if this is a thin archive.  *}
-.  unsigned int is_thin_archive : 1;
-.
-.  {* Set if only required symbols should be added in the link hash table for
-.     this object.  Used by VMS linkers.  *}
-.  unsigned int selective_search : 1;
+.  {* For input BFDs, the build ID, if the object has one. *}
+.  const struct bfd_build_id *build_id;
 .};
 .
 .};
 .
+.{* See note beside bfd_set_section_userdata.  *}
+.static inline bfd_boolean
+.bfd_set_cacheable (bfd * abfd, bfd_boolean val)
+.{
+.  abfd->cacheable = val;
+.  return TRUE;
+.}
+.
 */
 
 #include "sysdep.h"
 */
 
 #include "sysdep.h"
@@ -322,6 +392,9 @@ CODE_FRAGMENT
    where it is needed.  The typedef's used are defined in bfd.h */
 \f
 /*
    where it is needed.  The typedef's used are defined in bfd.h */
 \f
 /*
+INODE
+Error reporting, Miscellaneous, typedef bfd, BFD front end
+
 SECTION
        Error reporting
 
 SECTION
        Error reporting
 
@@ -356,6 +429,7 @@ CODE_FRAGMENT
 .  bfd_error_no_armap,
 .  bfd_error_no_more_archived_files,
 .  bfd_error_malformed_archive,
 .  bfd_error_no_armap,
 .  bfd_error_no_more_archived_files,
 .  bfd_error_malformed_archive,
+.  bfd_error_missing_dso,
 .  bfd_error_file_not_recognized,
 .  bfd_error_file_ambiguously_recognized,
 .  bfd_error_no_contents,
 .  bfd_error_file_not_recognized,
 .  bfd_error_file_ambiguously_recognized,
 .  bfd_error_no_contents,
@@ -388,6 +462,7 @@ const char *const bfd_errmsgs[] =
   N_("Archive has no index; run ranlib to add one"),
   N_("No more archived files"),
   N_("Malformed archive"),
   N_("Archive has no index; run ranlib to add one"),
   N_("No more archived files"),
   N_("Malformed archive"),
+  N_("DSO missing from command line"),
   N_("File format not recognized"),
   N_("File format is ambiguous"),
   N_("Section has no contents"),
   N_("File format not recognized"),
   N_("File format is ambiguous"),
   N_("Section has no contents"),
@@ -508,10 +583,12 @@ DESCRIPTION
 void
 bfd_perror (const char *message)
 {
 void
 bfd_perror (const char *message)
 {
+  fflush (stdout);
   if (message == NULL || *message == '\0')
     fprintf (stderr, "%s\n", bfd_errmsg (bfd_get_error ()));
   else
     fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_get_error ()));
   if (message == NULL || *message == '\0')
     fprintf (stderr, "%s\n", bfd_errmsg (bfd_get_error ()));
   else
     fprintf (stderr, "%s: %s\n", message, bfd_errmsg (bfd_get_error ()));
+  fflush (stderr);
 }
 
 /*
 }
 
 /*
@@ -522,11 +599,11 @@ SUBSECTION
        problem.  They call a BFD error handler function.  This
        function may be overridden by the program.
 
        problem.  They call a BFD error handler function.  This
        function may be overridden by the program.
 
-       The BFD error handler acts like printf.
+       The BFD error handler acts like vprintf.
 
 CODE_FRAGMENT
 .
 
 CODE_FRAGMENT
 .
-.typedef void (*bfd_error_handler_type) (const char *, ...);
+.typedef void (*bfd_error_handler_type) (const char *, va_list);
 .
 */
 
 .
 */
 
@@ -534,180 +611,269 @@ CODE_FRAGMENT
 
 static const char *_bfd_error_program_name;
 
 
 static const char *_bfd_error_program_name;
 
-/* This is the default routine to handle BFD error messages.
-   Like fprintf (stderr, ...), but also handles some extra format specifiers.
+/* This macro and _doprnt taken from libiberty _doprnt.c, tidied a
+   little and extended to handle '%A' and '%B'.  'L' as a modifer for
+   integer formats is used for bfd_vma and bfd_size_type args, which
+   vary in size depending on BFD configuration.  */
 
 
-   %A section name from section.  For group components, print group name too.
-   %B file name from bfd.  For archive components, prints archive too.
-
-   Note - because these two extra format specifiers require special handling
-   they are scanned for and processed in this function, before calling
-   vfprintf.  This means that the *arguments* for these format specifiers
-   must be the first ones in the variable argument list, regardless of where
-   the specifiers appear in the format string.  Thus for example calling
-   this function with a format string of:
-
-      "blah %s blah %A blah %d blah %B"
+#define PRINT_TYPE(TYPE) \
+  do                                                           \
+    {                                                          \
+      TYPE value = va_arg (ap, TYPE);                          \
+      result = fprintf (stream, specifier, value);             \
+    } while (0)
 
 
-   would involve passing the arguments as:
-
-      "blah %s blah %A blah %d blah %B",
-        asection_for_the_%A,
-       bfd_for_the_%B,
-       string_for_the_%s,
-       integer_for_the_%d);
- */
-
-void
-_bfd_default_error_handler (const char *fmt, ...)
+static int
+_doprnt (FILE *stream, const char *format, va_list ap)
 {
 {
-  va_list ap;
-  char *bufp;
-  const char *new_fmt, *p;
-  size_t avail = 1000;
-  char buf[1000];
-
-  /* PR 4992: Don't interrupt output being sent to stdout.  */
-  fflush (stdout);
+  const char *ptr = format;
+  char specifier[128];
+  int total_printed = 0;
 
 
-  if (_bfd_error_program_name != NULL)
-    fprintf (stderr, "%s: ", _bfd_error_program_name);
-  else
-    fprintf (stderr, "BFD: ");
-
-  va_start (ap, fmt);
-  new_fmt = fmt;
-  bufp = buf;
-
-  /* Reserve enough space for the existing format string.  */
-  avail -= strlen (fmt) + 1;
-  if (avail > 1000)
-    _exit (EXIT_FAILURE);
-
-  p = fmt;
-  while (1)
+  while (*ptr != '\0')
     {
     {
-      char *q;
-      size_t len, extra, trim;
+      int result;
 
 
-      p = strchr (p, '%');
-      if (p == NULL || p[1] == '\0')
+      if (*ptr != '%')
        {
        {
-         if (new_fmt == buf)
-           {
-             len = strlen (fmt);
-             memcpy (bufp, fmt, len + 1);
-           }
-         break;
+         /* While we have regular characters, print them.  */
+         char *end = strchr (ptr, '%');
+         if (end != NULL)
+           result = fprintf (stream, "%.*s", (int) (end - ptr), ptr);
+         else
+           result = fprintf (stream, "%s", ptr);
+         ptr += result;
        }
        }
-
-      if (p[1] == 'A' || p[1] == 'B')
+      else
        {
        {
-         len = p - fmt;
-         memcpy (bufp, fmt, len);
-         bufp += len;
-         fmt = p + 2;
-         new_fmt = buf;
-
-         /* If we run out of space, tough, you lose your ridiculously
-            long file or section name.  It's not safe to try to alloc
-            memory here;  We might be printing an out of memory message.  */
-         if (avail == 0)
+         /* We have a format specifier!  */
+         char *sptr = specifier;
+         int wide_width = 0, short_width = 0;
+
+         /* Copy the % and move forward.  */
+         *sptr++ = *ptr++;
+
+         /* Move past flags.  */
+         while (strchr ("-+ #0", *ptr))
+           *sptr++ = *ptr++;
+
+         if (*ptr == '*')
            {
            {
-             *bufp++ = '*';
-             *bufp++ = '*';
-             *bufp = '\0';
+             int value = abs (va_arg (ap, int));
+             sptr += sprintf (sptr, "%d", value);
+             ptr++;
            }
          else
            }
          else
+           /* Handle explicit numeric value.  */
+           while (ISDIGIT (*ptr))
+             *sptr++ = *ptr++;
+
+         if (*ptr == '.')
            {
            {
-             if (p[1] == 'B')
+             /* Copy and go past the period.  */
+             *sptr++ = *ptr++;
+             if (*ptr == '*')
                {
                {
-                 bfd *abfd = va_arg (ap, bfd *);
-
-                 if (abfd == NULL)
-                   /* Invoking %B with a null bfd pointer is an internal error.  */
-                   abort ();
-                 else if (abfd->my_archive)
-                   snprintf (bufp, avail, "%s(%s)",
-                             abfd->my_archive->filename, abfd->filename);
-                 else
-                   snprintf (bufp, avail, "%s", abfd->filename);
+                 int value = abs (va_arg (ap, int));
+                 sptr += sprintf (sptr, "%d", value);
+                 ptr++;
                }
              else
                }
              else
+               /* Handle explicit numeric value.  */
+               while (ISDIGIT (*ptr))
+                 *sptr++ = *ptr++;
+           }
+         while (strchr ("hlL", *ptr))
+           {
+             switch (*ptr)
                {
                {
-                 asection *sec = va_arg (ap, asection *);
-                 bfd *abfd;
-                 const char *group = NULL;
-                 struct coff_comdat_info *ci;
-
-                 if (sec == NULL)
-                   /* Invoking %A with a null section pointer is an internal error.  */
-                   abort ();
-                 abfd = sec->owner;
-                 if (abfd != NULL
-                     && bfd_get_flavour (abfd) == bfd_target_elf_flavour
-                     && elf_next_in_group (sec) != NULL
-                     && (sec->flags & SEC_GROUP) == 0)
-                   group = elf_group_name (sec);
-                 else if (abfd != NULL
-                          && bfd_get_flavour (abfd) == bfd_target_coff_flavour
-                          && (ci = bfd_coff_get_comdat_section (sec->owner,
-                                                                sec)) != NULL)
-                   group = ci->name;
-                 if (group != NULL)
-                   snprintf (bufp, avail, "%s[%s]", sec->name, group);
-                 else
-                   snprintf (bufp, avail, "%s", sec->name);
-               }
-             len = strlen (bufp);
-             avail = avail - len + 2;
-
-             /* We need to replace any '%' we printed by "%%".
-                First count how many.  */
-             q = bufp;
-             bufp += len;
-             extra = 0;
-             while ((q = strchr (q, '%')) != NULL)
-               {
-                 ++q;
-                 ++extra;
+               case 'h':
+                 short_width = 1;
+                 break;
+               case 'l':
+                 wide_width++;
+                 break;
+               case 'L':
+                 wide_width = 2;
+                 break;
+               default:
+                 abort();
                }
                }
+             *sptr++ = *ptr++;
+           }
 
 
-             /* If there isn't room, trim off the end of the string.  */
-             q = bufp;
-             bufp += extra;
-             if (extra > avail)
-               {
-                 trim = extra - avail;
-                 bufp -= trim;
-                 do
-                   {
-                     if (*--q == '%')
-                       --extra;
-                   }
-                 while (--trim != 0);
-                 *q = '\0';
-                 avail = extra;
-               }
-             avail -= extra;
+         /* Copy the type specifier, and NULL terminate.  */
+         *sptr++ = *ptr++;
+         *sptr = '\0';
 
 
-             /* Now double all '%' chars, shuffling the string as we go.  */
-             while (extra != 0)
-               {
-                 while ((q[extra] = *q) != '%')
-                   --q;
-                 q[--extra] = '%';
-                 --q;
-               }
+         switch (ptr[-1])
+           {
+           case 'd':
+           case 'i':
+           case 'o':
+           case 'u':
+           case 'x':
+           case 'X':
+           case 'c':
+             {
+               /* Short values are promoted to int, so just copy it
+                  as an int and trust the C library printf to cast it
+                  to the right width.  */
+               if (short_width)
+                 PRINT_TYPE (int);
+               else
+                 {
+                   /* L modifier for bfd_vma or bfd_size_type may be
+                      either long long or long.  */
+                   if (sptr[-2] == 'L')
+                     {
+                       sptr[-2] = 'l';
+                       if (BFD_ARCH_SIZE < 64 || BFD_HOST_64BIT_LONG)
+                         wide_width = 1;
+                       else
+                         {
+                           sptr[-1] = 'l';
+                           *sptr++ = ptr[-1];
+                           *sptr = '\0';
+                         }
+                     }
+
+                   switch (wide_width)
+                     {
+                     case 0:
+                       PRINT_TYPE (int);
+                       break;
+                     case 1:
+                       PRINT_TYPE (long);
+                       break;
+                     case 2:
+                     default:
+#if defined (__MSVCRT__)
+                       sptr[-3] = 'I';
+                       sptr[-2] = '6';
+                       sptr[-1] = '4';
+                       *sptr++ = ptr[-1];
+                       *sptr = '\0';
+#endif
+#if defined (__GNUC__) || defined (HAVE_LONG_LONG)
+                       PRINT_TYPE (long long);
+#else
+                       /* Fake it and hope for the best.  */
+                       PRINT_TYPE (long);
+#endif
+                       break;
+                     }
+                 }
+             }
+             break;
+           case 'f':
+           case 'e':
+           case 'E':
+           case 'g':
+           case 'G':
+             {
+               if (wide_width == 0)
+                 PRINT_TYPE (double);
+               else
+                 {
+#if defined (__GNUC__) || defined (HAVE_LONG_DOUBLE)
+                   PRINT_TYPE (long double);
+#else
+                   /* Fake it and hope for the best.  */
+                   PRINT_TYPE (double);
+#endif
+                 }
+             }
+             break;
+           case 's':
+             PRINT_TYPE (char *);
+             break;
+           case 'p':
+             PRINT_TYPE (void *);
+             break;
+           case '%':
+             fputc ('%', stream);
+             result = 1;
+             break;
+           case 'A':
+             {
+               asection *sec = va_arg (ap, asection *);
+               bfd *abfd;
+               const char *group = NULL;
+               struct coff_comdat_info *ci;
+
+               if (sec == NULL)
+                 /* Invoking %A with a null section pointer is an
+                    internal error.  */
+                 abort ();
+               abfd = sec->owner;
+               if (abfd != NULL
+                   && bfd_get_flavour (abfd) == bfd_target_elf_flavour
+                   && elf_next_in_group (sec) != NULL
+                   && (sec->flags & SEC_GROUP) == 0)
+                 group = elf_group_name (sec);
+               else if (abfd != NULL
+                        && bfd_get_flavour (abfd) == bfd_target_coff_flavour
+                        && (ci = bfd_coff_get_comdat_section (sec->owner,
+                                                              sec)) != NULL)
+                 group = ci->name;
+               if (group != NULL)
+                 result = fprintf (stream, "%s[%s]", sec->name, group);
+               else
+                 result = fprintf (stream, "%s", sec->name);
+             }
+             break;
+           case 'B':
+             {
+               bfd *abfd = va_arg (ap, bfd *);
+
+               if (abfd == NULL)
+                 /* Invoking %B with a null bfd pointer is an
+                    internal error.  */
+                 abort ();
+               else if (abfd->my_archive
+                        && !bfd_is_thin_archive (abfd->my_archive))
+                 result = fprintf (stream, "%s(%s)",
+                                   abfd->my_archive->filename, abfd->filename);
+               else
+                 result = fprintf (stream, "%s", abfd->filename);
+             }
+             break;
+           default:
+             abort();
            }
        }
            }
        }
-      p = p + 2;
+      if (result == -1)
+       return -1;
+      total_printed += result;
     }
 
     }
 
-  vfprintf (stderr, new_fmt, ap);
-  va_end (ap);
+  return total_printed;
+}
+
+/* This is the default routine to handle BFD error messages.
+   Like fprintf (stderr, ...), but also handles some extra format specifiers.
+
+   %A section name from section.  For group components, print group name too.
+   %B file name from bfd.  For archive components, prints archive too.  */
+
+static void
+error_handler_internal (const char *fmt, va_list ap)
+{
+  /* PR 4992: Don't interrupt output being sent to stdout.  */
+  fflush (stdout);
+
+  if (_bfd_error_program_name != NULL)
+    fprintf (stderr, "%s: ", _bfd_error_program_name);
+  else
+    fprintf (stderr, "BFD: ");
+
+  _doprnt (stderr, fmt, ap);
 
 
-  putc ('\n', stderr);
+  /* On AIX, putc is implemented as a macro that triggers a -Wunused-value
+     warning, so use the fputc function to avoid it.  */
+  fputc ('\n', stderr);
+  fflush (stderr);
 }
 
 /* This is a function pointer to the routine which should handle BFD
 }
 
 /* This is a function pointer to the routine which should handle BFD
@@ -716,7 +882,17 @@ _bfd_default_error_handler (const char *fmt, ...)
    function pointer permits a program linked against BFD to intercept
    the messages and deal with them itself.  */
 
    function pointer permits a program linked against BFD to intercept
    the messages and deal with them itself.  */
 
-bfd_error_handler_type _bfd_error_handler = _bfd_default_error_handler;
+static bfd_error_handler_type _bfd_error_internal = error_handler_internal;
+
+void
+_bfd_error_handler (const char *fmt, ...)
+{
+  va_list ap;
+
+  va_start (ap, fmt);
+  _bfd_error_internal (fmt, ap);
+  va_end (ap);
+}
 
 /*
 FUNCTION
 
 /*
 FUNCTION
@@ -735,8 +911,8 @@ bfd_set_error_handler (bfd_error_handler_type pnew)
 {
   bfd_error_handler_type pold;
 
 {
   bfd_error_handler_type pold;
 
-  pold = _bfd_error_handler;
-  _bfd_error_handler = pnew;
+  pold = _bfd_error_internal;
+  _bfd_error_internal = pnew;
   return pold;
 }
 
   return pold;
 }
 
@@ -760,24 +936,75 @@ bfd_set_error_program_name (const char *name)
   _bfd_error_program_name = name;
 }
 
   _bfd_error_program_name = name;
 }
 
+/*
+SUBSECTION
+       BFD assert handler
+
+       If BFD finds an internal inconsistency, the bfd assert
+       handler is called with information on the BFD version, BFD
+       source file and line.  If this happens, most programs linked
+       against BFD are expected to want to exit with an error, or mark
+       the current BFD operation as failed, so it is recommended to
+       override the default handler, which just calls
+       _bfd_error_handler and continues.
+
+CODE_FRAGMENT
+.
+.typedef void (*bfd_assert_handler_type) (const char *bfd_formatmsg,
+.                                         const char *bfd_version,
+.                                         const char *bfd_file,
+.                                         int bfd_line);
+.
+*/
+
+/* Note the use of bfd_ prefix on the parameter names above: we want to
+   show which one is the message and which is the version by naming the
+   parameters, but avoid polluting the program-using-bfd namespace as
+   the typedef is visible in the exported headers that the program
+   includes.  Below, it's just for consistency.  */
+
+static void
+_bfd_default_assert_handler (const char *bfd_formatmsg,
+                            const char *bfd_version,
+                            const char *bfd_file,
+                            int bfd_line)
+
+{
+  _bfd_error_handler (bfd_formatmsg, bfd_version, bfd_file, bfd_line);
+}
+
+/* Similar to _bfd_error_handler, a program can decide to exit on an
+   internal BFD error.  We use a non-variadic type to simplify passing
+   on parameters to other functions, e.g. _bfd_error_handler.  */
+
+static bfd_assert_handler_type _bfd_assert_handler = _bfd_default_assert_handler;
+
 /*
 FUNCTION
 /*
 FUNCTION
-       bfd_get_error_handler
+       bfd_set_assert_handler
 
 SYNOPSIS
 
 SYNOPSIS
-       bfd_error_handler_type bfd_get_error_handler (void);
+       bfd_assert_handler_type bfd_set_assert_handler (bfd_assert_handler_type);
 
 DESCRIPTION
 
 DESCRIPTION
-       Return the BFD error handler function.
+       Set the BFD assert handler function.  Returns the previous
+       function.
 */
 
 */
 
-bfd_error_handler_type
-bfd_get_error_handler (void)
+bfd_assert_handler_type
+bfd_set_assert_handler (bfd_assert_handler_type pnew)
 {
 {
-  return _bfd_error_handler;
+  bfd_assert_handler_type pold;
+
+  pold = _bfd_assert_handler;
+  _bfd_assert_handler = pnew;
+  return pold;
 }
 \f
 /*
 }
 \f
 /*
+INODE
+Miscellaneous, Memory Usage, Error reporting, BFD front end
+
 SECTION
        Miscellaneous
 
 SECTION
        Miscellaneous
 
@@ -861,18 +1088,10 @@ DESCRIPTION
        section @var{sec} to the values @var{rel} and @var{count}.
        The argument @var{abfd} is ignored.
 
        section @var{sec} to the values @var{rel} and @var{count}.
        The argument @var{abfd} is ignored.
 
+.#define bfd_set_reloc(abfd, asect, location, count) \
+.     BFD_SEND (abfd, _bfd_set_reloc, (abfd, asect, location, count))
 */
 
 */
 
-void
-bfd_set_reloc (bfd *ignore_abfd ATTRIBUTE_UNUSED,
-              sec_ptr asect,
-              arelent **location,
-              unsigned int count)
-{
-  asect->orelocation = location;
-  asect->reloc_count = count;
-}
-
 /*
 FUNCTION
        bfd_set_file_flags
 /*
 FUNCTION
        bfd_set_file_flags
@@ -921,8 +1140,9 @@ bfd_set_file_flags (bfd *abfd, flagword flags)
 void
 bfd_assert (const char *file, int line)
 {
 void
 bfd_assert (const char *file, int line)
 {
-  (*_bfd_error_handler) (_("BFD %s assertion fail %s:%d"),
-                        BFD_VERSION_STRING, file, line);
+  /* xgettext:c-format */
+  (*_bfd_assert_handler) (_("BFD %s assertion fail %s:%d"),
+                         BFD_VERSION_STRING, file, line);
 }
 
 /* A more or less friendly abort message.  In libbfd.h abort is
 }
 
 /* A more or less friendly abort message.  In libbfd.h abort is
@@ -932,14 +1152,16 @@ void
 _bfd_abort (const char *file, int line, const char *fn)
 {
   if (fn != NULL)
 _bfd_abort (const char *file, int line, const char *fn)
 {
   if (fn != NULL)
-    (*_bfd_error_handler)
-      (_("BFD %s internal error, aborting at %s line %d in %s\n"),
+    _bfd_error_handler
+      /* xgettext:c-format */
+      (_("BFD %s internal error, aborting at %s:%d in %s\n"),
        BFD_VERSION_STRING, file, line, fn);
   else
        BFD_VERSION_STRING, file, line, fn);
   else
-    (*_bfd_error_handler)
-      (_("BFD %s internal error, aborting at %s line %d\n"),
+    _bfd_error_handler
+      /* xgettext:c-format */
+      (_("BFD %s internal error, aborting at %s:%d\n"),
        BFD_VERSION_STRING, file, line);
        BFD_VERSION_STRING, file, line);
-  (*_bfd_error_handler) (_("Please report this bug.\n"));
+  _bfd_error_handler (_("Please report this bug.\n"));
   _exit (EXIT_FAILURE);
 }
 
   _exit (EXIT_FAILURE);
 }
 
@@ -951,9 +1173,11 @@ SYNOPSIS
        int bfd_get_arch_size (bfd *abfd);
 
 DESCRIPTION
        int bfd_get_arch_size (bfd *abfd);
 
 DESCRIPTION
-       Returns the architecture address size, in bits, as determined
-       by the object file's format.  For ELF, this information is
-       included in the header.
+       Returns the normalized architecture address size, in bits, as
+       determined by the object file's format.  By normalized, we mean
+       either 32 or 64.  For ELF, this information is included in the
+       header.  Use bfd_arch_bits_per_address for number of bits in
+       the architecture address.
 
 RETURNS
        Returns the arch size in bits if known, <<-1>> otherwise.
 
 RETURNS
        Returns the arch size in bits if known, <<-1>> otherwise.
@@ -965,7 +1189,7 @@ bfd_get_arch_size (bfd *abfd)
   if (abfd->xvec->flavour == bfd_target_elf_flavour)
     return get_elf_backend_data (abfd)->s->arch_size;
 
   if (abfd->xvec->flavour == bfd_target_elf_flavour)
     return get_elf_backend_data (abfd)->s->arch_size;
 
-  return -1;
+  return bfd_arch_bits_per_address (abfd) > 32 ? 64 : 32;
 }
 
 /*
 }
 
 /*
@@ -1010,7 +1234,8 @@ bfd_get_sign_extend_vma (bfd *abfd)
       || strcmp (name, "pe-x86-64") == 0
       || strcmp (name, "pei-x86-64") == 0
       || strcmp (name, "pe-arm-wince-little") == 0
       || strcmp (name, "pe-x86-64") == 0
       || strcmp (name, "pei-x86-64") == 0
       || strcmp (name, "pe-arm-wince-little") == 0
-      || strcmp (name, "pei-arm-wince-little") == 0)
+      || strcmp (name, "pei-arm-wince-little") == 0
+      || strcmp (name, "aixcoff-rs6000") == 0)
     return 1;
 
   if (CONST_STRNEQ (name, "mach-o"))
     return 1;
 
   if (CONST_STRNEQ (name, "mach-o"))
@@ -1162,7 +1387,7 @@ bfd_scan_vma (const char *string, const char **end, int base)
   if (sizeof (bfd_vma) <= sizeof (unsigned long))
     return strtoul (string, (char **) end, base);
 
   if (sizeof (bfd_vma) <= sizeof (unsigned long))
     return strtoul (string, (char **) end, base);
 
-#ifdef HAVE_STRTOULL
+#if defined (HAVE_STRTOULL) && defined (HAVE_LONG_LONG)
   if (sizeof (bfd_vma) <= sizeof (unsigned long long))
     return strtoull (string, (char **) end, base);
 #endif
   if (sizeof (bfd_vma) <= sizeof (unsigned long long))
     return strtoull (string, (char **) end, base);
 #endif
@@ -1265,27 +1490,6 @@ DESCRIPTION
 
 */
 
 
 */
 
-/*
-FUNCTION
-       bfd_merge_private_bfd_data
-
-SYNOPSIS
-       bfd_boolean bfd_merge_private_bfd_data (bfd *ibfd, bfd *obfd);
-
-DESCRIPTION
-       Merge private BFD information from the BFD @var{ibfd} to the
-       the output file BFD @var{obfd} when linking.  Return <<TRUE>>
-       on success, <<FALSE>> on error.  Possible error returns are:
-
-       o <<bfd_error_no_memory>> -
-       Not enough memory exists to create private data for @var{obfd}.
-
-.#define bfd_merge_private_bfd_data(ibfd, obfd) \
-.     BFD_SEND (obfd, _bfd_merge_private_bfd_data, \
-.              (ibfd, obfd))
-
-*/
-
 /*
 FUNCTION
        bfd_set_private_flags
 /*
 FUNCTION
        bfd_set_private_flags
@@ -1318,7 +1522,12 @@ DESCRIPTION
 .
 .#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \
 .       BFD_SEND (abfd, _bfd_find_nearest_line, \
 .
 .#define bfd_find_nearest_line(abfd, sec, syms, off, file, func, line) \
 .       BFD_SEND (abfd, _bfd_find_nearest_line, \
-.                 (abfd, sec, syms, off, file, func, line))
+.                 (abfd, syms, sec, off, file, func, line, NULL))
+.
+.#define bfd_find_nearest_line_discriminator(abfd, sec, syms, off, file, func, \
+.                                            line, disc) \
+.       BFD_SEND (abfd, _bfd_find_nearest_line, \
+.                 (abfd, syms, sec, off, file, func, line, disc))
 .
 .#define bfd_find_line(abfd, syms, sym, file, line) \
 .       BFD_SEND (abfd, _bfd_find_line, \
 .
 .#define bfd_find_line(abfd, syms, sym, file, line) \
 .       BFD_SEND (abfd, _bfd_find_line, \
@@ -1352,6 +1561,9 @@ DESCRIPTION
 .#define bfd_gc_sections(abfd, link_info) \
 .      BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info))
 .
 .#define bfd_gc_sections(abfd, link_info) \
 .      BFD_SEND (abfd, _bfd_gc_sections, (abfd, link_info))
 .
+.#define bfd_lookup_section_flags(link_info, flag_info, section) \
+.      BFD_SEND (abfd, _bfd_lookup_section_flags, (link_info, flag_info, section))
+.
 .#define bfd_merge_sections(abfd, link_info) \
 .      BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info))
 .
 .#define bfd_merge_sections(abfd, link_info) \
 .      BFD_SEND (abfd, _bfd_merge_sections, (abfd, link_info))
 .
@@ -1364,9 +1576,6 @@ DESCRIPTION
 .#define bfd_link_hash_table_create(abfd) \
 .      BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd))
 .
 .#define bfd_link_hash_table_create(abfd) \
 .      BFD_SEND (abfd, _bfd_link_hash_table_create, (abfd))
 .
-.#define bfd_link_hash_table_free(abfd, hash) \
-.      BFD_SEND (abfd, _bfd_link_hash_table_free, (hash))
-.
 .#define bfd_link_add_symbols(abfd, info) \
 .      BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info))
 .
 .#define bfd_link_add_symbols(abfd, info) \
 .      BFD_SEND (abfd, _bfd_link_add_symbols, (abfd, info))
 .
@@ -1468,7 +1677,7 @@ bfd_record_phdr (bfd *abfd,
   if (count > 0)
     memcpy (m->sections, secs, count * sizeof (asection *));
 
   if (count > 0)
     memcpy (m->sections, secs, count * sizeof (asection *));
 
-  for (pm = &elf_tdata (abfd)->segment_map; *pm != NULL; pm = &(*pm)->next)
+  for (pm = &elf_seg_map (abfd); *pm != NULL; pm = &(*pm)->next)
     ;
   *pm = m;
 
     ;
   *pm = m;
 
@@ -1574,128 +1783,6 @@ bfd_alt_mach_code (bfd *abfd, int alternative)
   return FALSE;
 }
 
   return FALSE;
 }
 
-/*
-CODE_FRAGMENT
-
-.struct bfd_preserve
-.{
-.  void *marker;
-.  void *tdata;
-.  flagword flags;
-.  const struct bfd_arch_info *arch_info;
-.  struct bfd_section *sections;
-.  struct bfd_section *section_last;
-.  unsigned int section_count;
-.  struct bfd_hash_table section_htab;
-.};
-.
-*/
-
-/*
-FUNCTION
-       bfd_preserve_save
-
-SYNOPSIS
-       bfd_boolean bfd_preserve_save (bfd *, struct bfd_preserve *);
-
-DESCRIPTION
-       When testing an object for compatibility with a particular
-       target back-end, the back-end object_p function needs to set
-       up certain fields in the bfd on successfully recognizing the
-       object.  This typically happens in a piecemeal fashion, with
-       failures possible at many points.  On failure, the bfd is
-       supposed to be restored to its initial state, which is
-       virtually impossible.  However, restoring a subset of the bfd
-       state works in practice.  This function stores the subset and
-       reinitializes the bfd.
-
-*/
-
-bfd_boolean
-bfd_preserve_save (bfd *abfd, struct bfd_preserve *preserve)
-{
-  preserve->tdata = abfd->tdata.any;
-  preserve->arch_info = abfd->arch_info;
-  preserve->flags = abfd->flags;
-  preserve->sections = abfd->sections;
-  preserve->section_last = abfd->section_last;
-  preserve->section_count = abfd->section_count;
-  preserve->section_htab = abfd->section_htab;
-
-  if (! bfd_hash_table_init (&abfd->section_htab, bfd_section_hash_newfunc,
-                            sizeof (struct section_hash_entry)))
-    return FALSE;
-
-  abfd->tdata.any = NULL;
-  abfd->arch_info = &bfd_default_arch_struct;
-  abfd->flags &= BFD_IN_MEMORY;
-  abfd->sections = NULL;
-  abfd->section_last = NULL;
-  abfd->section_count = 0;
-
-  return TRUE;
-}
-
-/*
-FUNCTION
-       bfd_preserve_restore
-
-SYNOPSIS
-       void bfd_preserve_restore (bfd *, struct bfd_preserve *);
-
-DESCRIPTION
-       This function restores bfd state saved by bfd_preserve_save.
-       If MARKER is non-NULL in struct bfd_preserve then that block
-       and all subsequently bfd_alloc'd memory is freed.
-
-*/
-
-void
-bfd_preserve_restore (bfd *abfd, struct bfd_preserve *preserve)
-{
-  bfd_hash_table_free (&abfd->section_htab);
-
-  abfd->tdata.any = preserve->tdata;
-  abfd->arch_info = preserve->arch_info;
-  abfd->flags = preserve->flags;
-  abfd->section_htab = preserve->section_htab;
-  abfd->sections = preserve->sections;
-  abfd->section_last = preserve->section_last;
-  abfd->section_count = preserve->section_count;
-
-  /* bfd_release frees all memory more recently bfd_alloc'd than
-     its arg, as well as its arg.  */
-  if (preserve->marker != NULL)
-    {
-      bfd_release (abfd, preserve->marker);
-      preserve->marker = NULL;
-    }
-}
-
-/*
-FUNCTION
-       bfd_preserve_finish
-
-SYNOPSIS
-       void bfd_preserve_finish (bfd *, struct bfd_preserve *);
-
-DESCRIPTION
-       This function should be called when the bfd state saved by
-       bfd_preserve_save is no longer needed.  ie. when the back-end
-       object_p function returns with success.
-
-*/
-
-void
-bfd_preserve_finish (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_preserve *preserve)
-{
-  /* It would be nice to be able to free more memory here, eg. old
-     tdata, but that's not possible since these blocks are sitting
-     inside bfd_alloc'd memory.  The section hash is on a separate
-     objalloc.  */
-  bfd_hash_table_free (&preserve->section_htab);
-}
-
 /*
 FUNCTION
        bfd_emul_get_maxpagesize
 /*
 FUNCTION
        bfd_emul_get_maxpagesize
@@ -1914,3 +2001,316 @@ bfd_demangle (bfd *abfd, const char *name, int options)
 
   return res;
 }
 
   return res;
 }
+
+/*
+FUNCTION
+       bfd_update_compression_header
+
+SYNOPSIS
+       void bfd_update_compression_header
+         (bfd *abfd, bfd_byte *contents, asection *sec);
+
+DESCRIPTION
+       Set the compression header at CONTENTS of SEC in ABFD and update
+       elf_section_flags for compression.
+*/
+
+void
+bfd_update_compression_header (bfd *abfd, bfd_byte *contents,
+                              asection *sec)
+{
+  if ((abfd->flags & BFD_COMPRESS) != 0)
+    {
+      if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+       {
+         if ((abfd->flags & BFD_COMPRESS_GABI) != 0)
+           {
+             const struct elf_backend_data *bed
+               = get_elf_backend_data (abfd);
+
+             /* Set the SHF_COMPRESSED bit.  */
+             elf_section_flags (sec) |= SHF_COMPRESSED;
+
+             if (bed->s->elfclass == ELFCLASS32)
+               {
+                 Elf32_External_Chdr *echdr
+                   = (Elf32_External_Chdr *) contents;
+                 bfd_put_32 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+                 bfd_put_32 (abfd, sec->size, &echdr->ch_size);
+                 bfd_put_32 (abfd, 1 << sec->alignment_power,
+                             &echdr->ch_addralign);
+               }
+             else
+               {
+                 Elf64_External_Chdr *echdr
+                   = (Elf64_External_Chdr *) contents;
+                 bfd_put_32 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+                 bfd_put_32 (abfd, 0, &echdr->ch_reserved);
+                 bfd_put_64 (abfd, sec->size, &echdr->ch_size);
+                 bfd_put_64 (abfd, 1 << sec->alignment_power,
+                             &echdr->ch_addralign);
+               }
+           }
+         else
+           {
+             /* Clear the SHF_COMPRESSED bit.  */
+             elf_section_flags (sec) &= ~SHF_COMPRESSED;
+
+             /* Write the zlib header.  It should be "ZLIB" followed by
+                the uncompressed section size, 8 bytes in big-endian
+                order.  */
+             memcpy (contents, "ZLIB", 4);
+             bfd_putb64 (sec->size, contents + 4);
+           }
+       }
+    }
+  else
+    abort ();
+}
+
+/*
+   FUNCTION
+   bfd_check_compression_header
+
+   SYNOPSIS
+       bfd_boolean bfd_check_compression_header
+         (bfd *abfd, bfd_byte *contents, asection *sec,
+         bfd_size_type *uncompressed_size);
+
+DESCRIPTION
+       Check the compression header at CONTENTS of SEC in ABFD and
+       store the uncompressed size in UNCOMPRESSED_SIZE if the
+       compression header is valid.
+
+RETURNS
+       Return TRUE if the compression header is valid.
+*/
+
+bfd_boolean
+bfd_check_compression_header (bfd *abfd, bfd_byte *contents,
+                             asection *sec,
+                             bfd_size_type *uncompressed_size)
+{
+  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour
+      && (elf_section_flags (sec) & SHF_COMPRESSED) != 0)
+    {
+      Elf_Internal_Chdr chdr;
+      const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+      if (bed->s->elfclass == ELFCLASS32)
+       {
+         Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) contents;
+         chdr.ch_type = bfd_get_32 (abfd, &echdr->ch_type);
+         chdr.ch_size = bfd_get_32 (abfd, &echdr->ch_size);
+         chdr.ch_addralign = bfd_get_32 (abfd, &echdr->ch_addralign);
+       }
+      else
+       {
+         Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) contents;
+         chdr.ch_type = bfd_get_32 (abfd, &echdr->ch_type);
+         chdr.ch_size = bfd_get_64 (abfd, &echdr->ch_size);
+         chdr.ch_addralign = bfd_get_64 (abfd, &echdr->ch_addralign);
+       }
+      if (chdr.ch_type == ELFCOMPRESS_ZLIB
+         && chdr.ch_addralign == 1U << sec->alignment_power)
+       {
+         *uncompressed_size = chdr.ch_size;
+         return TRUE;
+       }
+    }
+
+  return FALSE;
+}
+
+/*
+FUNCTION
+       bfd_get_compression_header_size
+
+SYNOPSIS
+       int bfd_get_compression_header_size (bfd *abfd, asection *sec);
+
+DESCRIPTION
+       Return the size of the compression header of SEC in ABFD.
+
+RETURNS
+       Return the size of the compression header in bytes.
+*/
+
+int
+bfd_get_compression_header_size (bfd *abfd, asection *sec)
+{
+  if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
+    {
+      if (sec == NULL)
+       {
+         if (!(abfd->flags & BFD_COMPRESS_GABI))
+           return 0;
+       }
+      else if (!(elf_section_flags (sec) & SHF_COMPRESSED))
+       return 0;
+
+      if (get_elf_backend_data (abfd)->s->elfclass == ELFCLASS32)
+       return sizeof (Elf32_External_Chdr);
+      else
+       return sizeof (Elf64_External_Chdr);
+    }
+
+  return 0;
+}
+
+/*
+FUNCTION
+       bfd_convert_section_size
+
+SYNOPSIS
+       bfd_size_type bfd_convert_section_size
+         (bfd *ibfd, asection *isec, bfd *obfd, bfd_size_type size);
+
+DESCRIPTION
+       Convert the size @var{size} of the section @var{isec} in input
+       BFD @var{ibfd} to the section size in output BFD @var{obfd}.
+*/
+
+bfd_size_type
+bfd_convert_section_size (bfd *ibfd, sec_ptr isec, bfd *obfd,
+                         bfd_size_type size)
+{
+  bfd_size_type hdr_size;
+
+  /* Do nothing if input file will be decompressed.  */
+  if ((ibfd->flags & BFD_DECOMPRESS))
+    return size;
+
+  /* Do nothing if either input or output aren't ELF.  */
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return size;
+
+  /* Do nothing if ELF classes of input and output are the same. */
+  if (get_elf_backend_data (ibfd)->s->elfclass
+      == get_elf_backend_data (obfd)->s->elfclass)
+    return size;
+
+  /* Do nothing if the input section isn't a SHF_COMPRESSED section. */
+  hdr_size = bfd_get_compression_header_size (ibfd, isec);
+  if (hdr_size == 0)
+    return size;
+
+  /* Adjust the size of the output SHF_COMPRESSED section.  */
+  if (hdr_size == sizeof (Elf32_External_Chdr))
+    return (size - sizeof (Elf32_External_Chdr)
+           + sizeof (Elf64_External_Chdr));
+  else
+    return (size - sizeof (Elf64_External_Chdr)
+           + sizeof (Elf32_External_Chdr));
+}
+
+/*
+FUNCTION
+       bfd_convert_section_contents
+
+SYNOPSIS
+       bfd_boolean bfd_convert_section_contents
+         (bfd *ibfd, asection *isec, bfd *obfd,
+          bfd_byte **ptr, bfd_size_type *ptr_size);
+
+DESCRIPTION
+       Convert the contents, stored in @var{*ptr}, of the section
+       @var{isec} in input BFD @var{ibfd} to output BFD @var{obfd}
+       if needed.  The original buffer pointed to by @var{*ptr} may
+       be freed and @var{*ptr} is returned with memory malloc'd by this
+       function, and the new size written to @var{ptr_size}.
+*/
+
+bfd_boolean
+bfd_convert_section_contents (bfd *ibfd, sec_ptr isec, bfd *obfd,
+                             bfd_byte **ptr, bfd_size_type *ptr_size)
+{
+  bfd_byte *contents;
+  bfd_size_type ihdr_size, ohdr_size, size;
+  Elf_Internal_Chdr chdr;
+  bfd_boolean use_memmove;
+
+  /* Do nothing if input file will be decompressed.  */
+  if ((ibfd->flags & BFD_DECOMPRESS))
+    return TRUE;
+
+  /* Do nothing if either input or output aren't ELF.  */
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
+    return TRUE;
+
+  /* Do nothing if ELF classes of input and output are the same. */
+  if (get_elf_backend_data (ibfd)->s->elfclass
+      == get_elf_backend_data (obfd)->s->elfclass)
+    return TRUE;
+
+  /* Do nothing if the input section isn't a SHF_COMPRESSED section. */
+  ihdr_size = bfd_get_compression_header_size (ibfd, isec);
+  if (ihdr_size == 0)
+    return TRUE;
+
+  contents = *ptr;
+
+  /* Convert the contents of the input SHF_COMPRESSED section to
+     output.  Get the input compression header and the size of the
+     output compression header.  */
+  if (ihdr_size == sizeof (Elf32_External_Chdr))
+    {
+      Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) contents;
+      chdr.ch_type = bfd_get_32 (ibfd, &echdr->ch_type);
+      chdr.ch_size = bfd_get_32 (ibfd, &echdr->ch_size);
+      chdr.ch_addralign = bfd_get_32 (ibfd, &echdr->ch_addralign);
+
+      ohdr_size = sizeof (Elf64_External_Chdr);
+
+      use_memmove = FALSE;
+    }
+  else
+    {
+      Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) contents;
+      chdr.ch_type = bfd_get_32 (ibfd, &echdr->ch_type);
+      chdr.ch_size = bfd_get_64 (ibfd, &echdr->ch_size);
+      chdr.ch_addralign = bfd_get_64 (ibfd, &echdr->ch_addralign);
+
+      ohdr_size = sizeof (Elf32_External_Chdr);
+      use_memmove = TRUE;
+    }
+
+  size = bfd_get_section_size (isec) - ihdr_size + ohdr_size;
+  if (!use_memmove)
+    {
+      contents = (bfd_byte *) bfd_malloc (size);
+      if (contents == NULL)
+       return FALSE;
+    }
+
+  /* Write out the output compression header.  */
+  if (ohdr_size == sizeof (Elf32_External_Chdr))
+    {
+      Elf32_External_Chdr *echdr = (Elf32_External_Chdr *) contents;
+      bfd_put_32 (obfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+      bfd_put_32 (obfd, chdr.ch_size, &echdr->ch_size);
+      bfd_put_32 (obfd, chdr.ch_addralign, &echdr->ch_addralign);
+    }
+  else
+    {
+      Elf64_External_Chdr *echdr = (Elf64_External_Chdr *) contents;
+      bfd_put_32 (obfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+      bfd_put_32 (obfd, 0, &echdr->ch_reserved);
+      bfd_put_64 (obfd, chdr.ch_size, &echdr->ch_size);
+      bfd_put_64 (obfd, chdr.ch_addralign, &echdr->ch_addralign);
+    }
+
+  /* Copy the compressed contents.  */
+  if (use_memmove)
+    memmove (contents + ohdr_size, *ptr + ihdr_size, size - ohdr_size);
+  else
+    {
+      memcpy (contents + ohdr_size, *ptr + ihdr_size, size - ohdr_size);
+      free (*ptr);
+      *ptr = contents;
+    }
+
+  *ptr_size = size;
+  return TRUE;
+}
This page took 0.037803 seconds and 4 git commands to generate.