aboutsummaryrefslogtreecommitdiff
path: root/bfd/compress.c
diff options
context:
space:
mode:
authorFangrui Song <maskray@google.com>2022-09-26 19:50:13 -0700
committerFangrui Song <i@maskray.me>2022-09-26 19:50:13 -0700
commit2cac01e3ffff74898c54fa5e6418817f5578adb6 (patch)
treec0209ba03d922dae339056488493fc16ebefe6d0 /bfd/compress.c
parente122316b7ce78b999db944d7b524e11d642e2a49 (diff)
downloadgdb-2cac01e3ffff74898c54fa5e6418817f5578adb6.zip
gdb-2cac01e3ffff74898c54fa5e6418817f5578adb6.tar.gz
gdb-2cac01e3ffff74898c54fa5e6418817f5578adb6.tar.bz2
binutils, gdb: support zstd compressed debug sections
PR29397 PR29563: Add new configure option --with-zstd which defaults to auto. If pkgconfig/libzstd.pc is found, define HAVE_ZSTD and support zstd compressed debug sections for most tools. * bfd: for addr2line, objdump --dwarf, gdb, etc * gas: support --compress-debug-sections=zstd * ld: support ELFCOMPRESS_ZSTD input and --compress-debug-sections=zstd * objcopy: support ELFCOMPRESS_ZSTD input for --decompress-debug-sections and --compress-debug-sections=zstd * gdb: support ELFCOMPRESS_ZSTD input. The bfd change references zstd symbols, so gdb has to link against -lzstd in this patch. If zstd is not supported, ELFCOMPRESS_ZSTD input triggers an error. We can avoid HAVE_ZSTD if binutils-gdb imports zstd/ like zlib/, but this is too heavyweight, so don't do it for now. ``` % ld/ld-new a.o ld/ld-new: a.o: section .debug_abbrev is compressed with zstd, but BFD is not built with zstd support ... % ld/ld-new a.o --compress-debug-sections=zstd ld/ld-new: --compress-debug-sections=zstd: ld is not built with zstd support % binutils/objcopy --compress-debug-sections=zstd a.o b.o binutils/objcopy: --compress-debug-sections=zstd: binutils is not built with zstd support % binutils/objcopy b.o --decompress-debug-sections binutils/objcopy: zstd.o: section .debug_abbrev is compressed with zstd, but BFD is not built with zstd support ... ```
Diffstat (limited to 'bfd/compress.c')
-rw-r--r--bfd/compress.c72
1 files changed, 54 insertions, 18 deletions
diff --git a/bfd/compress.c b/bfd/compress.c
index b2e3982..0e75b68 100644
--- a/bfd/compress.c
+++ b/bfd/compress.c
@@ -20,18 +20,31 @@
#include "sysdep.h"
#include <zlib.h>
+#ifdef HAVE_ZSTD
+#include <zstd.h>
+#endif
#include "bfd.h"
+#include "elf-bfd.h"
#include "libbfd.h"
#include "safe-ctype.h"
#define MAX_COMPRESSION_HEADER_SIZE 24
static bool
-decompress_contents (bfd_byte *compressed_buffer,
+decompress_contents (bool is_zstd, bfd_byte *compressed_buffer,
bfd_size_type compressed_size,
bfd_byte *uncompressed_buffer,
bfd_size_type uncompressed_size)
{
+ if (is_zstd)
+ {
+#ifdef HAVE_ZSTD
+ size_t ret = ZSTD_decompress (uncompressed_buffer, uncompressed_size,
+ compressed_buffer, compressed_size);
+ return !ZSTD_isError (ret);
+#endif
+ }
+
z_stream strm;
int rc;
@@ -69,7 +82,7 @@ decompress_contents (bfd_byte *compressed_buffer,
}
/* Compress data of the size specified in @var{uncompressed_size}
- and pointed to by @var{uncompressed_buffer} using zlib and store
+ and pointed to by @var{uncompressed_buffer} using zlib/zstd and store
as the contents field. This function assumes the contents
field was allocated using bfd_malloc() or equivalent.
@@ -150,9 +163,10 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
sec->size = orig_uncompressed_size;
if (decompress)
{
- if (!decompress_contents (uncompressed_buffer
- + orig_compression_header_size,
- zlib_size, buffer, buffer_size))
+ if (!decompress_contents (
+ sec->compress_status == DECOMPRESS_SECTION_ZSTD,
+ uncompressed_buffer + orig_compression_header_size,
+ zlib_size, buffer, buffer_size))
{
bfd_set_error (bfd_error_bad_value);
bfd_release (abfd, buffer);
@@ -175,10 +189,23 @@ bfd_compress_section_contents (bfd *abfd, sec_ptr sec,
}
else
{
- if (compress ((Bytef*) buffer + header_size,
- &compressed_size,
- (const Bytef*) uncompressed_buffer,
- uncompressed_size) != Z_OK)
+ if (abfd->flags & BFD_COMPRESS_ZSTD)
+ {
+#if HAVE_ZSTD
+ compressed_size = ZSTD_compress (
+ buffer + header_size, compressed_size, uncompressed_buffer,
+ uncompressed_size, ZSTD_CLEVEL_DEFAULT);
+ if (ZSTD_isError (compressed_size))
+ {
+ bfd_release (abfd, buffer);
+ bfd_set_error (bfd_error_bad_value);
+ return 0;
+ }
+#endif
+ }
+ else if (compress ((Bytef *)buffer + header_size, &compressed_size,
+ (const Bytef *)uncompressed_buffer, uncompressed_size)
+ != Z_OK)
{
bfd_release (abfd, buffer);
bfd_set_error (bfd_error_bad_value);
@@ -237,6 +264,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
bfd_size_type save_rawsize;
bfd_byte *compressed_buffer;
unsigned int compression_header_size;
+ const unsigned int compress_status = sec->compress_status;
if (abfd->direction != write_direction && sec->rawsize != 0)
sz = sec->rawsize;
@@ -248,7 +276,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
return true;
}
- switch (sec->compress_status)
+ switch (compress_status)
{
case COMPRESS_SECTION_NONE:
if (p == NULL)
@@ -298,7 +326,8 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
*ptr = p;
return true;
- case DECOMPRESS_SECTION_SIZED:
+ case DECOMPRESS_SECTION_ZLIB:
+ case DECOMPRESS_SECTION_ZSTD:
/* Read in the full compressed section contents. */
compressed_buffer = (bfd_byte *) bfd_malloc (sec->compressed_size);
if (compressed_buffer == NULL)
@@ -316,7 +345,7 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
/* Restore rawsize and size. */
sec->rawsize = save_rawsize;
sec->size = save_size;
- sec->compress_status = DECOMPRESS_SECTION_SIZED;
+ sec->compress_status = compress_status;
if (!ret)
goto fail_compressed;
@@ -330,8 +359,10 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
/* Set header size to the zlib header size if it is a
SHF_COMPRESSED section. */
compression_header_size = 12;
- if (!decompress_contents (compressed_buffer + compression_header_size,
- sec->compressed_size - compression_header_size, p, sz))
+ bool is_zstd = compress_status == DECOMPRESS_SECTION_ZSTD;
+ if (!decompress_contents (
+ is_zstd, compressed_buffer + compression_header_size,
+ sec->compressed_size - compression_header_size, p, sz))
{
bfd_set_error (bfd_error_bad_value);
if (p != *ptr)
@@ -381,7 +412,8 @@ DESCRIPTION
void
bfd_cache_section_contents (asection *sec, void *contents)
{
- if (sec->compress_status == DECOMPRESS_SECTION_SIZED)
+ if (sec->compress_status == DECOMPRESS_SECTION_ZLIB
+ || sec->compress_status == DECOMPRESS_SECTION_ZSTD)
sec->compress_status = COMPRESS_SECTION_DONE;
sec->contents = contents;
sec->flags |= SEC_IN_MEMORY;
@@ -418,6 +450,7 @@ bfd_is_section_compressed_with_header (bfd *abfd, sec_ptr sec,
int compression_header_size;
int header_size;
unsigned int saved = sec->compress_status;
+ unsigned int ch_type;
bool compressed;
*uncompressed_align_pow_p = 0;
@@ -448,7 +481,7 @@ bfd_is_section_compressed_with_header (bfd *abfd, sec_ptr sec,
{
if (compression_header_size != 0)
{
- if (!bfd_check_compression_header (abfd, header, sec,
+ if (!bfd_check_compression_header (abfd, header, sec, &ch_type,
uncompressed_size_p,
uncompressed_align_pow_p))
compression_header_size = -1;
@@ -507,7 +540,7 @@ SYNOPSIS
DESCRIPTION
Record compressed section size, update section size with
decompressed size and set compress_status to
- DECOMPRESS_SECTION_SIZED.
+ DECOMPRESS_SECTION_{ZLIB,ZSTD}.
Return @code{FALSE} if the section is not a valid compressed
section. Otherwise, return @code{TRUE}.
@@ -521,6 +554,7 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
int header_size;
bfd_size_type uncompressed_size;
unsigned int uncompressed_alignment_power = 0;
+ unsigned int ch_type;
z_stream strm;
compression_header_size = bfd_get_compression_header_size (abfd, sec);
@@ -550,6 +584,7 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
uncompressed_size = bfd_getb64 (header + 4);
}
else if (!bfd_check_compression_header (abfd, header, sec,
+ &ch_type,
&uncompressed_size,
&uncompressed_alignment_power))
{
@@ -569,7 +604,8 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec)
sec->compressed_size = sec->size;
sec->size = uncompressed_size;
bfd_set_section_alignment (sec, uncompressed_alignment_power);
- sec->compress_status = DECOMPRESS_SECTION_SIZED;
+ sec->compress_status = (ch_type == ELFCOMPRESS_ZSTD
+ ? DECOMPRESS_SECTION_ZSTD : DECOMPRESS_SECTION_ZLIB);
return true;
}