mirror of
https://github.com/radareorg/r2flutter.git
synced 2026-11-07 06:26:00 -10:00
Unify the tag from cid getter for the 3 possible formats
This commit is contained in:
1 parent
e9fa905562
commit
897a98d24d
9 files changed
+29
-65
No files matched your search
@@ -24,6 +24,7 @@ rank; each item states the concrete failure it causes.
|
||||
| `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`. |
|
||||
| `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. |
|
||||
| *(uncommitted)* | **P2.5 + part of P0.2**: 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. Also lands the **P0.2 read-only-data rule** (`modern_walk_is_rodata`): the six classes Dart moves into the data image when pointer compression is off now correctly have no fill records. Inert until the gate opens. |
|
||||
| *(uncommitted)* | **P1.1**: one `dart_cid_from_tags` helper now decodes `CID_INT32`, `CID_SHIFT1`, and `OBJECT_HEADER` tags for object inspection, modern and legacy cluster walks, data-image scanners, and InstructionTable discovery. This removes the duplicate decoders and fixes `CID_INT32` being treated as `OBJECT_HEADER` in two paths. |
|
||||
|
||||
Corrections to earlier assumptions, worth remembering:
|
||||
- **The CID tables are not the problem.** Flooring is exactly correct 2.10→3.12,
|
||||
@@ -133,18 +134,6 @@ app samples need collecting.
|
||||
|
||||
## P1 — correctness, lower prevalence or already-guarded
|
||||
|
||||
### P1.1 Tag-style CID decode applied inconsistently
|
||||
`dart_object.c:88-99` honours all three `DartTagStyle` variants, but cluster/CID
|
||||
decode hardcodes the OBJECT_HEADER form `(tags>>12)&0xFFFFF` in
|
||||
`dart_pool_clusters.c:226`, `modern_cid_from_tags` (`dart_pool_modern.c`, now the
|
||||
decoder's single site after P2.5), `dart_pool_data_image.c:82`; and
|
||||
`dart_pool_it.c:158-160` routes **CID_INT32** into the OBJECT_HEADER formula
|
||||
(should be `header & 0xffffffff`).
|
||||
**Failure:** pre-2.14 (CID_INT32) and 2.14–3.3 (CID_SHIFT1) snapshots are
|
||||
mis-decoded by every cluster walker. Mitigated today only because those eras also
|
||||
fail the modern gate and fall back to scanners.
|
||||
**Fix:** one tag-style-aware extractor, called everywhere.
|
||||
|
||||
### P1.2 Hardcoded 8-byte target word / arm64 assumptions
|
||||
- `modern_target_word_size()` (`dart_pool_modern.c:1196-1199`) **ignores `ctx` and
|
||||
returns 8** — it takes `ctx` only to `(void)` it. All ObjectPool `pp_offset`
|
||||
@@ -294,8 +283,7 @@ repeatedly. Consider a small multi-window/LRU cache and a short-read-tolerant re
|
||||
the landed P0.1 fix an end-to-end regression test.
|
||||
3. **P2.1 + P3.1** — delete the legacy walker; one cluster walk, one data scan.
|
||||
4. **P1.3** — shared frontend parser (fixes the `-r`/`r2 -n` AGENTS.md violations).
|
||||
5. **P1.1, P1.2** — tag-style helper (now a one-line change in the modern decoder
|
||||
thanks to P2.5); arch gating.
|
||||
5. **P1.2** — arch gating.
|
||||
6. **P3.2–P3.4**, remaining P1/P2 cleanups, test hardening.
|
||||
|
||||
`COMMIT2.md` tracks the narrower follow-ups left over from the discovery work
|
||||
|
||||
@@ -1121,6 +1121,13 @@ so the generator keeps `2.18.2` on the `3.9.2`-shaped fallback CID table used by
|
||||
the sample. This is documented as a Flutter-engine snapshot quirk, not as
|
||||
standalone Dart SDK `2.18.2` CID data.
|
||||
|
||||
CID extraction must go through `dart_cid_from_tags()`. Serialized snapshots use
|
||||
three encodings: a raw 32-bit CID through Dart 2.13, a CID shifted left by one
|
||||
through Dart 3.3, and the ObjectHeader bitfield from Dart 3.4 onward. Keeping the
|
||||
formula in one helper prevents object, cluster, data-image, and InstructionTable
|
||||
parsers from silently disagreeing. This only centralizes tag decoding; older
|
||||
cluster fill layouts still need validation before the modern parser gate opens.
|
||||
|
||||
## Dart SDK Stable Tag Refresh
|
||||
|
||||
Running `scripts/update-dart-version --sync-stable-tags --min-version 2.10.0`
|
||||
|
||||
+1
-14
@@ -85,19 +85,6 @@ static int dart_object_heap_tag(DartCtx *ctx) {
|
||||
return tag;
|
||||
}
|
||||
|
||||
static int dart_object_cid_from_header(DartCtx *ctx, ut64 header) {
|
||||
DartTagStyle style = ctx && ctx->layout? ctx->layout->tag_style: DART_TAG_STYLE_OBJECT_HEADER;
|
||||
switch (style) {
|
||||
case DART_TAG_STYLE_CID_INT32:
|
||||
return (int) (header & 0xffffffffU);
|
||||
case DART_TAG_STYLE_CID_SHIFT1:
|
||||
return (int) ((header >> 1) & 0xffffffffU);
|
||||
case DART_TAG_STYLE_OBJECT_HEADER:
|
||||
default:
|
||||
return (int) ((header >> 12) & 0xfffffU);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *dart_object_cid_name(DartCtx *ctx, int cid) {
|
||||
const DartVerLayout *layout = ctx? ctx->layout: NULL;
|
||||
for (int i = 0; i < DART_CID_KIND_COUNT; i++) {
|
||||
@@ -265,7 +252,7 @@ static bool dart_object_decode_at(DartCtx *ctx, ut64 addr, DartObjectInfo *out)
|
||||
}
|
||||
out->addr = addr;
|
||||
out->header = r_read_le64 (hdr);
|
||||
out->cid = dart_object_cid_from_header (ctx, out->header);
|
||||
out->cid = (int)dart_cid_from_tags (ctx, out->header);
|
||||
if (out->cid <= 0 || out->cid >= 0xfffff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1509,7 +1509,7 @@ RList *dart_pool_extract_classes(DartCtx *ctx) {
|
||||
if (!cs_read_u32 (&stream, &tags)) {
|
||||
break;
|
||||
}
|
||||
uint32_t cid = (tags >> 12) & 0xFFFFF;
|
||||
const uint32_t cid = dart_cid_from_tags (ctx, tags);
|
||||
bool is_canonical = ((tags >> 1) & 1) != 0;
|
||||
(void)is_canonical;
|
||||
if (ctx->verbose > 1) {
|
||||
|
||||
@@ -223,7 +223,7 @@ int deserialize_clusters(DartCtx *ctx, ut64 cluster_start, ut64 cluster_end, ut6
|
||||
}
|
||||
break;
|
||||
}
|
||||
uint32_t cid = (tags >> 12) & 0xFFFFF;
|
||||
const uint32_t cid = dart_cid_from_tags (ctx, tags);
|
||||
bool is_canonical = ((tags >> 1) & 1) != 0;
|
||||
if (ctx->verbose > 1) {
|
||||
fprintf (stderr, "[r2flutter] Cluster %" PRIu64 ": cid=%u canonical=%d cursor=0x%" PFMT64x "\n", ci, cid, is_canonical, stream.cursor);
|
||||
|
||||
@@ -21,21 +21,6 @@ void init_function_layout(DartCtx *ctx, DartFunctionLayout *fl) {
|
||||
}
|
||||
}
|
||||
|
||||
static ut32 extract_cid_from_header(DartCtx *ctx, ut64 header) {
|
||||
if (!ctx || !ctx->layout) {
|
||||
return 0;
|
||||
}
|
||||
switch (ctx->layout->tag_style) {
|
||||
case DART_TAG_STYLE_OBJECT_HEADER:
|
||||
return (ut32) ((header >> 12) & 0xFFFFF);
|
||||
case DART_TAG_STYLE_CID_SHIFT1:
|
||||
return (ut32) (header >> 1);
|
||||
case DART_TAG_STYLE_CID_INT32:
|
||||
default:
|
||||
return (ut32) ((header >> 12) & 0xFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
static bool read_object_pointer(DartCtx *ctx, const ut8 *buf, ut32 off, bool use_compressed, ut64 data_base, ut64 data_end, bool restrict_range, ut64 *out_addr) {
|
||||
(void)ctx;
|
||||
if (use_compressed) {
|
||||
@@ -79,7 +64,7 @@ bool read_data_image_field(DartCtx *ctx, ut64 pos, ut64 data_start, ut64 data_en
|
||||
return false;
|
||||
}
|
||||
ut64 header = r_read_le64 (hdr);
|
||||
if ((int) ((header >> 12) & 0xFFFFF) != kFieldCid) {
|
||||
if ((int)dart_cid_from_tags (ctx, header) != kFieldCid) {
|
||||
return false;
|
||||
}
|
||||
bool use_compressed = ctx->compressed_word_size == 4;
|
||||
@@ -174,7 +159,7 @@ bool read_data_image_method(DartCtx *ctx, ut64 pos, ut64 data_start, ut64 data_e
|
||||
}
|
||||
const int resolved_function_cid = dart_cid_get (ctx->layout, DART_CID_FUNCTION);
|
||||
const int cid_function = resolved_function_cid >= 0? resolved_function_cid: kFunctionCid;
|
||||
if ((int)extract_cid_from_header (ctx, r_read_le64 (buf)) != cid_function) {
|
||||
if ((int)dart_cid_from_tags (ctx, r_read_le64 (buf)) != cid_function) {
|
||||
return false;
|
||||
}
|
||||
ut64 entry = r_read_le64 (buf + fl->entry_off);
|
||||
|
||||
+1
-13
@@ -147,19 +147,7 @@ static bool read_it_data_header_from_string_object(DartCtx *ctx, ut64 obj_addr,
|
||||
return false;
|
||||
}
|
||||
ut64 tags = r_read_le64 (objhdr);
|
||||
ut32 cid = 0;
|
||||
switch (ctx->layout->tag_style) {
|
||||
case DART_TAG_STYLE_OBJECT_HEADER:
|
||||
cid = (ut32) ((tags >> 12) & 0xFFFFF);
|
||||
break;
|
||||
case DART_TAG_STYLE_CID_SHIFT1:
|
||||
cid = (ut32) (tags >> 1);
|
||||
break;
|
||||
case DART_TAG_STYLE_CID_INT32:
|
||||
default:
|
||||
cid = (ut32) ((tags >> 12) & 0xFFFFF);
|
||||
break;
|
||||
}
|
||||
const ut32 cid = dart_cid_from_tags (ctx, tags);
|
||||
const int resolved_string_cid = dart_cid_get (ctx->layout, DART_CID_ONE_BYTE_STRING);
|
||||
const int string_cid = resolved_string_cid >= 0? resolved_string_cid: kOneByteStringCid;
|
||||
if ((int)cid != string_cid) {
|
||||
|
||||
@@ -1361,10 +1361,6 @@ static bool modern_read_cluster_tags(ClusterStream *s, DartCtx *ctx, ut32 *out)
|
||||
return cs_read_tagged32 (s, out);
|
||||
}
|
||||
|
||||
static int modern_cid_from_tags(ut32 tags) {
|
||||
return (int) ((tags >> 12) & 0xFFFFF);
|
||||
}
|
||||
|
||||
// Shared alloc/fill cluster walker.
|
||||
//
|
||||
// Every consumer below reads the same stream the same way: for each cluster a
|
||||
@@ -1492,7 +1488,7 @@ static bool modern_walk_alloc(ModernWalk *w, ClusterStream *s) {
|
||||
if (!modern_read_cluster_tags (s, w->ctx, &tags)) {
|
||||
return modern_walk_fail (w, "alloc tag", i, s->cursor, -1);
|
||||
}
|
||||
m->cid = modern_cid_from_tags (tags);
|
||||
m->cid = (int)dart_cid_from_tags (w->ctx, tags);
|
||||
m->is_canonical = ((tags >> 1) & 1) != 0;
|
||||
m->is_immutable = (tags & (1 << 6)) != 0;
|
||||
m->start_ref = next_ref;
|
||||
|
||||
@@ -17,6 +17,19 @@ typedef struct {
|
||||
ut64 end;
|
||||
} ClusterStream;
|
||||
|
||||
static inline ut32 dart_cid_from_tags(const DartCtx *ctx, ut64 tags) {
|
||||
const DartTagStyle style = ctx && ctx->layout? ctx->layout->tag_style: DART_TAG_STYLE_OBJECT_HEADER;
|
||||
switch (style) {
|
||||
case DART_TAG_STYLE_CID_INT32:
|
||||
return (ut32)tags;
|
||||
case DART_TAG_STYLE_CID_SHIFT1:
|
||||
return (ut32) (tags >> 1);
|
||||
case DART_TAG_STYLE_OBJECT_HEADER:
|
||||
default:
|
||||
return (ut32) ((tags >> 12) & 0xfffffU);
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
kIllegalCid = 0,
|
||||
kClassCid = 5,
|
||||
|
||||
Reference in new issue
Block a user