From 7a8d5af180000bc0a324f9716ecc343e69c9f1d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Wed, 29 Dec 2021 14:15:52 +0100 Subject: [PATCH] [RzIL] Add rz_il_op_new_(unsigned|signed)() --- librz/il/rzil_opcodes.c | 25 ++++++++++++- librz/include/rz_il/rzil_opcodes.h | 4 ++- test/unit/test_il_vm.c | 56 ++++++++++++++++++++++++++++-- 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/librz/il/rzil_opcodes.c b/librz/il/rzil_opcodes.c index 22564a728f..a764098777 100644 --- a/librz/il/rzil_opcodes.c +++ b/librz/il/rzil_opcodes.c @@ -288,6 +288,26 @@ RZ_API RZ_OWN RzILOpBitVector *rz_il_op_new_cast(ut32 length, RZ_NONNULL RzILOpB return ret; } +/** + * \brief Extend val to length bits, filling up with zeroes + * + * For length > val->len, this fits the general notion of zero extension. + */ +RZ_API RZ_OWN RzILOpBitVector *rz_il_op_new_unsigned(ut32 length, RZ_NONNULL RzILOpBitVector *val) { + rz_return_val_if_fail(length && val, NULL); + return rz_il_op_new_cast(length, rz_il_op_new_b0(), val); +} + +/** + * \brief Extend val to length bits, filling up with val's most significant bit + * + * For length > val->len, this fits the general notion of sign extension. + */ +RZ_API RZ_OWN RzILOpBitVector *rz_il_op_new_signed(ut32 length, RZ_NONNULL RzILOpBitVector *val) { + rz_return_val_if_fail(length && val, NULL); + return rz_il_op_new_cast(length, rz_il_op_new_msb(rz_il_op_pure_dup(val)), val); +} + /** * \brief op structure for `neg` ('s bitv -> 's bitv) * @@ -673,7 +693,10 @@ RZ_API RZ_OWN RzILOpEffect *rz_il_op_new_storew(RzILMemIndex mem, RZ_NONNULL RzI #undef rz_il_op_new_2 #undef rz_il_op_new_3 -RZ_API RzILOpPure *rz_il_op_pure_dup(RZ_NULLABLE RzILOpPure *op) { +/** + * Duplicate the given op recursively, for example to reuse it multiple times in another op. + */ +RZ_API RzILOpPure *rz_il_op_pure_dup(RZ_NONNULL RzILOpPure *op) { rz_return_val_if_fail(op, NULL); RzILOpPure *r = RZ_NEW0(RzILOpPure); if (!r) { diff --git a/librz/include/rz_il/rzil_opcodes.h b/librz/include/rz_il/rzil_opcodes.h index 3fc8dddbdf..ad6dae548f 100644 --- a/librz/include/rz_il/rzil_opcodes.h +++ b/librz/include/rz_il/rzil_opcodes.h @@ -439,7 +439,7 @@ struct rz_il_op_pure_t { }; RZ_API void rz_il_op_pure_free(RZ_NULLABLE RzILOpPure *op); -RZ_API RzILOpPure *rz_il_op_pure_dup(RZ_NULLABLE RzILOpPure *op); +RZ_API RzILOpPure *rz_il_op_pure_dup(RZ_NONNULL RzILOpPure *op); RZ_API RZ_OWN RzILOpPure *rz_il_op_new_ite(RZ_NONNULL RzILOpPure *condition, RZ_NULLABLE RzILOpPure *x, RZ_NULLABLE RzILOpPure *y); RZ_API RZ_OWN RzILOpPure *rz_il_op_new_unk(); @@ -461,6 +461,8 @@ RZ_API RZ_OWN RzILOpBool *rz_il_op_new_eq(RZ_NONNULL RzILOpPure *x, RZ_NONNULL R RZ_API RZ_OWN RzILOpBool *rz_il_op_new_ule(RZ_NONNULL RzILOpPure *x, RZ_NONNULL RzILOpPure *y); RZ_API RZ_OWN RzILOpBool *rz_il_op_new_sle(RZ_NONNULL RzILOpPure *x, RZ_NONNULL RzILOpPure *y); RZ_API RZ_OWN RzILOpBitVector *rz_il_op_new_cast(ut32 length, RZ_NONNULL RzILOpBool *fill, RZ_NONNULL RzILOpBitVector *val); +RZ_API RZ_OWN RzILOpBitVector *rz_il_op_new_unsigned(ut32 length, RZ_NONNULL RzILOpBitVector *val); // "zero extension" +RZ_API RZ_OWN RzILOpBitVector *rz_il_op_new_signed(ut32 length, RZ_NONNULL RzILOpBitVector *val); // "sign extension" RZ_API RZ_OWN RzILOpBitVector *rz_il_op_new_neg(RZ_NONNULL RzILOpBitVector *value); RZ_API RZ_OWN RzILOpBitVector *rz_il_op_new_log_not(RZ_NONNULL RzILOpBitVector *value); RZ_API RZ_OWN RzILOpBitVector *rz_il_op_new_add(RZ_NONNULL RzILOpBitVector *x, RZ_NONNULL RzILOpBitVector *y); diff --git a/test/unit/test_il_vm.c b/test/unit/test_il_vm.c index 46e7a80162..8ada672910 100644 --- a/test/unit/test_il_vm.c +++ b/test/unit/test_il_vm.c @@ -189,7 +189,7 @@ static bool test_rzil_vm_op_cast() { mu_assert_eq(rz_bv_to_ut64(r), 0x2, "eval val"); rz_bv_free(r); - // 8 -> 16 (false) + // 8 -> 13 (false) op = rz_il_op_new_cast(13, rz_il_op_new_b0(), rz_il_op_new_bitv_from_ut64(8, 0x42)); r = rz_il_evaluate_bitv(vm, op); rz_il_op_pure_free(op); @@ -198,7 +198,7 @@ static bool test_rzil_vm_op_cast() { mu_assert_eq(rz_bv_to_ut64(r), 0x42, "eval val"); rz_bv_free(r); - // 8 -> 16 (true) + // 8 -> 13 (true) op = rz_il_op_new_cast(13, rz_il_op_new_b1(), rz_il_op_new_bitv_from_ut64(8, 0x42)); r = rz_il_evaluate_bitv(vm, op); rz_il_op_pure_free(op); @@ -211,6 +211,56 @@ static bool test_rzil_vm_op_cast() { mu_end; } +static bool test_rzil_vm_op_unsigned() { + RzILVM *vm = rz_il_vm_new(0, 8, false); + + // msb not set, filled with 0 + RzILOpPure *op = rz_il_op_new_unsigned(13, rz_il_op_new_bitv_from_ut64(8, 0x42)); + RzBitVector *r = rz_il_evaluate_bitv(vm, op); + rz_il_op_pure_free(op); + mu_assert_notnull(r, "eval"); + mu_assert_eq(rz_bv_len(r), 13, "eval length"); + mu_assert_eq(rz_bv_to_ut64(r), 0x42, "eval val"); + rz_bv_free(r); + + // msb set, still filled with 0 + op = rz_il_op_new_unsigned(13, rz_il_op_new_bitv_from_ut64(8, 0xf2)); + r = rz_il_evaluate_bitv(vm, op); + rz_il_op_pure_free(op); + mu_assert_notnull(r, "eval"); + mu_assert_eq(rz_bv_len(r), 13, "eval length"); + mu_assert_eq(rz_bv_to_ut64(r), 0xf2, "eval val"); + rz_bv_free(r); + + rz_il_vm_free(vm); + mu_end; +} + +static bool test_rzil_vm_op_signed() { + RzILVM *vm = rz_il_vm_new(0, 8, false); + + // msb not set, filled with 0 + RzILOpPure *op = rz_il_op_new_signed(13, rz_il_op_new_bitv_from_ut64(8, 0x42)); + RzBitVector *r = rz_il_evaluate_bitv(vm, op); + rz_il_op_pure_free(op); + mu_assert_notnull(r, "eval"); + mu_assert_eq(rz_bv_len(r), 13, "eval length"); + mu_assert_eq(rz_bv_to_ut64(r), 0x42, "eval val"); + rz_bv_free(r); + + // msb set, filled with 1 + op = rz_il_op_new_signed(13, rz_il_op_new_bitv_from_ut64(8, 0xf2)); + r = rz_il_evaluate_bitv(vm, op); + rz_il_op_pure_free(op); + mu_assert_notnull(r, "eval"); + mu_assert_eq(rz_bv_len(r), 13, "eval length"); + mu_assert_eq(rz_bv_to_ut64(r), 0x1ff2, "eval val"); + rz_bv_free(r); + + rz_il_vm_free(vm); + mu_end; +} + static bool test_rzil_vm_op_set() { RzILVM *vm = rz_il_vm_new(0, 8, false); @@ -430,6 +480,8 @@ bool all_tests() { mu_run_test(test_rzil_vm_operation); mu_run_test(test_rzil_vm_root_evaluation); mu_run_test(test_rzil_vm_op_cast); + mu_run_test(test_rzil_vm_op_unsigned); + mu_run_test(test_rzil_vm_op_signed); mu_run_test(test_rzil_vm_op_set); mu_run_test(test_rzil_vm_op_jmp); mu_run_test(test_rzil_vm_op_goto_addr);