[RzIL] Rewrite RzAnalysisRzil as RzAnalysisILVM with config

RzAnalysisILVM wraps around the low-level RzILVM and enables emulation
of real code from disassembly, rather than raw IL.
Analysis plugins now don't actively initialize the vm anymore, but
return a fully declarative description RzAnalysisILConfig of how to set
up the vm and optionally its initial state.
This also enables multiple IL vms to exist at the same time as plugins
can not mess with the global vm anymore. See the added integration test
for an example.
This commit is contained in:
Florian Märkl 2022-01-15 19:53:14 +01:00
parent 65efe6699c
commit f9e01ba07d
30 changed files with 663 additions and 550 deletions

View file

@ -145,3 +145,23 @@ implementation of [`unsigned`](https://github.com/rizinorg/rizin/blob/4487d7e1ac
And some may be omitted completely, such as
[`concat`](http://binaryanalysisplatform.github.io/bap/api/master/bap-core-theory/Bap_core_theory/Theory/module-type-Basic/index.html#val-concat),
as list operands would be rather awkward to handle in C.
Execution of real machine code
------------------------------
The bare IL described above is located in the `il` module. It comes with a
reference interpreter implemented as `RzILVM`, which may be used to evaluate
arbitrary pure and effect ops on a state of variables and memories. At this
point the IL does not have any connection to real architectures yet.
The `analysis` module then bridges exactly this gap. It provides the extended
`RzAnalysisILVM`, which directly builds on top of `RzILVM`, but adds the
connection to `RzIO` for memories, binding of IL variables to machine registers
and other related aspects.
An `RzAnalysisPlugin`, which is used to disassemble instructions of a specific
architecture, may also implement lifting from its raw machine code to RzIL in
its `op` callback.
In addition, it declaratively describes any architecture-specific info about
the global context in which this lifted code is meant to be executed by
implementing the `il_config` callback.

View file

@ -124,7 +124,7 @@ RZ_API RzAnalysis *rz_analysis_new(void) {
}
analysis->ht_global_var = ht_pp_new(NULL, global_kv_free, NULL);
analysis->global_var_tree = NULL;
analysis->rzil = NULL;
analysis->il_vm = NULL;
return analysis;
}
@ -145,7 +145,7 @@ RZ_API RzAnalysis *rz_analysis_free(RzAnalysis *a) {
plugin_fini(a);
rz_analysis_rzil_cleanup(a);
rz_analysis_il_vm_cleanup(a);
rz_list_free(a->fcns);
ht_up_free(a->ht_addr_fun);
ht_pp_free(a->ht_name_fun);
@ -202,19 +202,8 @@ RZ_API bool rz_analysis_use(RzAnalysis *analysis, const char *name) {
return false;
}
rz_analysis_set_reg_profile(analysis);
// default : init and enable RzIL if defined rzil_init
if (h->rzil_init) {
if (analysis->rzil) {
rz_analysis_rzil_cleanup(analysis);
analysis->rzil = NULL;
}
rz_analysis_rzil_setup(analysis);
} else {
// create it to make analysis_tp go right
if (!analysis->rzil) {
analysis->rzil = rz_analysis_rzil_new();
}
if (analysis->il_vm) {
rz_analysis_il_vm_setup(analysis);
}
return true;
}

View file

@ -0,0 +1,304 @@
// SPDX-FileCopyrightText: 2021 heersin <teablearcher@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_analysis.h>
/**
* \name Config and Init State
* @{
*/
static void var_state_free(void *e, void *user) {
RzAnalysisILInitStateVar *s = e;
if (!s) {
return;
}
rz_il_value_free(s->val);
}
RZ_API RzAnalysisILInitState *rz_analysis_il_init_state_new() {
RzAnalysisILInitState *r = RZ_NEW0(RzAnalysisILInitState);
if (!r) {
return NULL;
}
rz_vector_init(&r->vars, sizeof(RzAnalysisILInitStateVar), var_state_free, NULL);
return r;
}
RZ_API void rz_analysis_il_init_state_free(RzAnalysisILInitState *state) {
if (!state) {
return;
}
rz_vector_fini(&state->vars);
}
/**
* Set the value of the global variable called \p name name to \p val in the initial state \p state
*/
RZ_API void rz_analysis_il_init_state_set_var(RZ_NONNULL RzAnalysisILInitState *state,
RZ_NONNULL const char *name, RZ_NONNULL RZ_OWN RzILVal *val) {
rz_return_if_fail(state && name && val);
RzAnalysisILInitStateVar *v = rz_vector_push(&state->vars, NULL);
if (!v) {
rz_il_value_free(val);
return;
}
v->name = name;
v->val = val;
}
/**
* Create an IL config and initialize it with the given minimal mandatory info
*/
RZ_API RZ_OWN RzAnalysisILConfig *rz_analysis_il_config_new(ut32 pc_size, bool big_endian, ut32 mem_key_size) {
rz_return_val_if_fail(pc_size && mem_key_size, NULL);
RzAnalysisILConfig *r = RZ_NEW0(RzAnalysisILConfig);
if (!r) {
return NULL;
}
r->pc_size = pc_size;
r->big_endian = big_endian;
r->mem_key_size = mem_key_size;
rz_pvector_init(&r->labels, (RzPVectorFree)rz_il_effect_label_free);
return r;
}
RZ_API void rz_analysis_il_config_free(RzAnalysisILConfig *cfg) {
if (!cfg) {
return;
}
rz_pvector_fini(&cfg->labels);
free(cfg);
}
/**
* Add \p label to the IL config \p cfg to describe that it is globally available in a vm
*/
RZ_API void rz_analysis_il_config_add_label(RZ_NONNULL RzAnalysisILConfig *cfg, RZ_NONNULL RZ_OWN RzILEffectLabel *label) {
rz_return_if_fail(cfg && label);
rz_pvector_push(&cfg->labels, label);
}
/// @}
/////////////////////////////////////////////////////////
/**
* \name Analysis IL VM
* @{
*/
static void setup_vm_from_config(RzAnalysis *analysis, RzAnalysisILVM *vm, RzAnalysisILConfig *cfg);
static void setup_vm_init_state(RzAnalysisILVM *vm, RZ_NULLABLE RzAnalysisILInitState *is, RZ_NULLABLE RzReg *reg);
/**
* Create and initialize an RzAnalysisILVM with the current arch/cpu/bits configuration and plugin
* \p init_state_reg optional RzReg to take variable values from, unless the plugin overrides them using RzAnalysisILInitState
* \return RzAnalysisRzil* a pointer to RzAnalysisILVM instance
*/
RZ_API RZ_OWN RzAnalysisILVM *rz_analysis_il_vm_new(RzAnalysis *a, RZ_NULLABLE RzReg *init_state_reg) {
rz_return_val_if_fail(a, NULL);
RzAnalysisILConfig *config = a->cur->il_config(a);
if (!config) {
return false;
}
RzAnalysisILVM *r = RZ_NEW0(RzAnalysisILVM);
if (!r) {
goto ruby_pool;
}
r->io_buf = rz_buf_new_with_io(&a->iob);
setup_vm_from_config(a, r, config);
if (!r->vm) {
rz_buf_free(r->io_buf);
free(r);
r = NULL;
goto ruby_pool;
}
setup_vm_init_state(r, config->init_state, init_state_reg);
ruby_pool:
rz_analysis_il_config_free(config);
return r;
}
/**
* Frees an RzAnalysisILVM instance
*/
RZ_API void rz_analysis_il_vm_free(RZ_NULLABLE RzAnalysisILVM *vm) {
if (!vm) {
return;
}
rz_il_vm_free(vm->vm);
rz_il_reg_binding_free(vm->reg_binding);
rz_buf_free(vm->io_buf);
free(vm);
}
static bool setup_regs(RzAnalysis *a, RzAnalysisILVM *vm) {
if (!a->cur->get_reg_profile) {
return false;
}
// Explicitly use a new reg here!
// The a->reg might be changed by the user, but plugins expect exactly
// the register profile they supplied. Syncing will later adjust the register
// contents if necessary.
RzReg *reg = rz_reg_new();
if (!reg) {
return false;
}
char *profile = a->cur->get_reg_profile(a);
bool succ;
if (!profile) {
succ = false;
goto new_real;
}
succ = rz_reg_set_profile_string(reg, profile);
free(profile);
if (!succ) {
goto new_real;
}
// for now, we always derive the bound automatically,
// but manual binding dictated by the plugin would be plausible too
// in the future.
vm->reg_binding = rz_il_reg_binding_derive(reg);
if (!vm->reg_binding) {
succ = false;
goto new_real;
}
rz_il_vm_setup_reg_binding(vm->vm, vm->reg_binding);
new_real:
rz_reg_free(reg);
return succ;
}
static void setup_vm_from_config(RzAnalysis *analysis, RzAnalysisILVM *vm, RzAnalysisILConfig *cfg) {
vm->vm = rz_il_vm_new(0, cfg->pc_size, cfg->big_endian);
if (!vm->vm) {
return;
}
if (!setup_regs(analysis, vm)) { // regs are currently always derived
rz_il_vm_free(vm->vm);
vm->vm = NULL;
return;
}
rz_il_vm_add_mem(vm->vm, 0, rz_il_mem_new(vm->io_buf, cfg->mem_key_size));
void **it;
rz_pvector_foreach (&cfg->labels, it) {
RzILEffectLabel *lbl = *it;
rz_il_vm_add_label(vm->vm, rz_il_effect_label_dup(lbl));
}
}
static void setup_vm_init_state(RzAnalysisILVM *vm, RZ_NULLABLE RzAnalysisILInitState *is, RZ_NULLABLE RzReg *reg) {
if (reg) {
rz_il_vm_sync_from_reg(vm->vm, vm->reg_binding, reg);
}
if (is) {
RzAnalysisILInitStateVar *v;
rz_vector_foreach(&is->vars, v) {
rz_il_vm_set_global_var(vm->vm, v->name, rz_il_value_dup(v->val));
}
}
}
/**
* Set the values of all variables in \p vm that are bound to registers and PC to the respective contents from \p reg.
*
* This is like the low-level `rz_il_vm_sync_from_reg()`, but uses the binding that is part of \p vm.
* See its documentation for details.
*/
RZ_API void rz_analysis_il_vm_sync_from_reg(RzAnalysisILVM *vm, RZ_NONNULL RzReg *reg) {
rz_return_if_fail(vm && reg);
rz_il_vm_sync_from_reg(vm->vm, vm->reg_binding, reg);
}
/**
* Set the values of all bound regs in \p reg to the respective variable or PC contents in \p vm.
*
* This is like the low-level `rz_il_vm_sync_to_reg()`, but uses the binding that is part of \p vm.
* See its documentation for details.
*
* \return whether the sync was cleanly applied without errors or adjustments
*/
RZ_API bool rz_analysis_il_vm_sync_to_reg(RzAnalysisILVM *vm, RZ_NONNULL RzReg *reg) {
rz_return_val_if_fail(vm && reg, false);
return rz_il_vm_sync_to_reg(vm->vm, vm->reg_binding, reg);
}
/**
* Perform a single step in the VM
*
* If given, this syncs the contents of \p reg into the vm.
* Then it disassembles an instruction at the program counter of the vm and executes it.
* Finally, if no error occured, the contents are optionally synced back to \p reg.
*
* \return and indicator for which error occured, if any
*/
RZ_API RzAnalysisILStepResult rz_analysis_il_vm_step(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisILVM *vm, RZ_NULLABLE RzReg *reg) {
rz_return_val_if_fail(analysis && vm, false);
RzAnalysisPlugin *cur = analysis->cur;
if (!cur || !analysis->read_at) {
return RZ_ANALYSIS_IL_STEP_RESULT_NOT_SET_UP;
}
if (reg) {
rz_analysis_il_vm_sync_from_reg(vm, reg);
}
ut64 addr = rz_bv_to_ut64(vm->vm->pc);
ut8 code[32] = { 0 };
analysis->read_at(analysis, addr, code, sizeof(code));
RzAnalysisOp op = { 0 };
int r = rz_analysis_op(analysis, &op, addr, code, sizeof(code), RZ_ANALYSIS_OP_MASK_ESIL | RZ_ANALYSIS_OP_MASK_HINT);
RzILOpEffect *ilop = r < 0 ? NULL : op.il_op;
RzAnalysisILStepResult res;
if (ilop) {
bool succ = rz_il_vm_step(vm->vm, ilop, addr + (op.size > 0 ? op.size : 1));
res = succ ? RZ_ANALYSIS_IL_STEP_RESULT_SUCCESS : RZ_ANALYSIS_IL_STEP_IL_RUNTIME_ERROR;
if (reg) {
rz_analysis_il_vm_sync_to_reg(vm, reg);
}
} else {
res = RZ_ANALYSIS_IL_STEP_INVALID_OP;
}
rz_analysis_op_fini(&op);
return res;
}
/// @}
/////////////////////////////////////////////////////////
/**
* \name Global, user-faced VM setup
* @{
*/
/**
* (Re)initialize the global user-faced vm
* \return whether the init succeeded
*/
RZ_API bool rz_analysis_il_vm_setup(RzAnalysis *analysis) {
rz_return_val_if_fail(analysis, false);
rz_analysis_il_vm_cleanup(analysis);
if (!analysis->cur || !analysis->cur->il_config) {
return false;
}
analysis->il_vm = rz_analysis_il_vm_new(analysis, analysis->reg);
if (analysis->il_vm) {
// rz_analysis_il_vm_new merges the contents of analysis->reg with the plugin's optional RzAnalysisILInitState
// Now sync the merged state back:
rz_il_vm_sync_to_reg(analysis->il_vm->vm, analysis->il_vm->reg_binding, analysis->reg);
}
return !!analysis->il_vm;
}
/**
* Destroy the global user-faced vm
*/
RZ_API void rz_analysis_il_vm_cleanup(RzAnalysis *analysis) {
rz_return_if_fail(analysis);
rz_analysis_il_vm_free(analysis->il_vm);
analysis->il_vm = NULL;
}
/// @}

View file

@ -21,7 +21,7 @@ static void htup_vector_free(HtUPKv *kv) {
* \param rzil RZ_IL instance
* \return pointer to RzilTrace
*/
RZ_API RzAnalysisRzilTrace *rz_analysis_rzil_trace_new(RzAnalysis *analysis, RZ_NONNULL RzAnalysisRzil *rzil) {
RZ_API RzAnalysisRzilTrace *rz_analysis_rzil_trace_new(RzAnalysis *analysis, RZ_NONNULL RzAnalysisILVM *rzil) {
rz_return_val_if_fail(rzil, NULL);
size_t i;
RzAnalysisEsilTrace *trace = RZ_NEW0(RzAnalysisEsilTrace);
@ -91,6 +91,6 @@ RZ_API void rz_analysis_rzil_trace_free(RzAnalysisEsilTrace *trace) {
* \param rzil IL instance
* \param op RzAnalysisRzilOp, a general IL op structure (Designed for switching between different implementations of IL op struct)
*/
RZ_API void rz_analysis_rzil_trace_op(RzAnalysis *analysis, RZ_NONNULL RzAnalysisRzil *rzil, RZ_NONNULL RzAnalysisLiftedILOp op) {
RZ_API void rz_analysis_rzil_trace_op(RzAnalysis *analysis, RZ_NONNULL RzAnalysisILVM *rzil, RZ_NONNULL RzAnalysisLiftedILOp op) {
// TODO : rewrite this file when migrate to new op structure
}

View file

@ -92,9 +92,8 @@ rz_analysis_sources = [
'rtti.c',
'rtti_itanium.c',
'rtti_msvc.c',
'rzil/rzil.c',
'rzil/rzil_stats.c',
'rzil/rzil_trace.c',
'il/analysis_il.c',
'il/analysis_il_trace.c',
'serialize_analysis.c',
'serialize_typelink.c',
'sigdb.c',

View file

@ -1071,30 +1071,8 @@ static int address_bits(RzAnalysis *analysis, int bits) {
return 16;
}
static bool il_6502_init(RzAnalysis *analysis) {
rz_return_val_if_fail(analysis && analysis->rzil, false);
RzAnalysisRzil *rzil = analysis->rzil;
if (rzil->inited) {
RZ_LOG_ERROR("RzIL: 6502: already initialized\n");
return true;
}
RzILVM *vm = rzil->vm;
if (!rz_il_vm_init(rzil->vm, 0, 16, 8)) {
RZ_LOG_ERROR("RzIL: 6502: failed to initialize VM\n");
return false;
}
rz_il_vm_add_mem(vm, 0, rz_il_mem_new(rzil->io_buf, 16));
return true;
}
static bool il_6502_fini(RzAnalysis *analysis) {
rz_return_val_if_fail(analysis && analysis->rzil, false);
RzAnalysisRzil *rzil = analysis->rzil;
rzil->user = NULL;
rzil->inited = false;
return true;
static RzAnalysisILConfig *il_config(RzAnalysis *analysis) {
return rz_analysis_il_config_new(16, false, 16);
}
RzAnalysisPlugin rz_analysis_plugin_6502 = {
@ -1109,8 +1087,7 @@ RzAnalysisPlugin rz_analysis_plugin_6502 = {
.esil = true,
.esil_init = esil_6502_init,
.esil_fini = esil_6502_fini,
.rzil_init = il_6502_init,
.rzil_fini = il_6502_fini
.il_config = il_config
};
#ifndef RZ_PLUGIN_INCORE

View file

@ -150,59 +150,21 @@ RzILOpEffect *bf_rlimit(RzAnalysis *analysis, ut64 addr, ut64 target) {
return branch;
}
static bool bf_fini_rzil(RzAnalysis *analysis) {
rz_return_val_if_fail(analysis && analysis->rzil, false);
RzAnalysisRzil *rzil = analysis->rzil;
rzil->user = NULL;
rzil->inited = false;
return true;
}
static bool bf_init_rzil(RzAnalysis *analysis) {
rz_return_val_if_fail(analysis && analysis->rzil, false);
RzAnalysisRzil *rzil = analysis->rzil;
if (rzil->inited) {
RZ_LOG_ERROR("RzIL: brainfuck: already initialized\n");
return true;
static RzAnalysisILConfig *il_config(RzAnalysis *analysis) {
RzAnalysisILConfig *cfg = rz_analysis_il_config_new(64, false, 64);
cfg->init_state = rz_analysis_il_init_state_new();
if (!cfg->init_state) {
rz_analysis_il_config_free(cfg);
return NULL;
}
// TODO : get some arguments from rizin, predefined some for now.
ut32 addrsize = BF_ADDR_SIZE;
ut64 start_addr = 0;
// create core theory VM
if (!rz_il_vm_init(rzil->vm, start_addr, addrsize, false)) {
RZ_LOG_ERROR("RzIL: brainfuck: failed to initialize VM\n");
return false;
}
RzBuffer *buf = rz_buf_new_sparse_overlay(rzil->io_buf, RZ_BUF_SPARSE_WRITE_MODE_SPARSE);
if (!buf) {
rz_il_vm_fini(rzil->vm);
return false;
}
RzILMem *mem = rz_il_mem_new(buf, 64);
if (!mem) {
rz_buf_free(buf);
rz_il_vm_fini(rzil->vm);
return false;
}
rz_il_vm_add_mem(rzil->vm, 0, mem);
// set ptr to BF_ADDR_MEM
rz_reg_setv(analysis->reg, "ptr", BF_ADDR_MEM);
RzILEffectLabel *read_label = rz_il_vm_create_label_lazy(rzil->vm, "read");
RzILEffectLabel *write_label = rz_il_vm_create_label_lazy(rzil->vm, "write");
read_label->addr = (void *)bf_syscall_read;
write_label->addr = (void *)bf_syscall_write;
read_label->type = EFFECT_LABEL_SYSCALL;
write_label->type = EFFECT_LABEL_HOOK;
rzil->inited = true;
return true;
rz_analysis_il_init_state_set_var(cfg->init_state, "ptr", rz_il_value_new_bitv(rz_bv_new_from_ut64(64, BF_ADDR_MEM)));
RzILEffectLabel *read_label = rz_il_effect_label_new("read", EFFECT_LABEL_SYSCALL);
read_label->hook = bf_syscall_read;
rz_analysis_il_config_add_label(cfg, read_label);
RzILEffectLabel *write_label = rz_il_effect_label_new("write", EFFECT_LABEL_HOOK);
write_label->hook = bf_syscall_write;
rz_analysis_il_config_add_label(cfg, write_label);
return cfg;
}
static int bf_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *buf, int len, RzAnalysisOpMask mask) {
@ -286,8 +248,7 @@ RzAnalysisPlugin rz_analysis_plugin_bf = {
.bits = 64, // RzIL emulation of bf and the reg definitions above use 64bit values
.op = &bf_op,
.get_reg_profile = get_reg_profile,
.rzil_init = bf_init_rzil,
.rzil_fini = bf_fini_rzil
.il_config = il_config
};
#ifndef RZ_PLUGIN_INCORE

View file

@ -1,173 +0,0 @@
// SPDX-FileCopyrightText: 2021 heersin <teablearcher@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_analysis.h>
/**
* Create an empty RzAnalysisRzil instance
* inner VM should be init in adaptive plugin
* \return RzAnalysisRzil* a pointer to RzAnalysisRzil instance
*/
RZ_API RZ_OWN RzAnalysisRzil *rz_analysis_rzil_new() {
RzAnalysisRzil *rzil = RZ_NEW0(RzAnalysisRzil);
if (!rzil) {
return NULL;
}
rzil->vm = RZ_NEW0(RzILVM);
if (!rzil->vm) {
free(rzil);
return NULL;
}
return rzil;
}
/**
* Frees an RzAnalysisRzil instance
*/
RZ_API void rz_analysis_rzil_free(RZ_NULLABLE RzAnalysisRzil *rzil) {
if (!rzil) {
return;
}
rz_il_vm_free(rzil->vm);
rz_buf_free(rzil->io_buf);
free(rzil);
}
/**
* Cleanup IL instance : clean VM, clean arch-specific user_data, and IL itself
* \param analysis pointer to rizin's RzAnalysis
*/
RZ_API void rz_analysis_rzil_cleanup(RzAnalysis *analysis) {
rz_return_if_fail(analysis);
if (!analysis->rzil) {
return;
}
if (analysis->cur && analysis->cur->rzil_fini) {
analysis->cur->rzil_fini(analysis);
}
rz_analysis_rzil_free(analysis->rzil); // need to get rid of rzil even if we don't have callbacks
analysis->rzil = NULL;
}
/**
* Set instruction pointer for the current IL VM session
* \param rzil RzAnalysis* pointer to RzAnalysisRzil instance
* \param addr ut64 address of new pc
* \return true if set successfully, else return false
*/
RZ_API bool rz_analysis_rzil_set_pc(RzAnalysisRzil *rzil, ut64 addr) {
if (!rzil) {
return false;
}
rzil->pc_addr = addr;
return true;
}
static void setup_regs(RzAnalysis *a, RzAnalysisRzil *rzil) {
if (!a->cur->get_reg_profile) {
return;
}
// Explicitly use a new reg here!
// The a->reg might be changed by the user, but plugins expect exactly
// the register profile they supplied. Syncing will later adjust the register
// contents if necessary.
RzReg *reg = rz_reg_new();
if (!reg) {
return;
}
char *profile = a->cur->get_reg_profile(a);
if (!profile) {
goto new_real;
}
bool succ = rz_reg_set_profile_string(reg, profile);
free(profile);
if (!succ) {
goto new_real;
}
// for now, we always derive the bound automatically,
// but manual binding dictated by the plugin would be plausible too
// in the future.
RzILRegBinding *rb = rz_il_reg_binding_derive(reg);
if (!rb) {
goto new_real;
}
rz_il_vm_setup_reg_binding(rzil->vm, rb);
new_real:
rz_reg_free(reg);
return;
}
/**
* Init an empty IL
* \param analysis RzAnalysis* pointer to RzAnalysis
* \return true if setup, else return false
*/
RZ_API bool rz_analysis_rzil_setup(RzAnalysis *analysis) {
rz_return_val_if_fail(analysis && !analysis->rzil, false);
if (!analysis->cur || !analysis->cur->rzil_init) {
return false;
}
RzAnalysisRzil *rzil = rz_analysis_rzil_new();
if (!rzil) {
return false;
}
rzil->io_buf = rz_buf_new_with_io(&analysis->iob);
analysis->rzil = rzil;
analysis->cur->rzil_init(analysis);
setup_regs(analysis, rzil);
return true;
}
static void rz_analysis_rzil_parse_root(RzAnalysis *analysis, RzAnalysisRzil *rzil, RzAnalysisLiftedILOp ops) {
rz_return_if_fail(analysis && rzil);
// IL disabled
if (!ops) {
return;
}
// 1. step exec the op
// 2. call trace to collect trace info
// 3. call stats to collect stats info
}
/**
* Collect both `trace` and `stats` info of an instruction
* \param analysis
* \param rzil
* \param op
*/
RZ_API void rz_analysis_rzil_collect_info(RzAnalysis *analysis, RzAnalysisRzil *rzil, RzAnalysisOp *op, bool use_new) {
rz_return_if_fail(analysis && rzil && op);
if (use_new) {
RZ_LOG_ERROR("TODO : New Op Structure\n");
return;
}
if (!rzil->trace) {
rzil->trace = rz_analysis_rzil_trace_new(analysis, rzil);
if (!rzil->trace) {
RZ_LOG_ERROR("Unable to init IL trace\n");
return;
}
}
// TODO : add restore as esil_trace_op did
if (rzil->trace->idx != rzil->trace->end_idx) {
RZ_LOG_DEBUG("Restore WIP\n");
return;
}
// Create instruction trace for current instruction
RzILTraceInstruction *instruction = rz_analysis_il_trace_instruction_new(op->addr);
rz_pvector_push(rzil->trace->instructions, instruction);
rzil->trace->idx++;
rzil->trace->end_idx++;
// TODO : Add register change for sync with analysis->register
// Parse and emulate IL opcode, and collect `trace` and `stats` info
// Use new op struct for parsing
rz_analysis_rzil_parse_root(analysis, rzil, op->il_op);
}

View file

@ -1,31 +0,0 @@
// SPDX-FileCopyrightText: 2021 heersin <teablearcher@gmail.com>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_analysis.h>
// TODO : rewrite this file when migrate to new op structure
/**
* In ESIL, stats is used to collect these info :
* 1: ops.list : ESIL op
* 2: flg.read : List<flag> list of flag been read from
* 3: flg.write : List<flag> list of flags been written to
* 4: mem.read : List<memory address> list of memory address
* 5: mem.write : List<memory address> list of memory address
* 6: reg.read : List<register names> list of register names
* 7: reg.write : List<register names> list of register names
* These infos seems be used in `cmd_search_rop.c` only
*
* In the New IL, we should have the similar behavior at first
*
* CHECK_ME : flag read and write never been called in ESIL ??
*/
/**
* Record memory R/W address, register R/W names. similar to `trace`
* \param analysis RzAnalysis
* \param op a general IL op structure (Designed for switching between different implementations of IL op struct)
*/
RZ_API void rz_analysis_rzil_record_stats(RzAnalysis *analysis, RzAnalysisRzil *rzil, RzAnalysisLiftedILOp op) {
// ready for rewriting this file
}

View file

@ -10,7 +10,7 @@
#define LOOP_MAX 10
static bool analysis_emul_init(RzCore *core, RzConfigHold *hc, RzDebugTrace **dt, RzAnalysisEsilTrace **et, RzAnalysisRzilTrace **rt) {
if (!core->analysis->esil || !core->analysis->rzil) {
if (!core->analysis->esil) {
return false;
}
*dt = core->dbg->trace;
@ -18,7 +18,6 @@ static bool analysis_emul_init(RzCore *core, RzConfigHold *hc, RzDebugTrace **dt
core->dbg->trace = rz_debug_trace_new();
core->analysis->esil->trace = rz_analysis_esil_trace_new(core->analysis->esil);
core->analysis->rzil->trace = rz_analysis_rzil_trace_new(core->analysis, core->analysis->rzil);
rz_config_hold_i(hc, "esil.romem", "dbg.trace",
"esil.nonull", "dbg.follow", NULL);
@ -41,16 +40,6 @@ static void analysis_emul_restore(RzCore *core, RzConfigHold *hc, RzDebugTrace *
rz_config_hold_free(hc);
rz_debug_trace_free(core->dbg->trace);
rz_analysis_esil_trace_free(core->analysis->esil->trace);
if (!core->analysis->rzil) {
// not enable rzil or be freed ?
if (core->analysis->cur->rzil_init) {
// enable but be freed ??
rz_warn_if_reached();
}
} else {
rz_analysis_rzil_trace_free(core->analysis->rzil->trace);
core->analysis->rzil->trace = rt;
}
core->analysis->esil->trace = et;
core->dbg->trace = dt;
}

View file

@ -411,10 +411,9 @@ RZ_IPI void rz_core_analysis_esil_default(RzCore *core) {
rz_core_seek(core, at, true);
}
RZ_IPI void rz_core_analysis_rzil_reinit(RzCore *core) {
rz_analysis_rzil_cleanup(core->analysis);
rz_analysis_rzil_setup(core->analysis);
if (core->analysis->rzil) {
RZ_IPI void rz_core_analysis_il_reinit(RzCore *core) {
rz_analysis_il_vm_setup(core->analysis);
if (core->analysis->il_vm) {
// initialize the program counter with the current offset
rz_reg_set_value_by_role(core->analysis->reg, RZ_REG_NAME_PC, core->offset);
rz_core_reg_update_flags(core);
@ -429,23 +428,23 @@ RZ_IPI void rz_core_analysis_rzil_reinit(RzCore *core) {
* The type of the variable is handled dynamically.
* This is intended for setting from user input only.
*/
RZ_IPI bool rz_core_analysis_rzil_vm_set(RzCore *core, const char *var_name, ut64 value) {
RZ_IPI bool rz_core_analysis_il_vm_set(RzCore *core, const char *var_name, ut64 value) {
rz_return_val_if_fail(core && core->analysis && var_name, false);
RzAnalysisRzil *rzil = core->analysis->rzil;
if (!rzil || !rzil->vm) {
RzAnalysisILVM *vm = core->analysis->il_vm;
if (!vm) {
RZ_LOG_ERROR("RzIL: Run 'aezi' first to initialize the VM\n");
return false;
}
if (!strcmp(var_name, "PC")) {
RzBitVector *bv = rz_bv_new_from_ut64(rzil->vm->pc->len, value);
rz_bv_free(rzil->vm->pc);
rzil->vm->pc = bv;
RzBitVector *bv = rz_bv_new_from_ut64(vm->vm->pc->len, value);
rz_bv_free(vm->vm->pc);
vm->vm->pc = bv;
return true;
}
RzILVar *var = rz_il_vm_get_var(rzil->vm, RZ_IL_VAR_KIND_GLOBAL, var_name);
RzILVar *var = rz_il_vm_get_var(vm->vm, RZ_IL_VAR_KIND_GLOBAL, var_name);
if (!var) {
return false;
}
@ -459,7 +458,7 @@ RZ_IPI bool rz_core_analysis_rzil_vm_set(RzCore *core, const char *var_name, ut6
break;
}
if (val) {
rz_il_vm_set_global_var(rzil->vm, var_name, val);
rz_il_vm_set_global_var(vm->vm, var_name, val);
}
return true;
}
@ -509,9 +508,9 @@ static void rzil_print_register_bitv(RzBitVector *number, ILPrint *p) {
free(hex);
}
RZ_IPI void rz_core_analysis_rzil_vm_status(RzCore *core, const char *var_name, RzOutputMode mode) {
RzAnalysisRzil *rzil = core->analysis->rzil;
if (!rzil || !rzil->vm) {
RZ_IPI void rz_core_analysis_il_vm_status(RzCore *core, const char *var_name, RzOutputMode mode) {
RzAnalysisILVM *vm = core->analysis->il_vm;
if (!vm) {
RZ_LOG_ERROR("RzIL: Run 'aezi' first to initialize the VM\n");
return;
}
@ -537,10 +536,10 @@ RZ_IPI void rz_core_analysis_rzil_vm_status(RzCore *core, const char *var_name,
if (!var_name || !strcmp(var_name, "PC")) {
p.name = "PC";
rzil_print_register_bitv(rzil->vm->pc, &p);
rzil_print_register_bitv(vm->vm->pc, &p);
}
RzPVector *global_vars = rz_il_vm_get_all_vars(rzil->vm, RZ_IL_VAR_KIND_GLOBAL);
RzPVector *global_vars = rz_il_vm_get_all_vars(vm->vm, RZ_IL_VAR_KIND_GLOBAL);
if (global_vars) {
void **it;
rz_pvector_foreach (global_vars, it) {
@ -549,7 +548,7 @@ RZ_IPI void rz_core_analysis_rzil_vm_status(RzCore *core, const char *var_name,
continue;
}
p.name = var->name;
RzILVal *val = rz_il_vm_get_var_value(rzil->vm, RZ_IL_VAR_KIND_GLOBAL, var->name);
RzILVal *val = rz_il_vm_get_var_value(vm->vm, RZ_IL_VAR_KIND_GLOBAL, var->name);
if (!val) {
continue;
}
@ -608,65 +607,41 @@ RZ_IPI void rz_core_analysis_rzil_vm_status(RzCore *core, const char *var_name,
* Perform a single step at the PC given by analysis->reg in RzIL
* \return false if an error occured (e.g. invalid op)
*/
RZ_IPI bool rz_core_rzil_step(RzCore *core) {
if (!core->analysis || !core->analysis->rzil) {
RZ_IPI bool rz_core_il_step(RzCore *core) {
if (!core->analysis || !core->analysis->il_vm) {
RZ_LOG_ERROR("RzIL: Run 'aezi' first to initialize the VM\n");
return false;
}
RzAnalysis *analysis = core->analysis;
RzAnalysisRzil *rzil = analysis->rzil;
RzILVM *vm = rzil->vm;
RzAnalysisPlugin *cur = analysis->cur;
RzAnalysisOp op = { 0 };
if (!cur) {
// No analysis plugin
return false;
}
rz_il_vm_sync_from_reg(vm, analysis->reg);
ut64 addr = rz_bv_to_ut64(vm->pc);
// try load from vm
// fetch and parse if no opcode
ut8 code[32];
// analysis current data to trigger rzil_set_op_code
(void)rz_io_read_at_mapped(core->io, addr, code, sizeof(code));
int r = rz_analysis_op(analysis, &op, addr, code, sizeof(code), RZ_ANALYSIS_OP_MASK_ESIL | RZ_ANALYSIS_OP_MASK_HINT);
RzILOpEffect *ilop = r < 0 ? NULL : op.il_op;
bool succ = false;
if (ilop) {
succ = rz_il_vm_step(vm, ilop, addr + (op.size > 0 ? op.size : 1));
if (!succ) {
RZ_LOG_ERROR("RzIL: stepping failed.\n");
}
rz_il_vm_sync_to_reg(vm, analysis->reg);
RzAnalysisILStepResult r = rz_analysis_il_vm_step(core->analysis, core->analysis->il_vm, core->analysis->reg);
switch (r) {
case RZ_ANALYSIS_IL_STEP_RESULT_SUCCESS:
rz_core_reg_update_flags(core);
} else {
RZ_LOG_ERROR("RzIL: invalid instruction or lifting not implemented at address 0x%08" PFMT64x "\n", addr);
return true;
case RZ_ANALYSIS_IL_STEP_INVALID_OP:
RZ_LOG_ERROR("RzIL: invalid instruction or lifting not implemented at address 0x%08" PFMT64x "\n",
rz_reg_get_value_by_role(core->analysis->reg, RZ_REG_NAME_PC));
break;
default:
RZ_LOG_ERROR("RzIL: stepping failed.\n");
break;
}
rz_analysis_op_fini(&op);
return succ;
return false;
}
/**
* Perform a single step at the PC given by analysis->reg in RzIL and print any events that happened
* \return false if an error occured (e.g. invalid op)
*/
RZ_IPI bool rz_core_analysis_rzil_step_with_events(RzCore *core, PJ *pj) {
if (!rz_core_rzil_step(core)) {
RZ_IPI bool rz_core_analysis_il_step_with_events(RzCore *core, PJ *pj) {
if (!rz_core_il_step(core)) {
return false;
}
if (!core->analysis || !core->analysis->rzil || !core->analysis->rzil->vm) {
if (!core->analysis || !core->analysis->il_vm) {
return false;
}
RzILVM *vm = core->analysis->rzil->vm;
RzILVM *vm = core->analysis->il_vm->vm;
RzStrBuf *sb = NULL;
RzListIter *it;

View file

@ -7987,22 +7987,22 @@ RZ_IPI RzCmdStatus rz_analysis_function_strings_handler(RzCore *core, int argc,
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_rzil_vm_initialize_handler(RzCore *core, int argc, const char **argv) {
rz_core_analysis_rzil_reinit(core);
RZ_IPI RzCmdStatus rz_il_vm_initialize_handler(RzCore *core, int argc, const char **argv) {
rz_core_analysis_il_reinit(core);
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_rzil_vm_step_handler(RzCore *core, int argc, const char **argv) {
RZ_IPI RzCmdStatus rz_il_vm_step_handler(RzCore *core, int argc, const char **argv) {
ut64 repeat_times = argc == 1 ? 1 : rz_num_math(NULL, argv[1]);
for (ut64 i = 0; i < repeat_times; ++i) {
if (!rz_core_rzil_step(core)) {
if (!rz_core_il_step(core)) {
break;
}
}
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_rzil_vm_step_with_events_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
RZ_IPI RzCmdStatus rz_il_vm_step_with_events_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
ut64 repeat_times = argc == 1 ? 1 : rz_num_math(NULL, argv[1]);
PJ *pj = NULL;
if (mode == RZ_OUTPUT_MODE_JSON) {
@ -8014,7 +8014,7 @@ RZ_IPI RzCmdStatus rz_rzil_vm_step_with_events_handler(RzCore *core, int argc, c
pj_a(pj);
}
for (ut64 i = 0; i < repeat_times; ++i) {
if (!rz_core_analysis_rzil_step_with_events(core, pj)) {
if (!rz_core_analysis_il_step_with_events(core, pj)) {
break;
}
}
@ -8026,15 +8026,14 @@ RZ_IPI RzCmdStatus rz_rzil_vm_step_with_events_handler(RzCore *core, int argc, c
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_rzil_vm_step_until_addr_handler(RzCore *core, int argc, const char **argv) {
RZ_IPI RzCmdStatus rz_il_vm_step_until_addr_handler(RzCore *core, int argc, const char **argv) {
ut64 address = rz_num_math(core->num, argv[1]);
if (!core->analysis->rzil || !core->analysis->rzil->vm) {
if (!core->analysis->il_vm) {
RZ_LOG_ERROR("RzIL: the VM is not initialized.\n");
return RZ_CMD_STATUS_ERROR;
}
RzILVM *vm = core->analysis->rzil->vm;
RzILVM *vm = core->analysis->il_vm->vm;
ut64 pc = rz_bv_to_ut64(vm->pc);
while (pc != address) {
@ -8042,7 +8041,7 @@ RZ_IPI RzCmdStatus rz_rzil_vm_step_until_addr_handler(RzCore *core, int argc, co
rz_cons_printf("CTRL+C was pressed.\n");
break;
}
if (!rz_core_rzil_step(core)) {
if (!rz_core_il_step(core)) {
break;
}
pc = rz_bv_to_ut64(vm->pc);
@ -8050,15 +8049,15 @@ RZ_IPI RzCmdStatus rz_rzil_vm_step_until_addr_handler(RzCore *core, int argc, co
return RZ_CMD_STATUS_OK;
}
RZ_IPI RzCmdStatus rz_rzil_vm_status_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
RZ_IPI RzCmdStatus rz_il_vm_status_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode) {
if (argc == 3) {
ut64 value = rz_num_math(core->num, argv[2]);
if (rz_core_analysis_rzil_vm_set(core, argv[1], value)) {
if (rz_core_analysis_il_vm_set(core, argv[1], value)) {
rz_cons_printf("%s = 0x%" PFMT64x "\n", argv[1], value);
}
} else {
// print variable or all variables
rz_core_analysis_rzil_vm_status(core, argc == 2 ? argv[1] : NULL, mode);
rz_core_analysis_il_vm_status(core, argc == 2 ? argv[1] : NULL, mode);
}
return RZ_CMD_STATUS_OK;
}

View file

@ -493,12 +493,12 @@ commands:
- name: aezi
summary: Initialize the RzIL Virtual Machine at the current offset
type: RZ_CMD_DESC_TYPE_ARGV
cname: rzil_vm_initialize
cname: il_vm_initialize
args: []
- name: aezs
summary: Step N instructions within the RzIL Virtual Machine
type: RZ_CMD_DESC_TYPE_ARGV
cname: rzil_vm_step
cname: il_vm_step
args:
- name: n_times
type: RZ_CMD_ARG_TYPE_NUM
@ -506,7 +506,7 @@ commands:
- name: aezse
summary: Step N instructions within the RzIL VM and output VM changes (read & write)
type: RZ_CMD_DESC_TYPE_ARGV_MODES
cname: rzil_vm_step_with_events
cname: il_vm_step_with_events
modes:
- RZ_OUTPUT_MODE_STANDARD
- RZ_OUTPUT_MODE_JSON
@ -517,13 +517,13 @@ commands:
- name: aezsu
summary: Step until PC equals given address
type: RZ_CMD_DESC_TYPE_ARGV
cname: rzil_vm_step_until_addr
cname: il_vm_step_until_addr
args:
- name: address
type: RZ_CMD_ARG_TYPE_RZNUM
- name: aezv
summary: Print or modify the current status of the RzIL Virtual Machine
cname: rzil_vm_status
cname: il_vm_status
type: RZ_CMD_DESC_TYPE_ARGV_MODES
modes:
- RZ_OUTPUT_MODE_STANDARD

View file

@ -112,10 +112,10 @@ static const RzCmdDescArg analysis_function_import_list_args[2];
static const RzCmdDescArg analysis_function_opcode_stat_args[2];
static const RzCmdDescArg analysis_function_all_opcode_stat_args[2];
static const RzCmdDescArg analysis_function_rename_args[2];
static const RzCmdDescArg rzil_vm_step_args[2];
static const RzCmdDescArg rzil_vm_step_with_events_args[2];
static const RzCmdDescArg rzil_vm_step_until_addr_args[2];
static const RzCmdDescArg rzil_vm_status_args[3];
static const RzCmdDescArg il_vm_step_args[2];
static const RzCmdDescArg il_vm_step_with_events_args[2];
static const RzCmdDescArg il_vm_step_until_addr_args[2];
static const RzCmdDescArg il_vm_status_args[3];
static const RzCmdDescArg analysis_regs_args[2];
static const RzCmdDescArg analysis_regs_columns_args[2];
static const RzCmdDescArg analysis_regs_references_args[2];
@ -1906,15 +1906,15 @@ static const RzCmdDescHelp analysis_function_strings_help = {
static const RzCmdDescHelp aez_help = {
.summary = "RzIL Emulation",
};
static const RzCmdDescArg rzil_vm_initialize_args[] = {
static const RzCmdDescArg il_vm_initialize_args[] = {
{ 0 },
};
static const RzCmdDescHelp rzil_vm_initialize_help = {
static const RzCmdDescHelp il_vm_initialize_help = {
.summary = "Initialize the RzIL Virtual Machine at the current offset",
.args = rzil_vm_initialize_args,
.args = il_vm_initialize_args,
};
static const RzCmdDescArg rzil_vm_step_args[] = {
static const RzCmdDescArg il_vm_step_args[] = {
{
.name = "n_times",
.type = RZ_CMD_ARG_TYPE_NUM,
@ -1923,12 +1923,12 @@ static const RzCmdDescArg rzil_vm_step_args[] = {
},
{ 0 },
};
static const RzCmdDescHelp rzil_vm_step_help = {
static const RzCmdDescHelp il_vm_step_help = {
.summary = "Step N instructions within the RzIL Virtual Machine",
.args = rzil_vm_step_args,
.args = il_vm_step_args,
};
static const RzCmdDescArg rzil_vm_step_with_events_args[] = {
static const RzCmdDescArg il_vm_step_with_events_args[] = {
{
.name = "n_times",
.type = RZ_CMD_ARG_TYPE_NUM,
@ -1937,12 +1937,12 @@ static const RzCmdDescArg rzil_vm_step_with_events_args[] = {
},
{ 0 },
};
static const RzCmdDescHelp rzil_vm_step_with_events_help = {
static const RzCmdDescHelp il_vm_step_with_events_help = {
.summary = "Step N instructions within the RzIL VM and output VM changes (read & write)",
.args = rzil_vm_step_with_events_args,
.args = il_vm_step_with_events_args,
};
static const RzCmdDescArg rzil_vm_step_until_addr_args[] = {
static const RzCmdDescArg il_vm_step_until_addr_args[] = {
{
.name = "address",
.type = RZ_CMD_ARG_TYPE_RZNUM,
@ -1951,12 +1951,12 @@ static const RzCmdDescArg rzil_vm_step_until_addr_args[] = {
},
{ 0 },
};
static const RzCmdDescHelp rzil_vm_step_until_addr_help = {
static const RzCmdDescHelp il_vm_step_until_addr_help = {
.summary = "Step until PC equals given address",
.args = rzil_vm_step_until_addr_args,
.args = il_vm_step_until_addr_args,
};
static const RzCmdDescArg rzil_vm_status_args[] = {
static const RzCmdDescArg il_vm_status_args[] = {
{
.name = "var_name",
.type = RZ_CMD_ARG_TYPE_STRING,
@ -1972,9 +1972,9 @@ static const RzCmdDescArg rzil_vm_status_args[] = {
},
{ 0 },
};
static const RzCmdDescHelp rzil_vm_status_help = {
static const RzCmdDescHelp il_vm_status_help = {
.summary = "Print or modify the current status of the RzIL Virtual Machine",
.args = rzil_vm_status_args,
.args = il_vm_status_args,
};
static const RzCmdDescDetailEntry ar_Register_space_Filter_detail_entries[] = {
@ -11182,20 +11182,20 @@ RZ_IPI void rzshell_cmddescs_init(RzCore *core) {
RzCmdDesc *aez_cd = rz_cmd_desc_group_new(core->rcmd, cmd_analysis_cd, "aez", NULL, NULL, &aez_help);
rz_warn_if_fail(aez_cd);
RzCmdDesc *rzil_vm_initialize_cd = rz_cmd_desc_argv_new(core->rcmd, aez_cd, "aezi", rz_rzil_vm_initialize_handler, &rzil_vm_initialize_help);
rz_warn_if_fail(rzil_vm_initialize_cd);
RzCmdDesc *il_vm_initialize_cd = rz_cmd_desc_argv_new(core->rcmd, aez_cd, "aezi", rz_il_vm_initialize_handler, &il_vm_initialize_help);
rz_warn_if_fail(il_vm_initialize_cd);
RzCmdDesc *rzil_vm_step_cd = rz_cmd_desc_argv_new(core->rcmd, aez_cd, "aezs", rz_rzil_vm_step_handler, &rzil_vm_step_help);
rz_warn_if_fail(rzil_vm_step_cd);
RzCmdDesc *il_vm_step_cd = rz_cmd_desc_argv_new(core->rcmd, aez_cd, "aezs", rz_il_vm_step_handler, &il_vm_step_help);
rz_warn_if_fail(il_vm_step_cd);
RzCmdDesc *rzil_vm_step_with_events_cd = rz_cmd_desc_argv_modes_new(core->rcmd, aez_cd, "aezse", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_rzil_vm_step_with_events_handler, &rzil_vm_step_with_events_help);
rz_warn_if_fail(rzil_vm_step_with_events_cd);
RzCmdDesc *il_vm_step_with_events_cd = rz_cmd_desc_argv_modes_new(core->rcmd, aez_cd, "aezse", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_JSON, rz_il_vm_step_with_events_handler, &il_vm_step_with_events_help);
rz_warn_if_fail(il_vm_step_with_events_cd);
RzCmdDesc *rzil_vm_step_until_addr_cd = rz_cmd_desc_argv_new(core->rcmd, aez_cd, "aezsu", rz_rzil_vm_step_until_addr_handler, &rzil_vm_step_until_addr_help);
rz_warn_if_fail(rzil_vm_step_until_addr_cd);
RzCmdDesc *il_vm_step_until_addr_cd = rz_cmd_desc_argv_new(core->rcmd, aez_cd, "aezsu", rz_il_vm_step_until_addr_handler, &il_vm_step_until_addr_help);
rz_warn_if_fail(il_vm_step_until_addr_cd);
RzCmdDesc *rzil_vm_status_cd = rz_cmd_desc_argv_modes_new(core->rcmd, aez_cd, "aezv", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_TABLE | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET, rz_rzil_vm_status_handler, &rzil_vm_status_help);
rz_warn_if_fail(rzil_vm_status_cd);
RzCmdDesc *il_vm_status_cd = rz_cmd_desc_argv_modes_new(core->rcmd, aez_cd, "aezv", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_TABLE | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET, rz_il_vm_status_handler, &il_vm_status_help);
rz_warn_if_fail(il_vm_status_cd);
RzCmdDesc *ar_cd = rz_cmd_desc_group_state_new(core->rcmd, cmd_analysis_cd, "ar", RZ_OUTPUT_MODE_STANDARD | RZ_OUTPUT_MODE_RIZIN | RZ_OUTPUT_MODE_TABLE | RZ_OUTPUT_MODE_JSON | RZ_OUTPUT_MODE_QUIET, rz_analysis_regs_handler, &analysis_regs_help, &ar_help);
rz_warn_if_fail(ar_cd);

View file

@ -111,11 +111,11 @@ RZ_IPI RzCmdStatus rz_analysis_function_rename_handler(RzCore *core, int argc, c
RZ_IPI RzCmdStatus rz_analysis_function_autoname_handler(RzCore *core, int argc, const char **argv);
RZ_IPI RzCmdStatus rz_analysis_function_strings_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
RZ_IPI int rz_cmd_analysis_fcn(void *data, const char *input);
RZ_IPI RzCmdStatus rz_rzil_vm_initialize_handler(RzCore *core, int argc, const char **argv);
RZ_IPI RzCmdStatus rz_rzil_vm_step_handler(RzCore *core, int argc, const char **argv);
RZ_IPI RzCmdStatus rz_rzil_vm_step_with_events_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode);
RZ_IPI RzCmdStatus rz_rzil_vm_step_until_addr_handler(RzCore *core, int argc, const char **argv);
RZ_IPI RzCmdStatus rz_rzil_vm_status_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode);
RZ_IPI RzCmdStatus rz_il_vm_initialize_handler(RzCore *core, int argc, const char **argv);
RZ_IPI RzCmdStatus rz_il_vm_step_handler(RzCore *core, int argc, const char **argv);
RZ_IPI RzCmdStatus rz_il_vm_step_with_events_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode);
RZ_IPI RzCmdStatus rz_il_vm_step_until_addr_handler(RzCore *core, int argc, const char **argv);
RZ_IPI RzCmdStatus rz_il_vm_status_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode);
RZ_IPI RzCmdStatus rz_analysis_regs_handler(RzCore *core, int argc, const char **argv, RzCmdStateOutput *state);
RZ_IPI RzCmdStatus rz_analysis_regs_columns_handler(RzCore *core, int argc, const char **argv);
RZ_IPI RzCmdStatus rz_analysis_regs_references_handler(RzCore *core, int argc, const char **argv, RzOutputMode mode);

View file

@ -29,11 +29,11 @@ RZ_IPI void rz_core_analysis_esil_emulate(RzCore *core, ut64 addr, ut64 until_ad
RZ_IPI void rz_core_analysis_esil_emulate_bb(RzCore *core);
RZ_IPI void rz_core_analysis_esil_default(RzCore *core);
RZ_IPI void rz_core_analysis_rzil_reinit(RzCore *core);
RZ_IPI bool rz_core_analysis_rzil_vm_set(RzCore *core, const char *var_name, ut64 value);
RZ_IPI void rz_core_analysis_rzil_vm_status(RzCore *core, const char *varname, RzOutputMode mode);
RZ_IPI bool rz_core_rzil_step(RzCore *core);
RZ_IPI bool rz_core_analysis_rzil_step_with_events(RzCore *core, PJ *pj);
RZ_IPI void rz_core_analysis_il_reinit(RzCore *core);
RZ_IPI bool rz_core_analysis_il_vm_set(RzCore *core, const char *var_name, ut64 value);
RZ_IPI void rz_core_analysis_il_vm_status(RzCore *core, const char *varname, RzOutputMode mode);
RZ_IPI bool rz_core_il_step(RzCore *core);
RZ_IPI bool rz_core_analysis_il_step_with_events(RzCore *core, PJ *pj);
RZ_IPI bool rz_core_analysis_var_rename(RzCore *core, const char *name, const char *newname);
RZ_IPI char *rz_core_analysis_function_signature(RzCore *core, RzOutputMode mode, char *fcn_name);

View file

@ -184,12 +184,6 @@ RZ_API void rz_debug_trace_op(RzDebug *dbg, RzAnalysisOp *op) {
eprintf("Run aeim to get dbg->analysis->esil initialized\n");
}
}
if (dbg->analysis->rzil) {
rz_analysis_rzil_collect_info(dbg->analysis, dbg->analysis->rzil, op, false);
} else {
RZ_LOG_ERROR("Run aeim to get RzIL initialized\n");
}
}
if (oldpc != UT64_MAX) {
rz_debug_trace_add(dbg, oldpc, op->size); // XXX review what this line really do

View file

@ -3,12 +3,6 @@
#include <rz_il/definitions/label.h>
/**
* Create an effect label
* \param name label name
* \param type Label type
* \return Pointer to label
*/
RZ_API RzILEffectLabel *rz_il_effect_label_new(RZ_NONNULL const char *name, RzILEffectLabelType type) {
RzILEffectLabel *lbl = RZ_NEW0(RzILEffectLabel);
if (!lbl) {
@ -18,3 +12,29 @@ RZ_API RzILEffectLabel *rz_il_effect_label_new(RZ_NONNULL const char *name, RzIL
lbl->type = type;
return lbl;
}
RZ_API void rz_il_effect_label_free(RzILEffectLabel *lbl) {
if (!lbl) {
return;
}
free(lbl->label_id);
if (lbl->type == EFFECT_LABEL_ADDR) {
rz_bv_free(lbl->addr);
}
free(lbl);
return;
}
RZ_API RzILEffectLabel *rz_il_effect_label_dup(RZ_NONNULL RzILEffectLabel *lbl) {
rz_return_val_if_fail(lbl, NULL);
RzILEffectLabel *r = rz_il_effect_label_new(lbl->label_id, lbl->type);
if (!r) {
return NULL;
}
if (lbl->type == EFFECT_LABEL_ADDR) {
r->addr = rz_bv_dup(lbl->addr);
} else {
r->hook = lbl->hook;
}
return r;
}

View file

@ -197,11 +197,10 @@ RZ_API void rz_il_reg_binding_free(RzILRegBinding *rb) {
/**
* Setup variables to bind against registers
* \p rb the binding for which to create variables, ownership is transferred to the vm.
* \p rb the binding for which to create variables
*/
RZ_API void rz_il_vm_setup_reg_binding(RZ_NONNULL RzILVM *vm, RZ_NONNULL RZ_OWN RzILRegBinding *rb) {
rz_return_if_fail(vm && rb && !vm->reg_binding);
vm->reg_binding = rb;
RZ_API void rz_il_vm_setup_reg_binding(RZ_NONNULL RzILVM *vm, RZ_NONNULL RZ_BORROW RzILRegBinding *rb) {
rz_return_if_fail(vm && rb);
for (size_t i = 0; i < rb->regs_count; i++) {
rz_il_vm_create_global_var(vm, rb->regs[i].name,
rb->regs[i].size == 1 ? rz_il_sort_pure_bool() : rz_il_sort_pure_bv(rb->regs[i].size));
@ -219,8 +218,8 @@ RZ_API void rz_il_vm_setup_reg_binding(RZ_NONNULL RzILVM *vm, RZ_NONNULL RZ_OWN
*
* \return whether the sync was cleanly applied without errors or adjustments
*/
RZ_API bool rz_il_vm_sync_to_reg(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzReg *reg) {
rz_return_val_if_fail(vm && reg, false);
RZ_API bool rz_il_vm_sync_to_reg(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILRegBinding *rb, RZ_NONNULL RzReg *reg) {
rz_return_val_if_fail(vm && rb && reg, false);
bool perfect = true;
const char *pc = rz_reg_get_name(reg, RZ_REG_NAME_PC);
if (pc) {
@ -241,10 +240,6 @@ RZ_API bool rz_il_vm_sync_to_reg(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzReg *reg) {
} else {
perfect = false;
}
RzILRegBinding *rb = vm->reg_binding;
if (!vm->reg_binding) {
return false;
}
for (size_t i = 0; i < rb->regs_count; i++) {
RzILRegBindingItem *item = &rb->regs[i];
RzRegItem *ri = rz_reg_get(reg, item->name, RZ_REG_TYPE_ANY);
@ -298,8 +293,8 @@ RZ_API bool rz_il_vm_sync_to_reg(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzReg *reg) {
* Set the values of all variables in \p vm that are bound to registers and PC to the respective contents from \p reg.
* Contents of variables that are not bound to a register are left unchanged.
*/
RZ_API void rz_il_vm_sync_from_reg(RzILVM *vm, RZ_NONNULL RzReg *reg) {
rz_return_if_fail(vm && reg);
RZ_API void rz_il_vm_sync_from_reg(RzILVM *vm, RZ_NONNULL RzILRegBinding *rb, RZ_NONNULL RzReg *reg) {
rz_return_if_fail(vm && rb && reg);
const char *pc = rz_reg_get_name(reg, RZ_REG_NAME_PC);
if (pc) {
RzRegItem *ri = rz_reg_get(reg, pc, RZ_REG_TYPE_ANY);
@ -312,10 +307,6 @@ RZ_API void rz_il_vm_sync_from_reg(RzILVM *vm, RZ_NONNULL RzReg *reg) {
}
}
}
RzILRegBinding *rb = vm->reg_binding;
if (!vm->reg_binding) {
return;
}
for (size_t i = 0; i < rb->regs_count; i++) {
RzILRegBindingItem *item = &rb->regs[i];
RzILVar *var = rz_il_vm_get_var(vm, RZ_IL_VAR_KIND_GLOBAL, item->name);

View file

@ -15,14 +15,7 @@ extern RZ_IPI RzILOpEffectHandler rz_il_op_handler_effect_table_default[RZ_IL_OP
static void free_label_kv(HtPPKv *kv) {
free(kv->key);
RzILEffectLabel *lbl = kv->value;
if (lbl->type == EFFECT_LABEL_HOOK || lbl->type == EFFECT_LABEL_SYSCALL) {
lbl->addr = NULL;
}
rz_bv_free(lbl->addr);
free(lbl->label_id);
free(lbl);
rz_il_effect_label_free(kv->value);
}
/**
@ -102,7 +95,6 @@ RZ_API void rz_il_vm_fini(RzILVM *vm) {
rz_il_var_set_fini(&vm->local_vars);
rz_il_var_set_fini(&vm->local_pure_vars);
rz_il_reg_binding_free(vm->reg_binding);
rz_pvector_fini(&vm->vm_memory);
ht_pp_free(vm->vm_global_label_table);
@ -301,6 +293,11 @@ RZ_API RZ_BORROW RzILEffectLabel *rz_il_vm_find_label_by_name(RZ_NONNULL RzILVM
return ht_pp_find(vm->vm_global_label_table, lbl_name, NULL);
}
RZ_API void rz_il_vm_add_label(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILEffectLabel *label) {
rz_return_if_fail(vm && label);
ht_pp_update(vm->vm_global_label_table, label->label_id, label);
}
/**
* Create a label in VM
* \param vm RzILVM, pointer to VM
@ -310,11 +307,9 @@ RZ_API RZ_BORROW RzILEffectLabel *rz_il_vm_find_label_by_name(RZ_NONNULL RzILVM
*/
RZ_API RZ_BORROW RzILEffectLabel *rz_il_vm_create_label(RZ_NONNULL RzILVM *vm, RZ_NONNULL const char *name, RZ_NONNULL RZ_BORROW RzBitVector *addr) {
rz_return_val_if_fail(vm && name && addr, NULL);
HtPP *lbl_table = vm->vm_global_label_table;
RzILEffectLabel *lbl = rz_il_effect_label_new(name, EFFECT_LABEL_ADDR);
lbl->addr = rz_bv_dup(addr);
ht_pp_insert(lbl_table, name, lbl);
rz_il_vm_add_label(vm, lbl);
return lbl;
}
@ -326,12 +321,9 @@ RZ_API RZ_BORROW RzILEffectLabel *rz_il_vm_create_label(RZ_NONNULL RzILVM *vm, R
*/
RZ_API RZ_BORROW RzILEffectLabel *rz_il_vm_create_label_lazy(RZ_NONNULL RzILVM *vm, RZ_NONNULL const char *name) {
rz_return_val_if_fail(vm && name, NULL);
HtPP *lbl_table = vm->vm_global_label_table;
RzILEffectLabel *lbl = rz_il_effect_label_new(name, EFFECT_LABEL_ADDR);
lbl->addr = NULL;
ht_pp_insert(lbl_table, name, lbl);
rz_il_vm_add_label(vm, lbl);
return lbl;
}
@ -348,6 +340,5 @@ RZ_API RZ_BORROW RzILEffectLabel *rz_il_vm_update_label(RZ_NONNULL RzILVM *vm, R
rz_bv_free(lbl->addr);
}
lbl->addr = rz_bv_dup(addr);
return lbl;
}

View file

@ -550,6 +550,8 @@ typedef struct rz_analysis_hint_cb_t {
void (*on_bits)(struct rz_analysis_t *a, ut64 addr, int bits, bool set);
} RHintCb;
typedef struct rz_analysis_il_vm_t RzAnalysisILVM;
typedef struct rz_analysis_t {
char *cpu; // analysis.cpu
char *os; // asm.os
@ -582,7 +584,7 @@ typedef struct rz_analysis_t {
int esil_goto_limit; // esil.gotolimit
int pcalign; // asm.pcalign
struct rz_analysis_esil_t *esil;
struct rz_analysis_rzil_t *rzil;
RzAnalysisILVM *il_vm; ///< user-faced VM, NEVER use this for any analysis passes!
struct rz_analysis_plugin_t *cur;
RzAnalysisRange *limit; // analysis.from, analysis.to
RzList *plugins;
@ -980,7 +982,6 @@ typedef struct rz_analysis_ref_char {
#define ESIL_INTERNAL_PREFIX '$'
#define ESIL_STACK_NAME "esil.ram"
#define ANALYSIS_ESIL struct rz_analysis_esil_t
#define ANALYSIS_RZ_IL struct rz_analysis_rzil_t
typedef struct rz_analysis_esil_source_t {
ut32 id;
@ -1104,40 +1105,67 @@ typedef RzAnalysisEsilMemChange RzAnalysisRzilMemChange;
/* Alias esil strace */
typedef RzAnalysisEsilTrace RzAnalysisRzilTrace;
typedef struct rz_analysis_rzil_callbacks_t {
void *user;
/* callbacks */
int (*hook_flag_read)(ANALYSIS_RZ_IL *rzil, const char *flag, ut64 *num, RzAnalysis *analysis);
int (*hook_command)(ANALYSIS_RZ_IL *rzil, const char *op, RzAnalysis *analysis);
int (*hook_mem_read)(ANALYSIS_RZ_IL *rzil, ut64 addr, ut8 *buf, int len, RzAnalysis *analysis);
int (*mem_read)(ANALYSIS_RZ_IL *rzil, ut64 addr, ut8 *buf, int len, RzAnalysis *analysis);
int (*hook_mem_write)(ANALYSIS_RZ_IL *rzil, ut64 addr, const ut8 *buf, int len, RzAnalysis *analysis);
int (*mem_write)(ANALYSIS_RZ_IL *rzil, ut64 addr, const ut8 *buf, int len, RzAnalysis *analysis);
int (*hook_reg_read)(ANALYSIS_RZ_IL *rzil, const char *name, ut64 *res, int *size, RzAnalysis *analysis);
int (*reg_read)(ANALYSIS_RZ_IL *rzil, const char *name, ut64 *res, int *size, RzAnalysis *analysis);
int (*hook_reg_write)(ANALYSIS_RZ_IL *rzil, const char *name, ut64 *val, RzAnalysis *analysis);
int (*reg_write)(ANALYSIS_RZ_IL *rzil, const char *name, ut64 val, RzAnalysis *analysis);
} RzAnalysisRzilCallbacks;
/**
* \brief Description of the contents of a single IL variable
*/
typedef struct rz_analysis_il_init_state_var_t {
RZ_NONNULL const char *name;
RZ_NONNULL RzILVal *val;
} RzAnalysisILInitStateVar;
typedef struct rz_analysis_rzil_t {
RzILVM *vm;
RzBuffer *io_buf;
RzAnalysisRzilTrace *trace;
/**
* \brief Description of an initial state of an RzAnalysisILVM
*
* This may be used by an analysis plugin to communicate how to initialize
* variables/registers for a clean vm.
* Everything unspecified by this may be initialized to anything (for example
* whatever contents the RzReg currently has).
*/
typedef struct rz_analysis_il_init_state_t {
RzVector /* <RzAnalysisILInitStateVar> */ vars; ///< Contents of global variables
} RzAnalysisILInitState;
RzAnalysisRzilCallbacks cb;
Sdb *stats;
/**
* \brief Description of the global context of an RzAnalysisILVM
*
* This defines all information needed to initialize an IL vm in order to run
* in a declarative way, in particular:
*
* * Size of the program counter: given explicitly in `pc_size`
* * Endian: given explicitly in `big_endian`
* * Memories: currently always one memory with index 0 bound against IO, with key size given by `mem_key_size` and value size of 8
* * Registers: currently implicit, derived from the register profile with `rz_il_reg_binding_derive()`
* * Labels: given explicitly in `labels`
* * Initial State of Variables: optionally given in `init_state`
*/
typedef struct rz_analysis_il_config_t {
ut32 pc_size; ///< size of the program counter in bits
bool big_endian;
ut32 mem_key_size; ///< address size for memory 0, bound against IO
RzPVector /* <RzILEffectLabel> */ labels; ///< global labels, primarily for syscall/hook callbacks
RZ_NULLABLE RzAnalysisILInitState *init_state; ///< optional, initial contents for variables/registers, etc.
// more information might go in here, for example additional memories, register bindings, etc.
} RzAnalysisILConfig;
// TODO : some variables
// may not be used in new rz il
ut64 stack_addr;
ut32 stack_size;
/**
* \brief High-level RzIL vm to emulate disassembled code
*
* This builds upon the low-level `RzILVM`, which by itself does not know about
* IO and lifting, and enables emulation of instructions obtained by disassembling
* and lifting with analysis plugins.
*/
struct rz_analysis_il_vm_t {
RZ_NONNULL RzILVM *vm; ///< low-level vm to execute IL code
RZ_NONNULL RzBuffer *io_buf; ///< buffer to use for memory 0 (io)
RZ_NONNULL RzILRegBinding *reg_binding; ///< specifies which (global) variables are bound to registers
} /* RzAnalysisILVM */;
ut64 pc_addr;
int verbose;
void *user; // store data for architecture specified plugin
bool inited;
} RzAnalysisRzil;
typedef enum {
RZ_ANALYSIS_IL_STEP_RESULT_SUCCESS,
RZ_ANALYSIS_IL_STEP_RESULT_NOT_SET_UP,
RZ_ANALYSIS_IL_STEP_IL_RUNTIME_ERROR,
RZ_ANALYSIS_IL_STEP_INVALID_OP
} RzAnalysisILStepResult;
#undef ESIL
@ -1199,10 +1227,11 @@ typedef int (*RzAnalysisDiffFcnCallback)(RzAnalysis *analysis, RzList *fcns, RzL
typedef int (*RzAnalysisDiffEvalCallback)(RzAnalysis *analysis);
typedef int (*RzAnalysisEsilCB)(RzAnalysisEsil *esil);
typedef bool (*RzAnalysisRzilCB)(RzAnalysis *analysis);
typedef int (*RzAnalysisEsilLoopCB)(RzAnalysisEsil *esil, RzAnalysisOp *op);
typedef int (*RzAnalysisEsilTrapCB)(RzAnalysisEsil *esil, int trap_type, int trap_code);
typedef RzAnalysisILConfig *(*RzAnalysisILConfigCB)(RzAnalysis *analysis);
typedef struct rz_analysis_plugin_t {
const char *name;
const char *desc;
@ -1240,8 +1269,7 @@ typedef struct rz_analysis_plugin_t {
RzAnalysisEsilLoopCB esil_post_loop; // cycle-counting, firing interrupts, ...
RzAnalysisEsilTrapCB esil_trap; // traps / exceptions
RzAnalysisEsilCB esil_fini; // deinitialize
RzAnalysisRzilCB rzil_init;
RzAnalysisRzilCB rzil_fini;
RzAnalysisILConfigCB il_config; ///< return an IL config to execute lifted code of the given analysis' arch/cpu/bits
} RzAnalysisPlugin;
@ -1568,20 +1596,27 @@ RZ_API void rz_analysis_esil_trace_list(RzAnalysisEsil *esil);
RZ_API void rz_analysis_esil_trace_show(RzAnalysisEsil *esil, int idx);
RZ_API void rz_analysis_esil_trace_restore(RzAnalysisEsil *esil, int idx);
/* rzil : stats and trace */
RZ_API RZ_OWN RzAnalysisRzil *rz_analysis_rzil_new();
RZ_API void rz_analysis_rzil_free(RZ_NULLABLE RzAnalysisRzil *rzil);
RZ_API bool rz_analysis_rzil_set_pc(RzAnalysisRzil *rzil, ut64 addr);
RZ_API bool rz_analysis_rzil_setup(RzAnalysis *analysis);
RZ_API void rz_analysis_rzil_cleanup(RzAnalysis *analysis);
RZ_API void rz_analysis_set_rzil_op(RzAnalysisRzil *rzil, ut64 addr, RzPVector *oplist);
RZ_API void rz_analysis_rzil_record_stats(RzAnalysis *analysis, RzAnalysisRzil *rzil, RzAnalysisLiftedILOp op);
/* RzIL */
RZ_API RzAnalysisILInitState *rz_analysis_il_init_state_new();
RZ_API void rz_analysis_il_init_state_free(RzAnalysisILInitState *state);
RZ_API void rz_analysis_il_init_state_set_var(RZ_NONNULL RzAnalysisILInitState *state,
RZ_NONNULL const char *name, RZ_NONNULL RZ_OWN RzILVal *val);
RZ_API RZ_OWN RzAnalysisILConfig *rz_analysis_il_config_new(ut32 pc_size, bool big_endian, ut32 mem_key_size);
RZ_API void rz_analysis_il_config_free(RzAnalysisILConfig *cfg);
RZ_API void rz_analysis_il_config_add_label(RZ_NONNULL RzAnalysisILConfig *cfg, RZ_NONNULL RZ_OWN RzILEffectLabel *label);
RZ_API RZ_OWN RzAnalysisILVM *rz_analysis_il_vm_new(RzAnalysis *a, RZ_NULLABLE RzReg *init_state_reg);
RZ_API void rz_analysis_il_vm_free(RZ_NULLABLE RzAnalysisILVM *vm);
RZ_API void rz_analysis_il_vm_sync_from_reg(RzAnalysisILVM *vm, RZ_NONNULL RzReg *reg);
RZ_API bool rz_analysis_il_vm_sync_to_reg(RzAnalysisILVM *vm, RZ_NONNULL RzReg *reg);
RZ_API RzAnalysisILStepResult rz_analysis_il_vm_step(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisILVM *vm, RZ_NULLABLE RzReg *reg);
RZ_API bool rz_analysis_il_vm_setup(RzAnalysis *analysis);
RZ_API void rz_analysis_il_vm_cleanup(RzAnalysis *analysis);
/* trace */
RZ_API RzAnalysisRzilTrace *rz_analysis_rzil_trace_new(RzAnalysis *analysis, RzAnalysisRzil *rzil);
RZ_API RzAnalysisRzilTrace *rz_analysis_rzil_trace_new(RzAnalysis *analysis, RzAnalysisILVM *rzil);
RZ_API void rz_analysis_rzil_trace_free(RzAnalysisRzilTrace *trace);
RZ_API void rz_analysis_rzil_trace_op(RzAnalysis *analysis, RzAnalysisRzil *rzil, RzAnalysisLiftedILOp op);
RZ_API void rz_analysis_rzil_collect_info(RzAnalysis *analysis, RzAnalysisRzil *rzil, RzAnalysisOp *op, bool use_new);
RZ_API void rz_analysis_rzil_trace_op(RzAnalysis *analysis, RzAnalysisILVM *rzil, RzAnalysisLiftedILOp op);
RZ_API bool rz_analysis_add_device_peripheral_map(RzBinObject *o, RzAnalysis *analysis);

View file

@ -31,6 +31,8 @@ typedef struct rz_il_effect_label_t {
} RzILEffectLabel;
RZ_API RzILEffectLabel *rz_il_effect_label_new(const char *name, RzILEffectLabelType type);
RZ_API void rz_il_effect_label_free(RzILEffectLabel *lbl);
RZ_API RzILEffectLabel *rz_il_effect_label_dup(RZ_NONNULL RzILEffectLabel *lbl);
#ifdef __cplusplus
}

View file

@ -6,6 +6,10 @@
#include <rz_reg.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct rz_il_reg_binding_item_t {
char *name; ///< name of both the register and the variable that binds to it
ut32 size; ///< number of bits of the register and variable
@ -26,8 +30,12 @@ RZ_API RzILRegBinding *rz_il_reg_binding_derive(RZ_NONNULL RzReg *reg);
RZ_API RzILRegBinding *rz_il_reg_binding_exactly(RZ_NONNULL RzReg *reg, size_t regs_count, RZ_NONNULL RZ_BORROW const char **regs);
RZ_API void rz_il_reg_binding_free(RzILRegBinding *rb);
RZ_API void rz_il_vm_setup_reg_binding(RZ_NONNULL struct rz_il_vm_t *vm, RZ_NONNULL RZ_OWN RzILRegBinding *rb);
RZ_API bool rz_il_vm_sync_to_reg(RZ_NONNULL struct rz_il_vm_t *vm, RZ_NONNULL RzReg *reg);
RZ_API void rz_il_vm_sync_from_reg(RZ_NONNULL struct rz_il_vm_t *vm, RZ_NONNULL RzReg *reg);
RZ_API void rz_il_vm_setup_reg_binding(RZ_NONNULL struct rz_il_vm_t *vm, RZ_NONNULL RZ_BORROW RzILRegBinding *rb);
RZ_API bool rz_il_vm_sync_to_reg(RZ_NONNULL struct rz_il_vm_t *vm, RZ_NONNULL RzILRegBinding *rb, RZ_NONNULL RzReg *reg);
RZ_API void rz_il_vm_sync_from_reg(RZ_NONNULL struct rz_il_vm_t *vm, RZ_NONNULL RzILRegBinding *rb, RZ_NONNULL RzReg *reg);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -32,11 +32,9 @@ typedef bool (*RzILOpEffectHandler)(RzILVM *vm, RzILOpEffect *op);
typedef void (*RzILVmHook)(RzILVM *vm, RzILOpEffect *op);
/**
* \struct rz_il_vm_t
* \brief core theory VM structure
* \brief Low-level VM to execute raw IL code
*/
struct rz_il_vm_t {
RZ_NULLABLE RzILRegBinding *reg_binding; ///< Optional, specifies which (global) variables are bound to registers
RzILVarSet global_vars; ///< All global variables (usually bound to registers)
RzILVarSet local_vars; ///< All local variables, created by local set ops
RzILVarSet local_pure_vars; ///< All local variables, during execution temporarily bound by let, only usable in pure expressions and immutable
@ -75,6 +73,7 @@ RZ_API void rz_il_vm_mem_storew(RzILVM *vm, RzILMemIndex index, RzBitVector *key
// Labels
RZ_API RZ_BORROW RzBitVector *rz_il_hash_find_addr_by_lblname(RZ_NONNULL RzILVM *vm, RZ_NONNULL const char *lbl_name);
RZ_API RZ_BORROW RzILEffectLabel *rz_il_vm_find_label_by_name(RZ_NONNULL RzILVM *vm, RZ_NONNULL const char *lbl_name);
RZ_API void rz_il_vm_add_label(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILEffectLabel *label);
RZ_API RZ_BORROW RzILEffectLabel *rz_il_vm_create_label(RZ_NONNULL RzILVM *vm, RZ_NONNULL const char *name, RZ_NONNULL RZ_BORROW RzBitVector *addr);
RZ_API RZ_BORROW RzILEffectLabel *rz_il_vm_create_label_lazy(RZ_NONNULL RzILVM *vm, RZ_NONNULL const char *name);
RZ_API RZ_BORROW RzILEffectLabel *rz_il_vm_update_label(RZ_NONNULL RzILVM *vm, RZ_NONNULL char *name, RZ_NONNULL RZ_BORROW RzBitVector *addr);

View file

@ -231,18 +231,18 @@ static bool print_and_check_il(RzAsmState *as, RzAnalysisOp *op) {
eprintf("Invalid instruction of lifting not implemented.\n");
return false;
}
rz_analysis_rzil_cleanup(as->analysis);
rz_analysis_rzil_setup(as->analysis);
if (!as->analysis->rzil || !as->analysis->rzil->vm) {
RzAnalysisILVM *vm = rz_analysis_il_vm_new(as->analysis, NULL);
if (!vm) {
eprintf("Failed to initialize IL VM for this architecture.\n");
return false;
}
RzILValidateGlobalContext *ctx = rz_il_validate_global_context_new_from_vm(as->analysis->rzil->vm);
bool ret = true;
RzILValidateGlobalContext *ctx = rz_il_validate_global_context_new_from_vm(vm->vm);
if (!ctx) {
eprintf("Failed to derive context from IL VM.\n");
return false;
ret = false;
goto error_vm;
}
bool ret = true;
RzILOpEffect *il_op = op->il_op;
if (il_op) {
RzStrBuf sb;
@ -262,6 +262,8 @@ static bool print_and_check_il(RzAsmState *as, RzAnalysisOp *op) {
free(report);
}
rz_il_validate_global_context_free(ctx);
error_vm:
rz_analysis_il_vm_free(vm);
return ret;
}

View file

@ -1,5 +1,6 @@
NAME=aezsu: RzIL step until
FILE=bins/bf/hello-ok.bf
ARGS=-eio.cache=1
CMDS=<<EOF
s 0
aezi
@ -99,10 +100,10 @@ aezv ptr 0xc0ffee
aezv
EOF
EXPECT=<<EOF
PC: 0x0000000000000000 ptr: 0x0000000000000000
PC: 0x0000000000000000 ptr: 0x0000000000010000
--
PC = 0x42
PC: 0x0000000000000042 ptr: 0x0000000000000000
PC: 0x0000000000000042 ptr: 0x0000000000010000
--
ptr = 0xc0ffee
PC: 0x0000000000000042 ptr: 0x0000000000c0ffee

View file

@ -1,6 +1,6 @@
NAME=hello world
FILE=bins/bf/hello-ok.bf
ARGS=-b32
ARGS=-b32 -eio.cache=1
CMDS=<<EOF
e asm.arch=bf
e asm.bytes=true
@ -39,7 +39,7 @@ RUN
NAME=loopy hello world
FILE=bins/bf/hello-loops.bf
ARGS=-b32
ARGS=-b32 -eio.cache=1
CMDS=<<EOF
s 0
aezi
@ -52,7 +52,7 @@ RUN
NAME=instructions
FILE=bins/bf/hello-loops.bf
ARGS=-b32
ARGS=-b32 -eio.cache=1
CMDS=<<EOF
e asm.arch=bf
e analysis.arch=bf
@ -112,7 +112,7 @@ RUN
NAME=loopy hello world
FILE=bins/bf/hello-loops.bf
ARGS=-b32
ARGS=-b32 -eio.cache=1
CMDS=<<EOF
s 0
aezi
@ -125,7 +125,7 @@ RUN
NAME=instructions
FILE=bins/bf/hello-loops.bf
ARGS=-b32
ARGS=-b32 -eio.cache=1
CMDS=<<EOF
e asm.arch=bf
e analysis.arch=bf

View file

@ -3,6 +3,7 @@ if get_option('enable_tests')
'bin_vfiles',
'cpu_platform_profiles',
'open_analyse_save_load_project',
'analysis_il',
]
unit_test_env = environment()

View file

@ -0,0 +1,58 @@
// SPDX-FileCopyrightText: 2022 Florian Märkl <info@florianmaerkl.de>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_core.h>
#include "../unit/minunit.h"
/**
* Test running an IL vm with Analysis connection independently of the global user-faced vm
*/
static bool test_analysis_il_vm_step() {
RzCore *core = rz_core_new();
mu_assert_notnull(core, "init core");
RzCoreFile *cf = rz_core_file_open(core, "hex://a9754937", RZ_PERM_RWX, 0);
mu_assert_notnull(cf, "open hex file");
rz_core_bin_load(core, NULL, 0);
rz_config_set(core->config, "asm.arch", "6502");
RzReg *reg = rz_reg_new();
mu_assert_notnull(reg, "create reg");
char *reg_profile = rz_analysis_get_reg_profile(core->analysis);
mu_assert_notnull(reg_profile, "reg profile");
bool succ = rz_reg_set_profile_string(reg, reg_profile);
rz_mem_free(reg_profile);
mu_assert_true(succ, "apply reg profile");
RzAnalysisILVM *vm = rz_analysis_il_vm_new(core->analysis, reg);
mu_assert_notnull(vm, "create analysis vm");
rz_analysis_il_vm_sync_to_reg(vm, reg); // initial sync to get any plugin-specified initialization
// a9 75 lda #0x75
RzAnalysisILStepResult sr = rz_analysis_il_vm_step(core->analysis, vm, reg);
mu_assert_eq(sr, RZ_ANALYSIS_IL_STEP_RESULT_SUCCESS, "il step");
mu_assert_eq(rz_reg_getv(reg, "a"), 0x75, "result in local reg");
mu_assert_eq(rz_reg_get_value_by_role(reg, RZ_REG_NAME_PC), 2, "pc in local reg");
mu_assert_eq(rz_reg_getv(core->analysis->reg, "a"), 0x0, "global reg untouched");
mu_assert_eq(rz_reg_get_value_by_role(core->analysis->reg, RZ_REG_NAME_PC), 0, "global reg untouched");
// 49 37 eor #0x37
// ==> 0x75 ^ 0x37 = 0x42
sr = rz_analysis_il_vm_step(core->analysis, vm, reg);
mu_assert_eq(sr, RZ_ANALYSIS_IL_STEP_RESULT_SUCCESS, "il step");
mu_assert_eq(rz_reg_getv(reg, "a"), 0x42, "result in local reg");
mu_assert_eq(rz_reg_get_value_by_role(reg, RZ_REG_NAME_PC), 4, "pc in local reg");
mu_assert_eq(rz_reg_getv(core->analysis->reg, "a"), 0x0, "global reg untouched");
mu_assert_eq(rz_reg_get_value_by_role(core->analysis->reg, RZ_REG_NAME_PC), 0, "global reg untouched");
rz_reg_free(reg);
rz_analysis_il_vm_free(vm);
rz_core_free(core);
mu_end;
}
bool all_tests() {
mu_run_test(test_analysis_il_vm_step);
return tests_passed != tests_run;
}
mu_main(all_tests)

View file

@ -173,7 +173,7 @@ static bool test_il_vm_sync_to_reg() {
rz_bv_set_from_ut64(vm->pc, 0x10001);
rz_il_vm_sync_to_reg(vm, reg);
rz_il_vm_sync_to_reg(vm, rb, reg);
mu_assert_eq(rz_reg_getv(reg, "r0"), 0x8247abc, "reg from vm");
mu_assert_eq(rz_reg_getv(reg, "r1"), 0xfed134, "reg from vm");
mu_assert_eq(rz_reg_getv(reg, "pc"), 0x10001, "reg from vm");
@ -193,7 +193,7 @@ static bool test_il_vm_sync_to_reg() {
"gpr bf .1 41.0 0\n";
reg = rz_reg_new();
rz_reg_set_profile_string(reg, profile2);
rz_il_vm_sync_to_reg(vm, reg);
rz_il_vm_sync_to_reg(vm, rb, reg);
mu_assert_eq(rz_reg_getv(reg, "r0"), 0x8247abc, "reg from vm");
mu_assert_eq(rz_reg_getv(reg, "r1"), 0xfed134, "reg from vm");
mu_assert_eq(rz_reg_getv(reg, "pc"), 0x10001, "reg from vm");
@ -209,11 +209,12 @@ static bool test_il_vm_sync_to_reg() {
"gpr pc .64 32 0\n";
reg = rz_reg_new();
rz_reg_set_profile_string(reg, profile3);
rz_il_vm_sync_to_reg(vm, reg);
rz_il_vm_sync_to_reg(vm, rb, reg);
mu_assert_eq(rz_reg_getv(reg, "r1"), 1, "reg from vm");
mu_assert_eq(rz_reg_getv(reg, "pc"), 0x10001, "reg from vm");
rz_reg_free(reg);
rz_il_reg_binding_free(rb);
rz_il_vm_free(vm);
mu_end;
}
@ -242,7 +243,7 @@ static bool test_il_vm_sync_from_reg() {
RzILRegBinding *rb = rz_il_reg_binding_exactly(reg, RZ_ARRAY_SIZE(bind), bind);
rz_il_vm_setup_reg_binding(vm, rb);
rz_il_vm_sync_from_reg(vm, reg);
rz_il_vm_sync_from_reg(vm, rb, reg);
RzILVal *val = rz_il_vm_get_var_value(vm, RZ_IL_VAR_KIND_GLOBAL, "r0");
mu_assert_notnull(val, "val");
mu_assert_eq(val->type, RZ_IL_TYPE_PURE_BITVECTOR, "val type");
@ -287,7 +288,7 @@ static bool test_il_vm_sync_from_reg() {
rz_reg_setv(reg, "af", 42);
rz_reg_setv(reg, "bf", 0);
rz_il_vm_sync_from_reg(vm, reg);
rz_il_vm_sync_from_reg(vm, rb, reg);
val = rz_il_vm_get_var_value(vm, RZ_IL_VAR_KIND_GLOBAL, "r0");
mu_assert_notnull(val, "val");
mu_assert_eq(val->type, RZ_IL_TYPE_PURE_BITVECTOR, "val type");
@ -326,7 +327,7 @@ static bool test_il_vm_sync_from_reg() {
rz_reg_setv(reg, "r32", 0x0123456789abcdef);
rz_reg_setv(reg, "pc", 0x10002);
rz_il_vm_sync_from_reg(vm, reg);
rz_il_vm_sync_from_reg(vm, rb, reg);
val = rz_il_vm_get_var_value(vm, RZ_IL_VAR_KIND_GLOBAL, "r0");
mu_assert_notnull(val, "val");
mu_assert_eq(val->type, RZ_IL_TYPE_PURE_BITVECTOR, "val type");
@ -353,6 +354,7 @@ static bool test_il_vm_sync_from_reg() {
rz_reg_free(reg);
rz_il_reg_binding_free(rb);
rz_il_vm_free(vm);
mu_end;
}