diff options
author | Mark Wielaard <mjw@redhat.com> | 2015-10-21 01:33:56 +0200 |
---|---|---|
committer | Mark Wielaard <mjw@redhat.com> | 2015-11-02 16:32:39 +0100 |
commit | 1362745282b44aac8d9b1a4fd7cc250d1b797cc5 (patch) | |
tree | 0c036073e0fafc5f69acfe64be3ae70726628b84 | |
parent | b1a665cf5efc1661dc6cda0b74155052145ee3c6 (diff) | |
download | elfutils-1362745282b44aac8d9b1a4fd7cc250d1b797cc5.tar.gz |
libelf: Add elf_compress and elf_compress_gnu.
Signed-off-by: Mark Wielaard <mjw@redhat.com>
-rw-r--r-- | libelf/ChangeLog | 26 | ||||
-rw-r--r-- | libelf/Makefile.am | 3 | ||||
-rw-r--r-- | libelf/elf_compress.c | 409 | ||||
-rw-r--r-- | libelf/elf_compress_gnu.c | 150 | ||||
-rw-r--r-- | libelf/elf_end.c | 11 | ||||
-rw-r--r-- | libelf/elf_error.c | 32 | ||||
-rw-r--r-- | libelf/elf_getdata.c | 36 | ||||
-rw-r--r-- | libelf/gelf.h | 1 | ||||
-rw-r--r-- | libelf/libelf.h | 43 | ||||
-rw-r--r-- | libelf/libelf.map | 6 | ||||
-rw-r--r-- | libelf/libelfP.h | 22 | ||||
-rw-r--r-- | tests/ChangeLog | 15 | ||||
-rw-r--r-- | tests/Makefile.am | 10 | ||||
-rw-r--r-- | tests/elfgetzdata.c | 101 | ||||
-rw-r--r-- | tests/elfputzdata.c | 200 | ||||
-rw-r--r-- | tests/msg_tst.c | 7 | ||||
-rwxr-xr-x | tests/run-elfgetzdata.sh | 70 | ||||
-rwxr-xr-x | tests/run-elfputzdata.sh | 174 |
18 files changed, 1293 insertions, 23 deletions
diff --git a/libelf/ChangeLog b/libelf/ChangeLog index fbe8e3ae..663a461b 100644 --- a/libelf/ChangeLog +++ b/libelf/ChangeLog @@ -1,3 +1,29 @@ +2015-10-21 Mark Wielaard <mjw@redhat.com> + + * Makefile.am (libelf_a_SOURCES): Add elf32_zscn_compress.c, + elf64_zscn_compress.c and gelf_zscn_compress.c. + * elf32_zscn_compress.c: New file. + * elf64_zscn_compress.c: Likewise. + * gelf_zscn_compress.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. + * gelf.h: Define gelf_zscn_compress. + * libelf.h: Define elf32_zscn_compress and elf64_zscn_compress. + * libelf.map (ELFUTILS_1.7): Add elf32_zscn_compress, + elf64_zscn_compress and gelf_zscn_compress. + * 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. + (struct Elf_Scn): Add zdata_base. + 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..9e12fb37 100644 --- a/libelf/Makefile.am +++ b/libelf/Makefile.am @@ -88,7 +88,8 @@ 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 \ + 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 00000000..a9b4f1b9 --- /dev/null +++ b/libelf/elf_compress.c @@ -0,0 +1,409 @@ +/* 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 <unistd.h> +#include <zlib.h> + +#ifndef MAX +# define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + +void * +internal_function +__libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data, + size_t orig_size, size_t *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; + + /* Guess an output size. 1/8th of the original Elf_Data or at least 8K. */ + size_t block = MAX (orig_size, data->d_size) / 8; + if (block < 8 * 1024) + block = 8 * 1024; + size_t out_size = block; + void *out_buf = malloc (out_size); + if (out_buf == NULL) + { + __libelf_seterrno (ELF_E_NOMEM); + return NULL; + } + + 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; + } + + /* Cleanup and NULL return on error. Don't leak memory. */ + void *deflate_error (int err) + { + __libelf_seterrno (err); + deflateEnd (&z); + free (out_buf); + return NULL; + } + + /* Loop over data buffers. */ + int flush; + do + { + /* Convert to raw if different endianess. */ + if (ei_data != MY_ELFDATA) + { + if (gelf_xlatetof (scn->elf, data, data, ei_data) == NULL) + return deflate_error; + } + z.avail_in = data->d_size; + z.next_in = data->d_buf; + /* Get next buffer to see if this is the last one. */ + data = elf_getdata (scn, data); + flush = data == NULL ? Z_FINISH : Z_NO_FLUSH; + /* 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. */ + } + while (flush != Z_FINISH); /* More data blocks. */ + + zrc = deflateEnd (&z); + if (zrc != Z_OK) + return deflate_error (ELF_E_COMPRESS_ERROR); + + *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) +{ + /* This is the new raw data, replace and possibly free old data. */ + scn->rawdata.d.d_buf = buf; + scn->rawdata.d.d_size = size; + scn->rawdata.d.d_align = align; + + /* 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 NULL; + + int elfclass = elf->class; + int elfdata = ehdr.e_ident[EI_DATA]; + + GElf_Shdr shdr; + if (gelf_getshdr (scn, &shdr) == NULL) + return NULL; + + int compressed = (shdr.sh_flags & SHF_COMPRESSED); + if (type == ELFCOMPRESS_ZLIB) + { + /* Compress/Deflate. */ + if (compressed == 1) + { + __libelf_seterrno (ELF_E_ALREADY_COMPRESSED); + return -1; + } + + // XXX sh_size vs Elf_Data sizes. likewise for addralign. + size_t orig_size = shdr.sh_size; + size_t hsize = (elfclass == ELFCLASS32 + ? sizeof (Elf32_Chdr) : sizeof (Elf64_Chdr)); + size_t size; + void *out_buf = __libelf_compress (scn, hsize, elfdata, + orig_size, &size); + if (out_buf == NULL) + return NULL; + + /* 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 = shdr.sh_addralign; + if (elfdata != MY_ELFDATA) + { + CONVERT (chdr.ch_type); + CONVERT (chdr.ch_size); + CONVERT (chdr.ch_addralign); + } + memmove (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); + } + memmove (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 = 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, size, 1); + + /* 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; + } + + /* 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; + + /* Extract the header data first. */ + int ctype; + size_t size; + size_t align; + size_t hsize; + if (elfclass == ELFCLASS32) + { + hsize = sizeof (Elf32_Chdr); + if (data->d_size < hsize) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + return -1; + } + + Elf32_Chdr chdr; + if (elfdata == MY_ELFDATA + && (ALLOW_UNALIGNED + || (((uintptr_t) data->d_buf & (__alignof__ (Elf32_Chdr) - 1)) + == 0))) + chdr = *(Elf32_Chdr *) data->d_buf; + else + memcpy (&chdr, data->d_buf, hsize); + + if (elfdata == MY_ELFDATA) + { + ctype = chdr.ch_type; + size = chdr.ch_size; + align = chdr.ch_addralign; + } + else + { + CONVERT_TO (ctype, chdr.ch_type); + CONVERT_TO (size, chdr.ch_size); + CONVERT_TO (align, chdr.ch_addralign); + } + } + else + { + hsize = sizeof (Elf64_Chdr); + if (data->d_size < hsize) + { + __libelf_seterrno (ELF_E_INVALID_DATA); + return -1; + } + + Elf64_Chdr chdr; + if (elfdata == MY_ELFDATA + && (ALLOW_UNALIGNED + || (((uintptr_t) data->d_buf & (__alignof__ (Elf64_Chdr) - 1)) + == 0))) + chdr = *(Elf64_Chdr *) data->d_buf; + else + memcpy (&chdr, data->d_buf, hsize); + + if (elfdata == MY_ELFDATA) + { + ctype = chdr.ch_type; + size = chdr.ch_size; + align = chdr.ch_addralign; + } + else + { + CONVERT_TO (ctype, chdr.ch_type); + CONVERT_TO (size, chdr.ch_size); + CONVERT_TO (align, chdr.ch_addralign); + } + } + + if (ctype != ELFCOMPRESS_ZLIB) + { + __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE); + return -1; + } + + /* rawdata_base must be non-NULL since we found a compressed header. */ + 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; + + /* Note we keep the sh_entsize as is, we assume it is setup + correctly and ignored when SHF_COMPRESSED is set. */ + shdr.sh_size = size; + shdr.sh_addralign = align; + shdr.sh_flags &= ~SHF_COMPRESSED; + // XXX Don't! this sets dirty flag... + gelf_update_shdr (scn, &shdr); + + __libelf_reset_rawdata (scn, buf_out, size, align); + + 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 00000000..635df710 --- /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 NULL; + + int elfdata = ehdr.e_ident[EI_DATA]; + + GElf_Shdr shdr; + if (gelf_getshdr (scn, &shdr) == NULL) + return NULL; + + /* 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) + { + // XXX sh_size vs Elf_Data sizes. likewise for addralign. + size_t orig_size = shdr.sh_size; + size_t hsize = 4 + 8; /* GNU "ZLIB" + 8 byte size. */ + size_t size; + void *out_buf = __libelf_compress (scn, hsize, elfdata, + orig_size, &size); + if (out_buf == NULL) + return NULL; + + 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 = size; + + // XXX Don't! this sets dirty flag... + gelf_update_shdr (scn, &shdr); + + __libelf_reset_rawdata (scn, out_buf, size, 1); + + /* 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); + + 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 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..20c2f171 100644 --- a/libelf/elf_error.c +++ b/libelf/elf_error.c @@ -230,6 +230,31 @@ core files") (ELF_E_NO_PHDR_IDX \ + sizeof "file has no program header") N_("invalid offset") + "\0" +#define ELF_E_NOT_COMPRESSED_IDX \ + (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") }; @@ -277,7 +302,12 @@ 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_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..74513755 100644 --- a/libelf/elf_getdata.c +++ b/libelf/elf_getdata.c @@ -117,6 +117,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 +220,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 +237,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 +252,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 +262,9 @@ __libelf_set_rawdata_wrlock (Elf_Scn *scn) /* First a test whether the section is valid at all. */ size_t entsize; - if (type == SHT_HASH) + 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 +341,10 @@ __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); - } + if ((flags & SHF_COMPRESSED) != 0) + scn->rawdata.d.d_type = ELF_T_BYTE; 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/gelf.h b/libelf/gelf.h index e3f07404..29afc85a 100644 --- a/libelf/gelf.h +++ b/libelf/gelf.h @@ -183,7 +183,6 @@ 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); - /* Convert data structure from the representation in the file represented by ELF to their memory representation. */ extern Elf_Data *gelf_xlatetom (Elf *__elf, Elf_Data *__dest, diff --git a/libelf/libelf.h b/libelf/libelf.h index 54f7c29b..a376d880 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 @@ -268,6 +268,40 @@ extern Elf32_Shdr *elf32_getshdr (Elf_Scn *__scn); extern Elf64_Shdr *elf64_getshdr (Elf_Scn *__scn); +/* When type is ELF_ZSCN_T_NONE then ch_type is ignored and the raw + section data is decompressed if the section was compressed before. + The returned section header will have an updated sh_size, + sh_addralign and will have SHF_COMPRESSED cleared from the + sh_flags. sh_entsize isn't changed. If the section wasn't + compressed, or an error occurred while decompressing the section + date NULL is returned and elf_err is set. + + When type is ELF_ZSCN_T_GNU or ELF_ZSCN_T_ELF ch_type must be a + valid ELFCOMPRESS algorithm. Currently the only valid value is + ELFCOMPRESS_ZLIB. If the section wasn't compressed yet then the + Elf_Data is converted to the raw format of the Elf image and + compressed using the given algorithm. The correct compression + format header will be added at the start of the new raw data for the + section. The returned section header will have an updated sh_size, + sh_addralign and if type was ELF_ZSCN_T_ELF sh_flags will have + SHF_COMPRESSED set. sh_entsize isn't changed. If the section data + was already compressed, or an unknown compression type or algorithm + was given or if an error occurred while compressing NULL is returned + and elf_err is set. + + Too switch between GNU and ELF compression types or to use another + compression algorithm one has to uncompress the section first and + then compress using the other type/algorithm. + + All previous returned 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); @@ -288,8 +322,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 d_type is also set to + ELF_T_BYTE. */ 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..b2075600 100644 --- a/libelf/libelf.map +++ b/libelf/libelf.map @@ -138,3 +138,9 @@ ELFUTILS_1.6 { global: elf_getphdrnum; } ELFUTILS_1.5; + +ELFUTILS_1.7 { + global: + elf_compress; + elf_compress_gnu; +} ELFUTILS_1.6; diff --git a/libelf/libelfP.h b/libelf/libelfP.h index 993c6556..a50e44b4 100644 --- a/libelf/libelfP.h +++ b/libelf/libelfP.h @@ -138,6 +138,11 @@ enum ELF_E_INVALID_PHDR, 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 }; @@ -230,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. */ }; @@ -438,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. @@ -578,6 +590,16 @@ 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 *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) 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 042e3a4c..84fba1a1 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 e9c95535..1db72fc3 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 dwelfgetchdr + elfshphehdr elfstrmerge dwelfgetchdr \ + elfgetzdata elfputzdata asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \ asm-tst6 asm-tst7 asm-tst8 asm-tst9 @@ -120,7 +121,8 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \ run-readelf-dwz-multi.sh run-allfcts-multi.sh run-deleted.sh \ 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-dwelfgetchdr.sh + elfshphehdr run-lfs-symbols.sh run-dwelfgetchdr.sh \ + run-elfgetzdata.sh run-elfputzdata.sh if !BIARCH export ELFUTILS_DISABLE_BIARCH = 1 @@ -308,7 +310,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \ run-lfs-symbols.sh lfs-symbols testfile-nolfs.bz2 \ testfile-zgnu32.bz2 testfile-zgnu64.bz2 \ testfile-zgabi32.bz2 testfile-zgabi64.bz2 \ - run-dwelfgetchdr.sh + run-dwelfgetchdr.sh run-elfgetzdata.sh run-elfputzdata if USE_VALGRIND valgrind_cmd='valgrind -q --error-exitcode=1 --run-libc-freeres=no' @@ -458,6 +460,8 @@ dwfl_proc_attach_LDFLAGS = -pthread $(AM_LDFLAGS) elfshphehdr_LDADD =$(libelf) elfstrmerge_LDADD = $(libebl) $(libelf) dwelfgetchdr_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 00000000..9176d4f5 --- /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 00000000..2ab512c1 --- /dev/null +++ b/tests/elfputzdata.c @@ -0,0 +1,200 @@ +/* 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_buf == NULL) + { + printf ("No memory to copy section %zd data\n", idx); + return -1; + } + 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 10ff0f73..7f20d108 100644 --- a/tests/msg_tst.c +++ b/tests/msg_tst.c @@ -74,7 +74,12 @@ static struct "program header only allowed in executables, shared objects, \ and core files" }, { ELF_E_NO_PHDR, "file has no program header" }, - { ELF_E_INVALID_OFFSET, "invalid offset" } + { ELF_E_INVALID_OFFSET, "invalid offset" }, + { 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 00000000..c03ef6ae --- /dev/null +++ b/tests/run-elfgetzdata.sh @@ -0,0 +1,70 @@ +#! /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-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-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-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 + +exit 0 diff --git a/tests/run-elfputzdata.sh b/tests/run-elfputzdata.sh new file mode 100755 index 00000000..da423b5e --- /dev/null +++ b/tests/run-elfputzdata.sh @@ -0,0 +1,174 @@ +#! /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 + +exit 0 |