2024-04-17 14:11:36 +00:00
|
|
|
|
/* radare2 - LGPL - Copyright 2016-2024 - n4x0r, soez, pancake */
|
2016-10-20 13:02:25 +00:00
|
|
|
|
|
2023-09-07 09:23:04 +00:00
|
|
|
|
#if R_INCLUDE_BEGIN
|
2023-05-24 10:50:11 +00:00
|
|
|
|
// https://levelup.gitconnected.com/understand-heap-memory-allocation-a-hands-on-approach-775151caf2ea
|
|
|
|
|
// https://github.com/bminor/glibc/blob/glibc-2.28/malloc/malloc.c#L1658
|
2016-10-06 16:02:25 +00:00
|
|
|
|
#ifndef INCLUDE_HEAP_GLIBC_C
|
|
|
|
|
#define INCLUDE_HEAP_GLIBC_C
|
2020-08-31 16:45:12 +00:00
|
|
|
|
#include "r_config.h"
|
2016-10-06 16:02:25 +00:00
|
|
|
|
#define HEAP32 1
|
2023-05-24 08:36:04 +00:00
|
|
|
|
#include "dmh_glibc.inc.c"
|
2016-10-06 16:02:25 +00:00
|
|
|
|
#undef HEAP32
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-11-08 00:58:07 +00:00
|
|
|
|
#undef GH
|
2016-10-06 16:02:25 +00:00
|
|
|
|
#undef GHT
|
|
|
|
|
#undef GHT_MAX
|
2020-07-08 12:16:27 +00:00
|
|
|
|
#undef read_le
|
2016-10-06 16:02:25 +00:00
|
|
|
|
|
|
|
|
|
#if HEAP32
|
|
|
|
|
#define GH(x) x##_32
|
|
|
|
|
#define GHT ut32
|
|
|
|
|
#define GHT_MAX UT32_MAX
|
2020-07-08 12:16:27 +00:00
|
|
|
|
#define read_le(x) r_read_le##32(x)
|
2016-10-06 16:02:25 +00:00
|
|
|
|
#else
|
|
|
|
|
#define GH(x) x##_64
|
|
|
|
|
#define GHT ut64
|
|
|
|
|
#define GHT_MAX UT64_MAX
|
2020-07-08 12:16:27 +00:00
|
|
|
|
#define read_le(x) r_read_le##64(x)
|
2016-10-06 16:02:25 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2020-06-18 10:14:21 +00:00
|
|
|
|
/**
|
|
|
|
|
* \brief Find the address of a given symbol
|
|
|
|
|
* \param core RCore Pointer to the r2's core
|
|
|
|
|
* \param path Pointer to the binary path in which to look for the symbol
|
|
|
|
|
* \param sym_name Pointer to the symbol's name to search for
|
|
|
|
|
* \return address
|
|
|
|
|
*
|
|
|
|
|
* Used to find the address of a given symbol inside a binary
|
|
|
|
|
*
|
|
|
|
|
* TODO: Stop using deprecated functions like r_bin_cur
|
|
|
|
|
*/
|
|
|
|
|
static GHT GH(get_va_symbol)(RCore *core, const char *path, const char *sym_name) {
|
|
|
|
|
GHT vaddr = GHT_MAX;
|
|
|
|
|
RBin *bin = core->bin;
|
2023-05-24 08:32:10 +00:00
|
|
|
|
RBinFile *bf = r_bin_cur (bin);
|
2020-06-18 10:14:21 +00:00
|
|
|
|
|
2021-10-10 18:02:24 +00:00
|
|
|
|
RBinFileOptions opt;
|
|
|
|
|
r_bin_file_options_init (&opt, -1, 0, 0, false);
|
2023-05-24 08:32:10 +00:00
|
|
|
|
if (r_bin_open (bin, path, &opt)) {
|
2023-07-20 17:26:51 +00:00
|
|
|
|
RVecRBinSymbol *syms = r_bin_get_symbols_vec (bin);
|
2023-05-24 08:32:10 +00:00
|
|
|
|
RBinSymbol *s;
|
2023-07-20 17:26:51 +00:00
|
|
|
|
R_VEC_FOREACH (syms, s) {
|
2023-12-22 00:51:42 +00:00
|
|
|
|
const char *sname = r_bin_name_tostring (s->name);
|
|
|
|
|
if (!strcmp (sname, sym_name)) {
|
2023-05-24 08:32:10 +00:00
|
|
|
|
vaddr = s->vaddr;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-06-18 10:14:21 +00:00
|
|
|
|
}
|
2023-05-24 08:32:10 +00:00
|
|
|
|
RBinFile *libc_bf = r_bin_cur (bin);
|
|
|
|
|
r_bin_file_delete (bin, libc_bf->id);
|
|
|
|
|
r_bin_file_set_cur_binfile (bin, bf);
|
2020-06-18 10:14:21 +00:00
|
|
|
|
}
|
|
|
|
|
return vaddr;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-22 12:20:06 +00:00
|
|
|
|
static inline GHT GH(align_address_to_size)(ut64 addr, ut64 align) {
|
|
|
|
|
return addr + ((align - (addr % align)) % align);
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-31 16:45:12 +00:00
|
|
|
|
static inline GHT GH(get_next_pointer)(RCore *core, GHT pos, GHT next) {
|
|
|
|
|
return (core->dbg->glibc_version < 232) ? next : PROTECT_PTR (pos, next);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-05 20:22:38 +00:00
|
|
|
|
static GHT GH(get_main_arena_offset_with_symbol)(RCore *core, const char *libc_filename) {
|
2020-07-22 12:20:06 +00:00
|
|
|
|
GHT vaddr = GHT_MAX;
|
2024-03-05 20:22:38 +00:00
|
|
|
|
if (libc_filename && r_file_exists (libc_filename)) {
|
|
|
|
|
vaddr = GH (get_va_symbol)(core, libc_filename, "main_arena");
|
2020-07-22 12:20:06 +00:00
|
|
|
|
if (vaddr != GHT_MAX) {
|
2024-03-05 20:22:38 +00:00
|
|
|
|
R_LOG_INFO("Found main_arena with symbol");
|
2020-07-22 12:20:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-05 20:22:38 +00:00
|
|
|
|
return vaddr;
|
2020-07-22 12:20:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-02-14 13:38:40 +00:00
|
|
|
|
static GH(section_content) GH(get_section_content)(RCore *core, const char *path, const char *section_name) {
|
|
|
|
|
RBin *bin = core->bin;
|
|
|
|
|
RBinFile *bf = r_bin_cur (bin);
|
|
|
|
|
bool found_section = false;
|
|
|
|
|
GHT paddr;
|
|
|
|
|
GH(section_content) content = {.size = GHT_MAX, .buf = NULL};
|
|
|
|
|
|
|
|
|
|
RBinFileOptions opt;
|
|
|
|
|
r_bin_file_options_init (&opt, -1, 0, 0, false);
|
|
|
|
|
if (!r_bin_open (bin, path, &opt)) {
|
2024-02-24 11:33:40 +00:00
|
|
|
|
R_LOG_ERROR ("get_section_content: r_bin_open failed on path %s", path);
|
2024-02-14 13:38:40 +00:00
|
|
|
|
return content;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RBinFile *libc_bf = r_bin_cur (bin);
|
|
|
|
|
RList *sections = r_bin_get_sections (bin);
|
|
|
|
|
RBinSection *section;
|
|
|
|
|
RListIter *iter;
|
|
|
|
|
|
|
|
|
|
r_list_foreach (sections, iter, section) {
|
|
|
|
|
if (!strcmp (section->name, section_name)) {
|
|
|
|
|
found_section = true;
|
|
|
|
|
paddr = section->paddr;
|
|
|
|
|
content.size = section->size;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found_section) {
|
2024-02-24 11:33:40 +00:00
|
|
|
|
R_LOG_WARN ("get_section_content: section %s not found", section_name);
|
2024-02-14 13:38:40 +00:00
|
|
|
|
goto cleanup_exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// eprintf ("get_section_bytes: section found: %s content.size: %#08x paddr: %#08x\n", section_name, content.size, paddr);
|
|
|
|
|
content.buf = calloc (content.size, 1);
|
|
|
|
|
if (!content.buf) {
|
2024-02-24 11:33:40 +00:00
|
|
|
|
R_LOG_ERROR ("get_section_content: calloc failed");
|
2024-02-14 13:38:40 +00:00
|
|
|
|
goto cleanup_exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
st64 read_size = r_buf_read_at (libc_bf->buf, paddr, content.buf, content.size);
|
|
|
|
|
|
|
|
|
|
if (read_size != content.size) {
|
2024-02-24 11:33:40 +00:00
|
|
|
|
R_LOG_ERROR ("get_section_content: section read unexpected content.size: %#08x (section->size: %d)", read_size, content.size);
|
2024-02-14 13:38:40 +00:00
|
|
|
|
free (content.buf);
|
|
|
|
|
content.buf = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cleanup_exit:
|
|
|
|
|
r_bin_file_delete (bin, libc_bf->id);
|
2024-04-17 14:11:36 +00:00
|
|
|
|
if (bf) {
|
|
|
|
|
r_bin_file_set_cur_binfile (bin, bf);
|
|
|
|
|
}
|
2024-02-14 13:38:40 +00:00
|
|
|
|
return content;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
R_API double GH(get_glibc_version)(RCore *core, const char *libc_path) {
|
|
|
|
|
double version = 0.0;
|
|
|
|
|
|
|
|
|
|
// First see if there is a "__libc_version" symbol
|
|
|
|
|
// If yes read version from there
|
|
|
|
|
GHT version_symbol = GH (get_va_symbol) (core, libc_path, "__libc_version");
|
|
|
|
|
if (version_symbol != GHT_MAX) {
|
|
|
|
|
FILE *libc_file = fopen (libc_path, "rb");
|
|
|
|
|
if (libc_file == NULL) {
|
|
|
|
|
R_LOG_WARN ("resolve_glibc_version: Failed to open %s", libc_path);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// TODO: futureproof this
|
|
|
|
|
char version_buffer[5] = {0};
|
|
|
|
|
fseek (libc_file, version_symbol, SEEK_SET);
|
|
|
|
|
if (fread (version_buffer, 1, 4, libc_file) != 4) {
|
|
|
|
|
R_LOG_WARN ("resolve_glibc_version: Failed to read 4 bytes of version symbol");
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
fclose (libc_file);
|
|
|
|
|
if (!r_regex_match ("\\d.\\d\\d", "e", version_buffer)) {
|
|
|
|
|
R_LOG_WARN ("resolve_glibc_version: Unexpected version format: %s", version_buffer);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
version = strtod (version_buffer, NULL);
|
|
|
|
|
R_LOG_INFO ("libc version %.2f identified from symbol", version);
|
|
|
|
|
return version;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Next up we try to read version from banner in .rodata section
|
|
|
|
|
// also inspired by pwndbg
|
|
|
|
|
GH(section_content) rodata = GH (get_section_content) (core, libc_path, ".rodata");
|
|
|
|
|
|
|
|
|
|
const ut8 *banner_start = NULL;
|
|
|
|
|
if (rodata.buf != NULL) {
|
|
|
|
|
banner_start = r_mem_mem (rodata.buf, rodata.size, (const ut8 *)"GNU C Library", strlen ("GNU C Library"));
|
|
|
|
|
}
|
|
|
|
|
if (banner_start != NULL) {
|
|
|
|
|
RRegex *rx = r_regex_new ("release version (\\d.\\d\\d)", "en");
|
|
|
|
|
RList *matches = r_regex_match_list (rx, (const char *)banner_start);
|
|
|
|
|
// We only care about the first match
|
|
|
|
|
const char *first_match = r_list_first (matches);
|
|
|
|
|
if (first_match) {
|
|
|
|
|
const char *version_start = first_match + strlen ("release version ");
|
|
|
|
|
version = strtod (version_start, NULL);
|
|
|
|
|
}
|
|
|
|
|
r_list_free (matches);
|
|
|
|
|
r_regex_free (rx);
|
|
|
|
|
}
|
|
|
|
|
free (rodata.buf);
|
|
|
|
|
if (version != 0) {
|
|
|
|
|
R_LOG_INFO ("libc version %.2f identified from .rodata banner", version);
|
|
|
|
|
return version;
|
2023-04-10 10:54:51 +00:00
|
|
|
|
}
|
2024-02-14 13:38:40 +00:00
|
|
|
|
|
|
|
|
|
R_LOG_WARN ("get_glibc_version failed");
|
|
|
|
|
return version;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-24 11:33:40 +00:00
|
|
|
|
static const char* GH(get_libc_filename_from_maps)(RCore *core) {
|
|
|
|
|
r_return_val_if_fail (core && core->dbg && core->dbg->maps && core->bin && core->bin->file, NULL);
|
|
|
|
|
RListIter *iter;
|
|
|
|
|
RDebugMap *map = NULL;
|
|
|
|
|
|
|
|
|
|
r_debug_map_sync (core->dbg);
|
|
|
|
|
|
|
|
|
|
// Search for binary in memory maps named *libc-* or *libc.* *libc6_* or similiar
|
|
|
|
|
// TODO: This is very brittle, other bin names or LD_PRELOAD could be a problem
|
|
|
|
|
r_list_foreach (core->dbg->maps, iter, map) {
|
|
|
|
|
if (!map->name || r_str_startswith (core->bin->file, map->name)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (r_regex_match (".*libc6?[-_\\.]", "e", map->name)) {
|
2024-03-05 20:22:38 +00:00
|
|
|
|
r_config_set (core->config, "dbg.glibc.path", map->file);
|
2024-02-24 11:33:40 +00:00
|
|
|
|
return map->file;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-05 20:22:38 +00:00
|
|
|
|
// TODO: more options to get libc filename
|
|
|
|
|
static const char* GH(get_libc_filename)(RCore *core) {
|
|
|
|
|
const char *dbg_glibc_path = r_config_get (core->config, "dbg.glibc.path");
|
|
|
|
|
if (!R_STR_ISEMPTY (dbg_glibc_path)) {
|
|
|
|
|
return dbg_glibc_path;
|
|
|
|
|
}
|
|
|
|
|
return GH(get_libc_filename_from_maps) (core);
|
|
|
|
|
}
|
2024-02-24 11:33:40 +00:00
|
|
|
|
|
2024-02-14 13:38:40 +00:00
|
|
|
|
static bool GH(resolve_glibc_version)(RCore *core) {
|
|
|
|
|
r_return_val_if_fail (core && core->dbg && core->dbg->maps, false);
|
|
|
|
|
|
|
|
|
|
double version = 0;
|
|
|
|
|
|
|
|
|
|
if (core->dbg->glibc_version_resolved) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *dbg_glibc_version = r_config_get (core->config, "dbg.glibc.version");
|
|
|
|
|
if (R_STR_ISEMPTY (dbg_glibc_version)) {
|
|
|
|
|
dbg_glibc_version = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dbg_glibc_version) {
|
|
|
|
|
// TODO: use ^ and $ which appear to be broken
|
|
|
|
|
if (!r_regex_match ("\\d.\\d\\d", "e", dbg_glibc_version)) {
|
|
|
|
|
R_LOG_WARN ("resolve_glibc_version: Unexpected version format in dbg.glibc.version: %s"
|
|
|
|
|
" (expected format \"\\d.\\d\\d\")", dbg_glibc_version);
|
|
|
|
|
} else {
|
|
|
|
|
version = strtod (dbg_glibc_version, NULL);
|
|
|
|
|
core->dbg->glibc_version = (int) round ((version * 100));
|
|
|
|
|
core->dbg->glibc_version_d = version;
|
|
|
|
|
core->dbg->glibc_version_resolved = true;
|
|
|
|
|
R_LOG_INFO ("libc version %.2f set from dbg.glibc.version", core->dbg->glibc_version_d);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-24 11:33:40 +00:00
|
|
|
|
const char *libc_filename = GH(get_libc_filename_from_maps) (core);
|
2024-02-14 13:38:40 +00:00
|
|
|
|
|
2024-02-24 11:33:40 +00:00
|
|
|
|
if (!libc_filename) {
|
2024-02-14 13:38:40 +00:00
|
|
|
|
R_LOG_WARN ("resolve_glibc_version: no libc found in memory maps (cannot handle static binaries)");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// At this point we found a map in memory that _should_ be libc
|
2024-02-24 11:33:40 +00:00
|
|
|
|
version = GH (get_glibc_version) (core, libc_filename);
|
2024-02-14 13:38:40 +00:00
|
|
|
|
if (version != 0) {
|
|
|
|
|
core->dbg->glibc_version = (int) round ((version * 100));
|
|
|
|
|
core->dbg->glibc_version_d = version;
|
|
|
|
|
core->dbg->glibc_version_resolved = true;
|
|
|
|
|
char version_buffer[315] = {0};
|
|
|
|
|
// TODO: better way snprintf to 4 chars warns
|
|
|
|
|
// note: ‘snprintf’ output between 4 and 314 bytes into a destination of size 4
|
|
|
|
|
snprintf (version_buffer, sizeof (version_buffer)-1, "%.2f", version);
|
|
|
|
|
r_config_set (core->config, "dbg.glibc.version", version_buffer);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-05 20:22:38 +00:00
|
|
|
|
R_LOG_WARN ("Could not determine libc version");
|
2024-02-14 13:38:40 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool GH(is_tcache)(RCore *core) {
|
|
|
|
|
if (!r_config_get_b (core->config, "cfg.debug")) {
|
|
|
|
|
return r_config_get_b (core->config, "dbg.glibc.tcache");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (core->dbg->glibc_version_resolved || GH (resolve_glibc_version) (core)) {
|
|
|
|
|
return core->dbg->glibc_version_d > 2.25;
|
|
|
|
|
}
|
|
|
|
|
R_LOG_WARN ("is_tcache: glibc_version could not be resolved");
|
2023-04-10 10:54:51 +00:00
|
|
|
|
return false;
|
2020-03-19 14:26:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-26 05:27:36 +00:00
|
|
|
|
static GHT GH(tcache_chunk_size)(RCore *core, GHT brk_start) {
|
2020-06-18 10:14:21 +00:00
|
|
|
|
GH (RHeapChunk) *cnk = R_NEW0 (GH (RHeapChunk));
|
2023-04-10 10:54:51 +00:00
|
|
|
|
if (cnk) {
|
|
|
|
|
r_io_read_at (core->io, brk_start, (ut8 *)cnk, sizeof (GH (RHeapChunk)));
|
|
|
|
|
return (cnk->size >> 3) << 3; // clear chunk flag
|
2020-03-26 05:27:36 +00:00
|
|
|
|
}
|
2023-04-10 10:54:51 +00:00
|
|
|
|
return 0;
|
2020-03-26 05:27:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-20 20:15:30 +00:00
|
|
|
|
static void GH(update_arena_with_tc)(GH(RHeap_MallocState_227) *cmain_arena, MallocState *main_arena) {
|
2018-08-26 20:50:30 +00:00
|
|
|
|
int i = 0;
|
|
|
|
|
main_arena->mutex = cmain_arena->mutex;
|
|
|
|
|
main_arena->flags = cmain_arena->flags;
|
2018-10-19 23:23:15 +00:00
|
|
|
|
for (i = 0; i < BINMAPSIZE; i++) {
|
2018-08-26 20:50:30 +00:00
|
|
|
|
main_arena->binmap[i] = cmain_arena->binmap[i];
|
|
|
|
|
}
|
|
|
|
|
main_arena->have_fast_chunks = cmain_arena->have_fast_chunks;
|
|
|
|
|
main_arena->attached_threads = cmain_arena->attached_threads;
|
2018-10-19 23:23:15 +00:00
|
|
|
|
for (i = 0; i < NFASTBINS; i++) {
|
2020-06-18 10:14:21 +00:00
|
|
|
|
main_arena->GH (fastbinsY)[i] = cmain_arena->fastbinsY[i];
|
2018-08-26 20:50:30 +00:00
|
|
|
|
}
|
2020-06-18 10:14:21 +00:00
|
|
|
|
main_arena->GH (top) = cmain_arena->top;
|
|
|
|
|
main_arena->GH (last_remainder) = cmain_arena->last_remainder;
|
2018-10-19 23:23:15 +00:00
|
|
|
|
for (i = 0; i < NBINS * 2 - 2; i++) {
|
2020-06-18 10:14:21 +00:00
|
|
|
|
main_arena->GH (bins)[i] = cmain_arena->bins[i];
|
2018-08-26 20:50:30 +00:00
|
|
|
|
}
|
|
|
|
|
main_arena->GH(next) = cmain_arena->next;
|
|
|
|
|
main_arena->GH(next_free) = cmain_arena->next_free;
|
|
|
|
|
main_arena->GH(system_mem) = cmain_arena->system_mem;
|
|
|
|
|
main_arena->GH(max_system_mem) = cmain_arena->max_system_mem;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-20 20:15:30 +00:00
|
|
|
|
static void GH(update_arena_without_tc)(GH(RHeap_MallocState_223) *cmain_arena, MallocState *main_arena) {
|
2020-12-20 22:37:45 +00:00
|
|
|
|
size_t i = 0;
|
2018-08-26 20:50:30 +00:00
|
|
|
|
main_arena->mutex = cmain_arena->mutex;
|
|
|
|
|
main_arena->flags = cmain_arena->flags;
|
2020-03-23 15:25:55 +00:00
|
|
|
|
for (i = 0; i < BINMAPSIZE; i++) {
|
2018-08-26 20:50:30 +00:00
|
|
|
|
main_arena->binmap[i] = cmain_arena->binmap[i];
|
|
|
|
|
}
|
2018-09-17 00:00:39 +00:00
|
|
|
|
main_arena->attached_threads = 1;
|
2018-10-19 23:23:15 +00:00
|
|
|
|
for (i = 0; i < NFASTBINS; i++) {
|
2018-08-26 20:50:30 +00:00
|
|
|
|
main_arena->GH(fastbinsY)[i] = cmain_arena->fastbinsY[i];
|
|
|
|
|
}
|
|
|
|
|
main_arena->GH(top) = cmain_arena->top;
|
|
|
|
|
main_arena->GH(last_remainder) = cmain_arena->last_remainder;
|
2018-10-19 23:23:15 +00:00
|
|
|
|
for (i = 0; i < NBINS * 2 - 2; i++) {
|
2018-08-26 20:50:30 +00:00
|
|
|
|
main_arena->GH(bins)[i] = cmain_arena->bins[i];
|
|
|
|
|
}
|
|
|
|
|
main_arena->GH(next) = cmain_arena->next;
|
|
|
|
|
main_arena->GH(next_free) = cmain_arena->next_free;
|
|
|
|
|
main_arena->GH(system_mem) = cmain_arena->system_mem;
|
|
|
|
|
main_arena->GH(max_system_mem) = cmain_arena->max_system_mem;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-17 00:00:39 +00:00
|
|
|
|
static bool GH(update_main_arena)(RCore *core, GHT m_arena, MallocState *main_arena) {
|
2023-04-10 10:54:51 +00:00
|
|
|
|
const bool tcache = r_config_get_b (core->config, "dbg.glibc.tcache");
|
2018-08-26 20:50:30 +00:00
|
|
|
|
if (tcache) {
|
2024-03-20 20:15:30 +00:00
|
|
|
|
GH(RHeap_MallocState_227) *cmain_arena = R_NEW0 (GH(RHeap_MallocState_227));
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (!cmain_arena) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-06-13 15:35:36 +00:00
|
|
|
|
if (!r_io_read_at (core->io, m_arena, (ut8 *)cmain_arena, sizeof (GH(RHeap_MallocState_227)))) {
|
|
|
|
|
R_LOG_ERROR ("Cannot read");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-12-20 22:37:45 +00:00
|
|
|
|
GH(update_arena_with_tc)(cmain_arena, main_arena);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
} else {
|
2024-03-20 20:15:30 +00:00
|
|
|
|
GH(RHeap_MallocState_223) *cmain_arena = R_NEW0 (GH(RHeap_MallocState_223));
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (!cmain_arena) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-06-13 15:35:36 +00:00
|
|
|
|
if (!r_io_read_at (core->io, m_arena, (ut8 *)cmain_arena, sizeof (GH(RHeap_MallocState_223)))) {
|
|
|
|
|
R_LOG_ERROR ("Cannot read");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-12-20 22:37:45 +00:00
|
|
|
|
GH(update_arena_without_tc)(cmain_arena, main_arena);
|
2018-08-26 20:50:30 +00:00
|
|
|
|
}
|
2018-09-17 00:00:39 +00:00
|
|
|
|
return true;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void GH(get_brks)(RCore *core, GHT *brk_start, GHT *brk_end) {
|
2021-03-14 21:22:04 +00:00
|
|
|
|
if (r_config_get_b (core->config, "cfg.debug")) {
|
2018-09-25 16:59:05 +00:00
|
|
|
|
RListIter *iter;
|
|
|
|
|
RDebugMap *map;
|
|
|
|
|
r_debug_map_sync (core->dbg);
|
|
|
|
|
r_list_foreach (core->dbg->maps, iter, map) {
|
2023-04-10 10:54:51 +00:00
|
|
|
|
if (map->name && strstr (map->name, "[heap]")) {
|
|
|
|
|
*brk_start = map->addr;
|
|
|
|
|
*brk_end = map->addr_end;
|
|
|
|
|
break;
|
2018-09-25 16:59:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-10 10:54:51 +00:00
|
|
|
|
}
|
|
|
|
|
// coredump
|
|
|
|
|
RIOBank *bank = r_io_bank_get (core->io, core->io->bank);
|
|
|
|
|
if (!bank) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
RIOMapRef *mapref;
|
|
|
|
|
RListIter *iter;
|
|
|
|
|
r_list_foreach (bank->maprefs, iter, mapref) {
|
|
|
|
|
RIOMap *map = r_io_map_get (core->io, mapref->id);
|
|
|
|
|
if (map->name) {
|
|
|
|
|
if (strstr (map->name, "[heap]")) {
|
|
|
|
|
*brk_start = r_io_map_begin (map);
|
|
|
|
|
*brk_end = r_io_map_end (map);
|
|
|
|
|
break;
|
2018-09-25 16:59:05 +00:00
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-17 00:00:39 +00:00
|
|
|
|
static void GH(print_arena_stats)(RCore *core, GHT m_arena, MallocState *main_arena, GHT global_max_fast, int format) {
|
2020-04-12 18:45:24 +00:00
|
|
|
|
size_t i, j, k, start;
|
2018-08-26 20:50:30 +00:00
|
|
|
|
GHT align = 12 * SZ + sizeof (int) * 2;
|
2023-04-10 10:54:51 +00:00
|
|
|
|
const bool tcache = r_config_get_b (core->config, "dbg.glibc.tcache");
|
2019-04-27 08:55:18 +00:00
|
|
|
|
RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
|
|
|
|
|
|
2018-08-26 20:50:30 +00:00
|
|
|
|
if (tcache) {
|
|
|
|
|
align = 16;
|
|
|
|
|
}
|
2018-06-29 09:17:57 +00:00
|
|
|
|
|
2016-10-06 16:02:25 +00:00
|
|
|
|
GHT apart[NSMALLBINS + 1] = { 0LL };
|
|
|
|
|
if (format == '*') {
|
|
|
|
|
for (i = 0; i < NBINS * 2 - 2; i += 2) {
|
2018-08-26 20:50:30 +00:00
|
|
|
|
GHT addr = m_arena + align + SZ * i - SZ * 2;
|
|
|
|
|
GHT bina = main_arena->GH(bins)[i];
|
2023-04-10 10:54:51 +00:00
|
|
|
|
r_cons_printf ("f chunk.%zu.bin=0x%"PFMT64x"\n", i, (ut64)addr);
|
|
|
|
|
r_cons_printf ("f chunk.%zu.fd=0x%"PFMT64x"\n", i, (ut64)bina);
|
2018-08-26 20:50:30 +00:00
|
|
|
|
bina = main_arena->GH(bins)[i + 1];
|
2023-04-10 10:54:51 +00:00
|
|
|
|
r_cons_printf ("f chunk.%zu.bk=0x%"PFMT64x"\n", i, (ut64)bina);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < BINMAPSIZE; i++) {
|
2023-04-10 10:54:51 +00:00
|
|
|
|
r_cons_printf ("f binmap.%zu=0x%"PFMT64x, i, (ut64)main_arena->binmap[i]);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
{ /* maybe use SDB instead of flags for this? */
|
2018-11-14 22:35:44 +00:00
|
|
|
|
char units[8];
|
|
|
|
|
r_num_units (units, sizeof (units), main_arena->GH(max_system_mem));
|
2023-04-10 10:54:51 +00:00
|
|
|
|
r_cons_printf ("f heap.maxmem=%s\n", units);
|
2018-11-14 22:35:44 +00:00
|
|
|
|
|
|
|
|
|
r_num_units (units, sizeof (units), main_arena->GH(system_mem));
|
2023-04-10 10:54:51 +00:00
|
|
|
|
r_cons_printf ("f heap.sysmem=%s\n", units);
|
2018-11-14 22:35:44 +00:00
|
|
|
|
|
|
|
|
|
r_num_units (units, sizeof (units), main_arena->GH(next_free));
|
2023-04-10 10:54:51 +00:00
|
|
|
|
r_cons_printf ("f heap.nextfree=%s\n", units);
|
2018-11-14 22:35:44 +00:00
|
|
|
|
|
|
|
|
|
r_num_units (units, sizeof (units), main_arena->GH(next));
|
2023-04-10 10:54:51 +00:00
|
|
|
|
r_cons_printf ("f heap.next=%s\n", units);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PRINT_GA ("malloc_state @ ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x"\n\n", (ut64)m_arena);
|
|
|
|
|
PRINT_GA ("struct malloc_state main_arena {\n");
|
|
|
|
|
PRINT_GA (" mutex = ");
|
|
|
|
|
PRINTF_BA ("0x%08x\n", (ut32)main_arena->mutex);
|
|
|
|
|
PRINT_GA (" flags = ");
|
|
|
|
|
PRINTF_BA ("0x%08x\n", (ut32)main_arena->flags);
|
|
|
|
|
PRINT_GA (" fastbinsY = {\n");
|
|
|
|
|
|
2017-05-18 09:56:06 +00:00
|
|
|
|
for (i = 0, j = 1, k = SZ * 4; i < NFASTBINS; i++, j++, k += SZ * 2) {
|
2018-10-19 23:23:15 +00:00
|
|
|
|
if (FASTBIN_IDX_TO_SIZE (j) <= global_max_fast) {
|
2020-10-30 11:30:42 +00:00
|
|
|
|
PRINTF_YA (" Fastbin %02zu\n", j);
|
2017-05-18 09:56:06 +00:00
|
|
|
|
} else {
|
2020-10-30 11:30:42 +00:00
|
|
|
|
PRINTF_RA (" Fastbin %02zu\n", j);
|
2017-05-18 09:56:06 +00:00
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (" chunksize:");
|
2020-10-30 11:30:42 +00:00
|
|
|
|
PRINTF_BA (" == %04zu ", k);
|
2018-08-26 20:50:30 +00:00
|
|
|
|
PRINTF_GA ("0x%"PFMT64x, (ut64)main_arena->GH(fastbinsY)[i]);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (",\n");
|
|
|
|
|
}
|
|
|
|
|
PRINT_GA ("}\n");
|
|
|
|
|
PRINT_GA (" top = ");
|
2018-08-26 20:50:30 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)main_arena->GH(top));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (",\n");
|
|
|
|
|
PRINT_GA (" last_remainder = ");
|
2018-08-26 20:50:30 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)main_arena->GH(last_remainder));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (",\n");
|
|
|
|
|
PRINT_GA (" bins {\n");
|
|
|
|
|
|
|
|
|
|
/* Index & size for largebins */
|
|
|
|
|
start = SZ * 128;
|
|
|
|
|
for (i = start, k = 0, j = 0; j < NBINS - 2 && i < 1024 * 1024; i += 64) {
|
|
|
|
|
j = largebin_index (i);
|
|
|
|
|
if (j == k + NSMALLBINS + 1) {
|
|
|
|
|
apart[k++] = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (i = 0, j = 1, k = SZ * 4; i < NBINS * 2 - 2; i += 2, j++) {
|
2020-10-30 11:30:42 +00:00
|
|
|
|
PRINTF_YA (" Bin %03zu: ", j);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
if (j == 1) {
|
|
|
|
|
PRINT_GA ("Unsorted Bin");
|
|
|
|
|
PRINT_GA (" [");
|
|
|
|
|
PRINT_GA (" chunksize:");
|
|
|
|
|
PRINT_BA (" undefined ");
|
|
|
|
|
} else if (j > 1 && j <= NSMALLBINS) {
|
|
|
|
|
if (j == 2) {
|
|
|
|
|
PRINT_GA (" ┌");
|
|
|
|
|
} else if (j == (NSMALLBINS / 2)) {
|
|
|
|
|
PRINT_GA (" Small Bins │");
|
|
|
|
|
} else if (j != 2 && j != (NSMALLBINS / 2) && j != NSMALLBINS) {
|
|
|
|
|
PRINT_GA (" │");
|
|
|
|
|
} else {
|
|
|
|
|
PRINT_GA (" └");
|
|
|
|
|
}
|
|
|
|
|
PRINT_GA (" chunksize:");
|
2020-10-30 11:30:42 +00:00
|
|
|
|
PRINTF_BA (" == %06zu ", k);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
if (j < NSMALLBINS) {
|
|
|
|
|
k += SZ * 2;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (j == NSMALLBINS + 1) {
|
|
|
|
|
PRINT_GA (" ┌");
|
|
|
|
|
} else if (j == (NSMALLBINS / 2) * 3) {
|
|
|
|
|
PRINT_GA (" Large Bins │");
|
|
|
|
|
} else if (j != NSMALLBINS + 1 && j != (NSMALLBINS / 2) * 3 && j != NBINS - 1) {
|
|
|
|
|
PRINT_GA (" │");
|
|
|
|
|
} else {
|
|
|
|
|
PRINT_GA (" └");
|
|
|
|
|
}
|
|
|
|
|
PRINT_GA (" chunksize:");
|
|
|
|
|
if (j != NBINS - 1) {
|
2020-10-30 11:30:42 +00:00
|
|
|
|
PRINTF_BA (" >= %06"PFMT64d" ", (ut64)apart[j - NSMALLBINS - 1]);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
} else {
|
|
|
|
|
PRINT_BA (" remaining ");
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-08-26 20:50:30 +00:00
|
|
|
|
GHT bin = m_arena + align + SZ * i - SZ * 2;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINTF_GA ("0x%"PFMT64x"->fd = ", (ut64)bin);
|
2018-08-26 20:50:30 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)main_arena->GH(bins)[i]);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (", ");
|
|
|
|
|
PRINTF_GA ("0x%"PFMT64x"->bk = ", (ut64)bin);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)main_arena->GH(bins)[i + 1] );
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (", ");
|
|
|
|
|
r_cons_newline ();
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-13 19:21:34 +00:00
|
|
|
|
PRINT_GA ("}\n");
|
|
|
|
|
PRINT_GA (" binmap = { ");
|
2016-10-06 16:02:25 +00:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < BINMAPSIZE; i++) {
|
2017-08-07 10:47:48 +00:00
|
|
|
|
if (i) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (",");
|
|
|
|
|
}
|
2017-08-07 10:47:48 +00:00
|
|
|
|
PRINTF_BA ("0x%x", (ut32)main_arena->binmap[i]);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
PRINT_GA ("}\n");
|
|
|
|
|
PRINT_GA (" next = ");
|
2018-09-17 00:00:39 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)main_arena->GH(next));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (",\n");
|
|
|
|
|
PRINT_GA (" next_free = ");
|
2018-09-17 00:00:39 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)main_arena->GH(next_free));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (",\n");
|
|
|
|
|
PRINT_GA (" system_mem = ");
|
2018-09-17 00:00:39 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)main_arena->GH(system_mem));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (",\n");
|
|
|
|
|
PRINT_GA (" max_system_mem = ");
|
2018-09-17 00:00:39 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)main_arena->GH(max_system_mem));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (",\n");
|
|
|
|
|
PRINT_GA ("}\n\n");
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-20 20:15:30 +00:00
|
|
|
|
typedef struct GH(expected_arenas) {
|
|
|
|
|
GH(RHeap_MallocState_227) expected_227;
|
|
|
|
|
GH(RHeap_MallocState_223) expected_223;
|
|
|
|
|
GH(RHeap_MallocState_212) expected_212;
|
|
|
|
|
} GH(expected_arenas_s);
|
|
|
|
|
|
|
|
|
|
static GH(expected_arenas_s) GH (get_expected_main_arena_structures ) (RCore *core, GHT addend) {
|
|
|
|
|
GH(expected_arenas_s) expected_arenas = {
|
|
|
|
|
.expected_227 = {.next = addend, .attached_threads = 1},
|
|
|
|
|
.expected_223 = {.next = addend, .attached_threads = 1},
|
|
|
|
|
.expected_212 = {.next = addend}
|
|
|
|
|
};
|
|
|
|
|
return expected_arenas;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-05 20:22:38 +00:00
|
|
|
|
static GHT GH (get_main_arena_offset_with_relocs) (RCore *core, const char *libc_path) {
|
|
|
|
|
RBin *bin = core->bin;
|
|
|
|
|
RBinFile *bf = r_bin_cur (bin);
|
|
|
|
|
GHT main_arena = GHT_MAX;
|
|
|
|
|
RBinFileOptions opt;
|
|
|
|
|
r_bin_file_options_init (&opt, -1, 0, 0, false);
|
|
|
|
|
if (!r_bin_open (bin, libc_path, &opt)) {
|
|
|
|
|
R_LOG_WARN ("get_main_arena_with_relocs: Failed to open libc %s", libc_path);
|
|
|
|
|
return GHT_MAX;
|
|
|
|
|
}
|
|
|
|
|
RRBTree *relocs = r_bin_get_relocs (bin);
|
|
|
|
|
if (!relocs) {
|
|
|
|
|
R_LOG_WARN ("get_main_arena_with_relocs: Failed to get relocs from libc %s", libc_path);
|
|
|
|
|
return GHT_MAX;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get .data section to limit search
|
2024-05-12 23:30:08 +00:00
|
|
|
|
RList *section_list = r_bin_get_sections (bin);
|
2024-03-05 20:22:38 +00:00
|
|
|
|
RListIter *iter;
|
|
|
|
|
RBinSection *section;
|
|
|
|
|
RBinSection *data_section = NULL;
|
|
|
|
|
r_list_foreach (section_list, iter, section) {
|
|
|
|
|
if (!strcmp (section->name, ".data")) {
|
|
|
|
|
data_section = section;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!data_section) {
|
|
|
|
|
R_LOG_WARN ("get_main_arena_with_relocs: Failed to find .data section in %s", libc_path);
|
|
|
|
|
return GHT_MAX;
|
|
|
|
|
}
|
2024-03-20 20:15:30 +00:00
|
|
|
|
GH(section_content) libc_data = GH (get_section_content)(core, libc_path, ".data");
|
2024-03-05 20:22:38 +00:00
|
|
|
|
|
2024-03-20 20:15:30 +00:00
|
|
|
|
if (!core->dbg->glibc_version_resolved && !GH (resolve_glibc_version)(core)) {
|
|
|
|
|
R_LOG_WARN("get_main_arena_offset_with_relocs: glibc_version could not be resolved");
|
|
|
|
|
return GHT_MAX;
|
|
|
|
|
}
|
|
|
|
|
GHT next_field_offset = GHT_MAX;
|
|
|
|
|
GHT malloc_state_size = GHT_MAX;
|
|
|
|
|
|
|
|
|
|
if (core->dbg->glibc_version_d >= 2.27) {
|
|
|
|
|
next_field_offset = offsetof (GH(RHeap_MallocState_227), next);
|
|
|
|
|
malloc_state_size = sizeof (GH(RHeap_MallocState_227));
|
|
|
|
|
} else if (core->dbg->glibc_version_d >= 2.23) {
|
|
|
|
|
next_field_offset = offsetof (GH(RHeap_MallocState_223), next);
|
|
|
|
|
malloc_state_size = sizeof (GH(RHeap_MallocState_223));
|
|
|
|
|
} else if (core->dbg->glibc_version_d >= 2.12) {
|
|
|
|
|
next_field_offset = offsetof (GH(RHeap_MallocState_212), next);
|
|
|
|
|
malloc_state_size = sizeof (GH(RHeap_MallocState_212));
|
|
|
|
|
} else {
|
|
|
|
|
R_LOG_WARN ("get_main_arena_offset_with_relocs: cannot handle glibc version %.2f", core->dbg->glibc_version_d);
|
|
|
|
|
return GHT_MAX;
|
|
|
|
|
}
|
2024-03-05 20:22:38 +00:00
|
|
|
|
|
|
|
|
|
// Iterate over relocations and look for malloc_state structure
|
|
|
|
|
RRBNode *node;
|
|
|
|
|
RBinReloc *reloc;
|
2024-03-20 20:15:30 +00:00
|
|
|
|
|
2024-03-05 20:22:38 +00:00
|
|
|
|
r_crbtree_foreach (relocs, node, RBinReloc, reloc) {
|
|
|
|
|
// We only care about relocations in .data section
|
|
|
|
|
if (reloc->vaddr - next_field_offset < data_section->vaddr ||
|
|
|
|
|
reloc->vaddr > data_section->vaddr + data_section->size)
|
|
|
|
|
continue;
|
|
|
|
|
// If reloc->addend is the offset of main_arena, then reloc->vaddr should be the offset of main_arena.next
|
|
|
|
|
if (reloc->vaddr - next_field_offset == reloc->addend) {
|
|
|
|
|
// Candidate found, to be sure compare data with expected malloc_state
|
|
|
|
|
GHT search_start = reloc->addend - data_section->vaddr;
|
2024-03-20 20:15:30 +00:00
|
|
|
|
GH(expected_arenas_s) expected_arenas = GH(get_expected_main_arena_structures) (core, reloc->addend);
|
|
|
|
|
void *expected_p = NULL;
|
|
|
|
|
|
|
|
|
|
if (core->dbg->glibc_version_d >= 2.27) {
|
|
|
|
|
expected_p = (void *)&expected_arenas.expected_227;
|
|
|
|
|
} else if (core->dbg->glibc_version_d >= 2.23) {
|
|
|
|
|
expected_p = (void *)&expected_arenas.expected_223;
|
|
|
|
|
} else if (core->dbg->glibc_version_d >= 2.12) {
|
|
|
|
|
expected_p = (void *)&expected_arenas.expected_212;
|
|
|
|
|
} // else checked above
|
|
|
|
|
if (!memcmp (libc_data.buf + search_start, expected_p, malloc_state_size)) {
|
2024-03-05 20:22:38 +00:00
|
|
|
|
R_LOG_WARN ("Found main_arena offset with relocations");
|
|
|
|
|
main_arena = reloc->addend - data_section->vaddr;
|
|
|
|
|
break;
|
2024-03-20 20:15:30 +00:00
|
|
|
|
} else {
|
|
|
|
|
R_LOG_WARN ("get_main_arena_offset_with_relocs: main_arena candidate did not match");
|
2024-03-05 20:22:38 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RBinFile *libc_bf = r_bin_cur (bin);
|
|
|
|
|
r_bin_file_delete (bin, libc_bf->id);
|
|
|
|
|
r_bin_file_set_cur_binfile (bin, bf);
|
|
|
|
|
|
|
|
|
|
return main_arena;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-17 00:00:39 +00:00
|
|
|
|
static bool GH(r_resolve_main_arena)(RCore *core, GHT *m_arena) {
|
2020-06-18 10:14:21 +00:00
|
|
|
|
r_return_val_if_fail (core && core->dbg && core->dbg->maps, false);
|
|
|
|
|
|
|
|
|
|
if (core->dbg->main_arena_resolved) {
|
2024-03-02 21:59:54 +00:00
|
|
|
|
GHT dbg_glibc_main_arena = r_config_get_i (core->config, "dbg.glibc.main_arena");
|
|
|
|
|
if (!dbg_glibc_main_arena) {
|
|
|
|
|
R_LOG_ERROR ("core->dbg->main_arena_resolved is true but dbg.glibc.main_arena is NULL");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*m_arena = dbg_glibc_main_arena;
|
2020-06-18 10:14:21 +00:00
|
|
|
|
return true;
|
2017-05-18 09:56:06 +00:00
|
|
|
|
}
|
2018-09-21 22:11:22 +00:00
|
|
|
|
|
2024-02-14 13:38:40 +00:00
|
|
|
|
if (!GH (resolve_glibc_version) (core)) {
|
2024-03-05 20:22:38 +00:00
|
|
|
|
R_LOG_WARN ("r_resolve_main_arena: Could not resolve main glibc version!");
|
2024-02-14 13:38:40 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-21 22:11:22 +00:00
|
|
|
|
GHT brk_start = GHT_MAX, brk_end = GHT_MAX;
|
2018-10-19 23:23:15 +00:00
|
|
|
|
GHT libc_addr_sta = GHT_MAX, libc_addr_end = 0;
|
2024-03-05 20:22:38 +00:00
|
|
|
|
GHT main_arena_addr = GHT_MAX;
|
|
|
|
|
GHT main_arena_offset = GHT_MAX;
|
|
|
|
|
|
2023-05-24 08:32:10 +00:00
|
|
|
|
const bool in_debugger = r_config_get_b (core->config, "cfg.debug");
|
2018-09-21 22:11:22 +00:00
|
|
|
|
|
2023-05-24 08:32:10 +00:00
|
|
|
|
if (in_debugger) {
|
2024-03-05 20:22:38 +00:00
|
|
|
|
const char *libc_filename = GH(get_libc_filename) (core);
|
|
|
|
|
if (!libc_filename) {
|
|
|
|
|
R_LOG_WARN ("r_resolve_main_arena: Could not resolve libc filename");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
main_arena_offset = GH (get_main_arena_offset_with_symbol) (core, libc_filename);
|
|
|
|
|
if (main_arena_offset == GHT_MAX) {
|
|
|
|
|
main_arena_offset = GH (get_main_arena_offset_with_relocs) (core, libc_filename);
|
2023-10-06 10:06:37 +00:00
|
|
|
|
}
|
2024-03-05 20:22:38 +00:00
|
|
|
|
if (main_arena_offset == GHT_MAX) {
|
|
|
|
|
R_LOG_WARN ("Could not find main_arena via symbol or relocations");
|
|
|
|
|
// in this case fall back to bruteforce below
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-25 16:59:05 +00:00
|
|
|
|
RListIter *iter;
|
|
|
|
|
RDebugMap *map;
|
|
|
|
|
r_debug_map_sync (core->dbg);
|
|
|
|
|
r_list_foreach (core->dbg->maps, iter, map) {
|
2024-03-05 20:22:38 +00:00
|
|
|
|
if (map->perm == R_PERM_RW && strstr (map->name, libc_filename)) {
|
2018-09-25 16:59:05 +00:00
|
|
|
|
libc_addr_sta = map->addr;
|
|
|
|
|
libc_addr_end = map->addr_end;
|
2024-03-05 20:22:38 +00:00
|
|
|
|
if (main_arena_offset != GHT_MAX) {
|
|
|
|
|
main_arena_addr = map->addr + main_arena_offset;
|
|
|
|
|
}
|
2018-09-25 16:59:05 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2018-09-21 22:11:22 +00:00
|
|
|
|
}
|
2019-01-13 02:07:51 +00:00
|
|
|
|
} else {
|
2024-03-05 20:22:38 +00:00
|
|
|
|
// TODO: this is never hit unless libc version is set manually since it is resolved using `dm`
|
2021-10-25 20:53:58 +00:00
|
|
|
|
RIOBank *bank = r_io_bank_get (core->io, core->io->bank);
|
|
|
|
|
if (!bank) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
RIOMapRef *mapref;
|
|
|
|
|
RListIter *iter;
|
|
|
|
|
r_list_foreach (bank->maprefs, iter, mapref) {
|
|
|
|
|
RIOMap *map = r_io_map_get (core->io, mapref->id);
|
2019-05-02 09:53:03 +00:00
|
|
|
|
if (map->name && strstr (map->name, "arena")) {
|
2020-12-08 14:57:08 +00:00
|
|
|
|
libc_addr_sta = r_io_map_begin (map);
|
|
|
|
|
libc_addr_end = r_io_map_end (map);
|
2019-01-13 02:07:51 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-21 22:11:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (libc_addr_sta == GHT_MAX || libc_addr_end == GHT_MAX) {
|
2022-10-04 16:10:32 +00:00
|
|
|
|
const char *cmd = r_config_get_b (core->config, "cfg.debug")? "dm": "om";
|
|
|
|
|
R_LOG_WARN ("Can't find arena mapped in memory (see %s)", cmd);
|
2018-09-21 22:11:22 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GH(get_brks) (core, &brk_start, &brk_end);
|
|
|
|
|
if (brk_start == GHT_MAX || brk_end == GHT_MAX) {
|
2022-10-04 16:10:32 +00:00
|
|
|
|
R_LOG_ERROR ("No heap section found");
|
2018-10-19 00:02:38 +00:00
|
|
|
|
return false;
|
2018-09-21 22:11:22 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 10:54:51 +00:00
|
|
|
|
GHT addr_srch = libc_addr_sta;
|
|
|
|
|
GHT heap_sz = brk_end - brk_start;
|
2018-09-21 22:11:22 +00:00
|
|
|
|
MallocState *ta = R_NEW0 (MallocState);
|
2023-04-10 10:54:51 +00:00
|
|
|
|
if (R_UNLIKELY (!ta)) {
|
2018-09-21 22:11:22 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-06-18 10:14:21 +00:00
|
|
|
|
|
2024-03-05 20:22:38 +00:00
|
|
|
|
if (main_arena_addr != GHT_MAX) {
|
|
|
|
|
GH (update_main_arena) (core, main_arena_addr, ta);
|
|
|
|
|
*m_arena = main_arena_addr;
|
2020-06-18 10:14:21 +00:00
|
|
|
|
core->dbg->main_arena_resolved = true;
|
2024-03-02 21:59:54 +00:00
|
|
|
|
r_config_set_i (core->config, "dbg.glibc.main_arena", *m_arena);
|
2020-06-18 10:14:21 +00:00
|
|
|
|
free (ta);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2018-10-19 23:23:15 +00:00
|
|
|
|
while (addr_srch < libc_addr_end) {
|
2018-09-21 22:11:22 +00:00
|
|
|
|
GH (update_main_arena) (core, addr_srch, ta);
|
2022-08-18 12:37:29 +00:00
|
|
|
|
if (ta->GH(top) > brk_start && ta->GH(top) < brk_end &&
|
2018-09-21 22:11:22 +00:00
|
|
|
|
ta->GH(system_mem) == heap_sz) {
|
|
|
|
|
*m_arena = addr_srch;
|
|
|
|
|
free (ta);
|
2023-05-24 08:32:10 +00:00
|
|
|
|
if (in_debugger) {
|
2020-06-18 10:14:21 +00:00
|
|
|
|
core->dbg->main_arena_resolved = true;
|
|
|
|
|
}
|
2024-03-02 21:59:54 +00:00
|
|
|
|
r_config_set_i (core->config, "dbg.glibc.main_arena", *m_arena);
|
2024-03-05 20:22:38 +00:00
|
|
|
|
R_LOG_WARN ("Found main_arena offset with pattern matching");
|
2018-09-21 22:11:22 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
addr_srch += sizeof (GHT);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
2024-03-05 20:22:38 +00:00
|
|
|
|
R_LOG_WARN ("Cannot find main_arena");
|
2018-09-21 22:11:22 +00:00
|
|
|
|
free (ta);
|
2018-08-28 11:00:38 +00:00
|
|
|
|
return false;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void GH(print_heap_chunk)(RCore *core) {
|
|
|
|
|
GH(RHeapChunk) *cnk = R_NEW0 (GH(RHeapChunk));
|
|
|
|
|
if (!cnk) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-05-24 08:32:10 +00:00
|
|
|
|
GHT chunk = core->offset;
|
|
|
|
|
RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
|
2018-05-21 21:06:00 +00:00
|
|
|
|
(void) r_io_read_at (core->io, chunk, (ut8 *)cnk, sizeof (*cnk));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
|
|
|
|
|
PRINT_GA ("struct malloc_chunk @ ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)chunk);
|
2017-01-14 21:08:14 +00:00
|
|
|
|
PRINT_GA (" {\n prev_size = ");
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)cnk->prev_size);
|
|
|
|
|
PRINT_GA (",\n size = ");
|
2017-04-15 11:04:00 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)cnk->size & ~(NON_MAIN_ARENA | IS_MMAPPED | PREV_INUSE));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA(",\n flags: |N:");
|
2020-10-30 11:30:42 +00:00
|
|
|
|
PRINTF_BA("%1"PFMT64u, (ut64)(cnk->size & NON_MAIN_ARENA ) >> 2);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA(" |M:");
|
2020-10-30 11:30:42 +00:00
|
|
|
|
PRINTF_BA("%1"PFMT64u, (ut64)(cnk->size & IS_MMAPPED) >> 1);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA(" |P:");
|
2020-10-30 11:30:42 +00:00
|
|
|
|
PRINTF_BA("%1"PFMT64u, (ut64)cnk->size & PREV_INUSE);
|
2017-01-14 21:08:14 +00:00
|
|
|
|
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (",\n fd = ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)cnk->fd);
|
2017-01-14 21:08:14 +00:00
|
|
|
|
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (",\n bk = ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)cnk->bk);
|
2017-01-14 21:08:14 +00:00
|
|
|
|
|
2016-10-06 16:02:25 +00:00
|
|
|
|
if (cnk->size > SZ * 128) {
|
|
|
|
|
PRINT_GA (",\n fd-nextsize = ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64) cnk->fd_nextsize);
|
|
|
|
|
PRINT_GA (",\n bk-nextsize = ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64) cnk->bk_nextsize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PRINT_GA (",\n}\n");
|
|
|
|
|
GHT size = ((cnk->size >> 3) << 3) - SZ * 2;
|
|
|
|
|
if (size > SZ * 128) {
|
|
|
|
|
PRINT_GA ("chunk too big to be displayed\n");
|
|
|
|
|
size = SZ * 128;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *data = calloc (1, size);
|
|
|
|
|
if (data) {
|
2018-05-21 21:06:00 +00:00
|
|
|
|
r_io_read_at (core->io, chunk + SZ * 2, (ut8 *)data, size);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA ("chunk data = \n");
|
2017-06-06 00:20:49 +00:00
|
|
|
|
r_print_hexdump (core->print, chunk + SZ * 2, (ut8 *)data, size, SZ * 8, SZ, 1);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
free (data);
|
|
|
|
|
}
|
2017-04-15 11:03:49 +00:00
|
|
|
|
free (cnk);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-03-17 11:05:41 +00:00
|
|
|
|
static bool GH(is_arena)(RCore *core, GHT m_arena, GHT m_state) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (m_arena == m_state) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
MallocState *ta = R_NEW0 (MallocState);
|
|
|
|
|
if (!ta) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!GH(update_main_arena) (core, m_arena, ta)) {
|
|
|
|
|
free (ta);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (ta->GH(next) == m_state) {
|
|
|
|
|
free (ta);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
while (ta->GH(next) != GHT_MAX && ta->GH(next) != m_arena) {
|
|
|
|
|
if (!GH(update_main_arena) (core, ta->GH(next), ta)) {
|
|
|
|
|
free (ta);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (ta->GH(next) == m_state) {
|
|
|
|
|
free (ta);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free (ta);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-29 09:17:57 +00:00
|
|
|
|
static int GH(print_double_linked_list_bin_simple)(RCore *core, GHT bin, MallocState *main_arena, GHT brk_start) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
GHT next = GHT_MAX;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
int ret = 1;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
GH(RHeapChunk) *cnk = R_NEW0 (GH(RHeapChunk));
|
2019-04-27 08:55:18 +00:00
|
|
|
|
RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
|
2017-01-14 21:08:14 +00:00
|
|
|
|
|
2016-10-06 16:02:25 +00:00
|
|
|
|
if (!cnk) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-21 21:06:00 +00:00
|
|
|
|
r_io_read_at (core->io, bin, (ut8 *)cnk, sizeof (GH(RHeapChunk)));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
|
|
|
|
|
PRINTF_GA (" 0x%"PFMT64x, (ut64)bin);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (cnk->fd != bin) {
|
|
|
|
|
ret = 0;
|
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
while (cnk->fd != bin) {
|
|
|
|
|
PRINTF_BA ("->fd = 0x%"PFMT64x, (ut64)cnk->fd);
|
|
|
|
|
next = cnk->fd;
|
2018-08-26 20:50:30 +00:00
|
|
|
|
if (next < brk_start || next > main_arena->GH(top)) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_RA ("Double linked list corrupted\n");
|
|
|
|
|
free (cnk);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2018-05-21 21:06:00 +00:00
|
|
|
|
r_io_read_at (core->io, next, (ut8 *)cnk, sizeof (GH(RHeapChunk)));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PRINTF_GA ("->fd = 0x%"PFMT64x, (ut64)cnk->fd);
|
|
|
|
|
next = cnk->fd;
|
|
|
|
|
|
|
|
|
|
if (next != bin) {
|
|
|
|
|
PRINT_RA ("Double linked list corrupted\n");
|
|
|
|
|
free (cnk);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2018-05-21 21:06:00 +00:00
|
|
|
|
(void)r_io_read_at (core->io, next, (ut8 *)cnk, sizeof (GH(RHeapChunk)));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINTF_GA ("\n 0x%"PFMT64x, (ut64)bin);
|
|
|
|
|
|
|
|
|
|
while (cnk->bk != bin) {
|
|
|
|
|
PRINTF_BA ("->bk = 0x%"PFMT64x, (ut64) cnk->bk);
|
|
|
|
|
next = cnk->bk;
|
2018-08-26 20:50:30 +00:00
|
|
|
|
if (next < brk_start || next > main_arena->GH(top)) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_RA ("Double linked list corrupted.\n");
|
|
|
|
|
free (cnk);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2018-05-21 21:06:00 +00:00
|
|
|
|
(void)r_io_read_at (core->io, next, (ut8 *)cnk, sizeof (GH(RHeapChunk)));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PRINTF_GA ("->bk = 0x%"PFMT64x, (ut64)cnk->bk);
|
|
|
|
|
free (cnk);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
return ret;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-29 09:17:57 +00:00
|
|
|
|
static int GH(print_double_linked_list_bin_graph)(RCore *core, GHT bin, MallocState *main_arena, GHT brk_start) {
|
2018-03-07 21:14:12 +00:00
|
|
|
|
RAGraph *g = r_agraph_new (r_cons_canvas_new (1, 1));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
GHT next = GHT_MAX;
|
|
|
|
|
char title[256], chunk[256];
|
2017-01-14 21:08:14 +00:00
|
|
|
|
RANode *bin_node = NULL, *prev_node = NULL, *next_node = NULL;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
GH(RHeapChunk) *cnk = R_NEW0 (GH(RHeapChunk));
|
2019-04-27 08:55:18 +00:00
|
|
|
|
RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
|
|
|
|
|
if (!cnk || !g) {
|
|
|
|
|
free (cnk);
|
2016-10-20 13:02:25 +00:00
|
|
|
|
r_agraph_free (g);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
2016-10-20 13:02:25 +00:00
|
|
|
|
g->can->color = r_config_get_i (core->config, "scr.color");
|
2016-10-06 16:02:25 +00:00
|
|
|
|
|
2018-05-21 21:06:00 +00:00
|
|
|
|
(void)r_io_read_at (core->io, bin, (ut8 *)cnk, sizeof (GH(RHeapChunk)));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
snprintf (title, sizeof (title) - 1, "bin @ 0x%"PFMT64x"\n", (ut64)bin);
|
|
|
|
|
snprintf (chunk, sizeof (chunk) - 1, "fd: 0x%"PFMT64x"\nbk: 0x%"PFMT64x"\n",
|
2017-01-14 21:08:14 +00:00
|
|
|
|
(ut64)cnk->fd, (ut64)cnk->bk);
|
2021-02-10 09:41:54 +00:00
|
|
|
|
bin_node = r_agraph_add_node (g, title, chunk, NULL);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
prev_node = bin_node;
|
|
|
|
|
|
|
|
|
|
while (cnk->bk != bin) {
|
|
|
|
|
next = cnk->bk;
|
2018-08-26 20:50:30 +00:00
|
|
|
|
if (next < brk_start || next > main_arena->GH(top)) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_RA ("Double linked list corrupted\n");
|
|
|
|
|
free (cnk);
|
|
|
|
|
free (g);
|
|
|
|
|
return -1;
|
2017-01-14 21:08:14 +00:00
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
|
2018-05-21 21:06:00 +00:00
|
|
|
|
r_io_read_at (core->io, next, (ut8 *)cnk, sizeof (GH(RHeapChunk)));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
snprintf (title, sizeof (title) - 1, "Chunk @ 0x%"PFMT64x"\n", (ut64)next);
|
|
|
|
|
snprintf (chunk, sizeof (chunk) - 1, "fd: 0x%"PFMT64x"\nbk: 0x%"PFMT64x"\n",
|
|
|
|
|
(ut64)cnk->fd, (ut64)cnk->bk);
|
2021-02-10 09:41:54 +00:00
|
|
|
|
next_node = r_agraph_add_node (g, title, chunk, NULL);
|
2021-02-28 14:32:43 +00:00
|
|
|
|
r_agraph_add_edge (g, prev_node, next_node, false);
|
|
|
|
|
r_agraph_add_edge (g, next_node, prev_node, false);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
prev_node = next_node;
|
|
|
|
|
}
|
2017-01-14 21:08:14 +00:00
|
|
|
|
|
2021-02-28 14:32:43 +00:00
|
|
|
|
r_agraph_add_edge (g, prev_node, bin_node, false);
|
|
|
|
|
r_agraph_add_edge (g, bin_node, prev_node, false);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
r_agraph_print (g);
|
|
|
|
|
|
|
|
|
|
free (cnk);
|
|
|
|
|
r_agraph_free (g);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-29 09:17:57 +00:00
|
|
|
|
static int GH(print_double_linked_list_bin)(RCore *core, MallocState *main_arena, GHT m_arena, GHT offset, GHT num_bin, int graph) {
|
2023-05-24 08:32:10 +00:00
|
|
|
|
r_return_val_if_fail (core && core->dbg, -1);
|
|
|
|
|
if (!core->dbg->maps) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
return -1;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
2017-01-14 21:08:14 +00:00
|
|
|
|
int ret = 0;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
GHT brk_start = GHT_MAX, brk_end = GHT_MAX, initial_brk = GHT_MAX;
|
2019-04-27 08:55:18 +00:00
|
|
|
|
RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
|
2018-02-18 02:19:33 +00:00
|
|
|
|
if (num_bin > 126) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
2018-08-26 20:50:30 +00:00
|
|
|
|
GHT bin = main_arena->GH(bins)[num_bin];
|
2017-01-14 21:08:14 +00:00
|
|
|
|
|
2016-10-06 16:02:25 +00:00
|
|
|
|
if (!bin) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GH(get_brks) (core, &brk_start, &brk_end);
|
|
|
|
|
if (brk_start == GHT_MAX || brk_end == GHT_MAX) {
|
2022-10-04 16:10:32 +00:00
|
|
|
|
R_LOG_ERROR ("No heap section found");
|
2017-01-14 21:08:14 +00:00
|
|
|
|
return -1;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-10 10:54:51 +00:00
|
|
|
|
const bool tcache = r_config_get_b (core->config, "dbg.glibc.tcache");
|
2018-09-03 08:43:33 +00:00
|
|
|
|
if (tcache) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
const int fc_offset = r_config_get_i (core->config, "dbg.glibc.fc_offset");
|
2018-09-03 08:43:33 +00:00
|
|
|
|
bin = m_arena + offset + SZ * num_bin * 2 + 10 * SZ;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
initial_brk = ( (brk_start >> 12) << 12 ) + fc_offset;
|
2018-09-03 08:43:33 +00:00
|
|
|
|
} else {
|
|
|
|
|
bin = m_arena + offset + SZ * num_bin * 2 - SZ * 2;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
initial_brk = (brk_start >> 12) << 12;
|
2018-09-03 08:43:33 +00:00
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
|
2023-05-24 08:32:10 +00:00
|
|
|
|
if (num_bin == 0) {
|
|
|
|
|
PRINT_GA (" double linked list unsorted bin {\n");
|
|
|
|
|
} else if (num_bin > 0 && num_bin < NSMALLBINS) {
|
|
|
|
|
PRINT_GA (" double linked list small bin {\n");
|
|
|
|
|
} else if (num_bin >= NSMALLBINS && num_bin < NBINS - 2) {
|
|
|
|
|
PRINT_GA (" double linked list large bin {\n");
|
|
|
|
|
} else {
|
|
|
|
|
// ???
|
|
|
|
|
}
|
|
|
|
|
#if 0
|
2016-10-06 16:02:25 +00:00
|
|
|
|
switch (num_bin) {
|
|
|
|
|
case 0:
|
|
|
|
|
PRINT_GA (" double linked list unsorted bin {\n");
|
|
|
|
|
break;
|
|
|
|
|
case 1 ... NSMALLBINS - 1:
|
|
|
|
|
PRINT_GA (" double linked list small bin {\n");
|
|
|
|
|
break;
|
|
|
|
|
case NSMALLBINS ... NBINS - 2:
|
|
|
|
|
PRINT_GA (" double linked list large bin {\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2023-05-24 08:32:10 +00:00
|
|
|
|
#endif
|
|
|
|
|
if (graph < 2) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
ret = GH(print_double_linked_list_bin_simple)(core, bin, main_arena, initial_brk);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
} else {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
ret = GH(print_double_linked_list_bin_graph)(core, bin, main_arena, initial_brk);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
PRINT_GA ("\n }\n");
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-29 09:17:57 +00:00
|
|
|
|
static void GH(print_heap_bin)(RCore *core, GHT m_arena, MallocState *main_arena, const char *input) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
int i, j = 2;
|
|
|
|
|
GHT num_bin = GHT_MAX;
|
2018-09-03 09:06:32 +00:00
|
|
|
|
GHT offset;
|
2019-04-27 08:55:18 +00:00
|
|
|
|
RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
|
2018-06-29 09:17:57 +00:00
|
|
|
|
|
2023-04-10 10:54:51 +00:00
|
|
|
|
const bool tcache = r_config_get_b (core->config, "dbg.glibc.tcache");
|
2018-09-03 08:43:33 +00:00
|
|
|
|
if (tcache) {
|
2018-09-03 09:06:32 +00:00
|
|
|
|
offset = 16;
|
2018-09-03 08:43:33 +00:00
|
|
|
|
} else {
|
2018-09-03 09:06:32 +00:00
|
|
|
|
offset = 12 * SZ + sizeof (int) * 2;
|
2018-09-03 08:43:33 +00:00
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
|
|
|
|
|
switch (input[0]) {
|
|
|
|
|
case '\0': // dmhb
|
|
|
|
|
PRINT_YA ("Bins {\n");
|
|
|
|
|
for (i = 0; i < NBINS - 1; i++) {
|
|
|
|
|
PRINTF_YA (" Bin %03d:\n", i + 1);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
GH(print_double_linked_list_bin) (core, main_arena, m_arena, offset, i, 0);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
PRINT_YA ("\n}\n");
|
|
|
|
|
break;
|
|
|
|
|
case ' ': // dmhb [bin_num]
|
|
|
|
|
j--; // for spaces after input
|
2021-12-13 22:06:22 +00:00
|
|
|
|
// fallthrough
|
2016-10-06 16:02:25 +00:00
|
|
|
|
case 'g': // dmhbg [bin_num]
|
2023-04-10 10:54:51 +00:00
|
|
|
|
num_bin = r_num_math (core->num, input + j) - 1;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
if (num_bin > NBINS - 2) {
|
2022-06-28 00:49:42 +00:00
|
|
|
|
R_LOG_ERROR ("0 < bin <= %d", NBINS - 1);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2020-10-30 11:30:42 +00:00
|
|
|
|
PRINTF_YA (" Bin %03"PFMT64u":\n", (ut64)num_bin + 1);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
GH(print_double_linked_list_bin) (core, main_arena, m_arena, offset, num_bin, j);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
break;
|
2023-05-24 08:32:10 +00:00
|
|
|
|
case 'j':
|
|
|
|
|
default:
|
|
|
|
|
// unknown subcommand
|
|
|
|
|
R_LOG_ERROR ("Unknown subcommand");
|
|
|
|
|
break;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-24 08:32:10 +00:00
|
|
|
|
// TODO. return bool
|
2020-08-31 16:45:12 +00:00
|
|
|
|
static int GH(print_single_linked_list_bin)(RCore *core, MallocState *main_arena, GHT m_arena, GHT offset, GHT bin_num, bool demangle) {
|
2023-05-24 08:32:10 +00:00
|
|
|
|
r_return_val_if_fail (core && core->dbg, -1);
|
|
|
|
|
if (!core->dbg->maps) {
|
2018-09-08 10:29:31 +00:00
|
|
|
|
return -1;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
GHT next = GHT_MAX, brk_start = GHT_MAX, brk_end = GHT_MAX;
|
2019-04-27 08:55:18 +00:00
|
|
|
|
RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
|
2018-09-08 10:29:31 +00:00
|
|
|
|
|
|
|
|
|
GH(RHeapChunk) *cnk = R_NEW0 (GH(RHeapChunk));
|
|
|
|
|
if (!cnk) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (!GH(update_main_arena) (core, m_arena, main_arena)) {
|
|
|
|
|
free (cnk);
|
|
|
|
|
return 0;
|
2018-09-08 10:29:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-08-26 20:50:30 +00:00
|
|
|
|
GHT bin = main_arena->GH(fastbinsY)[bin_num];
|
2016-10-06 16:02:25 +00:00
|
|
|
|
if (!bin) {
|
2021-10-28 17:59:10 +00:00
|
|
|
|
free (cnk);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
bin = m_arena + offset + SZ * bin_num;
|
2018-05-21 21:06:00 +00:00
|
|
|
|
r_io_read_at (core->io, bin, (ut8 *)&next, SZ);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
|
2020-03-26 05:27:36 +00:00
|
|
|
|
GH(get_brks) (core, &brk_start, &brk_end);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
if (brk_start == GHT_MAX || brk_end == GHT_MAX) {
|
2022-10-04 16:10:32 +00:00
|
|
|
|
R_LOG_ERROR ("No heap section found");
|
2016-10-06 16:02:25 +00:00
|
|
|
|
free (cnk);
|
2017-01-14 21:08:14 +00:00
|
|
|
|
return 0;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-10-30 11:30:42 +00:00
|
|
|
|
PRINTF_GA (" fastbin %"PFMT64d" @ ", (ut64)bin_num + 1);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINTF_GA ("0x%"PFMT64x" {\n ", (ut64)bin);
|
|
|
|
|
|
2018-08-26 20:50:30 +00:00
|
|
|
|
GHT size = main_arena->GH(top) - brk_start;
|
2018-06-29 09:17:57 +00:00
|
|
|
|
|
2016-10-06 16:02:25 +00:00
|
|
|
|
GHT next_root = next, next_tmp = next, double_free = GHT_MAX;
|
2018-08-26 20:50:30 +00:00
|
|
|
|
while (next && next >= brk_start && next < main_arena->GH(top)) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)next);
|
2018-08-26 20:50:30 +00:00
|
|
|
|
while (double_free == GHT_MAX && next_tmp && next_tmp >= brk_start && next_tmp <= main_arena->GH(top)) {
|
2018-05-21 21:06:00 +00:00
|
|
|
|
r_io_read_at (core->io, next_tmp, (ut8 *)cnk, sizeof (GH(RHeapChunk)));
|
2020-08-31 16:45:12 +00:00
|
|
|
|
next_tmp = (!demangle) ? cnk->fd : PROTECT_PTR (next_tmp, cnk->fd);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
if (cnk->prev_size > size || ((cnk->size >> 3) << 3) > size) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (next_root == next_tmp) {
|
|
|
|
|
double_free = next_root;
|
2017-01-14 21:08:14 +00:00
|
|
|
|
break;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-05-21 21:06:00 +00:00
|
|
|
|
r_io_read_at (core->io, next, (ut8 *)cnk, sizeof (GH(RHeapChunk)));
|
2020-08-31 16:45:12 +00:00
|
|
|
|
next = (!demangle) ? cnk->fd : PROTECT_PTR (next, cnk->fd);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINTF_BA ("%s", next ? "->fd = " : "");
|
|
|
|
|
if (cnk->prev_size > size || ((cnk->size >> 3) << 3) > size) {
|
|
|
|
|
PRINTF_RA (" 0x%"PFMT64x, (ut64)next);
|
|
|
|
|
PRINT_RA (" Linked list corrupted\n");
|
|
|
|
|
PRINT_GA ("\n }\n");
|
|
|
|
|
free (cnk);
|
2017-01-14 21:08:14 +00:00
|
|
|
|
return -1;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
next_root = next_tmp = next;
|
|
|
|
|
if (double_free == next) {
|
|
|
|
|
PRINTF_RA ("0x%"PFMT64x, (ut64)next);
|
|
|
|
|
PRINT_RA (" Double free detected\n");
|
|
|
|
|
PRINT_GA ("\n }\n");
|
|
|
|
|
free (cnk);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-26 20:50:30 +00:00
|
|
|
|
if (next && (next < brk_start || next >= main_arena->GH(top))) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINTF_RA ("0x%"PFMT64x, (ut64)next);
|
|
|
|
|
PRINT_RA (" Linked list corrupted\n");
|
|
|
|
|
PRINT_GA ("\n }\n");
|
|
|
|
|
free (cnk);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2017-01-14 21:08:14 +00:00
|
|
|
|
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA ("\n }\n");
|
|
|
|
|
free (cnk);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-31 16:45:12 +00:00
|
|
|
|
void GH(print_heap_fastbin)(RCore *core, GHT m_arena, MallocState *main_arena, GHT global_max_fast, const char *input, bool demangle) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
int i;
|
2018-08-26 20:50:30 +00:00
|
|
|
|
GHT num_bin = GHT_MAX, offset = sizeof (int) * 2;
|
2023-04-10 10:54:51 +00:00
|
|
|
|
const bool tcache = r_config_get_b (core->config, "dbg.glibc.tcache");
|
2019-04-27 08:55:18 +00:00
|
|
|
|
RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
|
|
|
|
|
|
2018-08-26 20:50:30 +00:00
|
|
|
|
if (tcache) {
|
|
|
|
|
offset = 16;
|
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
|
|
|
|
|
switch (input[0]) {
|
|
|
|
|
case '\0': // dmhf
|
2018-09-08 10:29:31 +00:00
|
|
|
|
if (core->offset != core->prompt_offset) {
|
|
|
|
|
m_arena = core->offset;
|
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_YA ("fastbinY {\n");
|
|
|
|
|
for (i = 1; i <= NFASTBINS; i++) {
|
2017-05-18 09:56:06 +00:00
|
|
|
|
if (FASTBIN_IDX_TO_SIZE(i) <= global_max_fast) {
|
|
|
|
|
PRINTF_YA (" Fastbin %02d\n", i);
|
|
|
|
|
} else {
|
|
|
|
|
PRINTF_RA (" Fastbin %02d\n", i);
|
|
|
|
|
}
|
2020-08-31 16:45:12 +00:00
|
|
|
|
if (GH(print_single_linked_list_bin) (core, main_arena, m_arena, offset, i - 1, demangle)) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (" Empty bin");
|
|
|
|
|
PRINT_BA (" 0x0\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PRINT_YA ("}\n");
|
|
|
|
|
break;
|
|
|
|
|
case ' ': // dmhf [bin_num]
|
2023-04-10 10:54:51 +00:00
|
|
|
|
num_bin = r_num_get (core->num, input) - 1;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
if (num_bin >= NFASTBINS) {
|
2022-06-28 00:49:42 +00:00
|
|
|
|
R_LOG_ERROR ("0 < bin <= %d", NFASTBINS);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2020-08-31 16:45:12 +00:00
|
|
|
|
if (GH(print_single_linked_list_bin)(core, main_arena, m_arena, offset, num_bin, demangle)) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_GA (" Empty bin");
|
|
|
|
|
PRINT_BA (" 0x0\n");
|
|
|
|
|
}
|
|
|
|
|
break;
|
2023-05-24 08:32:10 +00:00
|
|
|
|
case 'j': // TODO implement json listing with PJ
|
|
|
|
|
default:
|
|
|
|
|
R_LOG_ERROR ("Unknown subcommand");
|
|
|
|
|
break;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-08 12:16:27 +00:00
|
|
|
|
static GH (RTcache)* GH (tcache_new) (RCore *core) {
|
|
|
|
|
r_return_val_if_fail (core, NULL);
|
|
|
|
|
GH (RTcache) *tcache = R_NEW0 (GH (RTcache));
|
2023-04-10 10:54:51 +00:00
|
|
|
|
if (R_UNLIKELY (!tcache)) {
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-07-08 12:16:27 +00:00
|
|
|
|
if (core->dbg->glibc_version >= TCACHE_NEW_VERSION) {
|
|
|
|
|
tcache->type = NEW;
|
2023-02-08 22:02:28 +00:00
|
|
|
|
tcache->RHeapTcache.heap_tcache = R_NEW0 (GH (RHeapTcache));
|
2020-07-08 12:16:27 +00:00
|
|
|
|
} else {
|
|
|
|
|
tcache->type = OLD;
|
2023-02-08 22:02:28 +00:00
|
|
|
|
tcache->RHeapTcache.heap_tcache_pre_230 = R_NEW0 (GH (RHeapTcachePre230));
|
2020-07-08 12:16:27 +00:00
|
|
|
|
}
|
|
|
|
|
return tcache;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void GH (tcache_free) (GH (RTcache)* tcache) {
|
|
|
|
|
r_return_if_fail (tcache);
|
|
|
|
|
tcache->type == NEW
|
2022-08-18 00:40:08 +00:00
|
|
|
|
? free (tcache->RHeapTcache.heap_tcache)
|
|
|
|
|
: free (tcache->RHeapTcache.heap_tcache_pre_230);
|
|
|
|
|
free (tcache);
|
2020-07-08 12:16:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool GH (tcache_read) (RCore *core, GHT tcache_start, GH (RTcache)* tcache) {
|
|
|
|
|
r_return_val_if_fail (core && tcache, false);
|
2024-06-13 15:35:36 +00:00
|
|
|
|
if ((st64)(tcache_start | UT16_MAX) <1) {
|
|
|
|
|
R_LOG_ERROR ("Cannot read at 0x%08"PFMT64x, (ut64)tcache_start);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!r_io_is_valid_offset (core->io, tcache_start, R_PERM_R)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2020-07-08 12:16:27 +00:00
|
|
|
|
return tcache->type == NEW
|
|
|
|
|
? r_io_read_at (core->io, tcache_start, (ut8 *)tcache->RHeapTcache.heap_tcache, sizeof (GH (RHeapTcache)))
|
|
|
|
|
: r_io_read_at (core->io, tcache_start, (ut8 *)tcache->RHeapTcache.heap_tcache_pre_230, sizeof (GH (RHeapTcachePre230)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int GH (tcache_get_count) (GH (RTcache)* tcache, int index) {
|
|
|
|
|
r_return_val_if_fail (tcache, 0);
|
|
|
|
|
return tcache->type == NEW
|
|
|
|
|
? tcache->RHeapTcache.heap_tcache->counts[index]
|
|
|
|
|
: tcache->RHeapTcache.heap_tcache_pre_230->counts[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GHT GH (tcache_get_entry) (GH (RTcache)* tcache, int index) {
|
|
|
|
|
r_return_val_if_fail (tcache, 0);
|
|
|
|
|
return tcache->type == NEW
|
|
|
|
|
? tcache->RHeapTcache.heap_tcache->entries[index]
|
|
|
|
|
: tcache->RHeapTcache.heap_tcache_pre_230->entries[index];
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-31 16:45:12 +00:00
|
|
|
|
static void GH (tcache_print) (RCore *core, GH (RTcache)* tcache, bool demangle) {
|
2020-07-08 12:16:27 +00:00
|
|
|
|
r_return_if_fail (core && tcache);
|
|
|
|
|
GHT tcache_fd = GHT_MAX;
|
|
|
|
|
GHT tcache_tmp = GHT_MAX;
|
|
|
|
|
RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
|
|
|
|
|
size_t i;
|
|
|
|
|
for (i = 0; i < TCACHE_MAX_BINS; i++) {
|
|
|
|
|
int count = GH (tcache_get_count) (tcache, i);
|
|
|
|
|
GHT entry = GH (tcache_get_entry) (tcache, i);
|
2020-12-20 22:37:45 +00:00
|
|
|
|
if (entry == GHT_MAX) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-07-08 12:16:27 +00:00
|
|
|
|
if (count > 0) {
|
|
|
|
|
PRINT_GA ("bin :");
|
2020-10-30 11:30:42 +00:00
|
|
|
|
PRINTF_BA ("%2zu", i);
|
2020-07-08 12:16:27 +00:00
|
|
|
|
PRINT_GA (", items :");
|
|
|
|
|
PRINTF_BA ("%2d", count);
|
|
|
|
|
PRINT_GA (", fd :");
|
|
|
|
|
|
2020-10-30 11:30:42 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)(entry - GH (HDR_SZ)));
|
2020-07-08 12:16:27 +00:00
|
|
|
|
if (count > 1) {
|
|
|
|
|
tcache_fd = entry;
|
|
|
|
|
size_t n;
|
|
|
|
|
for (n = 1; n < count; n++) {
|
|
|
|
|
bool r = r_io_read_at (core->io, tcache_fd, (ut8 *)&tcache_tmp, sizeof (GHT));
|
|
|
|
|
if (!r) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-08-31 16:45:12 +00:00
|
|
|
|
tcache_tmp = (!demangle)
|
|
|
|
|
? read_le (&tcache_tmp)
|
|
|
|
|
: PROTECT_PTR (tcache_fd, read_le (&tcache_tmp));
|
2020-10-30 11:30:42 +00:00
|
|
|
|
PRINTF_BA ("->0x%"PFMT64x, (ut64)(tcache_tmp - TC_HDR_SZ));
|
2020-07-08 12:16:27 +00:00
|
|
|
|
tcache_fd = tcache_tmp;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
PRINT_BA ("\n");
|
|
|
|
|
}
|
2018-08-26 20:50:30 +00:00
|
|
|
|
}
|
2020-07-08 12:16:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-08-31 16:45:12 +00:00
|
|
|
|
static void GH (print_tcache_instance)(RCore *core, GHT m_arena, MallocState *main_arena, bool demangle) {
|
2020-07-08 12:16:27 +00:00
|
|
|
|
r_return_if_fail (core && core->dbg && core->dbg->maps);
|
|
|
|
|
|
2023-04-10 10:54:51 +00:00
|
|
|
|
const bool tcache = r_config_get_b (core->config, "dbg.glibc.tcache");
|
2020-12-20 22:37:45 +00:00
|
|
|
|
if (!tcache || m_arena == GHT_MAX) {
|
2018-08-26 20:50:30 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2020-07-08 12:16:27 +00:00
|
|
|
|
GHT brk_start = GHT_MAX, brk_end = GHT_MAX, initial_brk = GHT_MAX;
|
|
|
|
|
GH (get_brks) (core, &brk_start, &brk_end);
|
|
|
|
|
GHT tcache_start = GHT_MAX;
|
2019-04-27 08:55:18 +00:00
|
|
|
|
RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
|
|
|
|
|
|
2020-07-08 12:16:27 +00:00
|
|
|
|
tcache_start = brk_start + 0x10;
|
|
|
|
|
GHT fc_offset = GH (tcache_chunk_size) (core, brk_start);
|
2020-03-26 05:27:36 +00:00
|
|
|
|
initial_brk = brk_start + fc_offset;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (brk_start == GHT_MAX || brk_end == GHT_MAX || initial_brk == GHT_MAX) {
|
2022-10-04 16:10:32 +00:00
|
|
|
|
R_LOG_ERROR ("No heap section found");
|
2018-06-29 09:17:57 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-08 12:16:27 +00:00
|
|
|
|
GH (RTcache)* r_tcache = GH (tcache_new) (core);
|
|
|
|
|
if (!r_tcache) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!GH (tcache_read) (core, tcache_start, r_tcache)) {
|
2018-09-03 00:49:46 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2018-06-29 09:17:57 +00:00
|
|
|
|
|
2020-12-20 22:37:45 +00:00
|
|
|
|
PRINT_GA ("Tcache main arena @");
|
2018-09-05 09:24:41 +00:00
|
|
|
|
PRINTF_BA (" 0x%"PFMT64x"\n", (ut64)m_arena);
|
2020-08-31 16:45:12 +00:00
|
|
|
|
GH (tcache_print) (core, r_tcache, demangle);
|
2018-09-03 00:49:46 +00:00
|
|
|
|
|
2020-07-08 12:16:27 +00:00
|
|
|
|
if (main_arena->GH (next) != m_arena) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
GHT mmap_start = GHT_MAX, tcache_start = GHT_MAX;
|
2018-09-03 00:49:46 +00:00
|
|
|
|
MallocState *ta = R_NEW0 (MallocState);
|
|
|
|
|
if (!ta) {
|
2022-08-18 00:40:08 +00:00
|
|
|
|
free (ta);
|
2020-07-08 12:16:27 +00:00
|
|
|
|
GH (tcache_free) (r_tcache);
|
2018-09-03 00:49:46 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2020-07-08 12:16:27 +00:00
|
|
|
|
ta->GH (next) = main_arena->GH (next);
|
|
|
|
|
while (GH (is_arena) (core, m_arena, ta->GH (next)) && ta->GH (next) != m_arena) {
|
2018-09-03 00:49:46 +00:00
|
|
|
|
PRINT_YA ("Tcache thread arena @ ");
|
2020-07-08 12:16:27 +00:00
|
|
|
|
PRINTF_BA (" 0x%"PFMT64x, (ut64)ta->GH (next));
|
|
|
|
|
mmap_start = ((ta->GH (next) >> 16) << 16);
|
2024-03-20 20:15:30 +00:00
|
|
|
|
tcache_start = mmap_start + sizeof (GH (RHeapInfo)) + sizeof (GH (RHeap_MallocState_227)) + GH (MMAP_ALIGN);
|
2018-09-03 00:49:46 +00:00
|
|
|
|
|
2020-07-08 12:16:27 +00:00
|
|
|
|
if (!GH (update_main_arena) (core, ta->GH (next), ta)) {
|
2018-09-05 09:24:41 +00:00
|
|
|
|
free (ta);
|
2020-07-08 12:16:27 +00:00
|
|
|
|
GH (tcache_free) (r_tcache);
|
2018-09-05 09:24:41 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ta->attached_threads) {
|
2018-09-08 10:29:31 +00:00
|
|
|
|
PRINT_BA ("\n");
|
2024-06-13 15:35:36 +00:00
|
|
|
|
if (!GH (tcache_read) (core, tcache_start, r_tcache)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-08-31 16:45:12 +00:00
|
|
|
|
GH (tcache_print) (core, r_tcache, demangle);
|
2020-07-08 12:16:27 +00:00
|
|
|
|
} else {
|
|
|
|
|
PRINT_GA (" free\n");
|
2018-09-03 00:49:46 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-08 12:16:27 +00:00
|
|
|
|
GH (tcache_free) (r_tcache);
|
2018-06-29 09:17:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-17 00:00:39 +00:00
|
|
|
|
static void GH(print_heap_segment)(RCore *core, MallocState *main_arena,
|
|
|
|
|
GHT m_arena, GHT m_state, GHT global_max_fast, int format_out) {
|
2023-04-10 10:54:51 +00:00
|
|
|
|
r_return_if_fail (core && main_arena);
|
|
|
|
|
if (!core->dbg || !core->dbg->maps) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-01-14 21:08:14 +00:00
|
|
|
|
|
2018-09-17 00:00:39 +00:00
|
|
|
|
int w, h;
|
|
|
|
|
GHT brk_start = GHT_MAX, brk_end = GHT_MAX, size_tmp, min_size = SZ * 4;
|
|
|
|
|
GHT tcache_fd = GHT_MAX, tcache_tmp = GHT_MAX;
|
|
|
|
|
GHT initial_brk = GHT_MAX, tcache_initial_brk = GHT_MAX;
|
|
|
|
|
|
2023-04-10 10:54:51 +00:00
|
|
|
|
const bool tcache = r_config_get_b (core->config, "dbg.glibc.tcache");
|
2018-08-26 20:50:30 +00:00
|
|
|
|
const int offset = r_config_get_i (core->config, "dbg.glibc.fc_offset");
|
2019-04-27 08:55:18 +00:00
|
|
|
|
RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
|
2020-08-31 16:45:12 +00:00
|
|
|
|
int glibc_version = core->dbg->glibc_version;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
|
|
|
|
|
if (m_arena == m_state) {
|
|
|
|
|
GH(get_brks) (core, &brk_start, &brk_end);
|
|
|
|
|
if (tcache) {
|
2020-08-31 16:45:12 +00:00
|
|
|
|
initial_brk = ((brk_start >> 12) << 12) + GH(HDR_SZ);
|
2021-03-14 21:22:04 +00:00
|
|
|
|
if (r_config_get_b (core->config, "cfg.debug")) {
|
2020-08-31 16:45:12 +00:00
|
|
|
|
tcache_initial_brk = initial_brk;
|
|
|
|
|
}
|
|
|
|
|
initial_brk += (glibc_version < 230)
|
|
|
|
|
? sizeof (GH (RHeapTcachePre230))
|
|
|
|
|
: sizeof (GH (RHeapTcache));
|
2018-09-17 00:00:39 +00:00
|
|
|
|
} else {
|
|
|
|
|
initial_brk = (brk_start >> 12) << 12;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
brk_start = ((m_state >> 16) << 16) ;
|
|
|
|
|
brk_end = brk_start + main_arena->GH(system_mem);
|
|
|
|
|
if (tcache) {
|
2024-03-20 20:15:30 +00:00
|
|
|
|
tcache_initial_brk = brk_start + sizeof (GH(RHeapInfo)) + sizeof (GH(RHeap_MallocState_227)) + GH(MMAP_ALIGN);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
initial_brk = tcache_initial_brk + offset;
|
|
|
|
|
} else {
|
2024-03-20 20:15:30 +00:00
|
|
|
|
initial_brk = brk_start + sizeof (GH(RHeapInfo)) + sizeof (GH(RHeap_MallocState_223)) + MMAP_OFFSET;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
}
|
2018-08-26 20:50:30 +00:00
|
|
|
|
}
|
2017-01-14 21:08:14 +00:00
|
|
|
|
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (brk_start == GHT_MAX || brk_end == GHT_MAX || initial_brk == GHT_MAX) {
|
2022-10-04 16:10:32 +00:00
|
|
|
|
R_LOG_ERROR ("No heap section");
|
2016-10-06 16:02:25 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-17 00:00:39 +00:00
|
|
|
|
GHT next_chunk = initial_brk, prev_chunk = next_chunk;
|
2018-05-18 22:11:39 +00:00
|
|
|
|
GH(RHeapChunk) *cnk = R_NEW0 (GH(RHeapChunk));
|
2020-01-08 04:52:00 +00:00
|
|
|
|
if (!cnk) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2018-06-20 00:24:47 +00:00
|
|
|
|
GH(RHeapChunk) *cnk_next = R_NEW0 (GH(RHeapChunk));
|
2020-01-08 04:52:00 +00:00
|
|
|
|
if (!cnk_next) {
|
|
|
|
|
free (cnk);
|
2018-05-18 22:11:39 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2017-01-14 21:08:14 +00:00
|
|
|
|
|
2018-09-17 00:00:39 +00:00
|
|
|
|
RConfigHold *hc = r_config_hold_new (core->config);
|
|
|
|
|
if (!hc) {
|
2019-12-13 17:25:19 +00:00
|
|
|
|
free (cnk);
|
|
|
|
|
free (cnk_next);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
w = r_cons_get_size (&h);
|
|
|
|
|
RConsCanvas *can = r_cons_canvas_new (w, h);
|
|
|
|
|
if (!can) {
|
|
|
|
|
free (cnk);
|
|
|
|
|
free (cnk_next);
|
|
|
|
|
r_config_hold_free (hc);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RAGraph *g = r_agraph_new (can);
|
|
|
|
|
if (!g) {
|
|
|
|
|
free (cnk);
|
|
|
|
|
free (cnk_next);
|
|
|
|
|
r_cons_canvas_free (can);
|
2019-03-04 00:24:43 +00:00
|
|
|
|
r_config_hold_restore (hc);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
r_config_hold_free (hc);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-12 01:48:37 +00:00
|
|
|
|
RANode *top = {0}, *chunk_node = {0}, *prev_node = {0};
|
2023-04-10 10:54:51 +00:00
|
|
|
|
char *node_title, *node_data;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
bool first_node = true;
|
|
|
|
|
|
2023-04-10 10:54:51 +00:00
|
|
|
|
char *top_data = strdup ("");
|
|
|
|
|
char *top_title = strdup ("");
|
2018-09-17 00:00:39 +00:00
|
|
|
|
|
2020-12-20 22:37:45 +00:00
|
|
|
|
if (!r_io_read_at (core->io, next_chunk, (ut8 *)cnk, sizeof (GH(RHeapChunk)))) {
|
2022-08-01 07:56:51 +00:00
|
|
|
|
R_LOG_ERROR ("Cannot read");
|
2021-01-27 09:53:50 +00:00
|
|
|
|
free (cnk);
|
|
|
|
|
free (cnk_next);
|
|
|
|
|
r_cons_canvas_free (can);
|
|
|
|
|
r_config_hold_restore (hc);
|
|
|
|
|
r_config_hold_free (hc);
|
2020-12-20 22:37:45 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2018-06-20 00:24:47 +00:00
|
|
|
|
size_tmp = (cnk->size >> 3) << 3;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
ut64 prev_chunk_addr;
|
|
|
|
|
ut64 prev_chunk_size;
|
2021-01-13 00:27:11 +00:00
|
|
|
|
PJ *pj = NULL;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
|
|
|
|
|
switch (format_out) {
|
|
|
|
|
case 'j':
|
2021-01-09 00:10:37 +00:00
|
|
|
|
pj = r_core_pj_new (core);
|
|
|
|
|
if (!pj) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
pj_o (pj);
|
|
|
|
|
pj_ka (pj, "chunks");
|
2018-09-17 00:00:39 +00:00
|
|
|
|
break;
|
|
|
|
|
case '*':
|
|
|
|
|
r_cons_printf ("fs+heap.allocated\n");
|
|
|
|
|
break;
|
|
|
|
|
case 'g':
|
|
|
|
|
can->linemode = r_config_get_i (core->config, "graph.linemode");
|
|
|
|
|
can->color = r_config_get_i (core->config, "scr.color");
|
|
|
|
|
core->cons->use_utf8 = r_config_get_i (core->config, "scr.utf8");
|
|
|
|
|
g->layout = r_config_get_i (core->config, "graph.layout");
|
|
|
|
|
r_agraph_set_title (g, "Heap Layout");
|
|
|
|
|
top_title = r_str_newf ("Top chunk @ 0x%"PFMT64x"\n", (ut64)main_arena->GH(top));
|
|
|
|
|
}
|
2018-06-20 00:24:47 +00:00
|
|
|
|
|
2018-08-26 20:50:30 +00:00
|
|
|
|
while (next_chunk && next_chunk >= brk_start && next_chunk < main_arena->GH(top)) {
|
2018-09-03 21:53:38 +00:00
|
|
|
|
if (size_tmp < min_size || next_chunk + size_tmp > main_arena->GH(top)) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
const char *status = "corrupted";
|
|
|
|
|
switch (format_out) {
|
|
|
|
|
case 'c':
|
|
|
|
|
PRINT_YA ("\n Malloc chunk @ ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x" ", (ut64)next_chunk);
|
|
|
|
|
PRINTF_RA ("[%s]\n",status);
|
|
|
|
|
PRINTF_RA (" size: 0x%"PFMT64x"\n fd: 0x%"PFMT64x", bk: 0x%"PFMT64x"\n",
|
|
|
|
|
(ut64)cnk->size, (ut64)cnk->fd, (ut64)cnk->bk);
|
|
|
|
|
break;
|
|
|
|
|
case 'j':
|
2021-01-09 00:10:37 +00:00
|
|
|
|
pj_o (pj);
|
|
|
|
|
pj_kn (pj, "addr", next_chunk);
|
|
|
|
|
pj_kn (pj, "size", cnk->size);
|
|
|
|
|
pj_ks (pj, "status", status);
|
|
|
|
|
pj_kN (pj, "fd", cnk->fd);
|
|
|
|
|
pj_kN (pj, "bk", cnk->bk);
|
|
|
|
|
pj_end (pj);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
break;
|
|
|
|
|
case '*':
|
|
|
|
|
r_cons_printf ("fs heap.corrupted\n");
|
2022-01-09 18:48:16 +00:00
|
|
|
|
ut64 chunkflag = (ut64)((prev_chunk >> 4) & 0xffffULL);
|
2022-08-15 16:11:20 +00:00
|
|
|
|
r_cons_printf ("f chunk.corrupted.%06"PFMT64x" %d 0x%"PFMT64x"\n",
|
2022-01-09 18:48:16 +00:00
|
|
|
|
chunkflag, (int)cnk->size, (ut64)prev_chunk);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
break;
|
|
|
|
|
case 'g':
|
|
|
|
|
node_title = r_str_newf (" Malloc chunk @ 0x%"PFMT64x" ", (ut64)prev_chunk);
|
|
|
|
|
node_data = r_str_newf ("[corrupted] size: 0x%"PFMT64x"\n fd: 0x%"PFMT64x", bk: 0x%"PFMT64x
|
|
|
|
|
"\nHeap graph could not be recovered\n", (ut64)cnk->size, (ut64)cnk->fd, (ut64)cnk->bk);
|
2021-02-10 09:41:54 +00:00
|
|
|
|
r_agraph_add_node (g, node_title, node_data, NULL);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (first_node) {
|
|
|
|
|
first_node = false;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2017-10-28 23:59:39 +00:00
|
|
|
|
|
2018-09-17 00:00:39 +00:00
|
|
|
|
prev_chunk_addr = (ut64)prev_chunk;
|
|
|
|
|
prev_chunk_size = (((ut64)cnk->size) >> 3) << 3;
|
2018-06-29 09:17:57 +00:00
|
|
|
|
|
2018-06-20 00:24:47 +00:00
|
|
|
|
bool fastbin = size_tmp >= SZ * 4 && size_tmp <= global_max_fast;
|
|
|
|
|
bool is_free = false, double_free = false;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
|
2018-06-20 00:24:47 +00:00
|
|
|
|
if (fastbin) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
int i = (size_tmp / (SZ * 2)) - 2;
|
2018-08-26 20:50:30 +00:00
|
|
|
|
GHT idx = (GHT)main_arena->GH(fastbinsY)[i];
|
2018-06-20 00:24:47 +00:00
|
|
|
|
(void)r_io_read_at (core->io, idx, (ut8 *)cnk, sizeof (GH(RHeapChunk)));
|
2020-08-31 16:45:12 +00:00
|
|
|
|
GHT next = GH (get_next_pointer) (core, idx, cnk->fd);
|
2018-06-20 00:24:47 +00:00
|
|
|
|
if (prev_chunk == idx && idx && !next) {
|
|
|
|
|
is_free = true;
|
|
|
|
|
}
|
2018-08-26 20:50:30 +00:00
|
|
|
|
while (next && next >= brk_start && next < main_arena->GH(top)) {
|
2018-06-20 00:24:47 +00:00
|
|
|
|
if (prev_chunk == idx || prev_chunk == next || idx == next) {
|
|
|
|
|
is_free = true;
|
|
|
|
|
if (idx == next) {
|
|
|
|
|
double_free = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
(void)r_io_read_at (core->io, next, (ut8 *)cnk_next, sizeof (GH(RHeapChunk)));
|
2020-08-31 16:45:12 +00:00
|
|
|
|
GHT next_node = GH (get_next_pointer) (core, next, cnk_next->fd);
|
2018-06-20 00:24:47 +00:00
|
|
|
|
// avoid triple while?
|
2018-08-26 20:50:30 +00:00
|
|
|
|
while (next_node && next_node >= brk_start && next_node < main_arena->GH(top)) {
|
2018-06-20 00:24:47 +00:00
|
|
|
|
if (prev_chunk == next_node) {
|
|
|
|
|
double_free = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
(void)r_io_read_at (core->io, next_node, (ut8 *)cnk_next, sizeof (GH(RHeapChunk)));
|
2020-08-31 16:45:12 +00:00
|
|
|
|
next_node = GH (get_next_pointer) (core, next_node, cnk_next->fd);
|
2018-06-20 00:24:47 +00:00
|
|
|
|
}
|
|
|
|
|
if (double_free) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
2018-05-21 21:06:00 +00:00
|
|
|
|
(void)r_io_read_at (core->io, next, (ut8 *)cnk, sizeof (GH(RHeapChunk)));
|
2020-08-31 16:45:12 +00:00
|
|
|
|
next = GH (get_next_pointer) (core, next, cnk->fd);
|
2018-06-20 00:24:47 +00:00
|
|
|
|
}
|
|
|
|
|
if (double_free) {
|
|
|
|
|
PRINT_RA (" Double free in simple-linked list detected ");
|
|
|
|
|
break;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
2018-09-17 00:00:39 +00:00
|
|
|
|
prev_chunk_size = ((i + 1) * GH(HDR_SZ)) + GH(HDR_SZ);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
2017-05-08 15:19:53 +00:00
|
|
|
|
|
2018-08-26 20:50:30 +00:00
|
|
|
|
if (tcache) {
|
2020-07-08 12:16:27 +00:00
|
|
|
|
GH(RTcache)* tcache_heap = GH (tcache_new) (core);
|
2018-09-05 09:24:41 +00:00
|
|
|
|
if (!tcache_heap) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
r_cons_canvas_free (can);
|
2019-03-04 00:24:43 +00:00
|
|
|
|
r_config_hold_restore (hc);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
r_config_hold_free (hc);
|
|
|
|
|
free (g);
|
2018-09-05 09:24:41 +00:00
|
|
|
|
free (cnk);
|
|
|
|
|
free (cnk_next);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-06-13 15:35:36 +00:00
|
|
|
|
if (!GH (tcache_read) (core, tcache_initial_brk, tcache_heap)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-07-08 12:16:27 +00:00
|
|
|
|
size_t i;
|
|
|
|
|
for (i = 0; i < TCACHE_MAX_BINS; i++) {
|
|
|
|
|
int count = GH (tcache_get_count) (tcache_heap, i);
|
|
|
|
|
GHT entry = GH (tcache_get_entry) (tcache_heap, i);
|
|
|
|
|
if (count > 0) {
|
|
|
|
|
if (entry - SZ * 2 == prev_chunk) {
|
2018-08-26 20:50:30 +00:00
|
|
|
|
is_free = true;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
prev_chunk_size = ((i + 1) * TC_HDR_SZ + GH(TC_SZ));
|
2018-08-26 20:50:30 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2020-07-08 12:16:27 +00:00
|
|
|
|
if (count > 1) {
|
|
|
|
|
tcache_fd = entry;
|
2018-08-31 10:23:15 +00:00
|
|
|
|
int n;
|
2020-07-08 12:16:27 +00:00
|
|
|
|
for (n = 1; n < count; n++) {
|
|
|
|
|
bool r = r_io_read_at (core->io, tcache_fd, (ut8*)&tcache_tmp, sizeof (GHT));
|
|
|
|
|
if (!r) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-08-31 16:45:12 +00:00
|
|
|
|
tcache_tmp = GH (get_next_pointer) (core, tcache_fd, read_le (&tcache_tmp));
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (tcache_tmp - SZ * 2 == prev_chunk) {
|
2018-08-26 20:50:30 +00:00
|
|
|
|
is_free = true;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
prev_chunk_size = ((i + 1) * TC_HDR_SZ + GH(TC_SZ));
|
2018-08-26 20:50:30 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
tcache_fd = (ut64)tcache_tmp;
|
2018-06-29 09:17:57 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-07-08 12:16:27 +00:00
|
|
|
|
GH (tcache_free) (tcache_heap);
|
2018-06-29 09:17:57 +00:00
|
|
|
|
}
|
2018-08-26 20:50:30 +00:00
|
|
|
|
|
2018-06-20 00:24:47 +00:00
|
|
|
|
next_chunk += size_tmp;
|
|
|
|
|
prev_chunk = next_chunk;
|
|
|
|
|
r_io_read_at (core->io, next_chunk, (ut8 *)cnk, sizeof (GH(RHeapChunk)));
|
|
|
|
|
size_tmp = (cnk->size >> 3) << 3;
|
2017-05-08 15:19:53 +00:00
|
|
|
|
|
2018-09-17 00:00:39 +00:00
|
|
|
|
const char *status = "allocated";
|
2023-04-10 10:54:51 +00:00
|
|
|
|
if (fastbin && is_free) {
|
|
|
|
|
status = "free";
|
2018-09-17 00:00:39 +00:00
|
|
|
|
}
|
|
|
|
|
if (!(cnk->size & 1)) {
|
|
|
|
|
status = "free";
|
|
|
|
|
}
|
2023-04-10 10:54:51 +00:00
|
|
|
|
if (tcache && is_free) {
|
|
|
|
|
status = "free";
|
2018-09-17 00:00:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (format_out) {
|
|
|
|
|
case 'c':
|
|
|
|
|
PRINT_YA ("\n Malloc chunk @ ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x" ", prev_chunk_addr);
|
|
|
|
|
PRINT_GA ("[size: ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, prev_chunk_size);
|
|
|
|
|
PRINTF_GA ("][%s]",status);
|
|
|
|
|
break;
|
|
|
|
|
case 'j':
|
2021-01-09 00:10:37 +00:00
|
|
|
|
pj_o (pj);
|
|
|
|
|
pj_kn (pj, "addr", prev_chunk_addr);
|
|
|
|
|
pj_kn (pj, "size", prev_chunk_size);
|
|
|
|
|
pj_ks (pj, "status", status);
|
|
|
|
|
pj_end (pj);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
break;
|
|
|
|
|
case '*':
|
|
|
|
|
r_cons_printf ("fs heap.%s\n", status);
|
2022-01-09 18:48:16 +00:00
|
|
|
|
ut64 chunkat = (prev_chunk_addr>>4) & 0xffff;
|
|
|
|
|
r_cons_printf ("f chunk.%06"PFMT64x" %d 0x%"PFMT64x"\n", chunkat, (int)prev_chunk_size, (ut64)prev_chunk_addr);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
break;
|
|
|
|
|
case 'g':
|
|
|
|
|
node_title = r_str_newf (" Malloc chunk @ 0x%"PFMT64x" ", (ut64)prev_chunk_addr);
|
|
|
|
|
node_data = r_str_newf ("size: 0x%"PFMT64x" status: %s\n", (ut64)prev_chunk_size, status);
|
2021-02-10 09:41:54 +00:00
|
|
|
|
chunk_node = r_agraph_add_node (g, node_title, node_data, NULL);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (first_node) {
|
|
|
|
|
first_node = false;
|
2018-06-20 00:24:47 +00:00
|
|
|
|
} else {
|
2021-02-28 14:32:43 +00:00
|
|
|
|
r_agraph_add_edge (g, prev_node, chunk_node, false);
|
2018-06-29 09:17:57 +00:00
|
|
|
|
}
|
2018-09-17 00:00:39 +00:00
|
|
|
|
prev_node = chunk_node;
|
|
|
|
|
break;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2018-06-20 00:24:47 +00:00
|
|
|
|
|
2018-09-17 00:00:39 +00:00
|
|
|
|
switch (format_out) {
|
|
|
|
|
case 'c':
|
|
|
|
|
PRINT_YA ("\n Top chunk @ ");
|
2021-02-28 14:32:43 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)main_arena->GH (top));
|
2018-09-17 00:00:39 +00:00
|
|
|
|
PRINT_GA (" - [brk_start: ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)brk_start);
|
|
|
|
|
PRINT_GA (", brk_end: ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)brk_end);
|
|
|
|
|
PRINT_GA ("]\n");
|
|
|
|
|
break;
|
|
|
|
|
case 'j':
|
2021-01-09 00:10:37 +00:00
|
|
|
|
pj_end (pj);
|
|
|
|
|
pj_kn (pj, "top", main_arena->GH(top));
|
|
|
|
|
pj_kn (pj, "brk", brk_start);
|
|
|
|
|
pj_kn (pj, "end", brk_end);
|
|
|
|
|
pj_end (pj);
|
|
|
|
|
r_cons_print (pj_string (pj));
|
|
|
|
|
pj_free (pj);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
break;
|
|
|
|
|
case '*':
|
|
|
|
|
r_cons_printf ("fs-\n");
|
2021-02-28 14:32:43 +00:00
|
|
|
|
r_cons_printf ("f heap.top = 0x%08"PFMT64x"\n", (ut64)main_arena->GH (top));
|
2018-09-17 00:00:39 +00:00
|
|
|
|
r_cons_printf ("f heap.brk = 0x%08"PFMT64x"\n", (ut64)brk_start);
|
|
|
|
|
r_cons_printf ("f heap.end = 0x%08"PFMT64x"\n", (ut64)brk_end);
|
|
|
|
|
break;
|
|
|
|
|
case 'g':
|
2021-02-10 09:41:54 +00:00
|
|
|
|
top = r_agraph_add_node (g, top_title, top_data, NULL);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (!first_node) {
|
2021-02-28 14:32:43 +00:00
|
|
|
|
r_agraph_add_edge (g, prev_node, top, false);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
free (node_data);
|
|
|
|
|
free (node_title);
|
|
|
|
|
}
|
|
|
|
|
r_agraph_print (g);
|
|
|
|
|
r_cons_canvas_free (can);
|
2019-03-04 00:24:43 +00:00
|
|
|
|
r_config_hold_restore (hc);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
r_config_hold_free (hc);
|
|
|
|
|
break;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-02-28 14:32:43 +00:00
|
|
|
|
r_cons_newline ();
|
2018-09-17 00:00:39 +00:00
|
|
|
|
free (g);
|
|
|
|
|
free (top_data);
|
|
|
|
|
free (top_title);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
free (cnk);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
free (cnk_next);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-06-29 09:17:57 +00:00
|
|
|
|
void GH(print_malloc_states)( RCore *core, GHT m_arena, MallocState *main_arena) {
|
|
|
|
|
MallocState *ta = R_NEW0 (MallocState);
|
2019-04-27 08:55:18 +00:00
|
|
|
|
RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
|
|
|
|
|
|
2016-10-06 16:02:25 +00:00
|
|
|
|
if (!ta) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
PRINT_YA ("main_arena @ ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x"\n", (ut64)m_arena);
|
2018-08-26 20:50:30 +00:00
|
|
|
|
if (main_arena->GH(next) != m_arena) {
|
|
|
|
|
ta->GH(next) = main_arena->GH(next);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
while (GH(is_arena) (core, m_arena, ta->GH(next)) && ta->GH(next) != m_arena) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_YA ("thread arena @ ");
|
2018-09-05 09:24:41 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)ta->GH(next));
|
2022-11-20 11:55:12 +00:00
|
|
|
|
// if the next pointer is equal to unsigned -1 we assume its invalid
|
|
|
|
|
// and return. otherwise we get undefined behavior and weird output offten
|
|
|
|
|
// times with thousands of lines in the output
|
|
|
|
|
// saying thread arenas are at 0xffff... which is obviously incorrect
|
|
|
|
|
// related to issue #20767
|
|
|
|
|
if (ta->GH(next) == GHT_MAX) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (!GH(update_main_arena) (core, ta->GH(next), ta)) {
|
|
|
|
|
free (ta);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (ta->attached_threads) {
|
|
|
|
|
PRINT_BA ("\n");
|
2018-09-01 01:05:47 +00:00
|
|
|
|
} else {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
PRINT_GA (" free\n");
|
2018-09-01 01:05:47 +00:00
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-18 00:40:08 +00:00
|
|
|
|
free (ta);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
2018-09-17 00:00:39 +00:00
|
|
|
|
|
2016-10-06 16:02:25 +00:00
|
|
|
|
void GH(print_inst_minfo)(GH(RHeapInfo) *heap_info, GHT hinfo) {
|
2019-04-27 08:55:18 +00:00
|
|
|
|
RConsPrintablePalette *pal = &r_cons_singleton ()->context->pal;
|
|
|
|
|
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINT_YA ("malloc_info @ ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x, (ut64)hinfo);
|
2018-05-18 23:28:19 +00:00
|
|
|
|
PRINT_YA (" {\n ar_ptr = " );
|
2016-10-06 16:02:25 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x"\n", (ut64)heap_info->ar_ptr);
|
|
|
|
|
PRINT_YA (" prev = ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x"\n", (ut64)heap_info->prev);
|
|
|
|
|
PRINT_YA (" size = ");
|
|
|
|
|
PRINTF_BA ("0x%"PFMT64x"\n", (ut64)heap_info->size);
|
|
|
|
|
PRINT_YA (" mprotect_size = ");
|
2017-01-14 21:08:14 +00:00
|
|
|
|
PRINTF_BA ("0x%"PFMT64x"\n", (ut64)heap_info->mprotect_size);
|
|
|
|
|
PRINT_YA ("}\n\n");
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-09-17 00:00:39 +00:00
|
|
|
|
void GH(print_malloc_info)(RCore *core, GHT m_state, GHT malloc_state) {
|
|
|
|
|
GHT h_info;
|
2017-01-14 21:08:14 +00:00
|
|
|
|
|
2016-10-06 16:02:25 +00:00
|
|
|
|
if (malloc_state == m_state) {
|
2023-05-24 08:32:10 +00:00
|
|
|
|
R_LOG_ERROR ("main_arena does not have an instance of malloc_info");
|
2018-09-17 00:00:39 +00:00
|
|
|
|
} else if (GH(is_arena) (core, malloc_state, m_state)) {
|
2016-10-06 16:02:25 +00:00
|
|
|
|
h_info = (malloc_state >> 16) << 16;
|
|
|
|
|
GH(RHeapInfo) *heap_info = R_NEW0 (GH(RHeapInfo));
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (!heap_info) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2018-05-21 21:06:00 +00:00
|
|
|
|
r_io_read_at (core->io, h_info, (ut8*)heap_info, sizeof (GH(RHeapInfo)));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
GH(print_inst_minfo) (heap_info, h_info);
|
2018-06-29 09:17:57 +00:00
|
|
|
|
MallocState *ms = R_NEW0 (MallocState);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (!ms) {
|
|
|
|
|
free (heap_info);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-01-14 21:08:14 +00:00
|
|
|
|
|
2016-10-06 16:02:25 +00:00
|
|
|
|
while (heap_info->prev != 0x0 && heap_info->prev != GHT_MAX) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (!GH(update_main_arena) (core, malloc_state, ms)) {
|
|
|
|
|
free (ms);
|
|
|
|
|
free (heap_info);
|
|
|
|
|
return;
|
2018-08-26 20:50:30 +00:00
|
|
|
|
}
|
|
|
|
|
if ((ms->GH(top) >> 16) << 16 != h_info) {
|
|
|
|
|
h_info = (ms->GH(top) >> 16) << 16;
|
2018-05-21 21:06:00 +00:00
|
|
|
|
r_io_read_at (core->io, h_info, (ut8*)heap_info, sizeof (GH(RHeapInfo)));
|
2016-10-06 16:02:25 +00:00
|
|
|
|
GH(print_inst_minfo) (heap_info, h_info);
|
2017-01-14 21:08:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
free (heap_info);
|
|
|
|
|
free (ms);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
} else {
|
2023-05-24 08:32:10 +00:00
|
|
|
|
R_LOG_ERROR ("This address is not part of the arenas");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-24 09:04:51 +00:00
|
|
|
|
// XXX. refactor to pass all those vars all together into a single struct
|
|
|
|
|
static void GH(dmhg)(RCore *core, const char *input, MallocState *main_arena, GHT global_max_fast, int format) {
|
|
|
|
|
GHT m_state = GHT_MAX;
|
2023-05-24 08:36:04 +00:00
|
|
|
|
GHT m_arena = GHT_MAX;
|
2023-05-24 09:04:51 +00:00
|
|
|
|
if (!GH(r_resolve_main_arena) (core, &m_arena)) {
|
|
|
|
|
R_LOG_ERROR ("Cannot find the main arena");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
input++;
|
|
|
|
|
bool get_state = false;
|
|
|
|
|
if (!*input) {
|
|
|
|
|
if (core->offset != core->prompt_offset) {
|
|
|
|
|
m_state = core->offset;
|
2023-05-24 08:32:10 +00:00
|
|
|
|
get_state = true;
|
|
|
|
|
}
|
2023-05-24 09:04:51 +00:00
|
|
|
|
} else {
|
|
|
|
|
m_state = r_num_math (core->num, input);
|
|
|
|
|
get_state = true;
|
|
|
|
|
}
|
|
|
|
|
if (!get_state) {
|
|
|
|
|
m_state = m_arena;
|
|
|
|
|
}
|
|
|
|
|
if (GH(is_arena) (core, m_arena, m_state)) {
|
|
|
|
|
if (!GH(update_main_arena) (core, m_state, main_arena)) {
|
|
|
|
|
return;
|
2023-05-24 08:32:10 +00:00
|
|
|
|
}
|
2023-05-24 09:04:51 +00:00
|
|
|
|
GH(print_heap_segment) (core, main_arena, m_arena, m_state, global_max_fast, format);
|
|
|
|
|
} else {
|
|
|
|
|
R_LOG_ERROR ("This address is not part of the arenas");
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
2017-01-14 21:08:14 +00:00
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
|
|
|
|
|
static const char* GH(help_msg)[] = {
|
|
|
|
|
"Usage:", " dmh", " # Memory map heap",
|
2018-09-17 00:00:39 +00:00
|
|
|
|
"dmh", " @[malloc_state]", "List heap chunks of a particular arena",
|
2023-05-24 08:32:10 +00:00
|
|
|
|
"dmh", "", "List the chunks inside the heap segment",
|
|
|
|
|
"dmh*", "", "Display heap details as radare2 commands",
|
2016-10-06 16:02:25 +00:00
|
|
|
|
"dmha", "", "List all malloc_state instances in application",
|
2018-09-17 00:00:39 +00:00
|
|
|
|
"dmhb", " @[malloc_state]", "Display all parsed Double linked list of main_arena's or a particular arena bins instance",
|
2016-10-06 16:02:25 +00:00
|
|
|
|
"dmhb", " [bin_num|bin_num:malloc_state]", "Display parsed double linked list of bins instance from a particular arena",
|
2024-04-04 10:55:53 +00:00
|
|
|
|
"dmhbg", " [bin_num]", "Display double linked list graph of main_arena's bin [Under developemnt]",
|
2016-10-06 16:02:25 +00:00
|
|
|
|
"dmhc", " @[chunk_addr]", "Display malloc_chunk struct for a given malloc chunk",
|
2018-09-17 00:00:39 +00:00
|
|
|
|
"dmhf", " @[malloc_state]", "Display all parsed fastbins of main_arena's or a particular arena fastbinY instance",
|
2016-10-06 16:02:25 +00:00
|
|
|
|
"dmhf", " [fastbin_num|fastbin_num:malloc_state]", "Display parsed single linked list in fastbinY instance from a particular arena",
|
|
|
|
|
"dmhg", " [malloc_state]", "Display heap graph of a particular arena",
|
2023-05-24 08:32:10 +00:00
|
|
|
|
"dmhg", "", "Display heap graph of heap segment",
|
2016-10-06 16:02:25 +00:00
|
|
|
|
"dmhi", " @[malloc_state]", "Display heap_info structure/structures for a given arena",
|
2020-11-10 05:19:37 +00:00
|
|
|
|
"dmhj", "", "List the chunks inside the heap segment in JSON format",
|
2023-05-24 08:32:10 +00:00
|
|
|
|
"dmhm", "[*j]", "List all malloc_state instance of a particular arena (@ malloc_state#addr)",
|
2018-09-17 00:00:39 +00:00
|
|
|
|
"dmht", "", "Display all parsed thread cache bins of all arena's tcache instance",
|
2016-10-06 16:02:25 +00:00
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
2023-05-24 08:32:10 +00:00
|
|
|
|
static int GH(dmh_glibc)(RCore *core, const char *input) {
|
2023-05-24 08:36:04 +00:00
|
|
|
|
GHT m_arena = GHT_MAX, m_state = GHT_MAX;
|
2018-09-25 16:59:05 +00:00
|
|
|
|
GHT global_max_fast = (64 * SZ / 4);
|
|
|
|
|
|
2018-06-29 09:17:57 +00:00
|
|
|
|
MallocState *main_arena = R_NEW0 (MallocState);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
if (!main_arena) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-09-25 16:59:05 +00:00
|
|
|
|
|
2021-10-24 20:27:47 +00:00
|
|
|
|
r_config_set_b (core->config, "dbg.glibc.tcache", GH(is_tcache) (core));
|
2020-03-19 14:26:12 +00:00
|
|
|
|
|
2018-09-17 00:00:39 +00:00
|
|
|
|
int format = 'c';
|
|
|
|
|
bool get_state = false;
|
|
|
|
|
|
2016-10-06 16:02:25 +00:00
|
|
|
|
switch (input[0]) {
|
|
|
|
|
case ' ' : // dmh [malloc_state]
|
2023-04-10 10:54:51 +00:00
|
|
|
|
m_state = r_num_get (core->num, input);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
get_state = true;
|
2023-04-10 10:54:51 +00:00
|
|
|
|
// pass through
|
2018-09-17 00:00:39 +00:00
|
|
|
|
case '\0': // dmh
|
2018-09-25 16:59:05 +00:00
|
|
|
|
if (GH(r_resolve_main_arena) (core, &m_arena)) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (core->offset != core->prompt_offset) {
|
|
|
|
|
m_state = core->offset;
|
|
|
|
|
} else {
|
|
|
|
|
if (!get_state) {
|
|
|
|
|
m_state = m_arena;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (GH(is_arena) (core, m_arena, m_state)) {
|
|
|
|
|
if (!GH(update_main_arena) (core, m_state, main_arena)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
GH(print_heap_segment) (core, main_arena, m_arena, m_state, global_max_fast, format);
|
|
|
|
|
break;
|
2017-10-28 23:59:39 +00:00
|
|
|
|
} else {
|
2023-05-24 08:32:10 +00:00
|
|
|
|
R_LOG_ERROR ("This address is not part of any arena");
|
2018-09-17 00:00:39 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'a': // dmha
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (GH(r_resolve_main_arena) (core, &m_arena)) {
|
|
|
|
|
if (!GH(update_main_arena) (core, m_arena, main_arena)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
GH(print_malloc_states) (core, m_arena, main_arena);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2017-10-28 23:59:39 +00:00
|
|
|
|
case 'i': // dmhi
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (GH(r_resolve_main_arena) (core, &m_arena)) {
|
|
|
|
|
if (!GH(update_main_arena) (core, m_arena, main_arena)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2023-04-10 10:54:51 +00:00
|
|
|
|
input++;
|
|
|
|
|
if (!*input) {
|
|
|
|
|
if (core->offset != core->prompt_offset) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
m_state = core->offset;
|
|
|
|
|
}
|
2023-04-10 10:54:51 +00:00
|
|
|
|
} else {
|
|
|
|
|
m_state = r_num_get (core->num, input);
|
|
|
|
|
}
|
2018-09-17 00:00:39 +00:00
|
|
|
|
GH(print_malloc_info) (core, m_arena, m_state);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2017-01-14 21:08:14 +00:00
|
|
|
|
case 'm': // "dmhm"
|
2018-09-25 16:59:05 +00:00
|
|
|
|
if (GH(r_resolve_main_arena) (core, &m_arena)) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
switch (input[1]) {
|
|
|
|
|
case '*':
|
|
|
|
|
format = '*';
|
2023-04-10 10:54:51 +00:00
|
|
|
|
input++;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
break;
|
|
|
|
|
case 'j':
|
|
|
|
|
format = 'j';
|
2023-04-10 10:54:51 +00:00
|
|
|
|
input++;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2023-04-10 10:54:51 +00:00
|
|
|
|
input++;
|
|
|
|
|
if (!*input) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (core->offset != core->prompt_offset) {
|
|
|
|
|
m_arena = core->offset;
|
2023-04-10 10:54:51 +00:00
|
|
|
|
if (!GH (update_main_arena) (core, m_arena, main_arena)) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2023-04-10 10:54:51 +00:00
|
|
|
|
if (!GH (update_main_arena) (core, m_arena, main_arena)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2018-09-17 00:00:39 +00:00
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
} else {
|
2023-04-10 10:54:51 +00:00
|
|
|
|
m_arena = r_num_get (core->num, input);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (!GH(update_main_arena) (core, m_arena, main_arena)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
2018-09-17 00:00:39 +00:00
|
|
|
|
GH(print_arena_stats) (core, m_arena, main_arena, global_max_fast, format);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'b': // "dmhb"
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (GH(r_resolve_main_arena) (core, &m_arena)) {
|
2023-04-10 10:54:51 +00:00
|
|
|
|
const char *arg = r_str_trim_head_ro (input + 1);
|
|
|
|
|
if (*arg) {
|
|
|
|
|
char *sep = strchr (arg, ':');
|
|
|
|
|
if (sep) {
|
|
|
|
|
m_state = r_num_get (core->num, sep + 1);
|
|
|
|
|
}
|
2018-10-08 09:33:51 +00:00
|
|
|
|
if (!m_state) {
|
|
|
|
|
m_state = m_arena;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (core->offset != core->prompt_offset) {
|
|
|
|
|
m_state = core->offset;
|
|
|
|
|
} else {
|
|
|
|
|
m_state = m_arena;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (GH(is_arena) (core, m_arena, m_state)) {
|
|
|
|
|
if (!GH(update_main_arena) (core, m_state, main_arena)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2023-04-10 10:54:51 +00:00
|
|
|
|
GH(print_heap_bin) (core, m_state, main_arena, arg);
|
2018-09-17 00:00:39 +00:00
|
|
|
|
} else {
|
2023-05-24 08:32:10 +00:00
|
|
|
|
R_LOG_ERROR ("This address is not part of the arenas");
|
2018-09-17 00:00:39 +00:00
|
|
|
|
break;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'c': // "dmhc"
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (GH(r_resolve_main_arena)(core, &m_arena)) {
|
2018-09-08 10:29:31 +00:00
|
|
|
|
GH(print_heap_chunk) (core);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'f': // "dmhf"
|
2018-09-25 16:59:05 +00:00
|
|
|
|
if (GH(r_resolve_main_arena) (core, &m_arena)) {
|
2023-04-10 10:54:51 +00:00
|
|
|
|
const bool demangle = r_config_get_b (core->config, "dbg.glibc.demangle"); // XXX reuse bin.demangle
|
|
|
|
|
const char *arg = r_str_trim_head_ro (input + 1);
|
|
|
|
|
if (*arg) {
|
|
|
|
|
char *sep = strchr (arg, ':');
|
|
|
|
|
if (sep) {
|
|
|
|
|
m_state = r_num_get (core->num, arg);
|
|
|
|
|
}
|
2018-10-08 09:33:51 +00:00
|
|
|
|
if (!m_state) {
|
|
|
|
|
m_state = m_arena;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
}
|
2018-10-08 09:33:51 +00:00
|
|
|
|
} else {
|
|
|
|
|
if (core->offset != core->prompt_offset) {
|
|
|
|
|
m_state = core->offset;
|
2018-09-17 00:00:39 +00:00
|
|
|
|
} else {
|
2018-10-08 09:33:51 +00:00
|
|
|
|
m_state = m_arena;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (GH(is_arena) (core, m_arena, m_state)) {
|
|
|
|
|
if (!GH(update_main_arena) (core, m_state, main_arena)) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2023-04-10 10:54:51 +00:00
|
|
|
|
GH(print_heap_fastbin) (core, m_state, main_arena, global_max_fast, arg, demangle);
|
2018-10-08 09:33:51 +00:00
|
|
|
|
} else {
|
2023-05-24 08:32:10 +00:00
|
|
|
|
R_LOG_ERROR ("This address is not part of the arenas");
|
2018-10-08 09:33:51 +00:00
|
|
|
|
break;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
}
|
2018-10-08 09:33:51 +00:00
|
|
|
|
}
|
2016-10-06 16:02:25 +00:00
|
|
|
|
break;
|
2023-05-24 08:32:10 +00:00
|
|
|
|
case 'g': // "dmhg"
|
|
|
|
|
case '*': // "dmh*"
|
2018-09-17 00:00:39 +00:00
|
|
|
|
case 'j': // "dmhj"
|
2023-05-24 09:04:51 +00:00
|
|
|
|
GH (dmhg) (core, input, main_arena, global_max_fast, input[0]);
|
2016-10-06 16:02:25 +00:00
|
|
|
|
break;
|
2018-06-29 09:17:57 +00:00
|
|
|
|
case 't':
|
2018-09-25 16:59:05 +00:00
|
|
|
|
if (GH(r_resolve_main_arena) (core, &m_arena)) {
|
2018-09-17 00:00:39 +00:00
|
|
|
|
if (!GH(update_main_arena) (core, m_arena, main_arena)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2020-08-31 16:45:12 +00:00
|
|
|
|
bool demangle = r_config_get_i (core->config, "dbg.glibc.demangle");
|
|
|
|
|
GH(print_tcache_instance) (core, m_arena, main_arena, demangle);
|
2018-06-29 09:17:57 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2016-10-06 16:02:25 +00:00
|
|
|
|
case '?':
|
|
|
|
|
r_core_cmd_help (core, GH(help_msg));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
free (main_arena);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2023-09-07 09:23:04 +00:00
|
|
|
|
|
|
|
|
|
#endif
|