From cfb6448172566f997ed35da06042ae158459100e Mon Sep 17 00:00:00 2001 From: pancake Date: Thu, 1 Oct 2026 16:46:58 +0200 Subject: [PATCH] Dartpool refs moved into -AA and speedup AAA --- src/r2/core_flutter.c | 16 ++++++- src/r2/flutter_analysis.c | 50 ++++++++++++++++------ src/r2/flutter_analysis.h | 1 + test/db/cmd/pp-string-dataref-xref-android | 2 +- 4 files changed, 53 insertions(+), 16 deletions(-) diff --git a/src/r2/core_flutter.c b/src/r2/core_flutter.c index 976e2c2..eecaf2e 100644 --- a/src/r2/core_flutter.c +++ b/src/r2/core_flutter.c @@ -91,7 +91,9 @@ static void r2flutter_subcmd_help(RCore *core, char action) { static void r2flutter_help(RCore *core) { r_cons_printf (core->cons, "Usage: r2flutter [qjr*] \n" - "| r2flutter -A[AA] analyze dart snapshot and apply flags/comments\n" + "| r2flutter -A apply flags, function names and signatures\n" + "| r2flutter -AA also seed anal.gp and apply ObjectPool xrefs\n" + "| r2flutter -AAA also run the full register-tracking scan (slow)\n" "| r2flutter -c[jr*] dump classes\n" "| r2flutter -C apply Dart classes, fields, methods and types\n" "| r2flutter -D prof override Dart snapshot profile by hash or version\n" @@ -391,6 +393,12 @@ static bool r2flutter_run_cmd(RCore *core, DartCtx *dctx, const R2FlutterCmd *cm r2flutter_help (core); return true; case 'A': + // Tiered analysis: + // -A flags, function names and signatures (fast) + // -AA + anal.gp seeding and the ObjectPool xref graph (data-image + // string references), without the expensive per-function scan + // -AAA + full register-tracking scan (PP-slot comments, field/arg + // tracking, null/bool annotations, indirect-call resolution) if (cmd->analysis_depth >= 2) { dctx->dump_fields = 1; } @@ -401,6 +409,12 @@ static bool r2flutter_run_cmd(RCore *core, DartCtx *dctx, const R2FlutterCmd *cm r2flutter_analysis_run (core, dctx, dctx->quiet); } else { r2flutter_analyze (core, dctx, dctx->quiet); + if (cmd->analysis_depth >= 2) { + int graph_xrefs = r2flutter_apply_pool_xrefs (core, dctx); + if (!dctx->quiet) { + R_LOG_INFO ("r2flutter: applied %d ObjectPool xrefs", graph_xrefs); + } + } } return true; case 'C': diff --git a/src/r2/flutter_analysis.c b/src/r2/flutter_analysis.c index 2ff725c..b6c525b 100644 --- a/src/r2/flutter_analysis.c +++ b/src/r2/flutter_analysis.c @@ -845,6 +845,17 @@ static void flutter_ensure_functions(RCore *core, RVecFlutterEntry *entries) { r_log_set_level (R_LOG_LEVEL_INFO); } const bool prev_trycatch = dart_core_trycatch_suspend (core); + // `af` only needs to recover each function's basic blocks here; the Dart + // scan tracks its own args/fields and resolves calls from the snapshot, so + // r2's variable analysis, call-following and jump-table recovery are pure + // overhead - disabling them roughly halves this af storm, the dominant cost + // of -AAA, without changing the recovered blocks. + bool prev_calls = r_config_get_b (core->config, "anal.calls"); + bool prev_vars = r_config_get_b (core->config, "anal.vars"); + bool prev_jmptbl = r_config_get_b (core->config, "anal.jmp.tbl"); + r_config_set_b (core->config, "anal.calls", false); + r_config_set_b (core->config, "anal.vars", false); + r_config_set_b (core->config, "anal.jmp.tbl", false); ut64 *addrp; R_VEC_FOREACH (entries, addrp) { if (!*addrp) { @@ -854,6 +865,9 @@ static void flutter_ensure_functions(RCore *core, RVecFlutterEntry *entries) { r_core_cmdf (core, "af @ 0x%" PFMT64x, *addrp); } } + r_config_set_b (core->config, "anal.calls", prev_calls); + r_config_set_b (core->config, "anal.vars", prev_vars); + r_config_set_b (core->config, "anal.jmp.tbl", prev_jmptbl); dart_core_trycatch_restore (core, prev_trycatch); if (restore_log_level) { r_log_set_level (old_level); @@ -1392,6 +1406,27 @@ void r2flutter_setup_pp_gp(RCore *core, DartCtx *dctx) { dart_read_cache_free (probe.rmem); } +// Apply the recovered ObjectPool xref graph (including data-image references +// such as a const object pointing at a string) so `axt` resolves pool strings +// that no instruction loads directly. Runs on a clean copy of the context: +// extraction needs the pristine state the standalone `-x` command sees, and the +// copy shares heap-owned pointers so only its own read cache is freed. Cheap +// relative to the function scan, which is why -AA can afford it. Returns the +// number of xrefs applied. +int r2flutter_apply_pool_xrefs(RCore *core, DartCtx *dctx) { + if (!core || !dctx) { + return 0; + } + DartCtx xrctx = *dctx; + xrctx.core = core; + xrctx.rmem = NULL; + xrctx.layout = NULL; + xrctx.dump_string_refs = true; + int applied = dart_pool_apply_xrefs (&xrctx); + dart_read_cache_free (xrctx.rmem); + return applied; +} + bool r2flutter_analysis_run(RCore *core, DartCtx *dctx, bool quiet) { R_RETURN_VAL_IF_FAIL (core && dctx, false); DartApp *app = dart_app_new_from_core (core, dctx); @@ -1425,20 +1460,7 @@ bool r2flutter_analysis_run(RCore *core, DartCtx *dctx, bool quiet) { flutter_ensure_functions (core, entries); flutter_scan_functions (core, &model, &pp_strings, &pp_refs, entries, &stats); - // Apply the recovered xref graph (including data-image references such as a - // const object pointing at a string) so `axt` resolves pool-referenced - // strings that no instruction loads directly. Run it on a clean copy of the - // original context - the scan above mutates app->dctx (read cache, layout), - // and dart_pool_extract_xrefs needs the same pristine state the standalone - // `-x` command sees. The copy shares heap-owned pointers, so we free only - // the read cache it allocates. - DartCtx xrctx = *dctx; - xrctx.core = core; - xrctx.rmem = NULL; - xrctx.layout = NULL; - xrctx.dump_string_refs = true; - int graph_xrefs = dart_pool_apply_xrefs (&xrctx); - dart_read_cache_free (xrctx.rmem); + int graph_xrefs = r2flutter_apply_pool_xrefs (core, dctx); if (!quiet) { R_LOG_INFO ("Flutter analysis: %d functions, %d calls, %d fields, %d classes, %d types, %d strings, %d PP refs, %d graph xrefs", diff --git a/src/r2/flutter_analysis.h b/src/r2/flutter_analysis.h index bc7e07b..a6c635e 100644 --- a/src/r2/flutter_analysis.h +++ b/src/r2/flutter_analysis.h @@ -6,5 +6,6 @@ bool r2flutter_analysis_run(RCore *core, DartCtx *dctx, bool quiet); void r2flutter_setup_pp_gp(RCore *core, DartCtx *dctx); +int r2flutter_apply_pool_xrefs(RCore *core, DartCtx *dctx); #endif diff --git a/test/db/cmd/pp-string-dataref-xref-android b/test/db/cmd/pp-string-dataref-xref-android index 468fc1b..69b38a8 100644 --- a/test/db/cmd/pp-string-dataref-xref-android +++ b/test/db/cmd/pp-string-dataref-xref-android @@ -4,7 +4,7 @@ ARGS=-NN -e scr.color=0 -e bin.relocs.apply=true CMDS=<