Add SHF_COMPRESSED support to gas and objcopy
authorH.J. Lu <hjl.tools@gmail.com>
Wed, 8 Apr 2015 14:53:54 +0000 (07:53 -0700)
committerH.J. Lu <hjl.tools@gmail.com>
Wed, 8 Apr 2015 14:54:09 +0000 (07:54 -0700)
This patch adds --compress-debug-sections={none|zlib|zlib-gnu|zlib-gabi}
options to gas and objcopy for ELF files. They control how DWARF debug
sections are compressed.  --compress-debug-sections=none is equivalent to
--nocompress-debug-sections.  --compress-debug-sections=zlib and
--compress-debug-sections=zlib-gnu are equivalent to
--compress-debug-sections.  --compress-debug-sections=zlib-gabi compresses
DWARF debug sections with SHF_COMPRESSED from the ELF ABI.  No linker
changes are required to support SHF_COMPRESSED.

bfd/

* archive.c (_bfd_get_elt_at_filepos): Also copy BFD_COMPRESS_GABI
bit.
* bfd.c (bfd::flags): Increase size to 18 bits.
(BFD_COMPRESS_GABI): New.
(BFD_FLAGS_SAVED): Add BFD_COMPRESS_GABI.
(BFD_FLAGS_FOR_BFD_USE_MASK): Likewise.
(bfd_update_compression_header): New fuction.
(bfd_check_compression_header): Likewise.
(bfd_get_compression_header_size): Likewise.
(bfd_is_section_compressed_with_header): Likewise.
* compress.c (MAX_COMPRESSION_HEADER_SIZE): New.
(bfd_compress_section_contents): Return the uncompressed size if
the full section contents is compressed successfully.  Support
converting from/to .zdebug* sections.
(bfd_get_full_section_contents): Call
bfd_get_compression_header_size to get compression header size.
(bfd_is_section_compressed): Renamed to ...
(bfd_is_section_compressed_with_header): This.  Add a pointer
argument to return compression header size.
(bfd_is_section_compressed): Use it.
(bfd_init_section_decompress_status): Call
bfd_get_compression_header_size to get compression header size.
Return FALSE if uncompressed section size is 0.
* elf.c (_bfd_elf_make_section_from_shdr): Support converting
from/to .zdebug* sections.
* bfd-in2.h: Regenerated.

binutils/

* objcopy.c (do_debug_sections): Add compress_zlib,
compress_gnu_zlib and compress_gabi_zlib.
(copy_options): Use optional_argument on compress-debug-sections.
(copy_usage): Update --compress-debug-sections.
(copy_file): Handle compress_zlib, compress_gnu_zlib and
compress_gabi_zlib.
(copy_main): Handle
--compress-debug-sections={none|zlib|zlib-gnu|zlib-gabi}.
* doc/binutils.texi: Document
--compress-debug-sections={none|zlib|zlib-gnu|zlib-gabi}.

binutils/testsuite/

* compress.exp: Add tests for
--compress-debug-sections={none|zlib|zlib-gnu|zlib-gabi}.
* binutils-all/dw2-3.rS: New file.
* binutils-all/dw2-3.rt: Likewise.
* binutils-all/libdw2-compressedgabi.out: Likewise.

gas/

* as.c (show_usage): Update --compress-debug-sections.
(std_longopts): Use optional_argument on compress-debug-sections.
(parse_args): Handle
--compress-debug-sections={none|zlib|zlib-gnu|zlib-gabi}.
* as.h (compressed_debug_section_type): New.
(flag_compress_debug): Change type to compressed_debug_section_type.
--compress-debug-sections={none|zlib|zlib-gnu|zlib-gabi}.
* write.c (compress_debug): Set BFD_COMPRESS_GABI for
--compress-debug-sections=zlib-gabi.  Call
bfd_get_compression_header_size to get compression header size.
Don't rename section name for --compress-debug-sections=zlib-gabi.
* config/tc-i386.c (compressed_debug_section_type): Set to
COMPRESS_DEBUG_ZLIB.
* doc/as.texinfo: Document
--compress-debug-sections={none|zlib|zlib-gnu|zlib-gabi}.

gas/testsuite/

* gas/i386/dw2-compressed-1.d: New file.
* gas/i386/dw2-compressed-2.d: Likewise.
* gas/i386/dw2-compressed-3.d: Likewise.
* gas/i386/x86-64-dw2-compressed-2.d: Likewise.
* gas/i386/i386.exp: Run dw2-compressed-2, dw2-compressed-1,
dw2-compressed-3 and x86-64-dw2-compressed-2.

ld/testsuite/

* ld-elf/compress.exp: Add a test for
--compress-debug-sections=zlib-gabi.
(build_tests): Add 2 tests for --compress-debug-sections=zlib-gabi.
(run_tests): Likewise.
Verify linker output with zlib-gabi compressed debug input.
* ld-elf/compressed1a.d: New file.
* ld-elf/compressed1b.d: Likewise.
* ld-elf/compressed1c.d: Likewise.

31 files changed:
bfd/ChangeLog
bfd/archive.c
bfd/bfd-in2.h
bfd/bfd.c
bfd/compress.c
bfd/elf.c
binutils/ChangeLog
binutils/doc/binutils.texi
binutils/objcopy.c
binutils/testsuite/ChangeLog
binutils/testsuite/binutils-all/compress.exp
binutils/testsuite/binutils-all/dw2-3.rS [new file with mode: 0644]
binutils/testsuite/binutils-all/dw2-3.rt [new file with mode: 0644]
binutils/testsuite/binutils-all/libdw2-compressedgabi.out [new file with mode: 0644]
gas/ChangeLog
gas/as.c
gas/as.h
gas/config/tc-i386.c
gas/doc/as.texinfo
gas/testsuite/ChangeLog
gas/testsuite/gas/i386/dw2-compressed-1.d [new file with mode: 0644]
gas/testsuite/gas/i386/dw2-compressed-2.d [new file with mode: 0644]
gas/testsuite/gas/i386/dw2-compressed-3.d [new file with mode: 0644]
gas/testsuite/gas/i386/i386.exp
gas/testsuite/gas/i386/x86-64-dw2-compressed-2.d [new file with mode: 0644]
gas/write.c
ld/testsuite/ChangeLog
ld/testsuite/ld-elf/compress.exp
ld/testsuite/ld-elf/compressed1a.d [new file with mode: 0644]
ld/testsuite/ld-elf/compressed1b.d [new file with mode: 0644]
ld/testsuite/ld-elf/compressed1c.d [new file with mode: 0644]

index 192d9aa..68e13c5 100644 (file)
@@ -1,3 +1,32 @@
+2015-04-08  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * archive.c (_bfd_get_elt_at_filepos): Also copy BFD_COMPRESS_GABI
+       bit.
+       * bfd.c (bfd::flags): Increase size to 18 bits.
+       (BFD_COMPRESS_GABI): New.
+       (BFD_FLAGS_SAVED): Add BFD_COMPRESS_GABI.
+       (BFD_FLAGS_FOR_BFD_USE_MASK): Likewise.
+       (bfd_update_compression_header): New fuction.
+       (bfd_check_compression_header): Likewise.
+       (bfd_get_compression_header_size): Likewise.
+       (bfd_is_section_compressed_with_header): Likewise.
+       * compress.c (MAX_COMPRESSION_HEADER_SIZE): New.
+       (bfd_compress_section_contents): Return the uncompressed size if
+       the full section contents is compressed successfully.  Support
+       converting from/to .zdebug* sections.
+       (bfd_get_full_section_contents): Call
+       bfd_get_compression_header_size to get compression header size.
+       (bfd_is_section_compressed): Renamed to ...
+       (bfd_is_section_compressed_with_header): This.  Add a pointer
+       argument to return compression header size.
+       (bfd_is_section_compressed): Use it.
+       (bfd_init_section_decompress_status): Call
+       bfd_get_compression_header_size to get compression header size.
+       Return FALSE if uncompressed section size is 0.
+       * elf.c (_bfd_elf_make_section_from_shdr): Support converting
+       from/to .zdebug* sections.
+       * bfd-in2.h: Regenerated.
+
 2015-04-07  Alan Modra  <amodra@gmail.com>
 
        * elf.c (_bfd_elf_get_reloc_section): Allow for .got.plt being
index 3899d84..31d86f3 100644 (file)
@@ -725,8 +725,10 @@ _bfd_get_elt_at_filepos (bfd *archive, file_ptr filepos)
 
   n_bfd->arelt_data = new_areldata;
 
-  /* Copy BFD_COMPRESS and BFD_DECOMPRESS flags.  */
-  n_bfd->flags |= archive->flags & (BFD_COMPRESS | BFD_DECOMPRESS);
+  /* Copy BFD_COMPRESS, BFD_DECOMPRESS and BFD_COMPRESS_GABI flags.  */
+  n_bfd->flags |= archive->flags & (BFD_COMPRESS
+                                   | BFD_DECOMPRESS
+                                   | BFD_COMPRESS_GABI);
 
   if (_bfd_add_bfd_to_archive_cache (archive, filepos, n_bfd))
     return n_bfd;
index 81def3f..679595e 100644 (file)
@@ -6323,7 +6323,7 @@ struct bfd
   ENUM_BITFIELD (bfd_direction) direction : 2;
 
   /* Format_specific flags.  */
-  flagword flags : 17;
+  flagword flags : 18;
 
   /* 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
@@ -6400,14 +6400,19 @@ struct bfd
   /* 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
+
   /* Flags bits to be saved in bfd_preserve_save.  */
 #define BFD_FLAGS_SAVED \
-  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN)
+  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN \
+   | BFD_COMPRESS_GABI)
 
   /* 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_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT \
+   | BFD_COMPRESS_GABI)
 
   /* Is the file descriptor being cached?  That is, can it be closed as
      needed, and re-opened when accessed later?  */
@@ -6777,6 +6782,15 @@ void bfd_emul_set_commonpagesize (const char *, bfd_vma);
 
 char *bfd_demangle (bfd *, const char *, int);
 
+void bfd_update_compression_header
+   (bfd *abfd, bfd_byte *contents, asection *sec);
+
+bfd_boolean bfd_check_compression_header
+   (bfd *abfd, bfd_byte *contents, asection *sec,
+    bfd_size_type uncompressed_size);
+
+int bfd_get_compression_header_size (bfd *abfd, asection *sec);
+
 /* Extracted from archive.c.  */
 symindex bfd_get_next_mapent
    (bfd *abfd, symindex previous, carsym **sym);
@@ -7289,6 +7303,10 @@ bfd_boolean bfd_get_full_section_contents
 void bfd_cache_section_contents
    (asection *sec, void *contents);
 
+bfd_boolean bfd_is_section_compressed_with_header
+   (bfd *abfd, asection *section,
+    int *compression_header_size_p);
+
 bfd_boolean bfd_is_section_compressed
    (bfd *abfd, asection *section);
 
index 5ae5eca..ba78cf3 100644 (file)
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -85,7 +85,7 @@ CODE_FRAGMENT
 .  ENUM_BITFIELD (bfd_direction) direction : 2;
 .
 .  {* Format_specific flags.  *}
-.  flagword flags : 17;
+.  flagword flags : 18;
 .
 .  {* 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
@@ -162,14 +162,19 @@ CODE_FRAGMENT
 .  {* 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
+.
 .  {* Flags bits to be saved in bfd_preserve_save.  *}
 .#define BFD_FLAGS_SAVED \
-.  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN)
+.  (BFD_IN_MEMORY | BFD_COMPRESS | BFD_DECOMPRESS | BFD_PLUGIN \
+.   | BFD_COMPRESS_GABI)
 .
 .  {* 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_PLUGIN | BFD_TRADITIONAL_FORMAT | BFD_DETERMINISTIC_OUTPUT \
+.   | BFD_COMPRESS_GABI)
 .
 .  {* Is the file descriptor being cached?  That is, can it be closed as
 .     needed, and re-opened when accessed later?  *}
@@ -1940,3 +1945,145 @@ bfd_demangle (bfd *abfd, const char *name, int options)
 
   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_64 (abfd, ELFCOMPRESS_ZLIB, &echdr->ch_type);
+                 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;
+       }
+    }
+  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 with
+       the uncompressed size UNCOMPRESSED_SIZE.
+
+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_64 (abfd, &echdr->ch_type);
+         chdr.ch_size = bfd_get_64 (abfd, &echdr->ch_size);
+         chdr.ch_addralign = bfd_get_64 (abfd, &echdr->ch_addralign);
+       }
+      return (chdr.ch_type == ELFCOMPRESS_ZLIB
+             && chdr.ch_size == uncompressed_size
+             && chdr.ch_addralign == 1U << sec->alignment_power);
+    }
+
+  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;
+}
index b57650f..ba9fc96 100644 (file)
@@ -24,6 +24,8 @@
 #include "libbfd.h"
 #include "safe-ctype.h"
 
+#define MAX_COMPRESSION_HEADER_SIZE 24
+
 static bfd_boolean
 decompress_contents (bfd_byte *compressed_buffer,
                     bfd_size_type compressed_size,
@@ -65,55 +67,136 @@ decompress_contents (bfd_byte *compressed_buffer,
    field was allocated using bfd_malloc() or equivalent.  If zlib
    is not installed on this machine, the input is unmodified.
 
-   Return @code{TRUE} if the full section contents is compressed
-   successfully.  */
+   Return the uncompressed size if the full section contents is
+   compressed successfully.  Otherwise return 0.  */
 
-static bfd_boolean
-bfd_compress_section_contents (bfd *abfd ATTRIBUTE_UNUSED, sec_ptr sec,
+static bfd_size_type
+bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
                               bfd_byte *uncompressed_buffer,
                               bfd_size_type uncompressed_size)
 {
   uLong compressed_size;
-  bfd_byte *compressed_buffer;
-
-  compressed_size = compressBound (uncompressed_size) + 12;
-  compressed_buffer = (bfd_byte *) bfd_malloc (compressed_size);
+  bfd_byte *buffer;
+  bfd_size_type buffer_size;
+  bfd_boolean decompress;
+  int zlib_size;
+  int orig_compression_header_size;
+  int compression_header_size
+    = bfd_get_compression_header_size (abfd, NULL);
+  bfd_boolean compressed
+    = bfd_is_section_compressed_with_header (abfd, sec,
+                                            &orig_compression_header_size);
+
+  if (compressed)
+    {
+      /* We shouldn't decompress unsupported compressed section.  */
+      if (orig_compression_header_size < 0)
+       abort ();
 
-  if (compressed_buffer == NULL)
-    return FALSE;
+      /* Different compression schemes.  Just move the compressed section
+        contents to the right position. */
+      if (orig_compression_header_size == 0)
+       {
+         /* Convert it from .zdebug* section.  Get the uncompressed
+            size first.  */
+         zlib_size = uncompressed_size;
+         compressed_size = zlib_size + compression_header_size;
+         uncompressed_size = bfd_getb64 (uncompressed_buffer + 4);
+       }
+      else
+       {
+         /* Convert it to .zdebug* section. */
+         zlib_size = uncompressed_size - orig_compression_header_size;
+         compressed_size = zlib_size;
+       }
+    }
+  else
+    compressed_size = compressBound (uncompressed_size) + 12;
 
-  if (compress ((Bytef*) compressed_buffer + 12,
-               &compressed_size,
-               (const Bytef*) uncompressed_buffer,
-               uncompressed_size) != Z_OK)
+  /* When converting from .zdebug* section, uncompress if it leads to
+     smaller size.  */
+  if (compressed
+      && orig_compression_header_size == 0
+      && compressed_size > uncompressed_size)
     {
-      free (compressed_buffer);
-      bfd_set_error (bfd_error_bad_value);
-      return FALSE;
+      decompress = TRUE;
+      buffer_size = uncompressed_size;
     }
+  else
+    {
+      decompress = FALSE;
+      buffer_size = compressed_size + compression_header_size;
+    }
+  buffer = (bfd_byte *) bfd_malloc (buffer_size);
+  if (buffer == NULL)
+    return 0;
 
-  compressed_size += 12;
-
-  /* PR binutils/18087: If compression didn't make the section smaller,
-     just keep it uncompressed.  */
-  if (compressed_size < uncompressed_size)
+  if (compressed)
     {
-      /* Write the zlib header.  In this case, it should be "ZLIB" followed
-        by the uncompressed section size, 8 bytes in big-endian order.  */
-      memcpy (compressed_buffer, "ZLIB", 4);
-      bfd_putb64 (uncompressed_size, compressed_buffer + 4);
-      free (uncompressed_buffer);
-      sec->contents = compressed_buffer;
-      sec->size = compressed_size;
-      sec->compress_status = COMPRESS_SECTION_DONE;
+      sec->size = uncompressed_size;
+      if (decompress)
+       {
+         if (!decompress_contents (uncompressed_buffer, zlib_size,
+                                   buffer, uncompressed_size))
+           {
+             bfd_set_error (bfd_error_bad_value);
+             free (buffer);
+             return 0;
+           }
+         free (uncompressed_buffer);
+         sec->contents = buffer;
+         sec->compress_status = COMPRESS_SECTION_DONE;
+         return uncompressed_size;
+       }
+      else
+       {
+         bfd_update_compression_header (abfd, buffer, sec);
+         memmove (buffer + compression_header_size,
+                  uncompressed_buffer + orig_compression_header_size,
+                  zlib_size);
+       }
     }
   else
     {
-      sec->contents = uncompressed_buffer;
-      sec->compress_status = COMPRESS_SECTION_NONE;
+      bfd_size_type size = uncompressed_size;
+      int header_size = 12 + compression_header_size;
+      if (compress ((Bytef*) buffer + header_size,
+                   &compressed_size,
+                   (const Bytef*) uncompressed_buffer,
+                   uncompressed_size) != Z_OK)
+       {
+         free (buffer);
+         bfd_set_error (bfd_error_bad_value);
+         return 0;
+       }
+
+      compressed_size += header_size;
+      /* PR binutils/18087: If compression didn't make the section smaller,
+        just keep it uncompressed.  */
+      if (compressed_size < uncompressed_size)
+       {
+         bfd_update_compression_header (abfd, buffer, sec);
+
+         /* Write the zlib header.  In this case, it should be "ZLIB"
+            followed by the uncompressed section size, 8 bytes in
+            big-endian order.  */
+         memcpy (buffer + compression_header_size, "ZLIB", 4);
+         bfd_putb64 (size, buffer + compression_header_size + 4);
+       }
+      else
+       {
+         sec->contents = uncompressed_buffer;
+         sec->compress_status = COMPRESS_SECTION_NONE;
+         return uncompressed_size;
+       }
     }
 
-  return TRUE;
+  free (uncompressed_buffer);
+  sec->contents = buffer;
+  sec->size = compressed_size;
+  sec->compress_status = COMPRESS_SECTION_DONE;
+
+  return uncompressed_size;
 }
 
 /*
@@ -143,6 +226,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
   bfd_size_type save_size;
   bfd_size_type save_rawsize;
   bfd_byte *compressed_buffer;
+  unsigned int compression_header_size;
 
   if (abfd->direction != write_direction && sec->rawsize != 0)
     sz = sec->rawsize;
@@ -200,7 +284,9 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
       if (p == NULL)
        goto fail_compressed;
 
-      if (!decompress_contents (compressed_buffer, sec->compressed_size, p, sz))
+      compression_header_size = bfd_get_compression_header_size (abfd, sec);
+      if (!decompress_contents (compressed_buffer + compression_header_size,
+                               sec->compressed_size, p, sz))
        {
          bfd_set_error (bfd_error_bad_value);
          if (p != *ptr)
@@ -256,50 +342,96 @@ bfd_cache_section_contents (asection *sec, void *contents)
   sec->flags |= SEC_IN_MEMORY;
 }
 
-
 /*
 FUNCTION
-       bfd_is_section_compressed
+       bfd_is_section_compressed_with_header
 
 SYNOPSIS
-       bfd_boolean bfd_is_section_compressed
-         (bfd *abfd, asection *section);
+       bfd_boolean bfd_is_section_compressed_with_header
+         (bfd *abfd, asection *section,
+         int *compression_header_size_p);
 
 DESCRIPTION
-       Return @code{TRUE} if @var{section} is compressed.
+       Return @code{TRUE} if @var{section} is compressed.  Compression
+       header size is returned in @var{compression_header_size_p}.  If
+       compression is unsupported, compression header size is returned
+       with -1.
 */
 
 bfd_boolean
-bfd_is_section_compressed (bfd *abfd, sec_ptr sec)
+bfd_is_section_compressed_with_header (bfd *abfd, sec_ptr sec,
+                                      int *compression_header_size_p)
 {
-  bfd_byte compressed_buffer [12];
+  bfd_byte header[MAX_COMPRESSION_HEADER_SIZE + 12];
+  int compression_header_size;
+  int header_size = 12;
   unsigned int saved = sec->compress_status;
   bfd_boolean compressed;
 
+  compression_header_size = bfd_get_compression_header_size (abfd, sec);
+  if (compression_header_size > MAX_COMPRESSION_HEADER_SIZE)
+    abort ();
+  header_size += compression_header_size;
+
   /* Don't decompress the section.  */
   sec->compress_status = COMPRESS_SECTION_NONE;
 
   /* Read the zlib header.  In this case, it should be "ZLIB" followed
      by the uncompressed section size, 8 bytes in big-endian order.  */
-  compressed = (bfd_get_section_contents (abfd, sec, compressed_buffer, 0, 12)
-               && CONST_STRNEQ ((char*) compressed_buffer, "ZLIB"));
+  compressed = bfd_get_section_contents (abfd, sec, header, 0,
+                                        header_size)
+               && CONST_STRNEQ ((char*) header + compression_header_size,
+                                "ZLIB");
 
-  /* Check for the pathalogical case of a debug string section that
-     contains the string ZLIB.... as the first entry.  We assume that
-     no uncompressed .debug_str section would ever be big enough to
-     have the first byte of its (big-endian) size be non-zero.  */
-  if (compressed
-      && strcmp (sec->name, ".debug_str") == 0
-      && ISPRINT (compressed_buffer[4]))
-    compressed = FALSE;
+  if (compressed)
+    {
+      if (compression_header_size != 0)
+       {
+         bfd_size_type uncompressed_size
+           = bfd_getb64 ((bfd_byte *) header
+                         + compression_header_size + 4);
+         if (!bfd_check_compression_header (abfd, header, sec,
+                                            uncompressed_size))
+           compression_header_size = -1;
+       }
+      /* Check for the pathalogical case of a debug string section that
+        contains the string ZLIB.... as the first entry.  We assume that
+        no uncompressed .debug_str section would ever be big enough to
+        have the first byte of its (big-endian) size be non-zero.  */
+      else if (strcmp (sec->name, ".debug_str") == 0
+              && ISPRINT (header[compression_header_size + 4]))
+       compressed = FALSE;
+    }
 
   /* Restore compress_status.  */
   sec->compress_status = saved;
+  *compression_header_size_p = compression_header_size;
   return compressed;
 }
 
 /*
 FUNCTION
+       bfd_is_section_compressed
+
+SYNOPSIS
+       bfd_boolean bfd_is_section_compressed
+         (bfd *abfd, asection *section);
+
+DESCRIPTION
+       Return @code{TRUE} if @var{section} is compressed.
+*/
+
+bfd_boolean
+bfd_is_section_compressed (bfd *abfd, sec_ptr sec)
+{
+  int compression_header_size;
+  return (bfd_is_section_compressed_with_header (abfd, sec,
+                                                &compression_header_size)
+         && compression_header_size >= 0);
+}
+
+/*
+FUNCTION
        bfd_init_section_decompress_status
 
 SYNOPSIS
@@ -319,13 +451,20 @@ DESCRIPTION
 bfd_boolean
 bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
 {
-  bfd_byte compressed_buffer [12];
+  bfd_byte header[MAX_COMPRESSION_HEADER_SIZE + 12];
+  int compression_header_size;
+  int header_size = 12;
   bfd_size_type uncompressed_size;
 
+  compression_header_size = bfd_get_compression_header_size (abfd, sec);
+  if (compression_header_size > MAX_COMPRESSION_HEADER_SIZE)
+    abort ();
+  header_size += compression_header_size;
+
   if (sec->rawsize != 0
       || sec->contents != NULL
       || sec->compress_status != COMPRESS_SECTION_NONE
-      || !bfd_get_section_contents (abfd, sec, compressed_buffer, 0, 12))
+      || !bfd_get_section_contents (abfd, sec, header, 0, header_size))
     {
       bfd_set_error (bfd_error_invalid_operation);
       return FALSE;
@@ -333,13 +472,20 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
 
   /* Read the zlib header.  In this case, it should be "ZLIB" followed
      by the uncompressed section size, 8 bytes in big-endian order.  */
-  if (! CONST_STRNEQ ((char*) compressed_buffer, "ZLIB"))
+  if (! CONST_STRNEQ ((char*) header + compression_header_size, "ZLIB"))
     {
       bfd_set_error (bfd_error_wrong_format);
       return FALSE;
     }
 
-  uncompressed_size = bfd_getb64 (compressed_buffer + 4);
+  uncompressed_size = bfd_getb64 (header + compression_header_size + 4);
+  if (compression_header_size != 0
+      && !bfd_check_compression_header (abfd, header, sec,
+                                       uncompressed_size))
+    {
+      bfd_set_error (bfd_error_wrong_format);
+      return FALSE;
+    }
   sec->compressed_size = sec->size;
   sec->size = uncompressed_size;
   sec->compress_status = DECOMPRESS_SECTION_SIZED;
@@ -389,9 +535,12 @@ bfd_init_section_compress_status (bfd *abfd, sec_ptr sec)
                                 0, uncompressed_size))
     ret = FALSE;
   else
-    ret = bfd_compress_section_contents (abfd, sec,
-                                        uncompressed_buffer,
-                                        uncompressed_size);
+    {
+      uncompressed_size = bfd_compress_section_contents (abfd, sec,
+                                                        uncompressed_buffer,
+                                                        uncompressed_size);
+      ret = uncompressed_size != 0;
+    }
 
   return ret;
 }
index 5fad4f1..a031b9e 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1042,26 +1042,35 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
     {
       enum { nothing, compress, decompress } action = nothing;
       char *new_name;
+      int compression_header_size;
+      bfd_boolean compressed
+       = bfd_is_section_compressed_with_header (abfd, newsect,
+                                                &compression_header_size);
 
-      if (bfd_is_section_compressed (abfd, newsect))
+      if (compressed)
        {
          /* Compressed section.  Check if we should decompress.  */
          if ((abfd->flags & BFD_DECOMPRESS))
            action = decompress;
        }
-      else
+
+      /* Compress the uncompressed section or convert from/to .zdebug*
+        section.  Check if we should compress.  */
+      if (action == nothing)
        {
-         /* Normal section.  Check if we should compress.  */
-         if ((abfd->flags & BFD_COMPRESS) && newsect->size != 0)
+         if (newsect->size != 0
+             && (abfd->flags & BFD_COMPRESS)
+             && compression_header_size >= 0
+             && (!compressed
+                 || ((compression_header_size > 0)
+                     != ((abfd->flags & BFD_COMPRESS_GABI) != 0))))
            action = compress;
+         else
+           return TRUE;
        }
 
-      new_name = NULL;
-      switch (action)
+      if (action == compress)
        {
-       case nothing:
-         break;
-       case compress:
          if (!bfd_init_section_compress_status (abfd, newsect))
            {
              (*_bfd_error_handler)
@@ -1069,25 +1078,9 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
                 abfd, name);
              return FALSE;
            }
-         /* PR binutils/18087: Compression does not always make a section
-            smaller.  So only rename the section when compression has
-            actually taken place.  */
-         if (newsect->compress_status == COMPRESS_SECTION_DONE)
-           {
-             if (name[1] != 'z')
-               {
-                 unsigned int len = strlen (name);
-
-                 new_name = bfd_alloc (abfd, len + 2);
-                 if (new_name == NULL)
-                   return FALSE;
-                 new_name[0] = '.';
-                 new_name[1] = 'z';
-                 memcpy (new_name + 2, name + 1, len);
-               }
-           }
-         break;
-       case decompress:
+       }
+      else
+       {
          if (!bfd_init_section_decompress_status (abfd, newsect))
            {
              (*_bfd_error_handler)
@@ -1095,6 +1088,13 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
                 abfd, name);
              return FALSE;
            }
+       }
+
+      new_name = NULL;
+      if (action == decompress
+          || (action == compress
+              && (abfd->flags & BFD_COMPRESS_GABI) != 0))
+       {
          if (name[1] == 'z')
            {
              unsigned int len = strlen (name);
@@ -1105,7 +1105,24 @@ _bfd_elf_make_section_from_shdr (bfd *abfd,
              new_name[0] = '.';
              memcpy (new_name + 1, name + 2, len - 1);
            }
-         break;
+       }
+      else if (action == compress
+              && newsect->compress_status == COMPRESS_SECTION_DONE)
+       {
+         /* PR binutils/18087: Compression does not always make a section
+            smaller.  So only rename the section when compression has
+            actually taken place.  */
+         if (name[1] != 'z')
+           {
+             unsigned int len = strlen (name);
+
+             new_name = bfd_alloc (abfd, len + 2);
+             if (new_name == NULL)
+               return FALSE;
+             new_name[0] = '.';
+             new_name[1] = 'z';
+             memcpy (new_name + 2, name + 1, len);
+           }
        }
       if (new_name != NULL)
        bfd_rename_section (abfd, newsect, new_name);
index bbc00b9..7d5b1a0 100644 (file)
@@ -1,5 +1,18 @@
 2015-04-08  H.J. Lu  <hongjiu.lu@intel.com>
 
+       * objcopy.c (do_debug_sections): Add compress_zlib,
+       compress_gnu_zlib and compress_gabi_zlib.
+       (copy_options): Use optional_argument on compress-debug-sections.
+       (copy_usage): Update --compress-debug-sections.
+       (copy_file): Handle compress_zlib, compress_gnu_zlib and
+       compress_gabi_zlib.
+       (copy_main): Handle
+       --compress-debug-sections={none|zlib|zlib-gnu|zlib-gabi}.
+       * doc/binutils.texi: Document
+       --compress-debug-sections={none|zlib|zlib-gnu|zlib-gabi}.
+
+2015-04-08  H.J. Lu  <hongjiu.lu@intel.com>
+
        * objcopy.c (copy_usage): Replace "--interleave [<number>]" with
        --interleave[=<number>].
 
index e0527aa..dbf44c9 100644 (file)
@@ -1849,6 +1849,19 @@ renamed to begin with @samp{.zdebug} instead of @samp{.debug}.  Note -
 if compression would actually make a section @emph{larger} then it is
 not compressed or renamed.
 
+@item --compress-debug-sections=none
+@itemx --compress-debug-sections=zlib
+@itemx --compress-debug-sections=zlib-gnu
+@itemx --compress-debug-sections=zlib-gabi
+For ELF files, these options control how DWARF debug sections are
+compressed.  @option{--compress-debug-sections=none} is equivalent
+to @option{--nocompress-debug-sections}.
+@option{--compress-debug-sections=zlib} and
+@option{--compress-debug-sections=zlib-gnu} are equivalent to
+@option{--compress-debug-sections}.
+@option{--compress-debug-sections=zlib-gabi} compresses
+DWARF debug sections with SHF_COMPRESSED from the ELF ABI.
+
 @item --decompress-debug-sections
 Decompress DWARF debug sections using zlib.  The original section
 names of the compressed sections are restored.
index a21006a..a0452c9 100644 (file)
@@ -204,6 +204,9 @@ static enum
 {
   nothing,
   compress,
+  compress_zlib,
+  compress_gnu_zlib,
+  compress_gabi_zlib,
   decompress
 } do_debug_sections = nothing;
 
@@ -380,7 +383,7 @@ static struct option copy_options[] =
   {"change-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_VMA},
   {"change-start", required_argument, 0, OPTION_CHANGE_START},
   {"change-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS},
-  {"compress-debug-sections", no_argument, 0, OPTION_COMPRESS_DEBUG_SECTIONS},
+  {"compress-debug-sections", optional_argument, 0, OPTION_COMPRESS_DEBUG_SECTIONS},
   {"debugging", no_argument, 0, OPTION_DEBUGGING},
   {"decompress-debug-sections", no_argument, 0, OPTION_DECOMPRESS_DEBUG_SECTIONS},
   {"disable-deterministic-archives", no_argument, 0, 'U'},
@@ -601,7 +604,8 @@ copy_usage (FILE *stream, int exit_status)
                                    <commit>\n\
      --subsystem <name>[:<version>]\n\
                                    Set PE subsystem to <name> [& <version>]\n\
-     --compress-debug-sections     Compress DWARF debug sections using zlib\n\
+     --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
+                                   Compress DWARF debug sections using zlib\n\
      --decompress-debug-sections   Decompress DWARF debug sections using zlib\n\
   -v --verbose                     List all object files modified\n\
   @<file>                          Read options from <file>\n\
@@ -2588,7 +2592,18 @@ copy_file (const char *input_filename, const char *output_filename,
   switch (do_debug_sections)
     {
     case compress:
+    case compress_zlib:
+    case compress_gnu_zlib:
+    case compress_gabi_zlib:
       ibfd->flags |= BFD_COMPRESS;
+      if (do_debug_sections != compress)
+       {
+         if (ibfd->xvec->flavour != bfd_target_elf_flavour)
+           fatal (_("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi] is unsupported for `%s'"),
+                  bfd_get_target (ibfd));
+         if (do_debug_sections == compress_gabi_zlib)
+           ibfd->flags |= BFD_COMPRESS_GABI;
+       }
       break;
     case decompress:
       ibfd->flags |= BFD_DECOMPRESS;
@@ -3998,7 +4013,22 @@ copy_main (int argc, char *argv[])
          break;
 
        case OPTION_COMPRESS_DEBUG_SECTIONS:
-         do_debug_sections = compress;
+         if (optarg)
+           {
+             if (strcasecmp (optarg, "none") == 0)
+               do_debug_sections = decompress;
+             else if (strcasecmp (optarg, "zlib") == 0)
+               do_debug_sections = compress_zlib;
+             else if (strcasecmp (optarg, "zlib-gnu") == 0)
+               do_debug_sections = compress_gnu_zlib;
+             else if (strcasecmp (optarg, "zlib-gabi") == 0)
+               do_debug_sections = compress_gabi_zlib;
+             else
+               fatal (_("unrecognized --compress-debug-sections type `%s'"),
+                      optarg);
+           }
+         else
+           do_debug_sections = compress;
          break;
 
        case OPTION_DEBUGGING:
index ece81a6..b97f412 100644 (file)
@@ -1,3 +1,11 @@
+2015-04-08  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * compress.exp: Add tests for
+       --compress-debug-sections={none|zlib|zlib-gnu|zlib-gabi}.
+       * binutils-all/dw2-3.rS: New file.
+       * binutils-all/dw2-3.rt: Likewise.
+       * binutils-all/libdw2-compressedgabi.out: Likewise.
+
 2015-04-06  H.J. Lu  <hongjiu.lu@intel.com>
 
        * binutils-all/compress.exp: Remove is_zlib_supported check.
index 36b2a26..4d3b71c 100644 (file)
@@ -217,3 +217,357 @@ if ![is_remote host] {
 }
 
 run_dump_test "debug_str"
+
+if { ![binutils_assemble_flags $srcdir/$subdir/dw2-1.S ${compressedfile}gabi.o --compress-debug-sections=zlib-gabi] } then {
+    fail "compressed debug sections with zlib-gabi"
+    return
+}
+
+if { ![binutils_assemble_flags $srcdir/$subdir/dw2-1.S ${compressedfile}gnu.o --compress-debug-sections=zlib-gnu] } then {
+    fail "compressed debug sections with zlib-gnu"
+    return
+}
+
+set src1 ${compressedfile}gnu.o
+set src2 ${compressedfile}.o
+set status [remote_exec build cmp "${src1} ${src2}"]
+set exec_output [lindex $status 1]
+set exec_output [prune_warnings $exec_output]
+if ![string match "" $exec_output] then {
+    fail "compressed debug sections with zlib-gnu"
+    return
+}
+
+if { ![binutils_assemble_flags $srcdir/$subdir/dw2-2.S ${compressedfile2}gabi.o --compress-debug-sections=zlib-gabi] } then {
+    fail "compressed debug sections with zlib-gabi"
+    return
+}
+
+if { ![binutils_assemble_flags $srcdir/$subdir/dw2-2.S ${compressedfile2}gnu.o --compress-debug-sections=zlib-gnu] } then {
+    fail "compressed debug sections with zlib-gnu"
+    return
+}
+
+set src1 ${compressedfile2}gnu.o
+set src2 ${compressedfile2}.o
+set status [remote_exec build cmp "${src1} ${src2}"]
+set exec_output [lindex $status 1]
+set exec_output [prune_warnings $exec_output]
+if ![string match "" $exec_output] then {
+    fail "compressed debug sections with zlib-gnu"
+    return
+}
+
+if { ![binutils_assemble_flags $srcdir/$subdir/dw2-3.S ${compressedfile3}gabi.o --compress-debug-sections=zlib-gabi] } then {
+    fail "compressed debug sections with zlib-gabi"
+    return
+}
+
+set testname "readelf -t zlib-gabi compress debug sections"
+set got [remote_exec host "$READELF -t --wide ${compressedfile3}gabi.o" "" "/dev/null" "tmpdir/dw2-3.rt"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+    fail "$testname (reason: unexpected output)"
+    send_log "$got\n"
+}
+if { [regexp_diff tmpdir/dw2-3.rt $srcdir/$subdir/dw2-3.rt] } then {
+    fail "$testname"
+} else {
+    pass "$testname"
+}
+
+set testname "readelf -S zlib-gabi compress debug sections"
+set got [remote_exec host "$READELF -S --wide ${compressedfile3}gabi.o" "" "/dev/null" "tmpdir/dw2-3.rS"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+    fail "$testname (reason: unexpected output)"
+    send_log "$got\n"
+}
+if { [regexp_diff tmpdir/dw2-3.rS $srcdir/$subdir/dw2-3.rS] } then {
+    fail "$testname"
+} else {
+    pass "$testname"
+}
+
+if { ![binutils_assemble_flags $srcdir/$subdir/dw2-3.S ${compressedfile3}gnu.o --compress-debug-sections=zlib-gnu] } then {
+    fail "compressed debug sections with zlib-gnu"
+    return
+}
+
+set src1 ${compressedfile3}gnu.o
+set src2 ${compressedfile3}.o
+set status [remote_exec build cmp "${src1} ${src2}"]
+set exec_output [lindex $status 1]
+set exec_output [prune_warnings $exec_output]
+if ![string match "" $exec_output] then {
+    fail "compressed debug sections with zlib-gnu"
+    return
+}
+
+remote_file host delete ${libfile}gabi.a
+set got [binutils_run $AR "rc ${libfile}gabi.a ${compressedfile}gabi.o ${compressedfile2}gabi.o ${compressedfile3}gabi.o"]
+if ![string match "" $got] then {
+    fail "compressed debug sections"
+    return
+}
+
+set testname "objcopy compress debug sections with zlib-gabi"
+set got [binutils_run $OBJCOPY "--compress-debug-sections=zlib-gabi ${testfile}.o ${copyfile}gabi.o"]
+if ![string match "" $got] then {
+    fail "objcopy ($testname)"
+    return
+}
+send_log "cmp ${compressedfile}gabi.o ${copyfile}gabi.o\n"
+verbose "cmp ${compressedfile}gabi.o ${copyfile}gabi.o"
+set src1 ${compressedfile}gabi.o
+set src2 ${copyfile}gabi.o
+set status [remote_exec build cmp "${src1} ${src2}"]
+set exec_output [lindex $status 1]
+set exec_output [prune_warnings $exec_output]
+if ![string match "" $exec_output] then {
+    send_log "$exec_output\n"
+    verbose "$exec_output" 1
+    fail "objcopy ($testname)"
+} else {
+    pass "objcopy ($testname)"
+}
+
+set testname "objcopy decompress compressed debug sections with zlib-gabi"
+set got [binutils_run $OBJCOPY "--decompress-debug-sections ${compressedfile}gabi.o ${copyfile}gabi.o"]
+if ![string match "" $got] then {
+    fail "objcopy ($testname)"
+    return
+}
+send_log "cmp ${testfile}.o ${copyfile}gabi.o\n"
+verbose "cmp ${testfile}.o ${copyfile}gabi.o"
+set src1 ${testfile}.o
+set src2 ${copyfile}gabi.o
+set status [remote_exec build cmp "${src1} ${src2}"]
+set exec_output [lindex $status 1]
+set exec_output [prune_warnings $exec_output]
+if ![string match "" $exec_output] then {
+    send_log "$exec_output\n"
+    verbose "$exec_output" 1
+    fail "objcopy ($testname)"
+} else {
+    pass "objcopy ($testname)"
+}
+
+set testname "objcopy zlib-gnu compress debug sections with zlib-gabi"
+set got [binutils_run $OBJCOPY "--compress-debug-sections=zlib-gabi ${compressedfile}.o ${copyfile}gabi.o"]
+if ![string match "" $got] then {
+    fail "objcopy ($testname)"
+    return
+}
+send_log "cmp ${compressedfile}gabi.o ${copyfile}gabi.o\n"
+verbose "cmp ${compressedfile}gabi.o ${copyfile}gabi.o"
+set src1 ${compressedfile}gabi.o
+set src2 ${copyfile}gabi.o
+set status [remote_exec build cmp "${src1} ${src2}"]
+set exec_output [lindex $status 1]
+set exec_output [prune_warnings $exec_output]
+if ![string match "" $exec_output] then {
+    send_log "$exec_output\n"
+    verbose "$exec_output" 1
+    fail "objcopy ($testname)"
+} else {
+    pass "objcopy ($testname)"
+}
+
+set testname "objcopy zlib-gabi compress debug sections with zlib-gnu"
+set got [binutils_run $OBJCOPY "--compress-debug-sections=zlib-gnu ${compressedfile}gabi.o ${copyfile}gnu.o"]
+if ![string match "" $got] then {
+    fail "objcopy ($testname)"
+    return
+}
+send_log "cmp ${compressedfile}gnu.o ${copyfile}gnu.o\n"
+verbose "cmp ${compressedfile}gnu.o ${copyfile}gnu.o"
+set src1 ${compressedfile}gnu.o
+set src2 ${copyfile}gnu.o
+set status [remote_exec build cmp "${src1} ${src2}"]
+set exec_output [lindex $status 1]
+set exec_output [prune_warnings $exec_output]
+if ![string match "" $exec_output] then {
+    send_log "$exec_output\n"
+    verbose "$exec_output" 1
+    fail "objcopy ($testname)"
+} else {
+    pass "objcopy ($testname)"
+}
+
+set testname "objcopy compress debug sections 3 with zlib-gabi"
+set got [binutils_run $OBJCOPY "--compress-debug-sections=zlib-gabi ${testfile3}.o ${copyfile}gabi.o"]
+if ![string match "" $got] then {
+    fail "objcopy ($testname)"
+    return
+}
+send_log "cmp ${compressedfile3}gabi.o ${copyfile}gabi.o\n"
+verbose "cmp ${compressedfile3}gabi.o ${copyfile}gabi.o"
+set src1 ${compressedfile3}gabi.o
+set src2 ${copyfile}gabi.o
+set status [remote_exec build cmp "${src1} ${src2}"]
+set exec_output [lindex $status 1]
+set exec_output [prune_warnings $exec_output]
+if ![string match "" $exec_output] then {
+    send_log "$exec_output\n"
+    verbose "$exec_output" 1
+    fail "objcopy ($testname)"
+} else {
+    pass "objcopy ($testname)"
+}
+
+set testname "objcopy decompress compressed debug sections 3 with zlib-gabi"
+set got [binutils_run $OBJCOPY "--decompress-debug-sections ${compressedfile3}gabi.o ${copyfile}gabi.o"]
+if ![string match "" $got] then {
+    fail "objcopy ($testname)"
+    return
+}
+send_log "cmp ${testfile3}.o ${copyfile}gabi.o\n"
+verbose "cmp ${testfile3}.o ${copyfile}gabi.o"
+set src1 ${testfile3}.o
+set src2 ${copyfile}gabi.o
+set status [remote_exec build cmp "${src1} ${src2}"]
+set exec_output [lindex $status 1]
+set exec_output [prune_warnings $exec_output]
+if ![string match "" $exec_output] then {
+    send_log "$exec_output\n"
+    verbose "$exec_output" 1
+    fail "objcopy ($testname)"
+} else {
+    pass "objcopy ($testname)"
+}
+
+set testname "objcopy zlib-gnu compress debug sections 3 with zlib-gabi"
+set got [binutils_run $OBJCOPY "--compress-debug-sections=zlib-gabi ${compressedfile3}.o ${copyfile}gabi.o"]
+if ![string match "" $got] then {
+    fail "objcopy ($testname)"
+    return
+}
+send_log "cmp ${compressedfile3}gabi.o ${copyfile}gabi.o\n"
+verbose "cmp ${compressedfile3}gabi.o ${copyfile}gabi.o"
+set src1 ${compressedfile3}gabi.o
+set src2 ${copyfile}gabi.o
+set status [remote_exec build cmp "${src1} ${src2}"]
+set exec_output [lindex $status 1]
+set exec_output [prune_warnings $exec_output]
+if ![string match "" $exec_output] then {
+    send_log "$exec_output\n"
+    verbose "$exec_output" 1
+    fail "objcopy ($testname)"
+} else {
+    pass "objcopy ($testname)"
+}
+
+set testname "objcopy zlib-gabi compress debug sections 3 with zlib-gnu"
+set got [binutils_run $OBJCOPY "--compress-debug-sections=zlib-gnu ${compressedfile3}gabi.o ${copyfile}gnu.o"]
+if ![string match "" $got] then {
+    fail "objcopy ($testname)"
+    return
+}
+send_log "cmp ${compressedfile3}gnu.o ${copyfile}gnu.o\n"
+verbose "cmp ${compressedfile3}gnu.o ${copyfile}gnu.o"
+set src1 ${compressedfile3}gnu.o
+set src2 ${copyfile}gnu.o
+set status [remote_exec build cmp "${src1} ${src2}"]
+set exec_output [lindex $status 1]
+set exec_output [prune_warnings $exec_output]
+if ![string match "" $exec_output] then {
+    send_log "$exec_output\n"
+    verbose "$exec_output" 1
+    fail "objcopy ($testname)"
+} else {
+    pass "objcopy ($testname)"
+}
+
+set testname "objcopy zlib-gnu compress debug sections 3"
+set got [binutils_run $OBJCOPY "${compressedfile3}gnu.o ${copyfile}gnu.o"]
+if ![string match "" $got] then {
+    fail "objcopy ($testname)"
+    return
+}
+send_log "cmp ${compressedfile3}gnu.o ${copyfile}gnu.o\n"
+verbose "cmp ${compressedfile3}gnu.o ${copyfile}gnu.o"
+set src1 ${compressedfile3}gnu.o
+set src2 ${copyfile}gnu.o
+set status [remote_exec build cmp "${src1} ${src2}"]
+set exec_output [lindex $status 1]
+set exec_output [prune_warnings $exec_output]
+if ![string match "" $exec_output] then {
+    send_log "$exec_output\n"
+    verbose "$exec_output" 1
+    fail "objcopy ($testname)"
+} else {
+    pass "objcopy ($testname)"
+}
+
+set testname "objcopy zlib-gnu compress debug sections 3"
+set got [binutils_run $OBJCOPY "${compressedfile3}gnu.o ${copyfile}gnu.o"]
+if ![string match "" $got] then {
+    fail "objcopy ($testname)"
+    return
+}
+send_log "cmp ${compressedfile3}gnu.o ${copyfile}gnu.o\n"
+verbose "cmp ${compressedfile3}gnu.o ${copyfile}gnu.o"
+set src1 ${compressedfile3}gnu.o
+set src2 ${copyfile}gnu.o
+set status [remote_exec build cmp "${src1} ${src2}"]
+set exec_output [lindex $status 1]
+set exec_output [prune_warnings $exec_output]
+if ![string match "" $exec_output] then {
+    send_log "$exec_output\n"
+    verbose "$exec_output" 1
+    fail "objcopy ($testname)"
+} else {
+    pass "objcopy ($testname)"
+}
+
+set testname "objcopy decompress debug sections in archive with zlib-gabi"
+set got [binutils_run $OBJCOPY "--decompress-debug-sections ${libfile}gabi.a ${copyfile}gabi.a"]
+if ![string match "" $got] then {
+    fail "objcopy ($testname)"
+} else {
+    set got [remote_exec host "$READELF -S --wide ${copyfile}gabi.a" "" "/dev/null" "tmpdir/libdw2.out"]
+
+    if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+       fail "$testname (reason: unexpected output)"
+       send_log $got
+       send_log "\n"
+    }
+
+    if { [regexp_diff tmpdir/libdw2.out $srcdir/$subdir/libdw2.out] } then {
+       fail "$testname"
+    } else {
+       pass "$testname"
+    }
+}
+
+set testname "objcopy compress debug sections in archive with zlib-gabi"
+set got [binutils_run $OBJCOPY "--compress-debug-sections=zlib-gabi ${copyfile}gabi.a ${compressedcopyfile}gabi.a"]
+if ![string match "" $got] then {
+    fail "objcopy ($testname)"
+} else {
+    set got [remote_exec host "$OBJDUMP -s -j .debug_info
+    ${compressedcopyfile}gabi.a" "" "/dev/null" "tmpdir/libdw2-compressedgabi.out"]
+
+    if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+       fail "$testname (reason: unexpected output)"
+       send_log $got
+       send_log "\n"
+    }
+
+    if { [regexp_diff tmpdir/libdw2-compressedgabi.out $srcdir/$subdir/libdw2-compressedgabi.out] } then {
+       fail "$testname"
+    } else {
+       pass "$testname"
+    }
+}
+
+set testname "objdump compress debug sections 3 with zlib-gabi"
+set got [remote_exec host "$OBJDUMP -W ${compressedfile3}gabi.o" "" "/dev/null" "objdump.out"]
+if { [lindex $got 0] != 0 || ![string match "" [lindex $got 1]] } then {
+    fail "$testname"
+    send_log "$got\n"
+}
+if { [regexp_diff objdump.out $srcdir/$subdir/dw2-3.W] } then {
+    fail "$testname"
+} else {
+    pass "$testname"
+}
diff --git a/binutils/testsuite/binutils-all/dw2-3.rS b/binutils/testsuite/binutils-all/dw2-3.rS
new file mode 100644 (file)
index 0000000..f1637e9
--- /dev/null
@@ -0,0 +1,3 @@
+#...
+ +\[[ 0-9]+\] .debug_info +(PROGBITS|MIPS_DWARF) +0+ +[0-9a-f]+ +[0-9a-f]+ [0-9a-f]+ +C +0 +0 +1
+#pass
diff --git a/binutils/testsuite/binutils-all/dw2-3.rt b/binutils/testsuite/binutils-all/dw2-3.rt
new file mode 100644 (file)
index 0000000..f59cbaa
--- /dev/null
@@ -0,0 +1,6 @@
+#...
+ +\[[ 0-9]+\] .debug_info
+ +(PROGBITS|MIPS_DWARF) +0+ +[0-9a-f]+ +[0-9a-f]+ +[0-9a-f]+ +0 +0 +1
+ +\[0+800\]: COMPRESSED
+ +ZLIB, 0+9d, 1
+#pass
diff --git a/binutils/testsuite/binutils-all/libdw2-compressedgabi.out b/binutils/testsuite/binutils-all/libdw2-compressedgabi.out
new file mode 100644 (file)
index 0000000..3d395e4
--- /dev/null
@@ -0,0 +1,3 @@
+#...
+ .*ZLIB.*
+#pass
index 6f9118d..7ff56c1 100644 (file)
@@ -1,3 +1,21 @@
+2015-04-08  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * as.c (show_usage): Update --compress-debug-sections.
+       (std_longopts): Use optional_argument on compress-debug-sections.
+       (parse_args): Handle
+       --compress-debug-sections={none|zlib|zlib-gnu|zlib-gabi}.
+       * as.h (compressed_debug_section_type): New.
+       (flag_compress_debug): Change type to compressed_debug_section_type.
+       --compress-debug-sections={none|zlib|zlib-gnu|zlib-gabi}.
+       * write.c (compress_debug): Set BFD_COMPRESS_GABI for
+       --compress-debug-sections=zlib-gabi.  Call
+       bfd_get_compression_header_size to get compression header size.
+       Don't rename section name for --compress-debug-sections=zlib-gabi.
+       * config/tc-i386.c (compressed_debug_section_type): Set to
+       COMPRESS_DEBUG_ZLIB.
+       * doc/as.texinfo: Document
+       --compress-debug-sections={none|zlib|zlib-gnu|zlib-gabi}.
+
 2015-04-07  Renlin Li  <renlin.li@arm.com>
 
        * config/tc-aarch64.c (mapping_state): Use subseg_text_p.
index a670d3e..2a8923f 100644 (file)
--- a/gas/as.c
+++ b/gas/as.c
@@ -246,7 +246,7 @@ Options:\n\
   fprintf (stream, _("\
   --alternate             initially turn on alternate macro syntax\n"));
   fprintf (stream, _("\
-  --compress-debug-sections\n\
+  --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
                           compress DWARF debug sections using zlib\n"));
   fprintf (stream, _("\
   --nocompress-debug-sections\n\
@@ -471,7 +471,7 @@ parse_args (int * pargc, char *** pargv)
     ,{"a", optional_argument, NULL, 'a'}
     /* Handle -al=<FILE>.  */
     ,{"al", optional_argument, NULL, OPTION_AL}
-    ,{"compress-debug-sections", no_argument, NULL, OPTION_COMPRESS_DEBUG}
+    ,{"compress-debug-sections", optional_argument, NULL, OPTION_COMPRESS_DEBUG}
     ,{"nocompress-debug-sections", no_argument, NULL, OPTION_NOCOMPRESS_DEBUG}
     ,{"debug-prefix-map", required_argument, NULL, OPTION_DEBUG_PREFIX_MAP}
     ,{"defsym", required_argument, NULL, OPTION_DEFSYM}
@@ -655,11 +655,31 @@ This program has absolutely no warranty.\n"));
          exit (EXIT_SUCCESS);
 
        case OPTION_COMPRESS_DEBUG:
-         flag_compress_debug = 1;
+         if (optarg)
+           {
+#if defined OBJ_ELF || defined OBJ_MAYBE_ELF
+             if (strcasecmp (optarg, "none") == 0)
+               flag_compress_debug = COMPRESS_DEBUG_NONE;
+             else if (strcasecmp (optarg, "zlib") == 0)
+               flag_compress_debug = COMPRESS_DEBUG_ZLIB;
+             else if (strcasecmp (optarg, "zlib-gnu") == 0)
+               flag_compress_debug = COMPRESS_DEBUG_GNU_ZLIB;
+             else if (strcasecmp (optarg, "zlib-gabi") == 0)
+               flag_compress_debug = COMPRESS_DEBUG_GABI_ZLIB;
+             else
+               as_fatal (_("Invalid --compress-debug-sections option: `%s'"),
+                         optarg);
+#else
+             as_fatal (_("--compress-debug-sections=%s is unsupported"),
+                       optarg);
+#endif
+           }
+         else
+           flag_compress_debug = COMPRESS_DEBUG;
          break;
 
        case OPTION_NOCOMPRESS_DEBUG:
-         flag_compress_debug = 0;
+         flag_compress_debug = COMPRESS_DEBUG_NONE;
          break;
 
        case OPTION_DEBUG_PREFIX_MAP:
index 2f05745..e04cc0f 100644 (file)
--- a/gas/as.h
+++ b/gas/as.h
@@ -370,8 +370,18 @@ COMMON int flag_strip_local_absolute;
 /* True if we should generate a traditional format object file.  */
 COMMON int flag_traditional_format;
 
-/* TRUE if debug sections should be compressed.  */
-COMMON int flag_compress_debug;
+/* Types of compressed debug sections.  We currently support zlib.  */
+enum compressed_debug_section_type
+{
+  COMPRESS_DEBUG_NONE = 0,
+  COMPRESS_DEBUG,
+  COMPRESS_DEBUG_ZLIB,
+  COMPRESS_DEBUG_GNU_ZLIB,
+  COMPRESS_DEBUG_GABI_ZLIB
+};
+
+/* Type of compressed debug sections we should generate.   */
+COMMON enum compressed_debug_section_type flag_compress_debug;
 
 /* TRUE if .note.GNU-stack section with SEC_CODE should be created */
 COMMON int flag_execstack;
index 8266134..1ab1252 100644 (file)
@@ -35,7 +35,8 @@
 
 #ifdef TE_LINUX
 /* Default to compress debug sections for Linux.  */
-int flag_compress_debug = 1;
+enum compressed_debug_section_type flag_compress_debug
+  = COMPRESS_DEBUG_ZLIB;
 #endif
 
 #ifndef REGISTER_WARNINGS
index bedb4d5..95d6c38 100644 (file)
@@ -630,6 +630,22 @@ to begin with @samp{.zdebug}, and the resulting object file may not be
 compatible with older linkers and object file utilities.  Note if compression
 would make a given section @emph{larger} then it is not compressed or renamed.
 
+@ifset ELF
+@cindex @samp{--compress-debug-sections=} option
+@item --compress-debug-sections=none
+@itemx --compress-debug-sections=zlib
+@itemx --compress-debug-sections=zlib-gnu
+@itemx --compress-debug-sections=zlib-gabi
+These options control how DWARF debug sections are compressed.
+@option{--compress-debug-sections=none} is equivalent to
+@option{--nocompress-debug-sections}.
+@option{--compress-debug-sections=zlib} and
+@option{--compress-debug-sections=zlib-gnu} are equivalent to
+@option{--compress-debug-sections}.
+@option{--compress-debug-sections=zlib-gabi} compresses
+DWARF debug sections with SHF_COMPRESSED from the ELF ABI.
+@end ifset
+
 @item --nocompress-debug-sections
 Do not compress DWARF debug sections.  This is the default.
 
index c896ec5..fc2b934 100644 (file)
@@ -1,3 +1,12 @@
+2015-04-08  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * gas/i386/dw2-compressed-1.d: New file.
+       * gas/i386/dw2-compressed-2.d: Likewise.
+       * gas/i386/dw2-compressed-3.d: Likewise.
+       * gas/i386/x86-64-dw2-compressed-2.d: Likewise.
+       * gas/i386/i386.exp: Run dw2-compressed-2, dw2-compressed-1,
+       dw2-compressed-3 and x86-64-dw2-compressed-2.
+
 2015-04-06  H.J. Lu  <hongjiu.lu@intel.com>
 
        * lib/gas-defs.exp (run_dump_test): Remove is_zlib_supported check.
diff --git a/gas/testsuite/gas/i386/dw2-compressed-1.d b/gas/testsuite/gas/i386/dw2-compressed-1.d
new file mode 100644 (file)
index 0000000..f4c110d
--- /dev/null
@@ -0,0 +1,105 @@
+#source: dw2-compress-1.s
+#as: --compress-debug-sections=zlib-gabi
+#readelf: -w
+#name: DWARF2 debugging information 1 with SHF_COMPRESSED
+
+Contents of the .debug_info section:
+
+  Compilation Unit @ offset 0x0:
+   Length:        0x4e \(32-bit\)
+   Version:       2
+   Abbrev Offset: 0x0
+   Pointer Size:  4
+ <0><b>: Abbrev Number: 1 \(DW_TAG_compile_unit\)
+    <c>   DW_AT_stmt_list   : 0x0
+    <10>   DW_AT_high_pc     : 0x4
+    <14>   DW_AT_low_pc      : 0x0
+    <18>   DW_AT_name        : file1.txt
+    <22>   DW_AT_producer    : GNU C 3.3.3
+    <2e>   DW_AT_language    : 1       \(ANSI C\)
+ <1><2f>: Abbrev Number: 2 \(DW_TAG_subprogram\)
+    <30>   DW_AT_external    : 1
+    <31>   DW_AT_decl_file   : 1
+    <32>   DW_AT_decl_line   : 2
+    <33>   DW_AT_name        : func_cu1
+    <3c>   DW_AT_type        : <0x4a>
+    <40>   DW_AT_low_pc      : 0x0
+    <44>   DW_AT_high_pc     : 0x4
+    <48>   DW_AT_frame_base  : 1 byte block: 55        \(DW_OP_reg5 \([^()]*\)\)
+ <1><4a>: Abbrev Number: 3 \(DW_TAG_base_type\)
+    <4b>   DW_AT_name        : int
+    <4f>   DW_AT_byte_size   : 4
+    <50>   DW_AT_encoding    : 5       \(signed\)
+ <1><51>: Abbrev Number: 0
+
+Contents of the .debug_abbrev section:
+
+  Number TAG \(0x0\)
+   1      DW_TAG_compile_unit    \[has children\]
+    DW_AT_stmt_list    DW_FORM_data4
+    DW_AT_high_pc      DW_FORM_addr
+    DW_AT_low_pc       DW_FORM_addr
+    DW_AT_name         DW_FORM_string
+    DW_AT_producer     DW_FORM_string
+    DW_AT_language     DW_FORM_data1
+    DW_AT value: 0     DW_FORM value: 0
+   2      DW_TAG_subprogram    \[no children\]
+    DW_AT_external     DW_FORM_flag
+    DW_AT_decl_file    DW_FORM_data1
+    DW_AT_decl_line    DW_FORM_data1
+    DW_AT_name         DW_FORM_string
+    DW_AT_type         DW_FORM_ref4
+    DW_AT_low_pc       DW_FORM_addr
+    DW_AT_high_pc      DW_FORM_addr
+    DW_AT_frame_base   DW_FORM_block1
+    DW_AT value: 0     DW_FORM value: 0
+   3      DW_TAG_base_type    \[no children\]
+    DW_AT_name         DW_FORM_string
+    DW_AT_byte_size    DW_FORM_data1
+    DW_AT_encoding     DW_FORM_data1
+    DW_AT value: 0     DW_FORM value: 0
+
+Raw dump of debug contents of section .debug_line:
+
+  Offset:                      0x0
+  Length:                      62
+  DWARF Version:               2
+  Prologue Length:             35
+  Minimum Instruction Length:  1
+  Initial value of 'is_stmt':  1
+  Line Base:                   1
+  Line Range:                  1
+  Opcode Base:                 16
+
+ Opcodes:
+  Opcode 1 has 0 args
+  Opcode 2 has 1 args
+  Opcode 3 has 1 args
+  Opcode 4 has 1 args
+  Opcode 5 has 1 args
+  Opcode 6 has 0 args
+  Opcode 7 has 0 args
+  Opcode 8 has 0 args
+  Opcode 9 has 1 args
+  Opcode 10 has 0 args
+  Opcode 11 has 0 args
+  Opcode 12 has 1 args
+  Opcode 13 has 0 args
+  Opcode 14 has 0 args
+  Opcode 15 has 0 args
+
+ The Directory Table is empty.
+
+ The File Name Table \(offset 0x.*\):
+  Entry        Dir     Time    Size    Name
+  1    0       0       0       file1.txt
+
+ Line Number Statements:
+  \[0x.*\]  Extended opcode 2: set Address to 0x0
+  \[0x.*\]  Advance Line by 3 to 4
+  \[0x.*\]  Copy
+  \[0x.*\]  Copy
+  \[0x.*\]  Extended opcode 2: set Address to 0x4
+  \[0x.*\]  Extended opcode 1: End of Sequence
+
+
diff --git a/gas/testsuite/gas/i386/dw2-compressed-2.d b/gas/testsuite/gas/i386/dw2-compressed-2.d
new file mode 100644 (file)
index 0000000..c62c02f
--- /dev/null
@@ -0,0 +1,7 @@
+#source: dw2-compress-2.s
+#as: --compress-debug-sections=zlib-gabi
+#addr2line: 0x0 0x10 -e
+#name: DWARF2 debugging information 2 with SHF_COMPRESSED
+
+./dw2-compress-2.c:12
+./dw2-compress-2.c:5
diff --git a/gas/testsuite/gas/i386/dw2-compressed-3.d b/gas/testsuite/gas/i386/dw2-compressed-3.d
new file mode 100644 (file)
index 0000000..bd2818b
--- /dev/null
@@ -0,0 +1,104 @@
+#source: dw2-compress-3.s
+#as: --compress-debug-sections=zlib-gabi
+#readelf: -w
+#name: DWARF2 debugging information 3 with SHF_COMPRESSED
+
+Contents of the .debug_info section:
+
+  Compilation Unit @ offset 0x0:
+   Length:        0x32 \(32-bit\)
+   Version:       4
+   Abbrev Offset: 0x0
+   Pointer Size:  4
+ <0><b>: Abbrev Number: 1 \(DW_TAG_compile_unit\)
+    <c>   DW_AT_producer    : \(indirect string, offset: 0x2\): GNU C 4.8.3
+    <10>   DW_AT_language    : 1       \(ANSI C\)
+    <11>   DW_AT_name        : \(indirect string, offset: 0xe\): dw2-compress-3.c
+    <15>   DW_AT_comp_dir    : \(indirect string, offset: 0x0\): .
+    <19>   DW_AT_stmt_list   : 0x0
+ <1><1d>: Abbrev Number: 2 \(DW_TAG_variable\)
+    <1e>   DW_AT_name        : foo
+    <22>   DW_AT_decl_file   : 1
+    <23>   DW_AT_decl_line   : 1
+    <24>   DW_AT_type        : <0x2e>
+    <28>   DW_AT_external    : 1
+    <28>   DW_AT_location    : 5 byte block: 3 4 0 0 0         \(DW_OP_addr: 4\)
+ <1><2e>: Abbrev Number: 3 \(DW_TAG_base_type\)
+    <2f>   DW_AT_byte_size   : 4
+    <30>   DW_AT_encoding    : 5       \(signed\)
+    <31>   DW_AT_name        : int
+ <1><35>: Abbrev Number: 0
+
+Contents of the .debug_abbrev section:
+
+  Number TAG \(0x0\)
+   1      DW_TAG_compile_unit    \[has children\]
+    DW_AT_producer     DW_FORM_strp
+    DW_AT_language     DW_FORM_data1
+    DW_AT_name         DW_FORM_strp
+    DW_AT_comp_dir     DW_FORM_strp
+    DW_AT_stmt_list    DW_FORM_sec_offset
+    DW_AT value: 0     DW_FORM value: 0
+   2      DW_TAG_variable    \[no children\]
+    DW_AT_name         DW_FORM_string
+    DW_AT_decl_file    DW_FORM_data1
+    DW_AT_decl_line    DW_FORM_data1
+    DW_AT_type         DW_FORM_ref4
+    DW_AT_external     DW_FORM_flag_present
+    DW_AT_location     DW_FORM_exprloc
+    DW_AT value: 0     DW_FORM value: 0
+   3      DW_TAG_base_type    \[no children\]
+    DW_AT_byte_size    DW_FORM_data1
+    DW_AT_encoding     DW_FORM_data1
+    DW_AT_name         DW_FORM_string
+    DW_AT value: 0     DW_FORM value: 0
+
+Contents of the .debug_aranges section:
+
+  Length:                   20
+  Version:                  2
+  Offset into .debug_info:  0x0
+  Pointer Size:             4
+  Segment Size:             0
+
+    Address    Length
+    00000000 00000000 
+
+Raw dump of debug contents of section .debug_line:
+
+  Offset:                      0x0
+  Length:                      45
+  DWARF Version:               2
+  Prologue Length:             39
+  Minimum Instruction Length:  1
+  Initial value of 'is_stmt':  1
+  Line Base:                   -5
+  Line Range:                  14
+  Opcode Base:                 13
+
+ Opcodes:
+  Opcode 1 has 0 args
+  Opcode 2 has 1 args
+  Opcode 3 has 1 args
+  Opcode 4 has 1 args
+  Opcode 5 has 1 args
+  Opcode 6 has 0 args
+  Opcode 7 has 0 args
+  Opcode 8 has 0 args
+  Opcode 9 has 1 args
+  Opcode 10 has 0 args
+  Opcode 11 has 0 args
+  Opcode 12 has 1 args
+
+ The Directory Table is empty.
+
+ The File Name Table \(offset 0x1c\):
+  Entry        Dir     Time    Size    Name
+  1    0       0       0       dw2-compress-3.c
+
+ No Line Number Statements.
+Contents of the .debug_str section:
+
+  0x00000000 2e00474e 55204320 342e382e 33006477 ..GNU C 4.8.3.dw
+  0x00000010 322d636f 6d707265 73732d33 2e6300   2-compress-3.c.
+
index 92b4424..26cb7ac 100644 (file)
@@ -384,6 +384,7 @@ if [expr ([istarget "i*86-*-*"] ||  [istarget "x86_64-*-*"]) && [gas_32_check]]
        run_dump_test "debug1"
 
        run_dump_test "dw2-compress-2"
+       run_dump_test "dw2-compressed-2"
 
        run_dump_test "bad-size"
 
@@ -420,6 +421,8 @@ if [expr [istarget "i*86-*-*"] || [istarget "x86_64-*-*"]] then {
        run_list_test_stdin "list-3" "-al"
        run_dump_test "dw2-compress-1"
        run_dump_test "dw2-compress-3"
+       run_dump_test "dw2-compressed-1"
+       run_dump_test "dw2-compressed-3"
     }
 }
 
@@ -735,6 +738,7 @@ if [expr ([istarget "i*86-*-*"] || [istarget "x86_64-*-*"]) && [gas_64_check]] t
        run_dump_test "x86-64-mpx-branch-2"
 
        run_dump_test "x86-64-dw2-compress-2"
+       run_dump_test "x86-64-dw2-compressed-2"
 
        run_dump_test "x86-64-size-1"
        run_dump_test "x86-64-size-2"
diff --git a/gas/testsuite/gas/i386/x86-64-dw2-compressed-2.d b/gas/testsuite/gas/i386/x86-64-dw2-compressed-2.d
new file mode 100644 (file)
index 0000000..1200aec
--- /dev/null
@@ -0,0 +1,7 @@
+#source: x86-64-dw2-compress-2.s
+#as: --compress-debug-sections
+#addr2line: 0x0 0x10 -e
+#name: 64bit DWARF2 debugging information 2 with SHF_COMPRESSED
+
+./dw2-compress-2.c:12
+./dw2-compress-2.c:6
index 1ae47a9..bc76962 100644 (file)
@@ -1413,6 +1413,9 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   struct z_stream_s *strm;
   int x;
   flagword flags = bfd_get_section_flags (abfd, sec);
+  unsigned int header_size, compression_header_size;
+  /* Maximimum compression header is 24 bytes.  */
+  bfd_byte compression_header[24];
 
   if (seginfo == NULL
       || sec->size < 32
@@ -1427,18 +1430,26 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   if (strm == NULL)
     return;
 
+  if (flag_compress_debug == COMPRESS_DEBUG_GABI_ZLIB)
+    stdoutput->flags |= BFD_COMPRESS | BFD_COMPRESS_GABI;
+  else
+    stdoutput->flags |= BFD_COMPRESS;
+  compression_header_size
+    = bfd_get_compression_header_size (stdoutput, NULL);
+
   /* Create a new frag to contain the "ZLIB" header.  */
+  header_size = 12 + compression_header_size;
   first_newf = frag_alloc (ob);
-  if (obstack_room (ob) < 12)
+  if (obstack_room (ob) < header_size)
     first_newf = frag_alloc (ob);
-  if (obstack_room (ob) < 12)
-    as_fatal (_("can't extend frag %u chars"), 12);
+  if (obstack_room (ob) < header_size)
+    as_fatal (_("can't extend frag %u chars"), header_size);
   last_newf = first_newf;
-  obstack_blank_fast (ob, 12);
+  obstack_blank_fast (ob, header_size);
   last_newf->fr_type = rs_fill;
-  last_newf->fr_fix = 12;
+  last_newf->fr_fix = header_size;
   header = last_newf->fr_literal;
-  compressed_size = 12;
+  compressed_size = header_size;
 
   /* Stream the frags through the compression engine, adding new frags
      as necessary to accomodate the compressed output.  */
@@ -1522,21 +1533,27 @@ compress_debug (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
   if (compressed_size >= uncompressed_size)
     return;
 
-  memcpy (header, "ZLIB", 4);
-  bfd_putb64 (uncompressed_size, header + 4);
+  if (compression_header_size)
+    memcpy (header, compression_header, compression_header_size);
+  memcpy (header + compression_header_size, "ZLIB", 4);
+  bfd_putb64 (uncompressed_size, header + compression_header_size + 4);
 
   /* Replace the uncompressed frag list with the compressed frag list.  */
   seginfo->frchainP->frch_root = first_newf;
   seginfo->frchainP->frch_last = last_newf;
 
   /* Update the section size and its name.  */
+  bfd_update_compression_header (abfd, (bfd_byte *) header, sec);
   x = bfd_set_section_size (abfd, sec, compressed_size);
   gas_assert (x);
-  compressed_name = (char *) xmalloc (strlen (section_name) + 2);
-  compressed_name[0] = '.';
-  compressed_name[1] = 'z';
-  strcpy (compressed_name + 2, section_name + 1);
-  bfd_section_name (stdoutput, sec) = compressed_name;
+  if (!compression_header_size)
+    {
+      compressed_name = (char *) xmalloc (strlen (section_name) + 2);
+      compressed_name[0] = '.';
+      compressed_name[1] = 'z';
+      strcpy (compressed_name + 2, section_name + 1);
+      bfd_section_name (stdoutput, sec) = compressed_name;
+    }
 }
 
 static void
index ef54e67..cfa22f4 100644 (file)
@@ -1,3 +1,14 @@
+2015-04-08  H.J. Lu  <hongjiu.lu@intel.com>
+
+       * ld-elf/compress.exp: Add a test for
+       --compress-debug-sections=zlib-gabi.
+       (build_tests): Add 2 tests for --compress-debug-sections=zlib-gabi.
+       (run_tests): Likewise.
+       Verify linker output with zlib-gabi compressed debug input.
+       * ld-elf/compressed1a.d: New file.
+       * ld-elf/compressed1b.d: Likewise.
+       * ld-elf/compressed1c.d: Likewise.
+
 2015-04-07  Alan Modra  <amodra@gmail.com>
 
        * ld-arm/tls-gdesc-nlazy.g: Adjust for readelf note.
index 682811a..adb7fc2 100644 (file)
@@ -40,6 +40,10 @@ if { ![ld_assemble $as "--compress-debug-sections $srcdir/$subdir/empty.s" tmpdi
     fail "linker compressed debug sections"
 }
 
+if { ![ld_assemble $as "--compress-debug-sections=zlib-gabi $srcdir/$subdir/empty.s" tmpdir/emptyzlib.o ] } {
+    fail "linker compressed debug sections"
+}
+
 set build_tests {
   {"Build libfoo.so with compressed debug sections"
    "-shared" "-fPIC -g -Wa,--compress-debug-sections"
@@ -47,13 +51,31 @@ set build_tests {
   {"Build libbar.so with compressed debug sections"
    "-shared" "-fPIC -g -Wa,--compress-debug-sections"
    {begin.c end.c} {} "libbar.so"}
+  {"Build libfoozlib.so with compressed debug sections with zlib-gabi"
+   "-shared" "-fPIC -g -Wa,--compress-debug-sections=zlib-gabi"
+   {foo.c} {} "libfoozlib.so"}
+  {"Build libbarzlib.so with compressed debug sections with zlib-gabi"
+   "-shared" "-fPIC -g -Wa,--compress-debug-sections=zlib-gabi"
+   {begin.c end.c} {} "libbarzlib.so"}
 }
 
 set run_tests {
     {"Run normal with libfoo.so with compressed debug sections"
-     "tmpdir/begin.o tmpdir/libfoo.so tmpdir/end.o" "-Wa,--compress-debug-sections"
-     {main.c} "normal" "normal.out"}
+     "tmpdir/begin.o tmpdir/libfoo.so tmpdir/end.o" ""
+     {main.c} "normal" "normal.out" "-Wa,--compress-debug-sections"}
+    {"Run normal with libfoo.so with compressed debug sections with zlib-gabi"
+     "tmpdir/begin.o tmpdir/libfoozlib.so tmpdir/end.o" ""
+     {main.c} "normal" "normal.out" "-Wa,--compress-debug-sections=zlib-gabi"}
 }
 
 run_cc_link_tests $build_tests
 run_ld_link_exec_tests [] $run_tests
+
+set test_name "Link with zlib-gabi compressed debug input"
+send_log "cmp tmpdir/libfoo.so tmpdir/libfoozlib.so\n"
+if { [catch {exec cmp tmpdir/libfoo.so tmpdir/libfoozlib.so}] } then {
+    send_log "tmpdir/libfoo.so tmpdir/libfoozlib.so differ.\n"
+    fail "$test_name"
+} else {
+    pass "$test_name"
+}
diff --git a/ld/testsuite/ld-elf/compressed1a.d b/ld/testsuite/ld-elf/compressed1a.d
new file mode 100644 (file)
index 0000000..653c203
--- /dev/null
@@ -0,0 +1,10 @@
+#source: compress1.s
+#as: --compress-debug-sections=zlib-gabi
+#ld: -e func_cu2
+#readelf: -t
+#notarget: alpha-*
+
+#failif
+#...
+  .*COMPRESSED.*
+#...
diff --git a/ld/testsuite/ld-elf/compressed1b.d b/ld/testsuite/ld-elf/compressed1b.d
new file mode 100644 (file)
index 0000000..83dc60f
--- /dev/null
@@ -0,0 +1,9 @@
+#source: compress1.s
+#as: --compress-debug-sections=zlib-gabi
+#ld: -r
+#readelf: -t
+
+#failif
+#...
+  .*COMPRESSED.*
+#...
diff --git a/ld/testsuite/ld-elf/compressed1c.d b/ld/testsuite/ld-elf/compressed1c.d
new file mode 100644 (file)
index 0000000..64f75be
--- /dev/null
@@ -0,0 +1,10 @@
+#source: compress1.s
+#as: --compress-debug-sections=zlib-gabi
+#ld: -shared
+#readelf: -t
+#target: *-*-linux* *-*-gnu*
+
+#failif
+#...
+  .*COMPRESSED.*
+#...