From patchwork Mon Oct 24 11:09:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Martin_Li=C5=A1ka?= X-Patchwork-Id: 59348 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A7C77385734B for ; Mon, 24 Oct 2022 11:10:08 +0000 (GMT) X-Original-To: elfutils-devel@sourceware.org Delivered-To: elfutils-devel@sourceware.org Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by sourceware.org (Postfix) with ESMTPS id E7E96385840C for ; Mon, 24 Oct 2022 11:10:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org E7E96385840C Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=suse.cz Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=suse.cz Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 1ECAD1FD86; Mon, 24 Oct 2022 11:10:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_rsa; t=1666609800; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=1N7sr6XhWC+IKb3ANrWcIZEoMXZ1xMP2jGOi8WPg2Mo=; b=BmYBhMdcwIUcaLiB2B8QI03cwCUIXecQj95mWx68QnVwkDWyNvHm9l4u+RUN+apFzl5k15 WtKtXi2xUxRUQMdPXytqB0ioR68faG+WvF743wpDoyxZdgQspOR7/07gEv3d+2BSvqdmPd JqslbiPfZ8obqcOq/ZcQyWodGxhpGvI= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_ed25519; t=1666609800; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=1N7sr6XhWC+IKb3ANrWcIZEoMXZ1xMP2jGOi8WPg2Mo=; b=cXoIZIwS3n6jW2RdP/+O/csUL3ZfabennQGyFpHEnCg6FEqM/TthHswBcVHEcAsSbpJEjt m/SsHtsbtelBBaCg== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id F028413357; Mon, 24 Oct 2022 11:09:59 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id wGBbOYdyVmPyKwAAMHmgww (envelope-from ); Mon, 24 Oct 2022 11:09:59 +0000 Message-ID: <542eb279-d15d-6f17-02c0-c53fd0f33055@suse.cz> Date: Mon, 24 Oct 2022 13:09:59 +0200 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.4.0 From: =?utf-8?q?Martin_Li=C5=A1ka?= Subject: [PATCH][RFC] readelf: partial support of ZSTD compression To: elfutils-devel@sourceware.org Content-Language: en-US X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: elfutils-devel@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Elfutils-devel mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , Cc: Mark Wielaard , Fangrui Song Errors-To: elfutils-devel-bounces+patchwork=sourceware.org@sourceware.org Sender: "Elfutils-devel" Support decompression of ZSTD sections and add support for it when -SWz is used: ... [30] .debug_abbrev PROGBITS 0000000000000000 00001f9d 00000168 0 C 0 0 1 [ELF ZSTD (2) 000002fc 1] ... One TODO I see is that: +libelf_so_LDLIBS = $(libelf_so_DEPS) -lz -lzstd should be conditional based on HAVE_ZSTD. But I don't know how to do that? And the second part should cover elfcompress where it should support ZSTD compression, leaving that for now. Martin libelf/ChangeLog: * Makefile.am: Add -lzstd. * elf.h (ELFCOMPRESS_ZSTD): Add new value. * elf_compress.c (__libelf_decompress): Dispatch based on the compression algorithm. (__libelf_decompress_zlib): New. (__libelf_decompress_zstd): New. (__libelf_decompress_elf): Pass type of compression to __libelf_decompress. * elf_compress_gnu.c (elf_compress_gnu): Use ELFCOMPRESS_ZLIB as .z* sections can be only compressed with ZLIB. * libelfP.h (__libelf_decompress): Change signature. m4/ChangeLog: * zstd.m4: New file. src/ChangeLog: * readelf.c (elf_ch_type_name): Use switch and support ZSTD. --- libelf/Makefile.am | 2 +- libelf/elf.h | 3 +++ libelf/elf_compress.c | 56 ++++++++++++++++++++++++++++++++++++--- libelf/elf_compress_gnu.c | 2 +- libelf/libelfP.h | 2 +- m4/zstd.m4 | 23 ++++++++++++++++ src/readelf.c | 18 ++++++++----- 7 files changed, 93 insertions(+), 13 deletions(-) create mode 100644 m4/zstd.m4 diff --git a/libelf/Makefile.am b/libelf/Makefile.am index 560ed45f..33f3a0a1 100644 --- a/libelf/Makefile.am +++ b/libelf/Makefile.am @@ -106,7 +106,7 @@ libelf_pic_a_SOURCES = am_libelf_pic_a_OBJECTS = $(libelf_a_SOURCES:.c=.os) libelf_so_DEPS = ../lib/libeu.a -libelf_so_LDLIBS = $(libelf_so_DEPS) -lz +libelf_so_LDLIBS = $(libelf_so_DEPS) -lz -lzstd if USE_LOCKS libelf_so_LDLIBS += -lpthread endif diff --git a/libelf/elf.h b/libelf/elf.h index 02a1b3f5..f0f0ec7d 100644 --- a/libelf/elf.h +++ b/libelf/elf.h @@ -506,6 +506,9 @@ typedef struct /* Legal values for ch_type (compression algorithm). */ #define ELFCOMPRESS_ZLIB 1 /* ZLIB/DEFLATE algorithm. */ +#define ELFCOMPRESS_ZSTD 2 /* Compressed with zstd */ + /* (see http://www.zstandard.org). */ + #define ELFCOMPRESS_LOOS 0x60000000 /* Start of OS-specific. */ #define ELFCOMPRESS_HIOS 0x6fffffff /* End of OS-specific. */ #define ELFCOMPRESS_LOPROC 0x70000000 /* Start of processor-specific. */ diff --git a/libelf/elf_compress.c b/libelf/elf_compress.c index d7f53af2..62b41b20 100644 --- a/libelf/elf_compress.c +++ b/libelf/elf_compress.c @@ -39,6 +39,10 @@ #include #include +#ifdef USE_ZSTD +#include +#endif + /* Cleanup and return result. Don't leak memory. */ static void * do_deflate_cleanup (void *result, z_stream *z, void *out_buf, @@ -207,7 +211,7 @@ __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data, void * internal_function -__libelf_decompress (void *buf_in, size_t size_in, size_t size_out) +__libelf_decompress_zlib (void *buf_in, size_t size_in, size_t size_out) { /* Catch highly unlikely compression ratios so we don't allocate some giant amount of memory for nothing. The max compression @@ -260,6 +264,50 @@ __libelf_decompress (void *buf_in, size_t size_in, size_t size_out) return buf_out; } +#ifdef USE_ZSTD +void * +internal_function +__libelf_decompress_zstd (void *buf_in, size_t size_in, size_t size_out) +{ + /* Malloc might return NULL when requestion zero size. This is highly + unlikely, it would only happen when the compression was forced. + But we do need a non-NULL buffer to return and set as result. + Just make sure to always allocate at least 1 byte. */ + void *buf_out = malloc (size_out ?: 1); + if (unlikely (buf_out == NULL)) + { + __libelf_seterrno (ELF_E_NOMEM); + return NULL; + } + + size_t ret = ZSTD_decompress (buf_out, size_out, buf_in, size_in); + if (ZSTD_isError (ret)) + { + free (buf_out); + __libelf_seterrno (ELF_E_DECOMPRESS_ERROR); + return NULL; + } + else + return buf_out; +} +#endif + +void * +internal_function +__libelf_decompress (int chtype, void *buf_in, size_t size_in, size_t size_out) +{ + if (chtype == ELFCOMPRESS_ZLIB) + return __libelf_decompress_zlib (buf_in, size_in, size_out); + else + { +#ifdef USE_ZSTD + return __libelf_decompress_zstd (buf_in, size_in, size_out); +#else + return 0; +#endif + } +} + void * internal_function __libelf_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign) @@ -268,7 +316,7 @@ __libelf_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign) if (gelf_getchdr (scn, &chdr) == NULL) return NULL; - if (chdr.ch_type != ELFCOMPRESS_ZLIB) + if (chdr.ch_type != ELFCOMPRESS_ZLIB && chdr.ch_type != ELFCOMPRESS_ZSTD) { __libelf_seterrno (ELF_E_UNKNOWN_COMPRESSION_TYPE); return NULL; @@ -295,7 +343,9 @@ __libelf_decompress_elf (Elf_Scn *scn, size_t *size_out, size_t *addralign) ? 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); + void *buf_out + = __libelf_decompress (chdr.ch_type, buf_in, size_in, chdr.ch_size); + *size_out = chdr.ch_size; *addralign = chdr.ch_addralign; return buf_out; diff --git a/libelf/elf_compress_gnu.c b/libelf/elf_compress_gnu.c index 3d2977e7..be9e990e 100644 --- a/libelf/elf_compress_gnu.c +++ b/libelf/elf_compress_gnu.c @@ -178,7 +178,7 @@ elf_compress_gnu (Elf_Scn *scn, int inflate, unsigned int flags) 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); + void *buf_out = __libelf_decompress (ELFCOMPRESS_ZLIB, buf_in, size_in, size); if (buf_out == NULL) return -1; diff --git a/libelf/libelfP.h b/libelf/libelfP.h index d88a613c..ab82357c 100644 --- a/libelf/libelfP.h +++ b/libelf/libelfP.h @@ -577,7 +577,7 @@ extern void * __libelf_compress (Elf_Scn *scn, size_t hsize, int ei_data, size_t *size, bool force) internal_function; -extern void * __libelf_decompress (void *buf_in, size_t size_in, +extern void * __libelf_decompress (int chtype, 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) diff --git a/m4/zstd.m4 b/m4/zstd.m4 new file mode 100644 index 00000000..6da4db68 --- /dev/null +++ b/m4/zstd.m4 @@ -0,0 +1,23 @@ +dnl Copyright (C) 2022 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl Enable features using the zstd library. +AC_DEFUN([AC_ZSTD], [ +AC_ARG_WITH(zstd, + [AS_HELP_STRING([--with-zstd], [support zstd compressed debug sections (default=auto)])], + [], [with_zstd=auto]) + +AS_IF([test "$with_zstd" != no], + [PKG_CHECK_MODULES(ZSTD, [libzstd], [ + AC_DEFINE(HAVE_ZSTD, 1, [Define to 1 if zstd is enabled.]) + ], [ + if test "$with_zstd" = yes; then + AC_MSG_ERROR([--with-zstd was given, but pkgconfig/libzstd.pc is not found]) + fi + ]) + ]) +]) diff --git a/src/readelf.c b/src/readelf.c index a206e60e..1af20e35 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -1229,13 +1229,17 @@ get_visibility_type (int value) static const char * elf_ch_type_name (unsigned int code) { - if (code == 0) - return "NONE"; - - if (code == ELFCOMPRESS_ZLIB) - return "ZLIB"; - - return "UNKNOWN"; + switch (code) + { + case 0: + return "NONE"; + case ELFCOMPRESS_ZLIB: + return "ZLIB"; + case ELFCOMPRESS_ZSTD: + return "ZSTD"; + default: + return "UNKNOWN"; + } } /* Print the section headers. */