Arch-agnostic jemalloc heap parser (#5828)

This commit is contained in:
bubblepipe 2026-01-27 15:31:48 +08:00 committed by GitHub
parent 3ed43c4c77
commit dca635cde9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 2628 additions and 944 deletions

View file

@ -3204,6 +3204,10 @@ RZ_API int rz_core_config_init(RzCore *core) {
SETDESC(n, "Select jemalloc version for heap parsing (auto-detected if 'auto')");
SETOPTIONS(n, "auto", "4.5.0", "5.3.0", NULL);
n = NODECB("dbg.jemalloc.page_size", "auto", NULL);
SETDESC(n, "Select page size for jemalloc heap parsing (auto-detected if 'auto')");
SETOPTIONS(n, "auto", "4k", "16k", "64k", NULL);
SETBPREF("esil.prestep", "true", "Step before esil evaluation in `de` commands");
SETPREF("esil.fillstack", "", "Initialize ESIL stack with (random, debrujn, sequence, zeros, ...)");
SETICB("esil.verbose", 0, &cb_esilverbose, "Show ESIL verbose level (0, 1, 2)");

View file

@ -5,7 +5,7 @@
#include <rz_core.h>
#include <rz_heap_jemalloc.h>
static ut64 je_get_va_symbol(RzCore *core, const char *path, const char *sym_name, bool is_64bit) {
static ut64 je_get_va_symbol(RzCore *core, const char *path, const char *sym_name) {
ut64 vaddr = UT64_MAX;
RzBin *bin = core->bin;
RzBinFile *current_bf = rz_bin_cur(bin);
@ -39,7 +39,7 @@ static ut64 je_get_va_symbol(RzCore *core, const char *path, const char *sym_nam
return vaddr;
}
static bool rz_resolve_jemalloc(RzCore *core, const char *symname, ut64 *symbol, bool is_64bit) {
static bool rz_resolve_jemalloc(RzCore *core, const char *symname, ut64 *symbol) {
RzListIter *iter;
RzDebugMap *map;
const char *jemalloc_path = NULL;
@ -72,7 +72,7 @@ static bool rz_resolve_jemalloc(RzCore *core, const char *symname, ut64 *symbol,
if (jemalloc_path) {
char *path = rz_str_newf("%s", jemalloc_path);
if (rz_file_exists(path)) {
ut64 vaddr = je_get_va_symbol(core, path, symname, is_64bit);
ut64 vaddr = je_get_va_symbol(core, path, symname);
if (jemalloc_addr != UT64_MAX && vaddr != UT64_MAX) {
*symbol = jemalloc_addr + vaddr;
free(path);
@ -86,7 +86,7 @@ static bool rz_resolve_jemalloc(RzCore *core, const char *symname, ut64 *symbol,
if (binary_path) {
char *path = rz_str_newf("%s", binary_path);
if (rz_file_exists(path)) {
ut64 vaddr = je_get_va_symbol(core, path, symname, is_64bit);
ut64 vaddr = je_get_va_symbol(core, path, symname);
if (binary_addr != UT64_MAX && vaddr != UT64_MAX) {
*symbol = binary_addr + vaddr;
free(path);
@ -104,19 +104,19 @@ static bool rz_resolve_jemalloc(RzCore *core, const char *symname, ut64 *symbol,
* jemalloc 4.x has je_chunksize symbol (chunk-based architecture)
* jemalloc 5.x does NOT have je_chunksize (extent-based architecture)
*/
static bool rz_jemalloc_detect_version(RzCore *core, bool is_64bit) {
static bool rz_jemalloc_detect_version(RzCore *core) {
ut64 chunksize_addr;
const char *current_version = rz_config_get(core->config, "dbg.jemalloc.version");
// Try to resolve je_chunksize - only exists in jemalloc 4.5.0
if (rz_resolve_jemalloc(core, "je_chunksize", &chunksize_addr, is_64bit)) {
if (rz_resolve_jemalloc(core, "je_chunksize", &chunksize_addr)) {
// je_chunksize found -> jemalloc 4.5.0
if (strcmp(current_version, "4.5.0") != 0) {
rz_config_set(core->config, "dbg.jemalloc.version", "4.5.0");
RZ_LOG_INFO("Detected jemalloc 4.5.0 (je_chunksize symbol found)\n");
}
return true;
} else if (rz_resolve_jemalloc(core, "je_arena_emap_global", &chunksize_addr, is_64bit)) {
} else if (rz_resolve_jemalloc(core, "je_arena_emap_global", &chunksize_addr)) {
if (strcmp(current_version, "5.3.0") != 0) {
rz_config_set(core->config, "dbg.jemalloc.version", "5.3.0");
RZ_LOG_INFO("Detected jemalloc 5.3.0 (je_arena_emap_global symbol found)\n");
@ -129,20 +129,8 @@ static bool rz_jemalloc_detect_version(RzCore *core, bool is_64bit) {
}
}
// ============================================================================
// jemalloc 4.5.0
// ============================================================================
/**
* \brief Read a pointer-sized value from memory
* \param io RzIO instance
* \param addr Address to read from
* \param value Output pointer for the value
* \param is_64bit Whether the target is 64-bit
* \return true on success, false on failure
*/
static inline bool read_ptr_at(RzIO *io, ut64 addr, ut64 *value, bool is_64bit) {
if (is_64bit) {
static inline bool read_ptr_at(RzIO *io, ut64 addr, ut64 *value, ut8 ptr_size) {
if (ptr_size == 8) {
ut8 buf[8];
if (!rz_io_read_at_mapped(io, addr, buf, 8)) {
return false;
@ -158,16 +146,19 @@ static inline bool read_ptr_at(RzIO *io, ut64 addr, ut64 *value, bool is_64bit)
return true;
}
static void jemalloc_get_chunks_450(RzCore *core, const char *input, bool is_64bit) {
// ============================================================================
// jemalloc 4.5.0
// ============================================================================
static void jemalloc_get_chunks_450(RzCore *core, const char *input, const RzJemallocConfig450 *config) {
ut64 cnksz;
RzConsPrintablePalette *pal = &rz_cons_singleton()->context->pal;
size_t ptr_size = is_64bit ? 8 : 4;
if (!rz_resolve_jemalloc(core, "je_chunksize", &cnksz, is_64bit)) {
if (!rz_resolve_jemalloc(core, "je_chunksize", &cnksz)) {
RZ_LOG_ERROR("Fail at reading symbol je_chunksize\n");
return;
}
if (!read_ptr_at(core->io, cnksz, &cnksz, is_64bit)) {
if (!read_ptr_at(core->io, cnksz, &cnksz, config->ptr_size)) {
RZ_LOG_ERROR("Failed to read je_chunksize value\n");
return;
}
@ -185,14 +176,14 @@ static void jemalloc_get_chunks_450(RzCore *core, const char *input, bool is_64b
return;
}
if (!read_and_parse_arena_t_450(core->io, arena_addr, &ar, is_64bit)) {
if (!read_and_parse_arena_t_450(core->io, arena_addr, &ar, config)) {
RZ_LOG_ERROR("Failed to read arena at 0x%" PFMT64x "\n", arena_addr);
return;
}
// Read achunks.qlh_first pointer
ut64 achunks_first = 0;
if (!read_achunks_first_450(core->io, ar.achunks_addr, &achunks_first, is_64bit)) {
if (!read_achunks_first_450(core->io, ar.achunks_addr, &achunks_first, config)) {
RZ_LOG_ERROR("Failed to read achunks list head\n");
return;
}
@ -201,7 +192,7 @@ static void jemalloc_get_chunks_450(RzCore *core, const char *input, bool is_64b
return;
}
if (!read_and_parse_extent_node_t_450(core->io, achunks_first, &head, is_64bit)) {
if (!read_and_parse_extent_node_t_450(core->io, achunks_first, &head, config)) {
RZ_LOG_ERROR("Failed to read extent_node\n");
return;
}
@ -215,7 +206,7 @@ static void jemalloc_get_chunks_450(RzCore *core, const char *input, bool is_64b
PRINTF_BA("0x%08" PFMT64x "\n", cnksz);
ut64 next_addr = head.ql_link_next;
while (next_addr && read_and_parse_extent_node_t_450(core->io, next_addr, &node, is_64bit)) {
while (next_addr && read_and_parse_extent_node_t_450(core->io, next_addr, &node, config)) {
if (node.en_addr == head.en_addr) {
break;
}
@ -236,18 +227,18 @@ static void jemalloc_get_chunks_450(RzCore *core, const char *input, bool is_64b
arena_t_450 ar;
extent_node_t_450 node, head;
if (!rz_resolve_jemalloc(core, "je_arenas", &sym, is_64bit)) {
if (!rz_resolve_jemalloc(core, "je_arenas", &sym)) {
RZ_LOG_ERROR("Cannot resolve je_arenas\n");
return;
}
if (!read_ptr_at(core->io, sym, &arenas_ptr, is_64bit)) {
if (!read_ptr_at(core->io, sym, &arenas_ptr, config->ptr_size)) {
RZ_LOG_ERROR("Failed to read je_arenas pointer\n");
return;
}
for (;;) {
if (!read_ptr_at(core->io, arenas_ptr + i * ptr_size, &arena_addr, is_64bit)) {
if (!read_ptr_at(core->io, arenas_ptr + i * config->ptr_size, &arena_addr, config->ptr_size)) {
break;
}
if (!arena_addr) {
@ -256,19 +247,19 @@ static void jemalloc_get_chunks_450(RzCore *core, const char *input, bool is_64b
PRINTF_GA("arenas[%d]: @ 0x%" PFMT64x " { \n", i++, arena_addr);
if (!read_and_parse_arena_t_450(core->io, arena_addr, &ar, is_64bit)) {
if (!read_and_parse_arena_t_450(core->io, arena_addr, &ar, config)) {
PRINT_GA("}\n");
continue;
}
ut64 achunks_first = 0;
if (!read_achunks_first_450(core->io, ar.achunks_addr, &achunks_first, is_64bit) ||
if (!read_achunks_first_450(core->io, ar.achunks_addr, &achunks_first, config) ||
achunks_first == 0) {
PRINT_GA("}\n");
continue;
}
if (!read_and_parse_extent_node_t_450(core->io, achunks_first, &head, is_64bit)) {
if (!read_and_parse_extent_node_t_450(core->io, achunks_first, &head, config)) {
PRINT_GA("}\n");
continue;
}
@ -282,7 +273,7 @@ static void jemalloc_get_chunks_450(RzCore *core, const char *input, bool is_64b
PRINTF_BA("0x%08" PFMT64x "\n", cnksz);
ut64 next_addr = head.ql_link_next;
while (next_addr && read_and_parse_extent_node_t_450(core->io, next_addr, &node, is_64bit)) {
while (next_addr && read_and_parse_extent_node_t_450(core->io, next_addr, &node, config)) {
if (node.en_addr == head.en_addr) {
break;
}
@ -300,18 +291,17 @@ static void jemalloc_get_chunks_450(RzCore *core, const char *input, bool is_64b
}
}
static void jemalloc_print_narenas_450(RzCore *core, const char *input, bool is_64bit) {
static void jemalloc_print_narenas_450(RzCore *core, const char *input, const RzJemallocConfig450 *config) {
ut64 symaddr;
ut64 arenas;
ut64 arena_addr = UT64_MAX;
int i = 0;
ut64 narenas = 0;
RzConsPrintablePalette *pal = &rz_cons_singleton()->context->pal;
size_t ptr_size = is_64bit ? 8 : 4;
if (input[0] == '\0') {
if (rz_resolve_jemalloc(core, "narenas_total", &symaddr, is_64bit)) {
if (!read_ptr_at(core->io, symaddr, &narenas, is_64bit)) {
if (rz_resolve_jemalloc(core, "narenas_total", &symaddr)) {
if (!read_ptr_at(core->io, symaddr, &narenas, config->ptr_size)) {
RZ_LOG_ERROR("Failed to read narenas_total\n");
return;
}
@ -326,15 +316,15 @@ static void jemalloc_print_narenas_450(RzCore *core, const char *input, bool is_
return;
}
if (rz_resolve_jemalloc(core, "je_arenas", &arenas, is_64bit)) {
if (!read_ptr_at(core->io, arenas, &arenas, is_64bit)) {
if (rz_resolve_jemalloc(core, "je_arenas", &arenas)) {
if (!read_ptr_at(core->io, arenas, &arenas, config->ptr_size)) {
RZ_LOG_ERROR("Failed to read je_arenas pointer\n");
return;
}
PRINTF_GA("arenas[%" PFMT64d "] @ 0x%" PFMT64x " {\n", narenas, arenas);
for (i = 0; i < (int)narenas; i++) {
ut64 at = arenas + (i * ptr_size);
if (!read_ptr_at(core->io, at, &arena_addr, is_64bit)) {
ut64 at = arenas + (i * config->ptr_size);
if (!read_ptr_at(core->io, at, &arena_addr, config->ptr_size)) {
continue;
}
if (!arena_addr) {
@ -352,7 +342,7 @@ static void jemalloc_print_narenas_450(RzCore *core, const char *input, bool is_
arena_addr = rz_num_math(core->num, addr_str);
arena_t_450 ar;
if (!read_and_parse_arena_t_450(core->io, arena_addr, &ar, is_64bit)) {
if (!read_and_parse_arena_t_450(core->io, arena_addr, &ar, config)) {
RZ_LOG_ERROR("Failed to read arena at 0x%" PFMT64x "\n", arena_addr);
return;
}
@ -386,19 +376,18 @@ static void jemalloc_print_narenas_450(RzCore *core, const char *input, bool is_
PRINTF_BA(" node_cache = 0x%" PFMT64x "\n", ar.node_cache_addr);
PRINTF_BA(" node_cache_mtx = 0x%" PFMT64x "\n", ar.node_cache_mtx_addr);
PRINTF_BA(" chunks_hooks = 0x%" PFMT64x "\n", ar.chunk_hooks_addr);
PRINTF_BA(" bins = %d 0x%" PFMT64x "\n", JM_NBINS_450, ar.bins_addr);
PRINTF_BA(" runs_avail = %d 0x%" PFMT64x "\n", npsizes_450(is_64bit), ar.runs_avail_addr);
PRINTF_BA(" bins = %d 0x%" PFMT64x "\n", config->sc_nbins, ar.bins_addr);
PRINTF_BA(" runs_avail = %d 0x%" PFMT64x "\n", config->npsizes, ar.runs_avail_addr);
PRINT_GA("}\n");
}
}
// Helper to print bin info for a single arena
static void jemalloc_print_arena_bins_450(RzCore *core, ut64 arena_addr, ut64 bin_info, RzConsPrintablePalette *pal, bool is_64bit) {
static void jemalloc_print_arena_bins_450(RzCore *core, ut64 arena_addr, ut64 bin_info, RzConsPrintablePalette *pal, const RzJemallocConfig450 *config) {
arena_bin_info_t_450 b;
size_t bin_info_size = arena_bin_info_size_450(is_64bit);
for (int j = 0; j < JM_NBINS_450; j++) {
if (!read_and_parse_arena_bin_info_t_450(core->io, bin_info + j * bin_info_size, &b, is_64bit)) {
for (ut32 j = 0; j < config->sc_nbins; j++) {
if (!read_and_parse_arena_bin_info_t_450(core->io, bin_info + j * config->bin_info_size, &b, config)) {
continue;
}
PRINT_YA(" {\n");
@ -418,35 +407,34 @@ static void jemalloc_print_arena_bins_450(RzCore *core, ut64 arena_addr, ut64 bi
}
}
static void jemalloc_get_bins_450(RzCore *core, const char *input, bool is_64bit) {
int i = 0;
static void jemalloc_get_bins_450(RzCore *core, const char *input, const RzJemallocConfig450 *config) {
ut64 bin_info;
ut64 arenas;
ut64 arena_addr = UT64_MAX;
RzConsPrintablePalette *pal = &rz_cons_singleton()->context->pal;
size_t ptr_size = is_64bit ? 8 : 4;
int i = 0;
if (input[0] == '\0') {
// No argument - use symbol resolution (debug mode)
if (!rz_resolve_jemalloc(core, "je_arena_bin_info", &bin_info, is_64bit)) {
if (!rz_resolve_jemalloc(core, "je_arena_bin_info", &bin_info)) {
RZ_LOG_ERROR("Cannot resolve je_arena_bin_info\n");
return;
}
if (rz_resolve_jemalloc(core, "je_arenas", &arenas, is_64bit)) {
if (!read_ptr_at(core->io, arenas, &arenas, is_64bit)) {
if (rz_resolve_jemalloc(core, "je_arenas", &arenas)) {
if (!read_ptr_at(core->io, arenas, &arenas, config->ptr_size)) {
RZ_LOG_ERROR("Failed to read je_arenas pointer\n");
return;
}
PRINTF_GA("arenas @ 0x%" PFMT64x " {\n", arenas);
for (;;) {
if (!read_ptr_at(core->io, arenas + i * ptr_size, &arena_addr, is_64bit)) {
if (!read_ptr_at(core->io, arenas + i * config->ptr_size, &arena_addr, config->ptr_size)) {
break;
}
if (!arena_addr) {
break;
}
PRINTF_YA(" arenas[%d]: @ 0x%" PFMT64x " {\n", i++, arena_addr);
jemalloc_print_arena_bins_450(core, arena_addr, bin_info, pal, is_64bit);
jemalloc_print_arena_bins_450(core, arena_addr, bin_info, pal, config);
PRINT_YA(" }\n");
}
}
@ -471,8 +459,8 @@ static void jemalloc_get_bins_450(RzCore *core, const char *input, bool is_64bit
arena_addr = rz_num_math(core->num, args);
bin_info = rz_num_math(core->num, bin_info_str);
PRINTF_GA("arena_t @ 0x%" PFMT64x " bins[%d] {\n", arena_addr, JM_NBINS_450);
jemalloc_print_arena_bins_450(core, arena_addr, bin_info, pal, is_64bit);
PRINTF_GA("arena_t @ 0x%" PFMT64x " bins[%d] {\n", arena_addr, config->sc_nbins);
jemalloc_print_arena_bins_450(core, arena_addr, bin_info, pal, config);
PRINT_GA("}\n");
free(args);
@ -483,19 +471,19 @@ static void jemalloc_get_bins_450(RzCore *core, const char *input, bool is_64bit
// jemalloc 5.3.0
// ============================================================================
static void jemalloc_print_extent_info_530(RzCore *core, ut64 edata_addr, bool is_64bit) {
static void jemalloc_print_extent_info_530(RzCore *core, ut64 edata_addr, const RzJemallocConfig530 *config) {
RzConsPrintablePalette *pal = &rz_cons_singleton()->context->pal;
edata_t_530 edata;
static const char *state_names[] = { "Active", "Dirty", "Muzzy", "Retained" };
if (!read_and_parse_edata_t_530(core->io, edata_addr, &edata, is_64bit)) {
if (!read_and_parse_edata_t_530(core->io, edata_addr, &edata, config)) {
RZ_LOG_ERROR("Failed to read edata at 0x%" PFMT64x "\n", edata_addr);
return;
}
ut64 e_bits = edata.e_bits;
ut64 e_addr = edata.e_addr;
ut64 e_size = edata.e_size_esn & ~((ut64)(1 << LG_PAGE_530) - 1);
ut64 e_size = edata.e_size_esn & ~((ut64)(1 << config->lg_page) - 1);
ut32 state = (e_bits & EDATA_BITS_STATE_MASK) >> EDATA_BITS_STATE_SHIFT;
bool slab = (e_bits & EDATA_BITS_SLAB_MASK) >> EDATA_BITS_SLAB_SHIFT;
@ -511,7 +499,44 @@ static void jemalloc_print_extent_info_530(RzCore *core, ut64 edata_addr, bool i
PRINTF_BA("%s\n", state < 4 ? state_names[state] : "Unknown");
}
static void jemalloc_enumerate_extents_530(RzCore *core, ut64 rtree_addr, bool is_64bit) {
static void jemalloc_process_leaf_elm_530(RzCore *core, ut64 leaf_addr, const RzJemallocConfig530 *config,
HtUU *seen_extents, ut32 *extent_count) {
rtree_leaf_elm_t_530 leaf;
if (!read_and_parse_rtree_leaf_elm_t_530(core->io, leaf_addr, &leaf, config)) {
return;
}
ut64 edata_addr;
if (config->rtree_leaf_compact) {
// Compact leaf format with le_bits
if (leaf.le_bits == 0) {
return;
}
edata_addr = rtree_leaf_elm_bits_edata_get_530(leaf.le_bits);
} else {
// Non-compact format with direct le_edata pointer
edata_addr = leaf.le_edata;
}
if (edata_addr == 0) {
return;
}
// Skip duplicates
bool found = false;
ht_uu_find(seen_extents, edata_addr, &found);
if (found) {
return;
}
ht_uu_insert(seen_extents, edata_addr, 1);
jemalloc_print_extent_info_530(core, edata_addr, config);
rz_cons_printf("\n");
(*extent_count)++;
}
static void jemalloc_enumerate_extents_530(RzCore *core, ut64 rtree_addr, const RzJemallocConfig530 *config) {
RzConsPrintablePalette *pal = &rz_cons_singleton()->context->pal;
HtUU *seen_extents = ht_uu_new();
if (!seen_extents) {
@ -521,125 +546,181 @@ static void jemalloc_enumerate_extents_530(RzCore *core, ut64 rtree_addr, bool i
ut32 lg_page, rtree_nsb, bits_per_level, max_subkeys;
ut64 root_offset;
rtree_params_530(is_64bit, &lg_page, &rtree_nsb, &bits_per_level, &max_subkeys, &root_offset);
rtree_params_530(config, &lg_page, &rtree_nsb, &bits_per_level, &max_subkeys, &root_offset);
ut64 root_addr = rtree_addr + root_offset;
size_t node_elm_size = rtree_node_elm_size_530(is_64bit);
size_t leaf_elm_size = rtree_leaf_elm_size_530(is_64bit);
ut32 extent_count = 0;
ut32 rtree_height = config->rtree_height;
PRINT_GA("Enumerating extents from rtree...\n");
// Level 1: iterate through root nodes
for (ut32 i = 0; i < max_subkeys; i++) {
rtree_node_elm_t_530 node;
ut64 node_addr = root_addr + i * node_elm_size;
if (rtree_height == 2) {
// 2-level tree: root -> leaf (x86_64, aarch64, i386, arm32)
for (ut32 i = 0; i < max_subkeys; i++) {
rtree_node_elm_t_530 node;
ut64 node_addr = root_addr + i * config->rtree_node_elm_size;
if (!read_and_parse_rtree_node_elm_t_530(core->io, node_addr, &node, is_64bit)) {
continue;
}
ut64 leaf_base = node.child;
if (leaf_base == 0) {
continue;
}
// Level 2: iterate through leaf nodes
for (ut32 j = 0; j < max_subkeys; j++) {
rtree_leaf_elm_t_530 leaf;
ut64 leaf_addr = leaf_base + j * leaf_elm_size;
if (!read_and_parse_rtree_leaf_elm_t_530(core->io, leaf_addr, &leaf, is_64bit)) {
if (!read_and_parse_rtree_node_elm_t_530(core->io, node_addr, &node, config)) {
continue;
}
ut64 edata_addr;
if (is_64bit) {
// 64-bit uses compact leaf format with le_bits
if (leaf.le_bits == 0) {
ut64 leaf_base = node.child;
if (leaf_base == 0) {
continue;
}
// Level 2: iterate through leaf nodes
for (ut32 j = 0; j < max_subkeys; j++) {
ut64 leaf_addr = leaf_base + j * config->rtree_leaf_elm_size;
jemalloc_process_leaf_elm_530(core, leaf_addr, config, seen_extents, &extent_count);
}
}
} else if (rtree_height == 3) {
// 3-level tree: root -> node -> leaf (riscv64)
for (ut32 i = 0; i < max_subkeys; i++) {
rtree_node_elm_t_530 level1_node;
ut64 level1_addr = root_addr + i * config->rtree_node_elm_size;
if (!read_and_parse_rtree_node_elm_t_530(core->io, level1_addr, &level1_node, config)) {
continue;
}
ut64 level2_base = level1_node.child;
if (level2_base == 0) {
continue;
}
// Level 2: intermediate nodes
for (ut32 j = 0; j < max_subkeys; j++) {
rtree_node_elm_t_530 level2_node;
ut64 level2_addr = level2_base + j * config->rtree_node_elm_size;
if (!read_and_parse_rtree_node_elm_t_530(core->io, level2_addr, &level2_node, config)) {
continue;
}
edata_addr = rtree_leaf_elm_bits_edata_get_530(leaf.le_bits);
} else {
// 32-bit uses non-compact format with direct le_edata pointer
edata_addr = leaf.le_edata;
}
if (edata_addr == 0) {
continue;
}
ut64 leaf_base = level2_node.child;
if (leaf_base == 0) {
continue;
}
// Skip duplicates
bool found = false;
ht_uu_find(seen_extents, edata_addr, &found);
if (found) {
continue;
// Level 3: leaf nodes
for (ut32 k = 0; k < max_subkeys; k++) {
ut64 leaf_addr = leaf_base + k * config->rtree_leaf_elm_size;
jemalloc_process_leaf_elm_530(core, leaf_addr, config, seen_extents, &extent_count);
}
}
ht_uu_insert(seen_extents, edata_addr, 1);
jemalloc_print_extent_info_530(core, edata_addr, is_64bit);
rz_cons_printf("\n");
extent_count++;
}
} else {
RZ_LOG_ERROR("Unsupported rtree height: %u\n", rtree_height);
}
PRINTF_GA("Total extents found: %u\n", extent_count);
ht_uu_free(seen_extents);
}
static ut64 jemalloc_rtree_lookup_530(RzCore *core, ut64 rtree_addr, ut64 addr, bool is_64bit) {
static ut64 jemalloc_rtree_lookup_530(RzCore *core, ut64 rtree_addr, ut64 addr, const RzJemallocConfig530 *config) {
ut32 lg_page, rtree_nsb, bits_per_level, max_subkeys;
ut64 root_offset;
rtree_params_530(is_64bit, &lg_page, &rtree_nsb, &bits_per_level, &max_subkeys, &root_offset);
rtree_params_530(config, &lg_page, &rtree_nsb, &bits_per_level, &max_subkeys, &root_offset);
// Remove page offset to get the key
ut64 key = addr >> lg_page;
// Calculate indices for each level
ut32 mask = (1U << bits_per_level) - 1;
ut32 root_idx = (key >> bits_per_level) & mask;
ut32 leaf_idx = key & mask;
ut64 root_addr = rtree_addr + root_offset;
size_t node_elm_size = rtree_node_elm_size_530(is_64bit);
size_t leaf_elm_size = rtree_leaf_elm_size_530(is_64bit);
ut32 rtree_height = config->rtree_height;
// Read root node to get leaf array base
rtree_node_elm_t_530 node;
ut64 node_addr = root_addr + (ut64)root_idx * node_elm_size;
if (!read_and_parse_rtree_node_elm_t_530(core->io, node_addr, &node, is_64bit)) {
return 0;
}
ut64 leaf_base = 0;
ut64 leaf_base = node.child;
if (leaf_base == 0) {
return 0;
}
if (rtree_height == 2) {
// 2-level tree: root -> leaf
ut32 root_idx = (key >> bits_per_level) & mask;
ut32 leaf_idx = key & mask;
rtree_leaf_elm_t_530 leaf;
ut64 leaf_addr = leaf_base + (ut64)leaf_idx * leaf_elm_size;
if (!read_and_parse_rtree_leaf_elm_t_530(core->io, leaf_addr, &leaf, is_64bit)) {
return 0;
}
if (is_64bit) {
if (leaf.le_bits == 0) {
rtree_node_elm_t_530 node;
ut64 node_addr = root_addr + (ut64)root_idx * config->rtree_node_elm_size;
if (!read_and_parse_rtree_node_elm_t_530(core->io, node_addr, &node, config)) {
return 0;
}
return rtree_leaf_elm_bits_edata_get_530(leaf.le_bits);
} else {
return leaf.le_edata;
leaf_base = node.child;
if (leaf_base == 0) {
return 0;
}
rtree_leaf_elm_t_530 leaf;
ut64 leaf_addr = leaf_base + (ut64)leaf_idx * config->rtree_leaf_elm_size;
if (!read_and_parse_rtree_leaf_elm_t_530(core->io, leaf_addr, &leaf, config)) {
return 0;
}
if (config->rtree_leaf_compact) {
if (leaf.le_bits == 0) {
return 0;
}
return rtree_leaf_elm_bits_edata_get_530(leaf.le_bits);
} else {
return leaf.le_edata;
}
} else if (rtree_height == 3) {
// 3-level tree: root -> node -> leaf (riscv64)
ut32 level1_idx = (key >> (2 * bits_per_level)) & mask;
ut32 level2_idx = (key >> bits_per_level) & mask;
ut32 leaf_idx = key & mask;
// Level 1: root node
rtree_node_elm_t_530 level1_node;
ut64 level1_addr = root_addr + (ut64)level1_idx * config->rtree_node_elm_size;
if (!read_and_parse_rtree_node_elm_t_530(core->io, level1_addr, &level1_node, config)) {
return 0;
}
ut64 level2_base = level1_node.child;
if (level2_base == 0) {
return 0;
}
// Level 2: intermediate node
rtree_node_elm_t_530 level2_node;
ut64 level2_addr = level2_base + (ut64)level2_idx * config->rtree_node_elm_size;
if (!read_and_parse_rtree_node_elm_t_530(core->io, level2_addr, &level2_node, config)) {
return 0;
}
leaf_base = level2_node.child;
if (leaf_base == 0) {
return 0;
}
// Level 3: leaf
rtree_leaf_elm_t_530 leaf;
ut64 leaf_addr = leaf_base + (ut64)leaf_idx * config->rtree_leaf_elm_size;
if (!read_and_parse_rtree_leaf_elm_t_530(core->io, leaf_addr, &leaf, config)) {
return 0;
}
if (config->rtree_leaf_compact) {
if (leaf.le_bits == 0) {
return 0;
}
return rtree_leaf_elm_bits_edata_get_530(leaf.le_bits);
} else {
return leaf.le_edata;
}
}
return 0;
}
static void jemalloc_find_extent_530(RzCore *core, const char *input, bool is_64bit) {
static void jemalloc_find_extent_530(RzCore *core, const char *input, const RzJemallocConfig530 *config) {
ut64 je_arena_emap_global_addr;
RzConsPrintablePalette *pal = &rz_cons_singleton()->context->pal;
if (input[0] == '\0') {
// No argument: enumerate all extents
if (rz_resolve_jemalloc(core, "je_arena_emap_global", &je_arena_emap_global_addr, is_64bit)) {
jemalloc_enumerate_extents_530(core, je_arena_emap_global_addr, is_64bit);
if (rz_resolve_jemalloc(core, "je_arena_emap_global", &je_arena_emap_global_addr)) {
jemalloc_enumerate_extents_530(core, je_arena_emap_global_addr, config);
} else {
RZ_LOG_ERROR("Cannot resolve je_arena_emap_global\n");
}
@ -648,22 +729,22 @@ static void jemalloc_find_extent_530(RzCore *core, const char *input, bool is_64
const char *addr_str = (input[0] == ' ') ? input + 1 : input;
ut64 lookup_addr = rz_num_math(core->num, addr_str);
if (!rz_resolve_jemalloc(core, "je_arena_emap_global", &je_arena_emap_global_addr, is_64bit)) {
if (!rz_resolve_jemalloc(core, "je_arena_emap_global", &je_arena_emap_global_addr)) {
RZ_LOG_ERROR("Cannot resolve je_arena_emap_global\n");
return;
}
ut64 edata_addr = jemalloc_rtree_lookup_530(core, je_arena_emap_global_addr, lookup_addr, is_64bit);
ut64 edata_addr = jemalloc_rtree_lookup_530(core, je_arena_emap_global_addr, lookup_addr, config);
if (edata_addr == 0) {
PRINTF_RA("No extent found for address 0x%" PFMT64x "\n", lookup_addr);
return;
}
jemalloc_print_extent_info_530(core, edata_addr, is_64bit);
jemalloc_print_extent_info_530(core, edata_addr, config);
}
}
static void jemalloc_extent_info_530(RzCore *core, const char *input, bool is_64bit) {
static void jemalloc_extent_info_530(RzCore *core, const char *input, const RzJemallocConfig530 *config) {
if (input[0] == '\0') {
RZ_LOG_ERROR("Usage: dmxei <edata_addr>\n");
return;
@ -672,25 +753,23 @@ static void jemalloc_extent_info_530(RzCore *core, const char *input, bool is_64
const char *addr_str = (input[0] == ' ') ? input + 1 : input;
ut64 edata_addr = rz_num_math(core->num, addr_str);
jemalloc_print_extent_info_530(core, edata_addr, is_64bit);
jemalloc_print_extent_info_530(core, edata_addr, config);
}
static void jemalloc_print_arena_bins_530(RzCore *core, ut64 arena, ut64 bin_info_addr, bool is_64bit) {
static void jemalloc_print_arena_bins_530(RzCore *core, ut64 arena, ut64 bin_info_addr, const RzJemallocConfig530 *config) {
RzConsPrintablePalette *pal = &rz_cons_singleton()->context->pal;
bin_info_t_530 bin_info;
bin_t_530 bin;
ut64 bins_off = bins_offset_530(is_64bit);
size_t bin_info_size = bin_info_size_530(is_64bit);
size_t bin_size = bin_size_530(is_64bit);
ut64 bins_off = config->arena_offsets.bins;
for (int j = 0; j < JM_NBINS_530; j++) {
if (!read_and_parse_bin_info_t_530(core->io, bin_info_addr + j * bin_info_size, &bin_info, is_64bit)) {
for (ut32 j = 0; j < config->sc_nbins; j++) {
if (!read_and_parse_bin_info_t_530(core->io, bin_info_addr + j * config->bin_info_size, &bin_info, config)) {
continue;
}
ut64 bin_addr = arena + bins_off + j * bin_size;
if (!read_and_parse_bin_t_530(core->io, bin_addr, &bin, is_64bit)) {
ut64 bin_addr = arena + bins_off + j * config->bin_size;
if (!read_and_parse_bin_t_530(core->io, bin_addr, &bin, config)) {
continue;
}
@ -709,31 +788,30 @@ static void jemalloc_print_arena_bins_530(RzCore *core, ut64 arena, ut64 bin_inf
}
}
static void jemalloc_get_bins_530(RzCore *core, const char *input, bool is_64bit) {
static void jemalloc_get_bins_530(RzCore *core, const char *input, const RzJemallocConfig530 *config) {
int i = 0;
ut64 bin_info;
ut64 arenas_sym;
ut64 arena = UT64_MAX;
RzConsPrintablePalette *pal = &rz_cons_singleton()->context->pal;
size_t ptr_size = is_64bit ? 8 : 4;
if (input[0] == '\0') {
// No argument - use symbol resolution (debug mode)
if (!rz_resolve_jemalloc(core, "je_bin_infos", &bin_info, is_64bit)) {
if (!rz_resolve_jemalloc(core, "je_bin_infos", &bin_info)) {
RZ_LOG_ERROR("Cannot resolve je_bin_infos\n");
return;
}
if (rz_resolve_jemalloc(core, "je_arenas", &arenas_sym, is_64bit)) {
if (rz_resolve_jemalloc(core, "je_arenas", &arenas_sym)) {
PRINTF_GA("arenas @ 0x%" PFMT64x " {\n", arenas_sym);
for (;;) {
if (!read_ptr_at(core->io, arenas_sym + i * ptr_size, &arena, is_64bit)) {
if (!read_ptr_at(core->io, arenas_sym + i * config->ptr_size, &arena, config->ptr_size)) {
break;
}
if (!arena) {
break;
}
PRINTF_YA(" arenas[%d]: @ 0x%" PFMT64x " {\n", i++, arena);
jemalloc_print_arena_bins_530(core, arena, bin_info, is_64bit);
jemalloc_print_arena_bins_530(core, arena, bin_info, config);
PRINT_YA(" }\n");
}
}
@ -757,25 +835,24 @@ static void jemalloc_get_bins_530(RzCore *core, const char *input, bool is_64bit
arena = rz_num_math(core->num, args);
bin_info = rz_num_math(core->num, bin_info_str);
PRINTF_GA("arena_t @ 0x%" PFMT64x " bins[%d] {\n", arena, JM_NBINS_530);
jemalloc_print_arena_bins_530(core, arena, bin_info, is_64bit);
PRINTF_GA("arena_t @ 0x%" PFMT64x " bins[%d] {\n", arena, config->sc_nbins);
jemalloc_print_arena_bins_530(core, arena, bin_info, config);
PRINT_GA("}\n");
free(args);
}
}
static void jemalloc_print_narenas_530(RzCore *core, const char *input, bool is_64bit) {
static void jemalloc_print_narenas_530(RzCore *core, const char *input, const RzJemallocConfig530 *config) {
ut64 symaddr;
ut64 arenas;
ut64 arena = UT64_MAX;
int i = 0;
ut64 narenas = 0;
RzConsPrintablePalette *pal = &rz_cons_singleton()->context->pal;
size_t ptr_size = is_64bit ? 8 : 4;
if (input[0] == '\0') { // no args, list all arenas
if (rz_resolve_jemalloc(core, "narenas_total", &symaddr, is_64bit)) {
if (!read_ptr_at(core->io, symaddr, &narenas, is_64bit)) {
if (rz_resolve_jemalloc(core, "narenas_total", &symaddr)) {
if (!read_ptr_at(core->io, symaddr, &narenas, config->ptr_size)) {
RZ_LOG_ERROR("Failed to read narenas_total\n");
return;
}
@ -790,11 +867,11 @@ static void jemalloc_print_narenas_530(RzCore *core, const char *input, bool is_
return;
}
if (rz_resolve_jemalloc(core, "je_arenas", &arenas, is_64bit)) {
if (rz_resolve_jemalloc(core, "je_arenas", &arenas)) {
PRINTF_GA("arenas[%" PFMT64d "] @ 0x%" PFMT64x " {\n", narenas, arenas);
for (i = 0; i < (int)narenas; i++) {
ut64 at = arenas + (i * ptr_size);
if (!read_ptr_at(core->io, at, &arena, is_64bit)) {
ut64 at = arenas + (i * config->ptr_size);
if (!read_ptr_at(core->io, at, &arena, config->ptr_size)) {
continue;
}
if (!arena) {
@ -811,7 +888,7 @@ static void jemalloc_print_narenas_530(RzCore *core, const char *input, bool is_
arena = rz_num_math(core->num, addr_str);
arena_t_530 ar;
if (!read_and_parse_arena_t_530(core->io, arena, &ar, is_64bit)) {
if (!read_and_parse_arena_t_530(core->io, arena, &ar, config)) {
RZ_LOG_ERROR("Failed to read arena at 0x%" PFMT64x "\n", arena);
return;
}
@ -837,47 +914,138 @@ static void jemalloc_print_narenas_530(RzCore *core, const char *input, bool is_
}
}
// ============================================================================
// page size detection
// ============================================================================
static const char *detect_page_size_from_smaps(int pid) {
#if __linux__
if (pid <= 0) {
return NULL;
}
char path[64];
snprintf(path, sizeof(path), "/proc/%d/smaps", pid);
FILE *f = fopen(path, "r");
if (!f) {
return NULL;
}
char line[256];
const char *result = NULL;
while (fgets(line, sizeof(line), f)) {
int page_kb = 0;
if (sscanf(line, "KernelPageSize: %d kB", &page_kb) == 1) {
switch (page_kb) {
case 4:
result = "4k";
break;
case 16:
result = "16k";
break;
case 64:
result = "64k";
break;
default:
result = "4k";
break;
}
break;
}
}
fclose(f);
return result;
#else
return NULL;
#endif
}
static const char *detect_page_size(RzCore *core, const char *arch, const char *os, int bits) {
const char *page_size = rz_config_get(core->config, "dbg.jemalloc.page_size");
if (page_size && strcmp(page_size, "auto") != 0) {
return page_size;
}
bool is_darwin = os && (!strcmp(os, "darwin") || !strcmp(os, "macos") || !strcmp(os, "ios"));
bool is_linux = os && !strcmp(os, "linux");
bool is_aarch64 = arch && (!strcmp(arch, "arm") || !strcmp(arch, "aarch64")) && bits == 64;
// darwin on aarch64: always 16KB
if (is_darwin && is_aarch64) {
return "16k";
}
// aarch64 linux: Can be 4k, 16k, or 64k
if (is_linux && is_aarch64) {
int pid = core->dbg ? core->dbg->pid : -1;
const char *detected = detect_page_size_from_smaps(pid);
if (detected) {
return detected;
}
// Fall back to 4k (most common)
}
// everything else: 4k (x86, x86_64, riscv, arm32)
return "4k";
}
// ============================================================================
// dispatcher
// ============================================================================
void cmd_dbg_map_jemalloc(RzCore *core, char dmx_variant, const char *arg) {
bool is_64bit = core->rasm->bits == 64;
const char *version = rz_config_get(core->config, "dbg.jemalloc.version");
if (!version || strcmp(version, "auto") == 0 || strcmp(version, "NULL") == 0 || version[0] == '\0') {
rz_jemalloc_detect_version(core, is_64bit);
rz_jemalloc_detect_version(core);
version = rz_config_get(core->config, "dbg.jemalloc.version");
}
const char *arch = rz_config_get(core->config, "asm.arch");
const char *os = rz_config_get(core->config, "asm.os");
int bits = rz_config_get_i(core->config, "asm.bits");
const char *page_size = detect_page_size(core, arch, os, bits);
if (version && strcmp(version, "4.5.0") == 0) {
const RzJemallocConfig450 *config = rz_jemalloc_get_config_450(arch, os, bits, page_size);
if (!config) {
RZ_LOG_ERROR("Failed to get jemalloc 4.5.0 configuration\n");
return;
}
switch (dmx_variant) {
case 'a': // dmxa
jemalloc_print_narenas_450(core, arg, is_64bit);
jemalloc_print_narenas_450(core, arg, config);
break;
case 'b': // dmxb
jemalloc_get_bins_450(core, arg, is_64bit);
jemalloc_get_bins_450(core, arg, config);
break;
case 'c': // dmxc
jemalloc_get_chunks_450(core, arg, is_64bit);
jemalloc_get_chunks_450(core, arg, config);
break;
default:
RZ_LOG_ERROR("Command not supported for jemalloc 4.5.0\n");
break;
}
} else if (version && strcmp(version, "5.3.0") == 0) {
const RzJemallocConfig530 *config = rz_jemalloc_get_config_530(arch, os, bits, page_size);
if (!config) {
RZ_LOG_ERROR("Failed to get jemalloc 5.3.0 configuration\n");
return;
}
switch (dmx_variant) {
case 'a': // dmxa - print arena
jemalloc_print_narenas_530(core, arg, is_64bit);
jemalloc_print_narenas_530(core, arg, config);
break;
case 'b': // dmxb - bin info
jemalloc_get_bins_530(core, arg, is_64bit);
jemalloc_get_bins_530(core, arg, config);
break;
case 'e': // dmxe - find extent for malloc'd address
jemalloc_find_extent_530(core, arg, is_64bit);
jemalloc_find_extent_530(core, arg, config);
break;
case 'i': // dmxei - extent info
jemalloc_extent_info_530(core, arg, is_64bit);
jemalloc_extent_info_530(core, arg, config);
break;
default:
RZ_LOG_ERROR("Command not supported for jemalloc 5.3.0\n");

View file

@ -4,6 +4,7 @@
#ifndef RZ_HEAP_JEMALLOC_H
#define RZ_HEAP_JEMALLOC_H
#include <rz_jemalloc/jemalloc_arch.h>
#include <rz_jemalloc/jemalloc_450.h>
#include <rz_jemalloc/jemalloc_530.h>

View file

@ -0,0 +1,2 @@
extract_config_530
extract_config_450

View file

@ -0,0 +1,132 @@
# SPDX-FileCopyrightText: 2026 bubblepipe <bubblepipe42@gmail.com>
# SPDX-License-Identifier: LGPL-3.0-only
# Makefile for jemalloc config extraction helper
#
# Usage:
# 1. Configure jemalloc first:
# cd /path/to/jemalloc
# ./configure [--host=<target>] [--with-lg-page=<N>]
# make
#
# 2. Build and run this helper:
# make JEMALLOC=/path/to/jemalloc
# ./extract_config_450 # or extract_config_530
#
# Cross-compilation examples:
# # ARM64 with 4KB pages
# cd /path/to/jemalloc
# ./configure --host=aarch64-linux-gnu --with-lg-page=12
# make
# cd /jemalloc-config-extractor
# make JEMALLOC=/path/to/jemalloc CC=aarch64-linux-gnu-gcc
#
# # ARM64 with 16KB pages
# ./configure --host=aarch64-linux-gnu --with-lg-page=14
# make JEMALLOC=/path/to/jemalloc CC=aarch64-linux-gnu-gcc
#
# # ARM32 with 4KB pages
# ./configure --host=arm-linux-gnueabihf --with-lg-page=12
# make JEMALLOC=/path/to/jemalloc CC=arm-linux-gnueabihf-gcc
#
# # i386 with 4KB pages
# ./configure --host=i686-linux-gnu --with-lg-page=12
# make JEMALLOC=/path/to/jemalloc CC=i686-linux-gnu-gcc
#
# # RISC-V 64-bit with 4KB pages
# ./configure --host=riscv64-linux-gnu --with-lg-page=12
# make JEMALLOC=/path/to/jemalloc CC=riscv64-linux-gnu-gcc
#
# # RISC-V 32-bit with 4KB pages
# ./configure --host=riscv32-linux-gnu --with-lg-page=12
# make JEMALLOC=/path/to/jemalloc CC=riscv32-linux-gnu-gcc
# Jemalloc root directory - REQUIRED for build targets
JEMALLOC ?=
# Only check JEMALLOC for targets that need it (not clean/help)
NEED_JEMALLOC := $(filter-out clean help,$(MAKECMDGOALS))
ifeq ($(MAKECMDGOALS),)
NEED_JEMALLOC := all
endif
ifneq ($(NEED_JEMALLOC),)
ifeq ($(JEMALLOC),)
$(error JEMALLOC is not set. Usage: make JEMALLOC=/path/to/jemalloc)
endif
endif
# Compiler (can be overridden for cross-compilation)
CC ?= gcc
# Include paths
CFLAGS += -I$(JEMALLOC)/include
# Required defines for jemalloc internal headers
CFLAGS += -D_GNU_SOURCE
CFLAGS += -D_REENTRANT
# Optimization and warnings
CFLAGS += -O0 -g -Wall
# Link with pthread (required by jemalloc mutex types)
LDFLAGS += -lpthread
# For jemalloc 5.x, we provide stub implementations for symbols referenced by
# inline functions, so no need to link against the library
LDFLAGS_530 = $(LDFLAGS)
# Detect jemalloc version to build the correct extractor
JEMALLOC_VERSION := $(shell cd $(JEMALLOC) 2>/dev/null && git describe --tags 2>/dev/null | cut -d. -f1)
ifeq ($(JEMALLOC_VERSION),4)
TARGETS := extract_config_450
else ifeq ($(JEMALLOC_VERSION),5)
TARGETS := extract_config_530
else
# Default if version can't be detected
TARGETS := extract_config_530
endif
.PHONY: all clean 450 530 help
all: $(TARGETS)
# Explicit version targets
450: extract_config_450
530: extract_config_530
extract_config_450: extract_config_450.c
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
extract_config_530: extract_config_530.c
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS_530)
clean:
rm -f extract_config_450 extract_config_530
# Help target
help:
@echo "jemalloc config extraction helper"
@echo ""
@echo "Usage:"
@echo " 1. Configure and build jemalloc first:"
@echo " cd /path/to/jemalloc"
@echo " ./configure [--host=<target>] [--with-lg-page=<N>]"
@echo " make"
@echo ""
@echo " 2. Build and run this helper:"
@echo " make JEMALLOC=/path/to/jemalloc"
@echo " ./extract_config_450 # or extract_config_530"
@echo ""
@echo "Cross-compilation:"
@echo " make JEMALLOC=/path/to/jemalloc CC=aarch64-linux-gnu-gcc"
@echo " make JEMALLOC=/path/to/jemalloc CC=arm-linux-gnueabihf-gcc"
@echo " make JEMALLOC=/path/to/jemalloc CC=i686-linux-gnu-gcc"
@echo " make JEMALLOC=/path/to/jemalloc CC=riscv64-linux-gnu-gcc"
@echo " make JEMALLOC=/path/to/jemalloc CC=riscv32-linux-gnu-gcc"
@echo ""
@echo "Page size options (--with-lg-page=N):"
@echo " 12 = 4KB pages (default)"
@echo " 14 = 16KB pages"
@echo " 16 = 64KB pages"

View file

@ -0,0 +1,190 @@
// SPDX-FileCopyrightText: 2026 bubblepipe <bubblepipe42@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
/**
* Helper program to extract jemalloc 4.5.0 configuration values.
*
* This program prints struct sizes and field offsets that are needed
* for the RzJemallocConfig450 structure in Rizin's heap parser.
*
* Usage:
* 1. Configure jemalloc for target: ./configure --host=<target> --with-lg-page=<N>
* 2. Build jemalloc: make
* 3. Build this program: make -C extract_config
* 4. Run: ./extract_config_450
*/
#include "jemalloc/internal/jemalloc_internal.h"
#include <stdio.h>
#include <stddef.h>
int main(void) {
printf("// =============================================================================\n");
printf("// jemalloc 4.5.0 configuration extracted from compiled source\n");
printf("// =============================================================================\n");
printf("//\n");
printf("// Compile-time configuration:\n");
printf("// sizeof(void*) = %zu\n", sizeof(void *));
printf("// LG_PAGE = %d (page size = %zu bytes)\n", LG_PAGE, (size_t)1 << LG_PAGE);
printf("// NBINS = %d\n", NBINS);
printf("// NPSIZES = %d\n", NPSIZES);
#ifdef USE_TREE
printf("// USE_TREE = defined\n");
#else
printf("// USE_TREE = not defined\n");
#endif
printf("// BITMAP_MAXBITS = %zu\n", (size_t)BITMAP_MAXBITS);
printf("// LG_BITMAP_GROUP_NBITS = %d\n", LG_BITMAP_GROUP_NBITS);
#ifdef USE_TREE
printf("// BITMAP_MAX_LEVELS = %d\n", BITMAP_MAX_LEVELS);
#endif
printf("//\n\n");
// Determine architecture name
const char *arch_name;
const char *arch_enum;
if (sizeof(void *) == 8) {
#if defined(__aarch64__)
arch_name = "aarch64";
arch_enum = "RZ_JEMALLOC_ARCH_AARCH64";
#elif defined(__riscv) && __riscv_xlen == 64
arch_name = "riscv64";
arch_enum = "RZ_JEMALLOC_ARCH_RISCV64";
#else
arch_name = "amd64";
arch_enum = "RZ_JEMALLOC_ARCH_AMD64";
#endif
} else {
#if defined(__arm__)
arch_name = "arm32";
arch_enum = "RZ_JEMALLOC_ARCH_ARM32";
#elif defined(__riscv) && __riscv_xlen == 32
arch_name = "riscv32";
arch_enum = "RZ_JEMALLOC_ARCH_RISCV32";
#else
arch_name = "i386";
arch_enum = "RZ_JEMALLOC_ARCH_I386";
#endif
}
// OS name
const char *os_name;
#if defined(__linux__)
os_name = "linux";
#elif defined(__APPLE__)
os_name = "darwin";
#elif defined(__FreeBSD__)
os_name = "freebsd";
#elif defined(__OpenBSD__)
os_name = "openbsd";
#elif defined(__NetBSD__)
os_name = "netbsd";
#elif defined(_WIN32)
os_name = "windows";
#else
os_name = "unknown";
#endif
// Page size suffix
const char *page_suffix;
switch (LG_PAGE) {
case 12: page_suffix = "4k"; break;
case 14: page_suffix = "16k"; break;
case 16: page_suffix = "64k"; break;
default: page_suffix = "unknown"; break;
}
printf("static const RzJemallocConfig450 rz_jemalloc_config_%s_%s_%s_450 = {\n",
arch_name, os_name, page_suffix);
printf("\t.arch = %s,\n", arch_enum);
printf("\t.ptr_size = %zu,\n", sizeof(void *));
printf("\t.is_big_endian = false,\n");
printf("\t.lg_page = %d,\n", LG_PAGE);
printf("\t.sc_nbins = %d,\n", NBINS);
printf("\t.npsizes = %d,\n", NPSIZES);
#ifdef USE_TREE
printf("\t.bitmap_use_tree = true,\n");
printf("\t.bitmap_max_levels = %d,\n", BITMAP_MAX_LEVELS);
#else
printf("\t.bitmap_use_tree = false,\n");
printf("\t.bitmap_max_levels = 0,\n");
#endif
printf("\t.extent_node_size = %zu,\n", sizeof(extent_node_t));
printf("\t.bin_info_size = %zu,\n", sizeof(arena_bin_info_t));
printf("\t.bin_size = %zu,\n", sizeof(arena_bin_t));
printf("\t.arena_size = %zu,\n", sizeof(arena_t));
printf("\t.bitmap_info_size = %zu,\n", sizeof(bitmap_info_t));
printf("\t.malloc_mutex_size = %zu,\n", sizeof(malloc_mutex_t));
// Arena offsets
printf("\t.arena_offsets = {\n");
printf("\t\t.lock = %zu,\n", offsetof(arena_t, lock));
printf("\t\t.stats = %zu,\n", offsetof(arena_t, stats));
printf("\t\t.tcache_ql = %zu,\n", offsetof(arena_t, tcache_ql));
printf("\t\t.prof_accumbytes = %zu,\n", offsetof(arena_t, prof_accumbytes));
printf("\t\t.achunks = %zu,\n", offsetof(arena_t, achunks));
printf("\t\t.extent_sn_next = %zu,\n", offsetof(arena_t, extent_sn_next));
printf("\t\t.lg_dirty_mult = %zu,\n", offsetof(arena_t, lg_dirty_mult));
printf("\t\t.purging = %zu,\n", offsetof(arena_t, purging));
printf("\t\t.nactive = %zu,\n", offsetof(arena_t, nactive));
printf("\t\t.runs_dirty = %zu,\n", offsetof(arena_t, runs_dirty));
printf("\t\t.chunks_cache = %zu,\n", offsetof(arena_t, chunks_cache));
printf("\t\t.decay = %zu,\n", offsetof(arena_t, decay));
printf("\t\t.huge = %zu,\n", offsetof(arena_t, huge));
printf("\t\t.huge_mtx = %zu,\n", offsetof(arena_t, huge_mtx));
printf("\t\t.chunks_szsnad_cached = %zu,\n", offsetof(arena_t, chunks_szsnad_cached));
printf("\t\t.chunks_ad_cached = %zu,\n", offsetof(arena_t, chunks_ad_cached));
printf("\t\t.chunks_mtx = %zu,\n", offsetof(arena_t, chunks_mtx));
printf("\t\t.node_cache = %zu,\n", offsetof(arena_t, node_cache));
printf("\t\t.node_cache_mtx = %zu,\n", offsetof(arena_t, node_cache_mtx));
printf("\t\t.chunk_hooks = %zu,\n", offsetof(arena_t, chunk_hooks));
printf("\t\t.bins = %zu,\n", offsetof(arena_t, bins));
printf("\t\t.runs_avail = %zu,\n", offsetof(arena_t, runs_avail));
printf("\t},\n");
// Extent node offsets
printf("\t.extent_node_offsets = {\n");
printf("\t\t.ql_link_next = %zu,\n", offsetof(extent_node_t, ql_link));
printf("\t},\n");
// Bin info offsets
printf("\t.bin_info_offsets = {\n");
printf("\t\t.bitmap_info = %zu,\n", offsetof(arena_bin_info_t, bitmap_info));
printf("\t\t.reg0_offset = %zu,\n", offsetof(arena_bin_info_t, reg0_offset));
printf("\t},\n");
printf("};\n");
// Print additional useful information
printf("\n// Additional struct information:\n");
printf("// extent_node_t:\n");
printf("// en_arena offset: %zu\n", offsetof(extent_node_t, en_arena));
printf("// en_addr offset: %zu\n", offsetof(extent_node_t, en_addr));
printf("// en_size offset: %zu\n", offsetof(extent_node_t, en_size));
printf("// en_sn offset: %zu\n", offsetof(extent_node_t, en_sn));
printf("// ql_link offset: %zu\n", offsetof(extent_node_t, ql_link));
printf("// total size: %zu\n", sizeof(extent_node_t));
printf("//\n// arena_bin_info_t:\n");
printf("// reg_size offset: %zu\n", offsetof(arena_bin_info_t, reg_size));
printf("// redzone_size offset: %zu\n", offsetof(arena_bin_info_t, redzone_size));
printf("// reg_interval offset: %zu\n", offsetof(arena_bin_info_t, reg_interval));
printf("// run_size offset: %zu\n", offsetof(arena_bin_info_t, run_size));
printf("// nregs offset: %zu\n", offsetof(arena_bin_info_t, nregs));
printf("// bitmap_info offset: %zu\n", offsetof(arena_bin_info_t, bitmap_info));
printf("// reg0_offset offset: %zu\n", offsetof(arena_bin_info_t, reg0_offset));
printf("// total size: %zu\n", sizeof(arena_bin_info_t));
printf("//\n// bitmap_info_t:\n");
printf("// nbits offset: %zu\n", offsetof(bitmap_info_t, nbits));
#ifdef USE_TREE
printf("// nlevels offset: %zu\n", offsetof(bitmap_info_t, nlevels));
printf("// levels offset: %zu\n", offsetof(bitmap_info_t, levels));
#else
printf("// ngroups offset: %zu\n", offsetof(bitmap_info_t, ngroups));
#endif
printf("// total size: %zu\n", sizeof(bitmap_info_t));
return 0;
}

View file

@ -0,0 +1,231 @@
// SPDX-FileCopyrightText: 2026 bubblepipe <bubblepipe42@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
/**
* Helper program to extract jemalloc 5.3.0 configuration values.
*
* This program prints struct sizes and field offsets that are needed
* for the RzJemallocConfig530 structure in Rizin's heap parser.
*
* Usage:
* 1. Configure jemalloc for target: ./configure --host=<target> --with-lg-page=<N>
* 2. Build jemalloc: make
* 3. Build this program: make -C extract_config
* 4. Run: ./extract_config_530
*/
// Note: We do NOT define JEMALLOC_NO_PRIVATE_NAMESPACE because we need the
// namespace macros to remap internal symbols (e.g., malloc_printf -> je_malloc_printf)
// when linking against the built jemalloc library.
#include "jemalloc/internal/jemalloc_preamble.h"
#include "jemalloc/internal/jemalloc_internal_includes.h"
#include <stdio.h>
#include <stddef.h>
// Stub implementations for symbols referenced by jemalloc inline functions.
// We only need struct layouts, not actual runtime functionality.
void je_malloc_printf(const char *fmt, ...) {
(void)fmt;
// Never called - stub only
}
// ticker_geom_table is referenced by ticker.h inline functions
const uint8_t ticker_geom_table[1 << TICKER_GEOM_NBITS] = { 0 };
int main(void) {
printf("// =============================================================================\n");
printf("// jemalloc 5.3.0 configuration extracted from compiled source\n");
printf("// =============================================================================\n");
printf("//\n");
printf("// Compile-time configuration:\n");
printf("// sizeof(void*) = %zu\n", sizeof(void *));
printf("// LG_PAGE = %d (page size = %zu bytes)\n", LG_PAGE, (size_t)1 << LG_PAGE);
printf("// SC_NBINS = %zu\n", (size_t)SC_NBINS);
printf("// SC_NSIZES = %zu\n", (size_t)SC_NSIZES);
#ifdef BITMAP_USE_TREE
printf("// BITMAP_USE_TREE = defined\n");
printf("// BITMAP_MAX_LEVELS = %d\n", BITMAP_MAX_LEVELS);
#else
printf("// BITMAP_USE_TREE = not defined\n");
#endif
printf("// LG_VADDR = %d\n", LG_VADDR);
printf("// RTREE_NSB = %d\n", RTREE_NSB);
printf("// RTREE_HEIGHT = %d\n", RTREE_HEIGHT);
printf("// RTREE_LEAF_COMPACT = %s\n",
#ifdef RTREE_LEAF_COMPACT
"defined"
#else
"not defined"
#endif
);
printf("// rtree_levels[0].bits = %d\n", rtree_levels[0].bits);
#if RTREE_HEIGHT > 1
printf("// rtree_levels[1].bits = %d\n", rtree_levels[1].bits);
#endif
#if RTREE_HEIGHT > 2
printf("// rtree_levels[2].bits = %d\n", rtree_levels[2].bits);
#endif
printf("//\n\n");
// Determine architecture name
const char *arch_name;
const char *arch_enum;
if (sizeof(void *) == 8) {
#if defined(__aarch64__)
arch_name = "aarch64";
arch_enum = "RZ_JEMALLOC_ARCH_AARCH64";
#elif defined(__riscv) && __riscv_xlen == 64
arch_name = "riscv64";
arch_enum = "RZ_JEMALLOC_ARCH_RISCV64";
#else
arch_name = "amd64";
arch_enum = "RZ_JEMALLOC_ARCH_AMD64";
#endif
} else {
#if defined(__arm__)
arch_name = "arm32";
arch_enum = "RZ_JEMALLOC_ARCH_ARM32";
#elif defined(__riscv) && __riscv_xlen == 32
arch_name = "riscv32";
arch_enum = "RZ_JEMALLOC_ARCH_RISCV32";
#else
arch_name = "i386";
arch_enum = "RZ_JEMALLOC_ARCH_I386";
#endif
}
// OS name
const char *os_name;
#if defined(__linux__)
os_name = "linux";
#elif defined(__APPLE__)
os_name = "darwin";
#elif defined(__FreeBSD__)
os_name = "freebsd";
#elif defined(__OpenBSD__)
os_name = "openbsd";
#elif defined(__NetBSD__)
os_name = "netbsd";
#elif defined(_WIN32)
os_name = "windows";
#else
os_name = "unknown";
#endif
// Page size suffix
const char *page_suffix;
switch (LG_PAGE) {
case 12: page_suffix = "4k"; break;
case 14: page_suffix = "16k"; break;
case 16: page_suffix = "64k"; break;
default: page_suffix = "unknown"; break;
}
printf("static const RzJemallocConfig530 rz_jemalloc_config_%s_%s_%s_530 = {\n",
arch_name, os_name, page_suffix);
printf("\t.arch = %s,\n", arch_enum);
printf("\t.ptr_size = %zu,\n", sizeof(void *));
printf("\t.is_big_endian = false,\n");
printf("\t.lg_page = %d,\n", LG_PAGE);
printf("\t.sc_nbins = %zu,\n", (size_t)SC_NBINS);
printf("\t.sc_nsizes = %zu,\n", (size_t)SC_NSIZES);
#ifdef BITMAP_USE_TREE
printf("\t.bitmap_use_tree = true,\n");
printf("\t.bitmap_max_levels = %d,\n", BITMAP_MAX_LEVELS);
#else
printf("\t.bitmap_use_tree = false,\n");
printf("\t.bitmap_max_levels = 0,\n");
#endif
printf("\t.rtree_nsb = %d,\n", RTREE_NSB);
printf("\t.rtree_bits_per_level = %d,\n", rtree_levels[0].bits);
printf("\t.rtree_height = %d,\n", RTREE_HEIGHT);
#ifdef RTREE_LEAF_COMPACT
printf("\t.rtree_leaf_compact = true,\n");
#else
printf("\t.rtree_leaf_compact = false,\n");
#endif
printf("\t.edata_size = %zu,\n", sizeof(edata_t));
printf("\t.bin_info_size = %zu,\n", sizeof(bin_info_t));
printf("\t.bin_size = %zu,\n", sizeof(bin_t));
printf("\t.arena_size = %zu,\n", sizeof(arena_t));
printf("\t.bitmap_info_size = %zu,\n", sizeof(bitmap_info_t));
printf("\t.rtree_node_elm_size = %zu,\n", sizeof(rtree_node_elm_t));
printf("\t.rtree_leaf_elm_size = %zu,\n", sizeof(rtree_leaf_elm_t));
// Arena offsets
printf("\t.arena_offsets = {\n");
printf("\t\t.stats = %zu,\n", offsetof(arena_t, stats));
printf("\t\t.tcache_ql = %zu,\n", offsetof(arena_t, tcache_ql));
printf("\t\t.cache_bin_arr = %zu,\n", offsetof(arena_t, cache_bin_array_descriptor_ql));
printf("\t\t.tcache_ql_mtx = %zu,\n", offsetof(arena_t, tcache_ql_mtx));
printf("\t\t.dss_prec = %zu,\n", offsetof(arena_t, dss_prec));
printf("\t\t.large = %zu,\n", offsetof(arena_t, large));
printf("\t\t.large_mtx = %zu,\n", offsetof(arena_t, large_mtx));
printf("\t\t.pa_shard = %zu,\n", offsetof(arena_t, pa_shard));
printf("\t\t.ind = %zu,\n", offsetof(arena_t, ind));
printf("\t\t.base = %zu,\n", offsetof(arena_t, base));
printf("\t\t.create_time = %zu,\n", offsetof(arena_t, create_time));
printf("\t\t.bins = %zu,\n", offsetof(arena_t, bins));
printf("\t\t.last_thd = %zu,\n", offsetof(arena_t, last_thd));
printf("\t},\n");
// Bin offsets
printf("\t.bin_offsets = {\n");
printf("\t\t.slabcur = %zu,\n", offsetof(bin_t, slabcur));
printf("\t},\n");
// Rtree offsets - need to check if rtree_t has root field directly
printf("\t.rtree_offsets = {\n");
printf("\t\t.root = %zu,\n", offsetof(rtree_t, root));
printf("\t},\n");
printf("};\n");
// Print additional useful information
printf("\n// Additional struct information:\n");
printf("// edata_t:\n");
printf("// e_bits offset: %zu\n", offsetof(edata_t, e_bits));
printf("// e_addr offset: %zu\n", offsetof(edata_t, e_addr));
printf("// total size: %zu\n", sizeof(edata_t));
printf("//\n// bin_info_t:\n");
printf("// reg_size offset: %zu\n", offsetof(bin_info_t, reg_size));
printf("// slab_size offset: %zu\n", offsetof(bin_info_t, slab_size));
printf("// nregs offset: %zu\n", offsetof(bin_info_t, nregs));
printf("// n_shards offset: %zu\n", offsetof(bin_info_t, n_shards));
printf("// total size: %zu\n", sizeof(bin_info_t));
printf("//\n// bin_t:\n");
printf("// lock offset: %zu\n", offsetof(bin_t, lock));
printf("// slabcur offset: %zu\n", offsetof(bin_t, slabcur));
printf("// slabs_nonfull offset: %zu\n", offsetof(bin_t, slabs_nonfull));
printf("// total size: %zu\n", sizeof(bin_t));
printf("//\n// rtree_t:\n");
printf("// root offset: %zu\n", offsetof(rtree_t, root));
printf("// total size: %zu\n", sizeof(rtree_t));
printf("//\n// rtree_node_elm_t:\n");
printf("// total size: %zu\n", sizeof(rtree_node_elm_t));
printf("//\n// rtree_leaf_elm_t:\n");
#ifdef RTREE_LEAF_COMPACT
printf("// le_bits offset: %zu (compact mode)\n", offsetof(rtree_leaf_elm_t, le_bits));
#else
printf("// le_edata offset: %zu (non-compact mode)\n", offsetof(rtree_leaf_elm_t, le_edata));
#endif
printf("// total size: %zu\n", sizeof(rtree_leaf_elm_t));
printf("//\n// bitmap_info_t:\n");
printf("// nbits offset: %zu\n", offsetof(bitmap_info_t, nbits));
#ifdef BITMAP_USE_TREE
printf("// nlevels offset: %zu\n", offsetof(bitmap_info_t, nlevels));
printf("// levels offset: %zu\n", offsetof(bitmap_info_t, levels));
#else
printf("// ngroups offset: %zu\n", offsetof(bitmap_info_t, ngroups));
#endif
printf("// total size: %zu\n", sizeof(bitmap_info_t));
return 0;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: 2026 jemalloc <https://jemalloc.net/>
// SPDX-FileCopyrightText: 2026 bubblepipe <bubblepipe42@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#ifndef RZ_JEMALLOC_ARCH_H
#define RZ_JEMALLOC_ARCH_H
#include <rz_util.h>
typedef enum {
RZ_JEMALLOC_ARCH_UNKNOWN = 0,
RZ_JEMALLOC_ARCH_I386,
RZ_JEMALLOC_ARCH_AMD64,
RZ_JEMALLOC_ARCH_ARM32,
RZ_JEMALLOC_ARCH_AARCH64,
RZ_JEMALLOC_ARCH_RISCV32,
RZ_JEMALLOC_ARCH_RISCV64,
} RzJemallocArch;
/**
* Log2 of page size values
*/
typedef enum {
RZ_JEMALLOC_PAGE_4K = 12,
RZ_JEMALLOC_PAGE_16K = 14,
RZ_JEMALLOC_PAGE_64K = 16,
} RzJemallocPageSize;
static inline const char *rz_jemalloc_page_size_name(ut8 lg_page) {
switch (lg_page) {
case 12:
return "4KB";
case 14:
return "16KB";
case 16:
return "64KB";
default:
return "Unknown";
}
}
#endif // RZ_JEMALLOC_ARCH_H

View file

@ -0,0 +1,155 @@
NAME=dmxa/dmxb/dmxe with 64-bit jemalloc 5.3.0 runtime (aarch64-linux-)
FILE=bins/heap/simpleheap-jemalloc-5.3.0-static-aarch64
ARGS=-d
CMDS=<<EOF
dcu sym.imp.getchar
dmxa~?narenas
echo ----
dmxb~reg_size : 0x800
echo ----
dmxe~Total extents found:
EOF
EXPECT=<<EOF
1
----
reg_size : 0x800
----
Total extents found: 16
EOF
RUN
NAME=dmxa/dmxb with jemalloc 4.5.0 memory dump (linux-amd64-4k_page)
FILE=bins/heap/linux_jemalloc-4.5.0_x64.bin
ARGS=-n
CMDS=<<EOF
e asm.arch=x86
e asm.bits=64
e asm.os=linux
e dbg.jemalloc.version=4.5.0
e dbg.jemalloc.page_size=4k
om 3 0x7f2601a03c00 0x8 0x0 rw- je_arenas
om 3 0x7f2601f5b2d0 0x4 0x8 rw- narenas_total
om 3 0x7f2601f5b380 0x900 0xc rw- je_arena_bin_info
om 3 0x7f2601a00140 0x2758 0x90c rw- arena
om 3 0x7f2601800000 0x200000 0x3064 rw- [heap]
dmxa 0x7f2601a00140~ind
dmxa 0x7f2601a00140~nthreads: application
dmxa 0x7f2601a00140~extent_sn_next
dmxa 0x7f2601a00140~spare
dmxa 0x7f2601a00140~purging
dmxa 0x7f2601a00140~nactive
dmxa 0x7f2601a00140~bins
echo ----
dmxb 0x7f2601a00140 0x7f2601f5b380~?regsize
dmxb 0x7f2601a00140 0x7f2601f5b380~regsize : 0x800
dmxb 0x7f2601a00140 0x7f2601f5b380~regsize : 0x3800
dmxb 0x7f2601a00140 0x7f2601f5b380~nregs : 0x200
EOF
EXPECT=<<EOF
ind = 0x0
nthreads: application allocation = 0x1
extent_sn_next = 0x1
spare = 0x0
purging = false
nactive = 0xc
bins = 36 0x7f2601a00ac0
----
36
regsize : 0x800
regsize : 0x3800
nregs : 0x200
EOF
RUN
NAME=dmxa/dmxb/dmxei with jemalloc 5.3.0 memory dump (linux-amd64-4k_page)
FILE=bins/heap/linux_jemalloc-5.3.0_x64.bin
ARGS=-n
CMDS=<<EOF
e asm.arch=x86
e asm.bits=64
e asm.os=linux
e dbg.jemalloc.version=5.3.0
e dbg.jemalloc.page_size=4k
om 3 0x561974e68b00 1440 0x0 rw- bin_info
om 3 0x7faa2cc010c0 0x20000 1440 rw- arena
om 3 0x7faa2cc16500 128 0x205a0 rw- extent
dmxa 0x7faa2cc010c0~ind
dmxa 0x7faa2cc010c0~nthreads: application
dmxa 0x7faa2cc010c0~stats
dmxa 0x7faa2cc010c0~dss_prec
dmxa 0x7faa2cc010c0~create_time.ns
echo ----
dmxb 0x7faa2cc010c0 0x561974e68b00~?reg_size
dmxb 0x7faa2cc010c0 0x561974e68b00~reg_size : 0x800
dmxb 0x7faa2cc010c0 0x561974e68b00~reg_size : 0x3800
dmxb 0x7faa2cc010c0 0x561974e68b00~nregs : 0x200
echo ----
dmxei 0x7faa2cc16500~Extent
dmxei 0x7faa2cc16500~Allocated Address
EOF
EXPECT=<<EOF
ind = 0x0
nthreads: application allocation = 0x1
stats = 0x7faa2cc010d8
dss_prec = 0x2
create_time.ns = 0x1a488a2868dea
----
36
reg_size : 0x800
reg_size : 0x3800
nregs : 0x200
----
Extent @ 0x7faa2cc16500
Allocated Address: 0x7faa2ca00000
EOF
RUN
NAME=dmxa/dmxb/dmxei with jemalloc 5.3.0 memory dump (linux-riscv64-4k_page)
FILE=bins/heap/linux_jemalloc-5.3.0_riscv64.bin
ARGS=-n
CMDS=<<EOF
e asm.arch=riscv
e asm.bits=64
e asm.os=linux
e dbg.jemalloc.version=5.3.0
e dbg.jemalloc.page_size=4k
om 3 0x55555d5b4830 1440 0x0 rw- bin_info
om 3 0x7fff960010c0 0x20000 1440 rw- arena
om 3 0x7fff96016500 128 0x205a0 rw- extent
dmxa 0x7fff960010c0~ind
dmxa 0x7fff960010c0~nthreads: application
dmxa 0x7fff960010c0~stats
dmxa 0x7fff960010c0~dss_prec
dmxa 0x7fff960010c0~create_time.ns
echo ----
dmxb 0x7fff960010c0 0x55555d5b4830~?reg_size
dmxb 0x7fff960010c0 0x55555d5b4830~reg_size : 0x800
dmxb 0x7fff960010c0 0x55555d5b4830~reg_size : 0x3800
dmxb 0x7fff960010c0 0x55555d5b4830~nregs : 0x200
echo ----
dmxei 0x7fff96016500~Extent
dmxei 0x7fff96016500~Allocated Address
EOF
EXPECT=<<EOF
ind = 0x0
nthreads: application allocation = 0x1
stats = 0x7fff960010d8
dss_prec = 0x2
create_time.ns = 0x35366573ac
----
36
reg_size : 0x800
reg_size : 0x3800
nregs : 0x200
----
Extent @ 0x7fff96016500
Allocated Address: 0x7fff95e00000
EOF
RUN

View file

@ -2,8 +2,11 @@ NAME=dmxa/dmxb with jemalloc 4.5.0 memory dump (linux-amd64-4k_page)
FILE=bins/heap/linux_jemalloc-4.5.0_x64.bin
ARGS=-n
CMDS=<<EOF
e asm.arch=x86
e asm.bits=64
e asm.os=linux
e dbg.jemalloc.version=4.5.0
e dbg.jemalloc.page_size=4k
om 3 0x7f2601a03c00 0x8 0x0 rw- je_arenas
om 3 0x7f2601f5b2d0 0x4 0x8 rw- narenas_total
@ -87,8 +90,11 @@ NAME=dmxa/dmxb/dmxei with jemalloc 5.3.0 memory dump (linux-amd64-4k_page)
FILE=bins/heap/linux_jemalloc-5.3.0_x64.bin
ARGS=-n
CMDS=<<EOF
e asm.arch=x86
e asm.bits=64
e asm.os=linux
e dbg.jemalloc.version=5.3.0
e dbg.jemalloc.page_size=4k
om 3 0x561974e68b00 1440 0x0 rw- bin_info
om 3 0x7faa2cc010c0 0x20000 1440 rw- arena
@ -167,3 +173,48 @@ EXPECT=<<EOF
Total extents found: 16
EOF
RUN
NAME=dmxa/dmxb/dmxei with jemalloc 5.3.0 memory dump (linux-riscv64-4k_page)
FILE=bins/heap/linux_jemalloc-5.3.0_riscv64.bin
ARGS=-n
CMDS=<<EOF
e asm.arch=riscv
e asm.bits=64
e asm.os=linux
e dbg.jemalloc.version=5.3.0
e dbg.jemalloc.page_size=4k
om 3 0x55555d5b4830 1440 0x0 rw- bin_info
om 3 0x7fff960010c0 0x20000 1440 rw- arena
om 3 0x7fff96016500 128 0x205a0 rw- extent
dmxa 0x7fff960010c0~ind
dmxa 0x7fff960010c0~nthreads: application
dmxa 0x7fff960010c0~stats
dmxa 0x7fff960010c0~dss_prec
dmxa 0x7fff960010c0~create_time.ns
echo ----
dmxb 0x7fff960010c0 0x55555d5b4830~?reg_size
dmxb 0x7fff960010c0 0x55555d5b4830~reg_size : 0x800
dmxb 0x7fff960010c0 0x55555d5b4830~reg_size : 0x3800
dmxb 0x7fff960010c0 0x55555d5b4830~nregs : 0x200
echo ----
dmxei 0x7fff96016500~Extent
dmxei 0x7fff96016500~Allocated Address
EOF
EXPECT=<<EOF
ind = 0x0
nthreads: application allocation = 0x1
stats = 0x7fff960010d8
dss_prec = 0x2
create_time.ns = 0x35366573ac
----
36
reg_size : 0x800
reg_size : 0x3800
nregs : 0x200
----
Extent @ 0x7fff96016500
Allocated Address: 0x7fff95e00000
EOF
RUN