Rewrite of zImage bin parser & new structured data methods (#5893)

This commit is contained in:
Giovanni 2026-02-09 19:00:42 +08:00 committed by GitHub
parent dcb4acf661
commit dfdd062f14
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 951 additions and 156 deletions

View file

@ -1,27 +0,0 @@
// SPDX-FileCopyrightText: 2009-2015 ninjahacker <wardjm@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_types.h>
#include <rz_util.h>
#include "zimg.h"
struct rz_bin_zimg_obj_t *rz_bin_zimg_new_buf(RzBuffer *buf) {
struct rz_bin_zimg_obj_t *bin = RZ_NEW0(struct rz_bin_zimg_obj_t);
if (!bin) {
goto fail;
}
bin->size = rz_buf_size(buf);
bin->b = rz_buf_ref(buf);
if (rz_buf_size(bin->b) < sizeof(struct zimg_header_t)) {
goto fail;
}
rz_buf_read_at(bin->b, 0, (ut8 *)&bin->header, sizeof(bin->header));
return bin;
fail:
if (bin) {
rz_buf_free(bin->b);
free(bin);
}
return NULL;
}

View file

@ -1,44 +0,0 @@
// SPDX-FileCopyrightText: 2009-2015 ninjahacker <wardjm@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef ZIMG_H
#define ZIMG_H
#include <rz_types.h>
#include <rz_util.h>
#include <rz_lib.h>
#include <rz_bin.h>
#define RZ_BIN_ZIMG_MAXSTR 256
struct zimg_header_t {
ut8 magic[8];
ut32 filler[6];
ut8 arm_magic[4];
ut32 kernel_start;
ut32 kernel_end;
};
typedef struct rz_bin_zimg_obj_t {
int size;
const char *file;
RzBuffer *b;
struct zimg_header_t header;
ut32 *strings;
ut64 code_from;
ut64 code_to;
Sdb *kv;
} RzBinZimgObj;
struct rz_bin_zimg_str_t {
char str[RZ_BIN_ZIMG_MAXSTR];
ut64 offset;
ut64 ordinal;
int size;
int last;
};
struct rz_bin_zimg_obj_t *rz_bin_zimg_new_buf(RzBuffer *buf);
struct rz_bin_zimg_str_t *rz_bin_zimg_get_strings(struct rz_bin_zimg_obj_t *bin);
#endif

View file

@ -271,7 +271,6 @@ rz_bin_sources = [
'format/pyc/pyc_magic.c', 'format/pyc/pyc_magic.c',
'format/te/te.c', 'format/te/te.c',
'format/wasm/wasm.c', 'format/wasm/wasm.c',
'format/zimg/zimg.c',
'pdb/cab_extract.c', 'pdb/cab_extract.c',
'pdb/dbi.c', 'pdb/dbi.c',

View file

@ -1,39 +1,461 @@
// SPDX-FileCopyrightText: 2011-2019 ninjahacker <wardjm@gmail.com> // SPDX-FileCopyrightText: 2026 deroad <deroad@kumo.xn--q9jyb4c>
// SPDX-License-Identifier: LGPL-3.0-only // SPDX-License-Identifier: LGPL-3.0-only
#include <rz_types.h> #include <rz_types.h>
#include <rz_util.h> #include <rz_util.h>
#include <rz_lib.h> #include <rz_lib.h>
#include <rz_bin.h> #include <rz_bin.h>
#include "zimg/zimg.h"
static Sdb *get_sdb(RzBinFile *bf) { typedef struct zimage_arm32_s {
rz_return_val_if_fail(bf && bf->o, false); ut32 arm32_magic; ///< 0x016f2818
struct rz_bin_zimg_obj_t *bin = (struct rz_bin_zimg_obj_t *)bf->o->bin_obj; ut32 kernel_start;
return bin ? bin->kv : NULL; ut32 kernel_end;
ut32 endianness_flag;
ut32 magic_table_flag;
ut32 magic_table;
} zimage_arm32_t;
typedef struct zimage_riscv_s {
ut64 image_load; ///< base address
ut64 kernel_size;
ut64 head_flags; ///< usually 0
ut16 version_major;
ut16 version_minor;
ut32 padding0; ///< should be 0
ut64 padding1; ///< should be 0
ut8 riscv_magic1[8]; ///< "RISCV\0\0\0"
ut8 riscv_magic2[4]; ///< "RSC\x05"
ut32 pe_header_offset; ///< from offset 0
} zimage_riscv_t;
typedef enum zimage_arch {
ZIMAGE_ARCH_ARM32_LE = 0,
ZIMAGE_ARCH_ARM32_BE,
ZIMAGE_ARCH_RISCV,
} zimage_arch_t;
typedef struct zimage_s {
zimage_arch_t arch;
const char *kernel;
union {
zimage_arm32_t arm32;
zimage_riscv_t riscv;
} info;
} zImage;
typedef bool (*zimage_parser_t)(zImage *image, RzBuffer *buf, ut64 off, bool big_endian);
typedef struct zimage_signature_s {
const ut8 *bytes;
size_t size;
ut64 offset;
} zimage_signature_t;
typedef struct zimage_marker_s {
const zimage_arch_t arch;
const bool big_endian;
const char *kernel;
const zimage_parser_t parser;
const zimage_signature_t *signatures;
const size_t n_signatures;
} zimage_marker_t;
/**
* Reference: https://github.com/torvalds/linux/blob/05f7e89ab9731565d8a62e3b5d1ec206485eeb0b/arch/riscv/kernel/head.S#L28
*
* #ifdef CONFIG_EFI
* li s4, -13 // encoding: [0x4d,0x5a] (compat)
* j 64 // encoding: [0x81,0xa0] (compat)
* #else
* j 64 // encoding: [0x81,0xa0] (compat)
* // encoding: [0x6f,0x00,0x00,0x04] (non-compat)
* .word 0
* #endif
* .balign 8
* #ifdef CONFIG_RISCV_M_MODE
* // Image load offset (0MB) from start of RAM for M-mode
* .dword 0
* #else
* #if __riscv_xlen == 64
* // Image load offset(2MB) from start of RAM
* .dword 0x200000
* #else
* // Image load offset(4MB) from start of RAM
* .dword 0x400000
* #endif
* #endif
* // Effective size of kernel image
* .dword _end - _start
* .dword __HEAD_FLAGS // likely 0
* .word RISCV_HEADER_VERSION // (RISCV_HEADER_VERSION_MAJOR << 16 | RISCV_HEADER_VERSION_MINOR)
* .word 0
* .dword 0
* .ascii RISCV_IMAGE_MAGIC // "RISCV\0\0\0"
* .balign 4
* .ascii RISCV_IMAGE_MAGIC2 // "RSC\x05"
* #ifdef CONFIG_EFI
* .word pe_head_start - _start
* pe_head_start:
* __EFI_PE_HEADER // "MZ"
* #else
* .word 0
* #endif
*/
#define RISCV_ZIMAGE_MAGIC1_VALUE "RISCV\0\0\0"
#define RISCV_ZIMAGE_MAGIC2_VALUE "RSC\x05"
#define RISCV_ZIMAGE_INFO_OFFSET 0x08
#define RISCV_ZIMAGE_MAGIC_OFFSET 0x30
// clang-format off
const ut8 marker_riscv_efi_compact[4] = { 0x4d, 0x5a, 0x81, 0xa0 };
const ut8 marker_riscv_compact[6] = { 0x81, 0xa0, 0, 0, 0, 0 };
const ut8 marker_riscv_non_compact[8] = { 0x6f, 0x00, 0x00, 0x04, 0, 0, 0, 0 };
const ut8 marker_riscv_magic[12] = { 'R', 'I', 'S', 'C', 'V', 0, 0, 0, 'R', 'S', 'C', 5 };
static const zimage_signature_t zimage_signature_riscv_efi_compact_5_9[] = {
{ marker_riscv_efi_compact, sizeof (marker_riscv_efi_compact), 0 },
{ marker_riscv_magic, sizeof (marker_riscv_magic), RISCV_ZIMAGE_MAGIC_OFFSET },
};
static const zimage_signature_t zimage_signature_riscv_compact_5_2[] = {
{ marker_riscv_compact, sizeof (marker_riscv_compact), 0 },
{ marker_riscv_magic, sizeof (marker_riscv_magic), RISCV_ZIMAGE_MAGIC_OFFSET },
};
static const zimage_signature_t zimage_signature_riscv_non_compact_5_2[] = {
{ marker_riscv_non_compact, sizeof (marker_riscv_non_compact), 0 },
{ marker_riscv_magic, sizeof (marker_riscv_magic), RISCV_ZIMAGE_MAGIC_OFFSET },
};
static const zimage_signature_t zimage_signature_riscv_compact_4_14[] = {
{ marker_riscv_compact, sizeof (marker_riscv_compact), 0 },
};
static const zimage_signature_t zimage_signature_riscv_non_compact_4_14[] = {
{ marker_riscv_non_compact, sizeof (marker_riscv_non_compact), 0 },
};
// clang-format on
static bool zimage_parse_riscv(zImage *image, RzBuffer *buf, ut64 off, bool big_endian) {
zimage_riscv_t *h = &image->info.riscv;
off += RISCV_ZIMAGE_INFO_OFFSET;
ut32 riscv_version = 0;
bool ok = rz_buf_read_ble64_offset(buf, &off, &h->image_load, big_endian) &&
rz_buf_read_ble64_offset(buf, &off, &h->kernel_size, big_endian) &&
rz_buf_read_ble64_offset(buf, &off, &h->head_flags, big_endian) &&
rz_buf_read_ble32_offset(buf, &off, &riscv_version, big_endian) &&
rz_buf_read_ble32_offset(buf, &off, &h->padding0, big_endian) &&
rz_buf_read_ble64_offset(buf, &off, &h->padding1, big_endian) &&
rz_buf_read_offset(buf, &off, h->riscv_magic1, sizeof(h->riscv_magic1)) &&
rz_buf_read_offset(buf, &off, h->riscv_magic2, sizeof(h->riscv_magic2)) &&
rz_buf_read_ble32_offset(buf, &off, &h->pe_header_offset, big_endian);
if (!ok) {
return false;
}
h->version_major = riscv_version >> 16;
h->version_minor = riscv_version & 0xffff;
return true;
} }
static bool load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *b, Sdb *sdb) { /**
obj->bin_obj = rz_bin_zimg_new_buf(b); * Reference: https://github.com/torvalds/linux/blob/05f7e89ab9731565d8a62e3b5d1ec206485eeb0b/arch/arm/boot/compressed/head.S#L188
return obj->bin_obj != NULL; *
* .rept 7
* __nop
* .endr
* #ifndef CONFIG_THUMB2_KERNEL
* __nop
* #else
* AR_CLASS( sub pc, pc, #3 ) @ A/R: switch to Thumb2 mode
* M_CLASS( nop.w ) @ M: already in Thumb2 mode
* .thumb
* #endif
*
* W(b) 1f
*
* .word _magic_sig @ Magic numbers to help the loader
* .word _magic_start @ absolute load/run zImage address
* .word _magic_end @ zImage end address
* .word 0x04030201 @ endianness flag
* .word 0x45454545 @ another magic number to indicate
* .word _magic_table @ additional data table
* __EFI_HEADER
*
*
* Additional values.
*
* _magic_sig = ZIMAGE_MAGIC(0x016f2818);
* _magic_start = ZIMAGE_MAGIC(_start);
* _magic_end = ZIMAGE_MAGIC(_edata);
* _magic_table = ZIMAGE_MAGIC(_table_start - _start);
*/
#define ARM_ZIMAGE_MAGIC_VALUE 0x016f2818
#define ARM_ZIMAGE_ENDIANNESS_VALUE 0x04030201
#define ARM_ZIMAGE_MAGIC_TABLE_VALUE 0x45454545
#define ARM_ZIMAGE_INFO_OFFSET 0x24
#define ARM_ZIMAGE_ENDIANNESS_OFFSET 0x30
#define ARM_ZIMAGE_MAGIC_TABLE_OFFSET 0x34
// clang-format off
const ut8 marker_arm32_mov_le[8] = { 0x00, 0x00, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe1 };
const ut8 marker_arm32_magic_le[4] = { 0x18, 0x28, 0x6f, 0x01 };
const ut8 marker_arm32_endianness_le[4] = { 1, 2, 3, 4 };
const ut8 marker_arm32_mov_be[8] = { 0xe1, 0xa0, 0x00, 0x00, 0xe1, 0xa0, 0x00, 0x00 };
const ut8 marker_arm32_magic_be[4] = { 0x01, 0x6f, 0x28, 0x18 };
const ut8 marker_arm32_endianness_be[4] = { 4, 3, 2, 1 };
const ut8 marker_arm32_magic_table[4] = { 0x45, 0x45, 0x45, 0x45 };
static const zimage_signature_t zimage_signature_arm32_le_4_14_plus[] = {
{ marker_arm32_mov_le, sizeof (marker_arm32_mov_le), 0 },
{ marker_arm32_magic_le, sizeof (marker_arm32_magic_le), ARM_ZIMAGE_INFO_OFFSET },
{ marker_arm32_endianness_le, sizeof (marker_arm32_endianness_le), ARM_ZIMAGE_ENDIANNESS_OFFSET },
{ marker_arm32_magic_table, sizeof (marker_arm32_magic_table), ARM_ZIMAGE_MAGIC_TABLE_OFFSET },
};
static const zimage_signature_t zimage_signature_arm32_le_3_16_4_14[] = {
{ marker_arm32_mov_le, sizeof (marker_arm32_mov_le), 0 },
{ marker_arm32_magic_le, sizeof (marker_arm32_magic_le), ARM_ZIMAGE_INFO_OFFSET },
{ marker_arm32_endianness_le, sizeof (marker_arm32_endianness_le), ARM_ZIMAGE_ENDIANNESS_OFFSET },
};
static const zimage_signature_t zimage_signature_arm32_le_pre3_16[] = {
{ marker_arm32_mov_le, sizeof (marker_arm32_mov_le), 0 },
{ marker_arm32_magic_le, sizeof (marker_arm32_magic_le), ARM_ZIMAGE_INFO_OFFSET },
};
static const zimage_signature_t zimage_signature_arm32_be_4_14_plus[] = {
{ marker_arm32_mov_be, sizeof (marker_arm32_mov_be), 0 },
{ marker_arm32_magic_be, sizeof (marker_arm32_magic_be), ARM_ZIMAGE_INFO_OFFSET },
{ marker_arm32_endianness_be, sizeof (marker_arm32_endianness_be), ARM_ZIMAGE_ENDIANNESS_OFFSET },
{ marker_arm32_magic_table, sizeof (marker_arm32_magic_table), ARM_ZIMAGE_MAGIC_TABLE_OFFSET },
};
static const zimage_signature_t zimage_signature_arm32_be_3_16_4_14[] = {
{ marker_arm32_mov_be, sizeof (marker_arm32_mov_be), 0 },
{ marker_arm32_magic_be, sizeof (marker_arm32_magic_be), ARM_ZIMAGE_INFO_OFFSET },
{ marker_arm32_endianness_be, sizeof (marker_arm32_endianness_be), ARM_ZIMAGE_ENDIANNESS_OFFSET },
};
static const zimage_signature_t zimage_signature_arm32_be_pre3_16[] = {
{ marker_arm32_mov_be, sizeof (marker_arm32_mov_be), 0 },
{ marker_arm32_magic_be, sizeof (marker_arm32_magic_be), ARM_ZIMAGE_INFO_OFFSET },
};
/*
if (h->magic_table_flag == ARM_ZIMAGE_MAGIC_TABLE_VALUE) {
return rz_str_dup("Linux zImage Kernel (4.14 or newer)");
} else if (zo->endianness_flag == ARM_ZIMAGE_ENDIANNESS_VALUE) {
return rz_str_dup("Linux zImage Kernel (3.16 - 4.14)");
}
return rz_str_dup("Linux zImage Kernel (3.16 or older)");
*/
// clang-format on
static bool zimage_parse_arm32(zImage *image, RzBuffer *buf, ut64 off, bool big_endian) {
zimage_arm32_t *h = &image->info.arm32;
off += ARM_ZIMAGE_INFO_OFFSET;
return rz_buf_read_ble32_offset(buf, &off, &h->arm32_magic, big_endian) &&
rz_buf_read_ble32_offset(buf, &off, &h->kernel_start, big_endian) &&
rz_buf_read_ble32_offset(buf, &off, &h->kernel_end, big_endian) &&
rz_buf_read_ble32_offset(buf, &off, &h->endianness_flag, big_endian) &&
rz_buf_read_ble32_offset(buf, &off, &h->magic_table_flag, big_endian) &&
rz_buf_read_ble32_offset(buf, &off, &h->magic_table, big_endian);
} }
static ut64 baddr(RzBinFile *bf) { static const zimage_marker_t zimage_markers[] = {
return 0; // clang-format off
{ ZIMAGE_ARCH_ARM32_LE, false, "4.14+" , zimage_parse_arm32, zimage_signature_arm32_le_4_14_plus, RZ_ARRAY_SIZE(zimage_signature_arm32_le_4_14_plus) },
{ ZIMAGE_ARCH_ARM32_LE, false, "3.16-4.14", zimage_parse_arm32, zimage_signature_arm32_le_3_16_4_14, RZ_ARRAY_SIZE(zimage_signature_arm32_le_3_16_4_14) },
{ ZIMAGE_ARCH_ARM32_LE, false, "2.6-3.16" , zimage_parse_arm32, zimage_signature_arm32_le_pre3_16, RZ_ARRAY_SIZE(zimage_signature_arm32_le_pre3_16) },
{ ZIMAGE_ARCH_ARM32_BE, true, "4.14+" , zimage_parse_arm32, zimage_signature_arm32_be_4_14_plus, RZ_ARRAY_SIZE(zimage_signature_arm32_be_4_14_plus) },
{ ZIMAGE_ARCH_ARM32_BE, true, "3.16-4.14", zimage_parse_arm32, zimage_signature_arm32_be_3_16_4_14, RZ_ARRAY_SIZE(zimage_signature_arm32_be_3_16_4_14) },
{ ZIMAGE_ARCH_ARM32_BE, true, "2.6-3.16" , zimage_parse_arm32, zimage_signature_arm32_be_pre3_16, RZ_ARRAY_SIZE(zimage_signature_arm32_be_pre3_16) },
{ ZIMAGE_ARCH_RISCV , false, "5.9+" , zimage_parse_riscv, zimage_signature_riscv_efi_compact_5_9 , RZ_ARRAY_SIZE(zimage_signature_riscv_efi_compact_5_9) },
{ ZIMAGE_ARCH_RISCV , false, "5.2+" , zimage_parse_riscv, zimage_signature_riscv_compact_5_2 , RZ_ARRAY_SIZE(zimage_signature_riscv_compact_5_2) },
{ ZIMAGE_ARCH_RISCV , false, "5.2+" , zimage_parse_riscv, zimage_signature_riscv_non_compact_5_2 , RZ_ARRAY_SIZE(zimage_signature_riscv_non_compact_5_2) },
{ ZIMAGE_ARCH_RISCV , false, "4.14-5.2" , zimage_parse_riscv, zimage_signature_riscv_compact_4_14 , RZ_ARRAY_SIZE(zimage_signature_riscv_compact_4_14) },
{ ZIMAGE_ARCH_RISCV , false, "4.14-5.2" , zimage_parse_riscv, zimage_signature_riscv_non_compact_4_14, RZ_ARRAY_SIZE(zimage_signature_riscv_non_compact_4_14) },
// clang-format on
};
static bool zimage_signature_check(RzBuffer *b, const zimage_signature_t *sig) {
ut8 bytes[16] = { 0 };
rz_return_val_if_fail(sig->size < sizeof(bytes), false);
if (!rz_buf_read_at(b, sig->offset, bytes, sig->size)) {
return false;
}
return !memcmp(bytes, sig->bytes, sig->size);
} }
static bool check_buffer(RzBuffer *b) { static bool zimage_marker_check(RzBuffer *b, const zimage_marker_t *marker) {
ut8 zimghdr[8]; for (size_t i = 0; i < marker->n_signatures; ++i) {
if (rz_buf_read_at(b, 0, zimghdr, sizeof(zimghdr))) { if (!zimage_signature_check(b, &marker->signatures[i])) {
// Checking ARM zImage kernel return false;
if (!memcmp(zimghdr, "\x00\x00\xa0\xe1\x00\x00\xa0\xe1", 8)) { }
}
return true;
}
static bool zimage_check_buffer(RzBuffer *b) {
for (size_t i = 0; i < RZ_ARRAY_SIZE(zimage_markers); ++i) {
const zimage_marker_t *marker = &zimage_markers[i];
if (zimage_marker_check(b, marker)) {
return true; return true;
} }
} }
return false; return false;
} }
static RzBinInfo *info(RzBinFile *bf) { static bool zimage_load_buffer(RzBinFile *bf, RzBinObject *obj, RzBuffer *b, Sdb *sdb) {
const zimage_marker_t *marker = NULL;
for (size_t i = 0; i < RZ_ARRAY_SIZE(zimage_markers); ++i) {
marker = &zimage_markers[i];
if (zimage_marker_check(b, marker)) {
break;
}
marker = NULL;
}
if (!marker) {
// should never happen.
return false;
}
zImage *image = RZ_NEW0(zImage);
if (!image || !marker->parser(image, b, 0, marker->big_endian)) {
free(image);
return false;
}
image->arch = marker->arch;
image->kernel = marker->kernel;
obj->bin_obj = image;
return true;
}
static ut64 zimage_kernel_base_address(const zImage *zo) {
if (zo->arch == ZIMAGE_ARCH_RISCV) {
return zo->info.riscv.image_load;
}
return 0;
}
static char *zimage_arch(const zImage *zo) {
switch (zo->arch) {
case ZIMAGE_ARCH_ARM32_LE:
return rz_str_dup("arm");
case ZIMAGE_ARCH_ARM32_BE:
return rz_str_dup("arm");
case ZIMAGE_ARCH_RISCV:
return rz_str_dup("riscv");
default:
return rz_str_dup("unknown");
}
}
static char *zimage_machine(const zImage *zo) {
switch (zo->arch) {
case ZIMAGE_ARCH_ARM32_LE:
return rz_str_dup("ARM32 LE");
case ZIMAGE_ARCH_ARM32_BE:
return rz_str_dup("ARM32 BE");
case ZIMAGE_ARCH_RISCV:
return rz_str_dup("RISC-V");
default:
return rz_str_dup("unknown");
}
}
static ut32 zimage_riscv_bits(const zImage *zo) {
const zimage_riscv_t *h = &zo->info.riscv;
switch (h->image_load) {
case 0x200000:
/* _riscv_xlen == 64 */
return 64;
case 0x400000:
/* this could be _riscv_xlen == 128, but nobody supports it. */
return 32;
case 0: /* RISCV_M_MODE: no-mmu */
return 32;
default:
// we keep this for any non-standard values.
return 32;
}
}
static char *zimage_riscv_cpu(const zImage *zo) {
const zimage_riscv_t *h = &zo->info.riscv;
switch (h->image_load) {
case 0x200000:
/* _riscv_xlen == 64 */
return rz_str_dup("rv64");
case 0x400000:
/* this could be _riscv_xlen == 128, but nobody supports it. */
return rz_str_dup("rv32");
case 0: /* RISCV_M_MODE: no-mmu */
return rz_str_dup("rv32+c");
default:
// we keep this for any non-standard values.
return rz_str_dup("rv32");
}
}
static char *zimage_cpu(const zImage *zo) {
switch (zo->arch) {
case ZIMAGE_ARCH_ARM32_LE:
/* fall-thru */
case ZIMAGE_ARCH_ARM32_BE:
return rz_str_dup("arm");
case ZIMAGE_ARCH_RISCV:
return zimage_riscv_cpu(zo);
default:
return NULL;
}
}
static ut32 zimage_bits(const zImage *zo) {
switch (zo->arch) {
case ZIMAGE_ARCH_ARM32_LE:
/* fall-thru */
case ZIMAGE_ARCH_ARM32_BE:
return 32;
case ZIMAGE_ARCH_RISCV:
return zimage_riscv_bits(zo);
default:
rz_warn_if_reached();
return 32;
}
}
static bool zimage_big_endian(const zImage *zo) {
switch (zo->arch) {
case ZIMAGE_ARCH_ARM32_BE:
return true;
default:
return false;
}
}
static char *zimage_detect_kernel(const zImage *zo) {
if (RZ_STR_ISNOTEMPTY(zo->kernel)) {
return rz_str_newf("Linux zImage Kernel (%s)", zo->kernel);
}
return rz_str_dup("Linux zImage Kernel");
}
static RzBinInfo *zimage_info(RzBinFile *bf) {
zImage *zo = bf->o->bin_obj;
RzBinInfo *ret = RZ_NEW0(RzBinInfo); RzBinInfo *ret = RZ_NEW0(RzBinInfo);
if (!ret) { if (!ret) {
return NULL; return NULL;
@ -41,77 +463,149 @@ static RzBinInfo *info(RzBinFile *bf) {
ret->file = rz_str_dup(bf->file); ret->file = rz_str_dup(bf->file);
ret->type = rz_str_dup("Linux zImage Kernel"); ret->type = rz_str_dup("Linux zImage Kernel");
ret->has_va = false; ret->has_va = false;
ret->bclass = rz_str_dup("Compressed Linux Kernel"); ret->bclass = zimage_detect_kernel(zo);
ret->rclass = rz_str_dup("zimg"); ret->rclass = rz_str_dup("zimg");
ret->os = rz_str_dup("linux"); ret->os = rz_str_dup("linux");
ret->subsystem = rz_str_dup("linux"); ret->subsystem = rz_str_dup("linux");
ret->machine = rz_str_dup("ARM"); // TODO: can be other cpus ret->machine = zimage_machine(zo);
ret->arch = rz_str_dup("arm"); ret->arch = zimage_arch(zo);
ret->cpu = zimage_cpu(zo);
ret->lang = "C"; ret->lang = "C";
ret->bits = 32; ret->bits = zimage_bits(zo);
ret->big_endian = 0; ret->big_endian = zimage_big_endian(zo);
ret->dbg_info = 0; // 1 | 4 | 8; /* Stripped | LineNums | Syms */ ret->dbg_info = 0;
return ret; return ret;
} }
static RzStructuredData *zimg_structure(RzBinFile *bf) { static ut64 zimage_baddr(RzBinFile *bf) {
const zImage *zo = bf->o->bin_obj;
return zimage_kernel_base_address(zo);
}
static RzBinAddr *zimage_bin_addr(RzBinSpecialSymbol type, ut64 offset, zImage *zo) {
RzBinAddr *ba = RZ_NEW0(RzBinAddr);
if (!ba) {
return NULL;
}
ba->type = type;
ba->paddr = ba->hpaddr = offset;
ba->vaddr = ba->hvaddr = zimage_kernel_base_address(zo) + offset;
ba->bits = zimage_bits(zo);
return ba;
}
static RzPVector /*<RzBinAddr *>*/ *zimage_entries(RzBinFile *bf) {
zImage *zo = bf->o->bin_obj;
RzBinAddr *ptr = NULL;
RzPVector /*<RzBinAddr *>*/ *ret = rz_pvector_new(free);
if (!ret) {
return NULL;
}
// ipl3 always includes the header, but ipl2 will jump after the ROM header.
ptr = zimage_bin_addr(RZ_BIN_SPECIAL_SYMBOL_ENTRY, 0, zo);
if (!ptr) {
rz_pvector_free(ret);
return NULL;
}
rz_pvector_push(ret, ptr);
return ret;
}
static void zimage_structure_arm32(zImage *image, RzStructuredData *root) {
zimage_arm32_t *zo = &image->info.arm32;
rz_structured_data_map_add_unsigned(root, "arm32_magic", zo->arm32_magic, true);
rz_structured_data_map_add_unsigned(root, "kernel_start", zo->kernel_start, true);
rz_structured_data_map_add_unsigned(root, "kernel_end", zo->kernel_end, true);
if (zo->endianness_flag == ARM_ZIMAGE_ENDIANNESS_VALUE) {
rz_structured_data_map_add_unsigned(root, "endianness_flag", zo->endianness_flag, true);
}
if (zo->magic_table_flag == ARM_ZIMAGE_MAGIC_TABLE_VALUE) {
rz_structured_data_map_add_unsigned(root, "magic_table_flag", zo->magic_table_flag, true);
rz_structured_data_map_add_unsigned(root, "magic_table", zo->magic_table, true);
}
}
static void zimage_structure_riscv(zImage *image, RzStructuredData *root) {
zimage_riscv_t *zo = &image->info.riscv;
rz_structured_data_map_add_unsigned(root, "image_load", zo->image_load, true);
rz_structured_data_map_add_unsigned(root, "kernel_size", zo->kernel_size, true);
rz_structured_data_map_add_unsigned(root, "head_flags", zo->head_flags, true);
RzStructuredData *version = rz_structured_data_map_add_map(root, "version");
if (version) {
rz_structured_data_map_add_unsigned(version, "major", zo->version_major, false);
rz_structured_data_map_add_unsigned(version, "minor", zo->version_minor, false);
}
rz_structured_data_map_add_unsigned(root, "padding0", zo->padding0, true);
rz_structured_data_map_add_unsigned(root, "padding1", zo->padding1, true);
rz_structured_data_map_add_bytes(root, "riscv_magic1", zo->riscv_magic1, sizeof(zo->riscv_magic1), RZ_STRUCTURED_DATA_FORMAT_HEXDUMP);
rz_structured_data_map_add_bytes(root, "riscv_magic2", zo->riscv_magic2, sizeof(zo->riscv_magic2), RZ_STRUCTURED_DATA_FORMAT_HEXDUMP);
if (zo->pe_header_offset) {
rz_structured_data_map_add_unsigned(root, "pe_header_offset", zo->pe_header_offset, true);
}
}
static RzStructuredData *zimage_structure(RzBinFile *bf) {
rz_return_val_if_fail(bf && bf->o && bf->o->bin_obj, NULL); rz_return_val_if_fail(bf && bf->o && bf->o->bin_obj, NULL);
RzBinZimgObj *zo = bf->o->bin_obj; zImage *image = bf->o->bin_obj;
RzStructuredData *info = rz_structured_data_new_map(); RzStructuredData *info = rz_structured_data_new_map();
if (!info) { if (!info) {
return NULL; return NULL;
} }
RzStructuredData *zimg = rz_structured_data_map_add_map(info, "zimg"); RzStructuredData *root = rz_structured_data_map_add_map(info, "zImage");
if (!zimg) { if (!root) {
rz_structured_data_free(info); rz_structured_data_free(info);
return NULL; return NULL;
} }
rz_structured_data_map_add_unsigned(zimg, "size", zo->size, false); rz_structured_data_map_add_string(root, "machine", zimage_machine(image));
if (RZ_STR_ISNOTEMPTY(image->kernel)) {
rz_structured_data_map_add_string(root, "kernel", image->kernel);
}
RzStructuredData *kernel = rz_structured_data_map_add_map(zimg, "kernel"); switch (image->arch) {
if (!kernel) { case ZIMAGE_ARCH_ARM32_LE:
/* fall-thru */
case ZIMAGE_ARCH_ARM32_BE:
zimage_structure_arm32(image, root);
break;
case ZIMAGE_ARCH_RISCV:
zimage_structure_riscv(image, root);
break;
default:
rz_structured_data_free(info); rz_structured_data_free(info);
return NULL; return NULL;
} }
RzStructuredData *magic = rz_structured_data_map_add_map(zimg, "magic");
if (!magic) {
rz_structured_data_free(info);
return NULL;
}
ut32 magic0 = rz_read_le32(&zo->header.magic[0]);
ut32 magic1 = rz_read_le32(&zo->header.magic[4]);
ut32 arm_magic = rz_read_le32(zo->header.arm_magic);
rz_structured_data_map_add_unsigned(magic, "magic0", magic0, true);
rz_structured_data_map_add_unsigned(magic, "magic1", magic1, true);
rz_structured_data_map_add_unsigned(magic, "arm_magic", arm_magic, true);
ut64 kernel_start = zo->header.kernel_start;
ut64 kernel_end = zo->header.kernel_end;
rz_structured_data_map_add_unsigned(kernel, "kernel_start", kernel_start, true);
rz_structured_data_map_add_unsigned(kernel, "kernel_end", kernel_end, true);
rz_structured_data_map_add_unsigned(kernel, "kernel_size", kernel_end - kernel_start, false);
return info; return info;
} }
RzBinPlugin rz_bin_plugin_zimg = { RzBinPlugin rz_bin_plugin_zimg = {
.name = "zimg", .name = "zimg",
.desc = "ZIMG format binary", .desc = "zImage format binary",
.license = "LGPL3", .license = "LGPL3",
.author = "ninjahacker", .author = "deroad",
.get_sdb = &get_sdb, .load_buffer = &zimage_load_buffer,
.load_buffer = &load_buffer, .check_buffer = &zimage_check_buffer,
.check_buffer = &check_buffer, .baddr = &zimage_baddr,
.baddr = &baddr, .info = &zimage_info,
.info = &info, .entries = &zimage_entries,
.bin_structure = &zimg_structure .bin_structure = &zimage_structure
}; };
#ifndef RZ_PLUGIN_INCORE #ifndef RZ_PLUGIN_INCORE

View file

@ -16,6 +16,14 @@ typedef enum rz_structured_data_block_t {
RZ_STRUCTURED_DATA_BLOCK_ARRAY = 1, RZ_STRUCTURED_DATA_BLOCK_ARRAY = 1,
} RzStructuredDataBlock; } RzStructuredDataBlock;
typedef enum rz_structured_data_format_t {
RZ_STRUCTURED_DATA_FORMAT_DEFAULT = 0, ///< Bytes are printed as hexadecimal one after each other.
RZ_STRUCTURED_DATA_FORMAT_COLON, ///< Bytes are printed as hexadecimal but separated by colons (`:`)
RZ_STRUCTURED_DATA_FORMAT_HEXDUMP, ///< Bytes are printed as a hexdump (16 bytes per line)
/// size
RZ_STRUCTURED_DATA_FORMAT_ENUM_MAX
} RzStructuredDataFormat;
typedef struct rz_structured_data_t RzStructuredData; typedef struct rz_structured_data_t RzStructuredData;
typedef void (*RzStructuredDataIteratorNew)(RZ_NULLABLE void *user, RzStructuredDataBlock block, size_t n_elems); typedef void (*RzStructuredDataIteratorNew)(RZ_NULLABLE void *user, RzStructuredDataBlock block, size_t n_elems);
@ -51,6 +59,8 @@ RZ_API bool rz_structured_data_map_add_signed(RZ_NONNULL RzStructuredData *paren
RZ_API bool rz_structured_data_map_add_double(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const char *key, double d); RZ_API bool rz_structured_data_map_add_double(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const char *key, double d);
RZ_API bool rz_structured_data_map_add_boolean(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const char *key, bool b); RZ_API bool rz_structured_data_map_add_boolean(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const char *key, bool b);
RZ_API bool rz_structured_data_map_add_string(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const char *key, RZ_NONNULL const char *v); RZ_API bool rz_structured_data_map_add_string(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const char *key, RZ_NONNULL const char *v);
RZ_API bool rz_structured_data_map_add_string_n(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const char *key, RZ_NONNULL const char *v, size_t v_size);
RZ_API bool rz_structured_data_map_add_bytes(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const char *key, RZ_NONNULL const ut8 *v, size_t v_size, RzStructuredDataFormat fmt);
/* primitive types for arrays */ /* primitive types for arrays */
RZ_API RZ_BORROW RzStructuredData *rz_structured_data_array_add_map(RZ_NONNULL RzStructuredData *parent); RZ_API RZ_BORROW RzStructuredData *rz_structured_data_array_add_map(RZ_NONNULL RzStructuredData *parent);
@ -61,6 +71,8 @@ RZ_API bool rz_structured_data_array_add_signed(RZ_NONNULL RzStructuredData *par
RZ_API bool rz_structured_data_array_add_double(RZ_NONNULL RzStructuredData *parent, double d); RZ_API bool rz_structured_data_array_add_double(RZ_NONNULL RzStructuredData *parent, double d);
RZ_API bool rz_structured_data_array_add_boolean(RZ_NONNULL RzStructuredData *parent, bool b); RZ_API bool rz_structured_data_array_add_boolean(RZ_NONNULL RzStructuredData *parent, bool b);
RZ_API bool rz_structured_data_array_add_string(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const char *v); RZ_API bool rz_structured_data_array_add_string(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const char *v);
RZ_API bool rz_structured_data_array_add_string_n(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const char *v, size_t v_size);
RZ_API bool rz_structured_data_array_add_bytes(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const ut8 *v, size_t v_size, RzStructuredDataFormat fmt);
RZ_API void rz_structured_data_iterate(RZ_NONNULL const RzStructuredData *sd, RZ_NONNULL const RzStructuredDataIterator *iterator, RZ_NULLABLE void *user); RZ_API void rz_structured_data_iterate(RZ_NONNULL const RzStructuredData *sd, RZ_NONNULL const RzStructuredDataIterator *iterator, RZ_NULLABLE void *user);
RZ_API void rz_structured_data_to_pj(RZ_NONNULL const RzStructuredData *sd, RZ_NONNULL PJ *pj); RZ_API void rz_structured_data_to_pj(RZ_NONNULL const RzStructuredData *sd, RZ_NONNULL PJ *pj);

View file

@ -182,6 +182,67 @@ static bool structured_data_array_add(RZ_NONNULL RzStructuredData *parent, RZ_NO
return true; return true;
} }
static char *structured_data_hexdump_padded(const ut8 *buffer, const size_t length) {
size_t i = 0, j = 0;
char readable[20] = { 0 };
RzStrBuf sb = { 0 };
rz_strbuf_init(&sb);
for (i = 0, j = 0; i < length; i++, j++) {
const ut8 c = buffer[i];
if (i > 0 && (i % 16) == 0) {
rz_strbuf_appendf(&sb, "|%-16s|\n", readable);
memset(readable, 0, sizeof(readable));
j = 0;
}
rz_strbuf_appendf(&sb, "%02x ", c);
readable[j] = IS_PRINTABLE(c) ? c : '.';
}
while ((i % 16) != 0) {
rz_strbuf_append_n(&sb, " ", 3);
i++;
}
rz_strbuf_appendf(&sb, "|%-16s|", readable);
return rz_strbuf_drain_nofree(&sb);
}
static char *structured_data_hex_colon_padded(const ut8 *buffer, size_t length) {
const char *hex = "0123456789abcdef";
const size_t size = 3 * length;
char *output = malloc(size);
if (!output) {
return NULL;
}
for (size_t i = 0, j = 0; i < length && j < size; i++, j += 3) {
const ut8 c = buffer[i];
output[j + 0] = hex[c >> 4];
output[j + 1] = hex[c & 0xf];
output[j + 2] = ':';
}
// always overwrite the last byte with null char.
output[size - 1] = '\0';
return output;
}
static char *structured_data_bytes_to_string(const ut8 *buffer, const size_t length, RzStructuredDataFormat fmt) {
if (length < 1) {
return strdup("");
}
switch (fmt) {
case RZ_STRUCTURED_DATA_FORMAT_COLON:
return structured_data_hex_colon_padded(buffer, length);
case RZ_STRUCTURED_DATA_FORMAT_HEXDUMP:
return structured_data_hexdump_padded(buffer, length);
default /* RZ_STRUCTURED_DATA_FORMAT_DEFAULT */:
return rz_hex_bin2strdup(buffer, length);
}
}
/** /**
* \brief Creates a new RzStructuredData initialized as a map * \brief Creates a new RzStructuredData initialized as a map
* *
@ -339,6 +400,51 @@ RZ_API bool rz_structured_data_map_add_string(RZ_NONNULL RzStructuredData *paren
return structured_data_map_add(parent, key, child); return structured_data_map_add(parent, key, child);
} }
/**
* \brief Adds a null terminated string type child (with a max size of n) to a parent and assigns it a map key
*
* \param parent Where to add the child RzStructuredData
* \param[in] key The key to assign the child RzStructuredData
* \param s The string value to assign to the child
* \param s_len The max size of the string value
*
* \return On success returns true, otherwise false.
*/
RZ_API bool rz_structured_data_map_add_string_n(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const char *key, RZ_NONNULL const char *s, size_t s_len) {
rz_return_val_if_fail(parent && parent->type == STRUCTURED_DATA_TYPE_MAP && key && s, false);
char *copy = rz_str_ndup(s, s_len);
if (!copy) {
return false;
}
RzStructuredData *child = structured_data_new_string(copy);
return structured_data_map_add(parent, key, child);
}
/**
* \brief Generates a hexdump of the bytes and assignes the string type child to a map parent
*
* \param parent Where to add the child RzStructuredData
* \param[in] key The key to assign the child RzStructuredData
* \param v The bytes value to hexdump and assign to the child
* \param v_size The max size of the bytes value
* \param fmt The format to use when dumping the bytes
*
* \return On success returns true, otherwise false.
*/
RZ_API bool rz_structured_data_map_add_bytes(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const char *key, RZ_NONNULL const ut8 *v, size_t v_size, RzStructuredDataFormat fmt) {
rz_return_val_if_fail(parent && parent->type == STRUCTURED_DATA_TYPE_MAP && key && v && fmt < RZ_STRUCTURED_DATA_FORMAT_ENUM_MAX, false);
char *copy = structured_data_bytes_to_string(v, v_size, fmt);
if (!copy) {
return false;
}
RzStructuredData *child = structured_data_new_string(copy);
return structured_data_map_add(parent, key, child);
}
/** /**
* \brief Returns a child, map type, RzStructuredData that has been added to the given parent * \brief Returns a child, map type, RzStructuredData that has been added to the given parent
* *
@ -454,7 +560,7 @@ RZ_API bool rz_structured_data_array_add_boolean(RZ_NONNULL RzStructuredData *pa
* \brief Adds a null terminated string type child to an array type parent * \brief Adds a null terminated string type child to an array type parent
* *
* \param parent Where to add the child RzStructuredData * \param parent Where to add the child RzStructuredData
* \param n The value to assign to the child * \param s The string value to assign to the child
* *
* \return On success returns true, otherwise false. * \return On success returns true, otherwise false.
*/ */
@ -470,6 +576,49 @@ RZ_API bool rz_structured_data_array_add_string(RZ_NONNULL RzStructuredData *par
return structured_data_array_add(parent, child); return structured_data_array_add(parent, child);
} }
/**
* \brief Adds a null terminated string type child (with a max size of n) to an array type parent
*
* \param parent Where to add the child RzStructuredData
* \param s The string value to assign to the child
* \param s_len The size of the string value
*
* \return On success returns true, otherwise false.
*/
RZ_API bool rz_structured_data_array_add_string_n(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const char *s, size_t s_len) {
rz_return_val_if_fail(parent && parent->type == STRUCTURED_DATA_TYPE_ARRAY && s, false);
char *copy = rz_str_ndup(s, s_len);
if (!copy) {
return false;
}
RzStructuredData *child = structured_data_new_string(copy);
return structured_data_array_add(parent, child);
}
/**
* \brief Generates a hexdump of the bytes and assignes the string type child to an array type parent
*
* \param parent Where to add the child RzStructuredData
* \param v The bytes value to hexdump and assign to the child
* \param v_size The max size of the bytes value
* \param fmt The format to use when dumping the bytes
*
* \return On success returns true, otherwise false.
*/
RZ_API bool rz_structured_data_array_add_bytes(RZ_NONNULL RzStructuredData *parent, RZ_NONNULL const ut8 *v, size_t v_size, RzStructuredDataFormat fmt) {
rz_return_val_if_fail(parent && parent->type == STRUCTURED_DATA_TYPE_ARRAY && v && fmt < RZ_STRUCTURED_DATA_FORMAT_ENUM_MAX, false);
char *copy = structured_data_bytes_to_string(v, v_size, fmt);
if (!copy) {
return false;
}
RzStructuredData *child = structured_data_new_string(copy);
return structured_data_array_add(parent, child);
}
static void structured_data_iterate_over(StructuredDataIterOver *sdio, const RzStructuredData *sd); static void structured_data_iterate_over(StructuredDataIterOver *sdio, const RzStructuredData *sd);
static void structured_data_iterate_over_map(StructuredDataIterOver *sdio, const RzStructuredData *sd) { static void structured_data_iterate_over_map(StructuredDataIterOver *sdio, const RzStructuredData *sd) {

File diff suppressed because one or more lines are too long

View file

@ -1,20 +1,26 @@
NAME=Test 32-bit arm NAME=ARM32 LE zImage 3.16-4.14
FILE=bins/zimg/arm32 FILE=bins/zimg/arm32
CMDS=<<EOF CMDS=<<EOF
iI iI
echo --- echo ---
iH iH
echo ---
oml
echo ---
pd 16
echo ---
pxw 16 @ 0x24
EOF EOF
EXPECT=<<EOF EXPECT=<<EOF
arch arm arch arm
cpu N/A cpu arm
features N/A features N/A
baddr 0x00000000 baddr 0x00000000
binsz 0x00000400 binsz 0x00000400
bintype zimg bintype zimg
bits 32 bits 32
retguard false retguard false
class Compressed Linux Kernel class Linux zImage Kernel (3.16-4.14)
compiler N/A compiler N/A
dbg_file N/A dbg_file N/A
endian LE endian LE
@ -23,7 +29,7 @@ guid N/A
intrp N/A intrp N/A
laddr 0x00000000 laddr 0x00000000
lang C lang C
machine ARM machine ARM32 LE
maxopsz 4 maxopsz 4
minopsz 4 minopsz 4
os linux os linux
@ -44,24 +50,230 @@ PIE false
RELROCS false RELROCS false
NX false NX false
--- ---
zimg: zImage:
size: 1024 machine: "ARM32 LE"
kernel: kernel: "3.16-4.14"
kernel_start: 0x16f2818 arm32_magic: 0x16f2818
kernel_end: 0x0 kernel_start: 0x0
kernel_size: 18446744073685489640 kernel_end: 0x343448
magic: endianness_flag: 0x4030201
magic0: 0xe1a00000
magic1: 0xe1a00000
arm_magic: 0xea000003
EOF ---
RUN
NAME=zimg maps
FILE=bins/zimg/arm32
CMDS=oml
EXPECT=<<EOF
1 fd: 3 +0x00000000 0x00000000 * 0x000003ff r-x 1 fd: 3 +0x00000000 0x00000000 * 0x000003ff r-x
---
;-- entry0:
0x00000000 mov r0, r0
0x00000004 mov r0, r0
0x00000008 mov r0, r0
0x0000000c mov r0, r0
0x00000010 mov r0, r0
0x00000014 mov r0, r0
0x00000018 mov r0, r0
0x0000001c mov r0, r0
,=< 0x00000020 b 0x34
| 0x00000024 invalid
| 0x00000028 andeq r0, r0, r0
| 0x0000002c eorseq r3, r4, r8, asr 8
| 0x00000030 streq r0, [r3], -0x201
`-> 0x00000034 mrs sb, apsr
0x00000038 bl 0x3700
0x0000003c mov r7, r1
---
0x00000024 0x016f2818 0x00000000 0x00343448 0x04030201 .(o.....H44.....
EOF
RUN
NAME=ARM32 LE zImage 3.14
FILE=bins/zimg/zImage.3.14.arm32le
CMDS=<<EOF
iI
echo ---
iH
echo ---
oml
echo ---
pd 16
echo ---
pxw 16 @ 0x24
EOF
EXPECT=<<EOF
arch arm
cpu arm
features N/A
baddr 0x00000000
binsz 0x00000200
bintype zimg
bits 32
retguard false
class Linux zImage Kernel (2.6-3.16)
compiler N/A
dbg_file N/A
endian LE
hdr.csum N/A
guid N/A
intrp N/A
laddr 0x00000000
lang C
machine ARM32 LE
maxopsz 4
minopsz 4
os linux
cc N/A
pcalign 4
rpath N/A
subsys linux
stripped false
crypto false
havecode true
va false
sanitiz false
static true
linenum false
lsyms false
canary false
PIE false
RELROCS false
NX false
---
zImage:
machine: "ARM32 LE"
kernel: "2.6-3.16"
arm32_magic: 0x16f2818
kernel_start: 0x0
kernel_end: 0x5abcd0
---
1 fd: 3 +0x00000000 0x00000000 * 0x000001ff r-x
---
;-- entry0:
0x00000000 mov r0, r0
0x00000004 mov r0, r0
0x00000008 mov r0, r0
0x0000000c mov r0, r0
0x00000010 mov r0, r0
0x00000014 mov r0, r0
0x00000018 mov r0, r0
0x0000001c mov r0, r0
,=< 0x00000020 b 0x30
| 0x00000024 invalid
| 0x00000028 andeq r0, r0, r0
| 0x0000002c ldrsbeq fp, [sl], -0xc0
`-> 0x00000030 mrs sb, apsr
0x00000034 bl 0x1480
0x00000038 mov r7, r1
0x0000003c mov r8, r2
---
0x00000024 0x016f2818 0x00000000 0x005abcd0 0xe10f9000 .(o.......Z.....
EOF
RUN
NAME=rv64 zImage 5.4
FILE=bins/zimg/zImage.5.4.rv64
CMDS=<<EOF
iI
echo ---
iH
echo ---
oml
echo ---
pd 32
echo ---
pxq 64 @ 0x8
EOF
EXPECT=<<EOF
arch riscv
cpu rv64
features N/A
baddr 0x00200000
binsz 0x00000200
bintype zimg
bits 64
retguard false
class Linux zImage Kernel (5.2+)
compiler N/A
dbg_file N/A
endian LE
hdr.csum N/A
guid N/A
intrp N/A
laddr 0x00000000
lang C
machine RISC-V
maxopsz 6
minopsz 4
os linux
cc N/A
pcalign 2
rpath N/A
subsys linux
stripped false
crypto false
havecode true
va false
sanitiz false
static true
linenum false
lsyms false
canary false
PIE false
RELROCS false
NX false
---
zImage:
machine: "RISC-V"
kernel: "5.2+"
image_load: 0x200000
kernel_size: 0x92416c
head_flags: 0x0
version:
major: 0
minor: 2
padding0: 0x0
padding1: 0x0
riscv_magic1: "52 49 53 43 56 00 00 00 |RISCV... |"
riscv_magic2: "52 53 43 05 |RSC. |"
---
1 fd: 3 +0x00000000 0x00000000 * 0x000001ff r-x
---
;-- entry0:
,=< 0x00000000 j 0x40
| 0x00000002 illegal
| 0x00000004 illegal
| 0x00000006 nop
| 0x00000008 illegal
| 0x0000000a addi s0, sp, 8
| 0x0000000c illegal
| 0x0000000e illegal
| 0x00000010 lw a1, 68(a0)
| 0x00000012 slli ra, ra, 0x4
| 0x00000014 illegal
| 0x00000016 illegal
| 0x00000018 illegal
| 0x0000001a illegal
| 0x0000001c illegal
| 0x0000001e illegal
| 0x00000020 invalid
| 0x00000022 illegal
| 0x00000024 illegal
| 0x00000026 illegal
| 0x00000028 illegal
| 0x0000002a illegal
| 0x0000002c illegal
| 0x0000002e illegal
| ;-- str.RISCV:
| 0x00000030 .string "RISCV" ; len=6
| 0x00000036 illegal
| 0x00000038 lw t1, 52(sp)
| 0x0000003a fmadd.s fa0, ft0, ft0, ft0, rne
| 0x0000003e illegal
`-> 0x00000040 csrw sie, zero
0x00000044 csrw sip, zero
0x00000048 auipc gp, 0x8e2
---
0x00000008 0x0000000000200000 0x000000000092416c .. .....lA......
0x00000018 0x0000000000000000 0x0000000000000002 ................
0x00000028 0x0000000000000000 0x0000005643534952 ........RISCV...
0x00000038 0x0000000005435352 0x1440107310401073 RSC.....s.@.s.@.
EOF EOF
RUN RUN