rizin/librz/il/il_vm_eval.c
Khairul Azhar Kasmiran c8878d3139
Convert %ll format specifiers to PFMT64 (#6267)
* Convert `%ll` format specifiers to PFMT64
* Remove ` ""` at end of some PFMT64
2026-04-22 05:57:04 +08:00

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;
}