[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:
Giovanni 2021-12-24 16:53:20 +01:00 committed by GitHub
parent 89d61756c1
commit 5963da2bba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 2059 additions and 1395 deletions

View file

@ -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();

View file

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

View file

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

View file

@ -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);

View file

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

View file

@ -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");

View file

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

View file

@ -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);
}
/**

View file

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

View file

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

View file

@ -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

View file

@ -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

View file

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

View file

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

View file

@ -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)

View file

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

View file

@ -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

View file

@ -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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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