mirror of
https://github.com/rizinorg/rizin
synced 2026-08-22 20:26:16 -04:00
[RzIL] Add loadw/storew and bind memories against RzBuffer (#2105)
* [RzIL] Load/Store via RzIO and RzBuffer * [RzIL] LoadW/StorWe via RzIO and RzBuffer Co-authored-by: Florian Märkl <info@florianmaerkl.de>
This commit is contained in:
parent
89d61756c1
commit
5963da2bba
22 changed files with 2059 additions and 1395 deletions
|
|
@ -15,9 +15,10 @@ static int getid(char ch) {
|
|||
}
|
||||
|
||||
/* New IL uplift bf */
|
||||
#define BF_ADDR_SIZE 64
|
||||
#define BF_ALIGN_SIZE 8
|
||||
#define BF_ID_STACK 32
|
||||
#define BF_ADDR_MEM 0x10000
|
||||
#define BF_ADDR_SIZE 64
|
||||
#define BF_BYTE_SIZE 8
|
||||
#define BF_ID_STACK 32
|
||||
|
||||
struct bf_stack_t {
|
||||
ut64 stack[BF_ID_STACK];
|
||||
|
|
@ -37,28 +38,18 @@ typedef struct bf_context_t {
|
|||
|
||||
static void bf_syscall_read(RzILVM *vm, RzILOp *op) {
|
||||
ut8 c = getc(stdin);
|
||||
RzBitVector *bv = rz_bv_new_from_ut64(BF_ALIGN_SIZE, c);
|
||||
|
||||
RzILVal *ptr_val = rz_il_value_dup(rz_il_hash_find_val_by_name(vm, "ptr"));
|
||||
|
||||
RzBitVector *bv = rz_bv_new_from_ut64(BF_BYTE_SIZE, c);
|
||||
RzILVal *ptr_val = rz_il_hash_find_val_by_name(vm, "ptr");
|
||||
rz_il_vm_mem_store(vm, 0, ptr_val->data.bv, bv);
|
||||
rz_il_value_free(ptr_val);
|
||||
rz_bv_free(bv);
|
||||
}
|
||||
|
||||
static void bf_syscall_write(RzILVM *vm, RzILOp *op) {
|
||||
RzILVal *ptr_val = rz_il_value_dup(rz_il_hash_find_val_by_name(vm, "ptr"));
|
||||
|
||||
RzILVal *ptr_val = rz_il_hash_find_val_by_name(vm, "ptr");
|
||||
RzBitVector *bv = rz_il_vm_mem_load(vm, 0, ptr_val->data.bv);
|
||||
if (!bv) {
|
||||
// default write nothing
|
||||
return;
|
||||
}
|
||||
ut32 c = rz_bv_to_ut32(bv);
|
||||
|
||||
rz_il_value_free(ptr_val);
|
||||
rz_bv_free(bv);
|
||||
|
||||
putchar(c);
|
||||
rz_bv_free(bv);
|
||||
}
|
||||
|
||||
ut64 pop_astack(BfStack *stack) {
|
||||
|
|
@ -102,7 +93,7 @@ RzPVector *bf_inc(RzILVM *vm, ut64 id) {
|
|||
// (store mem (var ptr) (+ (load (var ptr)) (int 1)))
|
||||
// mem == 0 because is the only mem in bf
|
||||
RzILOp *load = rz_il_op_new_load(0, bf_il_ptr());
|
||||
RzILOp *add = rz_il_op_new_add(load, bf_il_one(BF_ALIGN_SIZE));
|
||||
RzILOp *add = rz_il_op_new_add(load, bf_il_one(BF_BYTE_SIZE));
|
||||
RzILOp *store = rz_il_op_new_store(0, bf_il_ptr(), add);
|
||||
return rz_il_make_oplist(1, store);
|
||||
}
|
||||
|
|
@ -111,7 +102,7 @@ RzPVector *bf_dec(RzILVM *vm, ut64 id) {
|
|||
// (store mem (var ptr) (- (load (var ptr)) (int 1)))
|
||||
// mem == 0 because is the only mem in bf
|
||||
RzILOp *load = rz_il_op_new_load(0, bf_il_ptr());
|
||||
RzILOp *sub = rz_il_op_new_sub(load, bf_il_one(BF_ALIGN_SIZE));
|
||||
RzILOp *sub = rz_il_op_new_sub(load, bf_il_one(BF_BYTE_SIZE));
|
||||
RzILOp *store = rz_il_op_new_store(0, bf_il_ptr(), sub);
|
||||
return rz_il_make_oplist(1, store);
|
||||
}
|
||||
|
|
@ -218,9 +209,12 @@ static bool bf_specific_init(RzAnalysisRzil *rzil) {
|
|||
RzILVM *vm = rzil->vm;
|
||||
|
||||
// load reg
|
||||
// TODO use info of reg profile
|
||||
rz_il_vm_add_reg(vm, "ptr", BF_ADDR_SIZE);
|
||||
|
||||
// set ptr to BF_ADDR_MEM
|
||||
RzILVal *ptr = rz_il_hash_find_val_by_name(vm, "ptr");
|
||||
rz_bv_set_from_ut64(ptr->data.bv, BF_ADDR_MEM);
|
||||
|
||||
RzILEffectLabel *read_label = rz_il_vm_create_label_lazy(vm, "read");
|
||||
RzILEffectLabel *write_label = rz_il_vm_create_label_lazy(vm, "write");
|
||||
read_label->addr = (void *)bf_syscall_read;
|
||||
|
|
@ -228,8 +222,6 @@ static bool bf_specific_init(RzAnalysisRzil *rzil) {
|
|||
read_label->type = EFFECT_LABEL_SYSCALL;
|
||||
write_label->type = EFFECT_LABEL_HOOK;
|
||||
|
||||
// init mem
|
||||
rz_il_vm_add_mem(vm, vm->data_size);
|
||||
rzil->inited = true;
|
||||
|
||||
return true;
|
||||
|
|
@ -284,16 +276,28 @@ static bool bf_init_rzil(RzAnalysis *analysis) {
|
|||
}
|
||||
|
||||
// TODO : get some arguments from rizin, predefined some for now.
|
||||
int addrsize = BF_ADDR_SIZE;
|
||||
int datasize = BF_ALIGN_SIZE;
|
||||
ut32 addrsize = BF_ADDR_SIZE;
|
||||
ut64 start_addr = 0;
|
||||
|
||||
// create core theory VM
|
||||
if (!rz_il_vm_init(rzil->vm, start_addr, addrsize, datasize)) {
|
||||
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);
|
||||
|
||||
// init bf RZIL user-defined context
|
||||
rzil->user = bf_context_new();
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ RZ_API void rz_analysis_rzil_free(RZ_NULLABLE RzAnalysisRzil *rzil) {
|
|||
return;
|
||||
}
|
||||
rz_il_vm_free(rzil->vm);
|
||||
rz_buf_free(rzil->io_buf);
|
||||
free(rzil);
|
||||
}
|
||||
|
||||
|
|
@ -77,6 +78,8 @@ RZ_API bool rz_analysis_rzil_setup(RzAnalysis *analysis) {
|
|||
if (!rzil) {
|
||||
return false;
|
||||
}
|
||||
int fd = analysis->iob.fd_get_current(analysis->iob.io);
|
||||
rzil->io_buf = rz_buf_new_with_io(&analysis->iob, fd);
|
||||
analysis->rzil = rzil;
|
||||
analysis->cur->rzil_init(analysis);
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,36 +1,29 @@
|
|||
// SPDX-FileCopyrightText: 2021 Florian Märkl <info@florianmaerkl.de>
|
||||
// SPDX-FileCopyrightText: 2021 deroad <wargio@libero.it>
|
||||
// SPDX-FileCopyrightText: 2021 heersin <teablearcher@gmail.com>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
#include <rz_il/definitions/mem.h>
|
||||
|
||||
static void free_bv_key_value(HtPPKv *kv) {
|
||||
rz_bv_free(kv->value);
|
||||
rz_bv_free(kv->key);
|
||||
}
|
||||
#define KEY_LEN_MAX 64 // because RzBuffer uses ut64 addresses
|
||||
|
||||
/**
|
||||
* Create a Mem (Array)
|
||||
* \param min_unit_size, minimal size of a data unit of current arch
|
||||
* \return RzILMem*
|
||||
* Create a memory for accessing the given buffer.
|
||||
*/
|
||||
RZ_API RzILMem *rz_il_mem_new(ut32 min_unit_size) {
|
||||
RZ_API RzILMem *rz_il_mem_new(RzBuffer *buf, ut32 key_len) {
|
||||
rz_return_val_if_fail(buf && key_len, NULL);
|
||||
if (key_len > KEY_LEN_MAX) {
|
||||
// no assertion because it's not stricly a programming error to call this
|
||||
// with a higher len. It's just not supported.
|
||||
return NULL;
|
||||
}
|
||||
RzILMem *ret = RZ_NEW0(RzILMem);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HtPPOptions options = { 0 };
|
||||
options.cmp = (HtPPListComparator)rz_bv_cmp;
|
||||
options.hashfn = (HtPPHashFunction)rz_bv_hash;
|
||||
options.dupkey = (HtPPDupKey)rz_bv_dup;
|
||||
options.dupvalue = (HtPPDupValue)rz_bv_dup;
|
||||
options.freefn = (HtPPKvFreeFunc)free_bv_key_value;
|
||||
options.elem_size = sizeof(HtPPKv);
|
||||
HtPP *mem_map = ht_pp_new_opt(&options);
|
||||
|
||||
ret->kv_map = mem_map;
|
||||
ret->min_unit_size = min_unit_size;
|
||||
|
||||
rz_buf_ref(buf);
|
||||
ret->buf = buf;
|
||||
ret->key_len = key_len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -42,38 +35,139 @@ RZ_API void rz_il_mem_free(RzILMem *mem) {
|
|||
if (!mem) {
|
||||
return;
|
||||
}
|
||||
|
||||
ht_pp_free(mem->kv_map);
|
||||
rz_buf_free(mem->buf);
|
||||
free(mem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store data (bitvector) into an address (bitvector)
|
||||
* \param mem Memory
|
||||
* \param key address (bitvector)
|
||||
* \param value data (bitvector)
|
||||
* \return a pointer to memory
|
||||
* \brief Get the bit-size of a key (address) into the memory
|
||||
*
|
||||
* For all k, `rz_bv_len(rz_il_mem_load(mem, k)) == rz_il_mem_value_len(mem)`.
|
||||
* So this could be seen as the size of a byte. Because we only support RzBuffer-based mems
|
||||
* at the moment, this is always 8, but more options may be available in the future.
|
||||
*/
|
||||
RZ_API RzILMem *rz_il_mem_store(RzILMem *mem, RzBitVector *key, RzBitVector *value) {
|
||||
if (value->len < mem->min_unit_size) {
|
||||
RZ_LOG_ERROR("RzIL: Memory write size mismatch (expected size > %u, but got %u)\n", mem->min_unit_size, value->len);
|
||||
return NULL;
|
||||
}
|
||||
ht_pp_update(mem->kv_map, key, value);
|
||||
return mem;
|
||||
RZ_API ut32 rz_il_mem_key_len(RzILMem *mem) {
|
||||
return mem->key_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load data (bitvector) from current address (bitvector)
|
||||
* \brief Get the bit-size of a value in the memory
|
||||
*
|
||||
* For all k, `rz_bv_len(rz_il_mem_load(mem, k)) == rz_il_mem_value_len(mem)`.
|
||||
* So this could be seen as the size of a byte. Because we only support RzBuffer-based mems
|
||||
* at the moment, this is always 8, but more options may be available in the future.
|
||||
*/
|
||||
RZ_API ut32 rz_il_mem_value_len(RzILMem *mem) {
|
||||
return 8;
|
||||
}
|
||||
|
||||
#define return_val_if_key_len_wrong(mem, key, ret) \
|
||||
do { \
|
||||
if (rz_bv_len(key) != rz_il_mem_key_len(mem)) { \
|
||||
RZ_LOG_ERROR("RzIL: Memory key size mismatch (expected size = %u, but got %u)\n", \
|
||||
(unsigned int)rz_il_mem_key_len(mem), (unsigned int)rz_bv_len(key)); \
|
||||
return ret; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
/**
|
||||
* Load a single memory value (bitvector) from current address (bitvector)
|
||||
* \param mem Memory
|
||||
* \param key address (bitvector)
|
||||
* \return data (bitvector)
|
||||
*/
|
||||
RZ_API RzBitVector *rz_il_mem_load(RzILMem *mem, RzBitVector *key) {
|
||||
RzBitVector *val = ht_pp_find(mem->kv_map, key, NULL);
|
||||
if (val == NULL) {
|
||||
rz_return_val_if_fail(mem && key, NULL);
|
||||
return_val_if_key_len_wrong(mem, key, NULL);
|
||||
ut8 v = 0;
|
||||
rz_buf_read_at(mem->buf, rz_bv_to_ut64(key), &v, 1);
|
||||
return rz_bv_new_from_ut64(rz_il_mem_value_len(mem), v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a single memory value (bitvector) into an address (bitvector)
|
||||
* \param key address
|
||||
* \param value data
|
||||
* \return whether the store succeeded
|
||||
*/
|
||||
RZ_API bool rz_il_mem_store(RzILMem *mem, RzBitVector *key, RzBitVector *value) {
|
||||
rz_return_val_if_fail(mem && key && value, false);
|
||||
return_val_if_key_len_wrong(mem, key, false);
|
||||
if (rz_bv_len(value) != rz_il_mem_value_len(mem)) {
|
||||
RZ_LOG_ERROR("RzIL: Memory write value size mismatch (expected size = %u, but got %u)\n",
|
||||
(unsigned int)rz_il_mem_value_len(mem), (unsigned int)rz_bv_len(value));
|
||||
return false;
|
||||
}
|
||||
ut8 v = rz_bv_to_ut8(value);
|
||||
return rz_buf_write_at(mem->buf, rz_bv_to_ut64(key), &v, 1) == 1;
|
||||
}
|
||||
|
||||
static RzBitVector *read_n_bits(RzBuffer *buf, ut32 n_bits, RzBitVector *key, bool big_endian) {
|
||||
RzBitVector *value = rz_bv_new_zero(n_bits);
|
||||
if (!value) {
|
||||
rz_warn_if_reached();
|
||||
return NULL;
|
||||
}
|
||||
RzBitVector *ret = rz_bv_dup(val);
|
||||
return ret;
|
||||
|
||||
ut64 address = rz_bv_to_ut64(key);
|
||||
ut32 n_bytes = rz_bv_len_bytes(value);
|
||||
|
||||
ut8 *data = calloc(n_bytes, 1);
|
||||
if (!data) {
|
||||
return value;
|
||||
}
|
||||
|
||||
// we ignore bad reads. RzBuffer fills up with its "overflow byte" on failure.
|
||||
rz_buf_read_at(buf, address, data, n_bytes);
|
||||
if (big_endian) {
|
||||
value = rz_bv_new_from_bytes_be(data, 0, n_bits);
|
||||
} else {
|
||||
value = rz_bv_new_from_bytes_le(data, 0, n_bits);
|
||||
}
|
||||
free(data);
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool write_n_bits(RzBuffer *buf, RzBitVector *key, RzBitVector *value, bool big_endian) {
|
||||
ut64 address = rz_bv_to_ut64(key);
|
||||
ut32 n_bytes = rz_bv_len_bytes(value);
|
||||
|
||||
ut8 *data = calloc(n_bytes, 1);
|
||||
if (!data) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (big_endian) {
|
||||
rz_bv_set_to_bytes_be(value, data);
|
||||
} else {
|
||||
rz_bv_set_to_bytes_le(value, data);
|
||||
}
|
||||
|
||||
bool succ = rz_buf_write_at(buf, address, data, n_bytes) == n_bytes;
|
||||
free(data);
|
||||
return succ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an entire work of the given size from the given address
|
||||
* \param key address (bitvector)
|
||||
* \param n_bits How many bits to read. This also determines the size of the returned bitvector
|
||||
* \return data (bitvector)
|
||||
*/
|
||||
RZ_API RzBitVector *rz_il_mem_loadw(RzILMem *mem, RzBitVector *key, ut32 n_bits, bool big_endian) {
|
||||
rz_return_val_if_fail(mem && key && n_bits, NULL);
|
||||
return_val_if_key_len_wrong(mem, key, NULL);
|
||||
return read_n_bits(mem->buf, n_bits, key, big_endian);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store an entire word or arbitrary size at an address
|
||||
* \param key address
|
||||
* \param value data
|
||||
* \return whether the store succeeded
|
||||
*/
|
||||
RZ_API bool rz_il_mem_storew(RzILMem *mem, RzBitVector *key, RzBitVector *value, bool big_endian) {
|
||||
rz_return_val_if_fail(mem && key && value, false);
|
||||
return_val_if_key_len_wrong(mem, key, false);
|
||||
return write_n_bits(mem->buf, key, value, big_endian);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -329,15 +329,15 @@ static void il_opdmp_append(RzILOp *op, RzStrBuf *sb, PJ *pj) {
|
|||
static void il_opdmp_load(RzILOp *op, RzStrBuf *sb, PJ *pj) {
|
||||
RzILOpLoad *opx = op->op.load;
|
||||
if (sb) {
|
||||
rz_strbuf_append(sb, "load(key:");
|
||||
rz_strbuf_appendf(sb, "load(mem:%u, key:", (unsigned int)opx->mem);
|
||||
il_op_resolve(opx->key, sb, pj);
|
||||
rz_strbuf_appendf(sb, ", mem:%d)", opx->mem);
|
||||
rz_strbuf_append(sb, ")");
|
||||
} else {
|
||||
pj_o(pj);
|
||||
pj_ks(pj, "opcode", "load");
|
||||
pj_kn(pj, "mem", opx->mem);
|
||||
pj_k(pj, "key");
|
||||
il_op_resolve(opx->key, sb, pj);
|
||||
pj_kN(pj, "mem", opx->mem);
|
||||
pj_end(pj);
|
||||
}
|
||||
}
|
||||
|
|
@ -346,19 +346,19 @@ static void il_opdmp_store(RzILOp *op, RzStrBuf *sb, PJ *pj) {
|
|||
RzILOpStore *opx = op->op.store;
|
||||
|
||||
if (sb) {
|
||||
rz_strbuf_append(sb, "store(key:");
|
||||
rz_strbuf_appendf(sb, "store(mem:%u, key:", (unsigned int)opx->mem);
|
||||
il_op_resolve(opx->key, sb, pj);
|
||||
rz_strbuf_append(sb, ", value:");
|
||||
il_op_resolve(opx->value, sb, pj);
|
||||
rz_strbuf_appendf(sb, ", mem:%d)", opx->mem);
|
||||
rz_strbuf_appendf(sb, ")");
|
||||
} else {
|
||||
pj_o(pj);
|
||||
pj_ks(pj, "opcode", "store");
|
||||
pj_kn(pj, "mem", opx->mem);
|
||||
pj_k(pj, "key");
|
||||
il_op_resolve(opx->key, sb, pj);
|
||||
pj_k(pj, "value");
|
||||
il_op_resolve(opx->value, sb, pj);
|
||||
pj_kN(pj, "mem", opx->mem);
|
||||
pj_end(pj);
|
||||
}
|
||||
}
|
||||
|
|
@ -386,14 +386,14 @@ static void il_opdmp_set(RzILOp *op, RzStrBuf *sb, PJ *pj) {
|
|||
static void il_opdmp_let(RzILOp *op, RzStrBuf *sb, PJ *pj) {
|
||||
RzILOpLet *opx = op->op.let;
|
||||
if (sb) {
|
||||
rz_strbuf_appendf(sb, "let(v:%s%s, x:", opx->v, opx->mut ? "" : ", const");
|
||||
rz_strbuf_appendf(sb, "let(v:%s, x:", opx->v);
|
||||
il_op_resolve(opx->x, sb, pj);
|
||||
rz_strbuf_append(sb, ")");
|
||||
rz_strbuf_append(sb, opx->mut ? ")" : ", const)");
|
||||
} else {
|
||||
pj_o(pj);
|
||||
pj_ks(pj, "opcode", "let");
|
||||
pj_ks(pj, "dst", opx->v);
|
||||
pj_kb(pj, "mutable", opx->mut);
|
||||
pj_kb(pj, "const", !opx->mut);
|
||||
pj_k(pj, "src");
|
||||
il_op_resolve(opx->x, sb, pj);
|
||||
pj_end(pj);
|
||||
|
|
|
|||
|
|
@ -570,9 +570,9 @@ RZ_API RZ_OWN RzILOp *rz_il_op_new_branch(RZ_NONNULL RzILOp *condition, RZ_NULLA
|
|||
}
|
||||
|
||||
/**
|
||||
* \brief op structure for bitvector
|
||||
* \brief Helper to create RzILOpLoad
|
||||
*/
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_load(int mem, RZ_NONNULL RzILOp *key) {
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_load(RzILMemIndex mem, RZ_NONNULL RzILOp *key) {
|
||||
rz_return_val_if_fail(key, NULL);
|
||||
RzILOp *ret;
|
||||
rz_il_op_new_2(RZIL_OP_LOAD, RzILOpLoad, load, mem, key);
|
||||
|
|
@ -580,15 +580,35 @@ RZ_API RZ_OWN RzILOp *rz_il_op_new_load(int mem, RZ_NONNULL RzILOp *key) {
|
|||
}
|
||||
|
||||
/**
|
||||
* \brief op structure for bitvector
|
||||
* \brief Helper to create RzILOpStoreW
|
||||
*/
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_store(int mem, RZ_NONNULL RzILOp *key, RZ_NONNULL RzILOp *value) {
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_store(RzILMemIndex mem, RZ_NONNULL RzILOp *key, RZ_NONNULL RzILOp *value) {
|
||||
rz_return_val_if_fail(key && value, NULL);
|
||||
RzILOp *ret;
|
||||
rz_il_op_new_3(RZIL_OP_STORE, RzILOpStore, store, mem, key, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Helper to create RzILOpLoadW
|
||||
*/
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_loadw(RzILMemIndex mem, RZ_NONNULL RzILOp *key, ut32 n_bits) {
|
||||
rz_return_val_if_fail(key && n_bits, NULL);
|
||||
RzILOp *ret;
|
||||
rz_il_op_new_3(RZIL_OP_LOADW, RzILOpLoadW, loadw, mem, key, n_bits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Helper to create RzILOpStoreW
|
||||
*/
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_storew(RzILMemIndex mem, RZ_NONNULL RzILOp *key, RZ_NONNULL RzILOp *value) {
|
||||
rz_return_val_if_fail(key && value, NULL);
|
||||
RzILOp *ret;
|
||||
rz_il_op_new_3(RZIL_OP_STOREW, RzILOpStoreW, storew, mem, key, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief op structure for illegal/invalid
|
||||
*/
|
||||
|
|
@ -723,6 +743,12 @@ RZ_API void rz_il_op_free(RZ_NULLABLE RzILOp *op) {
|
|||
case RZIL_OP_STORE:
|
||||
rz_il_op_free_2(store, key, value);
|
||||
break;
|
||||
case RZIL_OP_LOADW:
|
||||
rz_il_op_free_1(loadw, key);
|
||||
break;
|
||||
case RZIL_OP_STOREW:
|
||||
rz_il_op_free_2(storew, key, value);
|
||||
break;
|
||||
case RZIL_OP_NOP:
|
||||
// nothing to free
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -595,7 +595,7 @@ RZ_API RZ_OWN void rz_il_evaluate_effect(RZ_NONNULL RzILVM *vm, RZ_NONNULL RzILO
|
|||
rz_il_value_free(result);
|
||||
break;
|
||||
case RZIL_OP_ARG_MEM:
|
||||
rz_il_mem_free(result);
|
||||
case RZIL_OP_ARG_EFF:
|
||||
break;
|
||||
default:
|
||||
RZ_LOG_ERROR("RzIL: unknown RzILEffect type\n");
|
||||
|
|
|
|||
|
|
@ -11,12 +11,6 @@ void *rz_il_handler_load(RzILVM *vm, RzILOp *op, RzILOpArgType *type) {
|
|||
|
||||
RzBitVector *addr = rz_il_evaluate_bitv(vm, op_load->key, type);
|
||||
RzBitVector *ret = rz_il_vm_mem_load(vm, op_load->mem, addr);
|
||||
if (ret == NULL) {
|
||||
// empty address --> first access
|
||||
// assume it's empty
|
||||
rz_il_vm_mem_store_zero(vm, op_load->mem, addr, &ret);
|
||||
}
|
||||
|
||||
rz_bv_free(addr);
|
||||
*type = RZIL_OP_ARG_BITV;
|
||||
return ret;
|
||||
|
|
@ -30,10 +24,37 @@ void *rz_il_handler_store(RzILVM *vm, RzILOp *op, RzILOpArgType *type) {
|
|||
RzBitVector *addr = rz_il_evaluate_bitv(vm, op_store->key, type);
|
||||
RzBitVector *value = rz_il_evaluate_bitv(vm, op_store->value, type);
|
||||
|
||||
RzILMem *m = rz_il_vm_mem_store(vm, op_store->mem, addr, value);
|
||||
rz_il_vm_mem_store(vm, op_store->mem, addr, value);
|
||||
rz_bv_free(addr);
|
||||
rz_bv_free(value);
|
||||
|
||||
*type = RZIL_OP_ARG_MEM;
|
||||
return m;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *rz_il_handler_loadw(RzILVM *vm, RzILOp *op, RzILOpArgType *type) {
|
||||
rz_return_val_if_fail(vm && op && type, NULL);
|
||||
RzILOpLoadW *op_loadw = op->op.loadw;
|
||||
|
||||
RzBitVector *addr = rz_il_evaluate_bitv(vm, op_loadw->key, type);
|
||||
RzBitVector *ret = rz_il_vm_mem_loadw(vm, op_loadw->mem, addr, op_loadw->n_bits);
|
||||
rz_bv_free(addr);
|
||||
*type = RZIL_OP_ARG_BITV;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *rz_il_handler_storew(RzILVM *vm, RzILOp *op, RzILOpArgType *type) {
|
||||
rz_return_val_if_fail(vm && op && type, NULL);
|
||||
|
||||
RzILOpStoreW *op_storew = op->op.storew;
|
||||
|
||||
RzBitVector *addr = rz_il_evaluate_bitv(vm, op_storew->key, type);
|
||||
RzBitVector *value = rz_il_evaluate_bitv(vm, op_storew->value, type);
|
||||
|
||||
rz_il_vm_mem_storew(vm, op_storew->mem, addr, value);
|
||||
rz_bv_free(addr);
|
||||
rz_bv_free(value);
|
||||
|
||||
*type = RZIL_OP_ARG_MEM;
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ void *rz_il_handler_branch(RzILVM *vm, RzILOp *op, RzILOpArgType *type);
|
|||
|
||||
void *rz_il_handler_load(RzILVM *vm, RzILOp *op, RzILOpArgType *type);
|
||||
void *rz_il_handler_store(RzILVM *vm, RzILOp *op, RzILOpArgType *type);
|
||||
void *rz_il_handler_loadw(RzILVM *vm, RzILOp *op, RzILOpArgType *type);
|
||||
void *rz_il_handler_storew(RzILVM *vm, RzILOp *op, RzILOpArgType *type);
|
||||
|
||||
// TODO: remove me when all the handlers are implemented
|
||||
void *rz_il_handler_unimplemented(RzILVM *vm, RzILOp *op, RzILOpArgType *type);
|
||||
|
|
@ -86,6 +88,8 @@ static RzILOpHandler op_handler_table_default[RZIL_OP_MAX] = {
|
|||
rz_il_handler_append, /* RZIL_OP_APPEND */
|
||||
rz_il_handler_load, /* RZIL_OP_LOAD */
|
||||
rz_il_handler_store, /* RZIL_OP_STORE */
|
||||
rz_il_handler_loadw, /* RZIL_OP_LOADW */
|
||||
rz_il_handler_storew, /* RZIL_OP_STOREW */
|
||||
rz_il_handler_nop, /* RZIL_OP_NOP */
|
||||
rz_il_handler_set, /* RZIL_OP_SET */
|
||||
rz_il_handler_let, /* RZIL_OP_LET */
|
||||
|
|
@ -128,12 +132,10 @@ static void free_bind_var_val(HtPPKv *kv) {
|
|||
* initiate an empty VM
|
||||
* \param vm RzILVM, pointer to an empty VM
|
||||
* \param start_addr ut64, initiation pc address
|
||||
* \param addr_size ut32, size of the address in VM
|
||||
* \param data_size ut32, size of the minimal data unit in VM
|
||||
* \param addr_size ut32, size of the address in VM
|
||||
*/
|
||||
RZ_API bool rz_il_vm_init(RzILVM *vm, ut64 start_addr, ut32 addr_size, ut32 data_size) {
|
||||
vm->addr_size = addr_size;
|
||||
vm->data_size = data_size;
|
||||
RZ_API bool rz_il_vm_init(RzILVM *vm, ut64 start_addr, ut32 addr_size, bool big_endian) {
|
||||
rz_return_val_if_fail(vm, false);
|
||||
|
||||
rz_pvector_init(&vm->vm_global_variable_list, (RzPVectorFree)rz_il_variable_free);
|
||||
rz_pvector_init(&vm->vm_local_variable_list, (RzPVectorFree)rz_il_variable_free);
|
||||
|
|
@ -216,6 +218,8 @@ RZ_API bool rz_il_vm_init(RzILVM *vm, ut64 start_addr, ut32 addr_size, ut32 data
|
|||
|
||||
vm->lab_count = 0;
|
||||
vm->val_count = 0;
|
||||
vm->addr_size = addr_size;
|
||||
vm->big_endian = big_endian;
|
||||
|
||||
vm->events = rz_list_newf((RzListFree)rz_il_event_free);
|
||||
if (!vm->events) {
|
||||
|
|
@ -265,15 +269,14 @@ RZ_API void rz_il_vm_fini(RzILVM *vm) {
|
|||
* Create a new empty VM
|
||||
* \param vm RzILVM, pointer to an empty VM
|
||||
* \param start_addr ut64, initiation pc address
|
||||
* \param addr_size ut32, size of the address in VM
|
||||
* \param data_size ut32, size of the minimal data unit in VM
|
||||
* \param addr_size ut32, size of the address in VM
|
||||
*/
|
||||
RZ_API RzILVM *rz_il_vm_new(ut64 start_addr, ut32 addr_size, ut32 data_size) {
|
||||
RZ_API RzILVM *rz_il_vm_new(ut64 start_addr, ut32 addr_size, bool big_endian) {
|
||||
RzILVM *vm = RZ_NEW0(RzILVM);
|
||||
if (!vm) {
|
||||
return NULL;
|
||||
}
|
||||
rz_il_vm_init(vm, start_addr, addr_size, data_size);
|
||||
rz_il_vm_init(vm, start_addr, addr_size, big_endian);
|
||||
return vm;
|
||||
}
|
||||
|
||||
|
|
@ -290,29 +293,42 @@ RZ_API void rz_il_vm_free(RzILVM *vm) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Add a memory in VM. We design this to support multiple memory in the future
|
||||
* \param vm RzILVM, pointer to VM
|
||||
* \param min_unit_size ut32, size of minimal unit of the vm
|
||||
* \return Mem memory, return a pointer to the newly created memory
|
||||
* Add a memory to VM at the given index.
|
||||
* Ownership of the memory is transferred to the VM.
|
||||
*/
|
||||
RZ_API RzILMem *rz_il_vm_add_mem(RzILVM *vm, ut32 min_unit_size) {
|
||||
RzILMem *mem = rz_il_mem_new(min_unit_size);
|
||||
rz_pvector_push(&vm->vm_memory, mem);
|
||||
return mem;
|
||||
RZ_API void rz_il_vm_add_mem(RzILVM *vm, RzILMemIndex index, RZ_OWN RzILMem *mem) {
|
||||
if (index < rz_pvector_len(&vm->vm_memory)) {
|
||||
rz_mem_free(rz_pvector_at(&vm->vm_memory, index));
|
||||
}
|
||||
rz_pvector_reserve(&vm->vm_memory, index + 1);
|
||||
// Fill up with NULLs until the given index
|
||||
while (rz_pvector_len(&vm->vm_memory) < index + 1) {
|
||||
rz_pvector_push(&vm->vm_memory, NULL);
|
||||
}
|
||||
rz_pvector_set(&vm->vm_memory, index, mem);
|
||||
}
|
||||
|
||||
RZ_API RzILMem *rz_il_vm_get_mem(RzILVM *vm, RzILMemIndex index) {
|
||||
if (index >= rz_pvector_len(&vm->vm_memory)) {
|
||||
return NULL;
|
||||
}
|
||||
return rz_pvector_at(&vm->vm_memory, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load data from memory by given key and generates an RZIL_EVENT_MEM_READ event
|
||||
* \param vm RzILVM, pointer to VM
|
||||
* \param mem_index ut32, index to choose a memory
|
||||
* \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
|
||||
* \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, ut32 mem_index, RzBitVector *key) {
|
||||
rz_return_val_if_fail(vm && key && mem_index < rz_pvector_len(&vm->vm_memory), NULL);
|
||||
RzBitVector *value = NULL;
|
||||
RzILMem *m = rz_pvector_at(&vm->vm_memory, mem_index);
|
||||
value = rz_il_mem_load(m, key);
|
||||
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(key, value));
|
||||
return value;
|
||||
}
|
||||
|
|
@ -321,40 +337,60 @@ RZ_API RzBitVector *rz_il_vm_mem_load(RzILVM *vm, ut32 mem_index, RzBitVector *k
|
|||
* Store data to memory by key, will create a key-value pair
|
||||
* or update the key-value pair if key existed; also generates
|
||||
* an RZIL_EVENT_MEM_WRITE event
|
||||
* \param vm RzILVM* pointer to VM
|
||||
* \param mem_index ut32, index to choose a memory
|
||||
* \param key RzBitVector, aka address, a key to store data from memory
|
||||
* \param value RzBitVector, aka value to store in memory
|
||||
* \return mem Mem, the memory you store data to
|
||||
* \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 RzILMem *rz_il_vm_mem_store(RzILVM *vm, ut32 mem_index, RzBitVector *key, RzBitVector *value) {
|
||||
rz_return_val_if_fail(vm && key && mem_index < rz_pvector_len(&vm->vm_memory), NULL);
|
||||
RzILMem *m = rz_pvector_at(&vm->vm_memory, mem_index);
|
||||
RzBitVector *old_value = rz_il_mem_load(m, key);
|
||||
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(key, old_value, value));
|
||||
rz_bv_free(old_value);
|
||||
return rz_il_mem_store(m, key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a Bitvector with value ZERO to memory by key, will create a key-value pair
|
||||
* or update the key-value pair if key existed.
|
||||
* \param vm RzILVM* pointer to VM
|
||||
* \param mem_index ut32, index to choose a memory
|
||||
* \param key RzBitVector, aka address, a key to store data from memory
|
||||
* \param value RzBitVector**, aka the ZERO just stored in memory
|
||||
* \return mem Mem, the memory you store data to
|
||||
* Load data from memory by given key and generates an RZIL_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 RzILMem *rz_il_vm_mem_store_zero(RzILVM *vm, ut32 mem_index, RzBitVector *key, RzBitVector **value) {
|
||||
rz_return_val_if_fail(vm && key && mem_index < rz_pvector_len(&vm->vm_memory), NULL);
|
||||
RzILMem *m = rz_pvector_at(&vm->vm_memory, mem_index);
|
||||
RzBitVector *zero = rz_bv_new(m->min_unit_size);
|
||||
RzBitVector *old_value = rz_il_mem_load(m, key);
|
||||
rz_bv_free(old_value);
|
||||
if (value) {
|
||||
*value = zero;
|
||||
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;
|
||||
}
|
||||
return rz_il_mem_store(m, key, zero);
|
||||
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(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 RZIL_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_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);
|
||||
rz_il_mem_storew(mem, key, value, vm->big_endian);
|
||||
rz_il_vm_event_add(vm, rz_il_event_mem_write_new(key, old_value, value));
|
||||
rz_bv_free(old_value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1123,6 +1123,7 @@ typedef struct rz_analysis_rzil_callbacks_t {
|
|||
|
||||
typedef struct rz_analysis_rzil_t {
|
||||
RzILVM *vm;
|
||||
RzBuffer *io_buf;
|
||||
RzAnalysisRzilTrace *trace;
|
||||
|
||||
RzAnalysisRzilCallbacks cb;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2021 Florian Märkl <info@florianmaerkl.de>
|
||||
// SPDX-FileCopyrightText: 2021 heersin <teablearcher@gmail.com>
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
|
|
@ -10,16 +11,31 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct rzil_mem_t {
|
||||
HtPP *kv_map;
|
||||
ut32 min_unit_size; // minimal unit size in bit (len of value bv)
|
||||
};
|
||||
typedef struct rzil_mem_t RzILMem;
|
||||
typedef ut32 RzILMemIndex;
|
||||
|
||||
RZ_API RzILMem *rz_il_mem_new(ut32 min_unit_size);
|
||||
/**
|
||||
* \brief A single memory as part of the RzIL VM.
|
||||
*
|
||||
* This can be seen as an array of bitvectors, indexed by bitvector keys, covering a
|
||||
* certain address space. It corresponds to `('a, 'b) mem` in bap where 'a and 'b
|
||||
* statically determine the size of all keys and values, respectively.
|
||||
* Because currently our memory can only bind to an RzBuffer, the key size is limited to
|
||||
* a maximum of 64bits and the value size is always 8, but this can be extended in
|
||||
* the future if necessary.
|
||||
*/
|
||||
typedef struct rzil_mem_t {
|
||||
RzBuffer *buf;
|
||||
ut32 key_len;
|
||||
} RzILMem;
|
||||
|
||||
RZ_API RzILMem *rz_il_mem_new(RzBuffer *buf, ut32 key_len);
|
||||
RZ_API void rz_il_mem_free(RzILMem *mem);
|
||||
RZ_API RzILMem *rz_il_mem_store(RzILMem *mem, RzBitVector *key, RzBitVector *value);
|
||||
RZ_API ut32 rz_il_mem_key_len(RzILMem *mem);
|
||||
RZ_API ut32 rz_il_mem_value_len(RzILMem *mem);
|
||||
RZ_API RzBitVector *rz_il_mem_load(RzILMem *mem, RzBitVector *key);
|
||||
RZ_API bool rz_il_mem_store(RzILMem *mem, RzBitVector *key, RzBitVector *value);
|
||||
RZ_API RzBitVector *rz_il_mem_loadw(RzILMem *mem, RzBitVector *key, ut32 n_bits, bool big_endian);
|
||||
RZ_API bool rz_il_mem_storew(RzILMem *mem, RzBitVector *key, RzBitVector *value, bool big_endian);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -284,10 +284,10 @@ struct rzil_op_bool_inv_t {
|
|||
*
|
||||
* load m k is the value associated with the key k in the memory m.
|
||||
*/
|
||||
struct rzil_op_load_t {
|
||||
int mem; ///< index of the memory in VM (different from the temp_val_list)
|
||||
RzILOp *key; ///< index of the RzBitVector key (address)
|
||||
};
|
||||
typedef struct rzil_op_load_t {
|
||||
RzILMemIndex mem; ///< index of the mem inside the vm to use
|
||||
RzILOp *key; ///< memory index of the RzBitVector key (address), must have exactly the size of a key in the memory
|
||||
} RzILOpLoad;
|
||||
|
||||
/**
|
||||
* \struct rzil_op_store_t
|
||||
|
|
@ -295,11 +295,33 @@ struct rzil_op_load_t {
|
|||
*
|
||||
* store m k x a memory m in which the key k is associated with the word x.
|
||||
*/
|
||||
struct rzil_op_store_t {
|
||||
int mem; ///< index of memory in VM
|
||||
RzILOp *key; ///< index of the RzBitVector key (address)
|
||||
RzILOp *value; ///< index of the RzILVal value (data) to store
|
||||
};
|
||||
typedef struct rzil_op_store_t {
|
||||
RzILMemIndex mem; ///< index of memory in the vm to use
|
||||
RzILOp *key; ///< address where to store to, must have exactly the size of a key in the memory
|
||||
RzILOp *value; ///< value to store, must have exactly the size of a memory cell
|
||||
} RzILOpStore;
|
||||
|
||||
/**
|
||||
* \brief Load an entire word of arbitrary bit size from a memory
|
||||
*
|
||||
* Endianness is determined by the vm
|
||||
*/
|
||||
typedef struct rzil_op_loadw_t {
|
||||
RzILMemIndex mem; ///< index of the mem inside the vm to use
|
||||
RzILOp *key; ///< memory index of the RzBitVector key (address)
|
||||
ut32 n_bits; ///< n of bits to read, and of the resulting bitvector
|
||||
} RzILOpLoadW;
|
||||
|
||||
/**
|
||||
* \brief Store an entire word of arbitrary bit size into a memory
|
||||
*
|
||||
* Endianness is determined by the vm
|
||||
*/
|
||||
typedef struct rzil_op_storew_t {
|
||||
RzILMemIndex mem; ///< index of memory in the vm to use
|
||||
RzILOp *key; ///< address where to store to
|
||||
RzILOp *value; ///< value to store, arbitrary size
|
||||
} RzILOpStoreW;
|
||||
|
||||
typedef enum {
|
||||
// Init
|
||||
|
|
@ -343,6 +365,8 @@ typedef enum {
|
|||
// Memory
|
||||
RZIL_OP_LOAD,
|
||||
RZIL_OP_STORE,
|
||||
RZIL_OP_LOADW,
|
||||
RZIL_OP_STOREW,
|
||||
|
||||
// Effects (opcode with side effects)
|
||||
RZIL_OP_NOP,
|
||||
|
|
@ -404,9 +428,6 @@ typedef struct rzil_op_blk_t RzILOpBlk;
|
|||
typedef struct rzil_op_repeat_t RzILOpRepeat;
|
||||
typedef struct rzil_op_branch_t RzILOpBranch;
|
||||
|
||||
typedef struct rzil_op_load_t RzILOpLoad;
|
||||
typedef struct rzil_op_store_t RzILOpStore;
|
||||
|
||||
// Then define a union to union all of these struct
|
||||
typedef union {
|
||||
RzILOpIte *ite;
|
||||
|
|
@ -450,6 +471,8 @@ typedef union {
|
|||
|
||||
RzILOpLoad *load;
|
||||
RzILOpStore *store;
|
||||
RzILOpLoadW *loadw;
|
||||
RzILOpStoreW *storew;
|
||||
} RzILOpUnion;
|
||||
|
||||
struct rz_il_op_t {
|
||||
|
|
@ -501,8 +524,10 @@ RZ_API RZ_OWN RzILOp *rz_il_op_new_seq(RZ_NONNULL RzILOp *x, RZ_NONNULL RzILOp *
|
|||
RZ_API RZ_OWN RzILOp *rz_il_op_new_blk(RZ_NONNULL RzILOp *data_effect, RZ_NONNULL RzILOp *ctrl_effect);
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_repeat(RZ_NONNULL RzILOp *condition, RZ_NONNULL RzILOp *data_effect);
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_branch(RZ_NONNULL RzILOp *condition, RZ_NULLABLE RzILOp *true_effect, RZ_NULLABLE RzILOp *false_effect);
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_load(int mem, RZ_NONNULL RzILOp *key);
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_store(int mem, RZ_NONNULL RzILOp *key, RZ_NONNULL RzILOp *value);
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_load(RzILMemIndex mem, RZ_NONNULL RzILOp *key);
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_store(RzILMemIndex mem, RZ_NONNULL RzILOp *key, RZ_NONNULL RzILOp *value);
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_loadw(RzILMemIndex mem, RZ_NONNULL RzILOp *key, ut32 n_bits);
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_storew(RzILMemIndex mem, RZ_NONNULL RzILOp *key, RZ_NONNULL RzILOp *value);
|
||||
RZ_API RZ_OWN RzILOp *rz_il_op_new_invalid();
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -12,12 +12,8 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define RZ_IL_VM_MAX_VAR 2048
|
||||
#define RZ_IL_VM_MAX_VAL 1024
|
||||
#define RZ_IL_VM_MAX_LAB 1024
|
||||
#define RZ_IL_VM_MAX_EFF 1024
|
||||
#define RZ_IL_VM_MAX_FLG 1024
|
||||
#define RZ_IL_VM_MAX_TEMP 32
|
||||
#define RZ_IL_VM_MAX_VAR 2048
|
||||
#define RZ_IL_VM_MAX_VAL 1024
|
||||
|
||||
typedef enum {
|
||||
RZIL_OP_ARG_BOOL,
|
||||
|
|
@ -40,24 +36,18 @@ struct rz_il_vm_t {
|
|||
RzILBag *vm_global_value_set; ///< Store all RzILVal instance
|
||||
RzPVector /*<RzILVar*>*/ vm_global_variable_list; ///< Store all the global RzILVar instance
|
||||
RzPVector /*<RzILVar*>*/ vm_local_variable_list; ///< Store all the local RzILVar instance
|
||||
|
||||
RzPVector /*<RzILMem*>*/ vm_memory; ///< Array of Memory, memory are actually hashmap in VM
|
||||
RzPVector /*<RzILMem*>*/ vm_memory; ///< Memories available in the VM, by their inded. May be sparse (contain NULLs).
|
||||
ut32 val_count, lab_count; ///< count for VM predefined things
|
||||
ut32 addr_size; ///< size of address space
|
||||
ut32 data_size; ///< size of minimal data unit
|
||||
|
||||
HtPP *vm_global_bind_table; ///< Hashtable to record relationships between global var and val
|
||||
HtPP *vm_local_bind_table; ///< Hashtable to record relationships between local var and val
|
||||
HtPP *vm_global_label_table; ///< Hashtable to maintain the label and address
|
||||
HtPP *vm_local_label_table; ///< Hashtable to maintain the label and address
|
||||
|
||||
HtPP *ct_opcodes; ///< Hashtable to maintain address and opcodes
|
||||
|
||||
RzBitVector *pc; ///< Program Counter of VM
|
||||
|
||||
RzILOpHandler *op_handler_table; ///< Array of Handler, handler can be indexed by opcode
|
||||
|
||||
RzList *events; ///< List of events that has happened in the last step
|
||||
bool big_endian; ///< Sets the endianness of the memory reads/writes operations
|
||||
};
|
||||
|
||||
// VM operations about Variable and Value
|
||||
|
|
|
|||
|
|
@ -4,16 +4,19 @@
|
|||
#ifndef RZ_IL_VM_LAYER_H
|
||||
#define RZ_IL_VM_LAYER_H
|
||||
#include <rz_il/rzil_vm.h>
|
||||
#include <rz_util.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// VM high level operations
|
||||
RZ_API RzILVM *rz_il_vm_new(ut64 start_addr, ut32 addr_size, ut32 data_size);
|
||||
RZ_API RzILVM *rz_il_vm_new(ut64 start_addr, ut32 addr_size, bool big_endian);
|
||||
RZ_API void rz_il_vm_free(RzILVM *vm);
|
||||
RZ_API bool rz_il_vm_init(RzILVM *vm, ut64 start_addr, ut32 addr_size, ut32 data_size);
|
||||
RZ_API bool rz_il_vm_init(RzILVM *vm, ut64 start_addr, ut32 addr_size, bool big_endian);
|
||||
RZ_API void rz_il_vm_fini(RzILVM *vm);
|
||||
RZ_API void rz_il_vm_add_mem(RzILVM *vm, RzILMemIndex index, RZ_OWN RzILMem *mem);
|
||||
RZ_API RzILMem *rz_il_vm_get_mem(RzILVM *vm, RzILMemIndex index);
|
||||
RZ_API void rz_il_vm_step(RzILVM *vm, RzILOp *root);
|
||||
RZ_API void rz_il_vm_list_step(RzILVM *vm, RzPVector *op_list, ut32 op_size);
|
||||
|
||||
|
|
@ -21,10 +24,10 @@ RZ_API void rz_il_vm_list_step(RzILVM *vm, RzPVector *op_list, ut32 op_size);
|
|||
RZ_API void rz_il_vm_event_add(RzILVM *vm, RzILEvent *evt);
|
||||
|
||||
// Memory operations
|
||||
RZ_API RzILMem *rz_il_vm_add_mem(RzILVM *vm, ut32 min_unit_size);
|
||||
RZ_API RzBitVector *rz_il_vm_mem_load(RzILVM *vm, ut32 mem_index, RzBitVector *key);
|
||||
RZ_API RzILMem *rz_il_vm_mem_store(RzILVM *vm, ut32 mem_index, RzBitVector *key, RzBitVector *value);
|
||||
RZ_API RzILMem *rz_il_vm_mem_store_zero(RzILVM *vm, ut32 mem_index, RzBitVector *key, RzBitVector **value);
|
||||
RZ_API RzBitVector *rz_il_vm_mem_load(RzILVM *vm, RzILMemIndex index, RzBitVector *key);
|
||||
RZ_API void rz_il_vm_mem_store(RzILVM *vm, RzILMemIndex index, RzBitVector *key, RzBitVector *value);
|
||||
RZ_API RzBitVector *rz_il_vm_mem_loadw(RzILVM *vm, RzILMemIndex index, RzBitVector *key, ut32 n_bits);
|
||||
RZ_API void rz_il_vm_mem_storew(RzILVM *vm, RzILMemIndex index, RzBitVector *key, RzBitVector *value);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,6 +191,7 @@ typedef struct rz_event_io_map_del_t {
|
|||
|
||||
struct rz_io_bind_t;
|
||||
|
||||
typedef int (*RzIOGetCurrentFd)(RzIO *io);
|
||||
typedef bool (*RzIODescUse)(RzIO *io, int fd);
|
||||
typedef RzIODesc *(*RzIODescGet)(RzIO *io, int fd);
|
||||
typedef ut64 (*RzIODescSize)(RzIODesc *desc);
|
||||
|
|
@ -231,6 +232,7 @@ typedef struct w32dbg_wrap_instance_t *(*RzIOGetW32DbgWrap)(RzIO *io);
|
|||
typedef struct rz_io_bind_t {
|
||||
int init;
|
||||
RzIO *io;
|
||||
RzIOGetCurrentFd fd_get_current;
|
||||
RzIODescUse desc_use;
|
||||
RzIODescGet desc_get;
|
||||
RzIODescSize desc_size;
|
||||
|
|
|
|||
|
|
@ -83,13 +83,18 @@ RZ_API bool rz_bv_is_zero_vector(RZ_NONNULL RzBitVector *x);
|
|||
RZ_API RZ_OWN RzBitVector *rz_bv_new_from_ut64(ut32 length, ut64 value);
|
||||
RZ_API RZ_OWN RzBitVector *rz_bv_new_from_st64(ut32 length, st64 value);
|
||||
RZ_API RZ_OWN RzBitVector *rz_bv_new_from_bytes_le(RZ_IN RZ_NONNULL const ut8 *buf, ut32 bit_offset, ut32 size);
|
||||
RZ_API RZ_OWN RzBitVector *rz_bv_new_from_bytes_be(RZ_IN RZ_NONNULL const ut8 *buf, ut32 bit_offset, ut32 size);
|
||||
RZ_API bool rz_bv_set_from_ut64(RZ_NONNULL RzBitVector *bv, ut64 value);
|
||||
RZ_API bool rz_bv_set_from_st64(RZ_NONNULL RzBitVector *bv, st64 value);
|
||||
RZ_API void rz_bv_set_from_bytes_le(RZ_NONNULL RzBitVector *bv, RZ_IN RZ_NONNULL const ut8 *buf, ut32 bit_offset, ut32 size);
|
||||
RZ_API void rz_bv_set_from_bytes_be(RZ_NONNULL RzBitVector *bv, RZ_IN RZ_NONNULL const ut8 *buf, ut32 bit_offset, ut32 size);
|
||||
RZ_API void rz_bv_set_to_bytes_le(RZ_NONNULL const RzBitVector *bv, RZ_OUT RZ_NONNULL ut8 *buf);
|
||||
RZ_API void rz_bv_set_to_bytes_be(RZ_NONNULL const RzBitVector *bv, RZ_OUT RZ_NONNULL ut8 *buf);
|
||||
RZ_API char *rz_bv_as_string(RZ_NONNULL RzBitVector *bv);
|
||||
RZ_API char *rz_bv_as_hex_string(RZ_NONNULL RzBitVector *bv);
|
||||
|
||||
RZ_API ut32 rz_bv_len(RZ_NONNULL RzBitVector *bv);
|
||||
RZ_API ut32 rz_bv_len(RZ_NONNULL const RzBitVector *bv);
|
||||
RZ_API ut32 rz_bv_len_bytes(RZ_NONNULL const RzBitVector *bv);
|
||||
RZ_API bool rz_bv_cmp(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y);
|
||||
RZ_API ut32 rz_bv_hash(RZ_NULLABLE RzBitVector *x);
|
||||
#define rz_bv_new_zero(l) rz_bv_new(l)
|
||||
|
|
|
|||
|
|
@ -525,6 +525,7 @@ RZ_API void rz_io_bind(RzIO *io, RzIOBind *bnd) {
|
|||
|
||||
bnd->io = io;
|
||||
bnd->init = true;
|
||||
bnd->fd_get_current = rz_io_fd_get_current;
|
||||
bnd->desc_use = rz_io_use_fd;
|
||||
bnd->desc_get = rz_io_desc_get;
|
||||
bnd->desc_size = rz_io_desc_size;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@
|
|||
#define NELEM(N, ELEMPER) ((N + (ELEMPER)-1) / (ELEMPER))
|
||||
#define BV_ELEM_SIZE 8U
|
||||
|
||||
// optimization for reversing 8 bits which uses 32 bits
|
||||
// https://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious
|
||||
#define reverse_byte(x) ((((x)*0x0802LU & 0x22110LU) | ((x)*0x8020LU & 0x88440LU)) * 0x10101LU >> 16)
|
||||
|
||||
/**
|
||||
* \brief Initialize a RzBitVector structure
|
||||
* \param bv Pointer to a uninitialized RzBitVector instance
|
||||
|
|
@ -116,9 +120,7 @@ RZ_API RZ_OWN char *rz_bv_as_hex_string(RZ_NONNULL RzBitVector *bv) {
|
|||
str[1] = 'x';
|
||||
for (ut32 i = 0, j = 2; i < bv->_elem_len; i++, j += 2) {
|
||||
ut8 b8 = bv->bits.large_a[i];
|
||||
// optimization for reversing 8 bits which uses 32 bits
|
||||
// https://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious
|
||||
b8 = ((b8 * 0x0802LU & 0x22110LU) | (b8 * 0x8020LU & 0x88440LU)) * 0x10101LU >> 16;
|
||||
b8 = reverse_byte(b8);
|
||||
str[j + 0] = hex[b8 >> 4];
|
||||
str[j + 1] = hex[b8 & 15];
|
||||
}
|
||||
|
|
@ -1092,15 +1094,32 @@ RZ_API bool rz_bv_cmp(RZ_NONNULL RzBitVector *x, RZ_NONNULL RzBitVector *y) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the length of bitvector
|
||||
* Get the length of bitvector in bits
|
||||
* \param bv RzBitVector
|
||||
* \return len ut32, length of bitvector
|
||||
* \return len ut32, length of bitvector in bits
|
||||
*/
|
||||
RZ_API ut32 rz_bv_len(RZ_NONNULL RzBitVector *bv) {
|
||||
RZ_API ut32 rz_bv_len(RZ_NONNULL const RzBitVector *bv) {
|
||||
rz_return_val_if_fail(bv, 0);
|
||||
return bv->len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the length of bitvector in bytes
|
||||
* \param bv RzBitVector
|
||||
* \return len ut32, length of bitvector in bytes
|
||||
*/
|
||||
RZ_API ut32 rz_bv_len_bytes(RZ_NONNULL const RzBitVector *bv) {
|
||||
rz_return_val_if_fail(bv, 0);
|
||||
if (bv->len > 64) {
|
||||
return bv->_elem_len;
|
||||
}
|
||||
ut32 align = bv->len;
|
||||
if (align & 3) {
|
||||
align += 8 - (align & 3);
|
||||
}
|
||||
return align >> 3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert ut64 to `length`-bits bitvector
|
||||
* \param length ut32, length of bitvector
|
||||
|
|
@ -1138,7 +1157,7 @@ RZ_API RZ_OWN RzBitVector *rz_bv_new_from_st64(ut32 length, st64 value) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Create a new bitvector of size bits and apply rz_bv_set_from_bytes_le() to it
|
||||
* Create a new bitvector of \p size bits and apply rz_bv_set_from_bytes_le() to it
|
||||
*/
|
||||
RZ_API RZ_OWN RzBitVector *rz_bv_new_from_bytes_le(RZ_IN RZ_NONNULL const ut8 *buf, ut32 bit_offset, ut32 size) {
|
||||
rz_return_val_if_fail(buf, NULL);
|
||||
|
|
@ -1150,6 +1169,19 @@ RZ_API RZ_OWN RzBitVector *rz_bv_new_from_bytes_le(RZ_IN RZ_NONNULL const ut8 *b
|
|||
return bv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new bitvector of \p size bits and apply rz_bv_set_from_bytes_be() to it
|
||||
*/
|
||||
RZ_API RZ_OWN RzBitVector *rz_bv_new_from_bytes_be(RZ_IN RZ_NONNULL const ut8 *buf, ut32 bit_offset, ut32 size) {
|
||||
rz_return_val_if_fail(buf, NULL);
|
||||
RzBitVector *bv = rz_bv_new(size);
|
||||
if (!bv) {
|
||||
return NULL;
|
||||
}
|
||||
rz_bv_set_from_bytes_be(bv, buf, bit_offset, size);
|
||||
return bv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert ut64 to N-bits bitvector
|
||||
* \param bv RzBitVector, pointer to bitvector
|
||||
|
|
@ -1213,12 +1245,84 @@ RZ_API void rz_bv_set_from_bytes_le(RZ_NONNULL RzBitVector *bv, RZ_IN RZ_NONNULL
|
|||
for (ut32 i = 0; i < bv->len; i++) {
|
||||
bool bit = false;
|
||||
if (i < size) {
|
||||
bit = !!(buf[(bit_offset + i) >> 3] & (1 << ((bit_offset + i) & 7)));
|
||||
ut32 idx = (bit_offset + i) >> 3;
|
||||
ut32 sh = (bit_offset + i) & 7;
|
||||
bit = (buf[idx] >> sh) & 1;
|
||||
}
|
||||
rz_bv_set(bv, i, bit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the bitvector's contents from the given bits. The bitvector's size is unchanged.
|
||||
* If bv->len < size, additional bits are cut off, if bv->len > size, the rest is filled up with 0.
|
||||
* \param buf big endian buffer of at least (bit_offset + size + 7) / 8 bytes
|
||||
* \param bit_offset offset inside buf to start reading from, in bits
|
||||
* \param size number of bits to read from buf
|
||||
*/
|
||||
RZ_API void rz_bv_set_from_bytes_be(RZ_NONNULL RzBitVector *bv, RZ_IN RZ_NONNULL const ut8 *buf, ut32 bit_offset, ut32 size) {
|
||||
rz_return_if_fail(buf && size);
|
||||
size = RZ_MIN(size, bv->len);
|
||||
// upper bits goes always in the upper bit of the bitv
|
||||
for (ut32 i = 0; i < bv->len; i++) {
|
||||
bool bit = false;
|
||||
if (i < size) {
|
||||
ut32 idx = (bit_offset + i) >> 3;
|
||||
ut32 sh = ((bit_offset + i) & 7);
|
||||
ut8 b8 = buf[idx];
|
||||
b8 = reverse_byte(b8);
|
||||
bit = (b8 >> sh) & 1;
|
||||
}
|
||||
rz_bv_set(bv, bv->len - 1 - i, bit);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the buffer contents from the given bitvector's bits in little endian format.
|
||||
* \param bv BitVector to use as source of the bits
|
||||
* \param buf buffer to write little endian data.
|
||||
*/
|
||||
RZ_API void rz_bv_set_to_bytes_le(RZ_NONNULL const RzBitVector *bv, RZ_OUT RZ_NONNULL ut8 *buf) {
|
||||
rz_return_if_fail(bv && buf);
|
||||
ut32 bytes = rz_bv_len_bytes(bv);
|
||||
if (bv->len > 64) {
|
||||
for (ut32 i = 0; i < bytes; i++) {
|
||||
ut8 b8 = bv->bits.large_a[i];
|
||||
buf[i] = reverse_byte(b8);
|
||||
}
|
||||
return;
|
||||
}
|
||||
ut64 val = bv->bits.small_u;
|
||||
for (ut32 i = 0; i < bytes; i++) {
|
||||
buf[i] = val & 0xFF;
|
||||
val >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the buffer contents from the given bitvector's bits in big endian format.
|
||||
* \param bv BitVector to use as source of the bits
|
||||
* \param buf buffer to write big endian data.
|
||||
*/
|
||||
RZ_API void rz_bv_set_to_bytes_be(RZ_NONNULL const RzBitVector *bv, RZ_OUT RZ_NONNULL ut8 *buf) {
|
||||
rz_return_if_fail(bv && buf);
|
||||
ut32 bytes = rz_bv_len_bytes(bv);
|
||||
if (bv->len > 64) {
|
||||
ut32 end = bytes - 1;
|
||||
for (ut32 i = 0; i < bytes; i++) {
|
||||
ut8 b8 = bv->bits.large_a[i];
|
||||
buf[end - i] = reverse_byte(b8);
|
||||
}
|
||||
return;
|
||||
}
|
||||
ut64 val = bv->bits.small_u;
|
||||
for (ut32 i = bytes - 1; i; i--) {
|
||||
buf[i] = val & 0xFF;
|
||||
val >>= 8;
|
||||
}
|
||||
buf[0] = val & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the hash from the bitvector data
|
||||
* \param x BitVector
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ aezsu 0x10
|
|||
aezv
|
||||
EOF
|
||||
EXPECT=<<EOF
|
||||
PC: 0x0000000000000010 ptr: 0x0000000000000001
|
||||
PC: 0x0000000000000010 ptr: 0x0000000000010001
|
||||
EOF
|
||||
RUN
|
||||
|
||||
|
|
@ -25,10 +25,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
|
||||
|
|
|
|||
2340
test/db/rzil/bf
2340
test/db/rzil/bf
File diff suppressed because it is too large
Load diff
|
|
@ -4,9 +4,7 @@
|
|||
#include <rz_util.h>
|
||||
#include "minunit.h"
|
||||
|
||||
static bool is_equal_bv(RzBitVector *x, RzBitVector *y) {
|
||||
return rz_bv_cmp(x, y) == 0;
|
||||
}
|
||||
#define is_equal_bv(x, y) (!rz_bv_cmp(x, y))
|
||||
|
||||
bool test_rz_bv_init32(void) {
|
||||
char *s = NULL;
|
||||
|
|
@ -492,6 +490,92 @@ bool test_rz_bv_cast(void) {
|
|||
mu_end;
|
||||
}
|
||||
|
||||
bool test_rz_bv_set_from_bytes_be(void) {
|
||||
const ut8 data[0x10] = {
|
||||
0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01,
|
||||
0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe
|
||||
};
|
||||
RzBitVector bv;
|
||||
rz_bv_init(&bv, 64);
|
||||
rz_bv_set_from_bytes_be(&bv, data, 0, 64);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xefcdab8967452301", "aligned 64");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 0, 62);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xefcdab8967452300", "aligned 64, padding");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 0, 100);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xefcdab8967452301", "aligned 64, cut off");
|
||||
rz_bv_fini(&bv);
|
||||
rz_bv_init(&bv, 42);
|
||||
rz_bv_set_from_bytes_be(&bv, data, 0, 42);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0x3bf36ae259d", "aligned 42");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 0, 40);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0x3bf36ae259c", "aligned 42, padding");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 0, 100);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0x3bf36ae259d", "aligned 42, cut off");
|
||||
rz_bv_fini(&bv);
|
||||
rz_bv_init(&bv, 80);
|
||||
rz_bv_set_from_bytes_be(&bv, data, 0, 80);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xefcdab89674523011032", "aligned 80");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 0, 78);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xefcdab89674523011030", "aligned 80, padding");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 0, 100);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xefcdab89674523011032", "aligned 80, cut off");
|
||||
rz_bv_fini(&bv);
|
||||
rz_bv_init(&bv, 64);
|
||||
rz_bv_set_from_bytes_be(&bv, data, 1, 64);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xdf9b5712ce8a4602", "off+1 64");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 1, 62);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xdf9b5712ce8a4600", "off+1, padding");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 1, 100);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xdf9b5712ce8a4602", "off+1 64, cut off");
|
||||
rz_bv_fini(&bv);
|
||||
rz_bv_init(&bv, 42);
|
||||
rz_bv_set_from_bytes_be(&bv, data, 1, 42);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0x37e6d5c4b3a", "off+1 42");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 1, 40);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0x37e6d5c4b38", "off+1 42, padding");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 1, 100);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0x37e6d5c4b3a", "off+1 42, cut off");
|
||||
rz_bv_fini(&bv);
|
||||
rz_bv_init(&bv, 80);
|
||||
rz_bv_set_from_bytes_be(&bv, data, 1, 80);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xdf9b5712ce8a46022064", "off+1 80");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 1, 78);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xdf9b5712ce8a46022064", "off+1 80, padding");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 1, 100);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xdf9b5712ce8a46022064", "off+1 80, cut off");
|
||||
rz_bv_fini(&bv);
|
||||
rz_bv_init(&bv, 64);
|
||||
rz_bv_set_from_bytes_be(&bv, data, 7, 64);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xe6d5c4b3a2918088", "off+7 64");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 7, 62);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xe6d5c4b3a2918088", "off+7, padding");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 7, 100);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xe6d5c4b3a2918088", "off+7 64, cut off");
|
||||
rz_bv_fini(&bv);
|
||||
rz_bv_init(&bv, 42);
|
||||
rz_bv_set_from_bytes_be(&bv, data, 7, 42);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0x39b5712ce8a", "off+7 42");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 7, 40);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0x39b5712ce88", "off+7 42, padding");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 7, 100);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0x39b5712ce8a", "off+7 42, cut off");
|
||||
rz_bv_fini(&bv);
|
||||
rz_bv_init(&bv, 80);
|
||||
rz_bv_set_from_bytes_be(&bv, data, 7, 80);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xe6d5c4b3a2918088192a", "off+7 80");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 7, 78);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xe6d5c4b3a29180881928", "off+7 80, padding");
|
||||
rz_bv_set_from_bytes_be(&bv, data, 7, 100);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(&bv), "0xe6d5c4b3a2918088192a", "off+7 80, cut off");
|
||||
rz_bv_fini(&bv);
|
||||
|
||||
RzBitVector *hbv = rz_bv_new_from_bytes_be(data, 0, 64);
|
||||
mu_assert_streq_free(rz_bv_as_hex_string(hbv), "0xefcdab8967452301", "aligned 64");
|
||||
rz_bv_free(hbv);
|
||||
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool test_rz_bv_set_from_bytes_le(void) {
|
||||
const ut8 data[0x10] = {
|
||||
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
|
||||
|
|
@ -590,6 +674,7 @@ bool all_tests() {
|
|||
mu_run_test(test_rz_bv_algorithm32);
|
||||
mu_run_test(test_rz_bv_algorithm128);
|
||||
mu_run_test(test_rz_bv_set_from_bytes_le);
|
||||
mu_run_test(test_rz_bv_set_from_bytes_be);
|
||||
return tests_passed != tests_run;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,10 +5,6 @@
|
|||
#include <rz_util.h>
|
||||
#include "minunit.h"
|
||||
|
||||
static bool is_equal_bv(RzBitVector *x, RzBitVector *y) {
|
||||
return rz_bv_cmp(x, y) == 0;
|
||||
}
|
||||
|
||||
static bool is_equal_bool(RzILBool *x, RzILBool *y) {
|
||||
return x->b == y->b;
|
||||
}
|
||||
|
|
@ -90,37 +86,161 @@ bool test_rzil_bool_logic(void) {
|
|||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_rzil_mem() {
|
||||
RzILMem *mem = rz_il_mem_new(8);
|
||||
static bool test_rzil_mem_load() {
|
||||
ut8 data[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x0, 0x0 };
|
||||
RzBuffer *buf = rz_buf_new_with_pointers(data, sizeof(data), false);
|
||||
rz_buf_set_overflow_byte(buf, 0xaa);
|
||||
RzILMem *mem = rz_il_mem_new(buf, 16);
|
||||
mu_assert_notnull(mem, "Create mem");
|
||||
|
||||
RzBitVector *addr = rz_bv_new_from_ut64(16, 121);
|
||||
RzBitVector *valid_data = rz_bv_new_from_ut64(8, 177);
|
||||
RzBitVector *invalid_data = rz_bv_new_from_ut64(4, 6);
|
||||
// valid read
|
||||
RzBitVector *addr = rz_bv_new_from_ut64(16, 5);
|
||||
RzBitVector *val = rz_il_mem_load(mem, addr);
|
||||
mu_assert_notnull(val, "load success");
|
||||
mu_assert_eq(rz_bv_len(val), 8, "load size");
|
||||
mu_assert_eq(rz_bv_to_ut64(val), 0x42, "load val");
|
||||
rz_bv_free(val);
|
||||
rz_bv_free(addr);
|
||||
|
||||
RzILMem *result = rz_il_mem_store(mem, addr, valid_data);
|
||||
mu_assert_eq(result, mem, "Store successfully");
|
||||
// invalid key size
|
||||
addr = rz_bv_new_from_ut64(8, 1);
|
||||
val = rz_il_mem_load(mem, addr);
|
||||
mu_assert_null(val, "invalid key size");
|
||||
rz_bv_free(addr);
|
||||
|
||||
result = rz_il_mem_store(mem, addr, invalid_data);
|
||||
mu_assert_null(result, "Unmatched type");
|
||||
// valid read (overflow)
|
||||
addr = rz_bv_new_from_ut64(16, 100);
|
||||
val = rz_il_mem_load(mem, addr);
|
||||
mu_assert_notnull(val, "load success");
|
||||
mu_assert_eq(rz_bv_len(val), 8, "load size");
|
||||
mu_assert_eq(rz_bv_to_ut64(val), 0xaa, "load val");
|
||||
rz_bv_free(val);
|
||||
|
||||
RzBitVector *data = rz_il_mem_load(mem, addr);
|
||||
mu_assert("Load correct data", is_equal_bv(data, valid_data));
|
||||
rz_bv_free(data);
|
||||
|
||||
rz_bv_free(valid_data);
|
||||
rz_bv_free(invalid_data);
|
||||
rz_bv_free(addr);
|
||||
rz_il_mem_free(mem);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_rzil_mem_store() {
|
||||
ut8 data[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x42, 0x0, 0x0 };
|
||||
RzBuffer *buf = rz_buf_new_with_pointers(data, sizeof(data), false);
|
||||
RzILMem *mem = rz_il_mem_new(buf, 16);
|
||||
mu_assert_notnull(mem, "Create mem");
|
||||
|
||||
RzBitVector *addr = rz_bv_new_from_ut64(16, 1);
|
||||
|
||||
// valid write
|
||||
RzBitVector *val = rz_bv_new_from_ut64(8, 177);
|
||||
bool succ = rz_il_mem_store(mem, addr, val);
|
||||
rz_bv_free(val);
|
||||
mu_assert_true(succ, "Store successfully");
|
||||
const ut8 expect0[] = { 0x0, 177, 0x0, 0x0, 0x0, 0x42, 0x0, 0x0 };
|
||||
mu_assert_memeq(data, expect0, sizeof(expect0), "stored");
|
||||
|
||||
// invalid data size
|
||||
val = rz_bv_new_from_ut64(4, 2);
|
||||
succ = rz_il_mem_store(mem, addr, val);
|
||||
rz_bv_free(val);
|
||||
mu_assert_false(succ, "Unmatched value type");
|
||||
mu_assert_memeq(data, expect0, sizeof(expect0), "not stored");
|
||||
|
||||
// invalid key size
|
||||
rz_bv_free(addr);
|
||||
addr = rz_bv_new_from_ut64(8, 1);
|
||||
val = rz_bv_new_from_ut64(8, 177);
|
||||
succ = rz_il_mem_store(mem, addr, val);
|
||||
rz_bv_free(val);
|
||||
mu_assert_false(succ, "invalid key size");
|
||||
mu_assert_memeq(data, expect0, sizeof(expect0), "not stored");
|
||||
|
||||
rz_bv_free(addr);
|
||||
rz_il_mem_free(mem);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_rzil_mem_loadw() {
|
||||
ut8 data[] = { 0x0, 0x0, 0x0, 0x0, 0x13, 0x37, 0x0, 0x0 };
|
||||
RzBuffer *buf = rz_buf_new_with_pointers(data, sizeof(data), false);
|
||||
rz_buf_set_overflow_byte(buf, 0xaa);
|
||||
RzILMem *mem = rz_il_mem_new(buf, 16);
|
||||
mu_assert_notnull(mem, "Create mem");
|
||||
|
||||
// valid read (le)
|
||||
RzBitVector *addr = rz_bv_new_from_ut64(16, 4);
|
||||
RzBitVector *val = rz_il_mem_loadw(mem, addr, 16, false);
|
||||
mu_assert_notnull(val, "loadw success");
|
||||
mu_assert_eq(rz_bv_len(val), 16, "loadw size");
|
||||
mu_assert_eq(rz_bv_to_ut64(val), 0x3713, "loadw val");
|
||||
rz_bv_free(val);
|
||||
|
||||
// valid read (be)
|
||||
val = rz_il_mem_loadw(mem, addr, 16, true);
|
||||
mu_assert_notnull(val, "loadw success");
|
||||
mu_assert_eq(rz_bv_len(val), 16, "loadw size");
|
||||
mu_assert_eq(rz_bv_to_ut64(val), 0x1337, "loadw val");
|
||||
rz_bv_free(val);
|
||||
|
||||
// invalid key size
|
||||
rz_bv_free(addr);
|
||||
addr = rz_bv_new_from_ut64(8, 1);
|
||||
val = rz_il_mem_loadw(mem, addr, 16, false);
|
||||
mu_assert_null(val, "invalid key size");
|
||||
|
||||
// valid read (overflow)
|
||||
addr = rz_bv_new_from_ut64(16, 100);
|
||||
val = rz_il_mem_loadw(mem, addr, 16, false);
|
||||
mu_assert_notnull(val, "load success");
|
||||
mu_assert_eq(rz_bv_len(val), 16, "load size");
|
||||
mu_assert_eq(rz_bv_to_ut64(val), 0xaaaa, "load val");
|
||||
rz_bv_free(val);
|
||||
|
||||
rz_bv_free(addr);
|
||||
rz_il_mem_free(mem);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_rzil_mem_storew() {
|
||||
ut8 data[] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
|
||||
RzBuffer *buf = rz_buf_new_with_pointers(data, sizeof(data), false);
|
||||
RzILMem *mem = rz_il_mem_new(buf, 32);
|
||||
mu_assert_notnull(mem, "Create mem");
|
||||
|
||||
// valid write (le)
|
||||
RzBitVector *addr = rz_bv_new_from_ut64(32, 4);
|
||||
RzBitVector *val = rz_bv_new_from_ut64(16, 0x1337);
|
||||
bool succ = rz_il_mem_storew(mem, addr, val, false);
|
||||
rz_bv_free(addr);
|
||||
mu_assert_true(succ, "storew success");
|
||||
const ut8 expect0[] = { 0x0, 0x0, 0x0, 0x0, 0x37, 0x13, 0x0, 0x0 };
|
||||
mu_assert_memeq(data, expect0, sizeof(expect0), "stored");
|
||||
|
||||
// valid write (be)
|
||||
addr = rz_bv_new_from_ut64(32, 2);
|
||||
succ = rz_il_mem_storew(mem, addr, val, true);
|
||||
mu_assert_true(succ, "storew success");
|
||||
const ut8 expect1[] = { 0x0, 0x0, 0x13, 0x37, 0x37, 0x13, 0x0, 0x0 };
|
||||
mu_assert_memeq(data, expect1, sizeof(expect1), "stored");
|
||||
rz_bv_free(val);
|
||||
rz_bv_free(addr);
|
||||
|
||||
// invalid key size
|
||||
addr = rz_bv_new_from_ut64(8, 1);
|
||||
val = rz_il_mem_load(mem, addr);
|
||||
mu_assert_null(val, "invalid key size");
|
||||
mu_assert_memeq(data, expect1, sizeof(expect1), "not stored");
|
||||
rz_bv_free(addr);
|
||||
|
||||
rz_il_mem_free(mem);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool all_tests() {
|
||||
mu_run_test(test_rzil_bool_init);
|
||||
mu_run_test(test_rzil_bool_logic);
|
||||
|
||||
mu_run_test(test_rzil_mem);
|
||||
mu_run_test(test_rzil_mem_load);
|
||||
mu_run_test(test_rzil_mem_store);
|
||||
mu_run_test(test_rzil_mem_loadw);
|
||||
mu_run_test(test_rzil_mem_storew);
|
||||
return tests_passed != tests_run;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,14 +6,14 @@
|
|||
#include "minunit.h"
|
||||
|
||||
static bool test_rzil_vm_init() {
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, 8);
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, true);
|
||||
mu_assert_eq(vm->addr_size, 8, "VM Init");
|
||||
rz_il_vm_free(vm);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_rzil_vm_basic_operation() {
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, 16);
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, true);
|
||||
|
||||
// 1. create variables
|
||||
RzILVar *var_r1 = rz_il_vm_create_global_variable(vm, "r1", RZIL_VAR_TYPE_UNK, true);
|
||||
|
|
@ -107,7 +107,7 @@ static bool test_rzil_vm_basic_operation() {
|
|||
}
|
||||
|
||||
static bool test_rzil_vm_operation() {
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, 16);
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, false);
|
||||
|
||||
// 1. create register r0 and r1
|
||||
rz_il_vm_add_reg(vm, "r0", 8);
|
||||
|
|
@ -137,7 +137,7 @@ static bool test_rzil_vm_operation() {
|
|||
}
|
||||
|
||||
static bool test_rzil_vm_root_evaluation() {
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, 16);
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, false);
|
||||
|
||||
// (ite (add 23 19)
|
||||
// true
|
||||
|
|
@ -170,7 +170,7 @@ static bool test_rzil_vm_root_evaluation() {
|
|||
}
|
||||
|
||||
static bool test_rzil_vm_op_set() {
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, 16);
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, false);
|
||||
|
||||
RzILVar *var_r1 = rz_il_vm_create_global_variable(vm, "r1", RZIL_VAR_TYPE_UNK, true);
|
||||
RzILVar *var_r2 = rz_il_vm_create_global_variable(vm, "r2", RZIL_VAR_TYPE_UNK, false);
|
||||
|
|
@ -204,7 +204,7 @@ static bool test_rzil_vm_op_set() {
|
|||
}
|
||||
|
||||
static bool test_rzil_vm_op_jmp() {
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, 16);
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, false);
|
||||
|
||||
RzILOp *op = rz_il_op_new_jmp(rz_il_op_new_bitv_from_ut64(8, 0x42));
|
||||
RzILOpArgType tret = RZIL_OP_ARG_INIT;
|
||||
|
|
@ -217,7 +217,7 @@ static bool test_rzil_vm_op_jmp() {
|
|||
}
|
||||
|
||||
static bool test_rzil_vm_op_goto_addr() {
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, 16);
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, false);
|
||||
|
||||
RzBitVector *dst = rz_bv_new_from_ut64(8, 0x42);
|
||||
rz_il_vm_create_label(vm, "beach", dst);
|
||||
|
|
@ -239,7 +239,7 @@ static void hook_test(RzILVM *vm, RzILOp *op) {
|
|||
}
|
||||
|
||||
static bool test_rzil_vm_op_goto_hook() {
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, 16);
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, false);
|
||||
|
||||
RzILVar *var = rz_il_vm_create_global_variable(vm, "myvar", RZIL_VAR_TYPE_UNK, true);
|
||||
rz_il_hash_bind(vm, var, rz_il_vm_create_value_bitv(vm, rz_bv_new_zero(32)));
|
||||
|
|
@ -264,6 +264,128 @@ static bool test_rzil_vm_op_goto_hook() {
|
|||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_rzil_vm_op_load() {
|
||||
const ut8 data[] = { 0x0, 0x1, 0x2, 0x42, 0x4, 0x5 };
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, false);
|
||||
RzBuffer *buf = rz_buf_new_with_pointers(data, sizeof(data), false);
|
||||
rz_buf_set_overflow_byte(buf, 0xaa);
|
||||
rz_il_vm_add_mem(vm, 0, rz_il_mem_new(buf, 16));
|
||||
rz_buf_free(buf);
|
||||
|
||||
RzILOp *op = rz_il_op_new_load(0, rz_il_op_new_bitv_from_ut64(16, 3));
|
||||
RzILOpArgType tret = RZIL_OP_ARG_INIT;
|
||||
RzBitVector *res = rz_il_evaluate_bitv(vm, op, &tret);
|
||||
rz_il_op_free(op);
|
||||
mu_assert_notnull(res, "eval res");
|
||||
mu_assert_eq(rz_bv_len(res), 8, "res byte size");
|
||||
mu_assert_eq(rz_bv_to_ut64(res), 0x42, "res value");
|
||||
|
||||
op = rz_il_op_new_load(0, rz_il_op_new_bitv_from_ut64(16, 100));
|
||||
tret = RZIL_OP_ARG_INIT;
|
||||
res = rz_il_evaluate_bitv(vm, op, &tret);
|
||||
rz_il_op_free(op);
|
||||
mu_assert_notnull(res, "eval res");
|
||||
mu_assert_eq(rz_bv_len(res), 8, "res byte size");
|
||||
mu_assert_eq(rz_bv_to_ut64(res), 0xaa, "res value (overflow)");
|
||||
|
||||
rz_il_vm_free(vm);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_rzil_vm_op_store() {
|
||||
ut8 data[] = { 0x0, 0x1, 0x2, 0x42, 0x4, 0x5 };
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, false);
|
||||
RzBuffer *buf = rz_buf_new_with_pointers(data, sizeof(data), false);
|
||||
rz_il_vm_add_mem(vm, 0, rz_il_mem_new(buf, 16));
|
||||
rz_buf_free(buf);
|
||||
|
||||
RzILOp *op = rz_il_op_new_store(0, rz_il_op_new_bitv_from_ut64(16, 2), rz_il_op_new_bitv_from_ut64(8, 0xab));
|
||||
RzILOpArgType tret = RZIL_OP_ARG_INIT;
|
||||
rz_il_evaluate_effect(vm, op, &tret);
|
||||
rz_il_op_free(op);
|
||||
ut8 expect[] = { 0x0, 0x1, 0xab, 0x42, 0x4, 0x5 };
|
||||
mu_assert_memeq(data, expect, sizeof(expect), "stored");
|
||||
|
||||
rz_il_vm_free(vm);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_rzil_vm_op_loadw_le() {
|
||||
const ut8 data[] = { 0x0, 0x1, 0x2, 0x42, 0x4, 0x5 };
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, false);
|
||||
RzBuffer *buf = rz_buf_new_with_pointers(data, sizeof(data), false);
|
||||
rz_buf_set_overflow_byte(buf, 0xaa);
|
||||
rz_il_vm_add_mem(vm, 0, rz_il_mem_new(buf, 16));
|
||||
rz_buf_free(buf);
|
||||
|
||||
RzILOp *op = rz_il_op_new_loadw(0, rz_il_op_new_bitv_from_ut64(16, 3), 16);
|
||||
RzILOpArgType tret = RZIL_OP_ARG_INIT;
|
||||
RzBitVector *res = rz_il_evaluate_bitv(vm, op, &tret);
|
||||
rz_il_op_free(op);
|
||||
mu_assert_notnull(res, "eval res");
|
||||
mu_assert_eq(rz_bv_len(res), 16, "res byte size");
|
||||
mu_assert_eq(rz_bv_to_ut64(res), 0x442, "res value");
|
||||
|
||||
rz_il_vm_free(vm);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_rzil_vm_op_storew_le() {
|
||||
ut8 data[] = { 0x0, 0x1, 0x2, 0x42, 0x4, 0x5 };
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, false);
|
||||
RzBuffer *buf = rz_buf_new_with_pointers(data, sizeof(data), false);
|
||||
rz_il_vm_add_mem(vm, 0, rz_il_mem_new(buf, 16));
|
||||
rz_buf_free(buf);
|
||||
|
||||
RzILOp *op = rz_il_op_new_storew(0, rz_il_op_new_bitv_from_ut64(16, 2), rz_il_op_new_bitv_from_ut64(16, 0xabcd));
|
||||
RzILOpArgType tret = RZIL_OP_ARG_INIT;
|
||||
rz_il_evaluate_effect(vm, op, &tret);
|
||||
rz_il_op_free(op);
|
||||
ut8 expect[] = { 0x0, 0x1, 0xcd, 0xab, 0x4, 0x5 };
|
||||
mu_assert_memeq(data, expect, sizeof(expect), "stored");
|
||||
|
||||
rz_il_vm_free(vm);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_rzil_vm_op_loadw_be() {
|
||||
const ut8 data[] = { 0x0, 0x1, 0x2, 0x42, 0x4, 0x5 };
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, true);
|
||||
RzBuffer *buf = rz_buf_new_with_pointers(data, sizeof(data), false);
|
||||
rz_buf_set_overflow_byte(buf, 0xaa);
|
||||
rz_il_vm_add_mem(vm, 0, rz_il_mem_new(buf, 16));
|
||||
rz_buf_free(buf);
|
||||
|
||||
RzILOp *op = rz_il_op_new_loadw(0, rz_il_op_new_bitv_from_ut64(16, 3), 16);
|
||||
RzILOpArgType tret = RZIL_OP_ARG_INIT;
|
||||
RzBitVector *res = rz_il_evaluate_bitv(vm, op, &tret);
|
||||
rz_il_op_free(op);
|
||||
mu_assert_notnull(res, "eval res");
|
||||
mu_assert_eq(rz_bv_len(res), 16, "res byte size");
|
||||
mu_assert_eq(rz_bv_to_ut64(res), 0x4204, "res value");
|
||||
|
||||
rz_il_vm_free(vm);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
static bool test_rzil_vm_op_storew_be() {
|
||||
ut8 data[] = { 0x0, 0x1, 0x2, 0x42, 0x4, 0x5 };
|
||||
RzILVM *vm = rz_il_vm_new(0, 8, true);
|
||||
RzBuffer *buf = rz_buf_new_with_pointers(data, sizeof(data), false);
|
||||
rz_il_vm_add_mem(vm, 0, rz_il_mem_new(buf, 16));
|
||||
rz_buf_free(buf);
|
||||
|
||||
RzILOp *op = rz_il_op_new_storew(0, rz_il_op_new_bitv_from_ut64(16, 2), rz_il_op_new_bitv_from_ut64(16, 0xabcd));
|
||||
RzILOpArgType tret = RZIL_OP_ARG_INIT;
|
||||
rz_il_evaluate_effect(vm, op, &tret);
|
||||
rz_il_op_free(op);
|
||||
ut8 expect[] = { 0x0, 0x1, 0xab, 0xcd, 0x4, 0x5 };
|
||||
mu_assert_memeq(data, expect, sizeof(expect), "stored");
|
||||
|
||||
rz_il_vm_free(vm);
|
||||
mu_end;
|
||||
}
|
||||
|
||||
bool all_tests() {
|
||||
mu_run_test(test_rzil_vm_init);
|
||||
mu_run_test(test_rzil_vm_basic_operation);
|
||||
|
|
@ -273,6 +395,12 @@ bool all_tests() {
|
|||
mu_run_test(test_rzil_vm_op_jmp);
|
||||
mu_run_test(test_rzil_vm_op_goto_addr);
|
||||
mu_run_test(test_rzil_vm_op_goto_hook);
|
||||
mu_run_test(test_rzil_vm_op_load);
|
||||
mu_run_test(test_rzil_vm_op_store);
|
||||
mu_run_test(test_rzil_vm_op_loadw_le);
|
||||
mu_run_test(test_rzil_vm_op_storew_le);
|
||||
mu_run_test(test_rzil_vm_op_loadw_be);
|
||||
mu_run_test(test_rzil_vm_op_storew_be);
|
||||
return tests_passed != tests_run;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue