Decode ObjectPool TaggedObject entries in -HHH

This commit is contained in:
pancake committed 2026-06-04 14:44:34 +02:00
1 parent d00af03d32
commit f5ce8ccab1
5 files changed
+502 -49

No files matched your search

+7
View File
@@ -233,6 +233,13 @@ A practical static pipeline for r2flutter should be:
9. Merge in loader import/export information from RBin.
10. Emit candidates with confidence, not as unconditional facts.
`-HHH` now covers the exploratory form of steps 2-4 for supported ObjectHeader
snapshots: it decodes ObjectPool entries and annotates tagged-object slots with
`resolved_kind`, `resolved_cid`, `resolved_name`, and function code indexes when
those can be recovered from the cluster streams. The remaining work is to turn
that per-command decoder into a reusable slot table for xrefs, FFI reporting,
and plugin-side queries.
Confidence should be explicit. For example:
- `high`: constant `DynamicLibrary.open` path and constant `lookupFunction`
+8 -4
View File
@@ -873,10 +873,14 @@ clusters. JSON mode mirrors this as `snapshots[].clusters[]`.
`-HHH` enables selected payload diagnostics on top of that same walk. The first
target is `ObjectPool`: when the fill range is parsed, it decodes entry bits,
entry type, patchability, snapshot behavior, raw immediates or target refs, and
both `pool_off`/`pp_off` annotations. If an `ObjectPool` allocation is visible
but a prior incomplete fill rule prevents reaching its payload, the row reports
`object_pool_decode: fill_not_parsed` instead of pretending entries are known.
This keeps the PP/ObjectPool work inspectable and feeds the focused `-p` path.
both `pool_off`/`pp_off` annotations. Tagged-object entries are now resolved
back through the cluster table when possible, so text/JSON/r2 output can include
`resolved_kind`, `resolved_cid`, `resolved_name`, and function `code_index`
fields for strings, functions, classes/libraries, and other known cluster
kinds. If an `ObjectPool` allocation is visible but a prior incomplete fill rule
prevents reaching its payload, the row reports `object_pool_decode:
fill_not_parsed` instead of pretending entries are known. This keeps the
PP/ObjectPool work inspectable and feeds the focused `-p` path.
`-p` now builds a synthetic static ObjectPool image from the decoded fill stream
when the parser can reach a concrete ObjectPool payload. Plain quiet output is
+8 -7
View File
@@ -323,7 +323,7 @@ name, then applies it to:
| `-f` | Dump recovered functions as `addr name`; with `-j`, emits objects with `addr`, `name`, and optional `size`. |
| `-H` | Dump snapshot header/layout/container information. |
| `-HH` | Dump the snapshot header plus VM/isolate cluster allocation/fill layout. |
| `-HHH` | Add selected cluster payload diagnostics, currently ObjectPool entry decoding/status. |
| `-HHH` | Add selected cluster payload diagnostics, currently ObjectPool entry decoding/status plus conservative ref resolution. |
| `-i` | Dump instruction-table entries. |
| `-p` | Print the reconstructed static ObjectPool PP address pair; with `-r`, map the synthetic pool image and set `anal.gp`/`x27` from the synthetic vaddr. |
| `-R` | Dump a radare2 script for applying method flags/comments and PP helpers. |
@@ -369,7 +369,7 @@ Plugin actions:
| `r2flutter -AAA` | Run Dart-aware code analysis and recover refs/comments. |
| `r2flutter -H` | Print snapshot header info. |
| `r2flutter -HH` | Print snapshot header info plus VM/isolate cluster allocation/fill layout. |
| `r2flutter -HHH` | Print cluster layout plus selected payload diagnostics, currently ObjectPool entries/status. |
| `r2flutter -HHH` | Print cluster layout plus selected payload diagnostics, currently ObjectPool entries/status and ref resolution. |
| `r2flutter -i` | Print instruction-table entries. |
| `r2flutter -p` | Print the reconstructed static ObjectPool PP address pair. |
| `r2flutter -R` | Print full radare2 script output. |
@@ -387,7 +387,7 @@ r2flutter -jc # classes as JSON
r2flutter -rz # string registration commands (`iz+`, `f str.*`, `Cs*`)
r2flutter -jH # snapshot header as JSON
r2flutter -HH -l 8 # snapshot header plus first 8 clusters per snapshot
r2flutter -HHH -l 36 # cluster walk plus ObjectPool entry diagnostics/status
r2flutter -HHH -l 36 # cluster walk plus ObjectPool entry diagnostics/status/ref resolution
r2flutter -r -p # map a synthetic ObjectPool and set anal.gp/x27
```
@@ -418,10 +418,11 @@ The `-R` path emits:
- Modern cluster name reconstruction currently requires compressed
ObjectHeader snapshots. Full-width ObjectHeader snapshots rely more heavily
on data-image and string heuristics.
- `-p` currently materializes ObjectPool layout and immediate entries from the
fill stream. Tagged Dart object entries remain placeholders because their
runtime heap addresses are assigned by VM deserialization and are not stored
as static file addresses.
- `-HHH` can resolve many tagged ObjectPool entries to their owning cluster
kind, CID, and static names such as strings/functions. `-p` still materializes
only the ObjectPool shape and immediate entries; tagged Dart object entries
remain placeholders because their runtime heap addresses are assigned by VM
deserialization and are not stored as static file addresses.
- Legacy cluster parsing uses conservative decoders and skips unknown clusters;
when class/function records cannot be trusted, the code falls back to bounded
scans.
+470 -38
View File
@@ -88,6 +88,29 @@ typedef struct {
ut8 *discarded_codes;
} ModernClusterMeta;
typedef struct {
DartCtx *ctx;
const ModernClusterMeta *meta;
ut64 num_clusters;
ut64 refs_count;
ut64 num_base_objects;
const ModernClusterMeta **cluster_by_ref;
char **strings_by_ref;
ut64 *class_name_ref;
ut64 *library_name_ref;
ut64 *patch_wrapped_ref;
ut64 *function_name_ref;
ut64 *function_owner_ref;
ut64 *function_code_index;
} ModernRefResolver;
typedef struct {
const char *kind;
char *name;
int cid;
ut64 code_index;
} ModernResolvedRef;
typedef struct {
const char *op;
const char *name;
@@ -1050,27 +1073,6 @@ static ut64 modern_pool_entry_pp_offset(DartCtx *ctx, ut64 index) {
return modern_pool_entry_pool_offset (ctx, index) + 1;
}
static bool modern_read_raw_word(ClusterStream *s, DartCtx *ctx, ut64 *out) {
ut8 buf[8] = { 0 };
int word_size = modern_target_word_size (ctx);
if (word_size == 4) {
if (!cs_read_bytes (s, buf, 4)) {
return false;
}
if (out) {
*out = r_read_le32 (buf);
}
return true;
}
if (!cs_read_bytes (s, buf, 8)) {
return false;
}
if (out) {
*out = r_read_le64 (buf);
}
return true;
}
static bool modern_skip_fill_instance(ClusterStream *s, const ModernClusterMeta *meta) {
ut64 bitmap = 0;
if (!cs_read_unsigned (s, &bitmap)) {
@@ -1262,13 +1264,44 @@ static const char *modern_pool_entry_behavior_name(ut8 behavior) {
}
}
static const char *modern_resolve_ref_name(char **strings_by_ref, ut64 *class_name_ref, ut64 *library_name_ref, ut64 *patch_wrapped_ref, ut64 *function_name_ref, ut64 refs_count, ut64 ref, int depth);
static char *modern_build_full_name(DartCtx *ctx, const char *owner_name, const char *method_name);
static bool modern_read_cluster_string(ClusterStream *s, char **out);
static bool modern_load_vm_base_strings(DartCtx *ctx, char **strings_by_ref, ut64 refs_count);
static void modern_resolved_ref_fini(ModernResolvedRef *resolved) {
if (!resolved) {
return;
}
free (resolved->name);
memset (resolved, 0, sizeof (*resolved));
resolved->cid = -1;
resolved->code_index = UT64_MAX;
}
static bool modern_decode_pool_entry(ClusterStream *s, DartCtx *ctx, ut8 type, ut8 behavior, ut64 *out_ref, ut64 *out_raw) {
if (out_ref) {
*out_ref = 0;
}
if (out_raw) {
*out_raw = 0;
}
if (behavior != 0) {
return true;
}
switch (type) {
case 0:
return modern_read_raw_word (s, ctx, out_raw);
{
(void)ctx;
int64_t imm = 0;
if (!cs_read_tagged64 (s, &imm)) {
return false;
}
if (out_raw) {
*out_raw = (ut64)imm;
}
return true;
}
case 1:
return cs_read_ref_id (s, out_ref);
case 2:
@@ -1278,7 +1311,395 @@ static bool modern_decode_pool_entry(ClusterStream *s, DartCtx *ctx, ut8 type, u
}
}
static void modern_emit_pool_entry_json(PJ *pj, DartCtx *ctx, ut64 index, ut64 stream_offset, ut64 value_offset, ut8 bits, ut8 type, ut8 patch, ut8 behavior, ut64 ref, ut64 raw) {
static ut64 modern_resolver_ref_count(const ModernClusterMeta *meta, ut64 num_clusters, ut64 num_base_objects) {
ut64 refs_count = num_base_objects + 1;
for (ut64 i = 0; i < num_clusters; i++) {
ut64 end = meta[i].start_ref + meta[i].count;
if (end > refs_count) {
refs_count = end;
}
}
return refs_count + 16;
}
static const ModernClusterMeta *modern_resolver_cluster_for_ref(const ModernRefResolver *resolver, ut64 ref) {
if (!resolver || !resolver->meta || !ref) {
return NULL;
}
if (ref < resolver->refs_count && resolver->cluster_by_ref) {
return resolver->cluster_by_ref[ref];
}
for (ut64 i = 0; i < resolver->num_clusters; i++) {
const ModernClusterMeta *meta = &resolver->meta[i];
if (ref >= meta->start_ref && ref < meta->start_ref + meta->count) {
return meta;
}
}
return NULL;
}
static void modern_resolver_free_strings(char **strings_by_ref, ut64 refs_count) {
if (!strings_by_ref) {
return;
}
for (ut64 i = 0; i < refs_count; i++) {
free (strings_by_ref[i]);
}
free (strings_by_ref);
}
static void modern_ref_resolver_fini(ModernRefResolver *resolver) {
if (!resolver) {
return;
}
free (resolver->cluster_by_ref);
modern_resolver_free_strings (resolver->strings_by_ref, resolver->refs_count);
free (resolver->class_name_ref);
free (resolver->library_name_ref);
free (resolver->patch_wrapped_ref);
free (resolver->function_name_ref);
free (resolver->function_owner_ref);
free (resolver->function_code_index);
memset (resolver, 0, sizeof (*resolver));
}
static bool modern_resolver_read_class_fill(ClusterStream *s, const ModernClusterMeta *meta, ModernRefResolver *resolver) {
ModernFillSpec spec = modern_get_fill_spec (resolver->ctx, meta->cid);
ut64 ref = meta->start_ref;
for (ut64 j = 0; j < meta->count; j++, ref++) {
ut64 name_ref = 0;
ut32 class_id = 0;
ut32 tmp32 = 0;
for (int k = 0; k < spec.num_refs; k++) {
ut64 rv = 0;
if (!cs_read_ref_id (s, &rv)) {
return false;
}
if (k == 0) {
name_ref = rv;
}
}
if (!cs_read_tagged32 (s, &class_id) || !cs_read_tagged32 (s, &tmp32) || !cs_read_tagged32 (s, &tmp32) || !cs_read_tagged32 (s, &tmp32) || !cs_read_tagged32 (s, &tmp32) || !cs_read_tagged32 (s, &tmp32) || !cs_read_tagged32 (s, &tmp32)) {
return false;
}
bool is_predefined = j < meta->main_count;
bool is_top_level = class_id >= (1U << 20);
if (is_predefined || !is_top_level) {
ut64 bitmap = 0;
if (!cs_read_unsigned (s, &bitmap)) {
return false;
}
}
if (ref < resolver->refs_count) {
resolver->class_name_ref[ref] = name_ref;
}
}
return true;
}
static bool modern_resolver_read_function_fill(ClusterStream *s, const ModernClusterMeta *meta, ModernRefResolver *resolver) {
ut64 ref = meta->start_ref;
for (ut64 j = 0; j < meta->count; j++, ref++) {
ut64 name_ref = 0;
ut64 owner_ref = 0;
ut64 sig_ref = 0;
ut64 data_ref = 0;
ut64 code_index = 0;
ut32 kind_tag = 0;
if (!cs_read_ref_id (s, &name_ref) || !cs_read_ref_id (s, &owner_ref) || !cs_read_ref_id (s, &sig_ref) || !cs_read_ref_id (s, &data_ref) || !cs_read_unsigned (s, &code_index) || !cs_read_tagged32 (s, &kind_tag)) {
return false;
}
(void)sig_ref;
(void)data_ref;
(void)kind_tag;
if (ref < resolver->refs_count) {
resolver->function_name_ref[ref] = name_ref;
resolver->function_owner_ref[ref] = owner_ref;
resolver->function_code_index[ref] = code_index? code_index - 1: UT64_MAX;
}
}
return true;
}
static bool modern_resolver_read_library_fill(ClusterStream *s, const ModernClusterMeta *meta, ModernRefResolver *resolver) {
ModernFillSpec spec = modern_get_fill_spec (resolver->ctx, meta->cid);
ut64 ref = meta->start_ref;
for (ut64 j = 0; j < meta->count; j++, ref++) {
ut64 name_ref = 0;
for (int k = 0; k < spec.num_refs; k++) {
ut64 rv = 0;
if (!cs_read_ref_id (s, &rv)) {
return false;
}
if (k == 0) {
name_ref = rv;
}
}
for (int k = 0; k < spec.scalar_count; k++) {
if (!modern_skip_scalar (s, spec.scalars[k])) {
return false;
}
}
if (ref < resolver->refs_count) {
resolver->library_name_ref[ref] = name_ref;
}
}
return true;
}
static bool modern_resolver_read_patch_class_fill(ClusterStream *s, const ModernClusterMeta *meta, ModernRefResolver *resolver) {
ut64 ref = meta->start_ref;
for (ut64 j = 0; j < meta->count; j++, ref++) {
ut64 wrapped_ref = 0;
ut64 script_ref = 0;
if (!cs_read_ref_id (s, &wrapped_ref) || !cs_read_ref_id (s, &script_ref)) {
return false;
}
(void)script_ref;
if (ref < resolver->refs_count) {
resolver->patch_wrapped_ref[ref] = wrapped_ref;
}
}
return true;
}
static bool modern_ref_resolver_init(ModernRefResolver *resolver, DartCtx *ctx, const ModernClusterMeta *meta, ut64 num_clusters, ut64 num_base_objects) {
if (!resolver || !ctx || !meta || !num_clusters) {
return false;
}
memset (resolver, 0, sizeof (*resolver));
resolver->ctx = ctx;
resolver->meta = meta;
resolver->num_clusters = num_clusters;
resolver->num_base_objects = num_base_objects;
resolver->refs_count = modern_resolver_ref_count (meta, num_clusters, num_base_objects);
resolver->cluster_by_ref = (const ModernClusterMeta **)calloc ((size_t)resolver->refs_count, sizeof (ModernClusterMeta *));
resolver->strings_by_ref = (char **)calloc ((size_t)resolver->refs_count, sizeof (char *));
resolver->class_name_ref = (ut64 *)calloc ((size_t)resolver->refs_count, sizeof (ut64));
resolver->library_name_ref = (ut64 *)calloc ((size_t)resolver->refs_count, sizeof (ut64));
resolver->patch_wrapped_ref = (ut64 *)calloc ((size_t)resolver->refs_count, sizeof (ut64));
resolver->function_name_ref = (ut64 *)calloc ((size_t)resolver->refs_count, sizeof (ut64));
resolver->function_owner_ref = (ut64 *)calloc ((size_t)resolver->refs_count, sizeof (ut64));
resolver->function_code_index = (ut64 *)calloc ((size_t)resolver->refs_count, sizeof (ut64));
if (!resolver->cluster_by_ref || !resolver->strings_by_ref || !resolver->class_name_ref || !resolver->library_name_ref || !resolver->patch_wrapped_ref || !resolver->function_name_ref || !resolver->function_owner_ref || !resolver->function_code_index) {
modern_ref_resolver_fini (resolver);
return false;
}
for (ut64 i = 0; i < resolver->refs_count; i++) {
resolver->function_code_index[i] = UT64_MAX;
}
for (ut64 i = 0; i < num_clusters; i++) {
const ModernClusterMeta *m = &meta[i];
ut64 end = m->start_ref + m->count;
if (end > resolver->refs_count) {
end = resolver->refs_count;
}
for (ut64 ref = m->start_ref; ref < end; ref++) {
resolver->cluster_by_ref[ref] = m;
}
}
modern_load_vm_base_strings (ctx, resolver->strings_by_ref, resolver->refs_count);
for (ut64 i = 0; i < num_clusters; i++) {
const ModernClusterMeta *m = &meta[i];
if (!m->fill_parsed || !m->fill_ok || m->fill_offset >= m->fill_end || !m->count) {
continue;
}
ClusterStream s = {
.ctx = ctx,
.cursor = m->fill_offset,
.end = m->fill_end,
};
ut64 ref = m->start_ref;
if (modern_is_string_cid (ctx, m->cid)) {
for (ut64 j = 0; j < m->count; j++, ref++) {
char *value = NULL;
if (!modern_read_cluster_string (&s, &value)) {
break;
}
if (ref < resolver->refs_count) {
free (resolver->strings_by_ref[ref]);
resolver->strings_by_ref[ref] = value;
} else {
free (value);
}
}
continue;
}
if (m->fill_kind == MODERN_FILL_CLASS) {
(void)modern_resolver_read_class_fill (&s, m, resolver);
continue;
}
if (m->cid == modern_cid_function (ctx)) {
(void)modern_resolver_read_function_fill (&s, m, resolver);
continue;
}
if (m->cid == 13) {
(void)modern_resolver_read_library_fill (&s, m, resolver);
continue;
}
if (m->cid == 6) {
(void)modern_resolver_read_patch_class_fill (&s, m, resolver);
continue;
}
}
return true;
}
static const char *modern_ref_kind_for_meta(DartCtx *ctx, const ModernClusterMeta *meta) {
if (!meta) {
return "base_object";
}
if (modern_is_string_cid (ctx, meta->cid)) {
return "string";
}
if (meta->cid == modern_cid_class (ctx)) {
return "class";
}
if (meta->cid == modern_cid_function (ctx)) {
return "function";
}
if (meta->cid == 13) {
return "library";
}
if (meta->cid == modern_cid_code (ctx)) {
return "code";
}
if (meta->cid == modern_cid_object_pool (ctx)) {
return "object_pool";
}
return modern_alloc_kind_name (meta->alloc_kind);
}
static void modern_ref_resolver_resolve(ModernRefResolver *resolver, ut64 ref, ModernResolvedRef *resolved) {
if (!resolved) {
return;
}
memset (resolved, 0, sizeof (*resolved));
resolved->cid = -1;
resolved->code_index = UT64_MAX;
if (!resolver || !ref) {
resolved->kind = "null";
return;
}
if (ref >= resolver->refs_count) {
resolved->kind = "out_of_range";
return;
}
const ModernClusterMeta *meta = modern_resolver_cluster_for_ref (resolver, ref);
if (!meta) {
resolved->kind = ref <= resolver->num_base_objects? "base_object": "unknown_ref";
return;
}
resolved->kind = modern_ref_kind_for_meta (resolver->ctx, meta);
resolved->cid = meta->cid;
if (!strcmp (resolved->kind, "string")) {
if (R_STR_ISNOTEMPTY (resolver->strings_by_ref[ref])) {
resolved->name = strdup (resolver->strings_by_ref[ref]);
}
return;
}
if (!strcmp (resolved->kind, "class")) {
ut64 name_ref = resolver->class_name_ref[ref];
if (name_ref < resolver->refs_count && R_STR_ISNOTEMPTY (resolver->strings_by_ref[name_ref])) {
resolved->name = strdup (resolver->strings_by_ref[name_ref]);
}
return;
}
if (!strcmp (resolved->kind, "function")) {
ut64 name_ref = resolver->function_name_ref[ref];
const char *method_name = name_ref < resolver->refs_count? resolver->strings_by_ref[name_ref]: NULL;
const char *owner_name = modern_resolve_ref_name (resolver->strings_by_ref, resolver->class_name_ref, resolver->library_name_ref, resolver->patch_wrapped_ref, resolver->function_name_ref, resolver->refs_count, resolver->function_owner_ref[ref], 0);
resolved->name = modern_build_full_name (resolver->ctx, owner_name, method_name);
resolved->code_index = resolver->function_code_index[ref];
return;
}
if (!strcmp (resolved->kind, "library")) {
ut64 name_ref = resolver->library_name_ref[ref];
if (name_ref < resolver->refs_count && R_STR_ISNOTEMPTY (resolver->strings_by_ref[name_ref])) {
resolved->name = strdup (resolver->strings_by_ref[name_ref]);
}
}
}
static void modern_resolve_pool_entry(ModernRefResolver *resolver, ut8 type, ut8 behavior, ut64 ref, ModernResolvedRef *resolved) {
if (!resolved) {
return;
}
memset (resolved, 0, sizeof (*resolved));
resolved->cid = -1;
resolved->code_index = UT64_MAX;
if (behavior != 0) {
resolved->kind = modern_pool_entry_behavior_name (behavior);
return;
}
if (type == 0) {
resolved->kind = "immediate";
return;
}
if (type == 2) {
resolved->kind = "native_function";
return;
}
if (type == 1) {
modern_ref_resolver_resolve (resolver, ref, resolved);
return;
}
resolved->kind = modern_pool_entry_type_name (type);
}
static void modern_emit_resolved_json(PJ *pj, const ModernResolvedRef *resolved) {
if (!pj || !resolved || R_STR_ISEMPTY (resolved->kind)) {
return;
}
pj_ks (pj, "resolved_kind", resolved->kind);
if (R_STR_ISNOTEMPTY (resolved->name)) {
pj_ks (pj, "resolved_name", resolved->name);
}
if (resolved->cid >= 0) {
pj_ki (pj, "resolved_cid", resolved->cid);
}
if (resolved->code_index != UT64_MAX) {
pj_kn (pj, "resolved_code_index", resolved->code_index);
}
}
static void modern_emit_resolved_text(RStrBuf *sb, const ModernResolvedRef *resolved) {
if (!sb || !resolved || R_STR_ISEMPTY (resolved->kind)) {
return;
}
r_strbuf_appendf (sb, " resolved_kind=%s", resolved->kind);
if (resolved->cid >= 0) {
r_strbuf_appendf (sb, " resolved_cid=%d", resolved->cid);
}
if (resolved->code_index != UT64_MAX) {
r_strbuf_appendf (sb, " code_index=%" PRIu64, (uint64_t)resolved->code_index);
}
if (R_STR_ISNOTEMPTY (resolved->name)) {
char *escaped = r_str_escape_utf8 (resolved->name, false, true);
r_strbuf_appendf (sb, " resolved_name=\"%s\"", escaped);
free (escaped);
}
}
static void modern_emit_resolved_r2(RStrBuf *sb, const ModernResolvedRef *resolved) {
if (!sb || !resolved || R_STR_ISEMPTY (resolved->kind)) {
return;
}
r_strbuf_appendf (sb, " resolved_kind=%s", resolved->kind);
if (resolved->cid >= 0) {
r_strbuf_appendf (sb, " resolved_cid=%d", resolved->cid);
}
if (resolved->code_index != UT64_MAX) {
r_strbuf_appendf (sb, " code_index=%" PRIu64, (uint64_t)resolved->code_index);
}
if (R_STR_ISNOTEMPTY (resolved->name)) {
char *escaped = r_str_escape_utf8 (resolved->name, false, true);
r_strbuf_appendf (sb, " resolved_name=\"%s\"", escaped);
free (escaped);
}
}
static void modern_emit_pool_entry_json(PJ *pj, DartCtx *ctx, ut64 index, ut64 stream_offset, ut64 value_offset, ut8 bits, ut8 type, ut8 patch, ut8 behavior, ut64 ref, ut64 raw, const ModernResolvedRef *resolved) {
pj_o (pj);
pj_kn (pj, "index", index);
pj_kn (pj, "pool_offset", modern_pool_entry_pool_offset (ctx, index));
@@ -1294,10 +1715,11 @@ static void modern_emit_pool_entry_json(PJ *pj, DartCtx *ctx, ut64 index, ut64 s
} else if (behavior == 0 && type == 0) {
pj_kn (pj, "raw", raw);
}
modern_emit_resolved_json (pj, resolved);
pj_end (pj);
}
static void modern_emit_pool_entry_text(RStrBuf *sb, DartCtx *ctx, ut64 index, ut64 stream_offset, ut64 value_offset, ut8 bits, ut8 type, ut8 patch, ut8 behavior, ut64 ref, ut64 raw) {
static void modern_emit_pool_entry_text(RStrBuf *sb, DartCtx *ctx, ut64 index, ut64 stream_offset, ut64 value_offset, ut8 bits, ut8 type, ut8 patch, ut8 behavior, ut64 ref, ut64 raw, const ModernResolvedRef *resolved) {
r_strbuf_appendf (sb,
" [%" PRIu64 "] pool_off=0x%" PFMT64x " pp_off=0x%" PFMT64x " bits=0x%02x type=%s patch=%s behavior=%s stream=0x%" PFMT64x,
(uint64_t)index,
@@ -1313,11 +1735,14 @@ static void modern_emit_pool_entry_text(RStrBuf *sb, DartCtx *ctx, ut64 index, u
} else if (behavior == 0 && type == 0) {
r_strbuf_appendf (sb, " value=0x%" PFMT64x " raw=0x%" PFMT64x, (ut64)value_offset, (ut64)raw);
}
modern_emit_resolved_text (sb, resolved);
r_strbuf_append (sb, "\n");
}
static void modern_emit_pool_entry_r2(RStrBuf *sb, const char *scope, ut64 cluster_index, ut64 pool_index, ut64 pool_ref, DartCtx *ctx, ut64 index, ut64 stream_offset, ut64 value_offset, ut8 bits, ut8 type, ut8 patch, ut8 behavior, ut64 ref, ut64 raw) {
static void modern_emit_pool_entry_r2(RStrBuf *sb, const char *scope, ut64 cluster_index, ut64 pool_index, ut64 pool_ref, DartCtx *ctx, ut64 index, ut64 stream_offset, ut64 value_offset, ut8 bits, ut8 type, ut8 patch, ut8 behavior, ut64 ref, ut64 raw, const ModernResolvedRef *resolved) {
r_strbuf_appendf (sb, "'f dart.%s.cluster.%" PRIu64 ".pool.%" PRIu64 ".entry.%" PRIu64 ".bits = 0x%02x\n", scope, (uint64_t)cluster_index, (uint64_t)pool_index, (uint64_t)index, (unsigned int)bits);
r_strbuf_appendf (sb, "'f dart.%s.cluster.%" PRIu64 ".pool.%" PRIu64 ".entry.%" PRIu64 ".pp_off = 0x%" PFMT64x "\n", scope, (uint64_t)cluster_index, (uint64_t)pool_index, (uint64_t)index, (ut64)modern_pool_entry_pp_offset (ctx, index));
r_strbuf_appendf (sb, "'f dart.%s.cluster.%" PRIu64 ".pool.%" PRIu64 ".entry.%" PRIu64 ".stream = 0x%" PFMT64x "\n", scope, (uint64_t)cluster_index, (uint64_t)pool_index, (uint64_t)index, (ut64)stream_offset);
r_strbuf_appendf (sb,
"'@0x%" PFMT64x "'CC Dart %s ObjectPool ref=%" PRIu64 " entry=%" PRIu64 " pool_off=0x%" PFMT64x " pp_off=0x%" PFMT64x " type=%s patch=%s behavior=%s",
(ut64)stream_offset,
@@ -1334,13 +1759,16 @@ static void modern_emit_pool_entry_r2(RStrBuf *sb, const char *scope, ut64 clust
} else if (behavior == 0 && type == 0) {
r_strbuf_appendf (sb, " value=0x%" PFMT64x " raw=0x%" PFMT64x, (ut64)value_offset, (ut64)raw);
}
modern_emit_resolved_r2 (sb, resolved);
r_strbuf_append (sb, "\n");
}
static bool modern_emit_object_pool_details(DartCtx *ctx, const ModernClusterMeta *meta, ut64 cluster_index, int limit, const char *r2_scope, RStrBuf *sb, PJ *pj) {
static bool modern_emit_object_pool_details(DartCtx *ctx, const ModernClusterMeta *all_meta, ut64 num_clusters, ut64 num_base_objects, const ModernClusterMeta *meta, ut64 cluster_index, int limit, const char *r2_scope, RStrBuf *sb, PJ *pj) {
if (!ctx || !meta || meta->fill_kind != MODERN_FILL_OBJECT_POOL || !meta->fill_parsed || !meta->fill_ok || meta->fill_offset >= meta->fill_end) {
return false;
}
ModernRefResolver resolver = { 0 };
bool have_resolver = modern_ref_resolver_init (&resolver, ctx, all_meta, num_clusters, num_base_objects);
ClusterStream s = {
.ctx = ctx,
.cursor = meta->fill_offset,
@@ -1395,13 +1823,16 @@ static bool modern_emit_object_pool_details(DartCtx *ctx, const ModernClusterMet
if (j >= emit_count) {
continue;
}
ModernResolvedRef resolved;
modern_resolve_pool_entry (have_resolver? &resolver: NULL, type, behavior, ref, &resolved);
if (pj) {
modern_emit_pool_entry_json (pj, ctx, j, entry_stream, value_offset, bits, type, patch, behavior, ref, raw);
modern_emit_pool_entry_json (pj, ctx, j, entry_stream, value_offset, bits, type, patch, behavior, ref, raw, &resolved);
} else if (sb && r2_scope) {
modern_emit_pool_entry_r2 (sb, r2_scope, cluster_index, i, pool_ref, ctx, j, entry_stream, value_offset, bits, type, patch, behavior, ref, raw);
modern_emit_pool_entry_r2 (sb, r2_scope, cluster_index, i, pool_ref, ctx, j, entry_stream, value_offset, bits, type, patch, behavior, ref, raw, &resolved);
} else if (sb) {
modern_emit_pool_entry_text (sb, ctx, j, entry_stream, value_offset, bits, type, patch, behavior, ref, raw);
modern_emit_pool_entry_text (sb, ctx, j, entry_stream, value_offset, bits, type, patch, behavior, ref, raw, &resolved);
}
modern_resolved_ref_fini (&resolved);
}
if (pj) {
pj_end (pj);
@@ -1419,6 +1850,7 @@ static bool modern_emit_object_pool_details(DartCtx *ctx, const ModernClusterMet
if (pj) {
pj_end (pj);
}
modern_ref_resolver_fini (&resolver);
if (!ok && sb) {
if (r2_scope) {
r_strbuf_appendf (sb, "'# Dart %s ObjectPool decode failed near 0x%" PFMT64x "\n", r2_scope, (ut64)s.cursor);
@@ -1462,7 +1894,7 @@ static void modern_emit_object_pool_r2_status(RStrBuf *sb, const char *scope, ut
}
}
static void modern_emit_cluster_json(DartCtx *ctx, PJ *pj, ut64 index, const ModernClusterMeta *meta, int limit, int detail) {
static void modern_emit_cluster_json(DartCtx *ctx, PJ *pj, ut64 index, const ModernClusterMeta *all_meta, ut64 num_clusters, ut64 num_base_objects, const ModernClusterMeta *meta, int limit, int detail) {
pj_o (pj);
pj_kn (pj, "index", index);
pj_kn (pj, "cid", meta->cid);
@@ -1504,13 +1936,13 @@ static void modern_emit_cluster_json(DartCtx *ctx, PJ *pj, ut64 index, const Mod
pj_ks (pj, "object_pool_decode", status);
}
if (status && !strcmp (status, "decoded")) {
(void)modern_emit_object_pool_details (ctx, meta, index, limit, NULL, NULL, pj);
(void)modern_emit_object_pool_details (ctx, all_meta, num_clusters, num_base_objects, meta, index, limit, NULL, NULL, pj);
}
}
pj_end (pj);
}
static void modern_emit_cluster_text(DartCtx *ctx, RStrBuf *sb, ut64 index, const ModernClusterMeta *meta, int limit, int detail) {
static void modern_emit_cluster_text(DartCtx *ctx, RStrBuf *sb, ut64 index, const ModernClusterMeta *all_meta, ut64 num_clusters, ut64 num_base_objects, const ModernClusterMeta *meta, int limit, int detail) {
r_strbuf_appendf (sb,
" %" PRIu64 " cid=%d alloc=%s fill=%s count=%" PRIu64 " refs=%" PRIu64 "..%" PRIu64 " flags=%s%s alloc=0x%" PFMT64x "..0x%" PFMT64x " fill=0x%" PFMT64x "..0x%" PFMT64x,
(uint64_t)index,
@@ -1549,14 +1981,14 @@ static void modern_emit_cluster_text(DartCtx *ctx, RStrBuf *sb, ut64 index, cons
if (detail >= 3) {
const char *status = modern_object_pool_decode_status (meta);
if (status && !strcmp (status, "decoded")) {
(void)modern_emit_object_pool_details (ctx, meta, index, limit, NULL, sb, NULL);
(void)modern_emit_object_pool_details (ctx, all_meta, num_clusters, num_base_objects, meta, index, limit, NULL, sb, NULL);
} else {
modern_emit_object_pool_text_status (sb, meta);
}
}
}
static void modern_emit_cluster_r2(DartCtx *ctx, RStrBuf *sb, const char *scope, ut64 index, const ModernClusterMeta *meta, int limit, int detail) {
static void modern_emit_cluster_r2(DartCtx *ctx, RStrBuf *sb, const char *scope, ut64 index, const ModernClusterMeta *all_meta, ut64 num_clusters, ut64 num_base_objects, const ModernClusterMeta *meta, int limit, int detail) {
const char *status = meta->fill_parsed? (meta->fill_ok? "ok": "failed"): "not_parsed";
ut64 alloc_size = meta->alloc_end > meta->alloc_offset? meta->alloc_end - meta->alloc_offset: 0;
ut64 fill_size = meta->fill_end > meta->fill_offset? meta->fill_end - meta->fill_offset: 0;
@@ -1582,7 +2014,7 @@ static void modern_emit_cluster_r2(DartCtx *ctx, RStrBuf *sb, const char *scope,
if (detail >= 3) {
const char *pool_status = modern_object_pool_decode_status (meta);
if (pool_status && !strcmp (pool_status, "decoded")) {
(void)modern_emit_object_pool_details (ctx, meta, index, limit, scope, sb, NULL);
(void)modern_emit_object_pool_details (ctx, all_meta, num_clusters, num_base_objects, meta, index, limit, scope, sb, NULL);
} else {
modern_emit_object_pool_r2_status (sb, scope, index, meta);
}
@@ -1822,11 +2254,11 @@ bool dart_modern_emit_cluster_summary(DartCtx *ctx, ut64 cluster_start, ut64 clu
}
for (ut64 i = 0; i < emit_count; i++) {
if (pj) {
modern_emit_cluster_json (ctx, pj, i, &meta[i], limit, detail);
modern_emit_cluster_json (ctx, pj, i, meta, num_clusters, num_base_objects, &meta[i], limit, detail);
} else if (sb && r2_scope) {
modern_emit_cluster_r2 (ctx, sb, r2_scope, i, &meta[i], limit, detail);
modern_emit_cluster_r2 (ctx, sb, r2_scope, i, meta, num_clusters, num_base_objects, &meta[i], limit, detail);
} else if (sb) {
modern_emit_cluster_text (ctx, sb, i, &meta[i], limit, detail);
modern_emit_cluster_text (ctx, sb, i, meta, num_clusters, num_base_objects, &meta[i], limit, detail);
}
}
if (sb && emit_count < num_clusters) {
+9
View File
@@ -0,0 +1,9 @@
NAME=object-pool-resolve-android
FILE=-
CMDS=<<EOF
!!../bin/r2flutter -q -j -HHH -l 1100 bins/android/mafia 2>/dev/null | python3 -c 'import json, sys; j = json.load (sys.stdin); iso = next (s for s in j["snapshots"] if s["label"] == "Isolate"); pool = next (p for c in iso["clusters"] for p in c.get ("object_pools", [])); e11 = pool["entries"][11]; e12 = pool["entries"][12]; print ("pool=%d len=%d e11=%s:%d:%s e12=%s:%d:%d:%s" % (pool["ref"], pool["length"], e11["resolved_kind"], e11["resolved_cid"], e11["resolved_name"], e12["resolved_kind"], e12["resolved_cid"], e12["resolved_code_index"], e12["resolved_name"]))'
EOF
EXPECT=<<EOF
pool=195985 len=46569 e11=string:93:getCallbackHandle e12=function:7:37188:method._anonymous_closure_
EOF
RUN