[RzIL] Remove vector-oplists in favor of seq
The root type of a lifted op is now simply a single RzILOpEffect, which can be for example a chain of seq ops. This is in line with what BAP uses. For convenient creation of sequences, `rz_il_op_new_seqn(ut32 n, ...)` is a drop-in replacement for `rz_il_make_oplist(ut32 n, ...)`.
This commit is contained in:
parent
20ed5b924f
commit
6a09385746
14 changed files with 179 additions and 148 deletions
|
|
@ -54,8 +54,7 @@ RZ_API bool rz_analysis_op_fini(RzAnalysisOp *op) {
|
|||
op->switch_op = NULL;
|
||||
RZ_FREE(op->mnemonic);
|
||||
if (op->rzil_op) {
|
||||
// TODO free root_node once it is implemented
|
||||
rz_pvector_free(op->rzil_op->ops);
|
||||
rz_il_op_effect_free(op->rzil_op->op);
|
||||
RZ_FREE(op->rzil_op);
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -77,49 +77,45 @@ ut64 parse_label_id(char *lbl_name) {
|
|||
return addr;
|
||||
}
|
||||
|
||||
RzPVector *bf_right_arrow(RzILVM *vm, ut64 id) {
|
||||
RzILOpEffect *bf_right_arrow(RzILVM *vm, ut64 id) {
|
||||
// (set ptr (+ (val ptr) (int 1)))
|
||||
RzILOpBitVector *add = rz_il_op_new_add(bf_il_ptr(), bf_il_one(BF_ADDR_SIZE));
|
||||
return rz_il_make_oplist(1, bf_il_set_ptr(add));
|
||||
return bf_il_set_ptr(add);
|
||||
}
|
||||
|
||||
RzPVector *bf_left_arrow(RzILVM *vm, ut64 id) {
|
||||
RzILOpEffect *bf_left_arrow(RzILVM *vm, ut64 id) {
|
||||
// (set ptr (- (val ptr) (int 1)))
|
||||
RzILOpBitVector *sub = rz_il_op_new_sub(bf_il_ptr(), bf_il_one(BF_ADDR_SIZE));
|
||||
return rz_il_make_oplist(1, bf_il_set_ptr(sub));
|
||||
return bf_il_set_ptr(sub);
|
||||
}
|
||||
|
||||
RzPVector *bf_inc(RzILVM *vm, ut64 id) {
|
||||
RzILOpEffect *bf_inc(RzILVM *vm, ut64 id) {
|
||||
// (store mem (var ptr) (+ (load (var ptr)) (int 1)))
|
||||
// mem == 0 because is the only mem in bf
|
||||
RzILOpBitVector *load = rz_il_op_new_load(0, bf_il_ptr());
|
||||
RzILOpBitVector *add = rz_il_op_new_add(load, bf_il_one(BF_BYTE_SIZE));
|
||||
RzILOpEffect *store = rz_il_op_new_store(0, bf_il_ptr(), add);
|
||||
return rz_il_make_oplist(1, store);
|
||||
return rz_il_op_new_store(0, bf_il_ptr(), add);
|
||||
}
|
||||
|
||||
RzPVector *bf_dec(RzILVM *vm, ut64 id) {
|
||||
RzILOpEffect *bf_dec(RzILVM *vm, ut64 id) {
|
||||
// (store mem (var ptr) (- (load (var ptr)) (int 1)))
|
||||
// mem == 0 because is the only mem in bf
|
||||
RzILOpBitVector *load = rz_il_op_new_load(0, bf_il_ptr());
|
||||
RzILOpBitVector *sub = rz_il_op_new_sub(load, bf_il_one(BF_BYTE_SIZE));
|
||||
RzILOpEffect *store = rz_il_op_new_store(0, bf_il_ptr(), sub);
|
||||
return rz_il_make_oplist(1, store);
|
||||
return rz_il_op_new_store(0, bf_il_ptr(), sub);
|
||||
}
|
||||
|
||||
RzPVector *bf_out(RzILVM *vm, ut64 id) {
|
||||
RzILOpEffect *bf_out(RzILVM *vm, ut64 id) {
|
||||
// (goto write)
|
||||
RzILOpEffect *goto_ = rz_il_op_new_goto("write");
|
||||
return rz_il_make_oplist(1, goto_);
|
||||
return rz_il_op_new_goto("write");
|
||||
}
|
||||
|
||||
RzPVector *bf_in(RzILVM *vm, ut64 id) {
|
||||
RzILOpEffect *bf_in(RzILVM *vm, ut64 id) {
|
||||
// (goto hook_read)
|
||||
RzILOpEffect *goto_ = rz_il_op_new_goto("read");
|
||||
return rz_il_make_oplist(1, goto_);
|
||||
return rz_il_op_new_goto("read");
|
||||
}
|
||||
|
||||
RzPVector *bf_llimit(RzILVM *vm, BfContext *ctx, ut64 id, ut64 addr) {
|
||||
RzILOpEffect *bf_llimit(RzILVM *vm, BfContext *ctx, ut64 id, ut64 addr) {
|
||||
// (perform (branch (load mem (var ptr))
|
||||
// (do nothing)
|
||||
// (goto ]))
|
||||
|
|
@ -159,13 +155,10 @@ RzPVector *bf_llimit(RzILVM *vm, BfContext *ctx, ut64 id, ut64 addr) {
|
|||
RzILOpEffect *goto_ = rz_il_op_new_goto(dst_label->label_id);
|
||||
|
||||
// branch if (load mem (var ptr)) is false then goto ]
|
||||
RzILOpEffect *branch = rz_il_op_new_branch(cond, NULL, goto_);
|
||||
|
||||
// perform
|
||||
return rz_il_make_oplist(1, branch);
|
||||
return rz_il_op_new_branch(cond, NULL, goto_);
|
||||
}
|
||||
|
||||
RzPVector *bf_rlimit(RzILVM *vm, BfContext *ctx, ut64 id, ut64 addr) {
|
||||
RzILOpEffect *bf_rlimit(RzILVM *vm, BfContext *ctx, ut64 id, ut64 addr) {
|
||||
// (perform (branch (load mem (var ptr))
|
||||
// (goto [)
|
||||
// (do nothing))
|
||||
|
|
@ -202,7 +195,7 @@ RzPVector *bf_rlimit(RzILVM *vm, BfContext *ctx, ut64 id, ut64 addr) {
|
|||
RzILOpEffect *branch = rz_il_op_new_branch(cond, goto_, NULL);
|
||||
|
||||
free(to_free);
|
||||
return rz_il_make_oplist(1, branch);
|
||||
return branch;
|
||||
}
|
||||
|
||||
static bool bf_specific_init(RzAnalysisRzil *rzil) {
|
||||
|
|
@ -320,7 +313,7 @@ static int bf_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *b
|
|||
|
||||
BfContext *ctx = analysis->rzil->user;
|
||||
RzILVM *vm = analysis->rzil->vm;
|
||||
RzPVector *oplist = NULL;
|
||||
RzILOpEffect *ilop = NULL;
|
||||
op->rzil_op = RZ_NEW0(RzAnalysisRzilOp);
|
||||
if (!op->rzil_op) {
|
||||
RZ_LOG_ERROR("Fail to init rzil op\n");
|
||||
|
|
@ -330,7 +323,7 @@ static int bf_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *b
|
|||
|
||||
switch (buf[0]) {
|
||||
case '[':
|
||||
oplist = bf_llimit(vm, ctx, op->id, addr);
|
||||
ilop = bf_llimit(vm, ctx, op->id, addr);
|
||||
op->type = RZ_ANALYSIS_OP_TYPE_CJMP;
|
||||
op->fail = addr + 1;
|
||||
buf = rz_mem_dup((void *)buf, len);
|
||||
|
|
@ -377,31 +370,31 @@ static int bf_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *b
|
|||
free((ut8 *)buf);
|
||||
break;
|
||||
case ']':
|
||||
oplist = bf_rlimit(vm, ctx, op->id, addr);
|
||||
ilop = bf_rlimit(vm, ctx, op->id, addr);
|
||||
op->type = RZ_ANALYSIS_OP_TYPE_UJMP;
|
||||
break;
|
||||
case '>':
|
||||
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
||||
oplist = bf_right_arrow(vm, op->id);
|
||||
ilop = bf_right_arrow(vm, op->id);
|
||||
break;
|
||||
case '<':
|
||||
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
||||
oplist = bf_left_arrow(vm, op->id);
|
||||
ilop = bf_left_arrow(vm, op->id);
|
||||
break;
|
||||
case '+':
|
||||
op->type = RZ_ANALYSIS_OP_TYPE_ADD;
|
||||
oplist = bf_inc(vm, op->id);
|
||||
ilop = bf_inc(vm, op->id);
|
||||
break;
|
||||
case '-':
|
||||
op->type = RZ_ANALYSIS_OP_TYPE_SUB;
|
||||
oplist = bf_dec(vm, op->id);
|
||||
ilop = bf_dec(vm, op->id);
|
||||
break;
|
||||
case '.':
|
||||
oplist = bf_out(vm, op->id);
|
||||
ilop = bf_out(vm, op->id);
|
||||
op->type = RZ_ANALYSIS_OP_TYPE_STORE;
|
||||
break;
|
||||
case ',':
|
||||
oplist = bf_in(vm, op->id);
|
||||
ilop = bf_in(vm, op->id);
|
||||
op->type = RZ_ANALYSIS_OP_TYPE_LOAD;
|
||||
break;
|
||||
case 0x00:
|
||||
|
|
@ -410,10 +403,11 @@ static int bf_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *b
|
|||
break;
|
||||
default:
|
||||
op->type = RZ_ANALYSIS_OP_TYPE_NOP;
|
||||
ilop = rz_il_op_new_nop();
|
||||
break;
|
||||
}
|
||||
if (oplist) {
|
||||
op->rzil_op->ops = oplist;
|
||||
if (ilop) {
|
||||
op->rzil_op->op = ilop;
|
||||
}
|
||||
ctx->op_count++;
|
||||
return op->size;
|
||||
|
|
|
|||
|
|
@ -636,8 +636,6 @@ RZ_IPI void rz_core_analysis_rzil_vm_status(RzCore *core, const char *var_name,
|
|||
|
||||
// step a list of ct_opcode at a given address
|
||||
RZ_IPI void rz_core_rzil_step(RzCore *core) {
|
||||
RzPVector *oplist;
|
||||
|
||||
if (!core->analysis || !core->analysis->rzil) {
|
||||
RZ_LOG_ERROR("RzIL: Run 'aezi' first to initialize the VM\n");
|
||||
return;
|
||||
|
|
@ -662,10 +660,10 @@ RZ_IPI void rz_core_rzil_step(RzCore *core) {
|
|||
// analysis current data to trigger rzil_set_op_code
|
||||
(void)rz_io_read_at_mapped(core->io, addr, code, sizeof(code));
|
||||
int size = rz_analysis_op(analysis, &op, addr, code, sizeof(code), RZ_ANALYSIS_OP_MASK_ESIL | RZ_ANALYSIS_OP_MASK_HINT);
|
||||
oplist = op.rzil_op ? op.rzil_op->ops : NULL;
|
||||
RzILOpEffect *ilop = op.rzil_op ? op.rzil_op->op : NULL;
|
||||
|
||||
if (oplist) {
|
||||
rz_il_vm_list_step(vm, oplist, size > 0 ? size : 1);
|
||||
if (ilop) {
|
||||
rz_il_vm_list_step(vm, ilop, size > 0 ? size : 1);
|
||||
} else {
|
||||
RZ_LOG_ERROR("RzIL: invalid instruction detected or reach the end of code at address 0x%08" PFMT64x "\n", addr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1052,9 +1052,9 @@ static void core_analysis_bytes(RzCore *core, const ut8 *buf, int len, int nops,
|
|||
pj_ks(pj, "esil", jesil);
|
||||
}
|
||||
if (op.rzil_op) {
|
||||
if (op.rzil_op->ops) {
|
||||
if (op.rzil_op->op) {
|
||||
pj_k(pj, "rzil");
|
||||
rz_il_oplist_json(op.rzil_op->ops, pj);
|
||||
rz_il_op_effect_json(op.rzil_op->op, pj);
|
||||
} else {
|
||||
pj_knull(pj, "rzil");
|
||||
}
|
||||
|
|
@ -1235,15 +1235,11 @@ static void core_analysis_bytes(RzCore *core, const ut8 *buf, int len, int nops,
|
|||
} else if (RZ_STR_ISNOTEMPTY(esilstr)) {
|
||||
printline("esil", "%s\n", esilstr);
|
||||
}
|
||||
if (op.rzil_op) {
|
||||
if (op.rzil_op->ops) {
|
||||
RzStrBuf *sbil = rz_strbuf_new("");
|
||||
rz_il_oplist_stringify(op.rzil_op->ops, sbil);
|
||||
printline("rzil", "%s\n", rz_strbuf_get(sbil));
|
||||
rz_strbuf_free(sbil);
|
||||
} else {
|
||||
printline_noarg("rzil", "[]");
|
||||
}
|
||||
if (op.rzil_op && op.rzil_op->op) {
|
||||
RzStrBuf *sbil = rz_strbuf_new("");
|
||||
rz_il_op_effect_stringify(op.rzil_op->op, sbil);
|
||||
printline("rzil", "%s\n", rz_strbuf_get(sbil));
|
||||
rz_strbuf_free(sbil);
|
||||
}
|
||||
if (hint && hint->jump != UT64_MAX) {
|
||||
op.jump = hint->jump;
|
||||
|
|
|
|||
|
|
@ -665,45 +665,6 @@ RZ_API void rz_il_op_effect_json(RZ_NONNULL RzILOpEffect *op, RZ_NONNULL PJ *pj)
|
|||
il_op_effect_resolve(op, NULL, pj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the string representation of the IL statements
|
||||
* \param op_list RzPVector*, array of IL statements
|
||||
* \param sb RzStrBuf*, a pointer to the string buffer
|
||||
*/
|
||||
RZ_API void rz_il_oplist_stringify(RZ_NONNULL RzPVector *op_list, RZ_NONNULL RzStrBuf *sb) {
|
||||
rz_return_if_fail(op_list && sb);
|
||||
|
||||
ut32 i = 0;
|
||||
void **iter;
|
||||
rz_strbuf_append(sb, "[");
|
||||
rz_pvector_foreach (op_list, iter) {
|
||||
RzILOpEffect *ilop = *iter;
|
||||
if (i > 0) {
|
||||
rz_strbuf_append(sb, ", ");
|
||||
}
|
||||
rz_il_op_effect_stringify(ilop, sb);
|
||||
i++;
|
||||
}
|
||||
rz_strbuf_append(sb, "]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the JSON representation of the IL statements
|
||||
* \param code RzPVector*, array of IL statements
|
||||
* \param pj PJ*, a pointer to the JSON buffer
|
||||
*/
|
||||
RZ_API void rz_il_oplist_json(RZ_NONNULL RzPVector *op_list, RZ_NONNULL PJ *pj) {
|
||||
rz_return_if_fail(op_list && pj);
|
||||
|
||||
pj_a(pj);
|
||||
void **iter;
|
||||
rz_pvector_foreach (op_list, iter) {
|
||||
RzILOpEffect *ilop = *iter;
|
||||
rz_il_op_effect_json(ilop, pj);
|
||||
}
|
||||
pj_end(pj);
|
||||
}
|
||||
|
||||
RZ_API void rz_il_event_stringify(RZ_NONNULL RzILEvent *evt, RZ_NONNULL RzStrBuf *sb) {
|
||||
rz_return_if_fail(evt && sb);
|
||||
char *tmp0 = NULL, *tmp1 = NULL, *tmp2 = NULL;
|
||||
|
|
|
|||
|
|
@ -560,6 +560,64 @@ RZ_API RZ_OWN RzILOpEffect *rz_il_op_new_seq(RZ_NONNULL RzILOpEffect *x, RZ_NONN
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chain \p n opcodes given as varargs in sequence using seq if necessary
|
||||
*
|
||||
* It works exactly like this seq helper from BAP:
|
||||
* let rec seq = function
|
||||
* | [] -> CT.perform Theory.Effect.Sort.bot
|
||||
* | [x] -> x
|
||||
* | x :: xs -> CT.seq x @@ seq xs
|
||||
*
|
||||
* \param n number of total opcodes given
|
||||
* \param ... \p num RzILOpEffect * ops to be executed in sequence
|
||||
*/
|
||||
RZ_API RZ_OWN RzILOpEffect *rz_il_op_new_seqn(ut32 n, ...) {
|
||||
if (!n) {
|
||||
return rz_il_op_new_nop();
|
||||
}
|
||||
RzILOpEffect *root = NULL;
|
||||
RzILOpEffect *prev_seq = NULL;
|
||||
va_list args;
|
||||
va_start(args, n);
|
||||
for (ut32 i = 0; i < n; ++i) {
|
||||
RzILOpEffect *cur_op = va_arg(args, RzILOpEffect *);
|
||||
if (i == n - 1) {
|
||||
// last one
|
||||
if (prev_seq) {
|
||||
prev_seq->op.seq->y = cur_op;
|
||||
} else {
|
||||
// n == 1, no need for seq at all
|
||||
root = cur_op;
|
||||
}
|
||||
break;
|
||||
}
|
||||
RzILOpEffect *seq = RZ_NEW0(RzILOpEffect);
|
||||
if (!seq) {
|
||||
break;
|
||||
}
|
||||
seq->op.seq = RZ_NEW0(RzILOpArgsSeq);
|
||||
if (!seq->op.seq) {
|
||||
free(seq);
|
||||
break;
|
||||
}
|
||||
seq->code = RZIL_OP_SEQ;
|
||||
seq->op.seq->x = cur_op;
|
||||
if (prev_seq) {
|
||||
// not the first one
|
||||
// We let the seq recurse in the second op because that
|
||||
// can enable tail call elimination in the evaluation.
|
||||
prev_seq->op.seq->y = seq;
|
||||
} else {
|
||||
// first one
|
||||
root = seq;
|
||||
}
|
||||
prev_seq = seq;
|
||||
}
|
||||
va_end(args);
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief op structure for `blk` (label -> data eff -> ctrl eff -> unit eff)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -386,27 +386,6 @@ RZ_API RZ_BORROW RzILEffectLabel *rz_il_vm_update_label(RZ_NONNULL RzILVM *vm, R
|
|||
return lbl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a core theory opcode vector
|
||||
* \param num int, number of total opcodes
|
||||
* \param ... op RzILOp, op will be pushed to vector one by one
|
||||
* \return oplist RzPVector*, pointer to the opcode
|
||||
*/
|
||||
RZ_API RZ_OWN RzPVector *rz_il_make_oplist(ut32 num, ...) {
|
||||
va_list args;
|
||||
RzILOpEffect *cur_op;
|
||||
RzPVector *oplist = rz_pvector_new((RzPVectorFree)rz_il_op_effect_free);
|
||||
|
||||
va_start(args, num);
|
||||
for (ut32 i = 0; i < num; ++i) {
|
||||
cur_op = va_arg(args, RzILOpEffect *);
|
||||
rz_pvector_push(oplist, cur_op);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
return oplist;
|
||||
}
|
||||
|
||||
static void *eval_pure(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILOpPure *op, RZ_NONNULL RzILPureType *type) {
|
||||
rz_return_val_if_fail(vm && op && type, NULL);
|
||||
RzILOpPureHandler handler = vm->op_handler_pure_table[op->code];
|
||||
|
|
|
|||
|
|
@ -400,20 +400,12 @@ RZ_API void rz_il_vm_event_add(RzILVM *vm, RzILEvent *evt) {
|
|||
* \param op_list, a list of op roots.
|
||||
* \param op_size, how much the pc value has to increate of.
|
||||
*/
|
||||
RZ_API bool rz_il_vm_list_step(RzILVM *vm, RzPVector *op_list, ut32 op_size) {
|
||||
rz_return_val_if_fail(vm && op_list, false);
|
||||
RZ_API bool rz_il_vm_list_step(RzILVM *vm, RzILOpEffect *op, ut32 op_size) {
|
||||
rz_return_val_if_fail(vm && op, false);
|
||||
|
||||
rz_list_purge(vm->events);
|
||||
|
||||
bool succ = true;
|
||||
void **iter;
|
||||
rz_pvector_foreach (op_list, iter) {
|
||||
RzILOpEffect *root = *iter;
|
||||
if (!rz_il_evaluate_effect(vm, root)) {
|
||||
succ = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bool succ = rz_il_evaluate_effect(vm, op);
|
||||
|
||||
RzBitVector *step = rz_bv_new_from_ut64(vm->pc->len, op_size);
|
||||
RzBitVector *next_pc = rz_bv_add(vm->pc, step, NULL);
|
||||
|
|
|
|||
|
|
@ -807,9 +807,8 @@ typedef enum rz_analysis_data_type_t {
|
|||
RZ_ANALYSIS_DATATYPE_FLOAT,
|
||||
} RzAnalysisDataType;
|
||||
|
||||
// For switchting to AST-like approach in the future
|
||||
typedef struct rz_analysis_rzil_op_t {
|
||||
RzPVector *ops;
|
||||
RzILOpEffect *op;
|
||||
} RzAnalysisRzilOp;
|
||||
|
||||
typedef struct rz_analysis_op_t {
|
||||
|
|
|
|||
|
|
@ -524,6 +524,7 @@ RZ_API RZ_OWN RzILOpEffect *rz_il_op_new_let(RZ_NONNULL const char *var, RZ_NONN
|
|||
RZ_API RZ_OWN RzILOpEffect *rz_il_op_new_jmp(RZ_NONNULL RzILOpBitVector *dst);
|
||||
RZ_API RZ_OWN RzILOpEffect *rz_il_op_new_goto(RZ_NONNULL const char *label);
|
||||
RZ_API RZ_OWN RzILOpEffect *rz_il_op_new_seq(RZ_NONNULL RzILOpEffect *x, RZ_NONNULL RzILOpEffect *y);
|
||||
RZ_API RZ_OWN RzILOpEffect *rz_il_op_new_seqn(ut32 n, ...);
|
||||
RZ_API RZ_OWN RzILOpEffect *rz_il_op_new_blk(RZ_NONNULL RzILOpEffect *data_effect, RZ_NONNULL RzILOpEffect *ctrl_effect);
|
||||
RZ_API RZ_OWN RzILOpEffect *rz_il_op_new_repeat(RZ_NONNULL RzILOpBool *condition, RZ_NONNULL RzILOpEffect *data_effect);
|
||||
RZ_API RZ_OWN RzILOpEffect *rz_il_op_new_branch(RZ_NONNULL RzILOpBool *condition, RZ_NULLABLE RzILOpEffect *true_effect, RZ_NULLABLE RzILOpEffect *false_effect);
|
||||
|
|
|
|||
|
|
@ -94,17 +94,11 @@ RZ_API RZ_BORROW RzILVal *rz_il_vm_fortify_bool(RZ_NONNULL RzILVM *vm, bool val)
|
|||
RZ_API void rz_il_vm_add_reg(RZ_NONNULL RzILVM *vm, RZ_NONNULL const char *name, ut32 length);
|
||||
RZ_API void rz_il_vm_add_bit_reg(RZ_NONNULL RzILVM *vm, RZ_NONNULL const char *name, bool value);
|
||||
|
||||
// VM store and load core theory opcodes
|
||||
RZ_API RZ_OWN RzPVector *rz_il_make_oplist(ut32 num, ...);
|
||||
#define rz_il_make_nop_list() rz_il_make_oplist(0, NULL)
|
||||
|
||||
RZ_API void rz_il_op_pure_stringify(RZ_NONNULL RzILOpPure *op, RZ_NONNULL RzStrBuf *sb);
|
||||
RZ_API void rz_il_op_effect_stringify(RZ_NONNULL RzILOpEffect *op, RZ_NONNULL RzStrBuf *sb);
|
||||
RZ_API void rz_il_oplist_stringify(RZ_NONNULL RzPVector *oplist, RZ_NONNULL RzStrBuf *sb);
|
||||
|
||||
RZ_API void rz_il_op_pure_json(RZ_NONNULL RzILOpPure *op, RZ_NONNULL PJ *pj);
|
||||
RZ_API void rz_il_op_effect_json(RZ_NONNULL RzILOpEffect *op, RZ_NONNULL PJ *pj);
|
||||
RZ_API void rz_il_oplist_json(RZ_NONNULL RzPVector *oplist, RZ_NONNULL PJ *pj);
|
||||
|
||||
RZ_API void rz_il_event_stringify(RZ_NONNULL RzILEvent *evt, RZ_NONNULL RzStrBuf *sb);
|
||||
RZ_API void rz_il_event_json(RZ_NONNULL RzILEvent *evt, RZ_NONNULL PJ *pj);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ RZ_API bool rz_il_vm_init(RzILVM *vm, ut64 start_addr, ut32 addr_size, bool big_
|
|||
RZ_API void rz_il_vm_fini(RzILVM *vm);
|
||||
RZ_API void rz_il_vm_add_mem(RzILVM *vm, RzILMemIndex index, RZ_OWN RzILMem *mem);
|
||||
RZ_API RzILMem *rz_il_vm_get_mem(RzILVM *vm, RzILMemIndex index);
|
||||
RZ_API bool rz_il_vm_list_step(RzILVM *vm, RzPVector *op_list, ut32 op_size);
|
||||
RZ_API bool rz_il_vm_list_step(RzILVM *vm, RzILOpEffect *op, ut32 op_size);
|
||||
|
||||
// VM Event operations
|
||||
RZ_API void rz_il_vm_event_add(RzILVM *vm, RzILEvent *evt);
|
||||
|
|
|
|||
|
|
@ -78,29 +78,29 @@ aoj @ 0x6a ~{.rzil}
|
|||
EOF
|
||||
EXPECT=<<EOF
|
||||
opcode: inc [ptr]
|
||||
rzil: [store(mem:0, key:var(v:ptr), value:add(x:load(mem:0, key:var(v:ptr)), y:bitv(bits:0x01, len:8)))]
|
||||
[{"opcode":"store","mem":0,"key":{"opcode":"var","value":"ptr"},"value":{"opcode":"add","x":{"opcode":"load","mem":0,"key":{"opcode":"var","value":"ptr"}},"y":{"opcode":"bitv","bits":"0x01","len":8}}}]
|
||||
rzil: store(mem:0, key:var(v:ptr), value:add(x:load(mem:0, key:var(v:ptr)), y:bitv(bits:0x01, len:8)))
|
||||
{"opcode":"store","mem":0,"key":{"opcode":"var","value":"ptr"},"value":{"opcode":"add","x":{"opcode":"load","mem":0,"key":{"opcode":"var","value":"ptr"}},"y":{"opcode":"bitv","bits":"0x01","len":8}}}
|
||||
opcode: while [ptr]
|
||||
rzil: [branch(condition:inv(x:is_zero(bv:load(mem:0, key:var(v:ptr)))), true_eff:nop(), false_eff:goto(lbl:]8))]
|
||||
[{"opcode":"branch","condition":{"opcode":"inv","x":{"opcode":"is_zero","bv":{"opcode":"load","mem":0,"key":{"opcode":"var","value":"ptr"}}}},"true_eff":{"opcode":"nop"},"false_eff":{"opcode":"goto","label":"]8"}}]
|
||||
rzil: branch(condition:inv(x:is_zero(bv:load(mem:0, key:var(v:ptr)))), true_eff:nop(), false_eff:goto(lbl:]8))
|
||||
{"opcode":"branch","condition":{"opcode":"inv","x":{"opcode":"is_zero","bv":{"opcode":"load","mem":0,"key":{"opcode":"var","value":"ptr"}}}},"true_eff":{"opcode":"nop"},"false_eff":{"opcode":"goto","label":"]8"}}
|
||||
opcode: inc ptr
|
||||
rzil: [set(v:ptr, x:add(x:var(v:ptr), y:bitv(bits:0x0000000000000001, len:64)))]
|
||||
[{"opcode":"set","dst":"ptr","src":{"opcode":"add","x":{"opcode":"var","value":"ptr"},"y":{"opcode":"bitv","bits":"0x0000000000000001","len":64}}}]
|
||||
rzil: set(v:ptr, x:add(x:var(v:ptr), y:bitv(bits:0x0000000000000001, len:64)))
|
||||
{"opcode":"set","dst":"ptr","src":{"opcode":"add","x":{"opcode":"var","value":"ptr"},"y":{"opcode":"bitv","bits":"0x0000000000000001","len":64}}}
|
||||
opcode: dec ptr
|
||||
rzil: [set(v:ptr, x:sub(x:var(v:ptr), y:bitv(bits:0x0000000000000001, len:64)))]
|
||||
[{"opcode":"set","dst":"ptr","src":{"opcode":"sub","x":{"opcode":"var","value":"ptr"},"y":{"opcode":"bitv","bits":"0x0000000000000001","len":64}}}]
|
||||
rzil: set(v:ptr, x:sub(x:var(v:ptr), y:bitv(bits:0x0000000000000001, len:64)))
|
||||
{"opcode":"set","dst":"ptr","src":{"opcode":"sub","x":{"opcode":"var","value":"ptr"},"y":{"opcode":"bitv","bits":"0x0000000000000001","len":64}}}
|
||||
opcode: dec [ptr]
|
||||
rzil: [store(mem:0, key:var(v:ptr), value:sub(x:load(mem:0, key:var(v:ptr)), y:bitv(bits:0x01, len:8)))]
|
||||
[{"opcode":"store","mem":0,"key":{"opcode":"var","value":"ptr"},"value":{"opcode":"sub","x":{"opcode":"load","mem":0,"key":{"opcode":"var","value":"ptr"}},"y":{"opcode":"bitv","bits":"0x01","len":8}}}]
|
||||
rzil: store(mem:0, key:var(v:ptr), value:sub(x:load(mem:0, key:var(v:ptr)), y:bitv(bits:0x01, len:8)))
|
||||
{"opcode":"store","mem":0,"key":{"opcode":"var","value":"ptr"},"value":{"opcode":"sub","x":{"opcode":"load","mem":0,"key":{"opcode":"var","value":"ptr"}},"y":{"opcode":"bitv","bits":"0x01","len":8}}}
|
||||
opcode: loop
|
||||
rzil: [branch(condition:inv(x:is_zero(bv:load(mem:0, key:var(v:ptr)))), true_eff:goto(lbl:[14), false_eff:nop())]
|
||||
[{"opcode":"branch","condition":{"opcode":"inv","x":{"opcode":"is_zero","bv":{"opcode":"load","mem":0,"key":{"opcode":"var","value":"ptr"}}}},"true_eff":{"opcode":"goto","label":"[14"},"false_eff":{"opcode":"nop"}}]
|
||||
rzil: branch(condition:inv(x:is_zero(bv:load(mem:0, key:var(v:ptr)))), true_eff:goto(lbl:[14), false_eff:nop())
|
||||
{"opcode":"branch","condition":{"opcode":"inv","x":{"opcode":"is_zero","bv":{"opcode":"load","mem":0,"key":{"opcode":"var","value":"ptr"}}}},"true_eff":{"opcode":"goto","label":"[14"},"false_eff":{"opcode":"nop"}}
|
||||
opcode: out [ptr]
|
||||
rzil: [goto(lbl:write)]
|
||||
[{"opcode":"goto","label":"write"}]
|
||||
rzil: goto(lbl:write)
|
||||
{"opcode":"goto","label":"write"}
|
||||
opcode: nop
|
||||
rzil: []
|
||||
null
|
||||
rzil: nop()
|
||||
{"opcode":"nop"}
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
|
|
|||
|
|
@ -234,6 +234,65 @@ static bool test_rzil_mem_storew() {
|
|||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_rzil_seqn() {
|
||||
// n = 0 ==> just a nop
|
||||
RzILOpEffect *s = rz_il_op_new_seqn(0);
|
||||
mu_assert_notnull(s, "seqn 0");
|
||||
mu_assert_eq(s->code, RZIL_OP_NOP, "seqn 0 nop");
|
||||
rz_il_op_effect_free(s);
|
||||
|
||||
// n = 1 ==> just the op
|
||||
RzILOpEffect *e0 = rz_il_op_new_goto("beach");
|
||||
s = rz_il_op_new_seqn(1, e0);
|
||||
mu_assert_notnull(s, "seqn 1");
|
||||
mu_assert_ptreq(s, e0, "seqn 1 op");
|
||||
rz_il_op_effect_free(s);
|
||||
|
||||
// n = 2 ==> single seq
|
||||
// (seq e0 e1)
|
||||
e0 = rz_il_op_new_goto("beach");
|
||||
RzILOpEffect *e1 = rz_il_op_new_goto("beach2");
|
||||
s = rz_il_op_new_seqn(2, e0, e1);
|
||||
mu_assert_notnull(s, "seqn 2");
|
||||
mu_assert_eq(s->code, RZIL_OP_SEQ, "seqn 2 seq");
|
||||
mu_assert_ptreq(s->op.seq->x, e0, "seqn 2 first");
|
||||
mu_assert_ptreq(s->op.seq->y, e1, "seqn 2 second");
|
||||
rz_il_op_effect_free(s);
|
||||
|
||||
// n = 3 ==> nested seq with recursion in the second op:
|
||||
// (seq e0 (seq e1 e2))
|
||||
e0 = rz_il_op_new_goto("beach");
|
||||
e1 = rz_il_op_new_goto("beach2");
|
||||
RzILOpEffect *e2 = rz_il_op_new_goto("beach3");
|
||||
s = rz_il_op_new_seqn(3, e0, e1, e2);
|
||||
mu_assert_notnull(s, "seqn 3");
|
||||
mu_assert_eq(s->code, RZIL_OP_SEQ, "seqn 3 seq");
|
||||
mu_assert_ptreq(s->op.seq->x, e0, "seqn 3 first");
|
||||
mu_assert_eq(s->op.seq->y->code, RZIL_OP_SEQ, "seqn 3 second seq");
|
||||
mu_assert_ptreq(s->op.seq->y->op.seq->x, e1, "seqn 3 second");
|
||||
mu_assert_ptreq(s->op.seq->y->op.seq->y, e2, "seqn 3 third");
|
||||
rz_il_op_effect_free(s);
|
||||
|
||||
// n = 4 ==> nested seq with recursion in the second op and no confusion:
|
||||
// (seq e0 (seq e1 (seq e2 e3)))
|
||||
e0 = rz_il_op_new_goto("beach");
|
||||
e1 = rz_il_op_new_goto("beach2");
|
||||
e2 = rz_il_op_new_goto("beach3");
|
||||
RzILOpEffect *e3 = rz_il_op_new_goto("beach3");
|
||||
s = rz_il_op_new_seqn(4, e0, e1, e2, e3);
|
||||
mu_assert_notnull(s, "seqn 4");
|
||||
mu_assert_eq(s->code, RZIL_OP_SEQ, "seqn 4 seq");
|
||||
mu_assert_ptreq(s->op.seq->x, e0, "seqn 4 first");
|
||||
mu_assert_eq(s->op.seq->y->code, RZIL_OP_SEQ, "seqn 4 second seq");
|
||||
mu_assert_ptreq(s->op.seq->y->op.seq->x, e1, "seqn 4 second");
|
||||
mu_assert_eq(s->op.seq->y->op.seq->y->code, RZIL_OP_SEQ, "seqn 4 third seq");
|
||||
mu_assert_ptreq(s->op.seq->y->op.seq->y->op.seq->x, e2, "seqn 4 third");
|
||||
mu_assert_ptreq(s->op.seq->y->op.seq->y->op.seq->y, e3, "seqn 4 fourth");
|
||||
rz_il_op_effect_free(s);
|
||||
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool all_tests() {
|
||||
mu_run_test(test_rzil_bool_init);
|
||||
mu_run_test(test_rzil_bool_logic);
|
||||
|
|
@ -241,6 +300,7 @@ bool all_tests() {
|
|||
mu_run_test(test_rzil_mem_store);
|
||||
mu_run_test(test_rzil_mem_loadw);
|
||||
mu_run_test(test_rzil_mem_storew);
|
||||
mu_run_test(test_rzil_seqn);
|
||||
return tests_passed != tests_run;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue