This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 4/6] libelf: Add elf_compress and elf_compress_gnu.


Signed-off-by: Mark Wielaard <mjw@redhat.com>
---
 libelf/ChangeLog          |  24 +++
 libelf/Makefile.am        |   3 +-
 libelf/elf_compress.c     | 394 ++++++++++++++++++++++++++++++++++++++++++++++
 libelf/elf_compress_gnu.c | 150 ++++++++++++++++++
 libelf/elf_end.c          |  11 +-
 libelf/elf_error.c        |  26 ++-
 libelf/elf_getdata.c      |  27 ++--
 libelf/libelf.h           |  38 ++++-
 libelf/libelf.map         |   5 +-
 libelf/libelfP.h          |  23 +++
 tests/ChangeLog           |  15 ++
 tests/Makefile.am         |  10 +-
 tests/elfgetzdata.c       | 101 ++++++++++++
 tests/elfputzdata.c       | 201 +++++++++++++++++++++++
 tests/msg_tst.c           |   6 +-
 tests/run-elfgetzdata.sh  | 122 ++++++++++++++
 tests/run-elfputzdata.sh  | 340 +++++++++++++++++++++++++++++++++++++++
 17 files changed, 1475 insertions(+), 21 deletions(-)
 create mode 100644 libelf/elf_compress.c
 create mode 100644 libelf/elf_compress_gnu.c
 create mode 100644 tests/elfgetzdata.c
 create mode 100644 tests/elfputzdata.c
 create mode 100755 tests/run-elfgetzdata.sh
 create mode 100755 tests/run-elfputzdata.sh

diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index d8eff1a..35221a6 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,27 @@
+2015-10-21  Mark Wielaard  <mjw@redhat.com>
+
+	* Makefile.am (libelf_a_SOURCES): Add elf_compress.c and
+	elf_compress_gnu.c.
+	* elf_compress.c: New file.
+	* elf_compress_gnu.c: Likewise.
+	* elf_end.c (elf_end): Free zdata_base.
+	* elf_error.c: Add ELF_E_ALREADY_COMPRESSED,
+	ELF_E_UNKNOWN_COMPRESSION_TYPE, ELF_E_COMPRESS_ERROR and
+	ELF_E_DECOMPRESS_ERROR.
+	* elf_data.c (__libelf_data_type): New internal function extracted
+	from convert_data.
+	(convert_data): Handle SHF_COMPRESSED.
+	* libelf.h: Define elf_compress and elf_compress_gnu.
+	* libelf.map (ELFUTILS_1.7): Add elf_compress and elf_compress_gnu.
+	* libelfP.h: Add ELF_E_ALREADY_COMPRESSED,
+	ELF_E_UNKNOWN_COMPRESSION_TYPE, ELF_E_COMPRESS_ERROR and
+	ELF_E_DECOMPRESS_ERROR. Define __libelf_data_type.
+	(__libelf_compress): New internal function definition.
+	(__libelf_decompress): Likewise.
+	(__libelf_reset_rawdata): Likewise.
+	(__libelf_data_type): Likewise.
+	(struct Elf_Scn): Add zdata_base.
+
 2015-11-19  Mark Wielaard  <mjw@redhat.com>
 
 	* Makefile.am (libelf_a_SOURCES): Add elf32_getchdr.c, elf64_getchdr.c
diff --git a/libelf/Makefile.am b/libelf/Makefile.am
index 8a678b8..167a832 100644
--- a/libelf/Makefile.am
+++ b/libelf/Makefile.am
@@ -89,7 +89,8 @@ libelf_a_SOURCES = elf_version.c elf_hash.c elf_error.c elf_fill.c \
 		   elf_getaroff.c \
 		   elf_gnu_hash.c \
 		   elf_scnshndx.c \
-		   elf32_getchdr.c elf64_getchdr.c gelf_getchdr.c
+		   elf32_getchdr.c elf64_getchdr.c gelf_getchdr.c \
+		   elf_compress.c elf_compress_gnu.c
 
 libelf_pic_a_SOURCES =
 am_libelf_pic_a_OBJECTS = $(libelf_a_SOURCES:.c=.os)
diff --git a/libelf/elf_compress.c b/libelf/elf_compress.c
new file mode 100644
index 0000000..6a26c7c
--- /dev/null
+++ b/libelf/elf_compress.c
@@ -0,0 +1,394 @@
+/* Compress or decompress a section.
+   Copyright (C) 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libelf.h>
+#include "libelfP.h"
+#include "common.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <zlib.h>
+
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+/* Given a section, uses the (in-memory) Elf_Data to extract the
+   original data size (including the given header size) and data
+   alignment.  Returns a buffer that has at least hsize bytes (for the
+   caller to fill in with a header) plus zlib compressed date.  Also
+   returns the new buffer size in new_size (hsize + compressed data
+   size).  */
+void *
+internal_function
+__libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data,
+		   size_t *orig_size, size_t *orig_addralign,
+		   size_t *new_size)
+{
+  /* The compressed data is the on-disk data.  We simplify the
+     implementation a bit by asking for the (converted) in-memory
+     data (which might be all there is if the user created it with
+     elf_newdata) and then convert back to raw if needed before
+     compressing.  Should be made a bit more clever to directly
+     use raw if that is directly available.  */
+  Elf_Data *data = elf_getdata (scn, NULL);
+  if (data == NULL)
+    return NULL;
+
+  *orig_addralign = data->d_align;
+  *orig_size = data->d_size;
+
+  /* Guess an output size. 1/8th of the original Elf_Data or at least 8K.  */
+  size_t block = MAX (data->d_size / 8, 8 * 1024);
+  size_t out_size = block;
+  void *out_buf = malloc (out_size);
+  if (out_buf == NULL)
+    {
+      __libelf_seterrno (ELF_E_NOMEM);
+      return NULL;
+    }
+
+  /* Caller gets to fill in the header at the start.  Just skip it here.  */
+  size_t used = hsize;
+
+  z_stream z;
+  z.zalloc = Z_NULL;
+  z.zfree = Z_NULL;
+  z.opaque = Z_NULL;
+  int zrc = deflateInit (&z, Z_BEST_COMPRESSION);
+  if (zrc != Z_OK)
+    {
+      __libelf_seterrno (ELF_E_COMPRESS_ERROR);
+      return NULL;
+    }
+
+  Elf_Data cdata;
+  cdata.d_buf = NULL;
+
+  /* Cleanup and NULL return on error.  Don't leak memory.  */
+  void *deflate_error (int err)
+  {
+    __libelf_seterrno (err);
+    deflateEnd (&z);
+    free (out_buf);
+    if (ei_data != MY_ELFDATA)
+      free (cdata.d_buf);
+    return NULL;
+  }
+
+  /* Loop over data buffers.  */
+  int flush = Z_NO_FLUSH;
+  do
+    {
+      /* Convert to raw if different endianess.  */
+      cdata = *data;
+      if (ei_data != MY_ELFDATA)
+	{
+	  /* Don't do this conversion in place, we might want to keep
+	     the original data around, caller decides.  */
+	  cdata.d_buf = malloc (data->d_size);
+	  if (cdata.d_buf == NULL)
+	    return deflate_error (ELF_E_NOMEM);
+	  if (gelf_xlatetof (scn->elf, &cdata, data, ei_data) == NULL)
+	    return deflate_error;
+	}
+
+      z.avail_in = cdata.d_size;
+      z.next_in = cdata.d_buf;
+
+      /* Get next buffer to see if this is the last one.  */
+      data = elf_getdata (scn, data);
+      if (data != NULL)
+	{
+	  *orig_addralign = MAX (*orig_addralign, data->d_align);
+	  *orig_size += data->d_size;
+	}
+      else
+	flush = Z_FINISH;
+
+      /* Flush one data buffer.  */
+      do
+	{
+	  z.avail_out = out_size - used;
+	  z.next_out = out_buf + used;
+	  zrc = deflate (&z, flush);
+	  if (zrc == Z_STREAM_ERROR)
+	    return deflate_error (ELF_E_COMPRESS_ERROR);
+	  used += (out_size - used) - z.avail_out;
+	  if (z.avail_out == 0)
+	    {
+	      void *bigger = realloc (out_buf, out_size + block);
+	      if (bigger == NULL)
+		return deflate_error (ELF_E_NOMEM);
+	      out_buf = bigger;
+	      out_size += block;
+	    }
+	}
+      while (z.avail_out == 0); /* Need more output buffer.  */
+
+      if (ei_data != MY_ELFDATA)
+	{
+	  free (cdata.d_buf);
+	  cdata.d_buf = NULL;
+	}
+    }
+  while (flush != Z_FINISH); /* More data blocks.  */
+
+  zrc = deflateEnd (&z);
+  if (zrc != Z_OK)
+    return deflate_error (ELF_E_COMPRESS_ERROR);
+
+  *new_size = used;
+  return out_buf;
+}
+
+void *
+internal_function
+__libelf_decompress (void *buf_in, size_t size_in, size_t size_out)
+{
+  void *buf_out = malloc (size_out);
+  if (unlikely (buf_out == NULL))
+    {
+      __libelf_seterrno (ELF_E_NOMEM);
+      return NULL;
+    }
+
+  z_stream z =
+    {
+      .next_in = buf_in,
+      .avail_in = size_in,
+      .next_out = buf_out,
+      .avail_out = size_out
+    };
+  int zrc = inflateInit (&z);
+  while (z.avail_in > 0 && likely (zrc == Z_OK))
+    {
+      z.next_out = buf_out + (size_out - z.avail_out);
+      zrc = inflate (&z, Z_FINISH);
+      if (unlikely (zrc != Z_STREAM_END))
+	{
+	  zrc = Z_DATA_ERROR;
+	  break;
+	}
+      zrc = inflateReset (&z);
+    }
+  if (likely (zrc == Z_OK))
+    zrc = inflateEnd (&z);
+
+  if (unlikely (zrc != Z_OK) || unlikely (z.avail_out != 0))
+    {
+      free (buf_out);
+      __libelf_seterrno (ELF_E_DECOMPRESS_ERROR);
+      return NULL;
+    }
+
+  return buf_out;
+}
+
+void
+internal_function
+__libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size, size_t align,
+			Elf_Type type)
+{
+  /* This is the new raw data, replace and possibly free old data.  */
+  // XXX d_off, d_version, ...
+  scn->rawdata.d.d_buf = buf;
+  scn->rawdata.d.d_size = size;
+  scn->rawdata.d.d_align = align;
+  scn->rawdata.d.d_type = type;
+
+  /* Existing existing data is no longer valid.  */
+  scn->data_list_rear = NULL;
+  if (scn->data_base != scn->rawdata_base)
+    free (scn->data_base);
+  scn->data_base = NULL;
+  if (scn->elf->map_address == NULL
+      || scn->rawdata_base == scn->zdata_base)
+    free (scn->rawdata_base);
+
+  scn->rawdata_base = buf;
+}
+
+int
+elf_compress (Elf_Scn *scn, int type)
+{
+  if (scn == NULL)
+    return -1;
+
+  Elf *elf = scn->elf;
+  GElf_Ehdr ehdr;
+  if (gelf_getehdr (elf, &ehdr) == NULL)
+    return -1;
+
+  int elfclass = elf->class;
+  int elfdata = ehdr.e_ident[EI_DATA];
+
+  GElf_Shdr shdr;
+  if (gelf_getshdr (scn, &shdr) == NULL)
+    return -1;
+
+  int compressed = (shdr.sh_flags & SHF_COMPRESSED);
+  if (type == ELFCOMPRESS_ZLIB)
+    {
+      /* Compress/Deflate.  */
+      if (compressed == 1)
+	{
+	  __libelf_seterrno (ELF_E_ALREADY_COMPRESSED);
+	  return -1;
+	}
+
+      size_t hsize = (elfclass == ELFCLASS32
+		      ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
+      size_t orig_size, orig_addralign, new_size;
+      void *out_buf = __libelf_compress (scn, hsize, elfdata,
+					 &orig_size, &orig_addralign,
+					 &new_size);
+      if (out_buf == NULL)
+	return -1;
+
+      /* Put the header in front of the data.  */
+      if (elfclass == ELFCLASS32)
+	{
+	  Elf32_Chdr chdr;
+	  chdr.ch_type = ELFCOMPRESS_ZLIB;
+	  chdr.ch_size = orig_size;
+	  chdr.ch_addralign = orig_addralign;
+	  if (elfdata != MY_ELFDATA)
+	    {
+	      CONVERT (chdr.ch_type);
+	      CONVERT (chdr.ch_size);
+	      CONVERT (chdr.ch_addralign);
+	    }
+	  memcpy (out_buf, &chdr, sizeof (Elf32_Chdr));
+	}
+      else
+	{
+	  Elf64_Chdr chdr;
+	  chdr.ch_type = ELFCOMPRESS_ZLIB;
+	  chdr.ch_reserved = 0;
+	  chdr.ch_size = orig_size;
+	  chdr.ch_addralign = shdr.sh_addralign;
+	  if (elfdata != MY_ELFDATA)
+	    {
+	      CONVERT (chdr.ch_type);
+	      CONVERT (chdr.ch_reserved);
+	      CONVERT (chdr.ch_size);
+	      CONVERT (chdr.ch_addralign);
+	    }
+	  memcpy (out_buf, &chdr, sizeof (Elf64_Chdr));
+	}
+
+      /* Note we keep the sh_entsize as is, we assume it is setup
+	 correctly and ignored when SHF_COMPRESSED is set.  */
+      shdr.sh_size = new_size;
+      shdr.sh_addralign = 1;
+      shdr.sh_flags |= SHF_COMPRESSED;
+      // XXX Don't! this sets dirty flag...
+      gelf_update_shdr (scn, &shdr);
+
+      __libelf_reset_rawdata (scn, out_buf, new_size, 1, ELF_T_CHDR);
+
+      /* The section is now compressed, we could keep the uncompressed
+	 data around, but since that might have been multiple Elf_Data
+	 buffers let the user uncompress it explicitly again if they
+	 want it to simplify bookkeeping.  */
+      scn->zdata_base = NULL;
+
+      return 0;
+    }
+  else if (type == 0)
+    {
+      /* Decompress/Inflate.  */
+      if (compressed == 0)
+	{
+	  __libelf_seterrno (ELF_E_NOT_COMPRESSED);
+	  return -1;
+	}
+
+      GElf_Chdr chdr;
+      if (gelf_getchdr (scn, &chdr) == NULL)
+	return -1;
+
+      if (chdr.ch_type != ELFCOMPRESS_ZLIB)
+	{
+	  __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
+	  return -1;
+	}
+
+      if (! powerof2 (chdr.ch_addralign))
+	{
+	  __libelf_seterrno (ELF_E_INVALID_ALIGN);
+	  return -1;
+	}
+
+      /* Take the in-memory representation, so we can even handle a
+	 section that has just been constructed (maybe it was copied
+	 over from some other ELF file first with elf_newdata).  This
+	 is slightly inefficient when the raw data needs to be
+	 converted since then we'll be converting the whole buffer and
+	 not just Chdr.  */
+      Elf_Data *data = elf_getdata (scn, NULL);
+      if (data == NULL)
+	return -1;
+
+      size_t hsize = (elfclass == ELFCLASS32
+		      ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr));
+      size_t size_in = data->d_size - hsize;
+      void *buf_in = data->d_buf + hsize;
+      void *buf_out = __libelf_decompress (buf_in, size_in, chdr.ch_size);
+      if (buf_out == NULL)
+	return -1;
+
+      /* Note we keep the sh_entsize as is, we assume it is setup
+	 correctly and ignored when SHF_COMPRESSED is set.  */
+      shdr.sh_size = chdr.ch_size;
+      shdr.sh_addralign = chdr.ch_addralign;
+      shdr.sh_flags &= ~SHF_COMPRESSED;
+      // XXX Don't! this sets dirty flag...
+      gelf_update_shdr (scn, &shdr);
+
+      __libelf_reset_rawdata (scn, buf_out, chdr.ch_size, chdr.ch_addralign,
+			      __libelf_data_type (elf, shdr.sh_type));
+
+      scn->zdata_base = buf_out;
+
+      return 0;
+    }
+  else
+    {
+      __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
+      return -1;
+    }
+}
diff --git a/libelf/elf_compress_gnu.c b/libelf/elf_compress_gnu.c
new file mode 100644
index 0000000..9d4378b
--- /dev/null
+++ b/libelf/elf_compress_gnu.c
@@ -0,0 +1,150 @@
+/* Compress or decompress a section.
+   Copyright (C) 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <libelf.h>
+#include "libelfP.h"
+#include "common.h"
+
+int
+elf_compress_gnu (Elf_Scn *scn, int inflate)
+{
+  if (scn == NULL)
+    return -1;
+
+  Elf *elf = scn->elf;
+  GElf_Ehdr ehdr;
+  if (gelf_getehdr (elf, &ehdr) == NULL)
+    return -1;
+
+  int elfdata = ehdr.e_ident[EI_DATA];
+
+  GElf_Shdr shdr;
+  if (gelf_getshdr (scn, &shdr) == NULL)
+    return -1;
+
+  /* For GNU compression we cannot really know whether the section is
+     already compressed or not.  Just try and see what happens...  */
+  // int compressed = (shdr.sh_flags & SHF_COMPRESSED);
+  if (inflate == 1)
+    {
+      size_t hsize = 4 + 8; /* GNU "ZLIB" + 8 byte size.  */
+      size_t orig_size, new_size, orig_addralign;
+      void *out_buf = __libelf_compress (scn, hsize, elfdata,
+					 &orig_size, &orig_addralign,
+					 &new_size);
+      if (out_buf == NULL)
+	return -1;
+
+      uint64_t be64_size = htobe64 (orig_size);
+      memmove (out_buf, "ZLIB", 4);
+      memmove (out_buf + 4, &be64_size, sizeof (be64_size));
+
+      /* We don't know anything about sh_entsize, sh_addralign and
+	 sh_flags won't have a SHF_COMPRESSED hint in the GNU format.
+	 Just adjust the sh_size.  */
+      shdr.sh_size = new_size;
+
+      // XXX Don't! this sets dirty flag...
+      gelf_update_shdr (scn, &shdr);
+
+      __libelf_reset_rawdata (scn, out_buf, new_size, 1, ELF_T_BYTE);
+
+      /* The section is now compressed, we could keep the uncompressed
+	 data around, but since that might have been multiple Elf_Data
+	 buffers let the user uncompress it explicitly again if they
+	 want it to simplify bookkeeping.  */
+      scn->zdata_base = NULL;
+
+      return 0;
+    }
+  else if (inflate == 0)
+    {
+      /* In theory the user could have constucted a compressed section
+	 by hand.  But we always just take the rawdata directly and
+	 decompress that.  */
+      Elf_Data *data = elf_rawdata (scn, NULL);
+      if (data == NULL)
+	return -1;
+
+      size_t hsize = 4 + 8; /* GNU "ZLIB" + 8 byte size.  */
+      if (data->d_size < hsize || memcmp (data->d_buf, "ZLIB", 4) != 0)
+	{
+          __libelf_seterrno (ELF_E_NOT_COMPRESSED);
+	  return -1;
+	}
+
+      /* There is a 12-byte header of "ZLIB" followed by
+	 an 8-byte big-endian size.  There is only one type and
+	 Alignment isn't preserved separately.  */
+      uint64_t gsize;
+      memcpy (&gsize, data->d_buf + 4, sizeof gsize);
+      gsize = be64toh (gsize);
+
+      /* One more sanity check, size should be bigger than original
+	 data size plus some overhead (4 chars ZLIB + 8 bytes size + 6
+	 bytes zlib stream overhead + 5 bytes overhead max for one 16K
+	 block) and should fit into a size_t.  */
+      if (gsize + 4 + 8 + 6 + 5 < data->d_size || gsize > SIZE_MAX)
+	{
+	  __libelf_seterrno (ELF_E_NOT_COMPRESSED);
+	  return -1;
+	}
+
+      size_t size = gsize;
+      size_t size_in = data->d_size - hsize;
+      void *buf_in = data->d_buf + hsize;
+      void *buf_out = __libelf_decompress (buf_in, size_in, size);
+      if (buf_out == NULL)
+	return -1;
+
+      /* We don't know anything about sh_entsize, sh_addralign and
+	 sh_flags won't have a SHF_COMPRESSED hint in the GNU format.
+	 Just adjust the sh_size.  */
+      shdr.sh_size = size;
+
+      // XXX Don't! this sets dirty flag...
+      gelf_update_shdr (scn, &shdr);
+
+      __libelf_reset_rawdata (scn, buf_out, size, shdr.sh_addralign,
+			      __libelf_data_type (elf, shdr.sh_type));
+
+      scn->zdata_base = buf_out;
+
+      return 0;
+    }
+  else
+    {
+      __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
+      return -1;
+    }
+
+}
diff --git a/libelf/elf_end.c b/libelf/elf_end.c
index 7ea876c..fde17b5 100644
--- a/libelf/elf_end.c
+++ b/libelf/elf_end.c
@@ -150,6 +150,12 @@ elf_end (Elf *elf)
 		  /* It doesn't matter which pointer.  */
 		  free (scn->shdr.e32);
 
+		/* Free zdata if uncompressed, but not yet used as
+		   rawdata_base.  If it is already used it will be
+		   freed below.  */
+		if (scn->zdata_base != scn->rawdata_base)
+		  free (scn->zdata_base);
+
 		/* If the file has the same byte order and the
 		   architecture doesn't require overly stringent
 		   alignment the raw data buffer is the same as the
@@ -158,8 +164,9 @@ elf_end (Elf *elf)
 		  free (scn->data_base);
 
 		/* The section data is allocated if we couldn't mmap
-		   the file.  */
-		if (elf->map_address == NULL)
+		   the file.  Or if we had to decompress.  */
+		if (elf->map_address == NULL
+		    || scn->rawdata_base == scn->zdata_base)
 		  free (scn->rawdata_base);
 
 		/* Free the list of data buffers for the section.
diff --git a/libelf/elf_error.c b/libelf/elf_error.c
index c404590..d6eac4d 100644
--- a/libelf/elf_error.c
+++ b/libelf/elf_error.c
@@ -235,6 +235,26 @@ core files")
   (ELF_E_INVALID_OFFSET_IDX			\
    + sizeof "invalid offset")
   N_("section does not contain compressed data")
+  "\0"
+#define ELF_E_ALREADY_COMPRESSED_IDX \
+  (ELF_E_NOT_COMPRESSED_IDX \
+   + sizeof "section does not contain compressed data")
+  N_("section contains compressed data")
+  "\0"
+#define ELF_E_UNKNOWN_COMPRESSION_TYPE_IDX \
+  (ELF_E_ALREADY_COMPRESSED_IDX \
+   + sizeof "section contains compressed data")
+  N_("unknown compression type")
+  "\0"
+#define ELF_E_COMPRESS_ERROR_IDX \
+  (ELF_E_UNKNOWN_COMPRESSION_TYPE_IDX \
+   + sizeof "unknown compression type")
+  N_("cannot compress data")
+  "\0"
+#define ELF_E_DECOMPRESS_ERROR_IDX \
+  (ELF_E_COMPRESS_ERROR_IDX \
+   + sizeof "cannot compress data")
+  N_("cannot decompress data")
 };
 
 
@@ -283,7 +303,11 @@ static const uint_fast16_t msgidx[ELF_E_NUM] =
   [ELF_E_INVALID_PHDR] = ELF_E_INVALID_PHDR_IDX,
   [ELF_E_NO_PHDR] = ELF_E_NO_PHDR_IDX,
   [ELF_E_INVALID_OFFSET] = ELF_E_INVALID_OFFSET_IDX,
-  [ELF_E_NOT_COMPRESSED] = ELF_E_NOT_COMPRESSED_IDX
+  [ELF_E_NOT_COMPRESSED] = ELF_E_NOT_COMPRESSED_IDX,
+  [ELF_E_ALREADY_COMPRESSED] = ELF_E_ALREADY_COMPRESSED_IDX,
+  [ELF_E_UNKNOWN_COMPRESSION_TYPE] = ELF_E_UNKNOWN_COMPRESSION_TYPE_IDX,
+  [ELF_E_COMPRESS_ERROR] = ELF_E_COMPRESS_ERROR_IDX,
+  [ELF_E_DECOMPRESS_ERROR] = ELF_E_DECOMPRESS_ERROR_IDX
 };
 #define nmsgidx ((int) (sizeof (msgidx) / sizeof (msgidx[0])))
 
diff --git a/libelf/elf_getdata.c b/libelf/elf_getdata.c
index bd1f068..4ec94b9 100644
--- a/libelf/elf_getdata.c
+++ b/libelf/elf_getdata.c
@@ -118,6 +118,22 @@ const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM]
 #endif
 
 
+Elf_Type
+internal_function
+__libelf_data_type (Elf *elf, int sh_type)
+{
+  /* Some broken ELF ABI for 64-bit machines use the wrong hash table
+     entry size.  See elf-knowledge.h for more information.  */
+  if (sh_type == SHT_HASH && elf->class == ELFCLASS64)
+    {
+      GElf_Ehdr ehdr_mem;
+      GElf_Ehdr *ehdr = __gelf_getehdr_rdlock (elf, &ehdr_mem);
+      return (SH_ENTSIZE_HASH (ehdr) == 4 ? ELF_T_WORD : ELF_T_XWORD);
+    }
+  else
+    return shtype_map[LIBELF_EV_IDX][TYPEIDX (sh_type)];
+}
+
 /* Convert the data in the current section.  */
 static void
 convert_data (Elf_Scn *scn, int version __attribute__ ((unused)), int eclass,
@@ -332,17 +348,8 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn)
      section type.  */
   if ((flags & SHF_COMPRESSED) != 0)
     scn->rawdata.d.d_type = ELF_T_CHDR;
-  else if (type == SHT_HASH && elf->class == ELFCLASS64)
-    {
-      /* Some broken ELF ABI for 64-bit machines use the wrong hash table
-	 entry size.  See elf-knowledge.h for more information.  */
-      GElf_Ehdr ehdr_mem;
-      GElf_Ehdr *ehdr = __gelf_getehdr_rdlock (elf, &ehdr_mem);
-      scn->rawdata.d.d_type
-	= (SH_ENTSIZE_HASH (ehdr) == 4 ? ELF_T_WORD : ELF_T_XWORD);
-    }
   else
-    scn->rawdata.d.d_type = shtype_map[LIBELF_EV_IDX][TYPEIDX (type)];
+    scn->rawdata.d.d_type = __libelf_data_type (elf, type);
   scn->rawdata.d.d_off = 0;
 
   /* Make sure the alignment makes sense.  d_align should be aligned both
diff --git a/libelf/libelf.h b/libelf/libelf.h
index 49234c8..ccafd78 100644
--- a/libelf/libelf.h
+++ b/libelf/libelf.h
@@ -274,6 +274,37 @@ extern Elf64_Shdr *elf64_getshdr (Elf_Scn *__scn);
 extern Elf32_Chdr *elf32_getchdr (Elf_Scn *__scn);
 extern Elf64_Chdr *elf64_getchdr (Elf_Scn *__scn);
 
+/* Compress or decompress the data of a section and adjust the section
+   header.
+
+   elf_compress works by setting or clearing the SHF_COMPRESS flag
+   from the section Shdr and will encode or decode a Elf32_Chdr or
+   Elf64_Chdr at the start of the section data.  elf_compress_gnu will
+   encode or decode any section, but is traditionally only used for
+   sections that have a name starting with a ".debug" when
+   uncompressed or ".zdebug" when compressed and stores just the
+   uncompressed size.  The GNU compression method is deprecated and
+   should only be used for legacy support.
+
+   elf_compress takes a compression type that should be either zero to
+   decompress or an ELFCOMPRESS algorithm to use for compression.
+   Currently only ELFCOMPRESS_ZLIB is supported.  elf_compress_gnu
+   will compress in the traditional GNU compression format when
+   compress is one and decompress the section data when compress is
+   zero.
+
+   On successful compression or decompression the function returns
+   zero.  Otherwise -1 is returned and elf_errno is set.
+
+   All previous returned Shdrs and Elf_Data buffers are invalidated by
+   this call and should no longer be accessed.
+
+   Note that although this changes the header and data returned it
+   doesn't mark the section as dirty.  To keep the changes when
+   calling elf_update the section has to be flagged ELF_F_DIRTY.  */
+extern int elf_compress (Elf_Scn *scn, int type);
+extern int elf_compress_gnu (Elf_Scn *scn, int compress);
+
 /* Set or clear flags for ELF file.  */
 extern unsigned int elf_flagelf (Elf *__elf, Elf_Cmd __cmd,
 				 unsigned int __flags);
@@ -294,8 +325,11 @@ extern unsigned int elf_flagshdr (Elf_Scn *__scn, Elf_Cmd __cmd,
 				  unsigned int __flags);
 
 
-/* Get data from section while translating from file representation
-   to memory representation.  */
+/* Get data from section while translating from file representation to
+   memory representation.  The Elf_Data d_type is set based on the
+   section type if known.  Otherwise d_type is set to ELF_T_BYTE.  If
+   the section contains compressed data then d_type is always set to
+   ELF_T_CHDR.  */
 extern Elf_Data *elf_getdata (Elf_Scn *__scn, Elf_Data *__data);
 
 /* Get uninterpreted section content.  */
diff --git a/libelf/libelf.map b/libelf/libelf.map
index d402ccc..10dc505 100644
--- a/libelf/libelf.map
+++ b/libelf/libelf.map
@@ -144,4 +144,7 @@ ELFUTILS_1.7 {
     elf32_getchdr;
     elf64_getchdr;
     gelf_getchdr;
-} ELFUTILS_1.6;
\ No newline at end of file
+
+    elf_compress;
+    elf_compress_gnu;
+} ELFUTILS_1.6;
diff --git a/libelf/libelfP.h b/libelf/libelfP.h
index 73fd765..b58f3fe 100644
--- a/libelf/libelfP.h
+++ b/libelf/libelfP.h
@@ -139,6 +139,10 @@ enum
   ELF_E_NO_PHDR,
   ELF_E_INVALID_OFFSET,
   ELF_E_NOT_COMPRESSED,
+  ELF_E_ALREADY_COMPRESSED,
+  ELF_E_UNKNOWN_COMPRESSION_TYPE,
+  ELF_E_COMPRESS_ERROR,
+  ELF_E_DECOMPRESS_ERROR,
   /* Keep this as the last entry.  */
   ELF_E_NUM
 };
@@ -231,6 +235,8 @@ struct Elf_Scn
   char *rawdata_base;		/* The unmodified data of the section.  */
   char *data_base;		/* The converted data of the section.  */
 
+  char *zdata_base;		/* The uncompressed data of the section.  */
+
   struct Elf_ScnList *list;	/* Pointer to the section list element the
 				   data is in.  */
 };
@@ -439,6 +445,11 @@ extern const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_
 # define __libelf_type_align(class, type)	1
 #endif
 
+/* Given an Elf handle and a section type returns the Elf_Data d_type.
+   Should not be called when SHF_COMPRESSED is set, the d_type should
+   be ELF_T_BYTE.  */
+extern Elf_Type __libelf_data_type (Elf *elf, int sh_type) internal_function;
+
 /* The libelf API does not have such a function but it is still useful.
    Get the memory size for the given type.
 
@@ -579,6 +590,18 @@ extern GElf_Sym *__gelf_getsym_internal (Elf_Data *__data, int __ndx,
 extern uint32_t __libelf_crc32 (uint32_t crc, unsigned char *buf, size_t len)
      attribute_hidden;
 
+extern void * __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data,
+				 size_t *orig_size, size_t *orig_addralign,
+				 size_t *size)
+     internal_function;
+
+extern void * __libelf_decompress (void *buf_in, size_t size_in,
+				   size_t size_out) internal_function;
+
+extern void __libelf_reset_rawdata (Elf_Scn *scn, void *buf, size_t size,
+				    size_t align, Elf_Type type)
+     internal_function;
+
 
 /* We often have to update a flag iff a value changed.  Make this
    convenient.  */
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 2c511be..149baf1 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,18 @@
+2015-10-21  Mark Wielaard  <mjw@redhat.com>
+
+	* Makefile.am (check_PROGRAMS): Add elfgetzdata and elfputzdata.
+	(TESTS): Add run-elfgetzdata.sh and run-elfputzdata.sh.
+	(EXTRA_DIST: Likewise.
+	(elfgetzdata_LDADD): New variable.
+	(elfputzdata_LDADD): Likewise.
+	* elfgetzdata.c: New file.
+	* elfputzdata.c: Likewise.
+	* msg_tst.c: Handle ELF_E_ALREADY_COMPRESSED,
+	ELF_E_UNKNOWN_COMPRESSION_TYPE, ELF_E_COMPRESS_ERROR and
+	ELF_E_DECOMPRESS_ERROR.
+	* run-elfgetzdata.sh: New test.
+	* run-elfputzdata.sh: Likewise.
+
 2015-10-28  Mark Wielaard  <mjw@redhat.com>
 
 	* run-readelf-z.sh: New test.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 80e4f38..a1c8420 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -52,7 +52,8 @@ check_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
 		  backtrace-data backtrace-dwarf debuglink debugaltlink \
 		  buildid deleted deleted-lib.so aggregate_size vdsosyms \
 		  getsrc_die strptr newdata elfstrtab dwfl-proc-attach \
-		  elfshphehdr elfstrmerge dwelfgnucompressed elfgetchdr
+		  elfshphehdr elfstrmerge dwelfgnucompressed elfgetchdr \
+		  elfgetzdata elfputzdata
 
 asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
 	    asm-tst6 asm-tst7 asm-tst8 asm-tst9
@@ -121,7 +122,8 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
 	run-linkmap-cut.sh run-aggregate-size.sh vdsosyms run-readelf-A.sh \
 	run-getsrc-die.sh run-strptr.sh newdata elfstrtab dwfl-proc-attach \
 	elfshphehdr run-lfs-symbols.sh run-dwelfgnucompressed.sh \
-	run-elfgetchdr.sh
+	run-elfgetchdr.sh \
+	run-elfgetzdata.sh run-elfputzdata.sh
 
 if !BIARCH
 export ELFUTILS_DISABLE_BIARCH = 1
@@ -312,7 +314,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
 	     run-dwelfgnucompressed.sh \
 	     testfile-zgabi32.bz2 testfile-zgabi64.bz2 \
 	     testfile-zgabi32be.bz2 testfile-zgabi64be.bz2 \
-	     run-elfgetchdr.sh
+	     run-elfgetchdr.sh run-elfgetzdata.sh run-elfputzdata.sh
 
 if USE_VALGRIND
 valgrind_cmd='valgrind -q --error-exitcode=1 --run-libc-freeres=no'
@@ -463,6 +465,8 @@ elfshphehdr_LDADD =$(libelf)
 elfstrmerge_LDADD = $(libebl) $(libelf)
 dwelfgnucompressed_LDADD = $(libelf) $(libdw)
 elfgetchdr_LDADD = $(libelf) $(libdw)
+elfgetzdata_LDADD = $(libelf)
+elfputzdata_LDADD = $(libelf)
 
 if GCOV
 check: check-am coverage
diff --git a/tests/elfgetzdata.c b/tests/elfgetzdata.c
new file mode 100644
index 0000000..9176d4f
--- /dev/null
+++ b/tests/elfgetzdata.c
@@ -0,0 +1,101 @@
+/* Copyright (C) 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <stdio.h>
+#include <unistd.h>
+
+
+int
+main (int argc, char *argv[])
+{
+  int result = 0;
+  int cnt;
+
+  elf_version (EV_CURRENT);
+
+  for (cnt = 1; cnt < argc; ++cnt)
+    {
+      int fd = open (argv[cnt], O_RDONLY);
+
+      Elf *elf = elf_begin (fd, ELF_C_READ, NULL);
+      if (elf == NULL)
+	{
+	  printf ("%s not usable %s\n", argv[cnt], elf_errmsg (-1));
+	  result = 1;
+	  close (fd);
+	  continue;
+	}
+
+      /* To get the section names.  */
+      size_t strndx;
+      elf_getshdrstrndx (elf, &strndx);
+
+      Elf_Scn *scn = NULL;
+      while ((scn = elf_nextscn (elf, scn)) != NULL)
+	{
+	  size_t idx = elf_ndxscn (scn);
+	  GElf_Shdr mem;
+	  GElf_Shdr *shdr = gelf_getshdr (scn, &mem);
+	  const char *name = elf_strptr (elf, strndx, shdr->sh_name);
+	  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+	    {
+	      /* Real compressed section.  */
+	      if (elf_compress (scn, 0) != 0)
+		{
+		  printf ("elf_compress failed for section %zd: %s\n",
+			  idx, elf_errmsg (-1));
+		  return -1;
+		}
+	      Elf_Data *d = elf_getdata (scn, NULL);
+	      printf ("%zd: %s, ELF compressed, size: %zx\n",
+		      idx, name, d->d_size);
+	    }
+	  else
+	    {
+	      /* Maybe an old GNU compressed .z section?  */
+	      if (name[0] == '.' && name[1] == 'z')
+		{
+		  if (elf_compress_gnu (scn, 0) != 0)
+		    {
+		      printf ("elf_compress_gnu failed for section %zd: %s\n",
+			      idx, elf_errmsg (-1));
+		      return -1;
+		    }
+		  Elf_Data *d = elf_getdata (scn, NULL);
+		  printf ("%zd: %s, GNU compressed, size: %zx\n",
+			  idx, name, d->d_size);
+		}
+	      else
+		printf ("%zd: %s, NOT compressed\n", idx, name);
+	    }
+	}
+
+      elf_end (elf);
+      close (fd);
+    }
+
+  return result;
+}
diff --git a/tests/elfputzdata.c b/tests/elfputzdata.c
new file mode 100644
index 0000000..e2083ac
--- /dev/null
+++ b/tests/elfputzdata.c
@@ -0,0 +1,201 @@
+/* Copyright (C) 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libelf.h>
+#include <gelf.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+int
+main (int argc, char *argv[])
+{
+  int result = 0;
+  int cnt;
+
+  if (argc < 3
+      || (strcmp (argv[1], "elf") != 0
+	  && strcmp (argv[1], "gnu") != 0))
+    {
+      printf ("Usage: (elf|gnu) files...\n");
+      return -1;
+    }
+
+  int gnu;
+  if (strcmp (argv[1], "gnu") == 0)
+    gnu = 1;
+  else
+    gnu = 0;
+
+  elf_version (EV_CURRENT);
+
+  for (cnt = 2; cnt < argc; ++cnt)
+    {
+      int fd = open (argv[cnt], O_RDONLY);
+
+      Elf *elf = elf_begin (fd, ELF_C_READ, NULL);
+      if (elf == NULL)
+	{
+	  printf ("%s not usable %s\n", argv[cnt], elf_errmsg (-1));
+	  result = 1;
+	  close (fd);
+	  continue;
+	}
+
+      /* To get the section names.  */
+      size_t strndx;
+      elf_getshdrstrndx (elf, &strndx);
+
+      Elf_Scn *scn = NULL;
+      while ((scn = elf_nextscn (elf, scn)) != NULL)
+	{
+	  size_t idx = elf_ndxscn (scn);
+	  GElf_Shdr mem;
+	  GElf_Shdr *shdr = gelf_getshdr (scn, &mem);
+	  const char *name = elf_strptr (elf, strndx, shdr->sh_name);
+	  if (idx == strndx)
+	    {
+	      printf ("Not compressing section string table %zd\n", idx);
+	    }
+	  else if (shdr->sh_type == SHT_NOBITS
+	      || (shdr->sh_flags & SHF_ALLOC) != 0)
+	    {
+	      printf ("Cannot compress %zd %s\n", idx, name);
+	    }
+	  else if ((shdr->sh_flags & SHF_COMPRESSED) != 0
+		   || strncmp (name, ".zdebug", strlen (".zdebug") == 0))
+	    {
+	      printf ("Already compressed %zd %s\n", idx, name);
+	    }
+	  else
+	    {
+	      size_t orig_size = shdr->sh_size;
+	      printf ("Lets compress %zd %s, size: %zd\n",
+		      idx, name, shdr->sh_size);
+	      Elf_Data *d = elf_getdata (scn, NULL);
+	      if (d == NULL)
+		{
+		  printf ("Couldn't get orig data for section %zd\n", idx);
+		  return -1;
+		}
+	      /* Make a copy so we can compare after
+		 compression/decompression.  */
+	      if (d->d_size != orig_size)
+		{
+		  printf ("Unexpected data size for orig section %zd\n", idx);
+		  return -1;
+		}
+	      char *orig_buf = malloc (d->d_size);
+	      if (orig_size > 0 && orig_buf == NULL)
+		{
+		  printf ("No memory to copy section %zd data\n", idx);
+		  return -1;
+		}
+	      if (orig_size > 0)
+		memcpy (orig_buf, d->d_buf, orig_size);
+
+	      if (gnu)
+		{
+		  if (elf_compress_gnu (scn, 1) == -1)
+		    {
+		      printf ("elf_compress_gnu failed for section %zd: %s\n",
+			      idx, elf_errmsg (-1));
+		      return -1;
+		    }
+		}
+	      else
+		{
+		  if (elf_compress (scn, ELFCOMPRESS_ZLIB) == -1)
+		    {
+		      printf ("elf_compress failed for section %zd: %s\n",
+			      idx, elf_errmsg (-1));
+		      return -1;
+		    }
+		}
+	      GElf_Shdr newmem;
+	      GElf_Shdr *newshdr = gelf_getshdr (scn, &newmem);
+	      size_t new_size = newshdr->sh_size;
+	      d = elf_getdata (scn, NULL);
+	      // Don't check this, might depend on zlib implementation.
+	      // fprintf (stderr, "  new_size: %zd\n", new_size);
+	      if (d->d_size != new_size)
+		{
+		  printf ("Unexpected data size for compressed section %zd\n",
+			  idx);
+		  return -1;
+		}
+	      if (new_size == orig_size
+		  && memcmp (orig_buf, d->d_buf, orig_size) == 0)
+		{
+		  printf ("section %zd didn't compress\n", idx);
+		  return -1;
+		}
+
+	      if (gnu)
+		{
+		  if (elf_compress_gnu (scn, 0) == -1)
+		    {
+		      printf ("elf_[un]compress_gnu failed for section %zd: %s\n",
+			      idx, elf_errmsg (-1));
+		      return -1;
+		    }
+		}
+	      else
+		{
+		  if (elf_compress (scn, 0) == -1)
+		    {
+		      printf ("elf_[un]compress failed for section %zd: %s\n",
+			      idx, elf_errmsg (-1));
+		      return -1;
+		    }
+		}
+	      GElf_Shdr newermem;
+	      GElf_Shdr *newershdr = gelf_getshdr (scn, &newermem);
+	      size_t newer_size = newershdr->sh_size;
+	      d = elf_getdata (scn, NULL);
+	      // fprintf (stderr, "  newer_size: %zd\n", newer_size);
+	      if (d->d_size != newer_size)
+		{
+		  printf ("Unexpected data size for compressed section %zd\n",
+			  idx);
+		  return -1;
+		}
+	      if (newer_size != orig_size
+		  && memcmp (orig_buf, d->d_buf, orig_size) != 0)
+		{
+		  printf ("section %zd didn't correctly uncompress\n", idx);
+		  return -1;
+		}
+	      free (orig_buf);
+	    }
+	}
+
+      elf_end (elf);
+      close (fd);
+    }
+
+  return result;
+}
diff --git a/tests/msg_tst.c b/tests/msg_tst.c
index b10c7c5..7f20d10 100644
--- a/tests/msg_tst.c
+++ b/tests/msg_tst.c
@@ -75,7 +75,11 @@ static struct
 and core files" },
     { ELF_E_NO_PHDR, "file has no program header" },
     { ELF_E_INVALID_OFFSET, "invalid offset" },
-    { ELF_E_NOT_COMPRESSED, "section does not contain compressed data" }
+    { ELF_E_NOT_COMPRESSED, "section does not contain compressed data" },
+    { ELF_E_ALREADY_COMPRESSED, "section contains compressed data" },
+    { ELF_E_UNKNOWN_COMPRESSION_TYPE, "unknown compression type" },
+    { ELF_E_COMPRESS_ERROR, "cannot compress data" },
+    { ELF_E_DECOMPRESS_ERROR, "cannot decompress data" }
   };
 
 
diff --git a/tests/run-elfgetzdata.sh b/tests/run-elfgetzdata.sh
new file mode 100755
index 0000000..91e60be
--- /dev/null
+++ b/tests/run-elfgetzdata.sh
@@ -0,0 +1,122 @@
+#! /bin/sh
+# Copyright (C) 2015 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+# See run-elfgetchdr.sh for testfiles.
+
+testfiles testfile-zgnu64
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata testfile-zgnu64 <<\EOF
+1: .text, NOT compressed
+2: .zdebug_aranges, GNU compressed, size: 60
+3: .zdebug_info, GNU compressed, size: aa
+4: .debug_abbrev, NOT compressed
+5: .zdebug_line, GNU compressed, size: 8d
+6: .shstrtab, NOT compressed
+7: .symtab, NOT compressed
+8: .strtab, NOT compressed
+EOF
+
+testfiles testfile-zgnu64be
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata testfile-zgnu64be <<\EOF
+1: .text, NOT compressed
+2: .eh_frame, NOT compressed
+3: .zdebug_aranges, GNU compressed, size: 60
+4: .zdebug_info, GNU compressed, size: 7e
+5: .debug_abbrev, NOT compressed
+6: .zdebug_line, GNU compressed, size: 8d
+7: .shstrtab, NOT compressed
+8: .symtab, NOT compressed
+9: .strtab, NOT compressed
+EOF
+
+testfiles testfile-zgabi64
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata testfile-zgabi64 <<\EOF
+1: .text, NOT compressed
+2: .debug_aranges, ELF compressed, size: 60
+3: .debug_info, ELF compressed, size: aa
+4: .debug_abbrev, NOT compressed
+5: .debug_line, ELF compressed, size: 8d
+6: .shstrtab, NOT compressed
+7: .symtab, NOT compressed
+8: .strtab, NOT compressed
+EOF
+
+testfiles testfile-zgabi64be
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata testfile-zgabi64be <<\EOF
+1: .text, NOT compressed
+2: .eh_frame, NOT compressed
+3: .debug_aranges, ELF compressed, size: 60
+4: .debug_info, ELF compressed, size: 7e
+5: .debug_abbrev, NOT compressed
+6: .debug_line, ELF compressed, size: 8d
+7: .shstrtab, NOT compressed
+8: .symtab, NOT compressed
+9: .strtab, NOT compressed
+EOF
+
+testfiles testfile-zgnu32
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata testfile-zgnu32 <<\EOF
+1: .text, NOT compressed
+2: .zdebug_aranges, GNU compressed, size: 40
+3: .zdebug_info, GNU compressed, size: 9a
+4: .debug_abbrev, NOT compressed
+5: .zdebug_line, GNU compressed, size: 85
+6: .shstrtab, NOT compressed
+7: .symtab, NOT compressed
+8: .strtab, NOT compressed
+EOF
+
+testfiles testfile-zgnu32be
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata testfile-zgnu32be <<\EOF
+1: .text, NOT compressed
+2: .eh_frame, NOT compressed
+3: .zdebug_aranges, GNU compressed, size: 40
+4: .zdebug_info, GNU compressed, size: 6e
+5: .debug_abbrev, NOT compressed
+6: .zdebug_line, GNU compressed, size: 85
+7: .shstrtab, NOT compressed
+8: .symtab, NOT compressed
+9: .strtab, NOT compressed
+EOF
+
+testfiles testfile-zgabi32
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata testfile-zgabi32 <<\EOF
+1: .text, NOT compressed
+2: .debug_aranges, ELF compressed, size: 40
+3: .debug_info, ELF compressed, size: 9a
+4: .debug_abbrev, NOT compressed
+5: .debug_line, ELF compressed, size: 85
+6: .shstrtab, NOT compressed
+7: .symtab, NOT compressed
+8: .strtab, NOT compressed
+EOF
+
+testfiles testfile-zgabi32be
+testrun_compare ${abs_top_builddir}/tests/elfgetzdata testfile-zgabi32be <<\EOF
+1: .text, NOT compressed
+2: .eh_frame, NOT compressed
+3: .debug_aranges, ELF compressed, size: 40
+4: .debug_info, ELF compressed, size: 6e
+5: .debug_abbrev, NOT compressed
+6: .debug_line, ELF compressed, size: 85
+7: .shstrtab, NOT compressed
+8: .symtab, NOT compressed
+9: .strtab, NOT compressed
+EOF
+
+exit 0
diff --git a/tests/run-elfputzdata.sh b/tests/run-elfputzdata.sh
new file mode 100755
index 0000000..e9a352e
--- /dev/null
+++ b/tests/run-elfputzdata.sh
@@ -0,0 +1,340 @@
+#! /bin/sh
+# Copyright (C) 2015 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+# Random ELF32 testfile
+testfiles testfile4
+
+testrun_compare ${abs_top_builddir}/tests/elfputzdata gnu testfile4 <<\EOF
+Cannot compress 1 .interp
+Cannot compress 2 .note.ABI-tag
+Cannot compress 3 .hash
+Cannot compress 4 .dynsym
+Cannot compress 5 .dynstr
+Cannot compress 6 .gnu.version
+Cannot compress 7 .gnu.version_r
+Cannot compress 8 .rel.got
+Cannot compress 9 .rel.plt
+Cannot compress 10 .init
+Cannot compress 11 .plt
+Cannot compress 12 .text
+Cannot compress 13 .fini
+Cannot compress 14 .rodata
+Cannot compress 15 .data
+Cannot compress 16 .eh_frame
+Cannot compress 17 .gcc_except_table
+Cannot compress 18 .ctors
+Cannot compress 19 .dtors
+Cannot compress 20 .got
+Cannot compress 21 .dynamic
+Lets compress 22 .sbss, size: 0
+Cannot compress 23 .bss
+Lets compress 24 .stab, size: 21540
+Lets compress 25 .stabstr, size: 57297
+Lets compress 26 .comment, size: 648
+Lets compress 27 .debug_aranges, size: 56
+Lets compress 28 .debug_pubnames, size: 93
+Lets compress 29 .debug_info, size: 960
+Lets compress 30 .debug_abbrev, size: 405
+Lets compress 31 .debug_line, size: 189
+Lets compress 32 .note, size: 240
+Not compressing section string table 33
+Lets compress 34 .symtab, size: 5488
+Lets compress 35 .strtab, size: 5727
+EOF
+
+testrun_compare ${abs_top_builddir}/tests/elfputzdata elf testfile4 <<\EOF
+Cannot compress 1 .interp
+Cannot compress 2 .note.ABI-tag
+Cannot compress 3 .hash
+Cannot compress 4 .dynsym
+Cannot compress 5 .dynstr
+Cannot compress 6 .gnu.version
+Cannot compress 7 .gnu.version_r
+Cannot compress 8 .rel.got
+Cannot compress 9 .rel.plt
+Cannot compress 10 .init
+Cannot compress 11 .plt
+Cannot compress 12 .text
+Cannot compress 13 .fini
+Cannot compress 14 .rodata
+Cannot compress 15 .data
+Cannot compress 16 .eh_frame
+Cannot compress 17 .gcc_except_table
+Cannot compress 18 .ctors
+Cannot compress 19 .dtors
+Cannot compress 20 .got
+Cannot compress 21 .dynamic
+Lets compress 22 .sbss, size: 0
+Cannot compress 23 .bss
+Lets compress 24 .stab, size: 21540
+Lets compress 25 .stabstr, size: 57297
+Lets compress 26 .comment, size: 648
+Lets compress 27 .debug_aranges, size: 56
+Lets compress 28 .debug_pubnames, size: 93
+Lets compress 29 .debug_info, size: 960
+Lets compress 30 .debug_abbrev, size: 405
+Lets compress 31 .debug_line, size: 189
+Lets compress 32 .note, size: 240
+Not compressing section string table 33
+Lets compress 34 .symtab, size: 5488
+Lets compress 35 .strtab, size: 5727
+EOF
+
+# Random ELF64 testfile
+testfiles testfile12
+
+testrun_compare ${abs_top_builddir}/tests/elfputzdata gnu testfile12 <<\EOF
+Cannot compress 1 .hash
+Cannot compress 2 .dynsym
+Cannot compress 3 .dynstr
+Cannot compress 4 .gnu.version
+Cannot compress 5 .gnu.version_r
+Cannot compress 6 .rela.dyn
+Cannot compress 7 .rela.plt
+Cannot compress 8 .init
+Cannot compress 9 .plt
+Cannot compress 10 .text
+Cannot compress 11 .fini
+Cannot compress 12 .rodata
+Cannot compress 13 .eh_frame_hdr
+Cannot compress 14 .eh_frame
+Cannot compress 15 .data
+Cannot compress 16 .dynamic
+Cannot compress 17 .ctors
+Cannot compress 18 .dtors
+Cannot compress 19 .jcr
+Cannot compress 20 .got
+Cannot compress 21 .bss
+Lets compress 22 .comment, size: 246
+Lets compress 23 .debug_aranges, size: 192
+Lets compress 24 .debug_pubnames, size: 26
+Lets compress 25 .debug_info, size: 3468
+Lets compress 26 .debug_abbrev, size: 341
+Lets compress 27 .debug_line, size: 709
+Lets compress 28 .debug_frame, size: 56
+Lets compress 29 .debug_str, size: 2235
+Lets compress 30 .debug_macinfo, size: 10518
+Not compressing section string table 31
+Lets compress 32 .symtab, size: 1944
+Lets compress 33 .strtab, size: 757
+EOF
+
+testrun_compare ${abs_top_builddir}/tests/elfputzdata elf testfile12 <<\EOF
+Cannot compress 1 .hash
+Cannot compress 2 .dynsym
+Cannot compress 3 .dynstr
+Cannot compress 4 .gnu.version
+Cannot compress 5 .gnu.version_r
+Cannot compress 6 .rela.dyn
+Cannot compress 7 .rela.plt
+Cannot compress 8 .init
+Cannot compress 9 .plt
+Cannot compress 10 .text
+Cannot compress 11 .fini
+Cannot compress 12 .rodata
+Cannot compress 13 .eh_frame_hdr
+Cannot compress 14 .eh_frame
+Cannot compress 15 .data
+Cannot compress 16 .dynamic
+Cannot compress 17 .ctors
+Cannot compress 18 .dtors
+Cannot compress 19 .jcr
+Cannot compress 20 .got
+Cannot compress 21 .bss
+Lets compress 22 .comment, size: 246
+Lets compress 23 .debug_aranges, size: 192
+Lets compress 24 .debug_pubnames, size: 26
+Lets compress 25 .debug_info, size: 3468
+Lets compress 26 .debug_abbrev, size: 341
+Lets compress 27 .debug_line, size: 709
+Lets compress 28 .debug_frame, size: 56
+Lets compress 29 .debug_str, size: 2235
+Lets compress 30 .debug_macinfo, size: 10518
+Not compressing section string table 31
+Lets compress 32 .symtab, size: 1944
+Lets compress 33 .strtab, size: 757
+EOF
+
+# Random ELF64BE testfile
+testfiles testfileppc64
+
+testrun_compare ${abs_top_builddir}/tests/elfputzdata gnu testfileppc64 <<\EOF
+Cannot compress 1 .interp
+Cannot compress 2 .note.ABI-tag
+Cannot compress 3 .note.gnu.build-id
+Cannot compress 4 .gnu.hash
+Cannot compress 5 .dynsym
+Cannot compress 6 .dynstr
+Cannot compress 7 .gnu.version
+Cannot compress 8 .gnu.version_r
+Cannot compress 9 .rela.plt
+Cannot compress 10 .init
+Cannot compress 11 .text
+Cannot compress 12 .fini
+Cannot compress 13 .rodata
+Cannot compress 14 .eh_frame_hdr
+Cannot compress 15 .eh_frame
+Cannot compress 16 .init_array
+Cannot compress 17 .fini_array
+Cannot compress 18 .jcr
+Cannot compress 19 .dynamic
+Cannot compress 20 .data
+Cannot compress 21 .opd
+Cannot compress 22 .got
+Cannot compress 23 .plt
+Cannot compress 24 .bss
+Lets compress 25 .comment, size: 88
+Lets compress 26 .debug_aranges, size: 96
+Lets compress 27 .debug_info, size: 363
+Lets compress 28 .debug_abbrev, size: 315
+Lets compress 29 .debug_line, size: 119
+Lets compress 30 .debug_frame, size: 96
+Lets compress 31 .debug_str, size: 174
+Lets compress 32 .debug_loc, size: 171
+Lets compress 33 .debug_ranges, size: 32
+Not compressing section string table 34
+Lets compress 35 .symtab, size: 1800
+Lets compress 36 .strtab, size: 602
+EOF
+
+testrun_compare ${abs_top_builddir}/tests/elfputzdata elf testfileppc64 <<\EOF
+Cannot compress 1 .interp
+Cannot compress 2 .note.ABI-tag
+Cannot compress 3 .note.gnu.build-id
+Cannot compress 4 .gnu.hash
+Cannot compress 5 .dynsym
+Cannot compress 6 .dynstr
+Cannot compress 7 .gnu.version
+Cannot compress 8 .gnu.version_r
+Cannot compress 9 .rela.plt
+Cannot compress 10 .init
+Cannot compress 11 .text
+Cannot compress 12 .fini
+Cannot compress 13 .rodata
+Cannot compress 14 .eh_frame_hdr
+Cannot compress 15 .eh_frame
+Cannot compress 16 .init_array
+Cannot compress 17 .fini_array
+Cannot compress 18 .jcr
+Cannot compress 19 .dynamic
+Cannot compress 20 .data
+Cannot compress 21 .opd
+Cannot compress 22 .got
+Cannot compress 23 .plt
+Cannot compress 24 .bss
+Lets compress 25 .comment, size: 88
+Lets compress 26 .debug_aranges, size: 96
+Lets compress 27 .debug_info, size: 363
+Lets compress 28 .debug_abbrev, size: 315
+Lets compress 29 .debug_line, size: 119
+Lets compress 30 .debug_frame, size: 96
+Lets compress 31 .debug_str, size: 174
+Lets compress 32 .debug_loc, size: 171
+Lets compress 33 .debug_ranges, size: 32
+Not compressing section string table 34
+Lets compress 35 .symtab, size: 1800
+Lets compress 36 .strtab, size: 602
+EOF
+
+# Random ELF32BE testfile
+testfiles testfileppc32
+
+testrun_compare ${abs_top_builddir}/tests/elfputzdata gnu testfileppc32 <<\EOF
+Cannot compress 1 .interp
+Cannot compress 2 .note.ABI-tag
+Cannot compress 3 .note.gnu.build-id
+Cannot compress 4 .gnu.hash
+Cannot compress 5 .dynsym
+Cannot compress 6 .dynstr
+Cannot compress 7 .gnu.version
+Cannot compress 8 .gnu.version_r
+Cannot compress 9 .rela.dyn
+Cannot compress 10 .rela.plt
+Cannot compress 11 .init
+Cannot compress 12 .text
+Cannot compress 13 .fini
+Cannot compress 14 .rodata
+Cannot compress 15 .eh_frame_hdr
+Cannot compress 16 .eh_frame
+Cannot compress 17 .init_array
+Cannot compress 18 .fini_array
+Cannot compress 19 .jcr
+Cannot compress 20 .got2
+Cannot compress 21 .dynamic
+Cannot compress 22 .got
+Cannot compress 23 .plt
+Cannot compress 24 .data
+Cannot compress 25 .sdata
+Cannot compress 26 .bss
+Lets compress 27 .comment, size: 88
+Lets compress 28 .debug_aranges, size: 64
+Lets compress 29 .debug_info, size: 319
+Lets compress 30 .debug_abbrev, size: 318
+Lets compress 31 .debug_line, size: 109
+Lets compress 32 .debug_frame, size: 64
+Lets compress 33 .debug_str, size: 179
+Lets compress 34 .debug_loc, size: 99
+Lets compress 35 .debug_ranges, size: 16
+Not compressing section string table 36
+Lets compress 37 .symtab, size: 1232
+Lets compress 38 .strtab, size: 569
+EOF
+
+testrun_compare ${abs_top_builddir}/tests/elfputzdata elf testfileppc32 <<\EOF
+Cannot compress 1 .interp
+Cannot compress 2 .note.ABI-tag
+Cannot compress 3 .note.gnu.build-id
+Cannot compress 4 .gnu.hash
+Cannot compress 5 .dynsym
+Cannot compress 6 .dynstr
+Cannot compress 7 .gnu.version
+Cannot compress 8 .gnu.version_r
+Cannot compress 9 .rela.dyn
+Cannot compress 10 .rela.plt
+Cannot compress 11 .init
+Cannot compress 12 .text
+Cannot compress 13 .fini
+Cannot compress 14 .rodata
+Cannot compress 15 .eh_frame_hdr
+Cannot compress 16 .eh_frame
+Cannot compress 17 .init_array
+Cannot compress 18 .fini_array
+Cannot compress 19 .jcr
+Cannot compress 20 .got2
+Cannot compress 21 .dynamic
+Cannot compress 22 .got
+Cannot compress 23 .plt
+Cannot compress 24 .data
+Cannot compress 25 .sdata
+Cannot compress 26 .bss
+Lets compress 27 .comment, size: 88
+Lets compress 28 .debug_aranges, size: 64
+Lets compress 29 .debug_info, size: 319
+Lets compress 30 .debug_abbrev, size: 318
+Lets compress 31 .debug_line, size: 109
+Lets compress 32 .debug_frame, size: 64
+Lets compress 33 .debug_str, size: 179
+Lets compress 34 .debug_loc, size: 99
+Lets compress 35 .debug_ranges, size: 16
+Not compressing section string table 36
+Lets compress 37 .symtab, size: 1232
+Lets compress 38 .strtab, size: 569
+EOF
+
+exit 0
-- 
1.8.3.1

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]