mirror of
https://github.com/radareorg/r2flutter.git
synced 2026-11-08 07:28:14 -10:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cef0ce07a | ||
|
|
7d019ea748 | ||
|
|
f7c6cc5b3d | ||
|
|
24e3502737 | ||
|
|
78719df43e | ||
|
|
3fe3c11bac |
No files matched your search
@@ -1797,3 +1797,89 @@ misaligned). Not yet handled: the x64 ObjectPool *slot* decoder (`-O pp+off`)
|
||||
still misreads compressed pool pointers, so a slot that the collector did not
|
||||
already resolve stays a bare offset; and there is no committed x86_64 test
|
||||
fixture.
|
||||
|
||||
## Dart 2.19 Type fill must not consume the legacy combined byte
|
||||
|
||||
The Flutter 3.7.12/Dart 2.19.0 snapshot hash
|
||||
`adb4292f3ec25074ca70abcd2d5c7251` exposed a one-byte fill-stream drift:
|
||||
`r2flutter -HHH` stopped after the `TypeArguments` cluster and reported the
|
||||
later ObjectPool as `fill_not_parsed`. Consequently `-AAA` could not build the
|
||||
synthetic PP image or apply ObjectPool string xrefs; `axt 0x31903` for
|
||||
`https://www.game250522linecfg.xyz` was empty.
|
||||
|
||||
The cause was treating all Dart 2.x `Type::ReadFill` records alike. Through
|
||||
2.18 their three references are followed by `ReadUnsigned(type_class_id)` and
|
||||
a one-byte combined nullability/type-state field. Dart 2.19 replaces that pair
|
||||
with one `ReadUnsigned(flags)`. Consuming the obsolete byte desynchronizes the
|
||||
rest of the fill stream. Keep the old rule only before 2.19; with the corrected
|
||||
rule the ObjectPool reaches cluster 652, `-p` reconstructs 44955 entries, and
|
||||
`r2flutter -AAA` applies 11560 graph xrefs, including an `axt` result for
|
||||
0x31903.
|
||||
|
||||
## Code xrefs need discarded instructions and correctly shifted PP offsets
|
||||
|
||||
The Dart 2.19 sample above has 29622 instruction-table entries, but only 7545
|
||||
retained `Code` objects. `first_entry_with_code=22077` separates instructions
|
||||
whose `Code` metadata was discarded from entries with retained metadata; it
|
||||
does not separate non-executable stubs from application code. The VM writer
|
||||
in `runtime/vm/app_snapshot.cc` orders discarded Code objects first. Both URL
|
||||
loaders are in that prefix (IT indices 14623 and 15109).
|
||||
|
||||
An unlimited instruction-table extraction must use the table header's length,
|
||||
not the clustered header's retained Code count. `-AAA` must collect all table
|
||||
entrypoints in addition to named methods so these functions get basic blocks
|
||||
and their PP loads are scanned. `has_code` still controls Code-index metadata
|
||||
lookups; it must not decide whether instructions can be analyzed.
|
||||
|
||||
ARM64 decoders can return an already shifted `RArchValue.imm` for
|
||||
`add x17, x27, 0x46, lsl 12`. Applying the text's shift to that value again
|
||||
produces `0x46000000`, breaking the subsequent pool lookup. Read the unshifted
|
||||
immediate from the instruction text and apply the shift exactly once.
|
||||
|
||||
Verified with `/tmp/mal/libapp.so` (identical to `libapp.so.noxrefs`):
|
||||
|
||||
- `0x85b028` in `fcn.0085afb0` loads `PP+0x46200` and now has a direct string
|
||||
xref to `0x73986` (`https://reg.gptreg0706.xyz`).
|
||||
- `0x836f98` in `fcn.00836f4c` loads `PP+0x4e6c8` and now has a direct string
|
||||
xref to `0x31903` (`https://www.game250522linecfg.xyz`).
|
||||
|
||||
The unaligned `0x20022d` and `0x2086f5` sources are synthetic pool slots in
|
||||
the serialized snapshot address range, not executable use sites. `-AA` keeps
|
||||
those pool links; `-AAA` adds the instruction-to-string links. Regression tests
|
||||
cover a cached discarded-Code table on Android, and real shifted PP loads on
|
||||
Android w0rdle and iOS Runner without depending on the private samples.
|
||||
|
||||
## Dart 2.19 class metadata uses the modern fill walker
|
||||
|
||||
`-c` printed ~280 `size=0` classes for a Dart 2.19 Android sample because
|
||||
`modern_can_extract_classes` only accepted `OBJECT_HEADER` (3.4+) snapshots.
|
||||
The legacy class parser then failed on the first (unified `String`) cluster
|
||||
and the string heuristic took over. The modern walker already handles
|
||||
`CID_SHIFT1` (2.14-3.3) for `-H`, pools and xrefs, and the Class fill layout
|
||||
(13 refs: name=0, library=7, super_type=9) matches 2.19 product snapshots.
|
||||
Gating on `modern_supported` recovers 6914 classes, 1515 fields and 7398
|
||||
methods on that sample.
|
||||
|
||||
## Class methods resolve entry points from InstructionTable slots
|
||||
|
||||
`Function` fills only carry a code index; `DartMethodInfo.entry_point` was
|
||||
never set, so every class method printed `0x00000000` on all versions. The
|
||||
index is the raw InstructionTable slot, not the `first_entry_with_code`
|
||||
relative `DartInstructionTableEntry.code_index`. Slots below
|
||||
`first_entry_with_code` belong to functions whose Code object was discarded
|
||||
(`dwarf_stack_traces_mode`), but they still own real instructions, so they are
|
||||
mapped too. On the 2.19 sample 22077 of 29622 slots are like that; `-f` used
|
||||
to list only the 7545 Code-backed ones and now also gets the 4614 named
|
||||
methods in the discarded range through `dart_app_merge_class_methods`.
|
||||
InstructionTable names stay authoritative there: `dedup_instructions` makes
|
||||
several methods share one body, so class-derived names only replace
|
||||
placeholder (`func.*`, `method.fn_*`) names.
|
||||
|
||||
## Signed 64-bit varints use the 192 end-byte marker
|
||||
|
||||
`cs_read_tagged64` decoded the final varint byte as `raw - 64` instead of
|
||||
`raw - 192` (`ReadStream::Read<T>` uses `kEndByteMarker`), adding
|
||||
`128 << shift` to every Mint/Smi. Field offsets (`host_offset_or_field_id`)
|
||||
came out as 128 + words, e.g. `_Closure._context` at `+0x428` instead of
|
||||
`+0x28` on 64-bit, and the `SemanticsAction` const map key `tap` decoded as
|
||||
129 instead of 1. `cs_read_tagged32` was already correct.
|
||||
+13
-4
@@ -265,6 +265,9 @@ static int dart_function_cmp(const DartFunction *fa, const DartFunction *fb) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Above placeholder names (func.*, method.fn_*) but below any resolved name.
|
||||
#define DART_CLASS_METHOD_NAME_QUALITY 20
|
||||
|
||||
static int dart_function_name_quality(const char *name) {
|
||||
if (R_STR_ISEMPTY (name)) {
|
||||
return 0;
|
||||
@@ -476,14 +479,17 @@ static char *dart_format_method_full_name(const DartClassInfo *ci, const DartMet
|
||||
if (!mi || R_STR_ISEMPTY (mi->name)) {
|
||||
return NULL;
|
||||
}
|
||||
char *lib = dart_sanitize_component (ci && ci->library_name? ci->library_name: "app", true);
|
||||
// Without a library name use the InstructionTable form (method.Owner.leaf)
|
||||
// so both sources agree on the name of the same entry.
|
||||
char *lib = ci && ci->library_name? dart_sanitize_component (ci->library_name, true): NULL;
|
||||
char *owner = dart_sanitize_component (ci && ci->name? ci->name: mi->owner_name, false);
|
||||
char *leaf = dart_format_method_leaf_name (ci? ci->name: mi->owner_name, mi);
|
||||
const char *name = leaf? leaf: mi->name;
|
||||
char *out = NULL;
|
||||
if (R_STR_ISNOTEMPTY (owner)) {
|
||||
out = r_str_newf ("method.%s.%s.%s", lib, owner, leaf? leaf: mi->name);
|
||||
out = lib? r_str_newf ("method.%s.%s.%s", lib, owner, name): r_str_newf ("method.%s.%s", owner, name);
|
||||
} else {
|
||||
out = r_str_newf ("method.%s..%s", lib, leaf? leaf: mi->name);
|
||||
out = lib? r_str_newf ("method.%s..%s", lib, name): r_str_newf ("method.%s", name);
|
||||
}
|
||||
r_name_filter (out, 0);
|
||||
free (lib);
|
||||
@@ -533,11 +539,14 @@ static void dart_app_merge_class_methods(DartApp *app) {
|
||||
continue;
|
||||
}
|
||||
char *fullname = dart_format_method_full_name (ci, mi);
|
||||
// InstructionTable names stay authoritative: deduplicated code is
|
||||
// shared by several methods, so class metadata only fills the
|
||||
// placeholder names the table could not resolve.
|
||||
dart_app_add_or_update_fn (app,
|
||||
fullname? fullname: mi->name,
|
||||
dart_normalize_code_addr (mi->entry_point),
|
||||
0,
|
||||
dart_function_name_quality (fullname? fullname: mi->name),
|
||||
R_MIN (dart_function_name_quality (fullname? fullname: mi->name), DART_CLASS_METHOD_NAME_QUALITY),
|
||||
mi->signature);
|
||||
free (fullname);
|
||||
}
|
||||
|
||||
@@ -1488,6 +1488,46 @@ static void resolve_class_and_field_names(DartCtx *ctx, RList *class_list, RList
|
||||
}
|
||||
}
|
||||
|
||||
// Function fills only carry an InstructionTable slot; decode the table once
|
||||
// and turn each method's slot into its entry address.
|
||||
static void resolve_method_entry_points(DartCtx *ctx, RList *class_list) {
|
||||
const int dump_snapshot_json = ctx->dump_snapshot_json;
|
||||
const int dump_fns_limit = ctx->dump_fns_limit;
|
||||
ctx->dump_snapshot_json = 0;
|
||||
ctx->dump_fns_limit = 0;
|
||||
RVecDartInstructionTableEntry *it = dart_pool_extract_instruction_table (ctx);
|
||||
ctx->dump_snapshot_json = dump_snapshot_json;
|
||||
ctx->dump_fns_limit = dump_fns_limit;
|
||||
if (!it) {
|
||||
return;
|
||||
}
|
||||
ut64 count = 0;
|
||||
DartInstructionTableEntry *ie;
|
||||
R_VEC_FOREACH (it, ie) {
|
||||
count = R_MAX (count, ie->index + 1);
|
||||
}
|
||||
// Function::code_index is the raw InstructionTable slot, not the
|
||||
// first_entry_with_code-relative index kept in ie->code_index. Slots below
|
||||
// first_entry_with_code lost their Code object (discarded in AOT) but
|
||||
// still own real instructions, so map them too.
|
||||
ut64 *addr_by_code_index = calloc (count + 1, sizeof (ut64));
|
||||
R_VEC_FOREACH (it, ie) {
|
||||
addr_by_code_index[ie->index] = ie->address;
|
||||
}
|
||||
RListIter *iter, *miter;
|
||||
DartClassInfo *ci;
|
||||
DartMethodInfo *mi;
|
||||
r_list_foreach (class_list, iter, ci) {
|
||||
r_list_foreach (ci->methods, miter, mi) {
|
||||
if (!mi->entry_point && mi->code_index < count) {
|
||||
mi->entry_point = addr_by_code_index[mi->code_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
free (addr_by_code_index);
|
||||
dart_instruction_table_list_free (it);
|
||||
}
|
||||
|
||||
RList *dart_pool_extract_classes(DartCtx *ctx) {
|
||||
if (!ctx || !ctx->core) {
|
||||
return NULL;
|
||||
@@ -1693,6 +1733,9 @@ RList *dart_pool_extract_classes(DartCtx *ctx) {
|
||||
}
|
||||
}
|
||||
dart_ctx_fini_layout (ctx, layout_owned);
|
||||
if (modern_classes) {
|
||||
resolve_method_entry_points (ctx, class_list);
|
||||
}
|
||||
return class_list;
|
||||
}
|
||||
|
||||
|
||||
@@ -392,6 +392,7 @@ typedef struct {
|
||||
// handful of clusters. Their readers are gated on this flag; everything
|
||||
// else is shared.
|
||||
bool legacy_format;
|
||||
bool legacy_type_combined_byte;
|
||||
bool shift1_format;
|
||||
bool closure_variable;
|
||||
// every CID this layout defines, indexed by kind; -1 when the kind is absent
|
||||
@@ -468,6 +469,7 @@ static ModernCidCache modern_cid_cache_init(const DartVerLayout *layout) {
|
||||
.typed_data_internal_limit = dart_cid_typed_data_limit (layout),
|
||||
.typed_data_stride = dart_cid_typed_data_stride (layout),
|
||||
.legacy_format = modern_layout_is_legacy (layout),
|
||||
.legacy_type_combined_byte = layout && dart_version_compare (layout->dart_version, "2.19.0") == -1,
|
||||
.shift1_format = layout && layout->tag_style == DART_TAG_STYLE_CID_SHIFT1,
|
||||
.closure_variable = layout && layout->closure_variable,
|
||||
};
|
||||
@@ -1077,14 +1079,26 @@ static ModernFillSpec modern_get_fill_spec(const ModernCidCache *cids, int cid)
|
||||
static const ModernFillSpecRule legacy_rules[] = {
|
||||
// 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<uint8_t>.
|
||||
{ DART_CID_TYPE, MODERN_FILL_REFS, 3, -1, -1, 2, { MODERN_SCALAR_UNSIGNED, MODERN_SCALAR_UINT8 } },
|
||||
// TypeParameter: ReadFromTo (3) + Read<int32_t> + 3x Read<uint8_t>.
|
||||
{ DART_CID_TYPE_PARAMETER, MODERN_FILL_REFS, 3, -1, -1, 4, { MODERN_SCALAR_TAGGED32, MODERN_SCALAR_UINT8, MODERN_SCALAR_UINT8, MODERN_SCALAR_UINT8 } },
|
||||
// SubtypeTestCache::ReadFill reads only the cache_ ref.
|
||||
{ DART_CID_SUBTYPE_TEST_CACHE, MODERN_FILL_REFS, 1, -1, -1, 0, { 0 } },
|
||||
};
|
||||
if (cids->legacy_format) {
|
||||
if (modern_cid_eq (cid, cids->type) && cids->legacy_type_combined_byte) {
|
||||
// Through Dart 2.18 Type::ReadFill has type_class_id followed by a
|
||||
// combined nullability/type-state byte. Dart 2.19 replaced those with
|
||||
// a single flags ReadUnsigned. Keeping the old byte for 2.19 shifts
|
||||
// every following fill cluster and makes the ObjectPool unreachable.
|
||||
return modern_fill_spec (&(ModernFillSpecRule){
|
||||
.kind = MODERN_FILL_REFS,
|
||||
.num_refs = 3,
|
||||
.name_idx = -1,
|
||||
.owner_idx = -1,
|
||||
.scalar_count = 2,
|
||||
.scalars = { MODERN_SCALAR_UNSIGNED, MODERN_SCALAR_UINT8 },
|
||||
});
|
||||
}
|
||||
for (size_t i = 0; i < R_ARRAY_SIZE (legacy_rules); i++) {
|
||||
if (modern_cid_of_kind (cids, legacy_rules[i].cid_kind) == cid) {
|
||||
return modern_fill_spec (&legacy_rules[i]);
|
||||
@@ -4450,7 +4464,7 @@ static bool modern_load_vm_base_strings(DartCtx *ctx, char **strings_by_ref, ut6
|
||||
}
|
||||
|
||||
static bool modern_can_extract_classes(DartCtx *ctx) {
|
||||
if (!ctx || !ctx->layout || ctx->layout->tag_style != DART_TAG_STYLE_OBJECT_HEADER) {
|
||||
if (!modern_supported (ctx)) {
|
||||
return false;
|
||||
}
|
||||
// Both pointer widths are supported: the class/field fill readers decode
|
||||
|
||||
@@ -460,7 +460,9 @@ static int decode_pool_and_emit(DartItEmitRequest *req) {
|
||||
goto cleanup;
|
||||
}
|
||||
const ut64 layout_cap = ctx->layout && ctx->layout->it_cap? ctx->layout->it_cap: 20000;
|
||||
const ut64 max_entries = req->max_entries > 0? req->max_entries: (req->on_it? itlen: layout_cap);
|
||||
// itlen counts retained Code objects, not instructions whose Code metadata
|
||||
// was discarded. Let the table header bound an unlimited IT extraction.
|
||||
const ut64 max_entries = req->max_entries > 0? req->max_entries: (req->on_it? 0: layout_cap);
|
||||
req->data_image_base = data_image_base;
|
||||
req->data_image_end = data_image_end;
|
||||
req->itlen = itlen;
|
||||
|
||||
@@ -483,33 +483,24 @@ bool cs_read_tagged32(ClusterStream *s, ut32 *out) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// ReadStream::Read<int64_t>: 7-bit groups, then a final byte holding a signed
|
||||
// value in [-64, 63] biased by kEndByteMarker (192).
|
||||
bool cs_read_tagged64(ClusterStream *s, int64_t *out) {
|
||||
ut8 raw = 0;
|
||||
if (!cs_read_u8 (s, &raw)) {
|
||||
return false;
|
||||
}
|
||||
int8_t b = (int8_t)raw;
|
||||
if (b < 0) {
|
||||
if (out) {
|
||||
*out = (int64_t)b + 192;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
int64_t v = (int64_t)raw;
|
||||
int shift = 7;
|
||||
for (int i = 1; i < 10; i++) {
|
||||
ut64 v = 0;
|
||||
int shift = 0;
|
||||
for (int i = 0; i < 10; i++) {
|
||||
ut8 raw = 0;
|
||||
if (!cs_read_u8 (s, &raw)) {
|
||||
return false;
|
||||
}
|
||||
b = (int8_t)raw;
|
||||
if (b < 0) {
|
||||
v |= ((int64_t)b + 192) << shift;
|
||||
if (raw > 0x7f) {
|
||||
v |= (ut64) ((int64_t)raw - 192) << shift;
|
||||
if (out) {
|
||||
*out = v;
|
||||
*out = (int64_t)v;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
v |= ((int64_t)raw) << shift;
|
||||
v |= (ut64)raw << shift;
|
||||
shift += 7;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -564,6 +564,7 @@ R_API RLibStruct radare_plugin = {
|
||||
.type = R_LIB_TYPE_CORE,
|
||||
.data = &r_core_plugin_r2flutter,
|
||||
.version = R2_VERSION,
|
||||
.abiversion = R2_ABIVERSION
|
||||
.abiversion = R2_ABIVERSION,
|
||||
.pkgname = "r2flutter"
|
||||
};
|
||||
#endif
|
||||
@@ -302,6 +302,22 @@ static bool flutter_parse_shifted_imm(const char *line, ut64 *imm) {
|
||||
if (!lsl) {
|
||||
return false;
|
||||
}
|
||||
// RArchValue.imm may already include the shift (depending on the ARM
|
||||
// decoder). Read the unshifted third operand before applying it once.
|
||||
const char *arg = strchr (line, ',');
|
||||
arg = arg? strchr (arg + 1, ','): NULL;
|
||||
if (!arg || arg >= lsl) {
|
||||
return false;
|
||||
}
|
||||
arg++;
|
||||
while (isspace ((ut8)*arg) || *arg == '#') {
|
||||
arg++;
|
||||
}
|
||||
char *end;
|
||||
ut64 value = strtoull (arg, &end, 0);
|
||||
if (end == arg) {
|
||||
return false;
|
||||
}
|
||||
const char *p = lsl + 3;
|
||||
while (isspace ((ut8)*p)) {
|
||||
p++;
|
||||
@@ -312,11 +328,11 @@ static bool flutter_parse_shifted_imm(const char *line, ut64 *imm) {
|
||||
if (!isdigit ((ut8)*p)) {
|
||||
return false;
|
||||
}
|
||||
int shift = atoi (p);
|
||||
if (shift <= 0 || shift >= 63) {
|
||||
ut64 shift = strtoull (p, NULL, 0);
|
||||
if (shift >= 64) {
|
||||
return false;
|
||||
}
|
||||
*imm <<= shift;
|
||||
*imm = value << shift;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -440,7 +456,7 @@ static bool flutter_parse_opinfo(const RAnalOp *op, FlutterOpInfo *info) {
|
||||
if (info->n_regs == 0 && (type == R_ANAL_OP_TYPE_RCALL || type == R_ANAL_OP_TYPE_UCALL || type == R_ANAL_OP_TYPE_ICALL || type == R_ANAL_OP_TYPE_IRCALL)) {
|
||||
flutter_parse_first_operand_reg (op->mnemonic, info);
|
||||
}
|
||||
if (info->has_imm && R_STR_ISNOTEMPTY (op->mnemonic)) {
|
||||
if (type == R_ANAL_OP_TYPE_ADD && info->has_imm && R_STR_ISNOTEMPTY (op->mnemonic)) {
|
||||
(void)flutter_parse_shifted_imm (op->mnemonic, &info->imm);
|
||||
}
|
||||
return info->n_regs > 0 || info->has_mem || info->has_imm;
|
||||
@@ -539,7 +555,7 @@ static bool flutter_model_load(FlutterAnalModel *model, RCore *core, DartCtx *dc
|
||||
}
|
||||
DartCtx ctx = *dctx;
|
||||
ctx.core = core;
|
||||
dart_recovery_model_load (&ctx, model, DART_RECOVERY_STRINGS | DART_RECOVERY_CLASSES | DART_RECOVERY_CLASS_FIELDS | DART_RECOVERY_METHOD_INDEX);
|
||||
dart_recovery_model_load (&ctx, model, DART_RECOVERY_STRINGS | DART_RECOVERY_CLASSES | DART_RECOVERY_CLASS_FIELDS | DART_RECOVERY_METHOD_INDEX | DART_RECOVERY_IT);
|
||||
if (!model->strings || !model->classes) {
|
||||
flutter_model_fini (model);
|
||||
return false;
|
||||
@@ -873,6 +889,17 @@ static RVecFlutterEntry *flutter_collect_entries(RCore *core, const DartApp *app
|
||||
flutter_collect_entries_from_flags (seen, entries, core);
|
||||
flutter_collect_entries_from_app (seen, entries, app);
|
||||
flutter_collect_entries_from_model (seen, entries, model);
|
||||
// Entries before first_entry_with_code still contain executable Dart code;
|
||||
// only their Code objects were discarded by the precompiler.
|
||||
if (model->it_entries) {
|
||||
DartInstructionTableEntry *entry;
|
||||
R_VEC_FOREACH (model->it_entries, entry) {
|
||||
if (entry->address && !ht_up_find (seen, entry->address, NULL)) {
|
||||
RVecFlutterEntry_push_back (entries, &entry->address);
|
||||
ht_up_insert (seen, entry->address, entries);
|
||||
}
|
||||
}
|
||||
}
|
||||
ht_up_free (seen);
|
||||
return entries;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"expect": {
|
||||
"contains": [
|
||||
"class _Closure@0150898 (size=64)",
|
||||
"+0x428 dynamic _context@0150898",
|
||||
"+0x28 dynamic _context@0150898",
|
||||
"class _Uri@0150898 (size=96)",
|
||||
"+0x0 dynamic _portMap@1026248 static final"
|
||||
],
|
||||
|
||||
@@ -8,8 +8,8 @@ EOF
|
||||
EXPECT=<<EOF
|
||||
class Pointer (size=32)
|
||||
methods:
|
||||
0x00000000 get:hashCode (GetterFunction)
|
||||
0x00000000 == (RegularFunction)
|
||||
0x00115f2c get:hashCode (GetterFunction)
|
||||
0x001299fc == (RegularFunction)
|
||||
class NativeType (size=16)
|
||||
class NativeFunction (size=16)
|
||||
EOF
|
||||
@@ -27,8 +27,8 @@ EXPECT=<<EOF
|
||||
# class Pointer (size=32)
|
||||
# type_params: 1
|
||||
"td struct dart_Pointer { };"
|
||||
# method 0x00000000 get:hashCode (GetterFunction)
|
||||
# method 0x00000000 == (RegularFunction)
|
||||
# method 0x00115f2c get:hashCode (GetterFunction)
|
||||
# method 0x001299fc == (RegularFunction)
|
||||
# class NativeType (size=16)
|
||||
EOF
|
||||
RUN
|
||||
@@ -8,8 +8,8 @@ EOF
|
||||
EXPECT=<<EOF
|
||||
class Pointer (size=32)
|
||||
methods:
|
||||
0x00000000 get:hashCode (GetterFunction)
|
||||
0x00000000 == (RegularFunction)
|
||||
0x00c6ab64 get:hashCode (GetterFunction)
|
||||
0x00d8bde8 == (RegularFunction)
|
||||
class NativeType (size=16)
|
||||
class NativeFunction (size=16)
|
||||
EOF
|
||||
@@ -43,8 +43,8 @@ EXPECT=<<EOF
|
||||
# class Pointer (size=32)
|
||||
# type_params: 1
|
||||
"td struct dart_Pointer { };"
|
||||
# method 0x00000000 get:hashCode (GetterFunction)
|
||||
# method 0x00000000 == (RegularFunction)
|
||||
# method 0x00c6ab64 get:hashCode (GetterFunction)
|
||||
# method 0x00d8bde8 == (RegularFunction)
|
||||
# class NativeType (size=16)
|
||||
EOF
|
||||
RUN
|
||||
@@ -33,14 +33,14 @@ ic dart_Future
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
class dart_Future
|
||||
0x00000000 method dart_Future sC Future_error
|
||||
0x00000000 method dart_Future sC Future_
|
||||
0x00000000 method dart_Future s _anonymous_closure_
|
||||
0x00000000 method dart_Future sC Future_value
|
||||
0x00000000 method dart_Future s wait
|
||||
0x00000000 method dart_Future s handleError
|
||||
0x00000000 method dart_Future sC Future_delayed
|
||||
0x00000000 method dart_Future sC Future_microtask
|
||||
0x00000000 method dart_Future sC Future_sync
|
||||
0x005d4f54 method dart_Future sC Future_error
|
||||
0x005d70cc method dart_Future sC Future_
|
||||
0x005d71b8 method dart_Future s _anonymous_closure_
|
||||
0x005e4a98 method dart_Future sC Future_value
|
||||
0x0060d7d4 method dart_Future s wait
|
||||
0x0060dfac method dart_Future s handleError
|
||||
0x0062edcc method dart_Future sC Future_delayed
|
||||
0x006d5018 method dart_Future sC Future_microtask
|
||||
0x00943c08 method dart_Future sC Future_sync
|
||||
EOF
|
||||
RUN
|
||||
@@ -25,7 +25,7 @@ map
|
||||
true
|
||||
array
|
||||
48
|
||||
129
|
||||
1
|
||||
instance
|
||||
SemanticsAction
|
||||
1
|
||||
|
||||
@@ -10,8 +10,8 @@ EXPECT=<<EOF
|
||||
# class Pointer (size=32)
|
||||
# type_params: 1
|
||||
"td struct dart_Pointer { };"
|
||||
# method 0x00000000 get:hashCode (GetterFunction)
|
||||
# method 0x00000000 == (RegularFunction)
|
||||
# method 0x00115f2c get:hashCode (GetterFunction)
|
||||
# method 0x001299fc == (RegularFunction)
|
||||
# class NativeType (size=16)
|
||||
EOF
|
||||
RUN
|
||||
@@ -8,8 +8,8 @@ EOF
|
||||
EXPECT=<<EOF
|
||||
class Pointer (size=32)
|
||||
methods:
|
||||
0x00000000 get:hashCode (GetterFunction)
|
||||
0x00000000 == (RegularFunction)
|
||||
0x00c6ab64 get:hashCode (GetterFunction)
|
||||
0x00d8bde8 == (RegularFunction)
|
||||
class NativeType (size=16)
|
||||
class NativeFunction (size=16)
|
||||
EOF
|
||||
@@ -27,8 +27,8 @@ EXPECT=<<EOF
|
||||
# class Pointer (size=32)
|
||||
# type_params: 1
|
||||
"td struct dart_Pointer { };"
|
||||
# method 0x00000000 get:hashCode (GetterFunction)
|
||||
# method 0x00000000 == (RegularFunction)
|
||||
# method 0x00c6ab64 get:hashCode (GetterFunction)
|
||||
# method 0x00d8bde8 == (RegularFunction)
|
||||
# class NativeType (size=16)
|
||||
EOF
|
||||
RUN
|
||||
@@ -8,8 +8,8 @@ EOF
|
||||
EXPECT=<<EOF
|
||||
metadata class.name class Pointer [ref=36652] -> 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.owner method Pointer.get:hashCode [ref=31064] @ 0x115f2c -> class Pointer [ref=36652]
|
||||
metadata method.name method Pointer.get:hashCode [ref=31064] @ 0x115f2c -> string get:hashCode [ref=7217] @ 0x2b0230
|
||||
EOF
|
||||
RUN
|
||||
|
||||
@@ -21,7 +21,7 @@ L ../src/r2/core_flutter.so
|
||||
r2flutter -j -l 3 -x
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
[{"kind":"class.name","origin":"metadata","src":{"type":"class","name":"Pointer","ref":36652},"dst":{"type":"string","name":"Pointer","ref":151,"addr":1778896}},{"kind":"class.library","origin":"metadata","src":{"type":"class","name":"Pointer","ref":36652},"dst":{"type":"library","name":"library#41733","ref":41733}},{"kind":"method.owner","origin":"metadata","src":{"type":"method","name":"Pointer.get:hashCode","ref":31064},"dst":{"type":"class","name":"Pointer","ref":36652}}]
|
||||
[{"kind":"class.name","origin":"metadata","src":{"type":"class","name":"Pointer","ref":36652},"dst":{"type":"string","name":"Pointer","ref":151,"addr":1778896}},{"kind":"class.library","origin":"metadata","src":{"type":"class","name":"Pointer","ref":36652},"dst":{"type":"library","name":"library#41733","ref":41733}},{"kind":"method.owner","origin":"metadata","src":{"type":"method","name":"Pointer.get:hashCode","ref":31064,"addr":1138476},"dst":{"type":"class","name":"Pointer","ref":36652}}]
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
||||
Reference in new issue
Block a user