diff --git a/librz/core/cconfig.c b/librz/core/cconfig.c index 6533f3b80f..c323651c18 100644 --- a/librz/core/cconfig.c +++ b/librz/core/cconfig.c @@ -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)"); diff --git a/librz/core/linux_heap_jemalloc.c b/librz/core/linux_heap_jemalloc.c index 504cdb3c72..62cdb56ad3 100644 --- a/librz/core/linux_heap_jemalloc.c +++ b/librz/core/linux_heap_jemalloc.c @@ -5,7 +5,7 @@ #include #include -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 \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"); diff --git a/librz/include/rz_heap_jemalloc.h b/librz/include/rz_heap_jemalloc.h index 28ce38e230..b9ed0e1eb2 100644 --- a/librz/include/rz_heap_jemalloc.h +++ b/librz/include/rz_heap_jemalloc.h @@ -4,6 +4,7 @@ #ifndef RZ_HEAP_JEMALLOC_H #define RZ_HEAP_JEMALLOC_H +#include #include #include diff --git a/subprojects/rzheap/jemalloc-config-extractor/.gitignore b/subprojects/rzheap/jemalloc-config-extractor/.gitignore new file mode 100644 index 0000000000..55061960cd --- /dev/null +++ b/subprojects/rzheap/jemalloc-config-extractor/.gitignore @@ -0,0 +1,2 @@ +extract_config_530 +extract_config_450 \ No newline at end of file diff --git a/subprojects/rzheap/jemalloc-config-extractor/Makefile b/subprojects/rzheap/jemalloc-config-extractor/Makefile new file mode 100644 index 0000000000..ee6548e4b1 --- /dev/null +++ b/subprojects/rzheap/jemalloc-config-extractor/Makefile @@ -0,0 +1,132 @@ +# SPDX-FileCopyrightText: 2026 bubblepipe +# SPDX-License-Identifier: LGPL-3.0-only + +# Makefile for jemalloc config extraction helper +# +# Usage: +# 1. Configure jemalloc first: +# cd /path/to/jemalloc +# ./configure [--host=] [--with-lg-page=] +# 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=] [--with-lg-page=]" + @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" diff --git a/subprojects/rzheap/jemalloc-config-extractor/extract_config_450.c b/subprojects/rzheap/jemalloc-config-extractor/extract_config_450.c new file mode 100644 index 0000000000..0ac3094aad --- /dev/null +++ b/subprojects/rzheap/jemalloc-config-extractor/extract_config_450.c @@ -0,0 +1,190 @@ +// SPDX-FileCopyrightText: 2026 bubblepipe +// 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= --with-lg-page= + * 2. Build jemalloc: make + * 3. Build this program: make -C extract_config + * 4. Run: ./extract_config_450 + */ + +#include "jemalloc/internal/jemalloc_internal.h" + +#include +#include + +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; +} diff --git a/subprojects/rzheap/jemalloc-config-extractor/extract_config_530.c b/subprojects/rzheap/jemalloc-config-extractor/extract_config_530.c new file mode 100644 index 0000000000..9e74598903 --- /dev/null +++ b/subprojects/rzheap/jemalloc-config-extractor/extract_config_530.c @@ -0,0 +1,231 @@ +// SPDX-FileCopyrightText: 2026 bubblepipe +// 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= --with-lg-page= + * 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 +#include + +// 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; +} diff --git a/subprojects/rzheap/rz_jemalloc/jemalloc_450.h b/subprojects/rzheap/rz_jemalloc/jemalloc_450.h index 217e783d23..3dd5cf3194 100644 --- a/subprojects/rzheap/rz_jemalloc/jemalloc_450.h +++ b/subprojects/rzheap/rz_jemalloc/jemalloc_450.h @@ -5,125 +5,509 @@ #ifndef RZ_JEMALLOC_450_H #define RZ_JEMALLOC_450_H +#include "jemalloc_arch.h" #include #include -#define JM_NBINS_450 36 #define NPSIZES_64_450 199 #define NPSIZES_32_450 71 #define SMOOTHSTEP_NSTEPS_450 200 #define BITMAP_MAX_LEVELS_450 5 #define LG_PAGE_450 12 -#define EXTENT_NODE_SIZE_64 112 -#define EXTENT_NODE_SIZE_32 56 -#define EXTENT_NODE_SIZE_MAX 112 +// ============================================================================ +// jemalloc 4.5.0 configuration +// ============================================================================ -#define ARENA_SIZE_64_450 10072 -#define ARENA_SIZE_32_450 5748 -#define ARENA_SIZE_MAX_450 10072 +typedef struct rz_jemalloc_arena_offsets_450_t { + ut32 lock; + ut32 stats; + ut32 tcache_ql; + ut32 prof_accumbytes; + ut32 achunks; + ut32 extent_sn_next; + ut32 lg_dirty_mult; + ut32 purging; + ut32 nactive; + ut32 runs_dirty; + ut32 chunks_cache; + ut32 decay; + ut32 huge; + ut32 huge_mtx; + ut32 chunks_szsnad_cached; + ut32 chunks_ad_cached; + ut32 chunks_mtx; + ut32 node_cache; + ut32 node_cache_mtx; + ut32 chunk_hooks; + ut32 bins; + ut32 runs_avail; +} RzJemallocArenaOffsets450; -#define ARENA_BIN_INFO_SIZE_64 64 -#define ARENA_BIN_INFO_SIZE_32 56 -#define ARENA_BIN_INFO_SIZE_MAX 64 +typedef struct rz_jemalloc_extent_node_offsets_450_t { + ut32 ql_link_next; +} RzJemallocExtentNodeOffsets450; -#define ARENA_BIN_SIZE_64 168 -#define ARENA_BIN_SIZE_32 116 -#define ARENA_BIN_SIZE_MAX 168 +typedef struct rz_jemalloc_bin_info_offsets_450_t { + ut32 bitmap_info; + ut32 reg0_offset; +} RzJemallocBinInfoOffsets450; -#define MALLOC_MUTEX_SIZE_64_450 80 -#define MALLOC_MUTEX_SIZE_32_450 44 +typedef struct rz_jemalloc_config_450_t { + RzJemallocArch arch; + ut8 ptr_size; + bool is_big_endian; -#define BITMAP_INFO_SIZE_64_450 16 -#define BITMAP_INFO_SIZE_32_450 32 + ut8 lg_page; -#define EXTENT_NODE_EN_ARENA_OFFSET_64 0 -#define EXTENT_NODE_EN_ADDR_OFFSET_64 8 -#define EXTENT_NODE_EN_SIZE_OFFSET_64 16 -#define EXTENT_NODE_EN_SN_OFFSET_64 24 -#define EXTENT_NODE_QL_LINK_NEXT_OFFSET_64 80 -#define EXTENT_NODE_QL_LINK_PREV_OFFSET_64 88 + ut32 sc_nbins; + ut32 npsizes; -#define EXTENT_NODE_EN_ARENA_OFFSET_32 0 -#define EXTENT_NODE_EN_ADDR_OFFSET_32 4 -#define EXTENT_NODE_EN_SIZE_OFFSET_32 8 -#define EXTENT_NODE_EN_SN_OFFSET_32 12 -#define EXTENT_NODE_QL_LINK_NEXT_OFFSET_32 40 -#define EXTENT_NODE_QL_LINK_PREV_OFFSET_32 44 + bool bitmap_use_tree; + ut32 bitmap_max_levels; -#define ARENA_IND_OFFSET_64_450 0 -#define ARENA_NTHREADS_OFFSET_64_450 4 -#define ARENA_LOCK_OFFSET_64_450 16 -#define ARENA_STATS_OFFSET_64_450 96 -#define ARENA_TCACHE_QL_OFFSET_64_450 224 -#define ARENA_PROF_ACCUMBYTES_OFFSET_64_450 232 -#define ARENA_OFFSET_STATE_OFFSET_64_450 240 -#define ARENA_DSS_PREC_OFFSET_64_450 248 -#define ARENA_ACHUNKS_OFFSET_64_450 256 -#define ARENA_EXTENT_SN_NEXT_OFFSET_64_450 264 -#define ARENA_SPARE_OFFSET_64_450 272 -#define ARENA_LG_DIRTY_MULT_OFFSET_64_450 280 -#define ARENA_PURGING_OFFSET_64_450 288 -#define ARENA_NACTIVE_OFFSET_64_450 296 -#define ARENA_NDIRTY_OFFSET_64_450 304 -#define ARENA_RUNS_DIRTY_OFFSET_64_450 312 -#define ARENA_CHUNKS_CACHE_OFFSET_64_450 328 -#define ARENA_DECAY_OFFSET_64_450 440 -#define ARENA_HUGE_OFFSET_64_450 2088 -#define ARENA_HUGE_MTX_OFFSET_64_450 2096 -#define ARENA_CHUNKS_SZSNAD_CACHED_OFFSET_64_450 2176 -#define ARENA_CHUNKS_AD_CACHED_OFFSET_64_450 2184 -#define ARENA_CHUNKS_MTX_OFFSET_64_450 2208 -#define ARENA_NODE_CACHE_OFFSET_64_450 2288 -#define ARENA_NODE_CACHE_MTX_OFFSET_64_450 2296 -#define ARENA_CHUNK_HOOKS_OFFSET_64_450 2376 -#define ARENA_BINS_OFFSET_64_450 2432 -#define ARENA_RUNS_AVAIL_OFFSET_64_450 8480 + ut32 extent_node_size; + ut32 bin_info_size; + ut32 bin_size; + ut32 arena_size; + ut32 bitmap_info_size; + ut32 malloc_mutex_size; -#define ARENA_IND_OFFSET_32_450 0 -#define ARENA_NTHREADS_OFFSET_32_450 4 -#define ARENA_LOCK_OFFSET_32_450 12 -#define ARENA_STATS_OFFSET_32_450 56 -#define ARENA_TCACHE_QL_OFFSET_32_450 152 -#define ARENA_PROF_ACCUMBYTES_OFFSET_32_450 156 -#define ARENA_OFFSET_STATE_OFFSET_32_450 164 -#define ARENA_DSS_PREC_OFFSET_32_450 168 -#define ARENA_ACHUNKS_OFFSET_32_450 172 -#define ARENA_EXTENT_SN_NEXT_OFFSET_32_450 176 -#define ARENA_SPARE_OFFSET_32_450 180 -#define ARENA_LG_DIRTY_MULT_OFFSET_32_450 184 -#define ARENA_PURGING_OFFSET_32_450 188 -#define ARENA_NACTIVE_OFFSET_32_450 192 -#define ARENA_NDIRTY_OFFSET_32_450 196 -#define ARENA_RUNS_DIRTY_OFFSET_32_450 200 -#define ARENA_CHUNKS_CACHE_OFFSET_32_450 208 -#define ARENA_DECAY_OFFSET_32_450 264 -#define ARENA_HUGE_OFFSET_32_450 1104 -#define ARENA_HUGE_MTX_OFFSET_32_450 1108 -#define ARENA_CHUNKS_SZSNAD_CACHED_OFFSET_32_450 1152 -#define ARENA_CHUNKS_AD_CACHED_OFFSET_32_450 1156 -#define ARENA_CHUNKS_MTX_OFFSET_32_450 1168 -#define ARENA_NODE_CACHE_OFFSET_32_450 1212 -#define ARENA_NODE_CACHE_MTX_OFFSET_32_450 1216 -#define ARENA_CHUNK_HOOKS_OFFSET_32_450 1260 -#define ARENA_BINS_OFFSET_32_450 1288 -#define ARENA_RUNS_AVAIL_OFFSET_32_450 5464 + RzJemallocArenaOffsets450 arena_offsets; + RzJemallocExtentNodeOffsets450 extent_node_offsets; + RzJemallocBinInfoOffsets450 bin_info_offsets; +} RzJemallocConfig450; -#define ARENA_BIN_INFO_REG_SIZE_OFFSET_64 0 -#define ARENA_BIN_INFO_REDZONE_SIZE_OFFSET_64 8 -#define ARENA_BIN_INFO_REG_INTERVAL_OFFSET_64 16 -#define ARENA_BIN_INFO_RUN_SIZE_OFFSET_64 24 -#define ARENA_BIN_INFO_NREGS_OFFSET_64 32 -#define ARENA_BIN_INFO_BITMAP_INFO_OFFSET_64 40 -#define ARENA_BIN_INFO_REG0_OFFSET_OFFSET_64 56 +static const RzJemallocConfig450 rz_jemalloc_config_amd64_linux_4k_450 = { + .arch = RZ_JEMALLOC_ARCH_AMD64, + .ptr_size = 8, + .is_big_endian = false, + .lg_page = 12, + .sc_nbins = 36, + .npsizes = 199, + .bitmap_use_tree = false, + .bitmap_max_levels = 0, + .extent_node_size = 112, + .bin_info_size = 64, + .bin_size = 168, + .arena_size = 10072, + .bitmap_info_size = 16, + .malloc_mutex_size = 80, + .arena_offsets = { + .lock = 16, + .stats = 96, + .tcache_ql = 224, + .prof_accumbytes = 232, + .achunks = 256, + .extent_sn_next = 264, + .lg_dirty_mult = 280, + .purging = 288, + .nactive = 296, + .runs_dirty = 312, + .chunks_cache = 328, + .decay = 440, + .huge = 2088, + .huge_mtx = 2096, + .chunks_szsnad_cached = 2176, + .chunks_ad_cached = 2184, + .chunks_mtx = 2208, + .node_cache = 2288, + .node_cache_mtx = 2296, + .chunk_hooks = 2376, + .bins = 2432, + .runs_avail = 8480, + }, + .extent_node_offsets = { + .ql_link_next = 80, + }, + .bin_info_offsets = { + .bitmap_info = 40, + .reg0_offset = 56, + }, +}; -#define ARENA_BIN_INFO_REG_SIZE_OFFSET_32 0 -#define ARENA_BIN_INFO_REDZONE_SIZE_OFFSET_32 4 -#define ARENA_BIN_INFO_REG_INTERVAL_OFFSET_32 8 -#define ARENA_BIN_INFO_RUN_SIZE_OFFSET_32 12 -#define ARENA_BIN_INFO_NREGS_OFFSET_32 16 -#define ARENA_BIN_INFO_BITMAP_INFO_OFFSET_32 20 -#define ARENA_BIN_INFO_REG0_OFFSET_OFFSET_32 52 +static const RzJemallocConfig450 rz_jemalloc_config_i386_linux_4k_450 = { + .arch = RZ_JEMALLOC_ARCH_I386, + .ptr_size = 4, + .is_big_endian = false, + .lg_page = 12, + .sc_nbins = 36, + .npsizes = 71, + .bitmap_use_tree = true, + .bitmap_max_levels = 5, + .extent_node_size = 56, + .bin_info_size = 56, + .bin_size = 116, + .arena_size = 5748, + .bitmap_info_size = 32, + .malloc_mutex_size = 44, + .arena_offsets = { + .lock = 12, + .stats = 56, + .tcache_ql = 152, + .prof_accumbytes = 156, + .achunks = 172, + .extent_sn_next = 176, + .lg_dirty_mult = 184, + .purging = 188, + .nactive = 192, + .runs_dirty = 200, + .chunks_cache = 208, + .decay = 264, + .huge = 1104, + .huge_mtx = 1108, + .chunks_szsnad_cached = 1152, + .chunks_ad_cached = 1156, + .chunks_mtx = 1168, + .node_cache = 1212, + .node_cache_mtx = 1216, + .chunk_hooks = 1260, + .bins = 1288, + .runs_avail = 5464, + }, + .extent_node_offsets = { + .ql_link_next = 40, + }, + .bin_info_offsets = { + .bitmap_info = 20, + .reg0_offset = 52, + }, +}; + +static const RzJemallocConfig450 rz_jemalloc_config_aarch64_linux_4k_450 = { + .arch = RZ_JEMALLOC_ARCH_AARCH64, + .ptr_size = 8, + .is_big_endian = false, + .lg_page = 12, + .sc_nbins = 36, + .npsizes = 199, + .bitmap_use_tree = false, + .bitmap_max_levels = 0, + .extent_node_size = 112, + .bin_info_size = 64, + .bin_size = 176, + .arena_size = 10392, + .bitmap_info_size = 16, + .malloc_mutex_size = 88, + .arena_offsets = { + .lock = 16, + .stats = 104, + .tcache_ql = 232, + .prof_accumbytes = 240, + .achunks = 264, + .extent_sn_next = 272, + .lg_dirty_mult = 288, + .purging = 296, + .nactive = 304, + .runs_dirty = 320, + .chunks_cache = 336, + .decay = 448, + .huge = 2096, + .huge_mtx = 2104, + .chunks_szsnad_cached = 2192, + .chunks_ad_cached = 2200, + .chunks_mtx = 2224, + .node_cache = 2312, + .node_cache_mtx = 2320, + .chunk_hooks = 2408, + .bins = 2464, + .runs_avail = 8800, + }, + .extent_node_offsets = { + .ql_link_next = 80, + }, + .bin_info_offsets = { + .bitmap_info = 40, + .reg0_offset = 56, + }, +}; + +static const RzJemallocConfig450 rz_jemalloc_config_aarch64_linux_16k_450 = { + .arch = RZ_JEMALLOC_ARCH_AARCH64, + .ptr_size = 8, + .is_big_endian = false, + .lg_page = 14, + .sc_nbins = 44, + .npsizes = 191, + .bitmap_use_tree = true, + .bitmap_max_levels = 4, + .extent_node_size = 112, + .bin_info_size = 104, + .bin_size = 176, + .arena_size = 11736, + .bitmap_info_size = 56, + .malloc_mutex_size = 88, + .arena_offsets = { + .lock = 16, + .stats = 104, + .tcache_ql = 232, + .prof_accumbytes = 240, + .achunks = 264, + .extent_sn_next = 272, + .lg_dirty_mult = 288, + .purging = 296, + .nactive = 304, + .runs_dirty = 320, + .chunks_cache = 336, + .decay = 448, + .huge = 2096, + .huge_mtx = 2104, + .chunks_szsnad_cached = 2192, + .chunks_ad_cached = 2200, + .chunks_mtx = 2224, + .node_cache = 2312, + .node_cache_mtx = 2320, + .chunk_hooks = 2408, + .bins = 2464, + .runs_avail = 10208, + }, + .extent_node_offsets = { + .ql_link_next = 80, + }, + .bin_info_offsets = { + .bitmap_info = 40, + .reg0_offset = 96, + }, +}; + +static const RzJemallocConfig450 rz_jemalloc_config_aarch64_linux_64k_450 = { + .arch = RZ_JEMALLOC_ARCH_AARCH64, + .ptr_size = 8, + .is_big_endian = false, + .lg_page = 16, + .sc_nbins = 52, + .npsizes = 183, + .bitmap_use_tree = true, + .bitmap_max_levels = 5, + .extent_node_size = 112, + .bin_info_size = 112, + .bin_size = 176, + .arena_size = 13080, + .bitmap_info_size = 64, + .malloc_mutex_size = 88, + .arena_offsets = { + .lock = 16, + .stats = 104, + .tcache_ql = 232, + .prof_accumbytes = 240, + .achunks = 264, + .extent_sn_next = 272, + .lg_dirty_mult = 288, + .purging = 296, + .nactive = 304, + .runs_dirty = 320, + .chunks_cache = 336, + .decay = 448, + .huge = 2096, + .huge_mtx = 2104, + .chunks_szsnad_cached = 2192, + .chunks_ad_cached = 2200, + .chunks_mtx = 2224, + .node_cache = 2312, + .node_cache_mtx = 2320, + .chunk_hooks = 2408, + .bins = 2464, + .runs_avail = 11616, + }, + .extent_node_offsets = { + .ql_link_next = 80, + }, + .bin_info_offsets = { + .bitmap_info = 40, + .reg0_offset = 104, + }, +}; + +static const RzJemallocConfig450 rz_jemalloc_config_arm32_linux_4k_450 = { + .arch = RZ_JEMALLOC_ARCH_ARM32, + .ptr_size = 4, + .is_big_endian = false, + .lg_page = 12, + .sc_nbins = 39, + .npsizes = 71, + .bitmap_use_tree = true, + .bitmap_max_levels = 5, + .extent_node_size = 56, + .bin_info_size = 56, + .bin_size = 128, + .arena_size = 6592, + .bitmap_info_size = 32, + .malloc_mutex_size = 44, + .arena_offsets = { + .lock = 12, + .stats = 56, + .tcache_ql = 160, + .prof_accumbytes = 168, + .achunks = 184, + .extent_sn_next = 188, + .lg_dirty_mult = 196, + .purging = 200, + .nactive = 204, + .runs_dirty = 212, + .chunks_cache = 220, + .decay = 280, + .huge = 1128, + .huge_mtx = 1132, + .chunks_szsnad_cached = 1176, + .chunks_ad_cached = 1180, + .chunks_mtx = 1192, + .node_cache = 1236, + .node_cache_mtx = 1240, + .chunk_hooks = 1284, + .bins = 1312, + .runs_avail = 6304, + }, + .extent_node_offsets = { + .ql_link_next = 40, + }, + .bin_info_offsets = { + .bitmap_info = 20, + .reg0_offset = 52, + }, +}; + +static const RzJemallocConfig450 rz_jemalloc_config_arm32_linux_64k_450 = { + .arch = RZ_JEMALLOC_ARCH_ARM32, + .ptr_size = 4, + .is_big_endian = false, + .lg_page = 16, + .sc_nbins = 55, + .npsizes = 55, + .bitmap_use_tree = true, + .bitmap_max_levels = 7, + .extent_node_size = 56, + .bin_info_size = 64, + .bin_size = 128, + .arena_size = 8576, + .bitmap_info_size = 40, + .malloc_mutex_size = 44, + .arena_offsets = { + .lock = 12, + .stats = 56, + .tcache_ql = 160, + .prof_accumbytes = 168, + .achunks = 184, + .extent_sn_next = 188, + .lg_dirty_mult = 196, + .purging = 200, + .nactive = 204, + .runs_dirty = 212, + .chunks_cache = 220, + .decay = 280, + .huge = 1128, + .huge_mtx = 1132, + .chunks_szsnad_cached = 1176, + .chunks_ad_cached = 1180, + .chunks_mtx = 1192, + .node_cache = 1236, + .node_cache_mtx = 1240, + .chunk_hooks = 1284, + .bins = 1312, + .runs_avail = 8352, + }, + .extent_node_offsets = { + .ql_link_next = 40, + }, + .bin_info_offsets = { + .bitmap_info = 20, + .reg0_offset = 60, + }, +}; + +static const RzJemallocConfig450 rz_jemalloc_config_aarch64_darwin_16k_450 = { + .arch = RZ_JEMALLOC_ARCH_AARCH64, + .ptr_size = 8, + .is_big_endian = false, + .lg_page = 14, + .sc_nbins = 44, + .npsizes = 191, + .bitmap_use_tree = true, + .bitmap_max_levels = 4, + .extent_node_size = 112, + .bin_info_size = 104, + .bin_size = 136, + .arena_size = 9816, + .bitmap_info_size = 56, + .malloc_mutex_size = 48, + .arena_offsets = { + .lock = 16, + .stats = 64, + .tcache_ql = 192, + .prof_accumbytes = 200, + .achunks = 224, + .extent_sn_next = 232, + .lg_dirty_mult = 248, + .purging = 256, + .nactive = 264, + .runs_dirty = 280, + .chunks_cache = 296, + .decay = 408, + .huge = 2056, + .huge_mtx = 2064, + .chunks_szsnad_cached = 2112, + .chunks_ad_cached = 2120, + .chunks_mtx = 2144, + .node_cache = 2192, + .node_cache_mtx = 2200, + .chunk_hooks = 2248, + .bins = 2304, + .runs_avail = 8288, + }, + .extent_node_offsets = { + .ql_link_next = 80, + }, + .bin_info_offsets = { + .bitmap_info = 40, + .reg0_offset = 96, + }, +}; + +static inline const RzJemallocConfig450 *rz_jemalloc_get_config_450(const char *arch, const char *os, int bits, const char *page_size) { + if (!arch || !os) { + return NULL; + } + + bool is_darwin = !strcmp(os, "darwin") || !strcmp(os, "macos") || !strcmp(os, "ios"); + bool is_x86 = !strcmp(arch, "x86") || !strcmp(arch, "x64"); + bool is_arm = !strcmp(arch, "arm") || !strcmp(arch, "aarch64"); + + bool is_16k = page_size && (!strcmp(page_size, "16k") || !strcmp(page_size, "16K")); + bool is_64k = page_size && (!strcmp(page_size, "64k") || !strcmp(page_size, "64K")); + + if (is_darwin && is_arm && bits == 64) { + return &rz_jemalloc_config_aarch64_darwin_16k_450; + } + + if (is_x86) { + if (bits == 64) { + return &rz_jemalloc_config_amd64_linux_4k_450; + } else { + return &rz_jemalloc_config_i386_linux_4k_450; + } + } + + if (is_arm) { + if (bits == 64) { + if (is_64k) { + return &rz_jemalloc_config_aarch64_linux_64k_450; + } else if (is_16k) { + return &rz_jemalloc_config_aarch64_linux_16k_450; + } + return &rz_jemalloc_config_aarch64_linux_4k_450; + } else { + if (is_64k) { + return &rz_jemalloc_config_arm32_linux_64k_450; + } + return &rz_jemalloc_config_arm32_linux_4k_450; + } + } + + return NULL; +} + +// ============================================================================ +// jemalloc 4.5.0 structs +// ============================================================================ /* * source: https://github.com/jemalloc/jemalloc/blob/4.5.0/include/jemalloc/internal/extent.h @@ -142,9 +526,7 @@ typedef struct extent_node_t_450 { */ typedef struct bitmap_info_t_450 { ut64 nbits; - // 64 bit dont use tree ut64 ngroups; - // 32 bit uses tree ut32 nlevels; ut64 levels[BITMAP_MAX_LEVELS_450 + 1]; } bitmap_info_t_450; @@ -196,229 +578,188 @@ typedef struct arena_t_450 { ut64 runs_avail_addr; } arena_t_450; -static inline size_t extent_node_size_450(bool is_64bit) { - return is_64bit ? EXTENT_NODE_SIZE_64 : EXTENT_NODE_SIZE_32; -} +// ============================================================================ +// jemalloc 4.5.0 parser functions +// ============================================================================ -static inline size_t arena_size_450(bool is_64bit) { - return is_64bit ? ARENA_SIZE_64_450 : ARENA_SIZE_32_450; -} - -static inline size_t arena_bin_info_size_450(bool is_64bit) { - return is_64bit ? ARENA_BIN_INFO_SIZE_64 : ARENA_BIN_INFO_SIZE_32; -} - -static inline size_t arena_bin_size_450(bool is_64bit) { - return is_64bit ? ARENA_BIN_SIZE_64 : ARENA_BIN_SIZE_32; -} - -static inline size_t malloc_mutex_size_450(bool is_64bit) { - return is_64bit ? MALLOC_MUTEX_SIZE_64_450 : MALLOC_MUTEX_SIZE_32_450; -} - -static inline size_t bitmap_info_size_450(bool is_64bit) { - return is_64bit ? BITMAP_INFO_SIZE_64_450 : BITMAP_INFO_SIZE_32_450; -} - -static inline ut64 bins_offset_450(bool is_64bit) { - return is_64bit ? ARENA_BINS_OFFSET_64_450 : ARENA_BINS_OFFSET_32_450; -} - -static inline ut64 achunks_offset_450(bool is_64bit) { - return is_64bit ? ARENA_ACHUNKS_OFFSET_64_450 : ARENA_ACHUNKS_OFFSET_32_450; -} - -static inline ut32 npsizes_450(bool is_64bit) { - return is_64bit ? NPSIZES_64_450 : NPSIZES_32_450; -} - -static inline bool read_and_parse_extent_node_t_450_64(RzIO *io, ut64 addr, extent_node_t_450 *out) { - bool ret = false; - ut8 buf[EXTENT_NODE_SIZE_64]; - if (!rz_io_read_at_mapped(io, addr, buf, EXTENT_NODE_SIZE_64)) { +static inline bool read_and_parse_extent_node_t_450(RzIO *io, ut64 addr, extent_node_t_450 *out, + const RzJemallocConfig450 *config) { + ut8 *buf = RZ_NEWS0(ut8, config->extent_node_size); + if (!buf) { return false; } - RzBuffer *b = rz_buf_new_with_bytes(buf, EXTENT_NODE_SIZE_64); + if (!rz_io_read_at_mapped(io, addr, buf, config->extent_node_size)) { + free(buf); + return false; + } + RzBuffer *b = rz_buf_new_with_pointers(buf, config->extent_node_size, true); if (!b) { + free(buf); return false; } ut64 offset = 0; - - if (!rz_buf_read_le64_offset(b, &offset, &out->en_arena) || - !rz_buf_read_le64_offset(b, &offset, &out->en_addr) || - !rz_buf_read_le64_offset(b, &offset, &out->en_size) || - !rz_buf_read_le64_offset(b, &offset, &out->en_sn)) { - goto cleanup; - } - offset = EXTENT_NODE_QL_LINK_NEXT_OFFSET_64; - if (!rz_buf_read_le64_offset(b, &offset, &out->ql_link_next) || - !rz_buf_read_le64_offset(b, &offset, &out->ql_link_prev)) { - goto cleanup; - } - ret = true; - -cleanup: - rz_buf_free(b); - return ret; -} - -static inline bool read_and_parse_extent_node_t_450_32(RzIO *io, ut64 addr, extent_node_t_450 *out) { bool ret = false; - ut8 buf[EXTENT_NODE_SIZE_32]; - if (!rz_io_read_at_mapped(io, addr, buf, EXTENT_NODE_SIZE_32)) { - return false; - } - RzBuffer *b = rz_buf_new_with_bytes(buf, EXTENT_NODE_SIZE_32); - if (!b) { - return false; - } - ut64 offset = 0; - ut32 en_arena, en_addr, en_size, en_sn; - if (!rz_buf_read_le32_offset(b, &offset, &en_arena) || - !rz_buf_read_le32_offset(b, &offset, &en_addr) || - !rz_buf_read_le32_offset(b, &offset, &en_size) || - !rz_buf_read_le32_offset(b, &offset, &en_sn)) { - goto cleanup; - } - out->en_arena = en_arena; - out->en_addr = en_addr; - out->en_size = en_size; - out->en_sn = en_sn; + const RzJemallocExtentNodeOffsets450 *eno = &config->extent_node_offsets; - offset = EXTENT_NODE_QL_LINK_NEXT_OFFSET_32; - ut32 ql_next, ql_prev; - if (!rz_buf_read_le32_offset(b, &offset, &ql_next) || - !rz_buf_read_le32_offset(b, &offset, &ql_prev)) { - goto cleanup; - } - out->ql_link_next = ql_next; - out->ql_link_prev = ql_prev; - ret = true; - -cleanup: - rz_buf_free(b); - return ret; -} - -static inline bool read_and_parse_extent_node_t_450(RzIO *io, ut64 addr, extent_node_t_450 *out, bool is_64bit) { - return is_64bit - ? read_and_parse_extent_node_t_450_64(io, addr, out) - : read_and_parse_extent_node_t_450_32(io, addr, out); -} - -static inline bool read_and_parse_arena_bin_info_t_450_64(RzIO *io, ut64 addr, arena_bin_info_t_450 *out) { - bool ret = false; - ut8 buf[ARENA_BIN_INFO_SIZE_64]; - if (!rz_io_read_at_mapped(io, addr, buf, ARENA_BIN_INFO_SIZE_64)) { - return false; - } - RzBuffer *b = rz_buf_new_with_bytes(buf, ARENA_BIN_INFO_SIZE_64); - if (!b) { - return false; - } - ut64 offset = 0; - - if (!rz_buf_read_le64_offset(b, &offset, &out->reg_size) || - !rz_buf_read_le64_offset(b, &offset, &out->redzone_size) || - !rz_buf_read_le64_offset(b, &offset, &out->reg_interval) || - !rz_buf_read_le64_offset(b, &offset, &out->run_size) || - !rz_buf_read_le32_offset(b, &offset, &out->nregs)) { - goto cleanup; - } - offset = ARENA_BIN_INFO_BITMAP_INFO_OFFSET_64; - if (!rz_buf_read_le64_offset(b, &offset, &out->bitmap_info.nbits) || - !rz_buf_read_le64_offset(b, &offset, &out->bitmap_info.ngroups)) { - goto cleanup; - } - out->bitmap_info.nlevels = 0; - for (int i = 0; i < BITMAP_MAX_LEVELS_450 + 1; i++) { - out->bitmap_info.levels[i] = 0; - } - offset = ARENA_BIN_INFO_REG0_OFFSET_OFFSET_64; - if (!rz_buf_read_le32_offset(b, &offset, &out->reg0_offset)) { - goto cleanup; - } - ret = true; - -cleanup: - rz_buf_free(b); - return ret; -} - -static inline bool read_and_parse_arena_bin_info_t_450_32(RzIO *io, ut64 addr, arena_bin_info_t_450 *out) { - bool ret = false; - ut8 buf[ARENA_BIN_INFO_SIZE_32]; - if (!rz_io_read_at_mapped(io, addr, buf, ARENA_BIN_INFO_SIZE_32)) { - return false; - } - RzBuffer *b = rz_buf_new_with_bytes(buf, ARENA_BIN_INFO_SIZE_32); - if (!b) { - return false; - } - ut64 offset = 0; - - ut32 reg_size, redzone_size, reg_interval, run_size; - if (!rz_buf_read_le32_offset(b, &offset, ®_size) || - !rz_buf_read_le32_offset(b, &offset, &redzone_size) || - !rz_buf_read_le32_offset(b, &offset, ®_interval) || - !rz_buf_read_le32_offset(b, &offset, &run_size) || - !rz_buf_read_le32_offset(b, &offset, &out->nregs)) { - goto cleanup; - } - out->reg_size = reg_size; - out->redzone_size = redzone_size; - out->reg_interval = reg_interval; - out->run_size = run_size; - - offset = ARENA_BIN_INFO_BITMAP_INFO_OFFSET_32; - ut32 nbits; - if (!rz_buf_read_le32_offset(b, &offset, &nbits) || - !rz_buf_read_le32_offset(b, &offset, &out->bitmap_info.nlevels)) { - goto cleanup; - } - out->bitmap_info.nbits = nbits; - out->bitmap_info.ngroups = 0; - for (int i = 0; i < BITMAP_MAX_LEVELS_450 + 1; i++) { - ut32 level; - if (!rz_buf_read_le32_offset(b, &offset, &level)) { + if (config->ptr_size == 8) { + if (!rz_buf_read_le64_offset(b, &offset, &out->en_arena) || + !rz_buf_read_le64_offset(b, &offset, &out->en_addr) || + !rz_buf_read_le64_offset(b, &offset, &out->en_size) || + !rz_buf_read_le64_offset(b, &offset, &out->en_sn) || + ((offset = eno->ql_link_next), !rz_buf_read_le64_offset(b, &offset, &out->ql_link_next)) || + !rz_buf_read_le64_offset(b, &offset, &out->ql_link_prev)) { goto cleanup; } - out->bitmap_info.levels[i] = level; - } - offset = ARENA_BIN_INFO_REG0_OFFSET_OFFSET_32; - if (!rz_buf_read_le32_offset(b, &offset, &out->reg0_offset)) { - goto cleanup; + } else { + ut32 en_arena, en_addr, en_size, en_sn, ql_next, ql_prev; + if (!rz_buf_read_le32_offset(b, &offset, &en_arena) || + !rz_buf_read_le32_offset(b, &offset, &en_addr) || + !rz_buf_read_le32_offset(b, &offset, &en_size) || + !rz_buf_read_le32_offset(b, &offset, &en_sn) || + ((offset = eno->ql_link_next), !rz_buf_read_le32_offset(b, &offset, &ql_next)) || + !rz_buf_read_le32_offset(b, &offset, &ql_prev)) { + goto cleanup; + } + out->en_arena = en_arena; + out->en_addr = en_addr; + out->en_size = en_size; + out->en_sn = en_sn; + out->ql_link_next = ql_next; + out->ql_link_prev = ql_prev; } ret = true; - cleanup: rz_buf_free(b); return ret; } -static inline bool read_and_parse_arena_bin_info_t_450(RzIO *io, ut64 addr, arena_bin_info_t_450 *out, bool is_64bit) { - return is_64bit - ? read_and_parse_arena_bin_info_t_450_64(io, addr, out) - : read_and_parse_arena_bin_info_t_450_32(io, addr, out); -} - -static inline bool read_and_parse_arena_t_450_64(RzIO *io, ut64 addr, arena_t_450 *out) { - bool ret = false; - ut8 *buf = malloc(ARENA_SIZE_64_450); +static inline bool read_and_parse_arena_bin_info_t_450(RzIO *io, ut64 addr, arena_bin_info_t_450 *out, + const RzJemallocConfig450 *config) { + ut8 *buf = RZ_NEWS0(ut8, config->bin_info_size); if (!buf) { return false; } - if (!rz_io_read_at_mapped(io, addr, buf, ARENA_SIZE_64_450)) { + if (!rz_io_read_at_mapped(io, addr, buf, config->bin_info_size)) { free(buf); return false; } - RzBuffer *b = rz_buf_new_with_bytes(buf, ARENA_SIZE_64_450); - free(buf); + RzBuffer *b = rz_buf_new_with_pointers(buf, config->bin_info_size, true); if (!b) { + free(buf); return false; } ut64 offset = 0; + bool ret = false; + + const RzJemallocBinInfoOffsets450 *bio = &config->bin_info_offsets; + + if (config->ptr_size == 8) { + if (!rz_buf_read_le64_offset(b, &offset, &out->reg_size) || + !rz_buf_read_le64_offset(b, &offset, &out->redzone_size) || + !rz_buf_read_le64_offset(b, &offset, &out->reg_interval) || + !rz_buf_read_le64_offset(b, &offset, &out->run_size) || + !rz_buf_read_le32_offset(b, &offset, &out->nregs)) { + goto cleanup; + } + + offset = bio->bitmap_info; + if (config->bitmap_use_tree) { // tree format for 64 bit + if (!rz_buf_read_le64_offset(b, &offset, &out->bitmap_info.nbits) || + !rz_buf_read_le32_offset(b, &offset, &out->bitmap_info.nlevels)) { + goto cleanup; + } + out->bitmap_info.ngroups = 0; + for (int i = 0; i < BITMAP_MAX_LEVELS_450 + 1; i++) { + if (!rz_buf_read_le64_offset(b, &offset, &out->bitmap_info.levels[i])) { + goto cleanup; + } + } + } else { // non-tree format for 64 bit + if (!rz_buf_read_le64_offset(b, &offset, &out->bitmap_info.nbits) || + !rz_buf_read_le64_offset(b, &offset, &out->bitmap_info.ngroups)) { + goto cleanup; + } + out->bitmap_info.nlevels = 0; + for (int i = 0; i < BITMAP_MAX_LEVELS_450 + 1; i++) { + out->bitmap_info.levels[i] = 0; + } + } + if (((offset = bio->reg0_offset), !rz_buf_read_le32_offset(b, &offset, &out->reg0_offset))) { + goto cleanup; + } + } else { + ut32 reg_size, redzone_size, reg_interval, run_size; + if (!rz_buf_read_le32_offset(b, &offset, ®_size) || + !rz_buf_read_le32_offset(b, &offset, &redzone_size) || + !rz_buf_read_le32_offset(b, &offset, ®_interval) || + !rz_buf_read_le32_offset(b, &offset, &run_size) || + !rz_buf_read_le32_offset(b, &offset, &out->nregs)) { + goto cleanup; + } + out->reg_size = reg_size; + out->redzone_size = redzone_size; + out->reg_interval = reg_interval; + out->run_size = run_size; + + offset = bio->bitmap_info; + if (config->bitmap_use_tree) { // tree format for 32 bit + ut32 nbits; + if (!rz_buf_read_le32_offset(b, &offset, &nbits) || + !rz_buf_read_le32_offset(b, &offset, &out->bitmap_info.nlevels)) { + goto cleanup; + } + out->bitmap_info.nbits = nbits; + out->bitmap_info.ngroups = 0; + for (int i = 0; i < BITMAP_MAX_LEVELS_450 + 1; i++) { + ut32 level; + if (!rz_buf_read_le32_offset(b, &offset, &level)) { + goto cleanup; + } + out->bitmap_info.levels[i] = level; + } + } else { // non-tree format for 32 bit + ut32 nbits, ngroups; + if (!rz_buf_read_le32_offset(b, &offset, &nbits) || + !rz_buf_read_le32_offset(b, &offset, &ngroups)) { + goto cleanup; + } + out->bitmap_info.nbits = nbits; + out->bitmap_info.ngroups = ngroups; + out->bitmap_info.nlevels = 0; + for (int i = 0; i < BITMAP_MAX_LEVELS_450 + 1; i++) { + out->bitmap_info.levels[i] = 0; + } + } + if (((offset = bio->reg0_offset), !rz_buf_read_le32_offset(b, &offset, &out->reg0_offset))) { + goto cleanup; + } + } + ret = true; +cleanup: + rz_buf_free(b); + return ret; +} + +static inline bool read_and_parse_arena_t_450(RzIO *io, ut64 addr, arena_t_450 *out, + const RzJemallocConfig450 *config) { + ut8 *buf = RZ_NEWS0(ut8, config->arena_size); + if (!buf) { + return false; + } + if (!rz_io_read_at_mapped(io, addr, buf, config->arena_size)) { + free(buf); + return false; + } + RzBuffer *b = rz_buf_new_with_pointers(buf, config->arena_size, true); + if (!b) { + free(buf); + return false; + } + ut64 offset = 0; + bool ret = false; + + const RzJemallocArenaOffsets450 *ao = &config->arena_offsets; if (!rz_buf_read_le32_offset(b, &offset, &out->ind) || !rz_buf_read_le32_offset(b, &offset, &out->nthreads[0]) || @@ -426,158 +767,72 @@ static inline bool read_and_parse_arena_t_450_64(RzIO *io, ut64 addr, arena_t_45 goto cleanup; } - ut64 lg_dirty_mult_raw; - ut8 purging_byte; - - offset = ARENA_PROF_ACCUMBYTES_OFFSET_64_450; - if (!rz_buf_read_le64_offset(b, &offset, &out->prof_accumbytes) || - !rz_buf_read_le64_offset(b, &offset, &out->offset_state) || - !rz_buf_read_le32_offset(b, &offset, &out->dss_prec)) { - goto cleanup; + if (config->ptr_size == 8) { + ut64 lg_dirty_mult_tmp; + ut8 purging_byte; + if (((offset = ao->prof_accumbytes), !rz_buf_read_le64_offset(b, &offset, &out->prof_accumbytes)) || + !rz_buf_read_le64_offset(b, &offset, &out->offset_state) || + !rz_buf_read_le32_offset(b, &offset, &out->dss_prec) || + ((offset = ao->extent_sn_next), !rz_buf_read_le64_offset(b, &offset, &out->extent_sn_next)) || + !rz_buf_read_le64_offset(b, &offset, &out->spare) || + ((offset = ao->lg_dirty_mult), !rz_buf_read_le64_offset(b, &offset, &lg_dirty_mult_tmp)) || + ((offset = ao->purging), !rz_buf_read8_offset(b, &offset, &purging_byte)) || + ((offset = ao->nactive), !rz_buf_read_le64_offset(b, &offset, &out->nactive)) || + !rz_buf_read_le64_offset(b, &offset, &out->ndirty)) { + goto cleanup; + } + out->lg_dirty_mult = (st64)lg_dirty_mult_tmp; + out->purging = purging_byte != 0; + } else { + ut32 offset_state, extent_sn_next, spare, lg_dirty_mult_tmp, nactive, ndirty; + ut8 purging_byte; + if (((offset = ao->prof_accumbytes), !rz_buf_read_le64_offset(b, &offset, &out->prof_accumbytes)) || + !rz_buf_read_le32_offset(b, &offset, &offset_state) || + !rz_buf_read_le32_offset(b, &offset, &out->dss_prec) || + ((offset = ao->extent_sn_next), !rz_buf_read_le32_offset(b, &offset, &extent_sn_next)) || + !rz_buf_read_le32_offset(b, &offset, &spare) || + ((offset = ao->lg_dirty_mult), !rz_buf_read_le32_offset(b, &offset, &lg_dirty_mult_tmp)) || + ((offset = ao->purging), !rz_buf_read8_offset(b, &offset, &purging_byte)) || + ((offset = ao->nactive), !rz_buf_read_le32_offset(b, &offset, &nactive)) || + !rz_buf_read_le32_offset(b, &offset, &ndirty)) { + goto cleanup; + } + out->offset_state = offset_state; + out->extent_sn_next = extent_sn_next; + out->spare = spare; + out->lg_dirty_mult = (st32)lg_dirty_mult_tmp; + out->purging = purging_byte != 0; + out->nactive = nactive; + out->ndirty = ndirty; } - offset = ARENA_EXTENT_SN_NEXT_OFFSET_64_450; - if (!rz_buf_read_le64_offset(b, &offset, &out->extent_sn_next) || - !rz_buf_read_le64_offset(b, &offset, &out->spare)) { - goto cleanup; - } + out->lock_addr = addr + ao->lock; + out->stats_addr = addr + ao->stats; + out->tcache_ql_addr = addr + ao->tcache_ql; + out->achunks_addr = addr + ao->achunks; + out->runs_dirty_addr = addr + ao->runs_dirty; + out->chunks_cache_addr = addr + ao->chunks_cache; + out->decay_addr = addr + ao->decay; + out->huge_addr = addr + ao->huge; + out->huge_mtx_addr = addr + ao->huge_mtx; + out->chunks_szsnad_cached_addr = addr + ao->chunks_szsnad_cached; + out->chunks_ad_cached_addr = addr + ao->chunks_ad_cached; + out->chunks_mtx_addr = addr + ao->chunks_mtx; + out->node_cache_addr = addr + ao->node_cache; + out->node_cache_mtx_addr = addr + ao->node_cache_mtx; + out->chunk_hooks_addr = addr + ao->chunk_hooks; + out->bins_addr = addr + ao->bins; + out->runs_avail_addr = addr + ao->runs_avail; - offset = ARENA_LG_DIRTY_MULT_OFFSET_64_450; - if (!rz_buf_read_le64_offset(b, &offset, &lg_dirty_mult_raw)) { - goto cleanup; - } - out->lg_dirty_mult = (st64)lg_dirty_mult_raw; - - offset = ARENA_PURGING_OFFSET_64_450; - if (rz_buf_read_at(b, offset, &purging_byte, 1) != 1) { - goto cleanup; - } - out->purging = purging_byte != 0; - - offset = ARENA_NACTIVE_OFFSET_64_450; - if (!rz_buf_read_le64_offset(b, &offset, &out->nactive) || - !rz_buf_read_le64_offset(b, &offset, &out->ndirty)) { - goto cleanup; - } - - out->lock_addr = addr + ARENA_LOCK_OFFSET_64_450; - out->stats_addr = addr + ARENA_STATS_OFFSET_64_450; - out->tcache_ql_addr = addr + ARENA_TCACHE_QL_OFFSET_64_450; - out->achunks_addr = addr + ARENA_ACHUNKS_OFFSET_64_450; - out->runs_dirty_addr = addr + ARENA_RUNS_DIRTY_OFFSET_64_450; - out->chunks_cache_addr = addr + ARENA_CHUNKS_CACHE_OFFSET_64_450; - out->decay_addr = addr + ARENA_DECAY_OFFSET_64_450; - out->huge_addr = addr + ARENA_HUGE_OFFSET_64_450; - out->huge_mtx_addr = addr + ARENA_HUGE_MTX_OFFSET_64_450; - out->chunks_szsnad_cached_addr = addr + ARENA_CHUNKS_SZSNAD_CACHED_OFFSET_64_450; - out->chunks_ad_cached_addr = addr + ARENA_CHUNKS_AD_CACHED_OFFSET_64_450; - out->chunks_mtx_addr = addr + ARENA_CHUNKS_MTX_OFFSET_64_450; - out->node_cache_addr = addr + ARENA_NODE_CACHE_OFFSET_64_450; - out->node_cache_mtx_addr = addr + ARENA_NODE_CACHE_MTX_OFFSET_64_450; - out->chunk_hooks_addr = addr + ARENA_CHUNK_HOOKS_OFFSET_64_450; - out->bins_addr = addr + ARENA_BINS_OFFSET_64_450; - out->runs_avail_addr = addr + ARENA_RUNS_AVAIL_OFFSET_64_450; ret = true; - cleanup: rz_buf_free(b); return ret; } -static inline bool read_and_parse_arena_t_450_32(RzIO *io, ut64 addr, arena_t_450 *out) { - bool ret = false; - ut8 *buf = malloc(ARENA_SIZE_32_450); - if (!buf) { - return false; - } - if (!rz_io_read_at_mapped(io, addr, buf, ARENA_SIZE_32_450)) { - free(buf); - return false; - } - RzBuffer *b = rz_buf_new_with_bytes(buf, ARENA_SIZE_32_450); - free(buf); - if (!b) { - return false; - } - ut64 offset = 0; - - if (!rz_buf_read_le32_offset(b, &offset, &out->ind) || - !rz_buf_read_le32_offset(b, &offset, &out->nthreads[0]) || - !rz_buf_read_le32_offset(b, &offset, &out->nthreads[1])) { - goto cleanup; - } - - ut32 offset_state, extent_sn_next, spare, lg_dirty_mult_raw, nactive, ndirty; - ut8 purging_byte; - - offset = ARENA_PROF_ACCUMBYTES_OFFSET_32_450; - if (!rz_buf_read_le64_offset(b, &offset, &out->prof_accumbytes) || - !rz_buf_read_le32_offset(b, &offset, &offset_state) || - !rz_buf_read_le32_offset(b, &offset, &out->dss_prec)) { - goto cleanup; - } - out->offset_state = offset_state; - - offset = ARENA_EXTENT_SN_NEXT_OFFSET_32_450; - if (!rz_buf_read_le32_offset(b, &offset, &extent_sn_next) || - !rz_buf_read_le32_offset(b, &offset, &spare)) { - goto cleanup; - } - out->extent_sn_next = extent_sn_next; - out->spare = spare; - - offset = ARENA_LG_DIRTY_MULT_OFFSET_32_450; - if (!rz_buf_read_le32_offset(b, &offset, &lg_dirty_mult_raw)) { - goto cleanup; - } - out->lg_dirty_mult = (st32)lg_dirty_mult_raw; - - offset = ARENA_PURGING_OFFSET_32_450; - if (rz_buf_read_at(b, offset, &purging_byte, 1) != 1) { - goto cleanup; - } - out->purging = purging_byte != 0; - - offset = ARENA_NACTIVE_OFFSET_32_450; - if (!rz_buf_read_le32_offset(b, &offset, &nactive) || - !rz_buf_read_le32_offset(b, &offset, &ndirty)) { - goto cleanup; - } - out->nactive = nactive; - out->ndirty = ndirty; - - out->lock_addr = addr + ARENA_LOCK_OFFSET_32_450; - out->stats_addr = addr + ARENA_STATS_OFFSET_32_450; - out->tcache_ql_addr = addr + ARENA_TCACHE_QL_OFFSET_32_450; - out->achunks_addr = addr + ARENA_ACHUNKS_OFFSET_32_450; - out->runs_dirty_addr = addr + ARENA_RUNS_DIRTY_OFFSET_32_450; - out->chunks_cache_addr = addr + ARENA_CHUNKS_CACHE_OFFSET_32_450; - out->decay_addr = addr + ARENA_DECAY_OFFSET_32_450; - out->huge_addr = addr + ARENA_HUGE_OFFSET_32_450; - out->huge_mtx_addr = addr + ARENA_HUGE_MTX_OFFSET_32_450; - out->chunks_szsnad_cached_addr = addr + ARENA_CHUNKS_SZSNAD_CACHED_OFFSET_32_450; - out->chunks_ad_cached_addr = addr + ARENA_CHUNKS_AD_CACHED_OFFSET_32_450; - out->chunks_mtx_addr = addr + ARENA_CHUNKS_MTX_OFFSET_32_450; - out->node_cache_addr = addr + ARENA_NODE_CACHE_OFFSET_32_450; - out->node_cache_mtx_addr = addr + ARENA_NODE_CACHE_MTX_OFFSET_32_450; - out->chunk_hooks_addr = addr + ARENA_CHUNK_HOOKS_OFFSET_32_450; - out->bins_addr = addr + ARENA_BINS_OFFSET_32_450; - out->runs_avail_addr = addr + ARENA_RUNS_AVAIL_OFFSET_32_450; - ret = true; - -cleanup: - rz_buf_free(b); - return ret; -} - -static inline bool read_and_parse_arena_t_450(RzIO *io, ut64 addr, arena_t_450 *out, bool is_64bit) { - return is_64bit - ? read_and_parse_arena_t_450_64(io, addr, out) - : read_and_parse_arena_t_450_32(io, addr, out); -} - -static inline bool read_achunks_first_450(RzIO *io, ut64 achunks_addr, ut64 *first_out, bool is_64bit) { - if (is_64bit) { +static inline bool read_achunks_first_450(RzIO *io, ut64 achunks_addr, ut64 *first_out, + const RzJemallocConfig450 *config) { + if (config->ptr_size == 8) { ut8 buf[8]; if (!rz_io_read_at_mapped(io, achunks_addr, buf, 8)) { return false; diff --git a/subprojects/rzheap/rz_jemalloc/jemalloc_530.h b/subprojects/rzheap/rz_jemalloc/jemalloc_530.h index 9eb6b2b389..dc14a2ebed 100644 --- a/subprojects/rzheap/rz_jemalloc/jemalloc_530.h +++ b/subprojects/rzheap/rz_jemalloc/jemalloc_530.h @@ -5,82 +5,15 @@ #ifndef RZ_JEMALLOC_530_H #define RZ_JEMALLOC_530_H +#include "jemalloc_arch.h" #include #include -#define EDATA_SIZE_64 128 -#define EDATA_SIZE_32 108 -#define EDATA_SIZE_MAX 128 -#define BIN_INFO_SIZE_64 40 -#define BIN_INFO_SIZE_32 48 -#define BIN_INFO_SIZE_MAX 48 -#define BIN_SIZE_64 224 -#define BIN_SIZE_32 172 -#define BIN_SIZE_MAX 224 -#define ARENA_SIZE_64 78952 -#define ARENA_SIZE_32 22004 -#define ARENA_SIZE_MAX 78952 -#define RTREE_NODE_ELM_SIZE_64 8 -#define RTREE_NODE_ELM_SIZE_32 4 -#define RTREE_NODE_ELM_SIZE_MAX 8 -#define RTREE_LEAF_ELM_SIZE_64 8 -#define RTREE_LEAF_ELM_SIZE_32 8 -#define RTREE_LEAF_ELM_SIZE_MAX 8 -#define PHN_LINK_SIZE_64 24 -#define PHN_LINK_SIZE_32 12 -#define PH_SIZE_64 16 -#define PH_SIZE_32 8 -#define NSTIME_SIZE_64 8 -#define NSTIME_SIZE_32 8 -#define BITMAP_INFO_SIZE_64 16 -#define BITMAP_INFO_SIZE_32 32 -#define RTREE_SIZE_64 2097272 -#define RTREE_SIZE_32 4188 -#define SC_NSIZES 235 -#define SC_LG_SLAB_MAXREGS 9 -#define MALLOC_MUTEX_SIZE_64 112 -#define MALLOC_MUTEX_SIZE_32 88 -#define BIN_STATS_SIZE_64 80 -#define BIN_STATS_SIZE_32 68 -#define MALLOCX_ARENA_BITS 12 -#define EDATA_ALIGNMENT 128 -#define LG_PAGE_530 12 -#define JM_NBINS_530 36 -#define ARENA_LAST_THD_OFFSET_64 16 -#define ARENA_STATS_OFFSET_64 24 -#define ARENA_TCACHE_QL_OFFSET_64 10392 -#define ARENA_CACHE_BIN_ARR_OFFSET_64 10400 -#define ARENA_TCACHE_QL_MTX_OFFSET_64 10408 -#define ARENA_DSS_PREC_OFFSET_64 10520 -#define ARENA_LARGE_OFFSET_64 10528 -#define ARENA_LARGE_MTX_OFFSET_64 10536 -#define ARENA_PA_SHARD_OFFSET_64 10648 -#define ARENA_IND_OFFSET_64 78928 -#define ARENA_BASE_OFFSET_64 78936 -#define ARENA_CREATE_TIME_OFFSET_64 78944 -#define ARENA_BINS_OFFSET_64 78952 -#define ARENA_STATS_OFFSET_32 16 -#define ARENA_TCACHE_QL_OFFSET_32 3960 -#define ARENA_CACHE_BIN_ARR_OFFSET_32 3964 -#define ARENA_TCACHE_QL_MTX_OFFSET_32 3968 -#define ARENA_LARGE_OFFSET_32 4032 -#define ARENA_LARGE_MTX_OFFSET_32 4036 -#define ARENA_PA_SHARD_OFFSET_32 4040 -#define ARENA_DSS_PREC_OFFSET_32 4056 -#define ARENA_IND_OFFSET_32 21988 -#define ARENA_BASE_OFFSET_32 21992 -#define ARENA_CREATE_TIME_OFFSET_32 21996 -#define ARENA_BINS_OFFSET_32 22004 -#define BIN_SLABCUR_OFFSET_64 192 -#define BIN_SLABCUR_OFFSET_32 156 -#define RTREE_NSB_64 36 -#define RTREE_NSB_32 20 -#define RTREE_BITS_PER_LEVEL_64 18 -#define RTREE_BITS_PER_LEVEL_32 10 -#define RTREE_MAX_SUBKEYS_64 (1U << RTREE_BITS_PER_LEVEL_64) -#define RTREE_MAX_SUBKEYS_32 (1U << RTREE_BITS_PER_LEVEL_32) -#define RTREE_ROOT_OFFSET_64 120 -#define RTREE_ROOT_OFFSET_32 92 +#define BITMAP_MAX_LEVELS_530 6 +#define SC_NSIZES 235 +#define SC_LG_SLAB_MAXREGS 9 +#define MALLOCX_ARENA_BITS 12 +#define EDATA_ALIGNMENT 128 #define MASK(CURRENT_FIELD_WIDTH, CURRENT_FIELD_SHIFT) ((((((ut64)0x1U) << (CURRENT_FIELD_WIDTH)) - 1)) << (CURRENT_FIELD_SHIFT)) @@ -112,25 +45,504 @@ #define EDATA_BITS_STATE_SHIFT (EDATA_BITS_GUARDED_WIDTH + EDATA_BITS_GUARDED_SHIFT) #define EDATA_BITS_STATE_MASK MASK(EDATA_BITS_STATE_WIDTH, EDATA_BITS_STATE_SHIFT) -#define EDATA_BITS_SZIND_WIDTH LG_CEIL(SC_NSIZES) -#define EDATA_BITS_SZIND_SHIFT (EDATA_BITS_STATE_WIDTH + EDATA_BITS_STATE_SHIFT) -#define EDATA_BITS_SZIND_MASK MASK(EDATA_BITS_SZIND_WIDTH, EDATA_BITS_SZIND_SHIFT) +// ============================================================================ +// jemalloc 5.3.0 configuration +// ============================================================================ -#define EDATA_BITS_NFREE_WIDTH (SC_LG_SLAB_MAXREGS + 1) -#define EDATA_BITS_NFREE_SHIFT (EDATA_BITS_SZIND_WIDTH + EDATA_BITS_SZIND_SHIFT) -#define EDATA_BITS_NFREE_MASK MASK(EDATA_BITS_NFREE_WIDTH, EDATA_BITS_NFREE_SHIFT) +typedef struct rz_jemalloc_arena_offsets_530_t { + ut32 stats; + ut32 tcache_ql; + ut32 cache_bin_arr; + ut32 tcache_ql_mtx; + ut32 dss_prec; + ut32 large; + ut32 large_mtx; + ut32 pa_shard; + ut32 ind; + ut32 base; + ut32 create_time; + ut32 bins; + ut32 last_thd; +} RzJemallocArenaOffsets530; -#define EDATA_BITS_BINSHARD_WIDTH 6 -#define EDATA_BITS_BINSHARD_SHIFT (EDATA_BITS_NFREE_WIDTH + EDATA_BITS_NFREE_SHIFT) -#define EDATA_BITS_BINSHARD_MASK MASK(EDATA_BITS_BINSHARD_WIDTH, EDATA_BITS_BINSHARD_SHIFT) +typedef struct rz_jemalloc_bin_offsets_530_t { + ut32 slabcur; +} RzJemallocBinOffsets530; -#define EDATA_BITS_IS_HEAD_WIDTH 1 -#define EDATA_BITS_IS_HEAD_SHIFT (EDATA_BITS_BINSHARD_WIDTH + EDATA_BITS_BINSHARD_SHIFT) -#define EDATA_BITS_IS_HEAD_MASK MASK(EDATA_BITS_IS_HEAD_WIDTH, EDATA_BITS_IS_HEAD_SHIFT) +typedef struct rz_jemalloc_rtree_offsets_530_t { + ut32 root; +} RzJemallocRtreeOffsets530; -#define RTREE_LEAF_STATE_WIDTH EDATA_BITS_STATE_WIDTH -#define RTREE_LEAF_STATE_SHIFT 2 -#define RTREE_LEAF_STATE_MASK MASK(RTREE_LEAF_STATE_WIDTH, RTREE_LEAF_STATE_SHIFT) +typedef struct rz_jemalloc_config_530_t { + RzJemallocArch arch; + ut8 ptr_size; + bool is_big_endian; + + ut8 lg_page; // Log2 of page size (12=4K, 14=16K, 16=64K) + + ut32 sc_nbins; + ut32 sc_nsizes; + + bool bitmap_use_tree; + ut32 bitmap_max_levels; + + ut32 rtree_nsb; + ut32 rtree_bits_per_level; + ut32 rtree_height; + bool rtree_leaf_compact; + + ut32 edata_size; + ut32 bin_info_size; + ut32 bin_size; + ut32 arena_size; + ut32 bitmap_info_size; + ut32 rtree_node_elm_size; + ut32 rtree_leaf_elm_size; + + RzJemallocArenaOffsets530 arena_offsets; + RzJemallocBinOffsets530 bin_offsets; + RzJemallocRtreeOffsets530 rtree_offsets; +} RzJemallocConfig530; + +static const RzJemallocConfig530 rz_jemalloc_config_amd64_linux_4k_530 = { + .arch = RZ_JEMALLOC_ARCH_AMD64, + .ptr_size = 8, + .is_big_endian = false, + .lg_page = 12, + .sc_nbins = 36, + .sc_nsizes = 232, + .bitmap_use_tree = false, + .bitmap_max_levels = 0, + .rtree_nsb = 36, + .rtree_bits_per_level = 18, + .rtree_height = 2, + .rtree_leaf_compact = true, + .edata_size = 128, + .bin_info_size = 40, + .bin_size = 224, + .arena_size = 78952, + .bitmap_info_size = 16, + .rtree_node_elm_size = 8, + .rtree_leaf_elm_size = 8, + .arena_offsets = { + .stats = 24, + .tcache_ql = 10392, + .cache_bin_arr = 10400, + .tcache_ql_mtx = 10408, + .dss_prec = 10520, + .large = 10528, + .large_mtx = 10536, + .pa_shard = 10648, + .ind = 78928, + .base = 78936, + .create_time = 78944, + .bins = 78952, + .last_thd = 16, + }, + .bin_offsets = { + .slabcur = 192, + }, + .rtree_offsets = { + .root = 120, + }, +}; + +static const RzJemallocConfig530 rz_jemalloc_config_i386_linux_4k_530 = { + .arch = RZ_JEMALLOC_ARCH_I386, + .ptr_size = 4, + .is_big_endian = false, + .lg_page = 12, + .sc_nbins = 36, + .sc_nsizes = 104, + .bitmap_use_tree = true, + .bitmap_max_levels = 5, + .rtree_nsb = 20, + .rtree_bits_per_level = 10, + .rtree_height = 2, + .rtree_leaf_compact = false, + .edata_size = 108, + .bin_info_size = 48, + .bin_size = 172, + .arena_size = 22004, + .bitmap_info_size = 32, + .rtree_node_elm_size = 4, + .rtree_leaf_elm_size = 8, + .arena_offsets = { + .stats = 16, + .tcache_ql = 3960, + .cache_bin_arr = 3964, + .tcache_ql_mtx = 3968, + .dss_prec = 4056, + .large = 4060, + .large_mtx = 4064, + .pa_shard = 4152, + .ind = 21988, + .base = 21992, + .create_time = 21996, + .bins = 22004, + .last_thd = 12, + }, + .bin_offsets = { + .slabcur = 156, + }, + .rtree_offsets = { + .root = 92, + }, +}; + +static const RzJemallocConfig530 rz_jemalloc_config_aarch64_linux_4k_530 = { + .arch = RZ_JEMALLOC_ARCH_AARCH64, + .ptr_size = 8, + .is_big_endian = false, + .lg_page = 12, + .sc_nbins = 36, + .sc_nsizes = 232, + .bitmap_use_tree = false, + .bitmap_max_levels = 0, + .rtree_nsb = 36, + .rtree_bits_per_level = 18, + .rtree_height = 2, + .rtree_leaf_compact = true, + .edata_size = 128, + .bin_info_size = 40, + .bin_size = 232, + .arena_size = 79048, + .bitmap_info_size = 16, + .rtree_node_elm_size = 8, + .rtree_leaf_elm_size = 8, + .arena_offsets = { + .stats = 24, + .tcache_ql = 10392, + .cache_bin_arr = 10400, + .tcache_ql_mtx = 10408, + .dss_prec = 10528, + .large = 10536, + .large_mtx = 10544, + .pa_shard = 10664, + .ind = 79024, + .base = 79032, + .create_time = 79040, + .bins = 79048, + .last_thd = 16, + }, + .bin_offsets = { + .slabcur = 200, + }, + .rtree_offsets = { + .root = 128, + }, +}; + +static const RzJemallocConfig530 rz_jemalloc_config_aarch64_linux_16k_530 = { + .arch = RZ_JEMALLOC_ARCH_AARCH64, + .ptr_size = 8, + .is_big_endian = false, + .lg_page = 14, + .sc_nbins = 44, + .sc_nsizes = 232, + .bitmap_use_tree = true, + .bitmap_max_levels = 5, + .rtree_nsb = 34, + .rtree_bits_per_level = 17, + .rtree_height = 2, + .rtree_leaf_compact = true, + .edata_size = 328, + .bin_info_size = 88, + .bin_size = 232, + .arena_size = 76312, + .bitmap_info_size = 64, + .rtree_node_elm_size = 8, + .rtree_leaf_elm_size = 8, + .arena_offsets = { + .stats = 24, + .tcache_ql = 10008, + .cache_bin_arr = 10016, + .tcache_ql_mtx = 10024, + .dss_prec = 10144, + .large = 10152, + .large_mtx = 10160, + .pa_shard = 10280, + .ind = 76288, + .base = 76296, + .create_time = 76304, + .bins = 76312, + .last_thd = 16, + }, + .bin_offsets = { + .slabcur = 200, + }, + .rtree_offsets = { + .root = 128, + }, +}; + +static const RzJemallocConfig530 rz_jemalloc_config_aarch64_linux_64k_530 = { + .arch = RZ_JEMALLOC_ARCH_AARCH64, + .ptr_size = 8, + .is_big_endian = false, + .lg_page = 16, + .sc_nbins = 52, + .sc_nsizes = 232, + .bitmap_use_tree = true, + .bitmap_max_levels = 5, + .rtree_nsb = 32, + .rtree_bits_per_level = 16, + .rtree_height = 2, + .rtree_leaf_compact = true, + .edata_size = 1112, + .bin_info_size = 88, + .bin_size = 232, + .arena_size = 73624, + .bitmap_info_size = 64, + .rtree_node_elm_size = 8, + .rtree_leaf_elm_size = 8, + .arena_offsets = { + .stats = 24, + .tcache_ql = 9624, + .cache_bin_arr = 9632, + .tcache_ql_mtx = 9640, + .dss_prec = 9760, + .large = 9768, + .large_mtx = 9776, + .pa_shard = 9896, + .ind = 73600, + .base = 73608, + .create_time = 73616, + .bins = 73624, + .last_thd = 16, + }, + .bin_offsets = { + .slabcur = 200, + }, + .rtree_offsets = { + .root = 128, + }, +}; + +static const RzJemallocConfig530 rz_jemalloc_config_arm32_linux_4k_530 = { + .arch = RZ_JEMALLOC_ARCH_ARM32, + .ptr_size = 4, + .is_big_endian = false, + .lg_page = 12, + .sc_nbins = 39, + .sc_nsizes = 107, + .bitmap_use_tree = true, + .bitmap_max_levels = 5, + .rtree_nsb = 20, + .rtree_bits_per_level = 10, + .rtree_height = 2, + .rtree_leaf_compact = false, + .edata_size = 120, + .bin_info_size = 48, + .bin_size = 184, + .arena_size = 24272, + .bitmap_info_size = 32, + .rtree_node_elm_size = 4, + .rtree_leaf_elm_size = 8, + .arena_offsets = { + .stats = 16, + .tcache_ql = 4296, + .cache_bin_arr = 4300, + .tcache_ql_mtx = 4304, + .dss_prec = 4400, + .large = 4404, + .large_mtx = 4408, + .pa_shard = 4504, + .ind = 24256, + .base = 24260, + .create_time = 24264, + .bins = 24272, + .last_thd = 12, + }, + .bin_offsets = { + .slabcur = 168, + }, + .rtree_offsets = { + .root = 104, + }, +}; + +static const RzJemallocConfig530 rz_jemalloc_config_arm32_linux_64k_530 = { + .arch = RZ_JEMALLOC_ARCH_ARM32, + .ptr_size = 4, + .is_big_endian = false, + .lg_page = 16, + .sc_nbins = 55, + .sc_nsizes = 107, + .bitmap_use_tree = true, + .bitmap_max_levels = 5, + .rtree_nsb = 16, + .rtree_bits_per_level = 8, + .rtree_height = 2, + .rtree_leaf_compact = false, + .edata_size = 1112, + .bin_info_size = 48, + .bin_size = 184, + .arena_size = 20384, + .bitmap_info_size = 32, + .rtree_node_elm_size = 4, + .rtree_leaf_elm_size = 8, + .arena_offsets = { + .stats = 16, + .tcache_ql = 3528, + .cache_bin_arr = 3532, + .tcache_ql_mtx = 3536, + .dss_prec = 3632, + .large = 3636, + .large_mtx = 3640, + .pa_shard = 3736, + .ind = 20368, + .base = 20372, + .create_time = 20376, + .bins = 20384, + .last_thd = 12, + }, + .bin_offsets = { + .slabcur = 168, + }, + .rtree_offsets = { + .root = 104, + }, +}; + +static const RzJemallocConfig530 rz_jemalloc_config_riscv64_linux_4k_530 = { + .arch = RZ_JEMALLOC_ARCH_RISCV64, + .ptr_size = 8, + .is_big_endian = false, + .lg_page = 12, + .sc_nbins = 36, + .sc_nsizes = 232, + .bitmap_use_tree = false, + .bitmap_max_levels = 0, + .rtree_nsb = 52, + .rtree_bits_per_level = 17, + .rtree_height = 3, + .rtree_leaf_compact = false, + .edata_size = 128, + .bin_info_size = 40, + .bin_size = 224, + .arena_size = 78952, + .bitmap_info_size = 16, + .rtree_node_elm_size = 8, + .rtree_leaf_elm_size = 16, + .arena_offsets = { + .stats = 24, + .tcache_ql = 10392, + .cache_bin_arr = 10400, + .tcache_ql_mtx = 10408, + .dss_prec = 10520, + .large = 10528, + .large_mtx = 10536, + .pa_shard = 10648, + .ind = 78928, + .base = 78936, + .create_time = 78944, + .bins = 78952, + .last_thd = 16, + }, + .bin_offsets = { + .slabcur = 192, + }, + .rtree_offsets = { + .root = 120, + }, +}; + +static const RzJemallocConfig530 rz_jemalloc_config_aarch64_darwin_16k_530 = { + .arch = RZ_JEMALLOC_ARCH_AARCH64, + .ptr_size = 8, + .is_big_endian = false, + .lg_page = 14, + .sc_nbins = 44, + .sc_nsizes = 232, + .bitmap_use_tree = true, + .bitmap_max_levels = 5, + .rtree_nsb = 34, + .rtree_bits_per_level = 17, + .rtree_height = 2, + .rtree_leaf_compact = true, + .edata_size = 328, + .bin_info_size = 88, + .bin_size = 184, + .arena_size = 75736, + .bitmap_info_size = 64, + .rtree_node_elm_size = 8, + .rtree_leaf_elm_size = 8, + .arena_offsets = { + .stats = 24, + .tcache_ql = 10008, + .cache_bin_arr = 10016, + .tcache_ql_mtx = 10024, + .dss_prec = 10096, + .large = 10104, + .large_mtx = 10112, + .pa_shard = 10184, + .ind = 75712, + .base = 75720, + .create_time = 75728, + .bins = 75736, + .last_thd = 16, + }, + .bin_offsets = { + .slabcur = 152, + }, + .rtree_offsets = { + .root = 80, + }, +}; + +static inline const RzJemallocConfig530 *rz_jemalloc_get_config_530(const char *arch, const char *os, int bits, const char *page_size) { + if (!arch || !os) { + return NULL; + } + + // default is_linux + bool is_darwin = !strcmp(os, "darwin") || !strcmp(os, "macos") || !strcmp(os, "ios"); + bool is_x86 = !strcmp(arch, "x86") || !strcmp(arch, "x64"); + bool is_arm = !strcmp(arch, "arm") || !strcmp(arch, "aarch64"); + bool is_riscv = !strcmp(arch, "riscv"); + + bool is_16k = page_size && (!strcmp(page_size, "16k") || !strcmp(page_size, "16K")); + bool is_64k = page_size && (!strcmp(page_size, "64k") || !strcmp(page_size, "64K")); + + if (is_darwin && is_arm && bits == 64) { + return &rz_jemalloc_config_aarch64_darwin_16k_530; + } + + if (is_x86) { + if (bits == 64) { + return &rz_jemalloc_config_amd64_linux_4k_530; + } else { + return &rz_jemalloc_config_i386_linux_4k_530; + } + } + + if (is_arm) { + if (bits == 64) { + if (is_64k) { + return &rz_jemalloc_config_aarch64_linux_64k_530; + } else if (is_16k) { + return &rz_jemalloc_config_aarch64_linux_16k_530; + } + return &rz_jemalloc_config_aarch64_linux_4k_530; + } else { + if (is_64k) { + return &rz_jemalloc_config_arm32_linux_64k_530; + } + return &rz_jemalloc_config_arm32_linux_4k_530; + } + } + + if (is_riscv && bits == 64) { + return &rz_jemalloc_config_riscv64_linux_4k_530; + } + + return NULL; +} + +// ============================================================================ +// jemalloc 5.3.0 structs +// ============================================================================ /* * source: https://github.com/jemalloc/jemalloc/blob/5.3.0/include/jemalloc/internal/ph.h @@ -184,17 +596,15 @@ typedef struct nstime_t_530 { } nstime_t_530; /* - * Unified bitmap_info structure - * 64-bit: nbits(8) + ngroups(8) = 16 bytes (no BITMAP_USE_TREE) - * 32-bit: nbits(4) + nlevels(4) + levels[6](24) = 32 bytes (BITMAP_USE_TREE) + * source: https://github.com/jemalloc/jemalloc/blob/5.3.0/include/jemalloc/internal/bin_info.h */ typedef struct bitmap_info_t_530 { ut64 nbits; - // Non-tree format (64-bit) + // Non-tree format ut64 ngroups; - // Tree format (32-bit) + // Tree format ut32 nlevels; - ut64 levels[6]; // BITMAP_MAX_LEVELS + 1 + ut64 levels[BITMAP_MAX_LEVELS_530 + 1]; } bitmap_info_t_530; /* @@ -236,278 +646,329 @@ typedef struct arena_t_530 { ut64 bins_addr; } arena_t_530; -static inline size_t rtree_node_elm_size_530(bool is_64bit) { - return is_64bit ? RTREE_NODE_ELM_SIZE_64 : RTREE_NODE_ELM_SIZE_32; -} +// ============================================================================ +// parser +// ============================================================================ -static inline size_t rtree_leaf_elm_size_530(bool is_64bit) { - return is_64bit ? RTREE_LEAF_ELM_SIZE_64 : RTREE_LEAF_ELM_SIZE_32; -} - -static inline size_t edata_size_530(bool is_64bit) { - return is_64bit ? EDATA_SIZE_64 : EDATA_SIZE_32; -} - -static inline size_t bin_info_size_530(bool is_64bit) { - return is_64bit ? BIN_INFO_SIZE_64 : BIN_INFO_SIZE_32; -} - -static inline size_t bin_size_530(bool is_64bit) { - return is_64bit ? BIN_SIZE_64 : BIN_SIZE_32; -} - -static inline size_t arena_size_530(bool is_64bit) { - return is_64bit ? ARENA_SIZE_64 : ARENA_SIZE_32; -} - -static inline ut64 bins_offset_530(bool is_64bit) { - return is_64bit ? ARENA_BINS_OFFSET_64 : ARENA_BINS_OFFSET_32; -} - -static inline bool read_and_parse_rtree_node_elm_t_530(RzIO *io, ut64 addr, rtree_node_elm_t_530 *out, bool is_64bit) { - size_t size = rtree_node_elm_size_530(is_64bit); - ut8 buf[RTREE_NODE_ELM_SIZE_MAX]; - if (!rz_io_read_at_mapped(io, addr, buf, size)) { +static inline bool read_and_parse_rtree_node_elm_t_530(RzIO *io, ut64 addr, rtree_node_elm_t_530 *out, + const RzJemallocConfig530 *config) { + ut8 *buf = RZ_NEWS0(ut8, config->rtree_node_elm_size); + if (!buf) { return false; } - RzBuffer *b = rz_buf_new_with_bytes(buf, size); + if (!rz_io_read_at_mapped(io, addr, buf, config->rtree_node_elm_size)) { + free(buf); + return false; + } + RzBuffer *b = rz_buf_new_with_pointers(buf, config->rtree_node_elm_size, true); if (!b) { + free(buf); return false; } ut64 offset = 0; - bool ret; - if (is_64bit) { - ret = rz_buf_read_le64_offset(b, &offset, &out->child); + bool ret = false; + if (config->ptr_size == 8) { + if (!rz_buf_read_le64_offset(b, &offset, &out->child)) { + goto cleanup; + } } else { ut32 val; - ret = rz_buf_read_le32_offset(b, &offset, &val); - if (ret) { - out->child = val; + if (!rz_buf_read_le32_offset(b, &offset, &val)) { + goto cleanup; } + out->child = val; } + ret = true; +cleanup: rz_buf_free(b); return ret; } -static inline bool read_and_parse_rtree_leaf_elm_t_530(RzIO *io, ut64 addr, rtree_leaf_elm_t_530 *out, bool is_64bit) { - size_t size = rtree_leaf_elm_size_530(is_64bit); - ut8 buf[RTREE_LEAF_ELM_SIZE_MAX]; - if (!rz_io_read_at_mapped(io, addr, buf, size)) { +static inline bool read_and_parse_rtree_leaf_elm_t_530(RzIO *io, ut64 addr, rtree_leaf_elm_t_530 *out, + const RzJemallocConfig530 *config) { + ut8 *buf = RZ_NEWS0(ut8, config->rtree_leaf_elm_size); + if (!buf) { return false; } - RzBuffer *b = rz_buf_new_with_bytes(buf, size); + if (!rz_io_read_at_mapped(io, addr, buf, config->rtree_leaf_elm_size)) { + free(buf); + return false; + } + RzBuffer *b = rz_buf_new_with_pointers(buf, config->rtree_leaf_elm_size, true); if (!b) { + free(buf); return false; } ut64 offset = 0; - bool ret; - if (is_64bit) { - // 64-bit uses compact format with le_bits + bool ret = false; + if (config->rtree_leaf_compact) { + // Compact format with le_bits (used by x86_64, aarch64) + if (!rz_buf_read_le64_offset(b, &offset, &out->le_bits)) { + goto cleanup; + } out->le_edata = 0; out->le_metadata = 0; - ret = rz_buf_read_le64_offset(b, &offset, &out->le_bits); } else { - // 32-bit uses non-compact format - ut32 edata, metadata; + // Non-compact format with separate le_edata and le_metadata + // Used by i386, arm32, and riscv64 out->le_bits = 0; - ret = rz_buf_read_le32_offset(b, &offset, &edata) && - rz_buf_read_le32_offset(b, &offset, &metadata); - if (ret) { + if (config->ptr_size == 8) { + // 64-bit non-compact format (riscv64) + if (!rz_buf_read_le64_offset(b, &offset, &out->le_edata) || + !rz_buf_read_le64_offset(b, &offset, &out->le_metadata)) { + goto cleanup; + } + } else { + // 32-bit non-compact format (i386, arm32) + ut32 edata, metadata; + if (!rz_buf_read_le32_offset(b, &offset, &edata) || + !rz_buf_read_le32_offset(b, &offset, &metadata)) { + goto cleanup; + } out->le_edata = edata; out->le_metadata = metadata; } } + ret = true; +cleanup: rz_buf_free(b); return ret; } -static inline bool read_and_parse_edata_t_530(RzIO *io, ut64 addr, edata_t_530 *out, bool is_64bit) { - size_t size = edata_size_530(is_64bit); - ut8 buf[EDATA_SIZE_MAX]; - if (!rz_io_read_at_mapped(io, addr, buf, size)) { - return false; - } - RzBuffer *b = rz_buf_new_with_bytes(buf, size); - if (!b) { - return false; - } - ut64 offset = 0; - bool ret = false; - if (!rz_buf_read_le64_offset(b, &offset, &out->e_bits)) { - rz_buf_free(b); - return ret; - } - if (is_64bit) { - ret = rz_buf_read_le64_offset(b, &offset, &out->e_addr) && - rz_buf_read_le64_offset(b, &offset, &out->e_size_esn) && - rz_buf_read_le64_offset(b, &offset, &out->e_ps) && - rz_buf_read_le64_offset(b, &offset, &out->e_sn); - } else { - ut32 e_addr, size_esn, ps; - if (rz_buf_read_le32_offset(b, &offset, &e_addr) && - rz_buf_read_le32_offset(b, &offset, &size_esn) && - rz_buf_read_le32_offset(b, &offset, &ps)) { - out->e_addr = e_addr; - out->e_size_esn = size_esn; - out->e_ps = ps; - ret = rz_buf_read_le64_offset(b, &offset, &out->e_sn); - } - } - rz_buf_free(b); - return ret; -} - -static inline bool read_and_parse_bin_info_t_530(RzIO *io, ut64 addr, bin_info_t_530 *out, bool is_64bit) { - size_t size = bin_info_size_530(is_64bit); - ut8 buf[BIN_INFO_SIZE_MAX]; - if (!rz_io_read_at_mapped(io, addr, buf, size)) { - return false; - } - RzBuffer *b = rz_buf_new_with_bytes(buf, size); - if (!b) { - return false; - } - ut64 offset = 0; - bool ret = false; - if (is_64bit) { - if (rz_buf_read_le64_offset(b, &offset, &out->reg_size) && - rz_buf_read_le64_offset(b, &offset, &out->slab_size) && - rz_buf_read_le32_offset(b, &offset, &out->nregs) && - rz_buf_read_le32_offset(b, &offset, &out->n_shards) && - rz_buf_read_le64_offset(b, &offset, &out->bitmap_info.nbits) && - rz_buf_read_le64_offset(b, &offset, &out->bitmap_info.ngroups)) { - out->bitmap_info.nlevels = 0; - ret = true; - } - } else { - ut32 reg_size, slab_size, nbits; - if (rz_buf_read_le32_offset(b, &offset, ®_size) && - rz_buf_read_le32_offset(b, &offset, &slab_size) && - rz_buf_read_le32_offset(b, &offset, &out->nregs) && - rz_buf_read_le32_offset(b, &offset, &out->n_shards) && - rz_buf_read_le32_offset(b, &offset, &nbits) && - rz_buf_read_le32_offset(b, &offset, &out->bitmap_info.nlevels)) { - out->reg_size = reg_size; - out->slab_size = slab_size; - out->bitmap_info.nbits = nbits; - out->bitmap_info.ngroups = 0; - ret = true; - for (int i = 0; i < 6; i++) { - ut32 level; - if (!rz_buf_read_le32_offset(b, &offset, &level)) { - ret = false; - break; - } - out->bitmap_info.levels[i] = level; - } - } - } - rz_buf_free(b); - return ret; -} - -static inline bool read_and_parse_bin_t_530(RzIO *io, ut64 addr, bin_t_530 *out, bool is_64bit) { - size_t size = bin_size_530(is_64bit); - ut8 buf[BIN_SIZE_MAX]; - if (!rz_io_read_at_mapped(io, addr, buf, size)) { - return false; - } - RzBuffer *b = rz_buf_new_with_bytes(buf, size); - if (!b) { - return false; - } - ut64 offset; - bool ret; - if (is_64bit) { - offset = BIN_SLABCUR_OFFSET_64; - ret = rz_buf_read_le64_offset(b, &offset, &out->slabcur); - } else { - offset = BIN_SLABCUR_OFFSET_32; - ut32 slabcur; - ret = rz_buf_read_le32_offset(b, &offset, &slabcur); - if (ret) { - out->slabcur = slabcur; - } - } - rz_buf_free(b); - return ret; -} - -static inline bool read_and_parse_arena_t_530(RzIO *io, ut64 addr, arena_t_530 *out, bool is_64bit) { - size_t size = arena_size_530(is_64bit); - ut8 *buf = malloc(size); +static inline bool read_and_parse_edata_t_530(RzIO *io, ut64 addr, edata_t_530 *out, + const RzJemallocConfig530 *config) { + ut8 *buf = RZ_NEWS0(ut8, config->edata_size); if (!buf) { return false; } - if (!rz_io_read_at_mapped(io, addr, buf, size)) { + if (!rz_io_read_at_mapped(io, addr, buf, config->edata_size)) { free(buf); return false; } - RzBuffer *b = rz_buf_new_with_bytes(buf, size); - free(buf); + RzBuffer *b = rz_buf_new_with_pointers(buf, config->edata_size, true); if (!b) { + free(buf); return false; } ut64 offset = 0; bool ret = false; + if (!rz_buf_read_le64_offset(b, &offset, &out->e_bits)) { + goto cleanup; + } + + if (config->ptr_size == 8) { + if (!rz_buf_read_le64_offset(b, &offset, &out->e_addr) || + !rz_buf_read_le64_offset(b, &offset, &out->e_size_esn) || + !rz_buf_read_le64_offset(b, &offset, &out->e_ps) || + !rz_buf_read_le64_offset(b, &offset, &out->e_sn)) { + goto cleanup; + } + } else { + ut32 e_addr, size_esn, ps; + if (!rz_buf_read_le32_offset(b, &offset, &e_addr) || + !rz_buf_read_le32_offset(b, &offset, &size_esn) || + !rz_buf_read_le32_offset(b, &offset, &ps) || + !rz_buf_read_le64_offset(b, &offset, &out->e_sn)) { + goto cleanup; + } + out->e_addr = e_addr; + out->e_size_esn = size_esn; + out->e_ps = ps; + } + ret = true; +cleanup: + rz_buf_free(b); + return ret; +} + +static inline bool read_and_parse_bin_info_t_530(RzIO *io, ut64 addr, bin_info_t_530 *out, + const RzJemallocConfig530 *config) { + ut8 *buf = RZ_NEWS0(ut8, config->bin_info_size); + if (!buf) { + return false; + } + if (!rz_io_read_at_mapped(io, addr, buf, config->bin_info_size)) { + free(buf); + return false; + } + RzBuffer *b = rz_buf_new_with_pointers(buf, config->bin_info_size, true); + if (!b) { + free(buf); + return false; + } + ut64 offset = 0; + bool ret = false; + + if (config->ptr_size == 8) { + if (!rz_buf_read_le64_offset(b, &offset, &out->reg_size) || + !rz_buf_read_le64_offset(b, &offset, &out->slab_size) || + !rz_buf_read_le32_offset(b, &offset, &out->nregs) || + !rz_buf_read_le32_offset(b, &offset, &out->n_shards)) { + goto cleanup; + } + + if (config->bitmap_use_tree) { + // Tree format: nbits + nlevels + levels[] + if (!rz_buf_read_le64_offset(b, &offset, &out->bitmap_info.nbits) || + !rz_buf_read_le32_offset(b, &offset, &out->bitmap_info.nlevels)) { + goto cleanup; + } + out->bitmap_info.ngroups = 0; + // Skip levels - we don't need them for basic parsing + for (ut32 i = 0; i < config->bitmap_max_levels + 1 && i < BITMAP_MAX_LEVELS_530 + 1; i++) { + out->bitmap_info.levels[i] = 0; + } + } else { + // Non-tree format: nbits + ngroups + if (!rz_buf_read_le64_offset(b, &offset, &out->bitmap_info.nbits) || + !rz_buf_read_le64_offset(b, &offset, &out->bitmap_info.ngroups)) { + goto cleanup; + } + out->bitmap_info.nlevels = 0; + } + } else { + ut32 reg_size, slab_size; + if (!rz_buf_read_le32_offset(b, &offset, ®_size) || + !rz_buf_read_le32_offset(b, &offset, &slab_size) || + !rz_buf_read_le32_offset(b, &offset, &out->nregs) || + !rz_buf_read_le32_offset(b, &offset, &out->n_shards)) { + goto cleanup; + } + out->reg_size = reg_size; + out->slab_size = slab_size; + + if (config->bitmap_use_tree) { + // Tree format for 32-bit + ut32 nbits; + if (!rz_buf_read_le32_offset(b, &offset, &nbits) || + !rz_buf_read_le32_offset(b, &offset, &out->bitmap_info.nlevels)) { + goto cleanup; + } + out->bitmap_info.nbits = nbits; + out->bitmap_info.ngroups = 0; + for (ut32 i = 0; i < config->bitmap_max_levels + 1 && i < BITMAP_MAX_LEVELS_530 + 1; i++) { + ut32 level; + if (!rz_buf_read_le32_offset(b, &offset, &level)) { + goto cleanup; + } + out->bitmap_info.levels[i] = level; + } + } else { + // Non-tree format for 32-bit (unlikely but handle it) + ut32 nbits, ngroups; + if (!rz_buf_read_le32_offset(b, &offset, &nbits) || + !rz_buf_read_le32_offset(b, &offset, &ngroups)) { + goto cleanup; + } + out->bitmap_info.nbits = nbits; + out->bitmap_info.ngroups = ngroups; + out->bitmap_info.nlevels = 0; + } + } + ret = true; +cleanup: + rz_buf_free(b); + return ret; +} + +static inline bool read_and_parse_bin_t_530(RzIO *io, ut64 addr, bin_t_530 *out, + const RzJemallocConfig530 *config) { + ut8 *buf = RZ_NEWS0(ut8, config->bin_size); + if (!buf) { + return false; + } + if (!rz_io_read_at_mapped(io, addr, buf, config->bin_size)) { + free(buf); + return false; + } + RzBuffer *b = rz_buf_new_with_pointers(buf, config->bin_size, true); + if (!b) { + free(buf); + return false; + } + ut64 offset = config->bin_offsets.slabcur; + bool ret = false; + if (config->ptr_size == 8) { + if (!rz_buf_read_le64_offset(b, &offset, &out->slabcur)) { + goto cleanup; + } + } else { + ut32 val; + if (!rz_buf_read_le32_offset(b, &offset, &val)) { + goto cleanup; + } + out->slabcur = val; + } + ret = true; +cleanup: + rz_buf_free(b); + return ret; +} + +static inline bool read_and_parse_arena_t_530(RzIO *io, ut64 addr, arena_t_530 *out, + const RzJemallocConfig530 *config) { + ut8 *buf = RZ_NEWS0(ut8, config->arena_size); + if (!buf) { + return false; + } + if (!rz_io_read_at_mapped(io, addr, buf, config->arena_size)) { + free(buf); + return false; + } + RzBuffer *b = rz_buf_new_with_pointers(buf, config->arena_size, true); + if (!b) { + free(buf); + return false; + } + ut64 offset = 0; + bool ret = false; + + // Read header fields sequentially if (!rz_buf_read_le32_offset(b, &offset, &out->nthreads[0]) || !rz_buf_read_le32_offset(b, &offset, &out->nthreads[1]) || !rz_buf_read_le32_offset(b, &offset, &out->binshard_next)) { - rz_buf_free(b); - return ret; + goto cleanup; } - if (is_64bit) { - offset = ARENA_LAST_THD_OFFSET_64; - if (rz_buf_read_le64_offset(b, &offset, &out->last_thd)) { - offset = ARENA_DSS_PREC_OFFSET_64; - if (rz_buf_read_le32_offset(b, &offset, &out->dss_prec)) { - offset = ARENA_IND_OFFSET_64; - if (rz_buf_read_le32_offset(b, &offset, &out->ind)) { - offset = ARENA_BASE_OFFSET_64; - if (rz_buf_read_le64_offset(b, &offset, &out->base) && - rz_buf_read_le64_offset(b, &offset, &out->create_time_ns)) { - out->stats_addr = addr + ARENA_STATS_OFFSET_64; - out->tcache_ql_addr = addr + ARENA_TCACHE_QL_OFFSET_64; - out->cache_bin_array_descriptor_ql_addr = addr + ARENA_CACHE_BIN_ARR_OFFSET_64; - out->tcache_ql_mtx_addr = addr + ARENA_TCACHE_QL_MTX_OFFSET_64; - out->large_addr = addr + ARENA_LARGE_OFFSET_64; - out->large_mtx_addr = addr + ARENA_LARGE_MTX_OFFSET_64; - out->pa_shard_addr = addr + ARENA_PA_SHARD_OFFSET_64; - out->bins_addr = addr + ARENA_BINS_OFFSET_64; - ret = true; - } - } - } + const RzJemallocArenaOffsets530 *ao = &config->arena_offsets; + + if (config->ptr_size == 8) { + if (((offset = ao->last_thd), !rz_buf_read_le64_offset(b, &offset, &out->last_thd)) || + ((offset = ao->dss_prec), !rz_buf_read_le32_offset(b, &offset, &out->dss_prec)) || + ((offset = ao->ind), !rz_buf_read_le32_offset(b, &offset, &out->ind)) || + ((offset = ao->base), !rz_buf_read_le64_offset(b, &offset, &out->base)) || + !rz_buf_read_le64_offset(b, &offset, &out->create_time_ns)) { + goto cleanup; } } else { - ut32 last_thd; - if (rz_buf_read_le32_offset(b, &offset, &last_thd)) { - out->last_thd = last_thd; - offset = ARENA_DSS_PREC_OFFSET_32; - if (rz_buf_read_le32_offset(b, &offset, &out->dss_prec)) { - offset = ARENA_IND_OFFSET_32; - ut32 base; - if (rz_buf_read_le32_offset(b, &offset, &out->ind) && - rz_buf_read_le32_offset(b, &offset, &base)) { - out->base = base; - if (rz_buf_read_le64_offset(b, &offset, &out->create_time_ns)) { - out->stats_addr = addr + ARENA_STATS_OFFSET_32; - out->tcache_ql_addr = addr + ARENA_TCACHE_QL_OFFSET_32; - out->cache_bin_array_descriptor_ql_addr = addr + ARENA_CACHE_BIN_ARR_OFFSET_32; - out->tcache_ql_mtx_addr = addr + ARENA_TCACHE_QL_MTX_OFFSET_32; - out->large_addr = addr + ARENA_LARGE_OFFSET_32; - out->large_mtx_addr = addr + ARENA_LARGE_MTX_OFFSET_32; - out->pa_shard_addr = addr + ARENA_PA_SHARD_OFFSET_32; - out->bins_addr = addr + ARENA_BINS_OFFSET_32; - ret = true; - } - } - } + ut32 val; + if (((offset = ao->last_thd), !rz_buf_read_le32_offset(b, &offset, &val))) { + goto cleanup; + } + out->last_thd = val; + if (((offset = ao->dss_prec), !rz_buf_read_le32_offset(b, &offset, &out->dss_prec)) || + ((offset = ao->ind), !rz_buf_read_le32_offset(b, &offset, &out->ind)) || + ((offset = ao->base), !rz_buf_read_le32_offset(b, &offset, &val))) { + goto cleanup; + } + out->base = val; + if (!rz_buf_read_le64_offset(b, &offset, &out->create_time_ns)) { + goto cleanup; } } + out->stats_addr = addr + ao->stats; + out->tcache_ql_addr = addr + ao->tcache_ql; + out->cache_bin_array_descriptor_ql_addr = addr + ao->cache_bin_arr; + out->tcache_ql_mtx_addr = addr + ao->tcache_ql_mtx; + out->large_addr = addr + ao->large; + out->large_mtx_addr = addr + ao->large_mtx; + out->pa_shard_addr = addr + ao->pa_shard; + out->bins_addr = addr + ao->bins; + + ret = true; +cleanup: rz_buf_free(b); return ret; } @@ -530,21 +991,13 @@ static inline ut64 rtree_leaf_elm_bits_edata_get_530(ut64 bits) { return ptr; } -static inline void rtree_params_530(bool is_64bit, ut32 *lg_page, ut32 *rtree_nsb, - ut32 *bits_per_level, ut32 *max_subkeys, - ut64 *root_offset) { - *lg_page = LG_PAGE_530; - if (is_64bit) { - *rtree_nsb = RTREE_NSB_64; - *bits_per_level = RTREE_BITS_PER_LEVEL_64; - *max_subkeys = RTREE_MAX_SUBKEYS_64; - *root_offset = RTREE_ROOT_OFFSET_64; - } else { - *rtree_nsb = RTREE_NSB_32; - *bits_per_level = RTREE_BITS_PER_LEVEL_32; - *max_subkeys = RTREE_MAX_SUBKEYS_32; - *root_offset = RTREE_ROOT_OFFSET_32; - } +static inline void rtree_params_530(const RzJemallocConfig530 *config, ut32 *lg_page, ut32 *rtree_nsb, + ut32 *bits_per_level, ut32 *max_subkeys, ut64 *root_offset) { + *lg_page = config->lg_page; + *rtree_nsb = config->rtree_nsb; + *bits_per_level = config->rtree_bits_per_level; + *max_subkeys = 1U << config->rtree_bits_per_level; + *root_offset = config->rtree_offsets.root; } #endif // RZ_JEMALLOC_530_H diff --git a/subprojects/rzheap/rz_jemalloc/jemalloc_arch.h b/subprojects/rzheap/rz_jemalloc/jemalloc_arch.h new file mode 100644 index 0000000000..09a7708926 --- /dev/null +++ b/subprojects/rzheap/rz_jemalloc/jemalloc_arch.h @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2026 jemalloc +// SPDX-FileCopyrightText: 2026 bubblepipe +// SPDX-License-Identifier: LGPL-3.0-only + +#ifndef RZ_JEMALLOC_ARCH_H +#define RZ_JEMALLOC_ARCH_H + +#include + +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 diff --git a/test/db/archos/linux-arm64/dbg_dmx b/test/db/archos/linux-arm64/dbg_dmx new file mode 100644 index 0000000000..2cf529f138 --- /dev/null +++ b/test/db/archos/linux-arm64/dbg_dmx @@ -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=<