mirror of
https://github.com/radareorg/r2flutter.git
synced 2026-11-07 06:26:00 -10:00
Decode Record fields in snapshot value graphs
This commit is contained in:
1 parent
3bfdd5601a
commit
25a5b3f026
6 files changed
+173
-2
No files matched your search
@@ -2001,3 +2001,29 @@ On iOS AuthPass, `PP+0x68` holds ref 168520 in the Code cluster starting at
|
||||
regression checks index zero, a discarded record, the following main record,
|
||||
and an unresolved deferred record. These targets use the existing table
|
||||
payload-address convention described above.
|
||||
|
||||
## Record inspection decodes the shape and field references
|
||||
|
||||
Record fills contain `ReadUnsigned (shape)` followed by one reference per
|
||||
field. `RecordShape::NumFieldsBitField` in the VM is the low 16 bits; the upper
|
||||
bits identify the registered array of named field names. Allocation records
|
||||
separately store each Record's field count. Retain those counts and check each
|
||||
fill against its own allocation instead of accepting only matching cluster
|
||||
minimum, maximum, and total counts.
|
||||
|
||||
The value graph now decodes Record fields into the same bounded edges used by
|
||||
other objects. JSON includes `shape`, `field_names_index`, `length`, and
|
||||
`fields`; text output prints the shape, length, and child values. Labels remain
|
||||
ordinal (`field_0`, etc.); the shape's named-field table index is preserved
|
||||
rather than treated as a reference or used to invent names. Empty Records
|
||||
report length zero. Cycles, depth limits, and the 128-child display limit use
|
||||
the existing graph handling. An unreadable or inconsistent Record fill stays
|
||||
`complete: false`.
|
||||
|
||||
In `t/libapp_1.so`, ref 146422 has shape 2 and fields referring to base object
|
||||
996 and instance 164557; that instance exposes the string `DOUBLE_QUOTE`.
|
||||
The public Android mafia fixture has the equivalent Record at ref 158051,
|
||||
whose second field is an `XmlAttributeType` instance. Synthetic compressed and
|
||||
uncompressed snapshots cover nested Records, named shapes, empty Records,
|
||||
cycles, truncation, and a malformed field count. Existing iOS graph tests
|
||||
continue to cover arrays, maps, and sets; those fixtures have no Record cluster.
|
||||
@@ -760,7 +760,7 @@ static bool modern_skip_alloc(ClusterStream *s, const ModernCidCache *cids, int
|
||||
return false;
|
||||
}
|
||||
meta->count = count;
|
||||
if (kind == MODERN_ALLOC_VARIABLE && count) {
|
||||
if ((kind == MODERN_ALLOC_VARIABLE || kind == MODERN_ALLOC_RECORD) && count) {
|
||||
meta->alloc_items = (ut64 *)calloc ((size_t)count, sizeof (ut64));
|
||||
if (!meta->alloc_items) {
|
||||
return false;
|
||||
@@ -1303,6 +1303,9 @@ static bool modern_skip_fill_record(ClusterStream *s, const ModernClusterMeta *m
|
||||
return false;
|
||||
}
|
||||
ut64 fields = shape & 0xffffULL;
|
||||
if (meta->alloc_items && fields != meta->alloc_items[i]) {
|
||||
return false;
|
||||
}
|
||||
if (meta->alloc_items_count == meta->count && fields > meta->alloc_items_max) {
|
||||
return false;
|
||||
}
|
||||
@@ -2982,10 +2985,12 @@ typedef struct {
|
||||
bool edges_truncated;
|
||||
bool has_type_arguments;
|
||||
bool has_scalar;
|
||||
bool has_shape;
|
||||
ut64 ref;
|
||||
ut64 count;
|
||||
ut64 type_arguments_ref;
|
||||
ut64 scalar;
|
||||
ut64 shape;
|
||||
int cid;
|
||||
const char *kind;
|
||||
char *name;
|
||||
@@ -3092,6 +3097,46 @@ static bool modern_value_read_array(ModernValueGraph *graph, ModernValueNode *no
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool modern_value_read_record(ModernValueGraph *graph, ModernValueNode *node, const ModernClusterMeta *meta) {
|
||||
ClusterStream s = {
|
||||
.ctx = graph->ctx,
|
||||
.cursor = meta->fill_offset,
|
||||
.end = meta->fill_end,
|
||||
};
|
||||
const ut64 target = node->ref - meta->start_ref;
|
||||
for (ut64 i = 0; i < meta->count; i++) {
|
||||
ut64 shape = 0;
|
||||
if (!cs_read_unsigned (&s, &shape)) {
|
||||
return false;
|
||||
}
|
||||
const ut64 fields = shape & 0xffffULL;
|
||||
if (!meta->alloc_items || fields != meta->alloc_items[i]) {
|
||||
return false;
|
||||
}
|
||||
if (i == target) {
|
||||
node->has_shape = true;
|
||||
node->shape = shape;
|
||||
if (!modern_value_edges_alloc (node, fields)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (ut64 j = 0; j < fields; j++) {
|
||||
ut64 ref = 0;
|
||||
if (!cs_read_ref_id (&s, &ref)) {
|
||||
return false;
|
||||
}
|
||||
if (i == target && j < node->edge_count) {
|
||||
node->edges[j].index = j;
|
||||
node->edges[j].ref = ref;
|
||||
}
|
||||
}
|
||||
if (i == target) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool modern_value_read_refs(ModernValueGraph *graph, ModernValueNode *node, const ModernClusterMeta *meta) {
|
||||
const ModernFillSpec spec = modern_get_fill_spec (&graph->cids, meta->cid);
|
||||
ClusterStream s = {
|
||||
@@ -3255,6 +3300,8 @@ static ModernValueNode *modern_value_graph_node(ModernValueGraph *graph, ut64 re
|
||||
}
|
||||
if (!strcmp (node->kind, "array")) {
|
||||
node->complete = modern_value_read_array (graph, node, meta);
|
||||
} else if (meta->fill_kind == MODERN_FILL_RECORD) {
|
||||
node->complete = modern_value_read_record (graph, node, meta);
|
||||
} else if (meta->fill_kind == MODERN_FILL_REFS) {
|
||||
node->complete = modern_value_read_refs (graph, node, meta);
|
||||
} else if (!strcmp (node->kind, "instance")) {
|
||||
@@ -3358,7 +3405,11 @@ static void modern_value_json_node(PJ *pj, ModernValueGraph *graph, ut64 ref, in
|
||||
if (node->has_type_arguments) {
|
||||
pj_kn (pj, "type_arguments_ref", node->type_arguments_ref);
|
||||
}
|
||||
if (node->count || node->edges) {
|
||||
if (node->has_shape) {
|
||||
pj_kn (pj, "shape", node->shape);
|
||||
pj_kn (pj, "field_names_index", node->shape >> 16);
|
||||
}
|
||||
if (node->count || node->edges || node->has_shape) {
|
||||
pj_kn (pj, "length", node->count);
|
||||
pj_kb (pj, "values_truncated", node->edges_truncated);
|
||||
}
|
||||
@@ -3425,6 +3476,9 @@ static void modern_value_text_node(RStrBuf *sb, ModernValueGraph *graph, ut64 re
|
||||
if (node->has_scalar) {
|
||||
r_strbuf_appendf (sb, " value=%" PFMT64d, (st64)node->scalar);
|
||||
}
|
||||
if (node->has_shape) {
|
||||
r_strbuf_appendf (sb, " shape=%" PRIu64 " length=%" PRIu64, (uint64_t)node->shape, (uint64_t)node->count);
|
||||
}
|
||||
r_strbuf_appendf (sb, " complete=%s\n", r_str_bool (node->complete));
|
||||
if (modern_value_path_contains (path, path_count, ref) || depth >= MODERN_VALUE_MAX_DEPTH) {
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
NAME=record-values-android
|
||||
FILE=bins/android/mafia/libapp.so
|
||||
CMDS=<<EOF
|
||||
L ../src/r2/core_flutter.so
|
||||
L ../src/r2/core_flutter.dylib
|
||||
r2flutter -q -j -O ref:158051~{snapshot.kind}
|
||||
r2flutter -q -j -O ref:158051~{snapshot.complete}
|
||||
r2flutter -q -j -O ref:158051~{snapshot.shape}
|
||||
r2flutter -q -j -O ref:158051~{snapshot.length}
|
||||
r2flutter -q -j -O ref:158051~{snapshot.fields[0].ref}
|
||||
r2flutter -q -j -O ref:158051~{snapshot.fields[1].value.name}
|
||||
r2flutter -q -j -O ref:158051~{snapshot.fields[1].value.fields[2].value.value}
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
record
|
||||
true
|
||||
2
|
||||
2
|
||||
1001
|
||||
XmlAttributeType
|
||||
DOUBLE_QUOTE
|
||||
EOF
|
||||
RUN
|
||||
@@ -0,0 +1,14 @@
|
||||
NAME=record-values-malformed
|
||||
FILE=malloc://0xfd
|
||||
CMDS=<<EOF
|
||||
L ../src/r2/core_flutter.so
|
||||
L ../src/r2/core_flutter.dylib
|
||||
wx 50414421f5f5dcdcf5000000000000000200000000000000333063303531636239313932663664363831326265336630623837613633353670726f647563742061726d363420636f6d707265737365642d706f696e746572730082898280800020cf82c1be0060d08580828281018180818384020084868381880181838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383
|
||||
r2flutter -q -j -O ref:6~{snapshot.kind}
|
||||
r2flutter -q -j -O ref:6~{snapshot.complete}
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
record
|
||||
false
|
||||
EOF
|
||||
RUN
|
||||
@@ -0,0 +1,34 @@
|
||||
NAME=record-values-synthetic
|
||||
FILE=malloc://0xfd
|
||||
CMDS=<<EOF
|
||||
L ../src/r2/core_flutter.so
|
||||
L ../src/r2/core_flutter.dylib
|
||||
wx 50414421f5f5dcdcf5000000000000000200000000000000333063303531636239313932663664363831326265336630623837613633353670726f647563742061726d363420636f6d707265737365642d706f696e746572730082898280800020cf82c1be0060d08580828281018180828384020084868381880181838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383
|
||||
r2flutter -q -j -O ref:5~{snapshot.complete}
|
||||
r2flutter -q -j -O ref:5~{snapshot.length}
|
||||
r2flutter -q -j -O ref:6~{snapshot.fields[0].value.value}
|
||||
r2flutter -q -j -O ref:6~{snapshot.fields[1].value.value}
|
||||
r2flutter -q -j -O ref:7~{snapshot.shape}
|
||||
r2flutter -q -j -O ref:7~{snapshot.field_names_index}
|
||||
r2flutter -q -j -O ref:7~{snapshot.fields[0].value.fields[1].value.value}
|
||||
r2flutter -q -j -O ref:8~{snapshot.fields[0].value.cycle}
|
||||
r2flutter -q -j -O ref:9~{snapshot.length}
|
||||
r2flutter -q -j -O ref:9~{snapshot.values_truncated}
|
||||
r2flutter -q -j -O ref:9~{snapshot.fields[127].value.value}
|
||||
r2flutter -q -j -O ref:9~{=}~name = ~?
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
true
|
||||
0
|
||||
1
|
||||
-2
|
||||
65538
|
||||
1
|
||||
-2
|
||||
true
|
||||
129
|
||||
true
|
||||
1
|
||||
128
|
||||
EOF
|
||||
RUN
|
||||
@@ -0,0 +1,20 @@
|
||||
NAME=record-values-uncompressed
|
||||
FILE=malloc://0x100
|
||||
CMDS=<<EOF
|
||||
L ../src/r2/core_flutter.so
|
||||
L ../src/r2/core_flutter.dylib
|
||||
wx 50414421f5f5dcdcf8000000000000000200000000000000333063303531636239313932663664363831326265336630623837613633353670726f647563742061726d3634206e6f2d636f6d707265737365642d706f696e746572730082898280800020cf82c1be0060d08580828281018180828384020084868381880181838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383838383
|
||||
r2flutter -q -j -O ref:6~{snapshot.kind}
|
||||
r2flutter -q -j -O ref:6~{snapshot.complete}
|
||||
r2flutter -q -j -O ref:6~{snapshot.length}
|
||||
r2flutter -q -j -O ref:6~{snapshot.fields[1].value.value}
|
||||
r2flutter -O ref:6~kind=record
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
record
|
||||
true
|
||||
2
|
||||
-2
|
||||
ref=6 kind=record cid=67 shape=2 length=2 complete=true
|
||||
EOF
|
||||
RUN
|
||||
Reference in new issue
Block a user