464 lines
19 KiB
C
464 lines
19 KiB
C
// SPDX-FileCopyrightText: 2021 heersin <teablearcher@gmail.com>
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
/**
|
|
* \file
|
|
* RzIL Virtual Machine Evaluation (Emulation)
|
|
*/
|
|
|
|
#include <rz_il/rz_il_vm.h>
|
|
|
|
// Handler for core theory opcodes
|
|
void *rz_il_handler_ite(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_var(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_let(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
|
|
void *rz_il_handler_bitv(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_msb(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_lsb(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_is_zero(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_eq(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_ule(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_sle(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_neg(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_logical_not(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_add(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_sub(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_mul(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_div(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_sdiv(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_mod(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_smod(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_shiftl(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_shiftr(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_logical_and(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_logical_or(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_logical_xor(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
|
|
void *rz_il_handler_bool_false(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_bool_true(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_bool_and(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_bool_or(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_bool_xor(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_bool_inv(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
|
|
void *rz_il_handler_cast(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_append(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
|
|
bool rz_il_handler_empty(RzILVM *vm, RzILOpEffect *op);
|
|
bool rz_il_handler_nop(RzILVM *vm, RzILOpEffect *op);
|
|
bool rz_il_handler_set(RzILVM *vm, RzILOpEffect *op);
|
|
bool rz_il_handler_jmp(RzILVM *vm, RzILOpEffect *op);
|
|
bool rz_il_handler_goto(RzILVM *vm, RzILOpEffect *op);
|
|
bool rz_il_handler_seq(RzILVM *vm, RzILOpEffect *op);
|
|
bool rz_il_handler_blk(RzILVM *vm, RzILOpEffect *op);
|
|
bool rz_il_handler_repeat(RzILVM *vm, RzILOpEffect *op);
|
|
bool rz_il_handler_branch(RzILVM *vm, RzILOpEffect *op);
|
|
|
|
void *rz_il_handler_load(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
bool rz_il_handler_store(RzILVM *vm, RzILOpEffect *op);
|
|
void *rz_il_handler_loadw(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
bool rz_il_handler_storew(RzILVM *vm, RzILOpEffect *op);
|
|
|
|
void *rz_il_handler_float(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fbits(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_is_finite(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_is_nan(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_is_inf(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_is_fzero(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_is_fneg(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_is_fpos(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fneg(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fabs(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fcast_int(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fcast_sint(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fcast_float(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fcast_sfloat(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fconvert(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_frequal(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fsucc(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fpred(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_forder(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fround(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fsqrt(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_frsqrt(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fexcept(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fadd(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fsub(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fdiv(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fmul(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fmod(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fhypot(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fpow(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fmad(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_frootn(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fpown(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
void *rz_il_handler_fcompound(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
|
|
// TODO: remove me when all the handlers are implemented
|
|
void *rz_il_handler_pure_unimplemented(RzILVM *vm, RzILOpPure *op, RzILTypePure *type);
|
|
bool rz_il_handler_effect_unimplemented(RzILVM *vm, RzILOpEffect *op);
|
|
|
|
RZ_IPI RzILOpPureHandler rz_il_op_handler_pure_table_default[RZ_IL_OP_PURE_MAX] = {
|
|
[RZ_IL_OP_VAR] = rz_il_handler_var,
|
|
[RZ_IL_OP_ITE] = rz_il_handler_ite,
|
|
[RZ_IL_OP_LET] = rz_il_handler_let,
|
|
[RZ_IL_OP_B0] = rz_il_handler_bool_false,
|
|
[RZ_IL_OP_B1] = rz_il_handler_bool_true,
|
|
[RZ_IL_OP_INV] = rz_il_handler_bool_inv,
|
|
[RZ_IL_OP_AND] = rz_il_handler_bool_and,
|
|
[RZ_IL_OP_OR] = rz_il_handler_bool_or,
|
|
[RZ_IL_OP_XOR] = rz_il_handler_bool_xor,
|
|
[RZ_IL_OP_BITV] = rz_il_handler_bitv,
|
|
[RZ_IL_OP_MSB] = rz_il_handler_msb,
|
|
[RZ_IL_OP_LSB] = rz_il_handler_lsb,
|
|
[RZ_IL_OP_IS_ZERO] = rz_il_handler_is_zero,
|
|
[RZ_IL_OP_NEG] = rz_il_handler_neg,
|
|
[RZ_IL_OP_LOGNOT] = rz_il_handler_logical_not,
|
|
[RZ_IL_OP_ADD] = rz_il_handler_add,
|
|
[RZ_IL_OP_SUB] = rz_il_handler_sub,
|
|
[RZ_IL_OP_MUL] = rz_il_handler_mul,
|
|
[RZ_IL_OP_DIV] = rz_il_handler_div,
|
|
[RZ_IL_OP_MOD] = rz_il_handler_mod,
|
|
[RZ_IL_OP_SDIV] = rz_il_handler_sdiv,
|
|
[RZ_IL_OP_SMOD] = rz_il_handler_smod,
|
|
[RZ_IL_OP_LOGAND] = rz_il_handler_logical_and,
|
|
[RZ_IL_OP_LOGOR] = rz_il_handler_logical_or,
|
|
[RZ_IL_OP_LOGXOR] = rz_il_handler_logical_xor,
|
|
[RZ_IL_OP_SHIFTR] = rz_il_handler_shiftr,
|
|
[RZ_IL_OP_SHIFTL] = rz_il_handler_shiftl,
|
|
[RZ_IL_OP_EQ] = rz_il_handler_eq,
|
|
[RZ_IL_OP_SLE] = rz_il_handler_sle,
|
|
[RZ_IL_OP_ULE] = rz_il_handler_ule,
|
|
[RZ_IL_OP_CAST] = rz_il_handler_cast,
|
|
[RZ_IL_OP_APPEND] = rz_il_handler_append,
|
|
[RZ_IL_OP_LOAD] = rz_il_handler_load,
|
|
[RZ_IL_OP_LOADW] = rz_il_handler_loadw,
|
|
|
|
// Fbasic Theory
|
|
[RZ_IL_OP_FLOAT] = rz_il_handler_float,
|
|
[RZ_IL_OP_FBITS] = rz_il_handler_fbits,
|
|
[RZ_IL_OP_IS_FINITE] = rz_il_handler_is_finite,
|
|
[RZ_IL_OP_IS_NAN] = rz_il_handler_is_nan,
|
|
[RZ_IL_OP_IS_INF] = rz_il_handler_is_inf,
|
|
[RZ_IL_OP_IS_FZERO] = rz_il_handler_is_fzero,
|
|
[RZ_IL_OP_IS_FNEG] = rz_il_handler_is_fneg,
|
|
[RZ_IL_OP_IS_FPOS] = rz_il_handler_is_fpos,
|
|
[RZ_IL_OP_FNEG] = rz_il_handler_fneg,
|
|
[RZ_IL_OP_FABS] = rz_il_handler_fabs,
|
|
[RZ_IL_OP_FREQUAL] = rz_il_handler_frequal,
|
|
[RZ_IL_OP_FSUCC] = rz_il_handler_fsucc,
|
|
[RZ_IL_OP_FPRED] = rz_il_handler_fpred,
|
|
[RZ_IL_OP_FORDER] = rz_il_handler_forder,
|
|
[RZ_IL_OP_FROUND] = rz_il_handler_fround,
|
|
[RZ_IL_OP_FSQRT] = rz_il_handler_fsqrt,
|
|
[RZ_IL_OP_FRSQRT] = rz_il_handler_pure_unimplemented,
|
|
[RZ_IL_OP_FEXCEPT] = rz_il_handler_fexcept,
|
|
[RZ_IL_OP_FADD] = rz_il_handler_fadd,
|
|
[RZ_IL_OP_FSUB] = rz_il_handler_fsub,
|
|
[RZ_IL_OP_FMUL] = rz_il_handler_fmul,
|
|
[RZ_IL_OP_FDIV] = rz_il_handler_fdiv,
|
|
[RZ_IL_OP_FMOD] = rz_il_handler_fmod,
|
|
[RZ_IL_OP_FMAD] = rz_il_handler_fmad,
|
|
|
|
[RZ_IL_OP_FCAST_INT] = rz_il_handler_fcast_int,
|
|
[RZ_IL_OP_FCAST_SINT] = rz_il_handler_fcast_sint,
|
|
[RZ_IL_OP_FCAST_FLOAT] = rz_il_handler_fcast_float,
|
|
[RZ_IL_OP_FCAST_SFLOAT] = rz_il_handler_fcast_sfloat,
|
|
[RZ_IL_OP_FCONVERT] = rz_il_handler_fconvert,
|
|
|
|
// Float Theory
|
|
// TODO : Implement other Float Theory operations
|
|
[RZ_IL_OP_FHYPOT] = rz_il_handler_pure_unimplemented,
|
|
[RZ_IL_OP_FPOW] = rz_il_handler_pure_unimplemented,
|
|
[RZ_IL_OP_FROOTN] = rz_il_handler_pure_unimplemented,
|
|
[RZ_IL_OP_FPOWN] = rz_il_handler_pure_unimplemented,
|
|
[RZ_IL_OP_FCOMPOUND] = rz_il_handler_pure_unimplemented,
|
|
};
|
|
|
|
RZ_IPI RzILOpEffectHandler rz_il_op_handler_effect_table_default[RZ_IL_OP_EFFECT_MAX] = {
|
|
[RZ_IL_OP_EMPTY] = rz_il_handler_empty,
|
|
[RZ_IL_OP_STORE] = rz_il_handler_store,
|
|
[RZ_IL_OP_STOREW] = rz_il_handler_storew,
|
|
[RZ_IL_OP_NOP] = rz_il_handler_nop,
|
|
[RZ_IL_OP_SET] = rz_il_handler_set,
|
|
[RZ_IL_OP_JMP] = rz_il_handler_jmp,
|
|
[RZ_IL_OP_GOTO] = rz_il_handler_goto,
|
|
[RZ_IL_OP_SEQ] = rz_il_handler_seq,
|
|
[RZ_IL_OP_BLK] = rz_il_handler_blk,
|
|
[RZ_IL_OP_REPEAT] = rz_il_handler_repeat,
|
|
[RZ_IL_OP_BRANCH] = rz_il_handler_branch,
|
|
};
|
|
|
|
/**
|
|
* Load data from memory by given key and generates an RZ_IL_EVENT_MEM_READ event
|
|
* \param vm RzILVM, pointer to VM
|
|
* \param key RzBitVector, aka address, a key to load data from memory
|
|
* \return val Bitvector, data at the address, has `vm->min_unit_size` length
|
|
*/
|
|
RZ_API RzBitVector *rz_il_vm_mem_load(RzILVM *vm, RzILMemIndex index, RzBitVector *key) {
|
|
rz_return_val_if_fail(vm && key, NULL);
|
|
RzILMem *mem = rz_il_vm_get_mem(vm, index);
|
|
if (!mem) {
|
|
RZ_LOG_ERROR("Non-existent mem %u referenced\n", (unsigned int)index);
|
|
return NULL;
|
|
}
|
|
RzBitVector *value = rz_il_mem_load(mem, key);
|
|
rz_il_vm_event_add(vm, rz_il_event_mem_read_new(index, key, value));
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Store data to memory by key, will create a key-value pair
|
|
* or update the key-value pair if key existed; also generates
|
|
* an RZ_IL_EVENT_MEM_WRITE event
|
|
* \param vm RzILVM* pointer to VM
|
|
* \param key RzBitVector, aka address, a key to store data from memory
|
|
* \param value RzBitVector, aka value to store in memory
|
|
*/
|
|
RZ_API void rz_il_vm_mem_store(RzILVM *vm, RzILMemIndex index, RzBitVector *key, RzBitVector *value) {
|
|
rz_return_if_fail(vm && key && value);
|
|
RzILMem *mem = rz_il_vm_get_mem(vm, index);
|
|
if (!mem) {
|
|
RZ_LOG_ERROR("Non-existent mem %u referenced\n", (unsigned int)index);
|
|
return;
|
|
}
|
|
RzBitVector *old_value = rz_il_mem_load(mem, key);
|
|
rz_il_mem_store(mem, key, value);
|
|
rz_il_vm_event_add(vm, rz_il_event_mem_write_new(index, key, old_value, value));
|
|
rz_bv_free(old_value);
|
|
}
|
|
|
|
/**
|
|
* Load data from memory by given key and generates an RZ_IL_EVENT_MEM_READ event
|
|
* \param vm RzILVM, pointer to VM
|
|
* \param key RzBitVector, aka address, a key to load data from memory
|
|
* \return val Bitvector, data at the address, has `vm->min_unit_size` length
|
|
*/
|
|
RZ_API RzBitVector *rz_il_vm_mem_loadw(RzILVM *vm, RzILMemIndex index, RzBitVector *key, ut32 n_bits) {
|
|
rz_return_val_if_fail(vm && key, NULL);
|
|
RzILMem *mem = rz_il_vm_get_mem(vm, index);
|
|
if (!mem) {
|
|
RZ_LOG_ERROR("Non-existent mem %u referenced\n", (unsigned int)index);
|
|
return NULL;
|
|
}
|
|
RzBitVector *value = rz_il_mem_loadw(mem, key, n_bits, vm->big_endian);
|
|
rz_il_vm_event_add(vm, rz_il_event_mem_read_new(index, key, value));
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Store data to memory by key, will create a key-value pair
|
|
* or update the key-value pair if key existed; also generates
|
|
* an RZ_IL_EVENT_MEM_WRITE event
|
|
* \param index RzILMemIndex, index of the memory to store data
|
|
* \param vm RzILVM* pointer to VM
|
|
* \param key RzBitVector, aka address, a key to store data from memory
|
|
* \param value RzBitVector, aka value to store in memory
|
|
*/
|
|
RZ_API void rz_il_vm_mem_storew(RzILVM *vm, RzILMemIndex index, RzBitVector *key, RzBitVector *value) {
|
|
rz_return_if_fail(vm && key && value);
|
|
RzILMem *mem = rz_il_vm_get_mem(vm, index);
|
|
if (!mem) {
|
|
RZ_LOG_ERROR("Non-existent mem %u referenced\n", (unsigned int)index);
|
|
return;
|
|
}
|
|
RzBitVector *old_value = rz_il_mem_loadw(mem, key, rz_bv_len(value), vm->big_endian);
|
|
if (!rz_il_mem_storew(mem, key, value, vm->big_endian)) {
|
|
RZ_LOG_ERROR("StoreW mem %u 0x%" PFMT64x " failed\n", (unsigned int)index, rz_bv_to_ut64(key));
|
|
goto end;
|
|
}
|
|
rz_il_vm_event_add(vm, rz_il_event_mem_write_new(index, key, old_value, value));
|
|
end:
|
|
rz_bv_free(old_value);
|
|
}
|
|
|
|
/**
|
|
* Adds to the VM a new event into the VM event list
|
|
* \param vm, RzILVM, pointer to the VM
|
|
* \param evt, RzILEvent, pointer to the event
|
|
*/
|
|
RZ_API void rz_il_vm_event_add(RzILVM *vm, RzILEvent *evt) {
|
|
rz_return_if_fail(vm && vm->events && evt);
|
|
if (!rz_pvector_push(vm->events, evt)) {
|
|
rz_warn_if_reached();
|
|
rz_il_event_free(evt);
|
|
}
|
|
if (evt->type == RZ_IL_EVENT_EXCEPTION && (vm->halt_exceptions & evt->data.exception)) {
|
|
RZ_LOG_WARN("Reached exception '%s'. Requesting VM to halt.\n", rz_il_event_exception_msg(evt->data.exception));
|
|
vm->halt = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove any recorded events from `vm->events`
|
|
*/
|
|
RZ_API void rz_il_vm_clear_events(RzILVM *vm) {
|
|
rz_pvector_clear(vm->events);
|
|
}
|
|
|
|
/**
|
|
* Execute the opcodes uplifted from raw instructions.A list may contain multiple opcode trees
|
|
* \param vm pointer to VM
|
|
* \param op_list, a list of op roots.
|
|
* \param fallthrough_addr initial address to set PC to. Thus also the address to "step to" if no explicit jump occurs.
|
|
*/
|
|
RZ_API bool rz_il_vm_step(RzILVM *vm, RzILOpEffect *op, ut64 fallthrough_addr) {
|
|
rz_return_val_if_fail(vm && op, false);
|
|
|
|
rz_il_vm_clear_events(vm);
|
|
|
|
// Set the successor pc **before** evaluating. Any jmp/goto may then overwrite it again.
|
|
ut64 old_pc = rz_bv_to_ut64(vm->pc);
|
|
RzBitVector *next_pc = rz_bv_new_from_ut64(vm->pc->len, fallthrough_addr);
|
|
rz_il_vm_event_add(vm, rz_il_event_pc_write_new(vm->pc, next_pc));
|
|
rz_bv_free(vm->pc);
|
|
vm->pc = next_pc;
|
|
|
|
bool succ = rz_il_evaluate_effect(vm, op);
|
|
if (vm->halt) {
|
|
RZ_LOG_WARN("Halting VM at 0x%" PFMT64x "!\n", old_pc);
|
|
// Reset PC to halting instruction.
|
|
RzBitVector *prev_pc = rz_bv_new_from_ut64(vm->pc->len, old_pc);
|
|
rz_bv_free(vm->pc);
|
|
vm->pc = prev_pc;
|
|
// Don't reset vm->halt flag.
|
|
// User should re-init VM.
|
|
return false;
|
|
}
|
|
|
|
// remove any local defined variable (local pure vars are unbound automatically)
|
|
rz_il_var_set_reset(&vm->local_vars);
|
|
return succ;
|
|
}
|
|
|
|
static void *eval_pure(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILOpPure *op, RZ_NONNULL RzILTypePure *type) {
|
|
rz_return_val_if_fail(vm && op && type, NULL);
|
|
RzILOpPureHandler handler = vm->op_handler_pure_table[op->code];
|
|
rz_return_val_if_fail(handler, NULL);
|
|
return handler(vm, op, type);
|
|
}
|
|
|
|
static bool eval_effect(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILOpEffect *op) {
|
|
rz_return_val_if_fail(vm && op, false);
|
|
RzILOpEffectHandler handler = vm->op_handler_effect_table[op->code];
|
|
rz_return_val_if_fail(handler, false);
|
|
return handler(vm, op);
|
|
}
|
|
|
|
static const char *pure_type_name(RzILTypePure type) {
|
|
switch (type) {
|
|
case RZ_IL_TYPE_PURE_BITVECTOR:
|
|
return "bitvector";
|
|
case RZ_IL_TYPE_PURE_BOOL:
|
|
return "bool";
|
|
case RZ_IL_TYPE_PURE_FLOAT:
|
|
return "float";
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Evaluate the given pure op, asserting it returns a bitvector.
|
|
* \return value in bitvector, or NULL if an error occurred (e.g. the op returned some other type)
|
|
*/
|
|
RZ_API RZ_NULLABLE RZ_OWN RzBitVector *rz_il_evaluate_bitv(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILOpBitVector *op) {
|
|
rz_return_val_if_fail(vm && op, NULL);
|
|
// check type and auto convertion between bitv/bool/val
|
|
RzILTypePure type = -1;
|
|
void *res = eval_pure(vm, op, &type);
|
|
if (!res) {
|
|
// propagate error
|
|
return NULL;
|
|
}
|
|
if (type != RZ_IL_TYPE_PURE_BITVECTOR) {
|
|
RZ_LOG_ERROR("RzIL: type error: expected bitvector, got %s\n", pure_type_name(type));
|
|
return NULL;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Evaluate the given pure op, asserting it returns a bool.
|
|
* \return value in bool, or NULL if an error occurred (e.g. the op returned some other type)
|
|
*/
|
|
RZ_API RZ_NULLABLE RZ_OWN RzILBool *rz_il_evaluate_bool(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILOpBool *op) {
|
|
rz_return_val_if_fail(vm && op, NULL);
|
|
// check type and auto convertion between bitv/bool/val
|
|
RzILTypePure type = -1;
|
|
void *res = eval_pure(vm, op, &type);
|
|
if (!res) {
|
|
// propagate error
|
|
return NULL;
|
|
}
|
|
if (type != RZ_IL_TYPE_PURE_BOOL) {
|
|
RZ_LOG_ERROR("RzIL: type error: expected bool, got %s\n", pure_type_name(type));
|
|
return NULL;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Evaluate the given pure op, returning the resulting bool or bitvector.
|
|
* \return val, RzILVal*, RzILVal type value
|
|
*/
|
|
RZ_API RZ_NULLABLE RZ_OWN RzILVal *rz_il_evaluate_val(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILOpPure *op) {
|
|
rz_return_val_if_fail(vm && op, NULL);
|
|
// check type and auto convertion between bitv/bool/val
|
|
RzILTypePure type = -1;
|
|
void *res = eval_pure(vm, op, &type);
|
|
if (!res) {
|
|
// propagate error
|
|
return NULL;
|
|
}
|
|
switch (type) {
|
|
case RZ_IL_TYPE_PURE_BOOL:
|
|
return rz_il_value_new_bool(res);
|
|
case RZ_IL_TYPE_PURE_BITVECTOR:
|
|
return rz_il_value_new_bitv(res);
|
|
case RZ_IL_TYPE_PURE_FLOAT:
|
|
return rz_il_value_new_float(res);
|
|
default:
|
|
RZ_LOG_ERROR("RzIL: type error: got %s\n", pure_type_name(type));
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Evaluate the given pure op, returning the resulting value and its type.
|
|
*/
|
|
RZ_API RZ_NULLABLE RZ_OWN void *rz_il_evaluate_pure(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILOpPure *op, RZ_NONNULL RzILTypePure *type) {
|
|
rz_return_val_if_fail(vm && op, NULL);
|
|
return eval_pure(vm, op, type);
|
|
}
|
|
|
|
/**
|
|
* Evaluate (execute) the given effect op
|
|
* \return false if an error occured and the execution should be aborted
|
|
*/
|
|
RZ_API bool rz_il_evaluate_effect(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILOpEffect *op) {
|
|
rz_return_val_if_fail(vm && op, false);
|
|
return eval_effect(vm, op);
|
|
}
|
|
|
|
/**
|
|
* Evaluate the given pure op, return the float
|
|
* \return NULL if an error occured
|
|
*/
|
|
RZ_API RZ_NULLABLE RZ_OWN RzFloat *rz_il_evaluate_float(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILOpPure *op) {
|
|
rz_return_val_if_fail(vm && op, NULL);
|
|
|
|
// check type and auto convertion between bitv/bool/val
|
|
RzILTypePure type = -1;
|
|
void *res = eval_pure(vm, op, &type);
|
|
if (!res) {
|
|
// propagate error
|
|
return NULL;
|
|
}
|
|
if (type != RZ_IL_TYPE_PURE_FLOAT) {
|
|
RZ_LOG_ERROR("RzIL: type error: expected float, got %s\n", pure_type_name(type));
|
|
return NULL;
|
|
}
|
|
return res;
|
|
}
|