Problem
Dart AOT does not maintain a stable ABI. Across minor Dart and Flutter releases, the VM changes snapshot magic hashes, Class IDs (CIDs), struct field offsets, and occasionally the underlying clustered serialization algorithms and reference encoding formats.
Attempting to address this by releasing a full flutterdec binary per Flutter/Dart version is unmaintainable:
- Release explosion: Rebuilding and maintaining 100+ full decompiler binaries across release matrices.
- Maintenance overhead: Bug fixes in ARM64 disassembly, IR generation, CFG structuring, or pseudocode lifting would require backporting to dozens of version branches.
- Misalignment with tool architecture: >90% of
flutterdec (instruction decoding, LLIR, CFG structuring, expression lifters, quality gates, and export script emitters) is Dart-version-agnostic.
Conversely, relying exclusively on static layout tables (data/dart-profiles.json) only solves identification and static field offsets; it cannot deserialize snapshots when cluster encoding formats or serializer logic evolve in new Dart VM generations.
Proposed Solution
Maintain a single, unified flutterdec core binary and decouple snapshot parsing into independently versioned parser adapters keyed by snapshot hash.
[Target Binary (libapp.so)]
│
├──> flutterdec Loader (Extracts 32-byte Snapshot Hash)
│
├──> Exact Adapter Resolution (`dart_adapter_<hash>`)
│ ├── Exact Hash Match --> Executes dedicated parser backend (Serwalker / r2flutter / compiled parser)
│ └── Unmapped / Beta --> Verified fallback or graceful degradation to instruction carving
│
└──> ProgramModel JSON (Schema v3)
│
└──> Unified flutterdec Core Engine (Disasm -> IR -> CFG -> Decompiler)
Key Components
-
Strict Core / Adapter Contract (ProgramModel Schema v3):
- Keep the adapter boundary as a strictly validated JSON contract (
schemas/adapter.schema.json).
- The core consumes
ProgramModel (libraries, classes, functions, object_pool, pool_geometry) without embedding Dart VM version-specific C++ headers.
-
CI-Driven Adapter & Profile Harvesting:
- Implement automated CI jobs tracking the official Dart SDK repository.
- For each new Dart release/tag:
- Extract the 32-byte snapshot hash, CIDs, and struct layout constants into
data/dart-profiles.json.
- Build and package the corresponding lightweight parser adapter artifact.
- Publish signed adapter artifacts that can be installed via CLI:
flutterdec adapter install --dart-hash <HASH>
-
Safe Fallback & Graceful Degradation Policy:
- Exact match by default: Require exact snapshot hash matching for high-confidence deserialization.
- Opt-in family compatibility: Allow experimental fallback to a tested family profile only when strict invariant checks pass (e.g., valid entry VAs, bounded pool indices, non-corrupted string tables).
- Graceful fallback: If a snapshot format is unknown or unsupported, degrade cleanly to instruction stream analysis (
isolate_instructions), function prologue recovery, and dispatch table call detection (sel<offset>) rather than failing fatally or emitting plausible-but-hallucinated metadata.
Alternatives Considered
- One full
flutterdec binary per Flutter version:
- Trade-off: High release maintenance burden, broken UX, duplicated build artifacts for components that never change between Dart versions.
- Monolithic in-core Rust deserializer:
- Trade-off: Heavy maintenance burden to mirror Dart VM C++ changes in Rust; high risk of silent deserialization breakage when VM serialization internals shift.
Scope and Risks
- Affected crates/modules:
crates/flutterdec-adapter: Adapter registry management, artifact verification, and manifest resolution.
adapters/: Reference adapter templates and native backend integrations (Serwalker / r2flutter / blutter).
data/dart-profiles.json: Continued profile updates for static identification.
- CI / GitHub Actions: Automated scraping and build pipelines for Dart SDK tags.
- Expected impact on performance/quality:
- Zero performance regression on the core disassembly/decompilation pipeline.
- Faster onboarding of new Flutter/Dart versions without binary rebuilds.
- Eliminates false-positive metadata by enforcing strict hash matching and schema validation.
- Test strategy:
- Acceptance tests verifying that fixtures from at least two distinct Dart snapshot families produce valid Schema v3
ProgramModel outputs.
- Test verifying unknown snapshot hashes take the safe fallback path without fabricating metadata.
- Negative test suite ensuring corrupt or mismatched adapter artifacts fail validation gracefully on checksum, snapshot hash, and schema checks.
- Determinism & regression test ensuring existing decompilation golden outputs remain unchanged.
Proposed Next Steps
- Formalize the adapter distribution manifest schema (version, snapshot_hash, schema_version, os/arch, checksum).
- Set up automated CI workflows to track new Dart SDK releases and produce layout profiles / adapters.
- Validate Serwalker integration as a primary native snapshot parser backend emitting Schema v3
ProgramModel.
Problem
Dart AOT does not maintain a stable ABI. Across minor Dart and Flutter releases, the VM changes snapshot magic hashes, Class IDs (CIDs), struct field offsets, and occasionally the underlying clustered serialization algorithms and reference encoding formats.
Attempting to address this by releasing a full
flutterdecbinary per Flutter/Dart version is unmaintainable:flutterdec(instruction decoding, LLIR, CFG structuring, expression lifters, quality gates, and export script emitters) is Dart-version-agnostic.Conversely, relying exclusively on static layout tables (
data/dart-profiles.json) only solves identification and static field offsets; it cannot deserialize snapshots when cluster encoding formats or serializer logic evolve in new Dart VM generations.Proposed Solution
Maintain a single, unified
flutterdeccore binary and decouple snapshot parsing into independently versioned parser adapters keyed by snapshot hash.Key Components
Strict Core / Adapter Contract (
ProgramModelSchema v3):schemas/adapter.schema.json).ProgramModel(libraries,classes,functions,object_pool,pool_geometry) without embedding Dart VM version-specific C++ headers.CI-Driven Adapter & Profile Harvesting:
data/dart-profiles.json.Safe Fallback & Graceful Degradation Policy:
isolate_instructions), function prologue recovery, and dispatch table call detection (sel<offset>) rather than failing fatally or emitting plausible-but-hallucinated metadata.Alternatives Considered
flutterdecbinary per Flutter version:Scope and Risks
crates/flutterdec-adapter: Adapter registry management, artifact verification, and manifest resolution.adapters/: Reference adapter templates and native backend integrations (Serwalker / r2flutter / blutter).data/dart-profiles.json: Continued profile updates for static identification.ProgramModeloutputs.Proposed Next Steps
ProgramModel.