Skip to content

Commit d9a8fdc

Browse files
committed
feat: implemented rd_make_code
1 parent fd16f51 commit d9a8fdc

5 files changed

Lines changed: 75 additions & 58 deletions

File tree

include/redasm/context.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ RD_API const char* rd_to_dec(i64 v);
154154
RD_API const char* rd_to_hex(i64 v);
155155
RD_API const char* rd_to_hexaddr(const RDContext* self, usize v);
156156
RD_API const char* rd_render_text(RDContext* self, RDAddress address);
157+
RD_API bool rd_make_code(RDContext* self, RDAddress address);
157158
RD_API bool rd_auto_undefine(RDContext* self, RDAddress address);
158159
RD_API bool rd_library_undefine(RDContext* self, RDAddress address);
159160
RD_API bool rd_user_undefine(RDContext* self, RDAddress address);

src/core/context.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,33 @@ const char* rd_render_text(RDContext* self, RDAddress address) {
508508
return self->str_buf.data;
509509
}
510510

511+
bool rd_make_code(RDContext* self, RDAddress address) {
512+
const RDSegmentFull* seg = rd_i_db_find_segment(self, address);
513+
if(!seg) return false;
514+
515+
if(!(seg->base.perm & RD_SP_X)) {
516+
RD_LOG_FAIL("cannot make code @ %" PRIx64 ", non-executable segment",
517+
address);
518+
return false;
519+
}
520+
521+
usize idx = rd_i_address2index(seg, address);
522+
523+
// already code is not a no-op there: it re-derives xrefs and flow.
524+
// That's exactly RD_EI_DIRTY
525+
if(rd_flagsbuffer_has_code(seg->flags, idx)) {
526+
rd_i_engine_enqueue_dirty(self, address, 1);
527+
return true;
528+
}
529+
530+
// tails/data/unknown: retract the old interpretation first.
531+
// The gate refuses if something higher-confidence lives here.
532+
if(!rd_i_undefine_n(self, address, 1, RD_CONFIDENCE_USER)) return false;
533+
534+
rd_i_engine_enqueue_code(self, address, 1);
535+
return true;
536+
}
537+
511538
bool rd_auto_undefine(RDContext* self, RDAddress address) {
512539
return rd_i_undefine(self, address, RD_CONFIDENCE_AUTO);
513540
}
@@ -983,6 +1010,10 @@ RDAddressSlice rd_get_all_address_by_type(const RDContext* self,
9831010
(RDContext*)self, (RDAddressVect*)&self->addr_type_buf, filter));
9841011
}
9851012

1013+
RDAddressSlice rd_get_all_functions_address(const RDContext* self) {
1014+
return vect_to_slice(RDAddressSlice, &self->functions.addresses);
1015+
}
1016+
9861017
RDFunctionSlice rd_get_all_functions(const RDContext* self) {
9871018
return (RDFunctionSlice){
9881019
.data = (const RDFunction**)self->functions.data,

src/core/engine.c

Lines changed: 26 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,27 @@
88

99
#define RD_ENGINE_QUEUE_SIZE 8192
1010

11+
static inline bool _rd_engine_is_dirty_kind(RDEngineItemKind k) {
12+
return k == RD_EI_DIRTY || k == RD_EI_CODE;
13+
}
14+
15+
static inline void _rd_engine_enqueue_dirty(RDContext* ctx, RDAddress address,
16+
usize n, RDEngineItemKind kind) {
17+
const RDSegmentFull* seg = rd_i_db_find_segment(ctx, address);
18+
if(!seg) return;
19+
20+
RDEngineItem item = {
21+
.kind = kind,
22+
.address = address,
23+
.from = address,
24+
.n = n,
25+
};
26+
27+
rd_i_registermap_init(&item.registers);
28+
queue_push(&ctx->engine.qdirty, item);
29+
rd_i_engine_mark_dirty(ctx);
30+
}
31+
1132
static void _rd_engine_queue_drain(RDEngineQueue* q) {
1233
while(!queue_is_empty(q)) {
1334
RDEngineItem item;
@@ -223,19 +244,11 @@ bool rd_i_engine_enqueue_call(RDContext* ctx, RDAddress address,
223244
}
224245

225246
void rd_i_engine_enqueue_dirty(RDContext* ctx, RDAddress address, usize n) {
226-
const RDSegmentFull* seg = rd_i_db_find_segment(ctx, address);
227-
if(!seg) return;
228-
229-
RDEngineItem item = {
230-
.kind = RD_EI_DIRTY,
231-
.address = address,
232-
.from = address,
233-
.n = n,
234-
};
247+
_rd_engine_enqueue_dirty(ctx, address, n, RD_EI_DIRTY);
248+
}
235249

236-
rd_i_registermap_init(&item.registers);
237-
queue_push(&ctx->engine.qdirty, item);
238-
rd_i_engine_mark_dirty(ctx);
250+
void rd_i_engine_enqueue_code(RDContext* ctx, RDAddress address, usize n) {
251+
_rd_engine_enqueue_dirty(ctx, address, n, RD_EI_CODE);
239252
}
240253

241254
bool rd_i_engine_mark_dirty(RDContext* ctx) {
@@ -309,7 +322,7 @@ u16 rd_i_engine_tick(RDContext* ctx) {
309322

310323
// something already re-decoded this range (eg. flow from a neighbour,
311324
// or a duplicate mark) there is nothing left to do
312-
if(ctx->engine.current.kind == RD_EI_DIRTY &&
325+
if(_rd_engine_is_dirty_kind(ctx->engine.current.kind) &&
313326
!rd_flagsbuffer_has_unknown(ctx->engine.segment->flags, idx))
314327
return 0;
315328

@@ -402,38 +415,6 @@ u16 rd_i_engine_tick(RDContext* ctx) {
402415
return instr.length;
403416
}
404417

405-
void rd_i_engine_reconcile_tick(RDContext* ctx) {
406-
if(queue_is_empty(&ctx->engine.qdirty)) return;
407-
408-
// RDDirtyRange d;
409-
// queue_pop(&ctx->engine.qdirty, &d);
410-
//
411-
// const RDSegmentFull* seg = rd_i_db_find_segment(ctx, d.address);
412-
// if(!seg) return; // no segment: nothing to reconcile
413-
//
414-
// usize start_idx = rd_i_address2index(seg, d.address);
415-
// usize end_idx = start_idx + d.n;
416-
//
417-
// // clamp: ranges never cross segments
418-
// if(end_idx > rd_flagsbuffer_get_length(seg->flags))
419-
// end_idx = rd_flagsbuffer_get_length(seg->flags);
420-
//
421-
// // snap both ends outward to item boundaries
422-
// rd_i_flagsbuffer_expand_range(seg->flags, &start_idx, &end_idx);
423-
//
424-
// switch(_rd_engine_reconcile_kind(seg, start_idx, d.hint)) {
425-
// case RD_DIRTY_CODE:
426-
// _rd_engine_reconcile_code(ctx, seg, start_idx, end_idx);
427-
// break;
428-
//
429-
// case RD_DIRTY_DATA:
430-
// _rd_engine_reconcile_data(ctx, seg, start_idx, end_idx);
431-
// break;
432-
//
433-
// default: break;
434-
// }
435-
}
436-
437418
void rd_flow(RDContext* ctx, RDAddress address) {
438419
// unset and do checks
439420
optional_unset(&ctx->engine.flow);

src/core/engine.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ bool rd_i_engine_enqueue_jump(RDContext* ctx, RDAddress address);
4444
bool rd_i_engine_enqueue_call(RDContext* ctx, RDAddress address,
4545
const char* name, RDConfidence c);
4646
void rd_i_engine_enqueue_dirty(RDContext* ctx, RDAddress address, usize n);
47+
void rd_i_engine_enqueue_code(RDContext* ctx, RDAddress address, usize n);
4748
bool rd_i_engine_mark_dirty(RDContext* ctx);
4849
bool rd_i_engine_has_pending_code(const RDContext* ctx);
4950
bool rd_i_engine_decode(RDContext* ctx, RDAddress address,
5051
const RDSegmentFull* seg, usize index,
5152
RDInstruction* instr);
5253
u16 rd_i_engine_tick(RDContext* ctx);
53-
void rd_i_engine_reconcile_tick(RDContext* ctx);
5454
void rd_i_engine_init(RDContext* ctx);
5555
void rd_i_engine_destroy(RDContext* ctx);

src/core/worker.c

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -207,23 +207,27 @@ static void _rd_worker_step_reconcile(RDContext* ctx) {
207207
usize end_idx = start_idx + item->n;
208208
rd_i_expand_range(ctx, seg, &start_idx, &end_idx);
209209

210-
if(!rd_flagsbuffer_has_code(seg->flags, start_idx)) {
211-
// data: refresh what the old bytes derived.
212-
// unknown: nothing.
213-
// neither needs decoding, so the item is done
214-
if(rd_flagsbuffer_has_data(seg->flags, start_idx))
215-
_rd_worker_reconcile_data(ctx, seg, start_idx, end_idx);
216-
217-
item->kind = RD_EI_NONE;
218-
hmap_destroy(&item->registers);
219-
continue;
210+
if(item->kind == RD_EI_CODE) goto keep;
211+
212+
if(rd_flagsbuffer_has_code(seg->flags, start_idx)) {
213+
rd_i_clear_n(ctx, item->address, item->n);
214+
goto keep;
220215
}
221216

217+
if(rd_flagsbuffer_has_data(seg->flags, start_idx))
218+
_rd_worker_reconcile_data(ctx, seg, start_idx, end_idx);
219+
220+
// data or unknown: nothing left for EMULATE
221+
hmap_destroy(&item->registers);
222+
item->kind = RD_EI_NONE;
223+
continue;
224+
225+
keep:
226+
// decode from the ITEM HEAD
227+
// a mid-item patch must not decode from the patched byte
222228
item->address = seg->base.start_address + start_idx;
223229
item->from = item->address;
224230
item->n = end_idx - start_idx;
225-
226-
rd_i_clear_n(ctx, item->address, item->n);
227231
}
228232

229233
ctx->engine.step = RD_WS_EMULATE1;

0 commit comments

Comments
 (0)