summaryrefslogtreecommitdiffstats
path: root/libelf
diff options
context:
space:
mode:
authorChih-Hung Hsieh <chh@google.com>2016-01-25 10:12:35 -0800
committerChih-Hung Hsieh <chh@google.com>2016-01-25 11:25:11 -0800
commit3ad5c39aed9ad8b3847015a8349053b7a1ac094f (patch)
tree482d3d6644a743b44c3fc79c95e2b6b5e30e6ab2 /libelf
parent97c644e689be3b7b3b7898513a38ead399d2285a (diff)
parent203f0a3eec8c630c5183fb9984d66339c1ea3c31 (diff)
downloadandroid_external_elfutils-3ad5c39aed9ad8b3847015a8349053b7a1ac094f.tar.gz
android_external_elfutils-3ad5c39aed9ad8b3847015a8349053b7a1ac094f.tar.bz2
android_external_elfutils-3ad5c39aed9ad8b3847015a8349053b7a1ac094f.zip
Merge upstream 0.165 SHA '203f0a3'
* git merge 203f0a3 * See all upstream changes since the previous merge in branch aosp/upstream-master: git diff 9d1e236..203f0a3 * Android relevant upstream changes: * Version number changed from 0.164 to 0.165 * libelf now depends on zlib * Changed version number in generated files: version.h, config.h * No change to generated files: libdw/known-dwarf.h * Updated libelf/Android.mk: * added new source files: gelf_getchdr.c elf{32,64}_getchdr.c elf_compress.c * added LOCAL_STATIC_LIBRARIES := libz Change-Id: Ieb306d84ffcaf680ad6e74da28fcc8efbf00592a
Diffstat (limited to 'libelf')
-rwxr-xr-xlibelf/Android.mk8
-rw-r--r--libelf/ChangeLog80
-rw-r--r--libelf/Makefile.am9
-rw-r--r--libelf/abstract.h20
-rw-r--r--libelf/chdr_xlate.h33
-rw-r--r--libelf/elf32_getchdr.c83
-rw-r--r--libelf/elf32_getshdr.c5
-rw-r--r--libelf/elf32_updatenull.c23
-rw-r--r--libelf/elf64_getchdr.c30
-rw-r--r--libelf/elf_begin.c2
-rw-r--r--libelf/elf_compress.c516
-rw-r--r--libelf/elf_compress_gnu.c208
-rw-r--r--libelf/elf_end.c11
-rw-r--r--libelf/elf_error.c44
-rw-r--r--libelf/elf_getdata.c41
-rw-r--r--libelf/elf_strptr.c51
-rw-r--r--libelf/exttypes.h4
-rw-r--r--libelf/gelf.h8
-rw-r--r--libelf/gelf_fsize.c1
-rw-r--r--libelf/gelf_getchdr.c69
-rw-r--r--libelf/gelf_xlate.c4
-rw-r--r--libelf/gelf_xlate.h1
-rw-r--r--libelf/libelf.h100
-rw-r--r--libelf/libelf.map10
-rw-r--r--libelf/libelfP.h35
25 files changed, 1361 insertions, 35 deletions
diff --git a/libelf/Android.mk b/libelf/Android.mk
index 1c0195c4..53d47be4 100755
--- a/libelf/Android.mk
+++ b/libelf/Android.mk
@@ -17,6 +17,7 @@ LOCAL_PATH := $(call my-dir)
LIBELF_SRC_FILES := \
elf32_checksum.c \
elf32_fsize.c \
+ elf32_getchdr.c \
elf32_getehdr.c \
elf32_getphdr.c \
elf32_getshdr.c \
@@ -29,6 +30,7 @@ LIBELF_SRC_FILES := \
elf32_xlatetom.c \
elf64_checksum.c \
elf64_fsize.c \
+ elf64_getchdr.c \
elf64_getehdr.c \
elf64_getphdr.c \
elf64_getshdr.c \
@@ -42,6 +44,7 @@ LIBELF_SRC_FILES := \
elf_begin.c \
elf_clone.c \
elf_cntl.c \
+ elf_compress.c \
elf_end.c \
elf_error.c \
elf_fill.c \
@@ -82,6 +85,7 @@ LIBELF_SRC_FILES := \
gelf_checksum.c \
gelf_fsize.c \
gelf_getauxv.c \
+ gelf_getchdr.c \
gelf_getclass.c \
gelf_getdyn.c \
gelf_getehdr.c \
@@ -148,6 +152,8 @@ LOCAL_CFLAGS += -Wno-pointer-arith
LOCAL_MODULE := libelf
+LOCAL_STATIC_LIBRARIES := libz
+
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -171,6 +177,8 @@ LOCAL_C_INCLUDES := \
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../bionic-fixup
+LOCAL_STATIC_LIBRARIES := libz
+
LOCAL_CFLAGS += -DHAVE_CONFIG_H -std=gnu99 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64
# to suppress the "pointer of type ‘void *’ used in arithmetic" warning
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index fbe8e3ae..afe6a6a5 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,83 @@
+2016-01-22 Chih-Hung Hsieh <chh@google.com>
+
+ * elf_compress.c (__libelf_compress): Move nested function
+ 'do_deflate_cleanup' to file scope to compile with clang.
+ * elf_strptr.c (elf_strptr): Move nested function 'get_zdata'
+ to file scope to compile with clang.
+
+2016-01-13 Mark Wielaard <mjw@redhat.com>
+
+ * libelf.h: Check SHF_COMPRESSED is defined. If not define it and the
+ associated ELF compression types/defines.
+
+2015-11-26 Mark Wielaard <mjw@redhat.com>
+
+ * elf_compress.c (__libelf_decompress_elf): New function, extracted
+ from...
+ (elf_compress): here. Check zdata_base use __libelf_decompress_elf.
+ * elf_strptr.c (elf_strptr): If SHF_COMPRESSED check, uncompress and
+ use zdata.
+ * libelfP.h (struct Elf_Scn): Add zdata_size and zdata_align.
+ (__libelf_decompress_elf): New internal function definition.
+
+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_begin.c (file_read_elf): Make a writable copy of the shdrs
+ for ELF_C_READ_MMAP.
+ * 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.
+ * elf32_updatenull.c (updatenull_wrlock): Check sh_entsize against
+ uncompressed section data size if SHF_COMPRESSED.
+ * elf32_getshdr.c (load_shdr_wrlock): Adjust assert to account for
+ ELF_C_READ_MMAP.
+ * 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 and gelf_getchdr.c.
+ (noinst_HEADERS): Add chdr_xlate.h.
+ * abstract.h: Define Chdr32 and Chdr64.
+ * chdr_xlate.h: New file.
+ * elf32_getchdr.c: New file.
+ * elf64_getchdr.c: New file.
+ * elf_error.c: Add ELF_E_NOT_COMPRESSED, ELF_E_INVALID_SECTION_TYPE
+ and ELF_E_INVALID_SECTION_FLAGS.
+ * elf_getdata.c (__libelf_set_rawdata_wrlock): Set d_type to
+ ELF_T_CHDR for SHF_COMPRESSED sections.
+ * exttypes.h: Add Chdr32 and Chdr64.
+ * gelf.h (GElf_Chdr): New typedef.
+ (gelf_getchdr): New function definition.
+ * gelf_fsize.c (__libelf_type_sizes): Add ELF_T_CHDR.
+ * gelf_getchdr.c: New file.
+ * gelf_xlate.c (__elf_xfctstom): Add ELF_T_CHDR cvt_chdr.
+ * gelf_xlate.h: Add Chdr.
+ * libelf.h (Elf_Type): Add ELF_T_CHDR.
+ (elf32_getchdr): New function definition.
+ (elf64_getchdr): Likewise.
+ * libelf.map (ELFUTILS_1.7): New sections add elf32_getchdr,
+ elf64_getchdr and gelf_getchdr.
+ * libelfP.h: Add ELF_E_NOT_COMPRESSED, ELF_E_INVALID_SECTION_TYPE
+ and ELF_E_INVALID_SECTION_FLAGS.
+
2015-10-16 Mark Wielaard <mjw@redhat.com>
* Makefile.am (libelf_so_LDLIBS): Add -lz.
diff --git a/libelf/Makefile.am b/libelf/Makefile.am
index 4a4131c1..167a8322 100644
--- a/libelf/Makefile.am
+++ b/libelf/Makefile.am
@@ -1,6 +1,6 @@
## Process this file with automake to create Makefile.in
##
-## Copyright (C) 1996-2010 Red Hat, Inc.
+## Copyright (C) 1996-2010, 2015 Red Hat, Inc.
## This file is part of elfutils.
##
## This file is free software; you can redistribute it and/or modify
@@ -88,7 +88,9 @@ libelf_a_SOURCES = elf_version.c elf_hash.c elf_error.c elf_fill.c \
elf32_offscn.c elf64_offscn.c gelf_offscn.c \
elf_getaroff.c \
elf_gnu_hash.c \
- elf_scnshndx.c
+ elf_scnshndx.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)
@@ -118,7 +120,8 @@ uninstall: uninstall-am
rm -f $(DESTDIR)$(libdir)/libelf.so
noinst_HEADERS = elf.h abstract.h common.h exttypes.h gelf_xlate.h libelfP.h \
- version_xlate.h gnuhash_xlate.h note_xlate.h dl-hash.h
+ version_xlate.h gnuhash_xlate.h note_xlate.h dl-hash.h \
+ chdr_xlate.h
EXTRA_DIST = libelf.map
CLEANFILES += $(am_libelf_pic_a_OBJECTS) libelf.so.$(VERSION)
diff --git a/libelf/abstract.h b/libelf/abstract.h
index 53713eec..d4515f27 100644
--- a/libelf/abstract.h
+++ b/libelf/abstract.h
@@ -1,5 +1,5 @@
/* Abstract description of component ELF types.
- Copyright (C) 1998, 1999, 2000, 2002, 2004, 2007 Red Hat, Inc.
+ Copyright (C) 1998, 1999, 2000, 2002, 2004, 2007, 2015 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 1998.
@@ -310,3 +310,21 @@ START (64, auxv_t, Ext##auxv_t) \
TYPE_XLATE (Elf64_cvt_Addr1 (&tdest->a_un.a_val, &tsrc->a_un.a_val);) \
TYPE_EXTRA (} a_un;) \
END (64, Ext##auxv_t)
+
+/* Note that there is actual compression data right after the Chdr.
+ So we also have a separate conversion function for the whole
+ section. */
+#define Chdr32(Ext) \
+START (32, Chdr, Ext##Chdr) \
+ TYPE_NAME (ElfW2(32, Ext##Word), ch_type) \
+ TYPE_NAME (ElfW2(32, Ext##Word), ch_size) \
+ TYPE_NAME (ElfW2(32, Ext##Word), ch_addralign) \
+END (32, Ext##Chdr)
+
+#define Chdr64(Ext) \
+START (64, Chdr, Ext##Chdr) \
+ TYPE_NAME (ElfW2(64, Ext##Word), ch_type) \
+ TYPE_NAME (ElfW2(64, Ext##Word), ch_reserved) \
+ TYPE_NAME (ElfW2(64, Ext##Xword), ch_size) \
+ TYPE_NAME (ElfW2(64, Ext##Xword), ch_addralign) \
+END (64, Ext##Chdr)
diff --git a/libelf/chdr_xlate.h b/libelf/chdr_xlate.h
new file mode 100644
index 00000000..70782b43
--- /dev/null
+++ b/libelf/chdr_xlate.h
@@ -0,0 +1,33 @@
+#include "common.h"
+
+/* These functions convert a while section, one Chdr plus compression data. */
+
+static void
+Elf32_cvt_chdr (void *dest, const void *src, size_t len, int encode)
+{
+ if (len == 0)
+ return;
+
+ /* Move everything over, if necessary, we only need to xlate the
+ header, not the compressed data following it. */
+ if (dest != src)
+ memmove (dest, src, len);
+
+ if (len >= sizeof (Elf32_Chdr))
+ Elf32_cvt_Chdr (dest, src, sizeof (Elf32_Chdr), encode);
+}
+
+static void
+Elf64_cvt_chdr (void *dest, const void *src, size_t len, int encode)
+{
+ if (len == 0)
+ return;
+
+ /* Move everything over, if necessary, we only need to xlate the
+ header, not the compressed data following it. */
+ if (dest != src)
+ memmove (dest, src, len);
+
+ if (len >= sizeof (Elf64_Chdr))
+ Elf64_cvt_Chdr (dest, src, sizeof (Elf64_Chdr), encode);
+}
diff --git a/libelf/elf32_getchdr.c b/libelf/elf32_getchdr.c
new file mode 100644
index 00000000..982a614c
--- /dev/null
+++ b/libelf/elf32_getchdr.c
@@ -0,0 +1,83 @@
+/* Return section compression header.
+ 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"
+
+#ifndef LIBELFBITS
+# define LIBELFBITS 32
+#endif
+
+
+ElfW2(LIBELFBITS,Chdr) *
+elfw2(LIBELFBITS,getchdr) (Elf_Scn *scn)
+{
+ ElfW2(LIBELFBITS,Shdr) *shdr = elfw2(LIBELFBITS,getshdr) (scn);
+ if (shdr == NULL)
+ return NULL;
+
+ /* Must have SHF_COMPRESSED flag set. Allocated or no bits sections
+ can never be compressed. */
+ if ((shdr->sh_flags & SHF_ALLOC) != 0)
+ {
+ __libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
+ return NULL;
+ }
+
+ if (shdr->sh_type == SHT_NULL
+ || shdr->sh_type == SHT_NOBITS)
+ {
+ __libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
+ return NULL;
+ }
+
+ if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
+ {
+ __libelf_seterrno (ELF_E_NOT_COMPRESSED);
+ return NULL;
+ }
+
+ /* This makes sure the data is in the correct format, so we don't
+ need to swap fields. */
+ Elf_Data *d = elf_getdata (scn, NULL);
+ if (d == NULL)
+ return NULL;
+
+ if (d->d_size < sizeof (ElfW2(LIBELFBITS,Chdr)) || d->d_buf == NULL)
+ {
+ __libelf_seterrno (ELF_E_INVALID_DATA);
+ return NULL;
+ }
+
+ return (ElfW2(LIBELFBITS,Chdr) *) d->d_buf;
+}
diff --git a/libelf/elf32_getshdr.c b/libelf/elf32_getshdr.c
index 3a6375c1..237d9122 100644
--- a/libelf/elf32_getshdr.c
+++ b/libelf/elf32_getshdr.c
@@ -99,6 +99,7 @@ load_shdr_wrlock (Elf_Scn *scn)
assert ((elf->flags & ELF_F_MALLOCED)
|| ehdr->e_ident[EI_DATA] != MY_ELFDATA
+ || elf->cmd == ELF_C_READ_MMAP
|| (! ALLOW_UNALIGNED
&& ((uintptr_t) file_shdr
& (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) != 0));
@@ -106,7 +107,9 @@ load_shdr_wrlock (Elf_Scn *scn)
/* Now copy the data and at the same time convert the byte order. */
if (ehdr->e_ident[EI_DATA] == MY_ELFDATA)
{
- assert ((elf->flags & ELF_F_MALLOCED) || ! ALLOW_UNALIGNED);
+ assert ((elf->flags & ELF_F_MALLOCED)
+ || elf->cmd == ELF_C_READ_MMAP
+ || ! ALLOW_UNALIGNED);
memcpy (shdr, file_shdr, size);
}
else
diff --git a/libelf/elf32_updatenull.c b/libelf/elf32_updatenull.c
index d3754d32..03de0321 100644
--- a/libelf/elf32_updatenull.c
+++ b/libelf/elf32_updatenull.c
@@ -382,12 +382,27 @@ __elfw2(LIBELFBITS,updatenull_wrlock) (Elf *elf, int *change_bop, size_t shnum)
/* Check that the section size is actually a multiple of
the entry size. */
- if (shdr->sh_entsize != 0
- && unlikely (shdr->sh_size % shdr->sh_entsize != 0)
+ if (shdr->sh_entsize != 0 && shdr->sh_entsize != 1
&& (elf->flags & ELF_F_PERMISSIVE) == 0)
{
- __libelf_seterrno (ELF_E_INVALID_SHENTSIZE);
- return -1;
+ /* For compressed sections check the uncompressed size. */
+ ElfW2(LIBELFBITS,Word) sh_size;
+ if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
+ sh_size = shdr->sh_size;
+ else
+ {
+ ElfW2(LIBELFBITS,Chdr) *chdr;
+ chdr = elfw2(LIBELFBITS,getchdr) (scn);
+ if (unlikely (chdr == NULL))
+ return -1;
+ sh_size = chdr->ch_size;
+ }
+
+ if (unlikely (sh_size % shdr->sh_entsize != 0))
+ {
+ __libelf_seterrno (ELF_E_INVALID_SHENTSIZE);
+ return -1;
+ }
}
}
diff --git a/libelf/elf64_getchdr.c b/libelf/elf64_getchdr.c
new file mode 100644
index 00000000..6588b791
--- /dev/null
+++ b/libelf/elf64_getchdr.c
@@ -0,0 +1,30 @@
+/* Return section compression header.
+ 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/>. */
+
+#define LIBELFBITS 64
+#include "elf32_getchdr.c"
diff --git a/libelf/elf_begin.c b/libelf/elf_begin.c
index d2920c4e..147f5f4b 100644
--- a/libelf/elf_begin.c
+++ b/libelf/elf_begin.c
@@ -340,6 +340,7 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
Elf32_Off e_shoff = elf->state.elf32.ehdr->e_shoff;
if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
+ && cmd != ELF_C_READ_MMAP /* We need a copy to be able to write. */
&& (ALLOW_UNALIGNED
|| (((uintptr_t) ((char *) ehdr + e_shoff)
& (__alignof__ (Elf32_Shdr) - 1)) == 0)))
@@ -441,6 +442,7 @@ file_read_elf (int fildes, void *map_address, unsigned char *e_ident,
Elf64_Off e_shoff = elf->state.elf64.ehdr->e_shoff;
if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA
+ && cmd != ELF_C_READ_MMAP /* We need a copy to be able to write. */
&& (ALLOW_UNALIGNED
|| (((uintptr_t) ((char *) ehdr + e_shoff)
& (__alignof__ (Elf64_Shdr) - 1)) == 0)))
diff --git a/libelf/elf_compress.c b/libelf/elf_compress.c
new file mode 100644
index 00000000..4c7c35e1
--- /dev/null
+++ b/libelf/elf_compress.c
@@ -0,0 +1,516 @@
+/* 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
+
+/* Cleanup and return result. Don't leak memory. */
+static void *
+do_deflate_cleanup (void *result, z_stream *z, void *out_buf,
+ int ei_data, Elf_Data *cdatap)
+{
+ deflateEnd (z);
+ free (out_buf);
+ if (ei_data != MY_ELFDATA)
+ free (cdatap->d_buf);
+ return result;
+}
+
+#define deflate_cleanup(result) \
+ do_deflate_cleanup(result, &z, out_buf, ei_data, &cdata)
+
+/* 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). Returns (void *) -1 when FORCE is false and the compressed
+ data would be bigger than the original data. */
+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, bool force)
+{
+ /* 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;
+
+ /* When not forced and we immediately know we would use more data by
+ compressing, because of the header plus zlib overhead (five bytes
+ per 16 KB block, plus a one-time overhead of six bytes for the
+ entire stream), don't do anything. */
+ Elf_Data *next_data = elf_getdata (scn, data);
+ if (next_data == NULL && !force
+ && data->d_size <= hsize + 5 + 6)
+ return (void *) -1;
+
+ *orig_addralign = data->d_align;
+ *orig_size = data->d_size;
+
+ /* Guess an output block size. 1/8th of the original Elf_Data plus
+ hsize. Make the first chunk twice that size (25%), then increase
+ by a block (12.5%) when necessary. */
+ size_t block = (data->d_size / 8) + hsize;
+ size_t out_size = 2 * 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;
+
+ /* 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)
+ {
+ __libelf_seterrno (ELF_E_NOMEM);
+ return deflate_cleanup (NULL);
+ }
+ if (gelf_xlatetof (scn->elf, &cdata, data, ei_data) == NULL)
+ return deflate_cleanup (NULL);
+ }
+
+ z.avail_in = cdata.d_size;
+ z.next_in = cdata.d_buf;
+
+ /* Get next buffer to see if this is the last one. */
+ data = next_data;
+ if (data != NULL)
+ {
+ *orig_addralign = MAX (*orig_addralign, data->d_align);
+ *orig_size += data->d_size;
+ next_data = elf_getdata (scn, data);
+ }
+ 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)
+ {
+ __libelf_seterrno (ELF_E_COMPRESS_ERROR);
+ return deflate_cleanup (NULL);
+ }
+ used += (out_size - used) - z.avail_out;
+
+ /* Bail out if we are sure the user doesn't want the
+ compression forced and we are using more compressed data
+ than original data. */
+ if (!force && flush == Z_FINISH && used >= *orig_size)
+ return deflate_cleanup ((void *) -1);
+
+ if (z.avail_out == 0)
+ {
+ void *bigger = realloc (out_buf, out_size + block);
+ if (bigger == NULL)
+ {
+ __libelf_seterrno (ELF_E_NOMEM);
+ return deflate_cleanup (NULL);
+ }
+ 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)
+ {
+ __libelf_seterrno (ELF_E_COMPRESS_ERROR);
+ return deflate_cleanup (NULL);
+ }
+
+ *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_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign)
+{
+ GElf_Chdr chdr;
+ if (gelf_getchdr (scn, &chdr) == NULL)
+ return NULL;
+
+ if (chdr.ch_type != ELFCOMPRESS_ZLIB)
+ {
+ __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
+ return NULL;
+ }
+
+ if (! powerof2 (chdr.ch_addralign))
+ {
+ __libelf_seterrno (ELF_E_INVALID_ALIGN);
+ return NULL;
+ }
+
+ /* 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 NULL;
+
+ int elfclass = scn->elf->class;
+ 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);
+ *size_out = chdr.ch_size;
+ *addralign = chdr.ch_addralign;
+ 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. */
+ scn->rawdata.d.d_off = 0;
+ scn->rawdata.d.d_version = __libelf_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, unsigned int flags)
+{
+ if (scn == NULL)
+ return -1;
+
+ if ((flags & ~ELF_CHF_FORCE) != 0)
+ {
+ __libelf_seterrno (ELF_E_INVALID_OPERAND);
+ return -1;
+ }
+
+ bool force = (flags & ELF_CHF_FORCE) != 0;
+
+ 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];
+
+ Elf64_Xword sh_flags;
+ Elf64_Word sh_type;
+ Elf64_Xword sh_addralign;
+ if (elfclass == ELFCLASS32)
+ {
+ Elf32_Shdr *shdr = elf32_getshdr (scn);
+ if (shdr == NULL)
+ return -1;
+
+ sh_flags = shdr->sh_flags;
+ sh_type = shdr->sh_type;
+ sh_addralign = shdr->sh_addralign;
+ }
+ else
+ {
+ Elf64_Shdr *shdr = elf64_getshdr (scn);
+ if (shdr == NULL)
+ return -1;
+
+ sh_flags = shdr->sh_flags;
+ sh_type = shdr->sh_type;
+ sh_addralign = shdr->sh_addralign;
+ }
+
+ if ((sh_flags & SHF_ALLOC) != 0)
+ {
+ __libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
+ return -1;
+ }
+
+ if (sh_type == SHT_NULL || sh_type == SHT_NOBITS)
+ {
+ __libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
+ return -1;
+ }
+
+ int compressed = (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, force);
+
+ /* Compression would make section larger, don't change anything. */
+ if (out_buf == (void *) -1)
+ return 0;
+
+ /* Compression failed, return error. */
+ 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 = 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. */
+ if (elfclass == ELFCLASS32)
+ {
+ Elf32_Shdr *shdr = elf32_getshdr (scn);
+ shdr->sh_size = new_size;
+ shdr->sh_addralign = 1;
+ shdr->sh_flags |= SHF_COMPRESSED;
+ }
+ else
+ {
+ Elf64_Shdr *shdr = elf64_getshdr (scn);
+ shdr->sh_size = new_size;
+ shdr->sh_addralign = 1;
+ shdr->sh_flags |= SHF_COMPRESSED;
+ }
+
+ __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 1;
+ }
+ else if (type == 0)
+ {
+ /* Decompress/Inflate. */
+ if (compressed == 0)
+ {
+ __libelf_seterrno (ELF_E_NOT_COMPRESSED);
+ return -1;
+ }
+
+ /* If the data is already decompressed (by elf_strptr), then we
+ only need to setup the rawdata and section header. XXX what
+ about elf_newdata? */
+ if (scn->zdata_base == NULL)
+ {
+ size_t size_out, addralign;
+ void *buf_out = __libelf_decompress_elf (scn, &size_out, &addralign);
+ if (buf_out == NULL)
+ return -1;
+
+ scn->zdata_base = buf_out;
+ scn->zdata_size = size_out;
+ scn->zdata_align = addralign;
+ }
+
+ /* Note we keep the sh_entsize as is, we assume it is setup
+ correctly and ignored when SHF_COMPRESSED is set. */
+ if (elfclass == ELFCLASS32)
+ {
+ Elf32_Shdr *shdr = elf32_getshdr (scn);
+ shdr->sh_size = scn->zdata_size;
+ shdr->sh_addralign = scn->zdata_align;
+ shdr->sh_flags &= ~SHF_COMPRESSED;
+ }
+ else
+ {
+ Elf64_Shdr *shdr = elf64_getshdr (scn);
+ shdr->sh_size = scn->zdata_size;
+ shdr->sh_addralign = scn->zdata_align;
+ shdr->sh_flags &= ~SHF_COMPRESSED;
+ }
+
+ __libelf_reset_rawdata (scn, scn->zdata_base,
+ scn->zdata_size, scn->zdata_align,
+ __libelf_data_type (elf, sh_type));
+
+ return 1;
+ }
+ 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 00000000..c35dc395
--- /dev/null
+++ b/libelf/elf_compress_gnu.c
@@ -0,0 +1,208 @@
+/* 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, unsigned int flags)
+{
+ if (scn == NULL)
+ return -1;
+
+ if ((flags & ~ELF_CHF_FORCE) != 0)
+ {
+ __libelf_seterrno (ELF_E_INVALID_OPERAND);
+ return -1;
+ }
+
+ bool force = (flags & ELF_CHF_FORCE) != 0;
+
+ 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];
+
+ Elf64_Xword sh_flags;
+ Elf64_Word sh_type;
+ Elf64_Xword sh_addralign;
+ if (elfclass == ELFCLASS32)
+ {
+ Elf32_Shdr *shdr = elf32_getshdr (scn);
+ if (shdr == NULL)
+ return -1;
+
+ sh_flags = shdr->sh_flags;
+ sh_type = shdr->sh_type;
+ sh_addralign = shdr->sh_addralign;
+ }
+ else
+ {
+ Elf64_Shdr *shdr = elf64_getshdr (scn);
+ if (shdr == NULL)
+ return -1;
+
+ sh_flags = shdr->sh_flags;
+ sh_type = shdr->sh_type;
+ sh_addralign = shdr->sh_addralign;
+ }
+
+ if ((sh_flags & SHF_ALLOC) != 0)
+ {
+ __libelf_seterrno (ELF_E_INVALID_SECTION_FLAGS);
+ return -1;
+ }
+
+ if (sh_type == SHT_NULL || sh_type == SHT_NOBITS)
+ {
+ __libelf_seterrno (ELF_E_INVALID_SECTION_TYPE);
+ 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 = (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, force);
+
+ /* Compression would make section larger, don't change anything. */
+ if (out_buf == (void *) -1)
+ return 0;
+
+ /* Compression failed, return error. */
+ 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. */
+ if (elfclass == ELFCLASS32)
+ {
+ Elf32_Shdr *shdr = elf32_getshdr (scn);
+ shdr->sh_size = new_size;
+ }
+ else
+ {
+ Elf64_Shdr *shdr = elf64_getshdr (scn);
+ shdr->sh_size = new_size;
+ }
+
+ __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 1;
+ }
+ 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. */
+ if (elfclass == ELFCLASS32)
+ {
+ Elf32_Shdr *shdr = elf32_getshdr (scn);
+ shdr->sh_size = size;
+ }
+ else
+ {
+ Elf64_Shdr *shdr = elf64_getshdr (scn);
+ shdr->sh_size = size;
+ }
+
+ __libelf_reset_rawdata (scn, buf_out, size, sh_addralign,
+ __libelf_data_type (elf, sh_type));
+
+ scn->zdata_base = buf_out;
+
+ return 1;
+ }
+ else
+ {
+ __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE);
+ return -1;
+ }
+}
diff --git a/libelf/elf_end.c b/libelf/elf_end.c
index 7ea876c3..fde17b50 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 d6bdaab0..888b389a 100644
--- a/libelf/elf_error.c
+++ b/libelf/elf_error.c
@@ -230,6 +230,41 @@ core files")
(ELF_E_NO_PHDR_IDX \
+ sizeof "file has no program header")
N_("invalid offset")
+ "\0"
+#define ELF_E_INVALID_SECTION_TYPE_IDX \
+ (ELF_E_INVALID_OFFSET_IDX \
+ + sizeof "invalid offset")
+ N_("invalid section type")
+ "\0"
+#define ELF_E_INVALID_SECTION_FLAGS_IDX \
+ (ELF_E_INVALID_SECTION_TYPE_IDX \
+ + sizeof "invalid section type")
+ N_("invalid section flags")
+ "\0"
+#define ELF_E_NOT_COMPRESSED_IDX \
+ (ELF_E_INVALID_SECTION_FLAGS_IDX \
+ + sizeof "invalid section flags")
+ 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")
};
@@ -277,7 +312,14 @@ static const uint_fast16_t msgidx[ELF_E_NUM] =
[ELF_E_GROUP_NOT_REL] = ELF_E_GROUP_NOT_REL_IDX,
[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_INVALID_OFFSET] = ELF_E_INVALID_OFFSET_IDX,
+ [ELF_E_INVALID_SECTION_TYPE] = ELF_E_INVALID_SECTION_TYPE_IDX,
+ [ELF_E_INVALID_SECTION_FLAGS] = ELF_E_INVALID_SECTION_FLAGS_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 9a567e51..4ec94b98 100644
--- a/libelf/elf_getdata.c
+++ b/libelf/elf_getdata.c
@@ -106,6 +106,7 @@ const uint_fast8_t __libelf_type_aligns[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM]
[ELF_T_NHDR] = __alignof__ (ElfW2(Bits,Nhdr)), \
[ELF_T_GNUHASH] = __alignof__ (Elf32_Word), \
[ELF_T_AUXV] = __alignof__ (ElfW2(Bits,auxv_t)), \
+ [ELF_T_CHDR] = __alignof__ (ElfW2(Bits,Chdr)), \
}
[EV_CURRENT - 1] =
{
@@ -117,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,
@@ -204,6 +221,7 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn)
Elf64_Off offset;
Elf64_Xword size;
Elf64_Xword align;
+ Elf64_Xword flags;
int type;
Elf *elf = scn->elf;
@@ -220,6 +238,7 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn)
size = shdr->sh_size;
type = shdr->sh_type;
align = shdr->sh_addralign;
+ flags = shdr->sh_flags;
}
else
{
@@ -234,6 +253,7 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn)
size = shdr->sh_size;
type = shdr->sh_type;
align = shdr->sh_addralign;
+ flags = shdr->sh_flags;
}
/* If the section has no data (for whatever reason), leave the `d_buf'
@@ -243,7 +263,10 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn)
/* First a test whether the section is valid at all. */
size_t entsize;
- if (type == SHT_HASH)
+ /* Compressed data has a header, but then compressed data. */
+ if ((flags & SHF_COMPRESSED) != 0)
+ entsize = 1;
+ else if (type == SHT_HASH)
{
GElf_Ehdr ehdr_mem;
GElf_Ehdr *ehdr = __gelf_getehdr_rdlock (elf, &ehdr_mem);
@@ -320,17 +343,13 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn)
}
scn->rawdata.d.d_size = size;
- /* Some broken ELF ABI for 64-bit machines use the wrong hash table
- entry size. See elf-knowledge.h for more information. */
- if (type == SHT_HASH && elf->class == ELFCLASS64)
- {
- 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);
- }
+
+ /* Compressed data always has type ELF_T_CHDR regardless of the
+ section type. */
+ if ((flags & SHF_COMPRESSED) != 0)
+ scn->rawdata.d.d_type = ELF_T_CHDR;
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/elf_strptr.c b/libelf/elf_strptr.c
index c5138dc6..ea210459 100644
--- a/libelf/elf_strptr.c
+++ b/libelf/elf_strptr.c
@@ -37,6 +37,21 @@
#include "libelfP.h"
+static void *
+get_zdata (Elf_Scn *strscn)
+{
+ size_t zsize, zalign;
+ void *zdata = __libelf_decompress_elf (strscn, &zsize, &zalign);
+ if (zdata == NULL)
+ return NULL;
+
+ strscn->zdata_base = zdata;
+ strscn->zdata_size = zsize;
+ strscn->zdata_align = zalign;
+
+ return zdata;
+}
+
char *
elf_strptr (Elf *elf, size_t idx, size_t offset)
{
@@ -94,8 +109,16 @@ elf_strptr (Elf *elf, size_t idx, size_t offset)
goto out;
}
- sh_size = shdr->sh_size;
- if (unlikely (offset >= shdr->sh_size))
+ if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
+ sh_size = shdr->sh_size;
+ else
+ {
+ if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
+ goto out;
+ sh_size = strscn->zdata_size;
+ }
+
+ if (unlikely (offset >= sh_size))
{
/* The given offset is too big, it is beyond this section. */
__libelf_seterrno (ELF_E_OFFSET_RANGE);
@@ -112,8 +135,16 @@ elf_strptr (Elf *elf, size_t idx, size_t offset)
goto out;
}
- sh_size = shdr->sh_size;
- if (unlikely (offset >= shdr->sh_size))
+ if ((shdr->sh_flags & SHF_COMPRESSED) == 0)
+ sh_size = shdr->sh_size;
+ else
+ {
+ if (strscn->zdata_base == NULL && get_zdata (strscn) == NULL)
+ goto out;
+ sh_size = strscn->zdata_size;
+ }
+
+ if (unlikely (offset >= sh_size))
{
/* The given offset is too big, it is beyond this section. */
__libelf_seterrno (ELF_E_OFFSET_RANGE);
@@ -131,7 +162,17 @@ elf_strptr (Elf *elf, size_t idx, size_t offset)
goto out;
}
- if (likely (strscn->data_list_rear == NULL))
+ if (unlikely (strscn->zdata_base != NULL))
+ {
+ /* Make sure the string is NUL terminated. Start from the end,
+ which very likely is a NUL char. */
+ if (likely (memrchr (&strscn->zdata_base[offset],
+ '\0', sh_size - offset) != NULL))
+ result = &strscn->zdata_base[offset];
+ else
+ __libelf_seterrno (ELF_E_INVALID_INDEX);
+ }
+ else if (likely (strscn->data_list_rear == NULL))
{
// XXX The above is currently correct since elf_newdata will
// make sure to convert the rawdata into the datalist if
diff --git a/libelf/exttypes.h b/libelf/exttypes.h
index 8cb2aaec..7bacd654 100644
--- a/libelf/exttypes.h
+++ b/libelf/exttypes.h
@@ -1,5 +1,5 @@
/* External ELF types.
- Copyright (C) 1998-2010 Red Hat, Inc.
+ Copyright (C) 1998-2010, 2015 Red Hat, Inc.
This file is part of elfutils.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1998.
@@ -75,6 +75,7 @@ Syminfo32 (Ext_);
Move32 (Ext_);
Lib32 (Ext_);
auxv_t32 (Ext_);
+Chdr32 (Ext_);
Ehdr64 (Ext_);
Phdr64 (Ext_);
@@ -92,6 +93,7 @@ Syminfo64 (Ext_);
Move64 (Ext_);
Lib64 (Ext_);
auxv_t64 (Ext_);
+Chdr64 (Ext_);
#undef START
#undef END
diff --git a/libelf/gelf.h b/libelf/gelf.h
index e3f07404..1bc7ee72 100644
--- a/libelf/gelf.h
+++ b/libelf/gelf.h
@@ -1,5 +1,5 @@
/* This file defines generic ELF types, structures, and macros.
- Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2007 Red Hat, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2004, 2005, 2007, 2015 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -85,6 +85,9 @@ typedef Elf64_Rela GElf_Rela;
/* Program segment header. */
typedef Elf64_Phdr GElf_Phdr;
+/* Header of a compressed section. */
+typedef Elf64_Chdr GElf_Chdr;
+
/* Dynamic section entry. */
typedef Elf64_Dyn GElf_Dyn;
@@ -183,6 +186,9 @@ extern int gelf_update_phdr (Elf *__elf, int __ndx, GElf_Phdr *__src);
/* Create new program header with PHNUM entries. */
extern unsigned long int gelf_newphdr (Elf *__elf, size_t __phnum);
+/* Get compression header of section if any. Returns NULL and sets
+ elf_errno if the section isn't compressed or an error occurred. */
+extern GElf_Chdr *gelf_getchdr (Elf_Scn *__scn, GElf_Chdr *__dst);
/* Convert data structure from the representation in the file represented
by ELF to their memory representation. */
diff --git a/libelf/gelf_fsize.c b/libelf/gelf_fsize.c
index a124fa84..0c509265 100644
--- a/libelf/gelf_fsize.c
+++ b/libelf/gelf_fsize.c
@@ -68,6 +68,7 @@ const size_t __libelf_type_sizes[EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM] =
[ELF_T_MOVE] = sizeof (ElfW2(LIBELFBITS, Ext_Move)), \
[ELF_T_LIB] = sizeof (ElfW2(LIBELFBITS, Ext_Lib)), \
[ELF_T_AUXV] = sizeof (ElfW2(LIBELFBITS, Ext_auxv_t)), \
+ [ELF_T_CHDR] = sizeof (ElfW2(LIBELFBITS, Ext_Chdr)), \
[ELF_T_GNUHASH] = ELFW2(LIBELFBITS, FSZ_WORD)
TYPE_SIZES (32)
},
diff --git a/libelf/gelf_getchdr.c b/libelf/gelf_getchdr.c
new file mode 100644
index 00000000..394bf4b3
--- /dev/null
+++ b/libelf/gelf_getchdr.c
@@ -0,0 +1,69 @@
+/* Return section compression header.
+ 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 "libelfP.h"
+#include <gelf.h>
+#include <stddef.h>
+
+
+GElf_Chdr *
+gelf_getchdr (Elf_Scn *scn, GElf_Chdr *dest)
+{
+ if (scn == NULL)
+ return NULL;
+
+ if (dest == NULL)
+ {
+ __libelf_seterrno (ELF_E_INVALID_OPERAND);
+ return NULL;
+ }
+
+ if (scn->elf->class == ELFCLASS32)
+ {
+ Elf32_Chdr *chdr = elf32_getchdr (scn);
+ if (chdr == NULL)
+ return NULL;
+ dest->ch_type = chdr->ch_type;
+ dest->ch_size = chdr->ch_size;
+ dest->ch_addralign = chdr->ch_addralign;
+ }
+ else
+ {
+ Elf64_Chdr *chdr = elf64_getchdr (scn);
+ if (chdr == NULL)
+ return NULL;
+ *dest = *chdr;
+ }
+
+ return dest;
+}
+INTDEF(gelf_getchdr)
diff --git a/libelf/gelf_xlate.c b/libelf/gelf_xlate.c
index c5805e73..f3d3b7a0 100644
--- a/libelf/gelf_xlate.c
+++ b/libelf/gelf_xlate.c
@@ -166,6 +166,7 @@ union unaligned
#include "version_xlate.h"
#include "gnuhash_xlate.h"
#include "note_xlate.h"
+#include "chdr_xlate.h"
/* Now the externally visible table with the function pointers. */
@@ -198,7 +199,8 @@ const xfct_t __elf_xfctstom[EV_NUM - 1][EV_NUM - 1][ELFCLASSNUM - 1][ELF_T_NUM]
[ELF_T_SYMINFO] = ElfW2(Bits, cvt_Syminfo), \
[ELF_T_MOVE] = ElfW2(Bits, cvt_Move), \
[ELF_T_LIB] = ElfW2(Bits, cvt_Lib), \
- [ELF_T_AUXV] = ElfW2(Bits, cvt_auxv_t)
+ [ELF_T_AUXV] = ElfW2(Bits, cvt_auxv_t), \
+ [ELF_T_CHDR] = ElfW2(Bits, cvt_chdr)
define_xfcts (32),
[ELF_T_GNUHASH] = Elf32_cvt_Word
},
diff --git a/libelf/gelf_xlate.h b/libelf/gelf_xlate.h
index f11eb90b..3c0e4bf6 100644
--- a/libelf/gelf_xlate.h
+++ b/libelf/gelf_xlate.h
@@ -50,6 +50,7 @@ TYPE (Syminfo, LIBELFBITS)
TYPE (Move, LIBELFBITS)
TYPE (Lib, LIBELFBITS)
TYPE (auxv_t, LIBELFBITS)
+TYPE (Chdr, LIBELFBITS)
/* Prepare for the next round. */
diff --git a/libelf/libelf.h b/libelf/libelf.h
index 54f7c29b..c0d6389f 100644
--- a/libelf/libelf.h
+++ b/libelf/libelf.h
@@ -1,5 +1,5 @@
/* Interface for libelf.
- Copyright (C) 1998-2010 Red Hat, Inc.
+ Copyright (C) 1998-2010, 2015 Red Hat, Inc.
This file is part of elfutils.
This file is free software; you can redistribute it and/or modify
@@ -35,6 +35,34 @@
/* Get the ELF types. */
#include <elf.h>
+#ifndef SHF_COMPRESSED
+ /* Older glibc elf.h might not yet define the ELF compression types. */
+ #define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */
+
+ /* Section compression header. Used when SHF_COMPRESSED is set. */
+
+ typedef struct
+ {
+ Elf32_Word ch_type; /* Compression format. */
+ Elf32_Word ch_size; /* Uncompressed data size. */
+ Elf32_Word ch_addralign; /* Uncompressed data alignment. */
+ } Elf32_Chdr;
+
+ typedef struct
+ {
+ Elf64_Word ch_type; /* Compression format. */
+ Elf64_Word ch_reserved;
+ Elf64_Xword ch_size; /* Uncompressed data size. */
+ Elf64_Xword ch_addralign; /* Uncompressed data alignment. */
+ } Elf64_Chdr;
+
+ /* Legal values for ch_type (compression algorithm). */
+ #define ELFCOMPRESS_ZLIB 1 /* ZLIB/DEFLATE algorithm. */
+ #define ELFCOMPRESS_LOOS 0x60000000 /* Start of OS-specific. */
+ #define ELFCOMPRESS_HIOS 0x6fffffff /* End of OS-specific. */
+ #define ELFCOMPRESS_LOPROC 0x70000000 /* Start of processor-specific. */
+ #define ELFCOMPRESS_HIPROC 0x7fffffff /* End of processor-specific. */
+#endif
/* Known translation types. */
typedef enum
@@ -64,6 +92,7 @@ typedef enum
ELF_T_LIB, /* Elf32_Lib, Elf64_Lib, ... */
ELF_T_GNUHASH, /* GNU-style hash section. */
ELF_T_AUXV, /* Elf32_auxv_t, Elf64_auxv_t, ... */
+ ELF_T_CHDR, /* Compressed, Elf32_Chdr, Elf64_Chdr, ... */
/* Keep this the last entry. */
ELF_T_NUM
} Elf_Type;
@@ -116,6 +145,12 @@ enum
#define ELF_F_PERMISSIVE ELF_F_PERMISSIVE
};
+/* Flags for elf_compress[_gnu]. */
+enum
+{
+ ELF_CHF_FORCE = 0x1
+#define ELF_CHF_FORCE ELF_CHF_FORCE
+};
/* Identification values for recognized object files. */
typedef enum
@@ -267,6 +302,62 @@ extern Elf32_Shdr *elf32_getshdr (Elf_Scn *__scn);
/* Similar for ELFCLASS64. */
extern Elf64_Shdr *elf64_getshdr (Elf_Scn *__scn);
+/* Returns compression header for a section if section data is
+ compressed. Returns NULL and sets elf_errno if the section isn't
+ compressed or an error occurred. */
+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 ".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.
+
+ The FLAGS argument can be zero or ELF_CHF_FORCE. If FLAGS contains
+ ELF_CHF_FORCE then it will always compress the section, even if
+ that would not reduce the size of the data section (including the
+ header). Otherwise elf_compress and elf_compress_gnu will compress
+ the section only if the total data size is reduced.
+
+ On successful compression or decompression the function returns
+ one. If (not forced) compression is requested and the data section
+ would not actually reduce in size, the section is not actually
+ compressed and zero is returned. Otherwise -1 is returned and
+ elf_errno is set.
+
+ It is an error to request compression for a section that already
+ has SHF_COMPRESSED set, or (for elf_compress) to request
+ decompression for an section that doesn't have SHF_COMPRESSED set.
+ It is always an error to call these functions on SHT_NOBITS
+ sections or if the section has the SHF_ALLOC flag set.
+ elf_compress_gnu will not check whether the section name starts
+ with ".debug" or .zdebug". It is the responsibilty of the caller
+ to make sure the deprecated GNU compression method is only called
+ on correctly named sections (and to change the name of the section
+ when using elf_compress_gnu).
+
+ 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, unsigned int flags);
+extern int elf_compress_gnu (Elf_Scn *scn, int compress, unsigned int flags);
/* Set or clear flags for ELF file. */
extern unsigned int elf_flagelf (Elf *__elf, Elf_Cmd __cmd,
@@ -288,8 +379,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 de6d912a..10dc5059 100644
--- a/libelf/libelf.map
+++ b/libelf/libelf.map
@@ -138,3 +138,13 @@ ELFUTILS_1.6 {
global:
elf_getphdrnum;
} ELFUTILS_1.5;
+
+ELFUTILS_1.7 {
+ global:
+ elf32_getchdr;
+ elf64_getchdr;
+ gelf_getchdr;
+
+ elf_compress;
+ elf_compress_gnu;
+} ELFUTILS_1.6;
diff --git a/libelf/libelfP.h b/libelf/libelfP.h
index 993c6556..57ccbce4 100644
--- a/libelf/libelfP.h
+++ b/libelf/libelfP.h
@@ -1,5 +1,5 @@
/* Internal interfaces for libelf.
- Copyright (C) 1998-2010 Red Hat, Inc.
+ Copyright (C) 1998-2010, 2015 Red Hat, Inc.
This file is part of elfutils.
Contributed by Ulrich Drepper <drepper@redhat.com>, 1998.
@@ -38,6 +38,7 @@
#include <gelf.h>
#include <errno.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
@@ -138,6 +139,13 @@ enum
ELF_E_INVALID_PHDR,
ELF_E_NO_PHDR,
ELF_E_INVALID_OFFSET,
+ ELF_E_INVALID_SECTION_TYPE,
+ ELF_E_INVALID_SECTION_FLAGS,
+ 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
};
@@ -230,6 +238,10 @@ 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. */
+ size_t zdata_size; /* If zdata_base != NULL, the size of data. */
+ size_t zdata_align; /* If zdata_base != NULL, the addralign. */
+
struct Elf_ScnList *list; /* Pointer to the section list element the
data is in. */
};
@@ -438,6 +450,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.
@@ -578,6 +595,22 @@ 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, bool force)
+ internal_function;
+
+extern void * __libelf_decompress (void *buf_in, size_t size_in,
+ size_t size_out) internal_function;
+extern void * __libelf_decompress_elf (Elf_Scn *scn,
+ size_t *size_out, size_t *addralign)
+ 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. */