Reportedly on AerynOS the zstd compressed debug data can include a
window descriptor, rather than setting the single segment flag. This
patch supports that. The libbacktrace decompressor doesn't care about
the window size since all the data is in memory anyhow, but we do have
to skip the byte. This patch is from Ivan Molodetskikh. Ran
libbacktrace tests on x86_64-pc-linux-gnu. Committed to mainline.
Ian
* elf.c (elf_zstd_decompress_frame): Support a compressed block
that does not set the single segment flag.
* zstdtest.c (tests): Add tests without single segment.
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index f3033580e03..0de12bc112e 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -4364,6 +4364,7 @@ elf_zstd_decompress_frame (const unsigned char **ppin,
uint32_t repeated_offset3;
uint16_t *scratch;
unsigned char hdr;
+ int single_segment;
int has_checksum;
uint64_t content_size;
int last_block;
@@ -4422,11 +4423,17 @@ elf_zstd_decompress_frame (const unsigned char **ppin,
hdr = *pin++;
- /* We expect a single frame. */
- if (unlikely ((hdr & (1 << 5)) == 0))
+ single_segment = (hdr & (1 << 5)) != 0;
+ if (!single_segment)
{
- elf_uncompress_failed ();
- return 0;
+ if (unlikely (pin >= pinend))
+ {
+ elf_uncompress_failed ();
+ return 0;
+ }
+ /* We have all the data in memory, so we can ignore the window
+ size. */
+ pin++;
}
/* Reserved bit must be zero. */
if (unlikely ((hdr & (1 << 3)) != 0))
@@ -4444,12 +4451,21 @@ elf_zstd_decompress_frame (const unsigned char **ppin,
switch (hdr >> 6)
{
case 0:
- if (unlikely (pin >= pinend))
+ if (!single_segment)
{
- elf_uncompress_failed ();
- return 0;
+ /* The content_size is not specified, but we know it from the
+ section header. */
+ content_size = (uint64_t) sout;
+ }
+ else
+ {
+ if (unlikely (pin >= pinend))
+ {
+ elf_uncompress_failed ();
+ return 0;
+ }
+ content_size = (uint64_t) *pin++;
}
- content_size = (uint64_t) *pin++;
break;
case 1:
if (unlikely (pin + 1 >= pinend))
diff --git a/libbacktrace/zstdtest.c b/libbacktrace/zstdtest.c
index 7776c80fc9b..db8072645b9 100644
--- a/libbacktrace/zstdtest.c
+++ b/libbacktrace/zstdtest.c
@@ -182,7 +182,32 @@ static const struct zstd_test tests[] =
"\xb4\x21\x45\x3b\x10\xe4\x7b\x99\x4d\x8a\x36\x64\x5c\x77\x08\x02"
"\xcb\xe0\xce"),
179,
- }
+ },
+ {
+ "window-descriptor",
+ "hello, world\n",
+ 0,
+ ("\x28\xb5\x2f\xfd"
+ "\x04" /* no Single_Segment_flag; Frame_Content_Size_flag = 0 */
+ "\x00" /* Window_Descriptor */
+ "\x69\x00\x00"
+ "\x68\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x0a"
+ "\x4c\x1f\xf9\xf1"),
+ 26,
+ },
+ {
+ "window-descriptor-and-content-size",
+ "hello, world\n",
+ 0,
+ ("\x28\xb5\x2f\xfd"
+ "\x84" /* no Single_Segment_flag; Frame_Content_Size_flag = 2 */
+ "\x00" /* Window_Descriptor */
+ "\x0d\x00\x00\x00" /* Frame_Content_Size */
+ "\x69\x00\x00"
+ "\x68\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x0a"
+ "\x4c\x1f\xf9\xf1"),
+ 30,
+ },
};
/* Test the hand coded samples. */
@@ -217,7 +242,7 @@ test_samples (struct backtrace_state *state)
error_callback_compress, NULL,
uncompressed, uncompressed_len))
{
- fprintf (stderr, "test %s: uncompress failed\n", tests[i].name);
+ fprintf (stderr, "FAIL: test %s: uncompress failed\n", tests[i].name);
++failures;
}
else
@@ -227,7 +252,7 @@ test_samples (struct backtrace_state *state)
{
size_t j;
- fprintf (stderr, "test %s: uncompressed data mismatch\n",
+ fprintf (stderr, "FAIL: test %s: uncompressed data mismatch\n",
tests[i].name);
for (j = 0; j < uncompressed_len; ++j)
if (tests[i].uncompressed[j] != uncompressed[j])