Skip to content

Commit be75d60

Browse files
committed
feat!: improved NORET detection in type system
1 parent b643bdd commit be75d60

10 files changed

Lines changed: 138 additions & 130 deletions

File tree

‎include/redasm/context.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ RD_API bool rd_expect_be16(const RDContext* self, RDAddress address, u16 v);
209209
RD_API bool rd_expect_be32(const RDContext* self, RDAddress address, u32 v);
210210
RD_API bool rd_expect_be64(const RDContext* self, RDAddress address, u64 v);
211211
RD_API bool rd_read_ptr(const RDContext* ctx, RDAddress address, RDAddress* v);
212+
RD_API bool rd_read_code_ptr(const RDContext* ctx, RDAddress address, RDAddress* v);
212213
RD_API bool rd_follow_ptr(RDContext* ctx, RDAddress address, RDAddress* v);
213214
RD_API bool rd_write_byte(RDContext* self, RDAddress address, u8 v);
214215
RD_API bool rd_write_le16(RDContext* self, RDAddress address, u16 v);

‎src/core/context.c‎

Lines changed: 52 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,54 @@ static void _rd_teardown_range(RDContext* self, const RDSegmentFull* seg,
4545
}
4646
}
4747

48+
static bool _rd_read_ptr(const RDContext* ctx, unsigned int ptr_size,
49+
RDAddress address, RDAddress* v) {
50+
bool is_be = ctx->processorplugin->flags & RD_PF_BE;
51+
52+
switch(ptr_size) {
53+
case sizeof(u8): {
54+
u8 ptr_v;
55+
if(!rd_read_byte(ctx, address, &ptr_v)) return false;
56+
*v = (RDAddress)ptr_v;
57+
return true;
58+
}
59+
60+
case sizeof(u16): {
61+
u16 ptr_v;
62+
if(is_be ? !rd_read_be16(ctx, address, &ptr_v)
63+
: !rd_read_le16(ctx, address, &ptr_v))
64+
return false;
65+
66+
*v = (RDAddress)ptr_v;
67+
return true;
68+
}
69+
70+
case sizeof(u32): {
71+
u32 ptr_v;
72+
if(is_be ? !rd_read_be32(ctx, address, &ptr_v)
73+
: !rd_read_le32(ctx, address, &ptr_v))
74+
return false;
75+
76+
*v = (RDAddress)ptr_v;
77+
return true;
78+
}
79+
80+
case sizeof(u64): {
81+
u64 ptr_v;
82+
if(is_be ? !rd_read_be64(ctx, address, &ptr_v)
83+
: !rd_read_le64(ctx, address, &ptr_v))
84+
return false;
85+
86+
*v = (RDAddress)ptr_v;
87+
return true;
88+
}
89+
90+
default: break;
91+
}
92+
93+
return false;
94+
}
95+
4896
void rd_i_expand_range(RDContext* self, const RDSegmentFull* seg, usize* start,
4997
usize* end) {
5098
assert(start && end);
@@ -724,50 +772,11 @@ bool rd_read_be64(const RDContext* self, RDAddress address, u64* v) {
724772
}
725773

726774
bool rd_read_ptr(const RDContext* ctx, RDAddress address, RDAddress* v) {
727-
bool is_be = ctx->processorplugin->flags & RD_PF_BE;
728-
729-
switch(ctx->processorplugin->ptr_size) {
730-
case sizeof(u8): {
731-
u8 ptr_v;
732-
if(!rd_read_byte(ctx, address, &ptr_v)) return false;
733-
*v = (RDAddress)ptr_v;
734-
return true;
735-
}
736-
737-
case sizeof(u16): {
738-
u16 ptr_v;
739-
if(is_be ? !rd_read_be16(ctx, address, &ptr_v)
740-
: !rd_read_le16(ctx, address, &ptr_v))
741-
return false;
742-
743-
*v = (RDAddress)ptr_v;
744-
return true;
745-
}
746-
747-
case sizeof(u32): {
748-
u32 ptr_v;
749-
if(is_be ? !rd_read_be32(ctx, address, &ptr_v)
750-
: !rd_read_le32(ctx, address, &ptr_v))
751-
return false;
752-
753-
*v = (RDAddress)ptr_v;
754-
return true;
755-
}
756-
757-
case sizeof(u64): {
758-
u64 ptr_v;
759-
if(is_be ? !rd_read_be64(ctx, address, &ptr_v)
760-
: !rd_read_le64(ctx, address, &ptr_v))
761-
return false;
762-
763-
*v = (RDAddress)ptr_v;
764-
return true;
765-
}
766-
767-
default: break;
768-
}
775+
return _rd_read_ptr(ctx, rd_get_ptr_size(ctx), address, v);
776+
}
769777

770-
return false;
778+
bool rd_read_code_ptr(const RDContext* ctx, RDAddress address, RDAddress* v) {
779+
return _rd_read_ptr(ctx, rd_get_code_ptr_size(ctx), address, v);
771780
}
772781

773782
bool rd_follow_ptr(RDContext* ctx, RDAddress address, RDAddress* v) {

‎src/core/function.c‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ const char* rd_i_function_to_str(const RDFunction* self, RDContext* ctx) {
241241
str_push(&ctx->tdef_buf, ' ');
242242
}
243243

244+
if(rd_function_is_noret(self)) str_append(&ctx->tdef_buf, "noreturn ");
245+
244246
RDName n; // try to get the name
245247
if(rd_i_get_name(ctx, self->address, false, &n))
246248
str_append(&ctx->tdef_buf, n.value);
@@ -264,8 +266,6 @@ const char* rd_i_function_to_str(const RDFunction* self, RDContext* ctx) {
264266
str_push(&ctx->tdef_buf, ')');
265267
}
266268

267-
if(rd_function_is_noret(self)) str_append(&ctx->tdef_buf, " noreturn");
268-
269269
assert(!vect_is_empty(&ctx->tdef_buf));
270270
return ctx->tdef_buf.data;
271271
}

‎src/core/worker.c‎

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,36 @@ static void _rd_worker_apply_function_types(RDContext* ctx) {
7777
RDTypeDef** it;
7878
vect_each(it, &ctx->typedefs) {
7979
const RDTypeDef* tdef = *it;
80-
if(tdef->kind != RD_TKIND_FUNC) continue;
80+
81+
if(tdef->kind != RD_TKIND_FUNC || tdef->flags & RD_TFLAG_BUILTIN)
82+
continue;
8183

8284
RDAddress address;
8385
if(!rd_get_address(ctx, tdef->name, &address)) continue;
8486

85-
RDFunction* f = rd_i_find_function(ctx, address);
86-
if(f) rd_i_function_set_type_def(f, tdef);
87+
const RDSegmentFull* seg = rd_i_db_find_segment(ctx, address);
88+
if(!seg) continue;
89+
90+
usize idx = rd_i_address2index(seg, address);
91+
92+
if(rd_flagsbuffer_has_func(seg->flags, idx)) {
93+
RDFunction* f = rd_i_find_function(ctx, address);
94+
if(!f || f->type_def == tdef) continue;
95+
96+
if(f->type_def && !(f->type_def->flags & RD_TFLAG_BUILTIN))
97+
continue;
98+
99+
rd_i_function_set_type_def(f, tdef);
100+
}
101+
else if(rd_flagsbuffer_has_type(seg->flags, idx)) {
102+
RDTypeFull t;
103+
if(!rd_i_get_type(ctx, address, &t) || t.base.def == tdef) continue;
104+
if(t.base.count > 0 || t.base.def->kind != RD_TKIND_FUNC) continue;
105+
if(!(t.base.def->flags & RD_TFLAG_BUILTIN)) continue;
106+
107+
rd_i_set_type(ctx, address, tdef->name, 0, t.base.mod,
108+
RD_CONFIDENCE_LIBRARY);
109+
}
87110
}
88111
}
89112

‎src/db/db.c‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,12 +132,7 @@ void rd_i_db_load(RDContext* ctx) {
132132

133133
// restore NORET status in KB
134134
RDTypeDef** it;
135-
vect_each(it, &ctx->typedefs) {
136-
rd_i_typedef_measure(ctx, *it);
137-
138-
if((*it)->kind == RD_TKIND_FUNC && (*it)->func_.is_noret)
139-
rd_i_kb_add_noret(ctx, (*it)->name);
140-
}
135+
vect_each(it, &ctx->typedefs) { rd_i_typedef_measure(ctx, *it); }
141136

142137
_rd_i_db_query_get_all_functions(ctx, &ctx->functions);
143138
_rd_i_db_query_get_all_sregval(ctx, &ctx->db->segment_regs,

‎src/io/flags.c‎

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
/*
55
* RDFlags: 32 bits per address.
66
*
7-
* 31 27 26 22 21 20 19 17 16 9 8 7 0
7+
* 31 27 26 21 20 19 18 16 15 9 8 7 0
88
* ┌────────┬──────────────┬─────┬────────┬────────────┬─┬──────────┐
99
* │ free │ structure │class│arrival │ preserve │V│ value │
1010
* └────────┴──────────────┴─────┴────────┴────────────┴─┴──────────┘
11-
* └───── cleared by clear ─────┘ └────── survives clear ─────────┘
12-
* └────── cleared by undefine ──────────┘ └─ survives undefine ──┘
11+
* └─ cleared by clear ─┘└──────── survives clear ────────┘
12+
* └──── cleared by undefine ────┘└─ survives undefine ───┘
1313
*
1414
* Ordering is forced by the masks: a flag survives an operation if it sits
1515
* BELOW that operation's cut. Both masks cut below the class bits, so both
@@ -18,15 +18,16 @@
1818
*
1919
* The three tiers, by who owns the truth:
2020
* preserve knowledge: users, loaders, DB rows. Class-agnostic and
21-
* head-only: FL_NORET marks an instruction, a function EP or an
22-
* IAT slot alike, exactly like FL_IMPORTED. Never retracted
23-
* implicitly.
21+
* head-only. Never retracted implicitly.
2422
* arrival how control REACHES here (call/jump/fall-through). Owned by the
2523
* referrer, not by this cell's decode: a byte change here does not
2624
* invalidate them, so they survive clear + re-decode. Dropped by
2725
* undefine ("means nothing") or by becoming a TAIL ("cannot live
2826
* mid-item").
2927
* structure what these bytes DECODE TO. Re-derived on every decode.
28+
* FL_NORET lives here: it means "this instruction terminates
29+
* flow", derived from the callee's type (RDFunctionType.is_noret),
30+
* NOT "the symbol here never returns" - that lives in the type.
3031
*
3132
* FL_FLOW and FL_FUNC are mutually exclusive, enforced symmetrically by both
3233
* setters so the outcome does not depend on discovery order.
@@ -35,7 +36,7 @@
3536
*
3637
* FL_FLOW: set on the DESTINATION instruction:
3738
* - means "reached by fall-through from the previous instruction".
38-
* - never set on function entries (FL_FUNC) or noreturn functions (FL_NORET)
39+
* - never set on function entries (FL_FUNC)
3940
* - both clear FL_FLOW automatically in their set functions.
4041
*/
4142

@@ -51,23 +52,22 @@ static const RDFlags FL_XREFOUT = 1U << 12;
5152
static const RDFlags FL_XREFIN = 1U << 13;
5253
static const RDFlags FL_EXPORTED = 1U << 14;
5354
static const RDFlags FL_IMPORTED = 1U << 15;
54-
static const RDFlags FL_NORET = 1U << 16;
5555

5656
// covers bits 0-15 (NOTE: always add the last flag above)
57-
#define FL_UNDEFINE_MASK ((RDFlags)((FL_NORET << 1) - 1))
57+
#define FL_UNDEFINE_MASK ((RDFlags)((FL_IMPORTED << 1) - 1))
5858
#define FL_HAS_INFO \
5959
((RDFlags)(FL_UNDEFINE_MASK & ~(FL_VALUE | FL_PATCH | 0xFF)))
6060

6161
// [ARRIVAL]
62-
static const RDFlags FL_FLOW = 1U << 17;
63-
static const RDFlags FL_JMPDST = 1U << 18;
64-
static const RDFlags FL_FUNC = 1U << 19;
62+
static const RDFlags FL_FLOW = 1U << 16;
63+
static const RDFlags FL_JMPDST = 1U << 17;
64+
static const RDFlags FL_FUNC = 1U << 18;
6565

66-
// covers bits 0-17 (NOTE: always add the last flag above)
66+
// covers bits 0-18 (NOTE: always add the last flag above)
6767
#define FL_CLEAR_MASK ((RDFlags)((FL_FUNC << 1) - 1))
6868

69-
// [CLASS]: 2-bit field, bits 20-21
70-
#define FL_CLASS_SHIFT 20
69+
// [CLASS]: 2-bit field, bits 19-20
70+
#define FL_CLASS_SHIFT 19
7171
#define FL_CLASS_MASK ((RDFlags)(3U << FL_CLASS_SHIFT))
7272

7373
typedef enum {
@@ -78,9 +78,9 @@ typedef enum {
7878
} RDFlagsClass;
7979

8080
// [STRUCTURE] CODE
81-
// kind: 2-bit field, bits 22-23.
81+
// kind: 2-bit field, bits 21-22.
8282
// JUMP/CALL are mutually exclusive.
83-
#define FL_KIND_SHIFT 22
83+
#define FL_KIND_SHIFT 21
8484
#define FL_KIND_MASK ((RDFlags)(3U << FL_KIND_SHIFT))
8585

8686
typedef enum {
@@ -89,14 +89,15 @@ typedef enum {
8989
FL_KI_CALL,
9090
} RDFlagsKind;
9191

92+
static const RDFlags FL_NORET = 1U << 23;
9293
static const RDFlags FL_COND = 1U << 24;
9394
static const RDFlags FL_DSLOT = 1U << 25;
9495
static const RDFlags FL_OPOVER = 1U << 26;
9596

9697
// [STRUCTURE] DATA
97-
static const RDFlags FL_TYPE = 1U << 22;
98-
static const RDFlags FL_FIELD = 1U << 23;
99-
static const RDFlags FL_ITEM = 1U << 24;
98+
static const RDFlags FL_TYPE = 1U << 23;
99+
static const RDFlags FL_FIELD = 1U << 24;
100+
static const RDFlags FL_ITEM = 1U << 25;
100101

101102
static RDFlagsClass _rd_flags_class(RDFlags self) {
102103
return (RDFlagsClass)((self & FL_CLASS_MASK) >> FL_CLASS_SHIFT);
@@ -145,7 +146,9 @@ bool rd_i_flags_has_call(RDFlags self) {
145146
return _rd_flags_kind(self) == FL_KI_CALL;
146147
}
147148

148-
bool rd_i_flags_has_noret(RDFlags self) { return self & FL_NORET; }
149+
bool rd_i_flags_has_noret(RDFlags self) {
150+
return rd_i_flags_has_code(self) && (self & FL_NORET);
151+
}
149152

150153
bool rd_i_flags_has_cond(RDFlags self) {
151154
return rd_i_flags_has_code(self) && (self & FL_COND);
@@ -238,7 +241,10 @@ void rd_i_flags_set_func(RDFlags* self) {
238241
*self &= ~FL_FLOW; // function entries break flow
239242
}
240243

241-
void rd_i_flags_set_noret(RDFlags* self) { *self |= FL_NORET; }
244+
void rd_i_flags_set_noret(RDFlags* self) {
245+
assert(rd_i_flags_has_code(*self));
246+
*self |= FL_NORET;
247+
}
242248

243249
void rd_i_flags_set_cond(RDFlags* self) {
244250
assert(rd_i_flags_has_jump(*self) || rd_i_flags_has_call(*self));

‎src/kb/kb.c‎

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -168,15 +168,6 @@ static const char* _rd_kb_get_param(const RDKBObject* obj, RDType* t,
168168
return rd_kbobject_get_str(obj, "name");
169169
}
170170

171-
static void _rd_kb_apply_noret(RDContext* ctx) {
172-
const char** it;
173-
vect_each(it, &ctx->kb->noret_names) {
174-
RDAddress address;
175-
if(!rd_get_address(ctx, *it, &address)) continue;
176-
rd_i_set_noret(ctx, address);
177-
}
178-
}
179-
180171
static void _rd_kb_load_dependencies(const RDKBObject* root, RDContext* ctx) {
181172
const RDKBObject* manifest = rd_kbobject_get_table(root, "manifest");
182173
if(!manifest) return;
@@ -313,7 +304,6 @@ static bool _rd_kb_load_functions(const RDKBObject* root, RDContext* ctx) {
313304
rd_typedef_register(tdef, ctx);
314305
}
315306

316-
_rd_kb_apply_noret(ctx);
317307
return true;
318308
}
319309

@@ -399,30 +389,10 @@ void rd_i_kb_destroy(RDKB* self) {
399389
}
400390

401391
vect_destroy(&self->ordinal_modules);
402-
vect_destroy(&self->noret_names);
403392
vect_destroy(&self->files);
404393
rd_free(self);
405394
}
406395

407-
void rd_i_kb_add_noret(RDContext* ctx, const char* name) {
408-
assert(name);
409-
410-
usize idx =
411-
vect_lower_bound(&ctx->kb->noret_names, name, rd_i_strcmp_key_pred);
412-
413-
if(idx == vect_length(&ctx->kb->noret_names) ||
414-
name != *vect_at(&ctx->kb->noret_names, idx)) {
415-
vect_ins(&ctx->kb->noret_names, idx, name);
416-
}
417-
}
418-
419-
bool rd_i_kb_is_noret(const RDContext* ctx, const char* name) {
420-
assert(name);
421-
422-
usize idx = vect_bsearch(&ctx->kb->noret_names, name, rd_i_strcmp_key_pred);
423-
return idx < vect_length(&ctx->kb->noret_names);
424-
}
425-
426396
const char* rd_i_kb_find_ordinal_name(RDContext* ctx, const char* module,
427397
u32 ordinal) {
428398
const RDKBOrdinalModule* mod =

‎src/kb/kb.h‎

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,12 @@ typedef struct RDKB {
3939
usize length;
4040
usize capacity;
4141
} ordinal_modules;
42-
43-
struct {
44-
const char** data;
45-
usize length;
46-
usize capacity;
47-
} noret_names;
4842
} RDKB;
4943

5044
void rd_i_kb_paths_init(const char** kb_paths);
5145
void rd_i_kb_paths_deinit(RDPathVect* self);
5246

5347
RDKB* rd_i_kb_create(void);
5448
void rd_i_kb_destroy(RDKB* self);
55-
void rd_i_kb_add_noret(RDContext* ctx, const char* name);
56-
bool rd_i_kb_is_noret(const RDContext* ctx, const char* name);
5749
const char* rd_i_kb_find_ordinal_name(RDContext* ctx, const char* module,
5850
u32 ordinal);

0 commit comments

Comments
 (0)