Arch-agnostic jemalloc heap parser (#5828)
This commit is contained in:
parent
3ed43c4c77
commit
dca635cde9
12 changed files with 2628 additions and 944 deletions
|
|
@ -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)");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
2
subprojects/rzheap/jemalloc-config-extractor/.gitignore
vendored
Normal file
2
subprojects/rzheap/jemalloc-config-extractor/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
extract_config_530
|
||||
extract_config_450
|
||||
132
subprojects/rzheap/jemalloc-config-extractor/Makefile
Normal file
132
subprojects/rzheap/jemalloc-config-extractor/Makefile
Normal 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"
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
42
subprojects/rzheap/rz_jemalloc/jemalloc_arch.h
Normal file
42
subprojects/rzheap/rz_jemalloc/jemalloc_arch.h
Normal 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
|
||||
155
test/db/archos/linux-arm64/dbg_dmx
Normal file
155
test/db/archos/linux-arm64/dbg_dmx
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue