Add support for dm commands in core dump mode. (#5930)

* add support for relative path core dump

---------

Co-authored-by: NOT XVilka <notxvilka@proton.me>
This commit is contained in:
bubblepipe 2026-03-17 17:01:20 +07:00 committed by GitHub
parent 33d0dcbeb2
commit 21d4084af0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 940 additions and 172 deletions

View file

@ -10,6 +10,55 @@
static bool core_file_do_load_for_debug(RzCore *r, ut64 baseaddr, const char *filenameuri);
static bool core_file_do_load_for_io_plugin(RzCore *r, ut64 baseaddr, ut64 loadaddr);
/**
* \brief Check whether the current file is a core dump
* \param core RzCore instance
* \return true if the current file is a core dump, false otherwise
*/
RZ_IPI bool rz_core_is_core_dump(RzCore *core) {
if (!core || !core->io || !core->bin) {
return false;
}
int cur_fd = rz_io_fd_get_current(core->io);
RzBinFile *bf = rz_bin_file_find_by_fd(core->bin, cur_fd);
if (!bf) {
// Fallback for cases where there is no binfile bound to the current fd.
bf = rz_bin_cur(core->bin);
}
RzBinPlugin *plugin = bf ? rz_bin_file_cur_plugin(bf) : NULL;
return plugin && plugin->file_type && plugin->file_type(bf) == RZ_BIN_TYPE_CORE;
}
/**
* \brief Strip `[fmv]map.` prefix of a given IOMap name
* \param map RzIOMap instance
* \return the name without the prefix or the same name if no prefix is found.
* NULL if map or map->name is NULL.
*/
RZ_IPI const char *rz_core_io_map_strip_prefix(const RzIOMap *map) {
if (!map || !map->name) {
return NULL;
}
const char *name = map->name;
if (rz_str_startswith(name, "fmap.") ||
rz_str_startswith(name, "mmap.") ||
rz_str_startswith(name, "vmap.")) {
return name + 5;
}
return NULL;
}
RZ_IPI const char *rz_core_io_map_file_path(const RzIOMap *map) {
const char *name = rz_core_io_map_strip_prefix(map);
return (name && *name == '/') ? name : NULL;
}
RZ_IPI const char *rz_core_io_map_file_path_or_relative(const RzIOMap *map) {
const char *name = rz_core_io_map_strip_prefix(map);
// Both "/abs/path" and "rel/path" contain a '/'; LOAD0, [stack] etc. do not.
return (name && strchr(name, '/')) ? name : NULL;
}
static RzCoreFile *core_file_new(RzCore *core, int fd) {
RzCoreFile *r = RZ_NEW0(RzCoreFile);
if (!r) {

View file

@ -8,6 +8,8 @@
#include <rz_core.h>
#include <rz_debug.h>
#include <sdb.h>
#include <cmd_descs.h>
#define TN_KEY_LEN 32
#define TN_KEY_FMT "%" PFMT64u
@ -515,64 +517,118 @@ static int dump_maps(RzCore *core, int perm, const char *filename) {
RzListIter *iter;
rz_debug_map_sync(core->dbg); // update process memory maps
ut64 addr = core->offset;
int do_dump = false;
int ret = !rz_list_empty(core->dbg->maps);
rz_list_foreach (core->dbg->maps, iter, map) {
do_dump = false;
if (perm == -1) {
if (addr >= map->addr && addr < map->addr_end) {
do_dump = true;
if (addr < map->addr || addr >= map->addr_end) {
continue;
}
} else if (perm == 0) {
do_dump = true;
} else if (perm == (map->perm & perm)) {
do_dump = true;
} else if (perm != 0 && perm != (map->perm & perm)) {
continue;
}
if (do_dump) {
ut8 *buf = malloc(map->size);
// TODO: use mmap here. we need a portable implementation
if (!buf) {
RZ_LOG_ERROR("core: Cannot allocate 0x%08" PFMT64x " bytes\n", map->size);
free(buf);
/// XXX: TODO: read by blocks!!1
continue;
}
if (map->size > MAX_MAP_SIZE) {
RZ_LOG_ERROR("core: map size is too big to be dumped (0x%08" PFMT64x " > 0x%08x)\n", map->addr, MAX_MAP_SIZE);
free(buf);
continue;
}
rz_io_read_at_mapped(core->io, map->addr, buf, map->size);
char *file = filename
? rz_str_dup(filename)
: rz_str_newf("0x%08" PFMT64x "-0x%08" PFMT64x "-%s.dmp",
map->addr, map->addr_end, rz_str_rwx_i(map->perm));
if (!rz_file_dump(file, buf, map->size, 0)) {
RZ_LOG_ERROR("core: Cannot write '%s'\n", file);
ret = 0;
} else {
RZ_LOG_WARN("core: Dumped %d byte(s) into %s\n", (int)map->size, file);
}
free(file);
ut8 *buf = RZ_NEWS(ut8, map->size);
// TODO: use mmap here. we need a portable implementation
if (!buf) {
RZ_LOG_ERROR("core: Cannot allocate 0x%08" PFMT64x " bytes\n", map->size);
free(buf);
/// XXX: TODO: read by blocks!!1
continue;
}
if (map->size > MAX_MAP_SIZE) {
RZ_LOG_ERROR("core: map size is too big to be dumped (0x%08" PFMT64x " > 0x%08x)\n", map->addr, MAX_MAP_SIZE);
free(buf);
continue;
}
rz_io_read_at_mapped(core->io, map->addr, buf, map->size);
char *file = filename
? rz_str_dup(filename)
: rz_str_newf("0x%08" PFMT64x "-0x%08" PFMT64x "-%s.dmp",
map->addr, map->addr_end, rz_str_rwx_i(map->perm));
if (!rz_file_dump(file, buf, map->size, 0)) {
RZ_LOG_ERROR("core: Cannot write '%s'\n", file);
ret = 0;
} else {
RZ_LOG_WARN("core: Dumped %d byte(s) into %s\n", (int)map->size, file);
}
free(file);
free(buf);
}
// eprintf ("No debug region found here\n");
return ret;
}
static void cmd_debug_current_modules(RzCore *core, RzOutputMode mode) { // "dmm"
#define MAX_MAP_SIZE (1024 * 1024 * 512)
static int dump_io_maps(RzCore *core, int perm, const char *filename) {
RzPVector *maps = rz_io_maps(core->io);
ut64 addr = core->offset;
int ret = !rz_pvector_empty(maps);
void **it;
rz_pvector_foreach (maps, it) {
RzIOMap *map = *it;
ut64 map_addr = map->itv.addr;
ut64 map_size = map->itv.size;
ut64 map_end = map_addr + map_size;
if (perm == -1) {
if (addr < map_addr || addr >= map_end) {
continue;
}
} else if (perm != 0 && perm != (map->perm & perm)) {
continue;
}
ut8 *buf = RZ_NEWS(ut8, map_size);
if (!buf) {
RZ_LOG_ERROR("core: Cannot allocate 0x%08" PFMT64x " bytes\n", map_size);
continue;
}
if (map_size > MAX_MAP_SIZE) {
RZ_LOG_ERROR("core: map size is too big to be dumped (0x%08" PFMT64x " > 0x%08x)\n", map_addr, MAX_MAP_SIZE);
free(buf);
continue;
}
rz_io_read_at_mapped(core->io, map_addr, buf, map_size);
char *file = filename
? rz_str_dup(filename)
: rz_str_newf("0x%08" PFMT64x "-0x%08" PFMT64x "-%s.dmp",
map_addr, map_end, rz_str_rwx_i(map->perm));
if (!rz_file_dump(file, buf, map_size, 0)) {
RZ_LOG_ERROR("core: Cannot write '%s'\n", file);
ret = 0;
} else {
RZ_LOG_WARN("core: Dumped %d byte(s) into %s\n", (int)map_size, file);
}
free(file);
free(buf);
}
return ret;
}
static void cmd_debug_current_modules(RzCore *core, RzCmdStateOutput *state) { // "dmm"
ut64 addr = core->offset;
RzDebugMap *map;
RzList *list;
RzListIter *iter;
PJ *pj = state->d.pj;
RzOutputMode mode = state->mode;
rz_cmd_state_output_array_start(state);
list = rz_debug_modules_list(core->dbg);
rz_list_foreach (list, iter, map) {
if (!(addr >= map->addr && addr < map->addr_end)) {
continue;
}
rz_cons_printf("0x%08" PFMT64x " 0x%08" PFMT64x " %s\n", map->addr, map->addr_end, map->file);
if (mode == RZ_OUTPUT_MODE_STANDARD) {
rz_cons_printf("0x%08" PFMT64x " 0x%08" PFMT64x " %s\n", map->addr, map->addr_end, map->file);
} else if (mode == RZ_OUTPUT_MODE_JSON) {
pj_o(pj);
pj_kn(pj, "addr", map->addr);
pj_kn(pj, "addr_end", map->addr_end);
pj_ks(pj, "file", map->file);
pj_end(pj);
}
}
rz_cmd_state_output_array_end(state);
rz_list_free(list);
}
@ -601,6 +657,91 @@ static void cmd_debug_modules(RzCore *core, RzCmdStateOutput *state) { // "dmm"
rz_list_free(list);
}
static RZ_OWN RzPVector /*<RzIOMap *>*/ *io_map_list(RzCore *core) { // "dmm"
RzPVector *maps = rz_io_maps(core->io);
RzPVector *ret = rz_pvector_new(NULL);
if (!ret) {
return NULL;
}
char *lastname = NULL;
void **it;
rz_pvector_foreach (maps, it) {
RzIOMap *map = *it;
const char *file = rz_core_io_map_file_path_or_relative(map);
if (!file) {
continue;
}
if (!RZ_STR_EQ(lastname, file)) {
rz_pvector_push(ret, map);
free(lastname);
lastname = rz_str_dup(file);
}
}
free(lastname);
return ret;
}
static void cmd_io_current_modules(RzCore *core, RzCmdStateOutput *state) { // "dmm"
ut64 addr = core->offset;
RzPVector *maps = io_map_list(core);
void **it;
PJ *pj = state->d.pj;
RzOutputMode mode = state->mode;
rz_cmd_state_output_array_start(state);
rz_pvector_foreach (maps, it) {
RzIOMap *map = *it;
ut64 map_addr = map->itv.addr;
ut64 map_end = map_addr + map->itv.size;
if (!(addr >= map_addr && addr < map_end)) {
continue;
}
const char *file = rz_core_io_map_file_path_or_relative(map);
if (!file) {
file = map->name;
}
if (mode == RZ_OUTPUT_MODE_STANDARD) {
rz_cons_printf("0x%08" PFMT64x " 0x%08" PFMT64x " %s\n", map_addr, map_end, file);
} else if (mode == RZ_OUTPUT_MODE_JSON) {
pj_o(pj);
pj_kn(pj, "addr", map_addr);
pj_kn(pj, "addr_end", map_end);
pj_ks(pj, "file", file);
pj_end(pj);
}
}
rz_cmd_state_output_array_end(state);
rz_pvector_free(maps);
}
static void cmd_io_modules(RzCore *core, RzCmdStateOutput *state) { // "dmm"
RzPVector *maps;
void **it;
PJ *pj = state->d.pj;
RzOutputMode mode = state->mode;
rz_cmd_state_output_array_start(state);
maps = io_map_list(core);
rz_pvector_foreach (maps, it) {
RzIOMap *map = *it;
const char *file = rz_core_io_map_file_path_or_relative(map);
if (!file) {
file = map->name;
}
if (mode == RZ_OUTPUT_MODE_STANDARD) {
rz_cons_printf("0x%08" PFMT64x " 0x%08" PFMT64x " %s\n", map->itv.addr, map->itv.addr + map->itv.size, file);
} else if (mode == RZ_OUTPUT_MODE_JSON) {
/* Escape backslashes (e.g. for Windows). */
pj_o(pj);
pj_kn(pj, "addr", map->itv.addr);
pj_kn(pj, "addr_end", map->itv.addr + map->itv.size);
pj_ks(pj, "name", file);
pj_end(pj);
}
}
rz_cmd_state_output_array_end(state);
rz_pvector_free(maps);
}
static ut64 addroflib(RzCore *core, const char *libname) {
RzListIter *iter;
RzDebugMap *map;
@ -642,6 +783,42 @@ static RzDebugMap *get_closest_map(RzCore *core, ut64 addr) {
return NULL;
}
static RzIOMap *get_io_map_from_lib_name(RzCore *core, const char *lib_name) {
if (!core || !lib_name) {
return NULL;
}
const char *basename = rz_file_basename(lib_name);
if (!basename) {
return NULL;
}
RzIOMap *result = NULL;
RzPVector *maps = io_map_list(core);
void **it;
rz_pvector_foreach (maps, it) {
RzIOMap *map = *it;
const char *file = rz_core_io_map_file_path_or_relative(map);
if (file && strstr(rz_file_basename(file), basename)) {
result = map;
break;
}
}
rz_pvector_free(maps);
if (result) {
return result;
}
// Fall back to all IO maps
maps = rz_io_maps(core->io);
rz_pvector_foreach (maps, it) {
RzIOMap *map = *it;
const char *file = rz_core_io_map_file_path_or_relative(map);
if (file && strstr(rz_file_basename(file), basename)) {
return map;
}
}
RZ_LOG_ERROR("Unknown library '%s' not found\n", lib_name);
return NULL;
}
/**
* \brief Hacky way to get the binary information of a file.
* It opens \p file into the current core->bin (backing up the previous pointer)
@ -679,14 +856,22 @@ static bool get_bin_info(RzCore *core, const char *file, ut64 baseaddr,
// dm
RZ_IPI RzCmdStatus rz_cmd_debug_list_maps_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
// dm is oml when file is a core dump
if (rz_core_is_core_dump(core)) {
return rz_open_maps_list_handler(core, argc, argv, state);
}
CMD_CHECK_DEBUG_DEAD(core);
rz_debug_map_sync(core->dbg); // update process memory maps
rz_core_debug_map_print(core, core->offset, state);
return RZ_CMD_STATUS_OK;
}
// dma
// dm+
RZ_IPI RzCmdStatus rz_cmd_debug_allocate_maps_handler(RzCore *core, int argc, const char **argv) {
if (rz_core_is_core_dump(core)) {
RZ_LOG_ERROR("Cannot allocate maps in core dump mode\n");
return RZ_CMD_STATUS_ERROR;
}
CMD_CHECK_DEBUG_DEAD(core);
ut64 addr = core->offset;
int size = (int)rz_num_math(core->num, argv[1]);
@ -696,20 +881,32 @@ RZ_IPI RzCmdStatus rz_cmd_debug_allocate_maps_handler(RzCore *core, int argc, co
// dmm
RZ_IPI RzCmdStatus rz_cmd_debug_modules_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
if (rz_core_is_core_dump(core)) {
cmd_io_modules(core, state);
return RZ_CMD_STATUS_OK;
}
CMD_CHECK_DEBUG_DEAD(core);
cmd_debug_modules(core, state);
return RZ_CMD_STATUS_OK;
}
// dmm.
RZ_IPI RzCmdStatus rz_cmd_debug_current_modules_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
RZ_IPI RzCmdStatus rz_cmd_debug_current_modules_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
if (rz_core_is_core_dump(core)) {
cmd_io_current_modules(core, state);
return RZ_CMD_STATUS_OK;
}
CMD_CHECK_DEBUG_DEAD(core);
cmd_debug_current_modules(core, mode);
cmd_debug_current_modules(core, state);
return RZ_CMD_STATUS_OK;
}
// dm-
RZ_IPI RzCmdStatus rz_cmd_debug_deallocate_map_handler(RzCore *core, int argc, const char **argv) {
if (rz_core_is_core_dump(core)) {
RZ_LOG_ERROR("Cannot deallocate maps in core dump mode\n");
return RZ_CMD_STATUS_ERROR;
}
CMD_CHECK_DEBUG_DEAD(core);
RzListIter *iter;
RzDebugMap *map;
@ -727,6 +924,10 @@ RZ_IPI RzCmdStatus rz_cmd_debug_deallocate_map_handler(RzCore *core, int argc, c
// dm=
RZ_IPI RzCmdStatus rz_cmd_debug_list_maps_ascii_handler(RzCore *core, int argc, const char **argv) {
// dm= is oml= when file is a core dump
if (rz_core_is_core_dump(core)) {
return rz_open_maps_list_ascii_handler(core, argc, argv);
}
CMD_CHECK_DEBUG_DEAD(core);
rz_debug_map_sync(core->dbg);
rz_debug_map_list_visual(core->dbg, core->offset, argv[0] + 2,
@ -735,21 +936,33 @@ RZ_IPI RzCmdStatus rz_cmd_debug_list_maps_ascii_handler(RzCore *core, int argc,
}
// dm.
RZ_IPI RzCmdStatus rz_cmd_debug_map_current_handler(RzCore *core, int argc, const char **argv) {
RZ_IPI RzCmdStatus rz_cmd_debug_map_current_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
// dm. is oml. when file is a core dump
if (rz_core_is_core_dump(core)) {
return rz_open_maps_list_cur_handler(core, argc, argv, state);
}
CMD_CHECK_DEBUG_DEAD(core);
ut64 addr = core->offset;
// RZ_OUTPUT_MODE_LONG is workaround for '.'
RzCmdStateOutput state = { 0 };
rz_cmd_state_output_init(&state, RZ_OUTPUT_MODE_LONG, core);
rz_core_debug_map_print(core, addr, &state);
rz_cmd_state_output_print(&state);
rz_cmd_state_output_fini(&state);
rz_cmd_state_output_init(state, RZ_OUTPUT_MODE_LONG, core);
rz_core_debug_map_print(core, addr, state);
rz_cmd_state_output_print(state);
rz_cmd_state_output_fini(state);
rz_cons_flush();
return RZ_CMD_STATUS_OK;
}
// dmd
RZ_IPI RzCmdStatus rz_cmd_debug_dump_maps_handler(RzCore *core, int argc, const char **argv) {
if (rz_core_is_core_dump(core)) {
if (argc == 2) {
dump_io_maps(core, -1, argv[1]);
} else if (argc == 1) {
dump_io_maps(core, -1, NULL);
}
return RZ_CMD_STATUS_OK;
}
CMD_CHECK_DEBUG_DEAD(core);
if (argc == 2) {
dump_maps(core, -1, argv[1]);
@ -761,6 +974,10 @@ RZ_IPI RzCmdStatus rz_cmd_debug_dump_maps_handler(RzCore *core, int argc, const
// dmda
RZ_IPI RzCmdStatus rz_cmd_debug_dump_maps_all_handler(RzCore *core, int argc, const char **argv) {
if (rz_core_is_core_dump(core)) {
dump_io_maps(core, 0, NULL);
return RZ_CMD_STATUS_OK;
}
CMD_CHECK_DEBUG_DEAD(core);
dump_maps(core, 0, NULL);
return RZ_CMD_STATUS_OK;
@ -768,6 +985,10 @@ RZ_IPI RzCmdStatus rz_cmd_debug_dump_maps_all_handler(RzCore *core, int argc, co
// dmdw
RZ_IPI RzCmdStatus rz_cmd_debug_dump_maps_writable_handler(RzCore *core, int argc, const char **argv) {
if (rz_core_is_core_dump(core)) {
dump_io_maps(core, RZ_PERM_RW, NULL);
return RZ_CMD_STATUS_OK;
}
CMD_CHECK_DEBUG_DEAD(core);
dump_maps(core, RZ_PERM_RW, NULL);
return RZ_CMD_STATUS_OK;
@ -789,21 +1010,41 @@ static RzDebugMap *get_debug_map_from_lib_name(RzCore *core, const char *lib_nam
}
RZ_IPI RzCmdStatus rz_cmd_debug_dmi_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
CMD_CHECK_DEBUG_DEAD(core);
if (argc == 1) {
// Effectively an alias for 'dmm'
if (rz_core_is_core_dump(core)) {
cmd_io_modules(core, state);
return RZ_CMD_STATUS_OK;
}
CMD_CHECK_DEBUG_DEAD(core);
cmd_debug_modules(core, state);
rz_cmd_state_output_print(state);
rz_cons_flush();
return RZ_CMD_STATUS_OK;
}
const char *lib_name = argc >= 2 ? argv[1] : NULL;
const char *sym_name = argc == 3 ? argv[2] : NULL;
RzCoreBinFilter filter = { .offset = UT64_MAX, .name = sym_name };
int action = RZ_CORE_BIN_ACC_SYMBOLS;
if (rz_core_is_core_dump(core)) {
RzIOMap *map = get_io_map_from_lib_name(core, lib_name);
if (!map) {
RZ_LOG_ERROR("Failed to get map from %s\n", lib_name);
return RZ_CMD_STATUS_ERROR;
}
const char *file = rz_core_io_map_file_path_or_relative(map);
if (!file) {
file = map->name;
}
if (!get_bin_info(core, file, map->itv.addr, state, action, &filter)) {
RZ_LOG_ERROR("Failed to get binary information for map: '%s' in file: '%s'\n", map->name, file);
return RZ_CMD_STATUS_ERROR;
}
return RZ_CMD_STATUS_OK;
}
CMD_CHECK_DEBUG_DEAD(core);
RzDebugMap *map = get_debug_map_from_lib_name(core, lib_name);
if (!map) {
RZ_LOG_ERROR("Failed to get map from %s\n", lib_name);
@ -818,22 +1059,48 @@ RZ_IPI RzCmdStatus rz_cmd_debug_dmi_handler(RzCore *core, int argc, const char *
}
RZ_IPI RzCmdStatus rz_cmd_debug_dmi_all_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state) {
CMD_CHECK_DEBUG_DEAD(core);
if (argc == 1) {
// Effectively an alias for 'dmm'
if (rz_core_is_core_dump(core)) {
cmd_io_modules(core, state);
rz_cmd_state_output_print(state);
rz_cons_flush();
return RZ_CMD_STATUS_OK;
}
CMD_CHECK_DEBUG_DEAD(core);
cmd_debug_modules(core, state);
rz_cmd_state_output_print(state);
rz_cons_flush();
return RZ_CMD_STATUS_OK;
}
const char *lib_name = argv[1];
RzCoreBinFilter filter = { .offset = UT64_MAX, .name = NULL };
int action = RZ_CORE_BIN_ACC_ALL & ~RZ_CORE_BIN_ACC_INFO;
if (rz_core_is_core_dump(core)) {
RzIOMap *map = get_io_map_from_lib_name(core, lib_name);
if (!map) {
RZ_LOG_ERROR("Failed to get map from %s\n", lib_name);
return RZ_CMD_STATUS_ERROR;
}
const char *file = rz_core_io_map_file_path_or_relative(map);
if (!file) {
file = map->name;
}
if (!get_bin_info(core, file, map->itv.addr, state, action, &filter)) {
RZ_LOG_ERROR("Failed to get binary information for map: '%s' in file: '%s'\n", map->name, file);
return RZ_CMD_STATUS_ERROR;
}
return RZ_CMD_STATUS_OK;
}
CMD_CHECK_DEBUG_DEAD(core);
RzDebugMap *map = get_debug_map_from_lib_name(core, lib_name);
if (!map) {
RZ_LOG_ERROR("Failed to get map from %s\n", lib_name);
return RZ_CMD_STATUS_ERROR;
}
const char *file = map->file ? map->file : map->name;
RzCoreBinFilter filter = { .offset = UT64_MAX, .name = NULL };
int action = RZ_CORE_BIN_ACC_ALL & ~RZ_CORE_BIN_ACC_INFO;
if (!get_bin_info(core, file, map->addr, state, action, &filter)) {
RZ_LOG_ERROR("Failed to get binary information for map: '%s' in file: '%s'\n", map->name, file);
return RZ_CMD_STATUS_ERROR;
@ -886,6 +1153,10 @@ RZ_IPI RzCmdStatus rz_cmd_debug_dmi_closest_handler(RzCore *core, int argc, cons
// dmp
RZ_IPI RzCmdStatus rz_debug_memory_permission_handler(RzCore *core, int argc, const char **argv) {
if (rz_core_is_core_dump(core)) {
RZ_LOG_ERROR("Cannot change memory permissions in core dump mode\n");
return RZ_CMD_STATUS_ERROR;
}
CMD_CHECK_DEBUG_DEAD(core);
RzListIter *iter;
RzDebugMap *map;
@ -915,10 +1186,36 @@ RZ_IPI RzCmdStatus rz_debug_memory_permission_handler(RzCore *core, int argc, co
return RZ_CMD_STATUS_OK;
}
static void rz_cmd_debug_dmS_handler_printer(ut64 baddr, const char *file, const char *sectname, RzOutputMode mode) {
char *res;
char *name = rz_str_escape((char *)rz_file_basename(file));
char *filesc = rz_str_escape(file);
char *old_prefix = rz_sys_getenv("RZ_BIN_PREFIX");
rz_sys_setenv("RZ_BIN_PREFIX", name);
const char *json_flag = (mode == RZ_OUTPUT_MODE_JSON) ? " -j" : "";
if (sectname && mode != RZ_OUTPUT_MODE_JSON) {
char *sect = rz_str_escape(sectname);
res = rz_sys_cmd_strf("rz-bin%s -B 0x%08" PFMT64x " -S \"%s\" | grep \"%s\"", json_flag, baddr, filesc, sect);
free(sect);
} else {
res = rz_sys_cmd_strf("rz-bin%s -B 0x%08" PFMT64x " -S \"%s\"", json_flag, baddr, filesc);
}
if (res) {
rz_str_remove_char(res, '\r');
}
rz_sys_setenv("RZ_BIN_PREFIX", old_prefix);
free(old_prefix);
free(filesc);
if (res) {
rz_cons_println(res);
}
free(name);
free(res);
}
RZ_IPI RzCmdStatus rz_cmd_debug_dmS_handler(RzCore *core, int argc, const char **argv, RzOutputMode m) {
CMD_CHECK_DEBUG_DEAD(core);
RzListIter *iter;
RzDebugMap *map;
ut64 addr;
const char *libname = NULL, *sectname = NULL;
ut64 baddr = 0LL;
@ -937,6 +1234,35 @@ RZ_IPI RzCmdStatus rz_cmd_debug_dmS_handler(RzCore *core, int argc, const char *
libname = argv[1];
}
}
if (rz_core_is_core_dump(core)) {
RzPVector *maps = io_map_list(core);
void **it;
rz_pvector_foreach (maps, it) {
RzIOMap *map = *it;
ut64 map_addr = map->itv.addr;
ut64 map_end = map_addr + map->itv.size;
if ((!libname ||
(addr != UT64_MAX && (addr >= map_addr && addr < map_end)) ||
(libname != NULL && (strstr(map->name, libname))))) {
baddr = map_addr;
const char *file = rz_core_io_map_file_path_or_relative(map);
if (!file) {
file = map->name;
}
rz_cmd_debug_dmS_handler_printer(baddr, file, sectname, m);
if (libname || addr != UT64_MAX) { // only single match requested
break;
}
}
}
rz_pvector_free(maps);
return RZ_CMD_STATUS_OK;
}
CMD_CHECK_DEBUG_DEAD(core);
RzDebugMap *map;
RzListIter *iter;
rz_debug_map_sync(core->dbg); // update process memory maps
RzList *list = rz_debug_modules_list(core->dbg);
rz_list_foreach (list, iter, map) {
@ -944,22 +1270,8 @@ RZ_IPI RzCmdStatus rz_cmd_debug_dmS_handler(RzCore *core, int argc, const char *
(addr != UT64_MAX && (addr >= map->addr && addr < map->addr_end)) ||
(libname != NULL && (strstr(map->name, libname))))) {
baddr = map->addr;
char *res;
const char *file = map->file ? map->file : map->name;
char *name = rz_str_escape((char *)rz_file_basename(file));
char *filesc = rz_str_escape(file);
/* TODO: do not spawn. use RzBin API */
if (sectname) {
char *sect = rz_str_escape(sectname);
res = rz_sys_cmd_strf("env RZ_BIN_PREFIX=\"%s\" rz-bin -B 0x%08" PFMT64x " -S \"%s\" | grep \"%s\"", name, baddr, filesc, sect);
free(sect);
} else {
res = rz_sys_cmd_strf("env RZ_BIN_PREFIX=\"%s\" rz-bin -B 0x%08" PFMT64x " -S \"%s\"", name, baddr, filesc);
}
free(filesc);
rz_cons_println(res);
free(name);
free(res);
rz_cmd_debug_dmS_handler_printer(baddr, file, sectname, m);
if (libname || addr != UT64_MAX) { // only single match requested
break;
}
@ -970,6 +1282,10 @@ RZ_IPI RzCmdStatus rz_cmd_debug_dmS_handler(RzCore *core, int argc, const char *
// dml
RZ_IPI RzCmdStatus rz_cmd_debug_dml_handler(RzCore *core, int argc, const char **argv) {
if (rz_core_is_core_dump(core)) {
RZ_LOG_ERROR("Cannot load into memory in core dump mode\n");
return RZ_CMD_STATUS_ERROR;
}
CMD_CHECK_DEBUG_DEAD(core);
RzListIter *iter;
RzDebugMap *map;
@ -1001,6 +1317,10 @@ RZ_IPI RzCmdStatus rz_cmd_debug_dml_handler(RzCore *core, int argc, const char *
// dmL
RZ_IPI RzCmdStatus rz_cmd_debug_dmL_handler(RzCore *core, int argc, const char **argv) {
if (rz_core_is_core_dump(core)) {
RZ_LOG_ERROR("Cannot allocate maps in core dump mode\n");
return RZ_CMD_STATUS_ERROR;
}
CMD_CHECK_DEBUG_DEAD(core);
int size;
ut64 addr;
@ -1013,35 +1333,33 @@ RZ_IPI RzCmdStatus rz_cmd_debug_dmL_handler(RzCore *core, int argc, const char *
// "dmxa"
RZ_IPI RzCmdStatus rz_cmd_debug_heap_jemalloc_a_handler(RzCore *core, int argc, const char **argv) {
bool has_specified_arena = argc > 1 && RZ_STR_ISNOTEMPTY(argv[1]);
ut64 arena_addr = 0;
// Only check debug mode when no argument is provided (symbol resolution needed)
// With address arguments we can still work in static mode
if (!has_specified_arena) {
CMD_CHECK_DEBUG_DEAD(core);
} else if (!rz_num_is_valid_input(core->num, argv[1])) {
RZ_LOG_ERROR("Invalid arena address '%s'\n", argv[1]);
return RZ_CMD_STATUS_ERROR;
} else {
arena_addr = rz_num_math(core->num, argv[1]);
if (has_specified_arena) {
if (!rz_num_is_valid_input(core->num, argv[1])) {
RZ_LOG_ERROR("Invalid arena address '%s'\n", argv[1]);
return RZ_CMD_STATUS_ERROR;
}
ut64 arena_addr = rz_num_math(core->num, argv[1]);
return rz_heap_jemalloc_cmd_a(core, has_specified_arena, arena_addr);
}
return rz_heap_jemalloc_cmd_a(core, has_specified_arena, arena_addr);
if (!rz_core_is_core_dump(core)) {
CMD_CHECK_DEBUG_DEAD(core);
}
return rz_heap_jemalloc_cmd_a(core, has_specified_arena, 0);
}
// "dmxb"
RZ_IPI RzCmdStatus rz_cmd_debug_heap_jemalloc_b_handler(RzCore *core, int argc, const char **argv) {
bool has_specified_arena = argc > 1 && RZ_STR_ISNOTEMPTY(argv[1]);
bool has_bin_info = argc > 2 && RZ_STR_ISNOTEMPTY(argv[2]);
ut64 arena_addr = 0;
ut64 bin_info_addr = 0;
if (!has_specified_arena) {
CMD_CHECK_DEBUG_DEAD(core);
} else if (!has_bin_info) {
RZ_LOG_ERROR("Usage: dmxb <arena_addr> <bin_info_addr>\n");
return RZ_CMD_STATUS_ERROR;
} else {
if (has_specified_arena) {
ut64 arena_addr = 0;
ut64 bin_info_addr = 0;
if (!has_bin_info) {
return RZ_CMD_STATUS_ERROR;
}
if (!rz_num_is_valid_input(core->num, argv[1])) {
RZ_LOG_ERROR("Invalid arena address '%s'\n", argv[1]);
return RZ_CMD_STATUS_ERROR;
@ -1052,43 +1370,53 @@ RZ_IPI RzCmdStatus rz_cmd_debug_heap_jemalloc_b_handler(RzCore *core, int argc,
}
arena_addr = rz_num_math(core->num, argv[1]);
bin_info_addr = rz_num_math(core->num, argv[2]);
return rz_heap_jemalloc_cmd_b(core, has_specified_arena, arena_addr, has_bin_info, bin_info_addr);
}
return rz_heap_jemalloc_cmd_b(core, has_specified_arena, arena_addr, has_bin_info, bin_info_addr);
if (!rz_core_is_core_dump(core)) {
CMD_CHECK_DEBUG_DEAD(core);
}
return rz_heap_jemalloc_cmd_b(core, has_specified_arena, 0, has_bin_info, 0);
}
// "dmxc"
RZ_IPI RzCmdStatus rz_cmd_debug_heap_jemalloc_c_handler(RzCore *core, int argc, const char **argv) {
bool has_specified_arena = argc > 1 && RZ_STR_ISNOTEMPTY(argv[1]);
ut64 arena_addr = 0;
if (!has_specified_arena) {
CMD_CHECK_DEBUG_DEAD(core);
} else if (!rz_num_is_valid_input(core->num, argv[1])) {
RZ_LOG_ERROR("Invalid arena address '%s'\n", argv[1]);
return RZ_CMD_STATUS_ERROR;
} else {
arena_addr = rz_num_math(core->num, argv[1]);
if (has_specified_arena) {
if (!rz_num_is_valid_input(core->num, argv[1])) {
RZ_LOG_ERROR("Invalid arena address '%s'\n", argv[1]);
return RZ_CMD_STATUS_ERROR;
}
ut64 arena_addr = rz_num_math(core->num, argv[1]);
return rz_heap_jemalloc_cmd_c(core, has_specified_arena, arena_addr);
}
return rz_heap_jemalloc_cmd_c(core, has_specified_arena, arena_addr);
if (!rz_core_is_core_dump(core)) {
CMD_CHECK_DEBUG_DEAD(core);
}
return rz_heap_jemalloc_cmd_c(core, has_specified_arena, 0);
}
// "dmxe" - Find extent for malloc address
RZ_IPI RzCmdStatus rz_cmd_debug_heap_jemalloc_e_handler(RzCore *core, int argc, const char **argv) {
bool has_addr = argc > 1 && RZ_STR_ISNOTEMPTY(argv[1]);
ut64 lookup_addr = 0;
if (!has_addr) {
CMD_CHECK_DEBUG_DEAD(core);
} else if (!rz_num_is_valid_input(core->num, argv[1])) {
RZ_LOG_ERROR("Invalid address '%s'\n", argv[1]);
return RZ_CMD_STATUS_ERROR;
} else {
lookup_addr = rz_num_math(core->num, argv[1]);
if (has_addr) {
if (!rz_num_is_valid_input(core->num, argv[1])) {
RZ_LOG_ERROR("Invalid address '%s'\n", argv[1]);
return RZ_CMD_STATUS_ERROR;
}
ut64 lookup_addr = rz_num_math(core->num, argv[1]);
return rz_heap_jemalloc_cmd_e(core, has_addr, lookup_addr);
}
return rz_heap_jemalloc_cmd_e(core, has_addr, lookup_addr);
if (!rz_core_is_core_dump(core)) {
CMD_CHECK_DEBUG_DEAD(core);
}
return rz_heap_jemalloc_cmd_e(core, has_addr, 0);
}
// "dmxei" - Display extent info
@ -1097,7 +1425,6 @@ RZ_IPI RzCmdStatus rz_cmd_debug_heap_jemalloc_ei_handler(RzCore *core, int argc,
ut64 extent_addr = 0;
if (!has_addr) {
RZ_LOG_ERROR("Usage: dmxei <edata_addr>\n");
return RZ_CMD_STATUS_ERROR;
}
if (!rz_num_is_valid_input(core->num, argv[1])) {

View file

@ -784,8 +784,11 @@ commands:
args: []
- name: dm.
cname: cmd_debug_map_current
type: RZ_CMD_DESC_TYPE_ARGV_STATE
summary: Show map name of current address
args: []
modes:
- RZ_OUTPUT_MODE_STANDARD
- name: dmm
summary: Module memory map commands
subcommands:
@ -799,8 +802,10 @@ commands:
args: []
- name: dmm.
cname: cmd_debug_current_modules
type: RZ_CMD_DESC_TYPE_ARGV_STATE
modes:
- RZ_OUTPUT_MODE_STANDARD
- RZ_OUTPUT_MODE_JSON
summary: List memory map of current module
args: []
- name: dm-
@ -899,6 +904,7 @@ commands:
cname: cmd_debug_dmS
modes:
- RZ_OUTPUT_MODE_STANDARD
- RZ_OUTPUT_MODE_JSON
args:
- name: addr|libname
type: RZ_CMD_ARG_TYPE_STRING

View file

@ -23352,12 +23352,12 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) {
RzCmdDesc *cmd_debug_list_maps_ascii_cd = rz_cmd_desc_argv_new(core->rcmd, dm_cd, "dm=", rz_cmd_debug_list_maps_ascii_handler, &cmd_debug_list_maps_ascii_help);
rz_warn_if_fail(cmd_debug_list_maps_ascii_cd);
RzCmdDesc *cmd_debug_map_current_cd = rz_cmd_desc_argv_new(core->rcmd, dm_cd, "dm.", rz_cmd_debug_map_current_handler, &cmd_debug_map_current_help);
RzCmdDesc *cmd_debug_map_current_cd = rz_cmd_desc_argv_state_new(core->rcmd, dm_cd, "dm.", RZ_OUTPUT_MODE_STANDARD, rz_cmd_debug_map_current_handler, &cmd_debug_map_current_help);
rz_warn_if_fail(cmd_debug_map_current_cd);
RzCmdDesc *dmm_cd = rz_cmd_desc_group_state_new(core->rcmd, dm_cd, "dmm", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_debug_modules_handler, &cmd_debug_modules_help, &dmm_help);
rz_warn_if_fail(dmm_cd);
RzCmdDesc *cmd_debug_current_modules_cd = rz_cmd_desc_argv_modes_new(core->rcmd, dmm_cd, "dmm.", RZ_OUTPUT_MODE_STANDARD, rz_cmd_debug_current_modules_handler, &cmd_debug_current_modules_help);
RzCmdDesc *cmd_debug_current_modules_cd = rz_cmd_desc_argv_state_new(core->rcmd, dmm_cd, "dmm.", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_debug_current_modules_handler, &cmd_debug_current_modules_help);
rz_warn_if_fail(cmd_debug_current_modules_cd);
RzCmdDesc *cmd_debug_deallocate_map_cd = rz_cmd_desc_argv_new(core->rcmd, dm_cd, "dm-", rz_cmd_debug_deallocate_map_handler, &cmd_debug_deallocate_map_help);
@ -23417,7 +23417,7 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) {
RzCmdDesc *cmd_debug_dmL_cd = rz_cmd_desc_argv_new(core->rcmd, dm_cd, "dmL", rz_cmd_debug_dmL_handler, &cmd_debug_dmL_help);
rz_warn_if_fail(cmd_debug_dmL_cd);
RzCmdDesc *cmd_debug_dmS_cd = rz_cmd_desc_argv_modes_new(core->rcmd, dm_cd, "dmS", RZ_OUTPUT_MODE_STANDARD, rz_cmd_debug_dmS_handler, &cmd_debug_dmS_help);
RzCmdDesc *cmd_debug_dmS_cd = rz_cmd_desc_argv_modes_new(core->rcmd, dm_cd, "dmS", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_debug_dmS_handler, &cmd_debug_dmS_help);
rz_warn_if_fail(cmd_debug_dmS_cd);
RzCmdDesc *dmw_cd = rz_cmd_desc_group_modes_new(core->rcmd, dm_cd, "dmw", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_cmd_debug_process_heaps_handler, &cmd_debug_process_heaps_help, &dmw_help);

View file

@ -1312,11 +1312,11 @@ RZ_IPI RzCmdStatus rz_cmd_debug_allocate_maps_handler(RzCore *core, int argc, co
// "dm="
RZ_IPI RzCmdStatus rz_cmd_debug_list_maps_ascii_handler(RzCore *core, int argc, const char **argv);
// "dm."
RZ_IPI RzCmdStatus rz_cmd_debug_map_current_handler(RzCore *core, int argc, const char **argv);
RZ_IPI RzCmdStatus rz_cmd_debug_map_current_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
// "dmm"
RZ_IPI RzCmdStatus rz_cmd_debug_modules_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
// "dmm."
RZ_IPI RzCmdStatus rz_cmd_debug_current_modules_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode);
RZ_IPI RzCmdStatus rz_cmd_debug_current_modules_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
// "dm-"
RZ_IPI RzCmdStatus rz_cmd_debug_deallocate_map_handler(RzCore *core, int argc, const char **argv);
// "dmd"

View file

@ -19,6 +19,10 @@ RZ_DEPRECATE RZ_IPI const char *rz_core_get_parser(RzCore *core);
RZ_IPI void rz_core_kuery_print(RzCore *core, const char *k);
RZ_IPI int rz_output_mode_to_char(RzOutputMode mode);
RZ_IPI void rz_core_print_warnings_after(RZ_NONNULL RzCore *core);
RZ_IPI bool rz_core_is_core_dump(RzCore *core);
RZ_IPI const char *rz_core_io_map_strip_prefix(const RzIOMap *map);
RZ_IPI const char *rz_core_io_map_file_path(const RzIOMap *map);
RZ_IPI const char *rz_core_io_map_file_path_or_relative(const RzIOMap *map);
RZ_IPI int bb_cmpaddr(const void *_a, const void *_b, void *user);
RZ_IPI int fcn_cmpaddr(const void *_a, const void *_b, void *user);

View file

@ -16,7 +16,7 @@
#include "core_private.h"
void print_heap_chunk_simple(RzCore *core, ut64 chunk, const char *status, PJ *pj, const RzHeapConfig *config);
static void rz_heap_get_brks(RzCore *core, ut64 *brk_start, ut64 *brk_end);
static bool rz_heap_get_brks(RzCore *core, ut64 *brk_start, ut64 *brk_end);
static inline bool init_glibc_config(RzCore *core, RzHeapConfig *config);
static ut64 rz_heap_get_main_arena_with_symbol(RzCore *core, RzDebugMap *map);
static bool rz_heap_is_arena(RzCore *core, ut64 m_arena, ut64 m_state, const RzHeapConfig *config);
@ -150,6 +150,10 @@ static inline ut64 rz_heap_get_next_pointer(RzCore *core, ut64 pos, ut64 next, c
: next;
}
RZ_IPI bool rz_heap_is_map_name_libc(const char *map_name) {
return map_name && (strstr(map_name, "/libc-") || strstr(map_name, "/libc."));
}
static ut64 rz_heap_get_main_arena_with_symbol(RzCore *core, RzDebugMap *map) {
rz_return_val_if_fail(core && map, UT64_MAX);
ut64 base_addr = map->addr;
@ -206,6 +210,24 @@ beach:
return main_arena;
}
static ut64 rz_heap_get_main_arena_with_symbol_core_dump(RzCore *core, RzIOMap *map) {
rz_return_val_if_fail(core && map, UT64_MAX);
ut64 base_addr = map->itv.addr;
rz_return_val_if_fail(base_addr != UT64_MAX, UT64_MAX);
ut64 main_arena = UT64_MAX;
ut64 off = UT64_MAX;
const char *path = rz_core_io_map_file_path_or_relative(map);
if (path && rz_file_exists(path)) {
off = rz_heap_get_va_symbol(core, path, "main_arena");
if (off != UT64_MAX) {
main_arena = base_addr + off;
return main_arena;
}
}
return UT64_MAX;
}
static ut8 *get_glibc_banner(RzCore *core, const char *section_name,
const char *libc_path) {
RzPVector *sections = NULL;
@ -507,7 +529,116 @@ bool rz_heap_update_main_arena_internal(RzCore *core, ut64 m_arena, MallocState
return true;
}
static void rz_heap_get_brks(RzCore *core, ut64 *brk_start, ut64 *brk_end) {
/**
* \brief Check if an IOMap corresponds to an anonymous LOAD segment.
*
* An anonymous LOAD segment is a memory mapping that is not backed by a
* named file. It is identified by a name starting with "LOAD" followed only
* by digits.
*
* \param map RzIOMap instance
* \return true if the map is an anonymous LOAD segment, false otherwise
*/
static bool io_map_is_anonymous_load(const RzIOMap *map) {
const char *name = rz_core_io_map_strip_prefix(map);
if (!name) {
return false;
}
if (!rz_str_startswith(name, "LOAD")) {
return false;
}
const char *p = name + 4;
if (*p == '\0') {
return false;
}
while (*p) {
if (*p < '0' || *p > '9') {
return false;
}
p++;
}
return true;
}
/**
* In debug mode, we can locate the heap by the `[heap]` label:
* [0xaaaaea80094c]> dm
* 0x0000aaaaea800000 - 0x0000aaaaea801000 * usr 4K s r-x /rizin/test/bins/heap/segfault-heap-aarch64 /rizin/test/bins/heap/segfault-heap-aarch64 ; rizin_test_bins_heap_segfault_heap_aarch64.r_x
* 0x0000aaaaea81f000 - 0x0000aaaaea820000 - usr 4K s r-- /rizin/test/bins/heap/segfault-heap-aarch64 /rizin/test/bins/heap/segfault-heap-aarch64 ; rizin_test_bins_heap_segfault_heap_aarch64.rw
* 0x0000aaaaea820000 - 0x0000aaaaea821000 - usr 4K s rw- /rizin/test/bins/heap/segfault-heap-aarch64 /rizin/test/bins/heap/segfault-heap-aarch64 ; loc.__data_start
* 0x0000aaab0f265000 - 0x0000aaab0f286000 - usr 132K s rw- [heap] [heap]
* 0x0000ffff9ac40000 - 0x0000ffff9add9000 - usr 1.6M s r-x /usr/lib/aarch64-linux-gnu/libc.so.6 /usr/lib/aarch64-linux-gnu/libc.so.6
* 0x0000ffff9add9000 - 0x0000ffff9aded000 - usr 80K s --- /usr/lib/aarch64-linux-gnu/libc.so.6 /usr/lib/aarch64-linux-gnu/libc.so.6
* But in core dumps, the [heap] label doesn't exist:
* [0x00000840]> dm
* 1 fd: 4 +0x00000000 0xaaaae3c60000 - 0xaaaae3c60fff r-x mmap./run/host_virtiofs/Users/bubblepipe/repo/rizin/test/bins/heap/segfault-heap-aarch64
* 2 fd: 3 +0x00002000 0xaaaae3c7f000 - 0xaaaae3c7ffff r-- fmap./run/host_virtiofs/Users/bubblepipe/repo/rizin/test/bins/heap/segfault-heap-aarch64
* 3 fd: 3 +0x00003000 0xaaaae3c80000 - 0xaaaae3c80fff r-- fmap./run/host_virtiofs/Users/bubblepipe/repo/rizin/test/bins/heap/segfault-heap-aarch64
* 4 fd: 3 +0x00004000 0xaaab126cd000 - 0xaaab126edfff r-- fmap.LOAD3
* 5 fd: 5 +0x00000000 0xffff9a5d0000 - 0xffff9a768fff r-x mmap./usr/lib/aarch64-linux-gnu/libc.so.6
* We identify the brk heap as the first anonymous LOAD segment after the main executable's last mapping.
* This works because the kernel places the brk region right after the program's
* data segment, while other regions are placed at a much higher address range.
*
* Source: https://man7.org/linux/man-pages/man2/brk.2.html
* "brk() and sbrk() change the location of the program break, which
* defines the end of the process's data segment (i.e., the program
* break is the first location after the end of the uninitialized
* data segment). Increasing the program break has the effect of
* allocating memory to the process; decreasing the break deallocates
* memory."
*/
static bool rz_heap_get_brks_core_dump(RzCore *core, ut64 *brk_start, ut64 *brk_end) {
RzPVector *maps = rz_io_maps(core->io);
if (!maps) {
return false;
}
// identify the main executable's file path:
// the first file-backed mapping (low address) that
// is not a special region like [stack], [vdso], etc.
const char *exe_path = NULL;
ut64 lowest_addr = UT64_MAX;
void **it;
rz_pvector_foreach (maps, it) {
RzIOMap *map = *it;
const char *path = rz_core_io_map_file_path_or_relative(map);
if (path && map->itv.addr < lowest_addr) {
lowest_addr = map->itv.addr;
exe_path = path;
}
}
if (!exe_path) {
return false;
}
// find the end of all mappings belonging to the executable
ut64 exe_end = 0;
rz_pvector_foreach (maps, it) {
RzIOMap *map = *it;
const char *path = rz_core_io_map_file_path_or_relative(map);
if (path && !strcmp(path, exe_path)) {
ut64 end = map->itv.addr + map->itv.size;
if (end > exe_end) {
exe_end = end;
}
}
}
// find the first anonymous LOAD segment after the executable
rz_pvector_foreach (maps, it) {
RzIOMap *map = *it;
if (map->itv.addr > exe_end && io_map_is_anonymous_load(map)) {
*brk_start = map->itv.addr;
*brk_end = map->itv.addr + map->itv.size;
return true;
}
}
return false;
}
static bool rz_heap_get_brks(RzCore *core, ut64 *brk_start, ut64 *brk_end) {
if (rz_config_get_b(core->config, "cfg.debug")) {
RzListIter *iter;
RzDebugMap *map;
@ -517,7 +648,7 @@ static void rz_heap_get_brks(RzCore *core, ut64 *brk_start, ut64 *brk_end) {
if (strstr(map->name, "[heap]")) {
*brk_start = map->addr;
*brk_end = map->addr_end;
break;
return true;
}
}
}
@ -530,11 +661,13 @@ static void rz_heap_get_brks(RzCore *core, ut64 *brk_start, ut64 *brk_end) {
if (strstr(map->name, "[heap]")) {
*brk_start = map->itv.addr;
*brk_end = map->itv.addr + map->itv.size;
break;
return true;
}
}
}
return rz_heap_get_brks_core_dump(core, brk_start, brk_end);
}
return false;
}
static void print_arena_stats(RzCore *core, ut64 m_arena, MallocState *main_arena, ut64 global_max_fast, int format, const RzHeapConfig *config) {
@ -661,10 +794,6 @@ static void print_arena_stats(RzCore *core, ut64 m_arena, MallocState *main_aren
PRINT_GA("}\n\n");
}
RZ_IPI bool rz_heap_is_map_name_libc(const char *map_name) {
return strstr(map_name, "/libc-") || strstr(map_name, "/libc.");
}
/**
* \brief Store the base address of main arena at m_arena
* \param core RzCore pointer
@ -704,6 +833,31 @@ RZ_API bool rz_heap_resolve_main_arena(RzCore *core, ut64 *m_arena) {
break;
}
}
} else if (rz_core_is_core_dump(core)) {
void **it;
RzPVector *maps = rz_io_maps(core->io);
rz_pvector_foreach (maps, it) {
RzIOMap *map = *it;
if (map->name && strstr(map->name, "arena")) {
libc_addr_sta = map->itv.addr;
libc_addr_end = map->itv.addr + map->itv.size;
break;
}
/* Try to find the main arena address using the glibc's symbols. */
if (rz_heap_is_map_name_libc(map->name) && first_libc && main_arena_sym == UT64_MAX) {
first_libc = false;
main_arena_sym = rz_heap_get_main_arena_with_symbol_core_dump(core, map);
}
if (rz_heap_is_map_name_libc(map->name)) {
if (map->itv.addr < libc_addr_sta) {
libc_addr_sta = map->itv.addr;
}
ut64 end = map->itv.addr + map->itv.size;
if (end > libc_addr_end) {
libc_addr_end = end;
}
}
}
} else {
void **it;
RzPVector *maps = rz_io_maps(core->io);
@ -717,7 +871,7 @@ RZ_API bool rz_heap_resolve_main_arena(RzCore *core, ut64 *m_arena) {
}
}
if (libc_addr_sta == UT64_MAX || libc_addr_end == UT64_MAX) {
if (libc_addr_sta == UT64_MAX || libc_addr_end == 0) {
if (rz_config_get_b(core->config, "cfg.debug")) {
RZ_LOG_WARN("core: Can't find glibc mapped in memory (see dm)\n");
} else {
@ -726,8 +880,7 @@ RZ_API bool rz_heap_resolve_main_arena(RzCore *core, ut64 *m_arena) {
return false;
}
rz_heap_get_brks(core, &brk_start, &brk_end);
if (brk_start == UT64_MAX || brk_end == UT64_MAX) {
if (!rz_heap_get_brks(core, &brk_start, &brk_end)) {
RZ_LOG_ERROR("core: no heap section\n");
return false;
}
@ -894,7 +1047,7 @@ static void resolve_tcache_perthread(RZ_NONNULL RzCore *core, const RzHeapConfig
RZ_API RZ_OWN bool resolve_heap_tcache(RZ_NONNULL RzCore *core, ut64 arena_base, const RzHeapConfig *config) {
RzDebug *dbg = core->dbg;
if (dbg->threads) {
if (rz_config_get_b(core->config, "cfg.debug") && dbg->threads) {
resolve_tcache_perthread(core, config);
return true;
}
@ -1233,8 +1386,7 @@ static int print_double_linked_list_bin(RzCore *core, MallocState *main_arena, u
return -1;
}
rz_heap_get_brks(core, &brk_start, &brk_end);
if (brk_start == UT64_MAX || brk_end == UT64_MAX) {
if (!rz_heap_get_brks(core, &brk_start, &brk_end)) {
RZ_LOG_ERROR("core: no heap section\n");
return -1;
}
@ -1333,10 +1485,9 @@ RzHeapBin *rz_heap_fastbin_content_internal(RzCore *core, MallocState *arena, in
if (!next) {
return heap_bin;
}
rz_heap_get_brks(core, &brk_start, &brk_end);
heap_bin->fd = next;
if (brk_start == UT64_MAX || brk_end == UT64_MAX) {
if (!rz_heap_get_brks(core, &brk_start, &brk_end)) {
return heap_bin;
}
@ -1486,8 +1637,7 @@ RzList /*<RzHeapBin *>*/ *rz_heap_tcache_content_internal(RzCore *core, ut64 are
}
ut64 brk_start = UT64_MAX, brk_end = UT64_MAX;
rz_heap_get_brks(core, &brk_start, &brk_end);
if (brk_start == UT64_MAX || brk_end == UT64_MAX) {
if (!rz_heap_get_brks(core, &brk_start, &brk_end)) {
return NULL;
}
@ -1713,8 +1863,7 @@ RzHeapBin *rz_heap_bin_content_internal(RzCore *core, MallocState *arena, int bi
}
ut64 brk_start = UT64_MAX, brk_end = UT64_MAX, initial_brk = UT64_MAX;
rz_heap_get_brks(core, &brk_start, &brk_end);
if (brk_start == UT64_MAX || brk_end == UT64_MAX) {
if (!rz_heap_get_brks(core, &brk_start, &brk_end)) {
return bin;
}
@ -2052,12 +2201,12 @@ RzList /*<RzHeapChunkListItem *>*/ *rz_heap_chunks_list_internal(RzCore *core, M
RzConsPrintablePalette *pal = &rz_cons_singleton()->context->pal;
if (m_arena == m_state) {
rz_heap_get_brks(core, &brk_start, &brk_end);
if (!rz_heap_get_brks(core, &brk_start, &brk_end)) {
return chunks;
}
if (tcache) {
initial_brk = ((brk_start >> 12) << 12) + config->chunk_hdr_size;
if (rz_config_get_b(core->config, "cfg.debug")) {
tcache_initial_brk = initial_brk;
}
tcache_initial_brk = initial_brk;
initial_brk += config->tcache.struct_size;
} else {
initial_brk = (brk_start >> 12) << 12;
@ -2112,8 +2261,8 @@ RzList /*<RzHeapChunkListItem *>*/ *rz_heap_chunks_list_internal(RzCore *core, M
if (fastbin) {
int i = (size_tmp / (ptr_size * 2)) - 2;
ut64 idx = (ut64)main_arena->fastbinsY[i];
if (!rz_glibc_read_chunk(core->io, idx, &cnk, config)) {
continue;
if (!idx || !rz_glibc_read_chunk(core->io, idx, &cnk, config)) {
goto skip_fastbin;
}
ut64 next = rz_heap_get_next_pointer(core, idx, cnk.fd, config);
if (prev_chunk == idx && idx && !next) {
@ -2127,7 +2276,7 @@ RzList /*<RzHeapChunkListItem *>*/ *rz_heap_chunks_list_internal(RzCore *core, M
break;
}
if (!rz_glibc_read_chunk(core->io, next, &cnk_next, config)) {
continue;
break;
}
ut64 next_node = rz_heap_get_next_pointer(core, next, cnk_next.fd, config);
// avoid triple while?
@ -2137,7 +2286,7 @@ RzList /*<RzHeapChunkListItem *>*/ *rz_heap_chunks_list_internal(RzCore *core, M
break;
}
if (!rz_glibc_read_chunk(core->io, next_node, &cnk_next, config)) {
continue;
break;
}
next_node = rz_heap_get_next_pointer(core, next_node, cnk_next.fd, config);
}
@ -2146,10 +2295,11 @@ RzList /*<RzHeapChunkListItem *>*/ *rz_heap_chunks_list_internal(RzCore *core, M
}
}
if (!rz_glibc_read_chunk(core->io, next, &cnk, config)) {
continue;
break;
}
next = rz_heap_get_next_pointer(core, next, cnk.fd, config);
}
skip_fastbin:
if (double_free) {
PRINT_RA(" Double free in simple-linked list detected ");
break;
@ -2323,8 +2473,9 @@ RZ_IPI RzCmdStatus rz_cmd_heap_chunks_print_handler(RzCore *core, int argc, cons
}
ut64 brk_start = 0, brk_end = 0;
if (m_arena == m_state) {
rz_heap_get_brks(core, &brk_start, &brk_end);
if (!rz_heap_get_brks(core, &brk_start, &brk_end)) {
return RZ_CMD_STATUS_ERROR;
}
} else {
brk_start = ((m_state >> 16) << 16);
brk_end = brk_start + main_arena->system_mem;

View file

@ -2,6 +2,7 @@
// SPDX-FileCopyrightText: 2026 bubblepipe <bubblepipe42@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include "core/core_private.h"
#include <rz_core.h>
#include <rz_heap_jemalloc.h>
#include <stdio.h>
@ -49,9 +50,52 @@ static ut64 je_get_va_symbol(RzCore *core, const char *path, const char *sym_nam
return vaddr;
}
static bool resolve_jemalloc_core_dump(RzCore *core, const char *symname, ut64 *symbol) {
void **it;
RzPVector *io_maps = rz_io_maps(core->io);
rz_pvector_foreach (io_maps, it) {
RzIOMap *io_map = *it;
const char *path = rz_core_io_map_file_path_or_relative(io_map);
if (!rz_file_exists(path)) {
continue;
}
// find the lowest map address for this file, for base_addr
bool already_processed = false;
ut64 base_addr = io_map->itv.addr;
void **it2;
rz_pvector_foreach (io_maps, it2) {
RzIOMap *m2 = *it2;
const char *p2 = rz_core_io_map_file_path_or_relative(m2);
if (!RZ_STR_EQ(p2, path)) {
continue;
}
if (it2 < it) {
already_processed = true;
break;
}
if (m2->itv.addr < base_addr) {
base_addr = m2->itv.addr;
}
}
if (already_processed) {
continue;
}
bool is_pie = false;
ut64 vaddr = je_get_va_symbol(core, path, symname, &is_pie);
if (vaddr != UT64_MAX) {
*symbol = is_pie ? (base_addr + vaddr) : vaddr;
return true;
}
}
return false;
}
static bool rz_resolve_jemalloc(RzCore *core, const char *symname, ut64 *symbol) {
RzListIter *iter;
RzDebugMap *map;
RzDebugMap *debug_map;
const char *jemalloc_path = NULL;
ut64 jemalloc_addr = UT64_MAX;
const char *binary_path = NULL;
@ -60,20 +104,25 @@ static bool rz_resolve_jemalloc(RzCore *core, const char *symname, ut64 *symbol)
if (!core || !core->dbg || !core->dbg->maps) {
return false;
}
rz_debug_map_sync(core->dbg);
rz_list_foreach (core->dbg->maps, iter, map) {
if (strstr(map->name, "libjemalloc.")) {
if (jemalloc_addr == UT64_MAX || map->addr < jemalloc_addr) {
jemalloc_addr = map->addr;
jemalloc_path = map->name;
if (rz_core_is_core_dump(core)) {
return resolve_jemalloc_core_dump(core, symname, symbol);
}
// for debug mode
rz_debug_map_sync(core->dbg);
rz_list_foreach (core->dbg->maps, iter, debug_map) {
if (strstr(debug_map->name, "libjemalloc.")) {
if (jemalloc_addr == UT64_MAX || debug_map->addr < jemalloc_addr) {
jemalloc_addr = debug_map->addr;
jemalloc_path = debug_map->name;
}
}
if (!strstr(map->name, ".so") && !strstr(map->name, "lib") &&
!strstr(map->name, "[") && strlen(map->name) > 0) {
if (binary_addr == UT64_MAX || map->addr < binary_addr) {
binary_addr = map->addr;
binary_path = map->name;
if (!strstr(debug_map->name, ".so") && !strstr(debug_map->name, "lib") &&
!strstr(debug_map->name, "[") && strlen(debug_map->name) > 0) {
if (binary_addr == UT64_MAX || debug_map->addr < binary_addr) {
binary_addr = debug_map->addr;
binary_path = debug_map->name;
}
}
}
@ -312,7 +361,7 @@ static void jemalloc_print_narenas_450(RzCore *core, bool has_specified_addr, ut
if (!has_specified_addr) {
if (rz_resolve_jemalloc(core, "narenas_total", &symaddr)) {
if (!read_ptr_at(core->io, symaddr, &narenas, config->ptr_size)) {
if (!read_ptr_at(core->io, symaddr, &narenas, 4)) {
RZ_LOG_ERROR("Failed to read narenas_total\n");
return;
}
@ -830,11 +879,15 @@ static void jemalloc_print_narenas_530(RzCore *core, bool has_specified_addr, ut
if (!has_specified_addr) { // no args, list all arenas
if (rz_resolve_jemalloc(core, "narenas_total", &symaddr)) {
if (!read_ptr_at(core->io, symaddr, &narenas, config->ptr_size)) {
RZ_LOG_DEBUG("symaddr : %" PFMT64d "\n", symaddr);
if (!read_ptr_at(core->io, symaddr, &narenas, 4)) {
RZ_LOG_ERROR("Failed to read narenas_total\n");
return;
}
PRINTF_GA("narenas : %" PFMT64d "\n", narenas);
} else {
RZ_LOG_ERROR("narena_total not resolved\n");
return;
}
if (narenas == 0) {
RZ_LOG_ERROR("No arenas allocated.\n");

View file

@ -15,7 +15,7 @@ EOF
EXPECT=<<EOF
1
3
2
1
EOF
RUN

View file

@ -153,3 +153,36 @@ Extent @ 0x7fff96016500
Allocated Address: 0x7fff95e00000
EOF
RUN
NAME=dmxa/dmxb/dmxe/dmxei with jemalloc 5.3.0 core dump (linux-amd64-4k_page)
FILE=bins/heap/segfault-jemalloc5.3.0-amd64-core
CMDS=<<EOF
dmxa~narena
dmxa~0x55ae211c05c0
dmxb~0x7f4550214528
dmxe~0x7f4550216500
dmxei 0x7f4550216980~Size
EOF
EXPECT=<<EOF
narenas : 129
arenas[129] @ 0x55ae211c05c0 {
bin[0] @ 0x7f4550214528 {
Extent @ 0x7f4550216500
Size: 0x1000
EOF
RUN
NAME=dmxa/dmxb/dmxc with jemalloc 4.5.0 core dump (linux-aarch64-4k_page)
FILE=bins/heap/segfault-jemalloc4.5.0-aarch64-core
CMDS=<<EOF
dmxa~narena
dmxb~0xffffa6e00140
dmxc~Chunk
EOF
EXPECT=<<EOF
narenas : 32
arenas[0]: @ 0xffffa6e00140 {
Chunk - start: 0xffffa6c00000, end: 0xffffa6e00000, size: 0x00200000
EOF
RUN

View file

@ -15,7 +15,7 @@ EOF
EXPECT=<<EOF
1
3
2
1
EOF
RUN

View file

@ -15,7 +15,7 @@ EOF
EXPECT=<<EOF
1
3
2
1
EOF
RUN

View file

@ -57,7 +57,7 @@ EOF
EXPECT=<<EOF
1
3
2
1
EOF
RUN

View file

@ -218,3 +218,21 @@ Extent @ 0x7fff96016500
Allocated Address: 0x7fff95e00000
EOF
RUN
NAME=dmxa/dmxb/dmxe/dmxei with jemalloc 5.3.0 core dump (linux-amd64-4k_page)
FILE=bins/heap/segfault-jemalloc5.3.0-amd64-core
CMDS=<<EOF
dmxa~narena
dmxa~0x55ae211c05c0
dmxb~0x7f4550214528
dmxe~0x7f4550216500
dmxei 0x7f4550216980~Size
EOF
EXPECT=<<EOF
narenas : 129
arenas[129] @ 0x55ae211c05c0 {
bin[0] @ 0x7f4550214528 {
Extent @ 0x7f4550216500
Size: 0x1000
EOF
RUN

View file

@ -116,11 +116,11 @@ CMDS=<<EOF
oml
EOF
EXPECT=<<EOF
1 fd: 3 +0x00002000 0x56149dfaf000 - 0x56149dfaffff r-- fmap./home/florian/dev/crash/crash-linux-x86_64
2 fd: 4 +0x00000000 0x56149dfb0000 - 0x56149dfb0fff r-x mmap./home/florian/dev/crash/crash-linux-x86_64
3 fd: 5 +0x00000000 0x56149dfb1000 - 0x56149dfb1fff r-- mmap./home/florian/dev/crash/crash-linux-x86_64
4 fd: 3 +0x00003000 0x56149dfb2000 - 0x56149dfb2fff r-- fmap./home/florian/dev/crash/crash-linux-x86_64
5 fd: 3 +0x00004000 0x56149dfb3000 - 0x56149dfb3fff r-- fmap./home/florian/dev/crash/crash-linux-x86_64
1 fd: 3 +0x00002000 0x56149dfaf000 - 0x56149dfaffff r-- fmap.bins/elf/core/crash-linux-x86_64
2 fd: 4 +0x00000000 0x56149dfb0000 - 0x56149dfb0fff r-x mmap.bins/elf/core/crash-linux-x86_64
3 fd: 5 +0x00000000 0x56149dfb1000 - 0x56149dfb1fff r-- mmap.bins/elf/core/crash-linux-x86_64
4 fd: 3 +0x00003000 0x56149dfb2000 - 0x56149dfb2fff r-- fmap.bins/elf/core/crash-linux-x86_64
5 fd: 3 +0x00004000 0x56149dfb3000 - 0x56149dfb3fff r-- fmap.bins/elf/core/crash-linux-x86_64
6 fd: 3 +0x00005000 0x7f582fa2e000 - 0x7f582fa2ffff r-- fmap.LOAD5
7 fd: 6 +0x00000000 0x7f582fa31000 - 0x7f582fa55fff r-- mmap./usr/lib/libc-2.33.so
8 fd: 3 +0x00007000 0x7f582fa30000 - 0x7f582fa30fff r-- fmap./usr/lib/libc-2.33.so
@ -174,9 +174,9 @@ CMDS=<<EOF
oml
EOF
EXPECT=<<EOF
1 fd: 3 +0x00001000 0x558ce37000 - 0x558ce37fff r-x fmap./home/alarm/crash/crash-linux-arm64
2 fd: 3 +0x00002000 0x558ce47000 - 0x558ce47fff r-- fmap./home/alarm/crash/crash-linux-arm64
3 fd: 3 +0x00003000 0x558ce48000 - 0x558ce48fff r-- fmap./home/alarm/crash/crash-linux-arm64
1 fd: 3 +0x00001000 0x558ce37000 - 0x558ce37fff r-x fmap.bins/elf/core/crash-linux-arm64
2 fd: 3 +0x00002000 0x558ce47000 - 0x558ce47fff r-- fmap.bins/elf/core/crash-linux-arm64
3 fd: 3 +0x00003000 0x558ce48000 - 0x558ce48fff r-- fmap.bins/elf/core/crash-linux-arm64
4 fd: 4 +0x00000000 0x7f8bd61000 - 0x7f8bebafff r-x mmap./usr/lib/libc-2.32.so
5 fd: 3 +0x00004000 0x7f8bd60000 - 0x7f8bd60fff r-x fmap./usr/lib/libc-2.32.so
6 fd: 5 +0x00000000 0x7f8bebb000 - 0x7f8becafff r-- mmap./usr/lib/libc-2.32.so
@ -601,3 +601,130 @@ cause = 0x0000000010800024
t = 0x0000000000000000
EOF
RUN
NAME=dm commands on x86-64 core dump
FILE=bins/elf/core/core-linux-x86_64
CMDS=<<EOF
dm~fmap?
dm~mmap?
dmj~{[0]}
dm=~fmap?
dm=~mmap?
echo ----
s 0x56149dfaf000
dm.~0x56149dfaf000
echo ----
dmm~libc
dmm.~bin
dmmj~libc
dmm.j~crash
echo ----
dmi bins/elf/core/crash-linux-x86_64~printf
dmij~{[0]}
dmia bins/elf/core/crash-linux-x86_64~MAGIC
obf bins/elf/core/crash-linux-x86_64
dmi.~end
echo ----
dmS~.rodata
EOF
EXPECT=<<EOF
15
7
{"map":1,"fd":3,"delta":8192,"from":94646549803008,"to":94646549807104,"perm":"r--","name":"fmap.bins/elf/core/crash-linux-x86_64"}
15
7
----
1 fd: 3 +0x00002000 0x56149dfaf000 - 0x56149dfaffff r-- fmap.bins/elf/core/crash-linux-x86_64
----
0x7f582fa31000 0x7f582fa56000 /usr/lib/libc-2.33.so
0x56149dfaf000 0x56149dfb0000 bins/elf/core/crash-linux-x86_64
[{"addr":94646549803008,"addr_end":94646549807104,"name":"bins/elf/core/crash-linux-x86_64"},{"addr":140016733065216,"addr_end":140016733216768,"name":"/usr/lib/libc-2.33.so"},{"addr":140016735272960,"addr_end":140016735277056,"name":"/usr/lib/ld-2.33.so"}]
[{"addr":94646549803008,"addr_end":94646549807104,"file":"bins/elf/core/crash-linux-x86_64"}]
----
2 0x00001030 0x56149dfb0030 GLOBAL FUNC 16 imp.printf
{"addr":94646549803008,"addr_end":94646549807104,"name":"bins/elf/core/crash-linux-x86_64"}
0x00000000 MAGIC 0x00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
34 ---------- 0x00004038 GLOBAL NOTYPE 0 _end
----
0x00002000 0x8 0x56149dfb1000 0x8 0x0 -r-- crash-linux-x86_64..rodata PROGBITS alloc
EOF
RUN
NAME=dm commands on arm64 core dump
FILE=bins/elf/core/core-linux-arm64
CMDS=<<EOF
dm~fmap?
dm~mmap?
dm=~fmap?
dm=~mmap?
echo ----
s 0x558ce37000
dm.~0x558ce37000
echo ----
dmm~libc
dmm.~bin
dmmj~libc
dmm.j~crash
echo ----
dmi bins/elf/core/crash-linux-arm64~printf
dmia bins/elf/core/crash-linux-arm64~MAGIC
obf bins/elf/core/crash-linux-arm64
dmi.~end
echo ----
dmS~.rodata
EOF
EXPECT=<<EOF
14
3
14
3
----
1 fd: 3 +0x00001000 0x558ce37000 - 0x558ce37fff r-x fmap.bins/elf/core/crash-linux-arm64
----
0x7f8bd61000 0x7f8bebb000 /usr/lib/libc-2.32.so
0x558ce37000 0x558ce38000 bins/elf/core/crash-linux-arm64
[{"addr":367435935744,"addr_end":367435939840,"name":"bins/elf/core/crash-linux-arm64"},{"addr":547806908416,"addr_end":547808325632,"name":"/usr/lib/libc-2.32.so"},{"addr":547808579584,"addr_end":547808714752,"name":"/usr/lib/ld-2.32.so"}]
[{"addr":367435935744,"addr_end":367435939840,"file":"bins/elf/core/crash-linux-arm64"}]
----
9 0x00000620 0x558ce37620 GLOBAL FUNC 16 imp.printf
0x00000000 MAGIC 0x00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
83 ---------- 0x00011038 GLOBAL NOTYPE 0 _bss_end__
----
0x00000818 0xc 0x558ce37818 0xc 0x0 -r-- crash-linux-arm64..rodata PROGBITS alloc
EOF
RUN
NAME=dmh commands on arm64 core dump
FILE=bins/heap/segfault-glibc-aarch64-core
CMDS=<<EOF
dmh~Arena
dmha
dmhb~Bin?
dmhc @ 0xaaab126cd290~0xaaab126cd2a0
echo ----
dmhd~Empty
dmhf~Arena
echo ----
dmhg~0x410?
dmhm~malloc_state
EOF
EXPECT=<<EOF
Arena @ 0xffff9a780a50
Main arena (addr=0xffff9a780a50, lastRemainder=0x0, top=0xaaab126cdae0, next=0xffff9a780a50)
128
0xaaab126cd2a0 0x6e75686320676942 0x617830207461206b Big chunk at 0xa
----
Fast_bin[01] [size: 0x20] Empty bin
Fast_bin[02] [size: 0x30] Empty bin
Fast_bin[03] [size: 0x40] Empty bin
Fast_bin[04] [size: 0x50] Empty bin
Fast_bin[05] [size: 0x60] Empty bin
Fast_bin[06] [size: 0x70] Empty bin
Fast_bin[07] [size: 0x80] Empty bin
Fast bins in Arena @ 0xffff9a780a50
----
2
malloc_state @ 0xffff9a780a50
struct malloc_state main_arena {
EOF
RUN