e83d5f939a
Release: crash-8.0.5-2 Resolves: RHEL-43414 Signed-off-by: Tao Liu <ltao@redhat.com>
493 lines
14 KiB
Diff
493 lines
14 KiB
Diff
From a584e9752fb2198c7f6d0130d8a94b17581f33c6 Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Yulong=20TANG=20=E6=B1=A4=E7=8E=89=E9=BE=99?=
|
|
<yulong.tang@nio.com>
|
|
Date: Tue, 20 Feb 2024 15:09:49 +0800
|
|
Subject: [PATCH 1/9] Adding the zram decompression algorithm "lzo-rle"
|
|
|
|
Port the improved decompression method for "lzo" in the kernel to
|
|
support decompression of "lzorle".
|
|
|
|
Since Linux 5.1, the default compression algorithm for zram was changed
|
|
from "lzo" to "lzo-rle". The crash-utility only supports decompression
|
|
for "lzo", when parsing vmcore files that utilize zram compression, such
|
|
as when using the gcore command to detach process core dump files,
|
|
parsing cannot be completed successfully.
|
|
|
|
before:
|
|
crash> gcore -v 0 1
|
|
gcore: WARNING: only the lzo compressor is supported
|
|
gcore: WARNING: only the lzo compressor is supported
|
|
gcore: WARNING: only the lzo compressor is supported
|
|
gcore: WARNING: only the lzo compressor is supported
|
|
after:
|
|
crash> gcore -v 0 1
|
|
Saved core.1.init
|
|
|
|
Signed-off-by: yulong.tang <yulong.t...@nio.com>
|
|
Reviewed-by: Tao Liu <l...@redhat.com>
|
|
Signed-off-by: Kazuhito Hagio <k-hagio...@nec.com>
|
|
---
|
|
Makefile | 13 +-
|
|
diskdump.c | 3 +
|
|
lzorle_decompress.c | 295 ++++++++++++++++++++++++++++++++++++++++++++
|
|
lzorle_decompress.h | 75 +++++++++++
|
|
4 files changed, 383 insertions(+), 3 deletions(-)
|
|
create mode 100644 lzorle_decompress.c
|
|
create mode 100644 lzorle_decompress.h
|
|
|
|
diff --git a/Makefile b/Makefile
|
|
index 9e97313..60dad18 100644
|
|
--- a/Makefile
|
|
+++ b/Makefile
|
|
@@ -60,6 +60,7 @@ SADUMP_HFILES=sadump.h
|
|
UNWIND_HFILES=unwind.h unwind_i.h rse.h unwind_x86.h unwind_x86_64.h
|
|
VMWARE_HFILES=vmware_vmss.h
|
|
MAPLE_TREE_HFILES=maple_tree.h
|
|
+LZORLE_HFILES=lzorle_decompress.h
|
|
|
|
CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \
|
|
kernel.c test.c gdb_interface.c configure.c net.c dev.c bpf.c \
|
|
@@ -74,12 +75,14 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \
|
|
xen_hyper.c xen_hyper_command.c xen_hyper_global_data.c \
|
|
xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c ipcs.c \
|
|
ramdump.c vmware_vmss.c vmware_guestdump.c \
|
|
- xen_dom0.c kaslr_helper.c sbitmap.c maple_tree.c
|
|
+ xen_dom0.c kaslr_helper.c sbitmap.c maple_tree.c \
|
|
+ lzorle_decompress.c
|
|
|
|
SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \
|
|
${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \
|
|
${LKCD_DUMP_HFILES} ${LKCD_TRACE_HFILES} ${LKCD_OBSOLETE_HFILES}\
|
|
- ${IBM_HFILES} ${SADUMP_HFILES} ${VMWARE_HFILES} ${MAPLE_TREE_HFILES}
|
|
+ ${IBM_HFILES} ${SADUMP_HFILES} ${VMWARE_HFILES} ${MAPLE_TREE_HFILES} \
|
|
+ ${LZORLE_HFILES}
|
|
|
|
OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \
|
|
build_data.o kernel.o test.o gdb_interface.o net.o dev.o bpf.o \
|
|
@@ -94,7 +97,8 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \
|
|
xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \
|
|
xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o ipcs.o \
|
|
ramdump.o vmware_vmss.o vmware_guestdump.o \
|
|
- xen_dom0.o kaslr_helper.o sbitmap.o maple_tree.o
|
|
+ xen_dom0.o kaslr_helper.o sbitmap.o maple_tree.o \
|
|
+ lzorle_decompress.o
|
|
|
|
MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c memory_driver/README
|
|
|
|
@@ -546,6 +550,9 @@ bpf.o: ${GENERIC_HFILES} bpf.c
|
|
maple_tree.o: ${GENERIC_HFILES} ${MAPLE_TREE_HFILES} maple_tree.c
|
|
${CC} -c ${CRASH_CFLAGS} maple_tree.c ${WARNING_OPTIONS} ${WARNING_ERROR}
|
|
|
|
+lzorle_decompress.o: lzorle_decompress.c
|
|
+ ${CC} -c ${CRASH_CFLAGS} lzorle_decompress.c ${WARNING_OPTIONS} ${WARNING_ERROR}
|
|
+
|
|
${PROGRAM}: force
|
|
@$(MAKE) all
|
|
|
|
diff --git a/diskdump.c b/diskdump.c
|
|
index 3ae7bf2..4a473e1 100644
|
|
--- a/diskdump.c
|
|
+++ b/diskdump.c
|
|
@@ -28,6 +28,7 @@
|
|
#include "xen_dom0.h"
|
|
#include "vmcore.h"
|
|
#include "maple_tree.h"
|
|
+#include "lzorle_decompress.h"
|
|
|
|
#define BITMAP_SECT_LEN 4096
|
|
|
|
@@ -3069,6 +3070,8 @@ try_zram_decompress(ulonglong pte_val, unsigned char *buf, ulong len, ulonglong
|
|
" with lzo library\n");
|
|
return 0;
|
|
#endif
|
|
+ } else if (STREQ(name, "lzo-rle")) {
|
|
+ decompressor = (void *)&lzorle_decompress_safe;
|
|
} else { /* todo: support more compressor */
|
|
error(WARNING, "only the lzo compressor is supported\n");
|
|
return 0;
|
|
diff --git a/lzorle_decompress.c b/lzorle_decompress.c
|
|
new file mode 100644
|
|
index 0000000..6c810ea
|
|
--- /dev/null
|
|
+++ b/lzorle_decompress.c
|
|
@@ -0,0 +1,295 @@
|
|
+/* lzorle_decompress.h
|
|
+ *
|
|
+ * from kernel lib/lzo/lzo1x_decompress_safe.c
|
|
+ *
|
|
+ * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <mar...@oberhumer.com>
|
|
+ * Copyright (C) 2024 NIO
|
|
+ *
|
|
+ * This program 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 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program 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.
|
|
+ */
|
|
+
|
|
+#include "defs.h"
|
|
+#include "lzorle_decompress.h"
|
|
+
|
|
+/* This MAX_255_COUNT is the maximum number of times we can add 255 to a base
|
|
+ * count without overflowing an integer. The multiply will overflow when
|
|
+ * multiplying 255 by more than MAXINT/255. The sum will overflow earlier
|
|
+ * depending on the base count. Since the base count is taken from a u8
|
|
+ * and a few bits, it is safe to assume that it will always be lower than
|
|
+ * or equal to 2*255, thus we can always prevent any overflow by accepting
|
|
+ * two less 255 steps. See Documentation/lzo.txt for more information.
|
|
+ */
|
|
+#define MAX_255_COUNT ((((ulong)~0) / 255) - 2)
|
|
+
|
|
+static inline uint16_t get_unaligned_le16 (const uint8_t *p) {
|
|
+ return p[0] | p[1] << 8;
|
|
+}
|
|
+
|
|
+int lzorle_decompress_safe(const unsigned char *in, ulong in_len,
|
|
+ unsigned char *out, ulong *out_len, void *other/* NOT USED */) {
|
|
+ unsigned char *op;
|
|
+ const unsigned char *ip;
|
|
+ ulong t, next;
|
|
+ ulong state = 0;
|
|
+ const unsigned char *m_pos;
|
|
+ const unsigned char * const ip_end = in + in_len;
|
|
+ unsigned char * const op_end = out + *out_len;
|
|
+
|
|
+ unsigned char bitstream_version;
|
|
+
|
|
+ static int efficient_unaligned_access = -1;
|
|
+
|
|
+ if (efficient_unaligned_access == -1) {
|
|
+#if defined(ARM) || defined(ARM64) || defined(X86) || defined(X86_64) || defined(PPC) || defined(PPC64) || defined(S390)|| defined(S390X)
|
|
+ efficient_unaligned_access = TRUE;
|
|
+#else
|
|
+ efficient_unaligned_access = FALSE;
|
|
+#endif
|
|
+
|
|
+ if ((kt->ikconfig_flags & IKCONFIG_AVAIL) &&
|
|
+ (get_kernel_config("CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS", NULL) == IKCONFIG_Y))
|
|
+ efficient_unaligned_access = TRUE;
|
|
+ }
|
|
+
|
|
+ op = out;
|
|
+ ip = in;
|
|
+
|
|
+ if (in_len < 3)
|
|
+ goto input_overrun;
|
|
+
|
|
+ if (in_len >= 5 && *ip == 17) {
|
|
+ bitstream_version = ip[1];
|
|
+ ip += 2;
|
|
+ } else {
|
|
+ bitstream_version = 0;
|
|
+ }
|
|
+
|
|
+ if (*ip > 17) {
|
|
+ t = *ip++ - 17;
|
|
+ if (t < 4) {
|
|
+ next = t;
|
|
+ goto match_next;
|
|
+ }
|
|
+ goto copy_literal_run;
|
|
+ }
|
|
+
|
|
+ for (;;) {
|
|
+ t = *ip++;
|
|
+ if (t < 16) {
|
|
+ if (state == 0) {
|
|
+ if (t == 0) {
|
|
+ ulong offset;
|
|
+ const unsigned char *ip_last = ip;
|
|
+
|
|
+ while (*ip == 0) {
|
|
+ ip++;
|
|
+ NEED_IP(1);
|
|
+ }
|
|
+ offset = ip - ip_last;
|
|
+ if (offset > MAX_255_COUNT)
|
|
+ return LZO_E_ERROR;
|
|
+
|
|
+ offset = (offset << 8) - offset;
|
|
+ t += offset + 15 + *ip++;
|
|
+ }
|
|
+ t += 3;
|
|
+copy_literal_run:
|
|
+ if (efficient_unaligned_access &&
|
|
+ (HAVE_IP(t + 15) && HAVE_OP(t + 15))) {
|
|
+ const unsigned char *ie = ip + t;
|
|
+ unsigned char *oe = op + t;
|
|
+ do {
|
|
+ COPY8(op, ip);
|
|
+ op += 8;
|
|
+ ip += 8;
|
|
+ COPY8(op, ip);
|
|
+ op += 8;
|
|
+ ip += 8;
|
|
+ } while (ip < ie);
|
|
+ ip = ie;
|
|
+ op = oe;
|
|
+ } else {
|
|
+ NEED_OP(t);
|
|
+ NEED_IP(t + 3);
|
|
+ do {
|
|
+ *op++ = *ip++;
|
|
+ } while (--t > 0);
|
|
+ }
|
|
+ state = 4;
|
|
+ continue;
|
|
+ } else if (state != 4) {
|
|
+ next = t & 3;
|
|
+ m_pos = op - 1;
|
|
+ m_pos -= t >> 2;
|
|
+ m_pos -= *ip++ << 2;
|
|
+ TEST_LB(m_pos);
|
|
+ NEED_OP(2);
|
|
+ op[0] = m_pos[0];
|
|
+ op[1] = m_pos[1];
|
|
+ op += 2;
|
|
+ goto match_next;
|
|
+ } else {
|
|
+ next = t & 3;
|
|
+ m_pos = op - (1 + M2_MAX_OFFSET);
|
|
+ m_pos -= t >> 2;
|
|
+ m_pos -= *ip++ << 2;
|
|
+ t = 3;
|
|
+ }
|
|
+ } else if (t >= 64) {
|
|
+ next = t & 3;
|
|
+ m_pos = op - 1;
|
|
+ m_pos -= (t >> 2) & 7;
|
|
+ m_pos -= *ip++ << 3;
|
|
+ t = (t >> 5) - 1 + (3 - 1);
|
|
+ } else if (t >= 32) {
|
|
+ t = (t & 31) + (3 - 1);
|
|
+ if (t == 2) {
|
|
+ ulong offset;
|
|
+ const unsigned char *ip_last = ip;
|
|
+
|
|
+ while (*ip == 0) {
|
|
+ ip++;
|
|
+ NEED_IP(1);
|
|
+ }
|
|
+ offset = ip - ip_last;
|
|
+ if (offset > MAX_255_COUNT)
|
|
+ return LZO_E_ERROR;
|
|
+
|
|
+ offset = (offset << 8) - offset;
|
|
+ t += offset + 31 + *ip++;
|
|
+ NEED_IP(2);
|
|
+ }
|
|
+ m_pos = op - 1;
|
|
+
|
|
+ next = get_unaligned_le16(ip);
|
|
+ ip += 2;
|
|
+ m_pos -= next >> 2;
|
|
+ next &= 3;
|
|
+ } else {
|
|
+ NEED_IP(2);
|
|
+ next = get_unaligned_le16(ip);
|
|
+ if (((next & 0xfffc) == 0xfffc) &&
|
|
+ ((t & 0xf8) == 0x18) &&
|
|
+ bitstream_version) {
|
|
+ NEED_IP(3);
|
|
+ t &= 7;
|
|
+ t |= ip[2] << 3;
|
|
+ t += MIN_ZERO_RUN_LENGTH;
|
|
+ NEED_OP(t);
|
|
+ memset(op, 0, t);
|
|
+ op += t;
|
|
+ next &= 3;
|
|
+ ip += 3;
|
|
+ goto match_next;
|
|
+ } else {
|
|
+ m_pos = op;
|
|
+ m_pos -= (t & 8) << 11;
|
|
+ t = (t & 7) + (3 - 1);
|
|
+ if (t == 2) {
|
|
+ ulong offset;
|
|
+ const unsigned char *ip_last = ip;
|
|
+
|
|
+ while (*ip == 0) {
|
|
+ ip++;
|
|
+ NEED_IP(1);
|
|
+ }
|
|
+ offset = ip - ip_last;
|
|
+ if (offset > MAX_255_COUNT)
|
|
+ return LZO_E_ERROR;
|
|
+
|
|
+ offset = (offset << 8) - offset;
|
|
+ t += offset + 7 + *ip++;
|
|
+ NEED_IP(2);
|
|
+ next = get_unaligned_le16(ip);
|
|
+ }
|
|
+ ip += 2;
|
|
+ m_pos -= next >> 2;
|
|
+ next &= 3;
|
|
+ if (m_pos == op)
|
|
+ goto eof_found;
|
|
+ m_pos -= 0x4000;
|
|
+ }
|
|
+ }
|
|
+ TEST_LB(m_pos);
|
|
+
|
|
+ if (efficient_unaligned_access &&
|
|
+ (op - m_pos >= 8)) {
|
|
+ unsigned char *oe = op + t;
|
|
+ if (HAVE_OP(t + 15)) {
|
|
+ do {
|
|
+ COPY8(op, m_pos);
|
|
+ op += 8;
|
|
+ m_pos += 8;
|
|
+ COPY8(op, m_pos);
|
|
+ op += 8;
|
|
+ m_pos += 8;
|
|
+ } while (op < oe);
|
|
+ op = oe;
|
|
+ if (HAVE_IP(6)) {
|
|
+ state = next;
|
|
+ COPY4(op, ip);
|
|
+ op += next;
|
|
+ ip += next;
|
|
+ continue;
|
|
+ }
|
|
+ } else {
|
|
+ NEED_OP(t);
|
|
+ do {
|
|
+ *op++ = *m_pos++;
|
|
+ } while (op < oe);
|
|
+ }
|
|
+ } else {
|
|
+ unsigned char *oe = op + t;
|
|
+ NEED_OP(t);
|
|
+ op[0] = m_pos[0];
|
|
+ op[1] = m_pos[1];
|
|
+ op += 2;
|
|
+ m_pos += 2;
|
|
+ do {
|
|
+ *op++ = *m_pos++;
|
|
+ } while (op < oe);
|
|
+ }
|
|
+match_next:
|
|
+ state = next;
|
|
+ t = next;
|
|
+ if (efficient_unaligned_access &&
|
|
+ (HAVE_IP(6) && HAVE_OP(4))) {
|
|
+ COPY4(op, ip);
|
|
+ op += t;
|
|
+ ip += t;
|
|
+ } else {
|
|
+ NEED_IP(t + 3);
|
|
+ NEED_OP(t);
|
|
+ while (t > 0) {
|
|
+ *op++ = *ip++;
|
|
+ t--;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+eof_found:
|
|
+ *out_len = op - out;
|
|
+ return (t != 3 ? LZO_E_ERROR :
|
|
+ ip == ip_end ? LZO_E_OK :
|
|
+ ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN);
|
|
+
|
|
+input_overrun:
|
|
+ *out_len = op - out;
|
|
+ return LZO_E_INPUT_OVERRUN;
|
|
+
|
|
+output_overrun:
|
|
+ *out_len = op - out;
|
|
+ return LZO_E_OUTPUT_OVERRUN;
|
|
+
|
|
+lookbehind_overrun:
|
|
+ *out_len = op - out;
|
|
+ return LZO_E_LOOKBEHIND_OVERRUN;
|
|
+}
|
|
diff --git a/lzorle_decompress.h b/lzorle_decompress.h
|
|
new file mode 100644
|
|
index 0000000..62d961b
|
|
--- /dev/null
|
|
+++ b/lzorle_decompress.h
|
|
@@ -0,0 +1,75 @@
|
|
+/* lzorle_decompress.h
|
|
+ *
|
|
+ * from kernel lib/lzo/lzodefs.h
|
|
+ *
|
|
+ * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer <mar...@oberhumer.com>
|
|
+ * Copyright (C) 2024 NIO
|
|
+ *
|
|
+ * This program 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 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program 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.
|
|
+ */
|
|
+
|
|
+#ifndef LZODEFS_H
|
|
+#define LZODEFS_H
|
|
+
|
|
+#define COPY4(dst, src) memcpy((dst), (src), sizeof(uint32_t))
|
|
+#define COPY8(dst, src) memcpy((dst), (src), sizeof(uint64_t))
|
|
+
|
|
+#define M1_MAX_OFFSET 0x0400
|
|
+#define M2_MAX_OFFSET 0x0800
|
|
+#define M3_MAX_OFFSET 0x4000
|
|
+#define M4_MAX_OFFSET_V0 0xbfff
|
|
+#define M4_MAX_OFFSET_V1 0xbffe
|
|
+
|
|
+#define M1_MIN_LEN 2
|
|
+#define M1_MAX_LEN 2
|
|
+#define M2_MIN_LEN 3
|
|
+#define M2_MAX_LEN 8
|
|
+#define M3_MIN_LEN 3
|
|
+#define M3_MAX_LEN 33
|
|
+#define M4_MIN_LEN 3
|
|
+#define M4_MAX_LEN 9
|
|
+
|
|
+#define M1_MARKER 0
|
|
+#define M2_MARKER 64
|
|
+#define M3_MARKER 32
|
|
+#define M4_MARKER 16
|
|
+
|
|
+#define MIN_ZERO_RUN_LENGTH 4
|
|
+#define MAX_ZERO_RUN_LENGTH (2047 + MIN_ZERO_RUN_LENGTH)
|
|
+
|
|
+#define lzo_dict_t unsigned short
|
|
+#define D_BITS 13
|
|
+#define D_SIZE (1u << D_BITS)
|
|
+#define D_MASK (D_SIZE - 1)
|
|
+#define D_HIGH ((D_MASK >> 1) + 1)
|
|
+
|
|
+#define LZO_E_OK 0
|
|
+#define LZO_E_ERROR (-1)
|
|
+#define LZO_E_OUT_OF_MEMORY (-2)
|
|
+#define LZO_E_NOT_COMPRESSIBLE (-3)
|
|
+#define LZO_E_INPUT_OVERRUN (-4)
|
|
+#define LZO_E_OUTPUT_OVERRUN (-5)
|
|
+#define LZO_E_LOOKBEHIND_OVERRUN (-6)
|
|
+#define LZO_E_EOF_NOT_FOUND (-7)
|
|
+#define LZO_E_INPUT_NOT_CONSUMED (-8)
|
|
+#define LZO_E_NOT_YET_IMPLEMELZO_HFILESNTED (-9)
|
|
+#define LZO_E_INVALID_ARGUMENT (-10)
|
|
+
|
|
+#define HAVE_IP(x) ((unsigned long)(ip_end - ip) >= (unsigned long)(x))
|
|
+#define HAVE_OP(x) ((unsigned long)(op_end - op) >= (unsigned long)(x))
|
|
+#define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun
|
|
+#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun
|
|
+#define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun
|
|
+
|
|
+int lzorle_decompress_safe(const unsigned char *in, unsigned long in_len,
|
|
+ unsigned char *out, unsigned long *out_len, void *other/* NOT USED */);
|
|
+
|
|
+#endif
|
|
--
|
|
2.40.1
|
|
|