From 5d86dff9faefc18b2cebc06695d71225d2fdec7d Mon Sep 17 00:00:00 2001 From: pancake Date: Thu, 3 Sep 2026 18:09:11 +0200 Subject: [PATCH] Update all tests to use commands instead of !! oneliners --- TODO.md | 2 +- doc/learn.md | 35 ++++++++ scripts/discovery_stripped_ios.sh | 10 --- scripts/strip_macho_symbols.py | 71 ---------------- src/lib/dart_dumper.c | 2 +- src/lib/dart_pool_modern.c | 20 ++--- src/r2/Makefile | 7 +- src/r2/core_flutter.c | 39 +++++---- test/db/cmd/class-layout-metadata | 41 +++++++--- test/db/cmd/classes-android | 12 ++- test/db/cmd/classes-ios | 12 ++- test/db/cmd/classes-mafia | 31 +++++-- test/db/cmd/code-cluster-layouts | 31 ++++--- test/db/cmd/discovery-stripped-ios | 19 ++++- test/db/cmd/entrypoint-ios | 18 +++-- test/db/cmd/fields-synthetic | 82 ++++++++++++------- test/db/cmd/funcs-android | 6 +- test/db/cmd/funcs-authpass | 14 ++-- test/db/cmd/funcs-authpass-semantic | 14 ++-- test/db/cmd/funcs-ios | 14 ++-- test/db/cmd/funcs-mafia | 50 ++++++++---- test/db/cmd/funcs-mafia-closure | 6 +- test/db/cmd/funcs-mafia-name-pool | 18 +++-- test/db/cmd/funcs-mafia-vm-symbols | 7 +- test/db/cmd/header-android | 6 +- test/db/cmd/header-authpass | 6 +- test/db/cmd/header-deep-macos | 10 ++- test/db/cmd/header-extended-ios | 10 ++- test/db/cmd/header-fingerprint | 10 ++- test/db/cmd/header-ios | 6 +- test/db/cmd/header-mafia | 6 +- test/db/cmd/header-markdown | 6 +- test/db/cmd/header-override-profile | 6 +- test/db/cmd/header-versioned | 37 ++++++--- test/db/cmd/it-android | 18 +++-- test/db/cmd/it-ios | 18 +++-- test/db/cmd/it-mafia | 18 +++-- test/db/cmd/layout-probe-unknown-hash | 72 ++++++++++++----- test/db/cmd/obf-map | 14 ++-- test/db/cmd/object-inspect | 43 ++++++++-- test/db/cmd/object-pool-entry-bits | 18 +++-- test/db/cmd/object-pool-resolve | 14 +++- test/db/cmd/pp-android | 73 +++++++++++++---- test/db/cmd/r2script-method-order | 16 ++-- test/db/cmd/reference-codec | 11 +-- test/db/cmd/sbom-synthetic | 12 ++- test/db/cmd/single-snapshot-313 | 68 +++++++++++++--- test/db/cmd/snapshot-value-graph | 112 ++++++++++++++++++++------ test/db/cmd/strings-android | 24 ++++-- test/db/cmd/strings-android-mafia | 38 ++++++--- test/db/cmd/strings-ios | 6 +- test/db/cmd/strings-r2-mafia | 6 +- test/db/cmd/types-android | 6 +- test/db/cmd/types-enum-android | 6 +- test/db/cmd/types-enum-ios | 6 +- test/db/cmd/types-ios | 6 +- test/db/cmd/types-mafia | 12 ++- test/db/cmd/xrefs-android | 18 +++-- test/db/cmd/xrefs-ios | 24 +++--- test/db/extras/compstr | 10 ++- test/db/extras/r2flutter-help | 96 ++++++++-------------- 61 files changed, 915 insertions(+), 514 deletions(-) delete mode 100644 scripts/discovery_stripped_ios.sh delete mode 100644 scripts/strip_macho_symbols.py diff --git a/TODO.md b/TODO.md index 9eba29e..078c51b 100644 --- a/TODO.md +++ b/TODO.md @@ -21,7 +21,7 @@ rank; each item states the concrete failure it causes. | `d387c0b` | Unknown-hash **fingerprinting** replaces the blind hardcoded "v3.9.2 defaults" (`dart_newest_profile()` auto-tracks the profile table). `-H` reports **`version_source`** (`exact-hash`/`override`/`fingerprint`/`unknown`) and labels guessed layouts `~+ (fingerprint)`. Report and decode paths now share the same layout (previously decode used a degenerate zeroed struct). Test: `header-fingerprint`. | | `2391781` | Explicit **3.7/3.8/3.10/3.11/3.12 CID + layout profiles** (parsed from each release's real `class_id.h`). Also **verified**: the floored tables were already byte-for-byte correct for *every* release 2.10.0–3.12.1, so no CID value changed — the rows are explicit coverage + a regression anchor. | | `cd6b655` | Discovery hardening: removed the **bogus instruction-blob classification** (only data snapshots carry magic `0xf5f5dcdc`; a stray hit could poison `iso_instr`); symbol-derived addresses are no longer clobbered by scan guesses; `vaddr==0` duplicates can't erase a good address; magic hits deduped; Mach-O segments skipped. | -| `0716a95` | **Structural instruction-image location** for symbol-less Mach-O: `vm_instr` = first executable section, `iso_instr = align_up(vm_instr + ImageSize, 64)` from the Dart Image header, with cross-checks that fall back to `0` rather than emit junk. Verified on stripped Runner (`0x4000`/`0xe700`, full 7671 IT entries) and AuthPass (`0x5a80`/`0xfdc0`). Adds `scripts/strip_macho_symbols.py` + `discovery-stripped-ios`. | +| `0716a95` | **Structural instruction-image location** for symbol-less Mach-O: `vm_instr` = first executable section, `iso_instr = align_up(vm_instr + ImageSize, 64)` from the Dart Image header, with cross-checks that fall back to `0` rather than emit junk. Verified on stripped Runner (`0x4000`/`0xe700`, full 7671 IT entries) and AuthPass (`0x5a80`/`0xfdc0`). The `discovery-stripped-ios` test clones the mapped thin slice with `o:`, clears symbol/export metadata with `wv4`, and reloads it with `ooi`. | | `d11ebc3` | **P0.1**: `modern_get_fill_spec`'s fallback `rules[]` is keyed by `DartCidKind` and resolved through a per-layout `by_kind[]` table built once in `modern_cid_cache_init`, instead of literal 3.6-era CIDs. Fixes a whole-block off-by-one on 3.2–3.5 layouts (36 CIDs from `SENTINEL` upward got the neighbouring class's ref/scalar layout) and `MonomorphicSmiableCall`/`UnlinkedCall` on 3.9+, where the two swapped places. Abstract classes that never form a cluster (`CallSiteData`, `AbstractType`, `TypedDataBase`) no longer claim a spec. | | `33bb19b` | **P2.5**: one shared cluster walker (`ModernWalk`) replaces the five hand-rolled tag→cid→alloc→fill loops. Consumers register readers in a `DartCidKind`-keyed table and the walker skips every class they don't claim, so tag decoding, alloc/fill skipping, `start_ref` bookkeeping and the inline-string decision each exist **once** (were 4–5× each). `modern_walk_fill_recorded` serves the resolver, which reads each cluster from its own recorded offset. Verified behaviour-preserving: output byte-identical on 5 samples × 21 actions. | | `e9fa905` | **Part of P0.2**: the read-only-data rule (`modern_walk_is_rodata`) — the six classes Dart moves into the data image when pointer compression is off (exactly `Serializer::ReadOnlyObjectType`) now correctly emit no fill records. Inert until the gate opens; see P0.2 for what still blocks it. | diff --git a/doc/learn.md b/doc/learn.md index 5a48d79..ed42717 100644 --- a/doc/learn.md +++ b/doc/learn.md @@ -1531,3 +1531,38 @@ version/hash overrides and exact known hashes also bypass the probe, preserving deterministic user control and fast known-version behavior. Verbose mode reports candidate validity, scores, the selected range start, or the reason the parser kept the fingerprint fallback. + +## Keep Snapshot Fixtures Inside radare2 + +Small serialized snapshots can live directly in r2r records as `malloc://` +files populated with `wx`. For tests derived from real binaries, `o: $s` makes +an in-memory copy of the current file; subsequent `wx` or `wv8` commands mutate +that copy without touching the fixture on disk. Open real inputs with `-n` when +the test depends on physical offsets, and patch every occurrence that the old +whole-file replacement changed. + +`o:` copies from the current seek, so seek to `0` before cloning a complete +mapped image. It creates and selects the malloc descriptor before filling its +bytes; after changing executable metadata, use `ooi` to parse the completed +in-memory image again. Plain `ob` only lists or selects an existing bin object +and leaves a clone without section or symbol information. For fat Mach-O, a +normal bin load maps the selected thin slice at virtual address zero, which +lets the stripped-discovery test clone and patch the slice without a temporary +file or a Python Mach-O rewriter. + +r2r starts radare2 with `-NN` and `R2_NOPLUGINS=1`, so core-plugin tests must +load the local `core_flutter` library explicitly with `L`. Tests try the native +`.dylib` and `.so` names to remain portable. JSON-path (`~{path}`) and gron +(`~{=}`) filters replace most Python extraction pipelines and keep expected +output focused. Empty command output followed by `~{=}` exposed a radare2 +console bug: the empty-buffer guard covered JSON formatting but not gron mode, +allowing `r_json_parsedup` to receive NULL. The guard and its `cons_grep` +regression test live in the sibling radare2 tree. + +On macOS, a core plugin built with `-undefined dynamic_lookup` must resolve +radare2 APIs from the host process. Linking `R2_LIBS` as well can load a second +installation's `libr_*` dylibs when their install names point at another +prefix. The ABI number can still match while host structures cross library +instances, producing hangs or crashes in parser-heavy commands. The Darwin +plugin target therefore leaves radare2 symbols unresolved; Linux continues to +link the libraries reported by `r2 -H R2_LIBS`. diff --git a/scripts/discovery_stripped_ios.sh b/scripts/discovery_stripped_ios.sh deleted file mode 100644 index a91de6c..0000000 --- a/scripts/discovery_stripped_ios.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -# Strip the iOS Runner App snapshot and verify structural instruction -# discovery still works without symbols. Run from the test/ directory. -A=bins/ios/Runner.app/Frameworks/App.framework/App -T=$(mktemp) -if python3 ../scripts/strip_macho_symbols.py "$A" "$T" > /dev/null 2>&1; then - printf "kdart=%s\n" "$(r2 -qc "is~kDart" "$T" 2> /dev/null | grep -c kDart)" - ../bin/r2flutter -q -H "$T" 2> /dev/null | grep -oE "vm_instr=\S+ iso_data=\S+ iso_instr=\S+" -fi -rm -f "$T" diff --git a/scripts/strip_macho_symbols.py b/scripts/strip_macho_symbols.py deleted file mode 100644 index e7dc753..0000000 --- a/scripts/strip_macho_symbols.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python3 -"""Write a copy of a Mach-O with its symbol table and dyld export trie removed. - -Used to build symbol-less test fixtures: the four kDart*Snapshot* symbols are -external/global and load-bearing (the Flutter engine looks them up at runtime), -so strip(1)/llvm-strip cannot remove them. This neutralises LC_SYMTAB (nsyms=0), -LC_DYLD_INFO[_ONLY] (export_off/size=0) and LC_DYLD_EXPORTS_TRIE (datasize=0) in -every arm64 slice (or the thin Mach-O), which makes r2 report no symbols while -leaving the snapshot bytes intact. This exercises r2flutter's symbol-less -discovery path (structural instruction-image location). - -Usage: strip_macho_symbols.py -""" -import struct, shutil, sys - -CPU_ARM64 = 0x0100000C - - -def patch_macho(d, base): - is64 = struct.unpack_from(' nsyms = 0 - struct.pack_into(' export_off/size = 0 - struct.pack_into(' datasize = 0 - struct.pack_into('I', d, 0)[0] - ok = False - if magic in (0xcafebabe, 0xcafebabf): # fat - b64 = magic == 0xcafebabf - nfat = struct.unpack_from('>I', d, 4)[0] - ao = 8 - for _ in range(nfat): - if b64: - ct, _cs, offset, _sz, _al, _res = struct.unpack_from('>IIQQII', d, ao) - ao += 32 - else: - ct, _cs, offset, _sz, _al = struct.unpack_from('>IIIII', d, ao) - ao += 20 - if ct == CPU_ARM64: - ok = patch_macho(d, offset) or ok - else: - ok = patch_macho(d, 0) - if not ok: - print("no symbol/export commands found to strip", file=sys.stderr) - return 1 - open(dst, 'wb').write(d) - return 0 - - -if __name__ == "__main__": - if len(sys.argv) != 3: - print(__doc__) - sys.exit(2) - sys.exit(main(sys.argv[1], sys.argv[2])) diff --git a/src/lib/dart_dumper.c b/src/lib/dart_dumper.c index e69e2ad..5254fee 100644 --- a/src/lib/dart_dumper.c +++ b/src/lib/dart_dumper.c @@ -269,7 +269,7 @@ static char *dart_signature_to_afs_proto(const char *fname, const char *sig) { if (!lp) { return NULL; } - char *ret = r_str_ndup (sig, (int)(lp - sig)); + char *ret = r_str_ndup (sig, (int) (lp - sig)); if (R_STR_ISEMPTY (ret)) { free (ret); return NULL; diff --git a/src/lib/dart_pool_modern.c b/src/lib/dart_pool_modern.c index b28c1d0..dcfc36d 100644 --- a/src/lib/dart_pool_modern.c +++ b/src/lib/dart_pool_modern.c @@ -903,7 +903,7 @@ static ModernFillSpec modern_get_fill_spec(const ModernCidCache *cids, int cid) } if (modern_cid_eq (cid, cids->function)) { // AOT Function::ReadFill: ReadFromTo (4 refs: name, owner, signature, - // data) + ReadUnsigned(code_index) + Read kind_tag. On Dart 2.x + // data) + ReadUnsigned (code_index) + Read kind_tag. On Dart 2.x // kind_tag is a Dart tagged varint, so read it as such; the token-position // word is only present with a non-product gen_snapshot (released Flutter // apps omit it). Newer snapshots keep the previous decoding. @@ -1048,9 +1048,9 @@ static ModernFillSpec modern_get_fill_spec(const ModernCidCache *cids, int cid) static const ModernFillSpecRule legacy_rules[] = { // PatchClass::to_snapshot stops at script_ in AOT: 3 refs, no scalars. { DART_CID_PATCH_CLASS, MODERN_FILL_REFS, 3, -1, -1, 0, { 0 } }, - // FfiTrampolineData: ReadFromTo (4) + ReadUnsigned(callback_id). + // FfiTrampolineData: ReadFromTo (4) + ReadUnsigned (callback_id). { DART_CID_FFI_TRAMPOLINE_DATA, MODERN_FILL_REFS, 4, -1, -1, 1, { MODERN_SCALAR_UNSIGNED } }, - // Type: ReadFromTo (3) + ReadUnsigned(type_class_id) + Read. + // Type: ReadFromTo (3) + ReadUnsigned (type_class_id) + Read. { DART_CID_TYPE, MODERN_FILL_REFS, 3, -1, -1, 2, { MODERN_SCALAR_UNSIGNED, MODERN_SCALAR_UINT8 } }, // TypeParameter: ReadFromTo (3) + Read + 3x Read. { DART_CID_TYPE_PARAMETER, MODERN_FILL_REFS, 3, -1, -1, 4, { MODERN_SCALAR_TAGGED32, MODERN_SCALAR_UINT8, MODERN_SCALAR_UINT8, MODERN_SCALAR_UINT8 } }, @@ -4707,10 +4707,10 @@ typedef struct { ut64 *code_owner_ref_by_index; int *code_owner_cid_by_index; // Signature recovery: FunctionType graph captured during the fill walk. - ut64 *function_sig_ref; // function ref -> its FunctionType ref (signature) - ut64 *ftype_result_ref; // FunctionType ref -> result_type object ref - ut32 *ftype_packed; // FunctionType ref -> packed_parameter_counts - ut64 *type_class_id; // Type ref -> declared class id (cid), 0 if absent + ut64 *function_sig_ref; // function ref -> its FunctionType ref (signature) + ut64 *ftype_result_ref; // FunctionType ref -> result_type object ref + ut32 *ftype_packed; // FunctionType ref -> packed_parameter_counts + ut64 *type_class_id; // Type ref -> declared class id (cid), 0 if absent HtUP *classname_ref_by_cid; // class cid -> class name string ref ut64 refs_count; ut64 itlen; @@ -4767,7 +4767,7 @@ static bool modern_name_scan_read_class(ModernWalk *w, ClusterStream *s, const M // Map real class ids (not synthetic top-level ids) to their name so // a Type's declared class id can be resolved to a class name. if (!is_top_level && class_id && name_ref && name_ref < u->refs_count && u->classname_ref_by_cid && !ht_up_find (u->classname_ref_by_cid, class_id, NULL)) { - ht_up_insert (u->classname_ref_by_cid, class_id, (void *)(uintptr_t)name_ref); + ht_up_insert (u->classname_ref_by_cid, class_id, (void *) (uintptr_t)name_ref); } } } @@ -4839,7 +4839,7 @@ static bool modern_name_scan_read_function_type(ModernWalk *w, ClusterStream *s, return true; } -// Type::ReadFill: 3 refs then (legacy) ReadUnsigned(type_class_id) + uint8, or +// Type::ReadFill: 3 refs then (legacy) ReadUnsigned (type_class_id) + uint8, or // (3.x) a single packed flags word carrying the class id at bit 3. Capture the // declared class id so a return/param Type can be mapped to a class name. static bool modern_name_scan_read_type(ModernWalk *w, ClusterStream *s, const ModernClusterMeta *m) { @@ -5042,7 +5042,7 @@ static const char *modern_sig_type_name(const ModernNameScanWalk *u, const Moder return "Set"; } if (u->classname_ref_by_cid) { - ut64 name_ref = (ut64)(uintptr_t)ht_up_find (u->classname_ref_by_cid, cid, NULL); + ut64 name_ref = (ut64) (uintptr_t)ht_up_find (u->classname_ref_by_cid, cid, NULL); if (name_ref && name_ref < u->refs_count && R_STR_ISNOTEMPTY (u->strings_by_ref[name_ref])) { return u->strings_by_ref[name_ref]; } diff --git a/src/r2/Makefile b/src/r2/Makefile index 12d32bb..92ed1f0 100644 --- a/src/r2/Makefile +++ b/src/r2/Makefile @@ -7,7 +7,7 @@ R2_LIBS ?= $(shell r2 -H R2_LIBS 2>/dev/null) R2_PLUGDIR ?= $(shell r2 -H R2_USER_PLUGINS) CFLAGS += $(R2_CFLAGS) LDFLAGS += $(R2_LDFLAGS) -LDLIBS += $(R2_LIBS) +R2_PLUGIN_LIBS = $(R2_LIBS) DEPFLAGS = -MMD -MP # Detect platform for shared library extension @@ -15,6 +15,9 @@ UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Darwin) EXT_SO = dylib LDFLAGS += -dynamiclib -undefined dynamic_lookup + # Resolve radare2 symbols from the host. Linking a second installation's + # libr_* dylibs into a core plugin corrupts ABI-compatible host structures. + R2_PLUGIN_LIBS = else EXT_SO = so LDFLAGS += -shared @@ -34,7 +37,7 @@ R2FLUTTER_LIB_TARGET = build/libr2flutter.a all: $(CORE_PLUGIN) $(CORE_PLUGIN): $(CORE_OBJ) $(R2FLUTTER_LIB) - $(CC) $(LDFLAGS) -o $@ $(CORE_OBJ) $(R2FLUTTER_LIB) $(LDLIBS) + $(CC) $(LDFLAGS) -o $@ $(CORE_OBJ) $(R2FLUTTER_LIB) $(R2_PLUGIN_LIBS) $(LDLIBS) core_flutter.o: core_flutter.c $(CC) $(CFLAGS) $(DEPFLAGS) -c $< -o $@ diff --git a/src/r2/core_flutter.c b/src/r2/core_flutter.c index e88744f..c44f63d 100644 --- a/src/r2/core_flutter.c +++ b/src/r2/core_flutter.c @@ -69,18 +69,18 @@ static void r2flutter_subcmd_help(RCore *core, char action) { switch (action) { case 'i': r_cons_printf (core->cons, - "Usage: r2flutter -i[j*] dump instruction table entries\n" + "Usage: r2flutter -i[jr*] dump instruction table entries\n" "| -i plain text output\n" "| -ie dump Dart code entrypoint; with -* mark instruction snapshots as dword arrays\n" "| -ij JSON output\n" - "| -i* r2 commands output\n"); + "| -ir, -i* r2 commands output\n"); break; case 'e': r_cons_printf (core->cons, - "Usage: r2flutter -ie[j*] dump Dart code entrypoint\n" + "Usage: r2flutter -ie[jr*] dump Dart code entrypoint\n" "| -ie plain text output\n" "| -iej JSON output\n" - "| -ie* r2 commands output; mark instruction snapshots as dword arrays\n"); + "| -ier, -ie* r2 commands output; mark instruction snapshots as dword arrays\n"); break; default: r2flutter_help (core); @@ -90,30 +90,31 @@ static void r2flutter_subcmd_help(RCore *core, char action) { static void r2flutter_help(RCore *core) { r_cons_printf (core->cons, - "Usage: r2flutter [j*] \n" + "Usage: r2flutter [qjr*] \n" "| r2flutter -A[AA] analyze dart snapshot and apply flags/comments\n" - "| r2flutter -c[j*] dump classes\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" - "| r2flutter -f[j*] dump recovered functions\n" + "| r2flutter -E[jr*] dump Dart code entrypoint\n" + "| r2flutter -f[jr*] dump recovered functions\n" "| r2flutter -H[HH] dump Dart AOT snapshot header info\n" - "| r2flutter -i[j*] dump instruction table entries\n" - "| r2flutter -ie[j*] dump Dart code entrypoint; with -* mark instruction snapshots as dword arrays\n" + "| r2flutter -i[jr*] dump instruction table entries\n" + "| r2flutter -ie[jr*] dump Dart code entrypoint; with -r/-* mark instruction snapshots as dword arrays\n" "| r2flutter -l N limit function/instruction-table/xref output\n" "| r2flutter -m file load Flutter obfuscation map JSON\n" "| r2flutter -n use heuristic name-pool fallback; names may be wrong\n" "| r2flutter -O spec decode a tagged pointer, PP slot, or snapshot ref:N\n" - "| r2flutter -p[j*] print reconstructed ObjectPool PP value\n" + "| r2flutter -p[jr*] print reconstructed ObjectPool PP value\n" "| r2flutter -R dump full radare2 script (like standalone -R)\n" - "| r2flutter -S[j*] dump best-effort recovered SBOM/components\n" - "| r2flutter -T[j*] dump string-based type names\n" - "| r2flutter -x[j*] dump metadata/data-image xrefs; with -z, include string refs/ax in -*\n" - "| r2flutter -z[j*] dump reliable ObjectPool-referenced strings\n" - "| r2flutter -zz[j*] dump all fuzzy/carved strings (-xzz includes refs/ax in -*)\n" + "| r2flutter -S[jr*] dump best-effort recovered SBOM/components\n" + "| r2flutter -T[jr*] dump string-based type names\n" + "| r2flutter -x[jr*] dump metadata/data-image xrefs; with -z, include string refs/ax in -r/-*\n" + "| r2flutter -z[jr*] dump reliable ObjectPool-referenced strings\n" + "| r2flutter -zz[jr*] dump all fuzzy/carved strings (-xzz includes refs/ax in -r/-*)\n" "| r2flutter -h show this help\n" "| r2flutter -v increase parser verbosity\n" "| r2flutter -V show version\n" - "Modifiers: j=json, *=r2 commands\n"); + "Modifiers: q=quiet, j=json, r/*=r2 commands\n"); } static bool r2flutter_analyze(RCore *core, DartCtx *dctx, int quiet) { @@ -231,6 +232,9 @@ static bool r2flutter_parse_cmd(const char *args, DartCtx *dctx, R2FlutterCmd *c case 'c': cmd->action = flag; break; + case 'E': + cmd->action = 'e'; + break; case 'C': cmd->action = flag; break; @@ -322,6 +326,7 @@ static bool r2flutter_parse_cmd(const char *args, DartCtx *dctx, R2FlutterCmd *c case 'q': dctx->quiet = 1; break; + case 'r': case '*': cmd->fmt = 'r'; break; @@ -428,7 +433,7 @@ static bool r2flutter_run_cmd(RCore *core, DartCtx *dctx, const R2FlutterCmd *cm r2flutter_dump_r2script (core, dctx); return true; case 'S': - out = dart_pool_dump_sbom (dctx, NULL, cmd->fmt); + out = dart_pool_dump_sbom (dctx, core->io && core->io->desc? core->io->desc->name: NULL, cmd->fmt); break; case 'z': out = cmd->string_depth >= 2? dart_pool_dump_strings_fuzzy (dctx, cmd->fmt): dart_pool_dump_strings (dctx, cmd->fmt); diff --git a/test/db/cmd/class-layout-metadata b/test/db/cmd/class-layout-metadata index 80399f6..cab95e3 100644 --- a/test/db/cmd/class-layout-metadata +++ b/test/db/cmd/class-layout-metadata @@ -1,17 +1,36 @@ NAME=serialized-class-layout-metadata -FILE=- +FILE=malloc://0x94 CMDS=</dev/null | python3 -c 'import json,sys; a,b=json.load(sys.stdin); la=a["layout"]; lb=b["layout"]; print(a["ref"], a["class_id"], a["library"]["ref"], a["super"]["type_ref"], la["instance_size"], la["next_field_offset"], la["type_arg_offset"], la["field_bitmap"]); print(b["ref"], b["class_id"], b["library"]["ref"], b["super"]["type_ref"], lb["instance_size"], lb["next_field_offset"], "field_bitmap" in lb, b["flags"]["toplevel"])' -!!python3 -c 'import sys; open(sys.argv[1], "wb").write(bytes.fromhex(sys.argv[2]))' /tmp/r2flutter-class-metadata-truncated.bin 50414421f5f5dcdc74000000000000000200000000000000303435313930376332656161383436376538343863303036376266653865643470726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730086818180800020c181818080808080808280838080807022c4c4c3c2c1c0c0 -!!../bin/r2flutter -q -j -c /tmp/r2flutter-class-metadata-truncated.bin 2>/dev/null | python3 -c 'import json,sys; print("truncated_classes", len(json.load(sys.stdin)))' -!!../bin/r2flutter -q -j -HHH /tmp/r2flutter-class-metadata-truncated.bin 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); print("truncated_fill", d["snapshots"][0]["clusters"][0]["fill_status"])' -!!rm -f /tmp/r2flutter-class-metadata.bin /tmp/r2flutter-class-metadata-truncated.bin +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +wx 50414421f5f5dcdc8c000000000000000200000000000000303435313930376332656161383436376538343863303036376266653865643470726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730086828180800020c182818080808080808280838080807022c4c4c3c2c1c0c08584808080808080858086808080070040c0c5c4c0c0c0c0 +r2flutter -q -j -c~{=}ref,class_id,layout.,flags.toplevel +o malloc://0x7c +wx 50414421f5f5dcdc74000000000000000200000000000000303435313930376332656161383436376538343863303036376266653865643470726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730086818180800020c181818080808080808280838080807022c4c4c3c2c1c0c0 +r2flutter -q -j -c +r2flutter -q -j -HHH~{snapshots[0].clusters[0].fill_status} EOF EXPECT=</dev/null | sed -n '1,7p' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -c~:0..7 EOF EXPECT=</dev/null | head -6 +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -c~:0..6 EOF EXPECT=</dev/null | sed -n '1,6p' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -c~:0..6 EOF EXPECT=</dev/null | head -7 +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -c~:0..7 EOF EXPECT=</dev/null | head -6 +FILE=bins/android/mafia/libapp.so +CMDS=</dev/null | awk '/class _RawReceivePort@1026248/{raw=1} raw && /_portMap@1026248 static final/{field=1} /firstMatch/{method=1} END { print "field=" field + 0; print "method=" method + 0 }' +FILE=bins/android/mafia/libapp.so +CMDS=</dev/null | head -7 +FILE=bins/android/mafia/libapp.so +CMDS=</dev/null | python3 -c 'import sys; lines=list(sys.stdin); code=next(x for x in lines if "alloc=code" in x); pool=next(x for x in lines if "bits=" in x); print("2.12", next(x for x in code.split() if x.startswith("fill_status=")), next(x for x in pool.split() if x.startswith("ref=")))' -!!python3 -c 'import sys; open(sys.argv[1], "wb").write(bytes.fromhex(sys.argv[2]))' /tmp/r2flutter-code-215.bin 50414421f5f5dcdc6e000000000000000300000000000000323464396434313163326639306338666265383930376639396538396434623070726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e74657273008284828785e281c080ea818184878080808080808081002c82 -!!../bin/r2flutter -q -HHH -l 3 /tmp/r2flutter-code-215.bin 2>/dev/null | python3 -c 'import sys; lines=list(sys.stdin); code=next(x for x in lines if "alloc=code" in x); pool=next(x for x in lines if "bits=" in x); print("2.15", next(x for x in code.split() if x.startswith("fill_status=")), next(x for x in pool.split() if x.startswith("ref=")))' -!!python3 -c 'import sys; open(sys.argv[1], "wb").write(bytes.fromhex(sys.argv[2]))' /tmp/r2flutter-code-217.bin 50414421f5f5dcdc6d000000000000000300000000000000313434316436623133623836323366613766626636313433336162656264333170726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e7465727300828482878589e281c080ea81818780808080808081002c82 -!!../bin/r2flutter -q -HHH -l 3 /tmp/r2flutter-code-217.bin 2>/dev/null | python3 -c 'import sys; lines=list(sys.stdin); code=next(x for x in lines if "alloc=code" in x); pool=next(x for x in lines if "bits=" in x); print("2.17", next(x for x in code.split() if x.startswith("fill_status=")), next(x for x in pool.split() if x.startswith("ref=")))' -!!rm -f /tmp/r2flutter-code-212.bin /tmp/r2flutter-code-215.bin /tmp/r2flutter-code-217.bin +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +wx 50414421f5f5dcdc6d000000000000000300000000000000356239373239326232356630613731353631336237613238653037333466373770726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e74657273008284818187ce8180d1818184878080808080808081002c82 +r2flutter -q -HHH -l 3~alloc=code:0 +r2flutter -q -HHH -l 3~bits=:0 +o malloc://0x76 +wx 50414421f5f5dcdc6e000000000000000300000000000000323464396434313163326639306338666265383930376639396538396434623070726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e74657273008284828785e281c080ea818184878080808080808081002c82 +r2flutter -q -HHH -l 3~alloc=code:0 +r2flutter -q -HHH -l 3~bits=:0 +o malloc://0x75 +wx 50414421f5f5dcdc6d000000000000000300000000000000313434316436623133623836323366613766626636313433336162656264333170726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e7465727300828482878589e281c080ea81818780808080808081002c82 +r2flutter -q -HHH -l 3~alloc=code:0 +r2flutter -q -HHH -l 3~bits=:0 EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -qE EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -jE EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -rE EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -c EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -c EOF EXPECT=<","offset":24,"flags":{"static":false,"final":false,"const":false,"late":false}},{"name":"genericItems","type":"List","offset":32,"flags":{"static":false,"final":false,"const":false,"late":false}},{"name":"callback","type":"(int) => String","offset":40,"flags":{"static":false,"final":false,"const":false,"late":false}}],"methods":[{"name":"compute","entry":0,"owner":"TestClass","signature":"(int) => String","kind_tag":0,"kind":"RegularFunction"}]},{"ref":13,"name":"TestInterface","library":{"ref":11,"name":"package:test"},"layout":{"instance_size":0,"type_params":0,"type_arg_offset":0},"flags":{"abstract":false,"enum":false,"mixin":false,"toplevel":false}}] @@ -30,9 +34,11 @@ EOF RUN NAME=strings-fields-synthetic -FILE=- +FILE=bins/synthetic/field_snapshot.bin CMDS=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -zz EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -xzz EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -x EOF EXPECT=< string TestClass [ref=2] @ 0x6e @@ -95,43 +105,57 @@ L ../src/r2/core_flutter.dylib L ../src/r2/core_flutter.so r2flutter -C e bin.lang -ic | sed 's, dart , ? ,g' +ic t dart_TestClass EOF EXPECT=</dev/null | awk 'BEGIN { td = 0; bad = 0 } /^"td struct dart_TestClass \{ uint8_t _pad0\[0x10\]; int64_t fieldA; void \* items; void \* genericItems; void \* callback; \};"$/ { td = 1 } /^af @/ || /^afc / || /td struct\.dart/ || /\(int\) => String callback @/ { bad = 1 } END { print "td=" td; print "bad=" bad }' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -c~?td struct dart_TestClass +r2flutter -r -c~?^af +r2flutter -r -c~?struct.dart +r2flutter -r -c~?callback EOF EXPECT=</dev/null" | awk '/class .* dart_TestClass( :: dart_TestInterface)?$/ { cls = 1 } /class .* dart_TestClass :: dart_TestInterface$/ { super = 1 } /method.* compute$/ { method = 1 } /field.* fieldA$/ { field = 1 } /^pf \[16\]\.qppp fieldA items genericItems callback$/ { type = 1 } END { print "class=" cls + 0; print "super=" super + 0; print "method=" method + 0; print "field=" field + 0; print "type=" type + 0 }' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -C +ic~?&class,dart_TestClass +ic~?&dart_TestClass,dart_TestInterface +ic~?&method,compute +ic~?&field,fieldA +t dart_TestClass~?fieldA items genericItems callback EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -f -l 3 EOF EXPECT=</dev/null | awk '/method\._RawSecureSocket_.*\._secureHandshake_/ { print "handshake=" $1; next } /method\._SecureFilterImpl_.*\.registerBadCertificateCallback$/ { print "register=" $1; next } /method\._SecureFilterImpl_.*\._registerBadCertificateCallback_/ { print "register_impl=" $1; next } /method\._RawSecureSocket_.*\._onBadCertificateWrapper_/ { print "wrapper=" $1; next }' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -f~_secureHandshake_,registerBadCertificateCallback,_registerBadCertificateCallback_,_onBadCertificateWrapper_ EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -f -l 3 EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -f -l 2 EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -f -l 3 EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -f -l 2 EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -qrf -l 2 EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -f -l 3 EOF EXPECT=<Stub, not shifted into a neighboring method name by # the name-pool fallback. 0x5b6bf4 is the AllocateDurationStub in this fixture. NAME=funcs-mafia-allocate-stub -FILE=- +FILE=bins/android/mafia/libapp.so CMDS=</dev/null | grep -E '^0x5b6bf4 ' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -f -q~0x5b6bf4 EOF EXPECT=</dev/null | grep -c '^0x5b6bf4 method.fn_' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -f -q~?&0x5b6bf4,method.fn_ EOF EXPECT=</dev/null | grep -c ' stub.typetest_' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -f -q~?stub.typetest_ EOF EXPECT=</dev/null | grep -c ' stub.Allocate' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -f -q~?stub.Allocate EOF EXPECT=</dev/null | grep -E '0x5b72b0|0x5b74cc' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -f -q~0x5b72b0,0x5b74cc EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -f -q -n -l 6 EOF EXPECT=</dev/null | awk '$1=="0x5b6bf4" || $1=="0x5b6f6c" || $1=="0x5bb750" {print} / stub\.Allocate/ {alloc++} / stub\.typetest_/ {type++} END {print "alloc=" alloc; print "typetest=" type}' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -f -q -n~0x5b6bf4,0x5b6f6c,0x5bb750 +r2flutter -f -q -n~?stub.Allocate +r2flutter -f -q -n~?stub.typetest_ EOF EXPECT=</dev/null | awk '$1=="0xe11f60" || $1=="0xe1205c" || $1=="0xe12174" || $1=="0xe12220" || $1=="0xe122a8" {print} $1=="0xe12220" || $1=="0xe122a8" {names[$2]=1} END {n=0; for (name in names) {n++} print "unique_greaterthan=" n}' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -f -q~0xe11f60,0xe1205c,0xe12174,0xe12220,0xe122a8 EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -H EOF EXPECT=</dev/null | grep -Eo '^( detail: object_pool_entries| 34 cid=23 alloc=object_pool fill=object_pool count=1| object_pool ref=9145 index=0 length=1380)' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -HHH -l 36~object_pool_entries,34 cid=23,object_pool ref=9145 EOF EXPECT=</dev/null | grep -Eo '^(## (VM|Isolate) Clusters| columns:.*| 0 cid=92 alloc=rodata fill=none count=[0-9]+| \.\.\. [0-9]+ clusters omitted by -l)' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -HH -l 1~VM Clusters,Isolate Clusters,columns,0 cid=92,clusters omitted EOF EXPECT=</dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); print("version=%s source=%s tag=%s" % (d["dart_version"], d["version_source"], d["tag_style"]))' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -D ffffffffffffffffffffffffffffffff -H~{=}dart_version,version_source,tag_style EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -H EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -H EOF EXPECT=</dev/null | grep -E '^(#{1,2} |={3,}|-{3,})' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -H~Dart AOT Snapshot Header,Snapshot Addresses,VM Snapshot,Isolate Snapshot,Class IDs EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -D 830f4f59e7969c70b595182826435c19 -H EOF EXPECT=</dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); c=d["cluster"]; print(d["dart_version"], c["clusters"], c["it_len"], c["it_off"], d["header_fields"])' -!!python3 -c 'import sys; open(sys.argv[1], "wb").write(bytes.fromhex(sys.argv[2]))' /tmp/r2flutter-header-212.bin 50414421f5f5dcdc5b000000000000000300000000000000356239373239326232356630613731353631336237613238653037333466373770726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e7465727300828381828780 -!!../bin/r2flutter -j -H /tmp/r2flutter-header-212.bin 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); c=d["cluster"]; print(d["dart_version"], c["clusters"], c["it_len"], c["it_off"], d["header_fields"])' -!!python3 -c 'import sys; open(sys.argv[1], "wb").write(bytes.fromhex(sys.argv[2]))' /tmp/r2flutter-header-217.bin 50414421f5f5dcdc5c000000000000000300000000000000313434316436623133623836323366613766626636313433336162656264333170726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082838187858980 -!!../bin/r2flutter -j -H /tmp/r2flutter-header-217.bin 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); c=d["cluster"]; print(d["dart_version"], c["clusters"], c["it_len"], c["it_off"], d["header_fields"])' -!!rm -f /tmp/r2flutter-header-210.bin /tmp/r2flutter-header-212.bin /tmp/r2flutter-header-217.bin +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +wx 50414421f5f5dcdc5a000000000000000300000000000000386565346566376136376466393834356662613333313733343139386139353370726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e74657273008283818780 +r2flutter -q -j -H~{=}cluster.clusters,cluster.it_len,cluster.it_off,dart_version,header_fields +o malloc://0x63 +wx 50414421f5f5dcdc5b000000000000000300000000000000356239373239326232356630613731353631336237613238653037333466373770726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e7465727300828381828780 +r2flutter -q -j -H~{=}cluster.clusters,cluster.it_len,cluster.it_off,dart_version,header_fields +o malloc://0x64 +wx 50414421f5f5dcdc5c000000000000000300000000000000313434316436623133623836323366613766626636313433336162656264333170726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082838187858980 +r2flutter -q -j -H~{=}cluster.clusters,cluster.it_len,cluster.it_off,dart_version,header_fields EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -l 3 -i EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -l 2 -i EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -l 2 -i EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -l 3 -i EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -l 2 -i EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -l 2 -i EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -l 3 -i EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -l 2 -i EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -l 2 -i EOF EXPECT=</dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["dart_version"], d["version_source"], d["cid_table"]["num_predefined"], d["cluster"]["clusters"])' -!!python3 -c 'import sys; b=open(sys.argv[1], "rb").read().replace(b"d20a1be77c3d3c41b2a5accaee1ce549", b"b"*32); open(sys.argv[2], "wb").write(b)' bins/ios/Runner.app/Frameworks/App.framework/App /tmp/r2flutter-probe-ios.bin -!!../bin/r2flutter -q -j -H /tmp/r2flutter-probe-ios.bin 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["dart_version"], d["version_source"], d["cid_table"]["num_predefined"], d["cluster"]["clusters"])' -!!python3 -c 'import sys; b=bytes.fromhex(sys.argv[2]).replace(b"0451907c2eaa8467e848c0067bfe8ed4", b"c"*32); open(sys.argv[1], "wb").write(b)' /tmp/r2flutter-probe-single.bin 50414421f5f5dcdc97000000000000000200000000000000303435313930376332656161383436376538343863303036376266653865643470726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082868485890020c1810040c481c0800020ce81820060c58181808080808080808080808080807022c4c4c3c0c0c0c080808087808080808080808080808080810181 -!!../bin/r2flutter -q -j -H /tmp/r2flutter-probe-single.bin 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["dart_version"], d["version_source"], d["single_snapshot"], d["vm_data"], d["iso_data"], d["cluster"]["clusters"])' -!!python3 -c 'import sys; b=bytes.fromhex(sys.argv[2]).replace(b"1441d6b13b8623fa7fbf61433abebd31", b"d"*32); open(sys.argv[1], "wb").write(b)' /tmp/r2flutter-probe-legacy.bin 50414421f5f5dcdc6d000000000000000300000000000000313434316436623133623836323366613766626636313433336162656264333170726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e7465727300828482878589e281c080ea81818780808080808081002c82 -!!../bin/r2flutter -q -j -H /tmp/r2flutter-probe-legacy.bin 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["dart_version"], d["version_source"], d["header_fields"], d["cid_table"]["cid_code"])' -!!../bin/r2flutter -q -j -D 2.17.0 -H /tmp/r2flutter-probe-legacy.bin 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["dart_version"], d["version_source"])' -!!python3 -c 'import sys; b=bytes.fromhex(sys.argv[2]).replace(b"1441d6b13b8623fa7fbf61433abebd31", b"e"*32); open(sys.argv[1], "wb").write(b)' /tmp/r2flutter-probe-incomplete.bin 50414421f5f5dcdc5c000000000000000300000000000000313434316436623133623836323366613766626636313433336162656264333170726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082838187858980 -!!../bin/r2flutter -q -j -H /tmp/r2flutter-probe-incomplete.bin 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["version_source"], d["tag_style"])' -!!python3 -c 'import sys; b=bytearray(open(sys.argv[1], "rb").read()); b[8:16]=(4096).to_bytes(8, "little"); open(sys.argv[2], "wb").write(b)' /tmp/r2flutter-probe-incomplete.bin /tmp/r2flutter-probe-bad-length.bin -!!../bin/r2flutter -q -j -H /tmp/r2flutter-probe-bad-length.bin 2>/dev/null | python3 -c 'import json,sys; print(json.load(sys.stdin)["error"])' -!!rm -f /tmp/r2flutter-probe-android.bin /tmp/r2flutter-probe-ios.bin /tmp/r2flutter-probe-single.bin /tmp/r2flutter-probe-legacy.bin /tmp/r2flutter-probe-incomplete.bin /tmp/r2flutter-probe-bad-length.bin +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +o: $s +wx 6161616161616161616161616161616161616161616161616161616161616161 @ 0x354 +wx 6161616161616161616161616161616161616161616161616161616161616161 @ 0x4a94 +r2flutter -q -j -H~{=}cluster.clusters,dart_version,version_source,num_predefined +on bins/ios/Runner.app/Frameworks/App.framework/App +s 0 +o: $s +wx 6262626262626262626262626262626262626262626262626262626262626262 @ 0x1b4914 +wx 6262626262626262626262626262626262626262626262626262626262626262 @ 0x1bd614 +r2flutter -q -j -H~{=}cluster.clusters,dart_version,version_source,num_predefined +o malloc://0x9f +wx 50414421f5f5dcdc97000000000000000200000000000000303435313930376332656161383436376538343863303036376266653865643470726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082868485890020c1810040c481c0800020ce81820060c58181808080808080808080808080807022c4c4c3c0c0c0c080808087808080808080808080808080810181 +wx 6363636363636363636363636363636363636363636363636363636363636363 @ 0x18 +r2flutter -q -j -H~{=}cluster.clusters,dart_version,version_source,single_snapshot,vm_data,iso_data +o malloc://0x75 +wx 50414421f5f5dcdc6d000000000000000300000000000000313434316436623133623836323366613766626636313433336162656264333170726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e7465727300828482878589e281c080ea81818780808080808081002c82 +wx 6464646464646464646464646464646464646464646464646464646464646464 @ 0x18 +r2flutter -q -j -H~{=}dart_version,version_source,header_fields,cid_code +r2flutter -q -j -D 2.17.0 -H~{=}dart_version,version_source +o malloc://0x64 +wx 50414421f5f5dcdc5c000000000000000300000000000000313434316436623133623836323366613766626636313433336162656264333170726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082838187858980 +wx 6565656565656565656565656565656565656565656565656565656565656565 @ 0x18 +r2flutter -q -j -H~{=}version_source,tag_style +wv8 4096 @ 8 +r2flutter -q -j -H~{error} EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -f -l 3 -m custom/obf-map.txt EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -i -l 2 -m custom/obf-map.txt EOF EXPECT=</dev/null | python3 -c 'import json, sys; j = json.load (sys.stdin); o = j["value"]["object"]; s = o["string"]; print ("%s addr=0x%x cid=%d len=%d value=%s" % (j["kind"], o["addr"], o["cid"], s["length"], s["value"]))' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -j -O 0x1651~{=}kind,value.object.addr,value.object.cid,value.object.string.length,value.object.string.value EOF EXPECT=</dev/null | python3 -c 'import json, sys; j = json.load (sys.stdin); p = j["pp_slot"]; v = j["value"]; s = j["snapshot"]; print ("%s index=%d type=%s kind=%s cid=%d name=%s decoded=%s snapshot=%s:%s" % (j["kind"], p["entry_index"], p["type"], p["resolved_kind"], p["resolved_cid"], p["resolved_name"], v["decoded"], s["kind"], s["value"]))' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -j -O pp+0x68~{=}kind,pp_slot.entry_index,pp_slot.type,pp_slot.resolved_kind,pp_slot.resolved_cid,pp_slot.resolved_name,value.decoded,snapshot.kind,snapshot.value EOF EXPECT=</dev/null" +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -O 0x1651 EOF EXPECT=</dev/null | python3 -c 'import sys; line=next(x for x in sys.stdin if "bits=" in x); print("3.0", *(x for x in line.split() if x.startswith(("bits=", "type=", "patch=", "behavior=", "ref="))))' -!!python3 -c 'import sys; open(sys.argv[1], "wb").write(bytes.fromhex(sys.argv[2]))' /tmp/r2flutter-pool-320.bin 50414421f5f5dcdc61000000000000000300000000000000396436333632323636623738653431393866373834646131613238666438326270726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e74657273008283818589ec8181818102ac -!!../bin/r2flutter -q -HHH -l 1 /tmp/r2flutter-pool-320.bin 2>/dev/null | python3 -c 'import sys; line=next(x for x in sys.stdin if "bits=" in x); print("3.2", *(x for x in line.split() if x.startswith(("bits=", "type=", "patch=", "behavior=", "ref="))))' -!!rm -f /tmp/r2flutter-pool-300.bin /tmp/r2flutter-pool-320.bin +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +wx 50414421f5f5dcdc61000000000000000300000000000000636535643337636632366561346661616335343363643231366633623936643170726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e74657273008283818589ec8181818002ac +r2flutter -q -HHH -l 1~bits=:0 +o malloc://0x69 +wx 50414421f5f5dcdc61000000000000000300000000000000396436333632323636623738653431393866373834646131613238666438326270726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e74657273008283818589ec8181818102ac +r2flutter -q -HHH -l 1~bits=:0 EOF EXPECT=</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"]))' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -j -HHH -l 1100~{snapshots[1].clusters[1088].object_pools[0].ref} +r2flutter -q -j -HHH -l 1100~{snapshots[1].clusters[1088].object_pools[0].length} +r2flutter -q -j -HHH -l 1100~{snapshots[1].clusters[1088].object_pools[0].entries[11]} +r2flutter -q -j -HHH -l 1100~{snapshots[1].clusters[1088].object_pools[0].entries[12]} EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -p EOF EXPECT=</dev/null | python3 -c 'import json, sys; j = json.load (sys.stdin); print ("base=%d vaddr=%d paddr=%d kind=%s cluster=%d pool=%d length=%d size=%d word=%d source_paddr=%d" % (j["base"], j["vaddr"], j["paddr"], j["kind"], j["cluster_index"], j["pool_ref"], j["length"], j["size"], j["word_size"], j["source_addr"]["paddr"]))' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -j -p~{=}base,vaddr,paddr,kind,cluster_index,pool_ref,length,size,word_size,source_addr.paddr EOF EXPECT=</dev/null | grep -E '^(o malloc://|e anal[.]gp=|dr anal[.]roregs=|dr x27=|f PP =|f dart[.]pp )' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -r -p~malloc://,anal.gp,anal.roregs,x27=,PP =,dart.pp EOF EXPECT=</dev/null" +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -p EOF EXPECT=</dev/null" +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -p EOF EXPECT=</dev/null | python3 -c 'import json, sys; j = json.load (sys.stdin); print ("base=%d vaddr=%d paddr=%d kind=%s cluster=%d pool=%d length=%d size=%d word=%d source_paddr=%d" % (j["base"], j["vaddr"], j["paddr"], j["kind"], j["cluster_index"], j["pool_ref"], j["length"], j["size"], j["word_size"], j["source_addr"]["paddr"]))' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -j -p~{=}base,vaddr,paddr,kind,cluster_index,pool_ref,length,size,word_size,source_addr.paddr EOF EXPECT=</dev/null | perl -ne 'if (/^f method\..* = 0x([0-9a-fA-F]+)/) { $v = hex ($1); if (defined $p && $v < $p) { print "UNSORTED\n"; exit 1; } $p = $v; $count++; } END { if ($count > 0) { print "OK\n"; } else { print "NO_METHODS\n"; exit 1; } }' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -R~^f method.:0..3 CMDS_END EXPECT=</dev/null | tail -4 | head -3 +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -R~:-3..0 CMDS_END EXPECT=</dev/null | python3 -c 'import sys; print(next(line.strip() for line in sys.stdin if "bits=" in line))' -!!rm -f /tmp/r2flutter-ref-217.bin +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +wx 50414421f5f5dcdc62000000000000000300000000000000313434316436623133623836323366613766626636313433336162656264333170726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e7465727300828381878589ea818181002c82 +r2flutter -q -HHH -l 1~bits=:0 EOF EXPECT=</dev/null | sed -n '1,8p' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -S~:0..8 EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -jS EOF EXPECT=</dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); s=d["snapshots"][0]; c={x["cid"]:x for x in s["clusters"]}; e=c[23]["object_pools"][0]["entries"][0]; print(d["dart_version"], d["single_snapshot"], d["vm_data"], d["iso_data"], len(d["snapshots"]), s["label"], s["clusters_parsed"]); print(c[5]["alloc"], c[5]["fill_status"], c[18]["fill_status"], c[57]["alloc"], c[57]["fill"], c[57]["items"]["total"], e["ref"])' -!!python3 -c 'import sys; open(sys.argv[1], "wb").write(bytes.fromhex(sys.argv[2]))' /tmp/r2flutter-single-314.bin 50414421f5f5dcdc97000000000000000200000000000000376131656133663666356366313038396137663665353564376632306462666470726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082868485890020c1810040c481c0800020ce81820060c58181808080808080808080808080807022c4c4c3c0c0c0c080808087808080808080808080808080810181 -!!../bin/r2flutter -q -j -H /tmp/r2flutter-single-314.bin 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d["dart_version"], d["single_snapshot"], d["vm_data"], d["iso_data"], d["cid_table"]["num_predefined"])' -!!python3 -c 'import sys; open(sys.argv[1], "wb").write(bytes.fromhex(sys.argv[2]))' /tmp/r2flutter-single-313-truncated.bin 50414421f5f5dcdc92000000000000000200000000000000303435313930376332656161383436376538343863303036376266653865643470726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082868485890020c1810040c481c0800020ce81820060c58181808080808080808080808080807022c4c4c3c0c0c0c08080808780808080808080808080 -!!../bin/r2flutter -q -j -HHH -l 8 /tmp/r2flutter-single-313-truncated.bin 2>/dev/null | python3 -c 'import json,sys; d=json.load(sys.stdin); s=d["snapshots"][0]; c={x["cid"]:x for x in s["clusters"]}; print("truncated", d["dart_version"], s["label"], s["clusters_parsed"], c[57]["fill_status"], c[23]["fill_status"], c[23]["object_pool_decode"])' -!!rm -f /tmp/r2flutter-single-313.bin /tmp/r2flutter-single-314.bin /tmp/r2flutter-single-313-truncated.bin +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +wx 50414421f5f5dcdc97000000000000000200000000000000303435313930376332656161383436376538343863303036376266653865643470726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082868485890020c1810040c481c0800020ce81820060c58181808080808080808080808080807022c4c4c3c0c0c0c080808087808080808080808080808080810181 +r2flutter -q -j -HHH -l 8~{dart_version} +r2flutter -q -j -HHH -l 8~{single_snapshot} +r2flutter -q -j -HHH -l 8~{vm_data} +r2flutter -q -j -HHH -l 8~{iso_data} +r2flutter -q -j -HHH -l 8~{snapshots[0].label} +r2flutter -q -j -HHH -l 8~{snapshots[0].clusters_parsed} +r2flutter -q -j -HHH -l 8~{snapshots[0].clusters[0].alloc} +r2flutter -q -j -HHH -l 8~{snapshots[0].clusters[0].fill_status} +r2flutter -q -j -HHH -l 8~{snapshots[0].clusters[1].fill_status} +r2flutter -q -j -HHH -l 8~{snapshots[0].clusters[2].alloc} +r2flutter -q -j -HHH -l 8~{snapshots[0].clusters[2].fill} +r2flutter -q -j -HHH -l 8~{snapshots[0].clusters[2].items.total} +r2flutter -q -j -HHH -l 8~{snapshots[0].clusters[3].object_pools[0].entries[0].ref} +o malloc://0x9f +wx 50414421f5f5dcdc97000000000000000200000000000000376131656133663666356366313038396137663665353564376632306462666470726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082868485890020c1810040c481c0800020ce81820060c58181808080808080808080808080807022c4c4c3c0c0c0c080808087808080808080808080808080810181 +r2flutter -q -j -H~{dart_version} +r2flutter -q -j -H~{single_snapshot} +r2flutter -q -j -H~{vm_data} +r2flutter -q -j -H~{iso_data} +r2flutter -q -j -H~{cid_table.num_predefined} +o malloc://0x9a +wx 50414421f5f5dcdc92000000000000000200000000000000303435313930376332656161383436376538343863303036376266653865643470726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082868485890020c1810040c481c0800020ce81820060c58181808080808080808080808080807022c4c4c3c0c0c0c08080808780808080808080808080 +r2flutter -q -j -HHH -l 8~{dart_version} +r2flutter -q -j -HHH -l 8~{snapshots[0].label} +r2flutter -q -j -HHH -l 8~{snapshots[0].clusters_parsed} +r2flutter -q -j -HHH -l 8~{snapshots[0].clusters[2].fill_status} +r2flutter -q -j -HHH -l 8~{snapshots[0].clusters[3].fill_status} +r2flutter -q -j -HHH -l 8~{snapshots[0].clusters[3].object_pool_decode} EOF EXPECT=</dev/null | python3 -c 'import json,sys; s=json.load(sys.stdin)["snapshot"]; d=s["fields"][2]["value"]; a=d["elements"]; i=a[1]["value"]; f=i["fields"]; print("%s cid=%d complete=%s data=%s len=%d pair=%s:%s(%s) fields=%s,%s,%s"%(s["kind"],s["cid"],s["complete"],d["kind"],d["length"],a[0]["value"]["value"],i["kind"],i["name"],f[0]["value"],f[1]["value"],f[2]["value"]["value"]))' -!!../bin/r2flutter -q -j -O ref:160785 bins/android/mafia 2>/dev/null | python3 -c 'import json,sys; s=json.load(sys.stdin)["snapshot"]; print("%s cid=%d complete=%s data=%s"%(s["kind"],s["cid"],s["complete"],s["fields"][2]["value"]["kind"]))' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -j -O ref:158145~{snapshot.kind} +r2flutter -q -j -O ref:158145~{snapshot.cid} +r2flutter -q -j -O ref:158145~{snapshot.complete} +r2flutter -q -j -O ref:158145~{snapshot.fields[2].value.kind} +r2flutter -q -j -O ref:158145~{snapshot.fields[2].value.length} +r2flutter -q -j -O ref:158145~{snapshot.fields[2].value.elements[0].value.value} +r2flutter -q -j -O ref:158145~{snapshot.fields[2].value.elements[1].value.kind} +r2flutter -q -j -O ref:158145~{snapshot.fields[2].value.elements[1].value.name} +r2flutter -q -j -O ref:158145~{snapshot.fields[2].value.elements[1].value.fields[0].value} +r2flutter -q -j -O ref:158145~{snapshot.fields[2].value.elements[1].value.fields[1].value} +r2flutter -q -j -O ref:158145~{snapshot.fields[2].value.elements[1].value.fields[2].value.value} +r2flutter -q -j -O ref:160785~{snapshot.kind} +r2flutter -q -j -O ref:160785~{snapshot.cid} +r2flutter -q -j -O ref:160785~{snapshot.complete} +r2flutter -q -j -O ref:160785~{snapshot.fields[2].value.kind} EOF EXPECT=</dev/null | python3 -c 'import json,sys; s=json.load(sys.stdin)["snapshot"]; a=s["fields"][2]["value"]["elements"]; print("%s cid=%d complete=%s strings=%s/%s"%(s["kind"],s["cid"],s["complete"],a[0]["value"]["value"],a[1]["value"]["value"]))' -!!../bin/r2flutter -q -j -O ref:211161 bins/ios/AuthPass.app/Frameworks/App.framework/App 2>/dev/null | python3 -c 'import json,sys; s=json.load(sys.stdin)["snapshot"]; print("%s cid=%d complete=%s data=%s"%(s["kind"],s["cid"],s["complete"],s["fields"][2]["value"]["kind"]))' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -j -O ref:209553~{=}~snapshot.kind,snapshot.cid,snapshot.complete,cancel,Cancel +r2flutter -q -j -O ref:211161~{=}~snapshot.kind,snapshot.cid,snapshot.complete,"array" EOF EXPECT=</dev/null | python3 -c 'import json,sys; s=json.load(sys.stdin)["snapshot"]; print("valid",s["kind"],s["complete"],[(x["name"],x["value"]["kind"]) for x in s["fields"]])' -!!../bin/r2flutter -q -j -O ref:3 /tmp/r2flutter-value-cycle.bin 2>/dev/null | python3 -c 'import json,sys; s=json.load(sys.stdin)["snapshot"]; v=s["elements"][0]["value"]; print("cycle",s["kind"],s["complete"],s["length"],v["kind"],v["cycle"])' -!!../bin/r2flutter -q -j -O ref:3 /tmp/r2flutter-value-map-truncated.bin 2>/dev/null | python3 -c 'import json,sys; s=json.load(sys.stdin)["snapshot"]; print("truncated",s["kind"],s["complete"],"fields" in s)' -!!../bin/r2flutter -q -j -O ref:99 /tmp/r2flutter-value-map.bin 2>/dev/null | python3 -c 'import json,sys; s=json.load(sys.stdin)["snapshot"]; print("invalid",s["kind"],s["complete"])' -!!rm -f /tmp/r2flutter-value-map.bin /tmp/r2flutter-value-map-truncated.bin /tmp/r2flutter-value-cycle.bin +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +wx 50414421f5f5dcdc63000000000000000200000000000000303435313930376332656161383436376538343863303036376266653865643470726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082818180800060d5818080808080 +r2flutter -q -j -O ref:3~{=}snapshot.kind,snapshot.complete,.name,.value.kind +o malloc://0x6a +wx 50414421f5f5dcdc62000000000000000200000000000000303435313930376332656161383436376538343863303036376266653865643470726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082818180800040d68181818083 +r2flutter -q -j -O ref:3~{snapshot.kind} +r2flutter -q -j -O ref:3~{snapshot.complete} +r2flutter -q -j -O ref:3~{snapshot.length} +r2flutter -q -j -O ref:3~{snapshot.elements[0].value.kind} +r2flutter -q -j -O ref:3~{snapshot.elements[0].value.cycle} +o malloc://0x6a +wx 50414421f5f5dcdc62000000000000000200000000000000303435313930376332656161383436376538343863303036376266653865643470726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082818180800060d58180808080 +r2flutter -q -j -O ref:3~{snapshot.kind} +r2flutter -q -j -O ref:3~{snapshot.complete} +o malloc://0x6b +wx 50414421f5f5dcdc63000000000000000200000000000000303435313930376332656161383436376538343863303036376266653865643470726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082818180800060d5818080808080 +r2flutter -q -j -O ref:99~{snapshot.kind} +r2flutter -q -j -O ref:99~{snapshot.complete} EOF EXPECT=</dev/null | sed -n '1,6p' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -zz~:0..6 EOF EXPECT=</dev/null | sed -n '1p' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -vzz~:0 EOF EXPECT=</dev/null | head -7 +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -zz~:0..7 EOF EXPECT=</dev/null | head -6 +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -qrzz~:0..6 EOF EXPECT=</dev/null | sed -n '1,14p' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -zz~:0..14 EOF EXPECT=</dev/null | sed -n '1,14p' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -xzz~:0..14 EOF EXPECT=</dev/null | python3 -c 'import json, sys; a = json.load (sys.stdin); e = next (s for s in a if s["value"] == "useShouldInterceptRequest"); r = e["refs"][0]; print ("count=%d value=%s addr=0x%x kind=%s ref=%d name=%s" % (len (a), e["value"], e["addr"], r["kind"], r["obj"], r["name"]))' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -j -xz~{[0]} EOF EXPECT=</dev/null | sed -n '1,3p' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -z~:0..3 EOF EXPECT=</dev/null | sed -n '1,4p' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -q -r -x -z~:0..4 EOF EXPECT=</dev/null | sed -n '1,3p'" +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -qz~:0..3 EOF EXPECT=</dev/null | sed -n '1,7p' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -zz~:0..7 EOF EXPECT=</dev/null | head -7 +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -zz~:0..7 EOF EXPECT=</dev/null | sed -n '1,6p' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -T~:0..6 EOF EXPECT=</dev/null | grep '^enum AppLifecycleState {' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -T~^enum AppLifecycleState EOF EXPECT=</dev/null | grep '^enum AppLifecycleState {' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -T~^enum AppLifecycleState EOF EXPECT=</dev/null | sed -n '1,7p' +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -T~:0..7 EOF EXPECT=</dev/null | head -6 +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -T~:0..6 EOF EXPECT=</dev/null | head -7 +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -T~:0..7 EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -l 4 -x EOF EXPECT=< string _Uint16List @ 0x1660 @@ -12,9 +14,11 @@ EOF RUN NAME=json-xrefs-android -FILE=- +FILE=bins/android/first/libapp.so CMDS=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -l 3 -x EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -l 2 -x EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -l 4 -x EOF EXPECT=< string Pointer [ref=151] @ 0x1b24d0 +metadata class.library class Pointer [ref=36652] -> library library#41733 [ref=41733] metadata method.owner method Pointer.get:hashCode [ref=31064] -> class Pointer [ref=36652] metadata method.name method Pointer.get:hashCode [ref=31064] -> string get:hashCode [ref=7217] @ 0x2b0230 -metadata method.signature method Pointer.get:hashCode [ref=31064] -> type type#1 [ref=1] EOF RUN NAME=json-xrefs-ios -FILE=- +FILE=bins/ios/Runner.app/Frameworks/App.framework/App CMDS=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -j -l 3 -x EOF EXPECT=</dev/null +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -r -l 2 -x EOF EXPECT=< string Pointer [ref=151] @ 0x1b24d0 '@0x1b24d0'CCu base64:UG9pbnRlcg== -# metadata method.owner method Pointer.get:hashCode [ref=31064] -> class Pointer [ref=36652] +# metadata class.library class Pointer [ref=36652] -> library library#41733 [ref=41733] EOF RUN diff --git a/test/db/extras/compstr b/test/db/extras/compstr index 47b2eb4..c0370b8 100644 --- a/test/db/extras/compstr +++ b/test/db/extras/compstr @@ -1,7 +1,11 @@ NAME=compstr -FILE=- +FILE=bins/ios/Runner.app/Frameworks/App.framework/App CMDS=</dev/null" | head -c 200 +L ../src/r2/core_flutter.dylib +L ../src/r2/core_flutter.so +r2flutter -jzz~{[0]} +EOF +EXPECT=< -Modifiers: - -h Show help - -j Output in JSON format - -n Heuristic fallback for unknown functions; may assign wrong names - -q Compact output; suppress non-essential detail - -r Output r2 commands for the selected action - -v Verbose (stderr debug info) - -vv More verbose (dump headers) - -V Show version -Actions: - -A[AA] Analyze Dart snapshot and apply flags/comments - -c[jr*] Print extracted class information - -f[jr*] Print all extracted functions (addr name) - -H[HH] Print Dart AOT snapshot header info - -i[jr*] Print instruction table entries (-ii same as -i) - -ie[jr*], -E[jr*] Print Dart code entrypoint - -O Decode Dart tagged/object pointer or ObjectPool PP slot - -p[jr*] Print reconstructed ObjectPool PP value - -R Print radare2 script for snapshot analysis - -S[jr*] Print best-effort recovered SBOM/components - -T[jr*] Print string-based type names - -x[jr*] Print metadata/data-image xrefs; with -z, include string refs/ax in -r - -z[jr*] Print reliable ObjectPool-referenced strings (-q prints values only) - -zz[jr*] Print all fuzzy/carved extracted strings (-xzz includes refs/ax in -r) -Options: - -D Override Dart snapshot profile for analysis - -l Limit output to N items - -m Load Flutter obfuscation map JSON -=== -Usage: r2flutter [j*] +Usage: r2flutter [qjr*] | r2flutter -A[AA] analyze dart snapshot and apply flags/comments -| r2flutter -c[j*] dump classes +| r2flutter -c[jr*] dump classes | r2flutter -C apply Dart classes, fields, methods and types | r2flutter -D prof override Dart snapshot profile by hash or version -| r2flutter -f[j*] dump recovered functions +| r2flutter -E[jr*] dump Dart code entrypoint +| r2flutter -f[jr*] dump recovered functions | r2flutter -H[HH] dump Dart AOT snapshot header info -| r2flutter -i[j*] dump instruction table entries -| r2flutter -ie[j*] dump Dart code entrypoint; with -* mark instruction snapshots as dword arrays +| r2flutter -i[jr*] dump instruction table entries +| r2flutter -ie[jr*] dump Dart code entrypoint; with -r/-* mark instruction snapshots as dword arrays | r2flutter -l N limit function/instruction-table/xref output | r2flutter -m file load Flutter obfuscation map JSON | r2flutter -n use heuristic name-pool fallback; names may be wrong -| r2flutter -O addr decode Dart tagged/object pointer or ObjectPool PP slot -| r2flutter -p[j*] print reconstructed ObjectPool PP value +| r2flutter -O spec decode a tagged pointer, PP slot, or snapshot ref:N +| r2flutter -p[jr*] print reconstructed ObjectPool PP value | r2flutter -R dump full radare2 script (like standalone -R) -| r2flutter -S[j*] dump best-effort recovered SBOM/components -| r2flutter -T[j*] dump string-based type names -| r2flutter -x[j*] dump metadata/data-image xrefs; with -z, include string refs/ax in -* -| r2flutter -z[j*] dump reliable ObjectPool-referenced strings -| r2flutter -zz[j*] dump all fuzzy/carved strings (-xzz includes refs/ax in -*) +| r2flutter -S[jr*] dump best-effort recovered SBOM/components +| r2flutter -T[jr*] dump string-based type names +| r2flutter -x[jr*] dump metadata/data-image xrefs; with -z, include string refs/ax in -r/-* +| r2flutter -z[jr*] dump reliable ObjectPool-referenced strings +| r2flutter -zz[jr*] dump all fuzzy/carved strings (-xzz includes refs/ax in -r/-*) | r2flutter -h show this help | r2flutter -v increase parser verbosity | r2flutter -V show version -Modifiers: j=json, *=r2 commands +Modifiers: q=quiet, j=json, r/*=r2 commands === -Usage: ../bin/r2flutter [-jrv*] -=== -Usage: r2flutter [j*] +Usage: r2flutter [qjr*] | r2flutter -A[AA] analyze dart snapshot and apply flags/comments -| r2flutter -c[j*] dump classes +| r2flutter -c[jr*] dump classes | r2flutter -C apply Dart classes, fields, methods and types | r2flutter -D prof override Dart snapshot profile by hash or version -| r2flutter -f[j*] dump recovered functions +| r2flutter -E[jr*] dump Dart code entrypoint +| r2flutter -f[jr*] dump recovered functions | r2flutter -H[HH] dump Dart AOT snapshot header info -| r2flutter -i[j*] dump instruction table entries -| r2flutter -ie[j*] dump Dart code entrypoint; with -* mark instruction snapshots as dword arrays +| r2flutter -i[jr*] dump instruction table entries +| r2flutter -ie[jr*] dump Dart code entrypoint; with -r/-* mark instruction snapshots as dword arrays | r2flutter -l N limit function/instruction-table/xref output | r2flutter -m file load Flutter obfuscation map JSON | r2flutter -n use heuristic name-pool fallback; names may be wrong -| r2flutter -O addr decode Dart tagged/object pointer or ObjectPool PP slot -| r2flutter -p[j*] print reconstructed ObjectPool PP value +| r2flutter -O spec decode a tagged pointer, PP slot, or snapshot ref:N +| r2flutter -p[jr*] print reconstructed ObjectPool PP value | r2flutter -R dump full radare2 script (like standalone -R) -| r2flutter -S[j*] dump best-effort recovered SBOM/components -| r2flutter -T[j*] dump string-based type names -| r2flutter -x[j*] dump metadata/data-image xrefs; with -z, include string refs/ax in -* -| r2flutter -z[j*] dump reliable ObjectPool-referenced strings -| r2flutter -zz[j*] dump all fuzzy/carved strings (-xzz includes refs/ax in -*) +| r2flutter -S[jr*] dump best-effort recovered SBOM/components +| r2flutter -T[jr*] dump string-based type names +| r2flutter -x[jr*] dump metadata/data-image xrefs; with -z, include string refs/ax in -r/-* +| r2flutter -z[jr*] dump reliable ObjectPool-referenced strings +| r2flutter -zz[jr*] dump all fuzzy/carved strings (-xzz includes refs/ax in -r/-*) | r2flutter -h show this help | r2flutter -v increase parser verbosity | r2flutter -V show version -Modifiers: j=json, *=r2 commands +Modifiers: q=quiet, j=json, r/*=r2 commands EOF RUN