diff --git a/librz/analysis/p/analysis_bf.c b/librz/analysis/p/analysis_bf.c index 6961cbdea4..d7b90b5f5a 100644 --- a/librz/analysis/p/analysis_bf.c +++ b/librz/analysis/p/analysis_bf.c @@ -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(); diff --git a/librz/analysis/rzil/rzil.c b/librz/analysis/rzil/rzil.c index 6f0b903585..dd70a6fe0d 100644 --- a/librz/analysis/rzil/rzil.c +++ b/librz/analysis/rzil/rzil.c @@ -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; diff --git a/librz/il/definitions/mem.c b/librz/il/definitions/mem.c index a3a3c52457..569a2cf847 100644 --- a/librz/il/definitions/mem.c +++ b/librz/il/definitions/mem.c @@ -1,36 +1,29 @@ +// SPDX-FileCopyrightText: 2021 Florian Märkl +// SPDX-FileCopyrightText: 2021 deroad // SPDX-FileCopyrightText: 2021 heersin // SPDX-License-Identifier: LGPL-3.0-only #include -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); } diff --git a/librz/il/rzil_export.c b/librz/il/rzil_export.c index b9e95e7955..148d081bd4 100644 --- a/librz/il/rzil_export.c +++ b/librz/il/rzil_export.c @@ -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); diff --git a/librz/il/rzil_opcodes.c b/librz/il/rzil_opcodes.c index 35f1dde65c..4e65730405 100644 --- a/librz/il/rzil_opcodes.c +++ b/librz/il/rzil_opcodes.c @@ -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; diff --git a/librz/il/rzil_vm.c b/librz/il/rzil_vm.c index 0ffbdeb5e1..b448732bad 100644 --- a/librz/il/rzil_vm.c +++ b/librz/il/rzil_vm.c @@ -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"); diff --git a/librz/il/theory_mem.c b/librz/il/theory_mem.c index 116e8aece4..fe2dcb17dd 100644 --- a/librz/il/theory_mem.c +++ b/librz/il/theory_mem.c @@ -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; } diff --git a/librz/il/vm_layer.c b/librz/il/vm_layer.c index 6f52d18371..a9989ab21f 100644 --- a/librz/il/vm_layer.c +++ b/librz/il/vm_layer.c @@ -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); } /** diff --git a/librz/include/rz_analysis.h b/librz/include/rz_analysis.h index 97f3ea8307..fbd45f0a7b 100644 --- a/librz/include/rz_analysis.h +++ b/librz/include/rz_analysis.h @@ -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; diff --git a/librz/include/rz_il/definitions/mem.h b/librz/include/rz_il/definitions/mem.h index eaada03c87..6d80819305 100644 --- a/librz/include/rz_il/definitions/mem.h +++ b/librz/include/rz_il/definitions/mem.h @@ -1,3 +1,4 @@ +// SPDX-FileCopyrightText: 2021 Florian Märkl // SPDX-FileCopyrightText: 2021 heersin // 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 } diff --git a/librz/include/rz_il/rzil_opcodes.h b/librz/include/rz_il/rzil_opcodes.h index 6a124a0c08..d67b6b0a80 100644 --- a/librz/include/rz_il/rzil_opcodes.h +++ b/librz/include/rz_il/rzil_opcodes.h @@ -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 diff --git a/librz/include/rz_il/rzil_vm.h b/librz/include/rz_il/rzil_vm.h index c44b192068..79f38c8655 100644 --- a/librz/include/rz_il/rzil_vm.h +++ b/librz/include/rz_il/rzil_vm.h @@ -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 /**/ vm_global_variable_list; ///< Store all the global RzILVar instance RzPVector /**/ vm_local_variable_list; ///< Store all the local RzILVar instance - - RzPVector /**/ vm_memory; ///< Array of Memory, memory are actually hashmap in VM + RzPVector /**/ 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 diff --git a/librz/include/rz_il/vm_layer.h b/librz/include/rz_il/vm_layer.h index 4d4aa9c1a9..2385885a68 100644 --- a/librz/include/rz_il/vm_layer.h +++ b/librz/include/rz_il/vm_layer.h @@ -4,16 +4,19 @@ #ifndef RZ_IL_VM_LAYER_H #define RZ_IL_VM_LAYER_H #include +#include #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 } diff --git a/librz/include/rz_io.h b/librz/include/rz_io.h index 96ea6e96eb..f82b0e8b0e 100644 --- a/librz/include/rz_io.h +++ b/librz/include/rz_io.h @@ -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; diff --git a/librz/include/rz_util/rz_bitvector.h b/librz/include/rz_util/rz_bitvector.h index fc5e7b6985..c7b8314c6a 100644 --- a/librz/include/rz_util/rz_bitvector.h +++ b/librz/include/rz_util/rz_bitvector.h @@ -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) diff --git a/librz/io/io.c b/librz/io/io.c index f2e63ca7ff..a1271ece6f 100644 --- a/librz/io/io.c +++ b/librz/io/io.c @@ -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; diff --git a/librz/util/bitvector.c b/librz/util/bitvector.c index e4d3942591..6c8d8c7d63 100644 --- a/librz/util/bitvector.c +++ b/librz/util/bitvector.c @@ -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 diff --git a/test/db/cmd/cmd_aez b/test/db/cmd/cmd_aez index d930b65b5e..4c84cf306b 100644 --- a/test/db/cmd/cmd_aez +++ b/test/db/cmd/cmd_aez @@ -7,7 +7,7 @@ aezsu 0x10 aezv EOF EXPECT=< #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; } diff --git a/test/unit/test_il_definitions.c b/test/unit/test_il_definitions.c index c644586113..afda143fda 100644 --- a/test/unit/test_il_definitions.c +++ b/test/unit/test_il_definitions.c @@ -5,10 +5,6 @@ #include #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; } diff --git a/test/unit/test_il_vm.c b/test/unit/test_il_vm.c index eb3bcab086..705cc0256b 100644 --- a/test/unit/test_il_vm.c +++ b/test/unit/test_il_vm.c @@ -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; }