diff --git a/librz/analysis/arch/ppc/ppc_il.h b/librz/analysis/arch/ppc/ppc_il.h index bff9ee544ec..c4a190f3d04 100644 --- a/librz/analysis/arch/ppc/ppc_il.h +++ b/librz/analysis/arch/ppc/ppc_il.h @@ -23,15 +23,6 @@ */ #define DCACHE_LINE_SIZE 128 -/** - * \brief Writes to the info log that an unimplemented instruction was encountered and returns an EMPTY() effect. - */ -#define NOT_IMPLEMENTED \ - do { \ - RZ_LOG_INFO("IL instruction not implemented."); \ - return NULL; \ - } while (0) - /** * \brief Unsigned value \p i which is PPC_ARCH_BITS (32 or 64) wide. */ diff --git a/librz/il/il_routines.c b/librz/il/il_routines.c new file mode 100644 index 00000000000..03a1843b471 --- /dev/null +++ b/librz/il/il_routines.c @@ -0,0 +1,213 @@ +// SPDX-FileCopyrightText: 2023 Rot127 +// SPDX-License-Identifier: LGPL-3.0-only + +/** + * \file Implements common bit operation perfomed on values. + */ + +#include +#include +#include + +/** + * \brief Extracts \p length bits from \p start of \p value and returns them as U32. + * + * Performed operation: ((value >> start) & (-0x1 >> 0x20 - length)); + * + * \param value The value to extract the bits from. It must be a bitvector of size 32. + * \param start The start index of the bits to extract. Passed bitvector can be of any width. + * \param length Number of bits to extract. Passed bitvector must be 32bits in size. + * + * \return A 32bit wide bitvector with the extracted value. + */ +RZ_API RZ_OWN RzILOpBitVector *rz_il_extract32(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length) { + rz_return_val_if_fail(value && start && length, NULL); + RzILOpPure *op_RSHIFT_0 = rz_il_op_new_shiftr(rz_il_op_new_b0(), value, start); + RzILOpPure *op_SUB_4 = rz_il_op_new_sub(rz_il_op_new_bitv_from_st64(32, 0x20), length); + RzILOpPure *op_RSHIFT_5 = rz_il_op_new_shiftr(rz_il_op_new_b0(), rz_il_op_new_bitv_from_ut64(32, -1), op_SUB_4); + RzILOpPure *op_AND_6 = rz_il_op_new_log_and(op_RSHIFT_0, op_RSHIFT_5); + return op_AND_6; +} + +/** + * \brief Extracts \p length bits from \p start of \p value and returns them as U64. + * + * Performed operation: ((value >> start) & (-0x1 >> 0x40 - length)); + * + * \param value The value to extract the bits from. It must be a bitvector of size 64. + * \param start The start index of the bits to extract. Passed bitvector can be of any width. + * \param length Number of bits to extract. Passed bitvector must be 32bits in size. + * + * \return A 64bit wide bitvector with the extracted value. + */ +RZ_API RZ_OWN RzILOpBitVector *rz_il_extract64(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length) { + rz_return_val_if_fail(value && start && length, NULL); + RzILOpPure *op_RSHIFT_0 = rz_il_op_new_shiftr(rz_il_op_new_b0(), value, start); + RzILOpPure *op_SUB_4 = rz_il_op_new_sub(rz_il_op_new_bitv_from_st64(32, 0x40), length); + RzILOpPure *op_RSHIFT_5 = rz_il_op_new_shiftr(rz_il_op_new_b0(), rz_il_op_new_bitv_from_ut64(64, -1), op_SUB_4); + RzILOpPure *op_AND_6 = rz_il_op_new_log_and(op_RSHIFT_0, op_RSHIFT_5); + return op_AND_6; +} + +/** + * \brief Extracts \p length bits from \p start from \p value and returns them as S64. The extracted value is sign extended. + * + * Performed operation: (((st64) (value << 0x40 - length - start)) >> 0x40 - length); + * + * \param value The value to extract the bits from. It must be a bitvector of size 64. + * \param start The start index of the bits to extract. Passed bitvector can be of any width. + * \param length Number of bits to extract. Passed bitvector must be 32bits in size. + * + * \return A 64bit wide sign extended bitvector with the extracted value. + */ +RZ_API RZ_OWN RzILOpBitVector *rz_il_sextract64(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length) { + rz_return_val_if_fail(value && start && length, NULL); + RzILOpPure *op_SUB_1 = rz_il_op_new_sub(rz_il_op_new_bitv_from_st64(32, 0x40), length); + RzILOpPure *op_SUB_2 = rz_il_op_new_sub(op_SUB_1, start); + RzILOpPure *op_LSHIFT_3 = rz_il_op_new_shiftl(rz_il_op_new_b0(), value, op_SUB_2); + RzILOpPure *op_SUB_6 = rz_il_op_new_sub(rz_il_op_new_bitv_from_st64(32, 0x40), rz_il_op_pure_dup(length)); + RzILOpPure *op_RSHIFT_7 = rz_il_op_new_shiftr_arith(rz_il_op_new_cast(64, rz_il_op_new_b0(), op_LSHIFT_3), op_SUB_6); + return op_RSHIFT_7; +} + +/** + * \brief Deposits \p fieldval in \p value. The \p fieldval is inserted at \p start until \p start + \p length (wrapped around). + * + * Performed operation: ((value & (~((-0x1 >> 0x40 - length) << start))) | ((fieldval << start) & ((-0x1 >> 0x40 - length) << start))); + * + * \param value The value to deposit \p fieldval into. It must be a bitvector of size 64. + * \param start The start index to deposit \p fieldval into. Passed bitvector can be of any width. + * \param length Number of bits to deposit. Passed bitvector must be 32bits in size. + * \param fieldval The bits to deposit into \p value into. It must be a bitvector of size 64. + * + * \return \p value where bits[start:length] are replaced with \p fieldval (wrapped around). + */ +RZ_API RZ_OWN RzILOpBitVector *rz_il_deposit64(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length, RZ_BORROW RzILOpBitVector *fieldval) { + rz_return_val_if_fail(value && start && length && fieldval, NULL); + RzILOpPure *op_SUB_4 = rz_il_op_new_sub(rz_il_op_new_bitv_from_st64(32, 0x40), length); + RzILOpPure *op_RSHIFT_5 = rz_il_op_new_shiftr(rz_il_op_new_b0(), rz_il_op_new_bitv_from_ut64(64, -1), op_SUB_4); + RzILOpPure *op_LSHIFT_6 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_RSHIFT_5, start); + RzILOpPure *op_NOT_8 = rz_il_op_new_log_not(op_LSHIFT_6); + RzILOpPure *op_AND_9 = rz_il_op_new_log_and(value, op_NOT_8); + RzILOpPure *op_LSHIFT_10 = rz_il_op_new_shiftl(rz_il_op_new_b0(), fieldval, rz_il_op_pure_dup(start)); + RzILOpPure *op_AND_11 = rz_il_op_new_log_and(op_LSHIFT_10, rz_il_op_pure_dup(op_LSHIFT_6)); + RzILOpPure *op_OR_12 = rz_il_op_new_log_or(op_AND_9, op_AND_11); + return op_OR_12; +} + +/** + * \brief Deposits \p fieldval in \p value. The \p fieldval is inserted at \p start until \p start + \p length (wrapped around). + * + * Performed operation: ((value & (~((-0x1 >> 0x20 - length) << start))) | ((fieldval << start) & ((-0x1 >> 0x20 - length) << start))); + * + * \param value The value to deposit \p fieldval into. It must be a bitvector of size 32. + * \param start The start index to deposit \p fieldval into. Passed bitvector can be of any width. + * \param length Number of bits to deposit. Passed bitvector must be 32bits in size. + * \param fieldval The bits to deposit into \p value into. It must be a bitvector of size 32. + * + * \return \p value where bits[start:length] are replaced with \p fieldval (wrapped around). + */ +RZ_API RZ_OWN RzILOpBitVector *rz_il_deposit32(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length, RZ_BORROW RzILOpBitVector *fieldval) { + rz_return_val_if_fail(value && start && length && fieldval, NULL); + RzILOpPure *op_SUB_4 = rz_il_op_new_sub(rz_il_op_new_bitv_from_st64(32, 0x20), length); + RzILOpPure *op_RSHIFT_5 = rz_il_op_new_shiftr(rz_il_op_new_b0(), rz_il_op_new_bitv_from_ut64(32, -1), op_SUB_4); + RzILOpPure *op_LSHIFT_6 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_RSHIFT_5, start); + RzILOpPure *op_NOT_8 = rz_il_op_new_log_not(op_LSHIFT_6); + RzILOpPure *op_AND_9 = rz_il_op_new_log_and(value, op_NOT_8); + RzILOpPure *op_LSHIFT_10 = rz_il_op_new_shiftl(rz_il_op_new_b0(), fieldval, rz_il_op_pure_dup(start)); + RzILOpPure *op_AND_11 = rz_il_op_new_log_and(op_LSHIFT_10, rz_il_op_pure_dup(op_LSHIFT_6)); + RzILOpPure *op_OR_12 = rz_il_op_new_log_or(op_AND_9, op_AND_11); + return op_OR_12; +} + +/** + * \brief Performes a byte swap of \p t. + * + * Perfomed operation: (((((st32) t) & 0xff00) >> 0x8) | ((((st32) t) & 0xff) << 0x8)); + * + * \param t A 16bit wide bitvector for which to swap the bytes. + * + * \return The bitvector \p t with swapped bytes. + */ +RZ_API RZ_OWN RzILOpBitVector *rz_il_bswap16(RZ_BORROW RzILOpBitVector *t) { + rz_return_val_if_fail(t, NULL); + RzILOpPure *op_AND_2 = rz_il_op_new_log_and(rz_il_op_new_cast(32, rz_il_op_new_b0(), t), rz_il_op_new_bitv_from_st64(32, 0xff00)); + RzILOpPure *op_RSHIFT_4 = rz_il_op_new_shiftr_arith(op_AND_2, rz_il_op_new_bitv_from_st64(32, 8)); + RzILOpPure *op_AND_7 = rz_il_op_new_log_and(rz_il_op_new_cast(32, rz_il_op_new_b0(), rz_il_op_pure_dup(t)), rz_il_op_new_bitv_from_st64(32, 0xff)); + RzILOpPure *op_LSHIFT_9 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_AND_7, rz_il_op_new_bitv_from_st64(32, 8)); + RzILOpPure *op_OR_10 = rz_il_op_new_log_or(op_RSHIFT_4, op_LSHIFT_9); + return rz_il_op_new_cast(16, rz_il_op_new_b0(), op_OR_10); +} + +/** + * \brief Performes a byte swap of \p t. + * + * Perfomed operation: + * ((t & ((ut32) 0xff)) << 0x18) + * | ((t & ((ut32) 0xff00)) << 0x8)) + * | ((t & ((ut32) 0xff0000)) >> 0x8)) + * | ((t & ((ut32) 0xff000000)) >> 0x18)); + * + * \param t A 32bit wide bitvector for which to swap the bytes. + * + * \return The bitvector \p t with swapped bytes. + */ +RZ_API RZ_OWN RzILOpBitVector *rz_il_bswap32(RZ_BORROW RzILOpBitVector *t) { + rz_return_val_if_fail(t, NULL); + RzILOpPure *op_AND_2 = rz_il_op_new_log_and(t, rz_il_op_new_cast(32, rz_il_op_new_b0(), rz_il_op_new_bitv_from_st64(32, 0xff))); + RzILOpPure *op_LSHIFT_4 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_AND_2, rz_il_op_new_bitv_from_st64(32, 24)); + RzILOpPure *op_AND_7 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_cast(32, rz_il_op_new_b0(), rz_il_op_new_bitv_from_st64(32, 0xff00))); + RzILOpPure *op_LSHIFT_9 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_AND_7, rz_il_op_new_bitv_from_st64(32, 8)); + RzILOpPure *op_OR_10 = rz_il_op_new_log_or(op_LSHIFT_4, op_LSHIFT_9); + RzILOpPure *op_AND_13 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_cast(32, rz_il_op_new_b0(), rz_il_op_new_bitv_from_st64(32, 0xff0000))); + RzILOpPure *op_RSHIFT_15 = rz_il_op_new_shiftr(rz_il_op_new_b0(), op_AND_13, rz_il_op_new_bitv_from_st64(32, 8)); + RzILOpPure *op_OR_16 = rz_il_op_new_log_or(op_OR_10, op_RSHIFT_15); + RzILOpPure *op_AND_19 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_cast(32, rz_il_op_new_b0(), rz_il_op_new_bitv_from_st64(32, 0xff000000))); + RzILOpPure *op_RSHIFT_21 = rz_il_op_new_shiftr(rz_il_op_new_b0(), op_AND_19, rz_il_op_new_bitv_from_st64(32, 24)); + RzILOpPure *op_OR_22 = rz_il_op_new_log_or(op_OR_16, op_RSHIFT_21); + return op_OR_22; +} + +/** + * \brief Performes a byte swap of \p t. + * + * Perfomed operation: + * ((t & 0xff) << 0x38) + * | ((t & 0xff00) << 0x28)) + * | ((t & 0xff0000) << 0x18)) + * | ((t & 0xff000000) << 0x8)) + * | ((t & 0xff00000000) >> 0x8)) + * | ((t & 0xff0000000000) >> 0x18)) + * | ((t & 0xff000000000000) >> 0x28)) + * | ((t & 0xff00000000000000) >> 0x38)); + * + * \param t A 64bit wide bitvector for which to swap the bytes. + * + * \return The bitvector \p t with swapped bytes. + */ +RZ_API RZ_OWN RzILOpBitVector *rz_il_bswap64(RZ_BORROW RzILOpBitVector *t) { + RzILOpPure *op_AND_1 = rz_il_op_new_log_and(t, rz_il_op_new_bitv_from_ut64(64, 0xff)); + RzILOpPure *op_LSHIFT_3 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_AND_1, rz_il_op_new_bitv_from_st64(32, 0x38)); + RzILOpPure *op_AND_5 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_bitv_from_ut64(64, 0xff00)); + RzILOpPure *op_LSHIFT_7 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_AND_5, rz_il_op_new_bitv_from_st64(32, 0x28)); + RzILOpPure *op_OR_8 = rz_il_op_new_log_or(op_LSHIFT_3, op_LSHIFT_7); + RzILOpPure *op_AND_10 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_bitv_from_ut64(64, 0xff0000)); + RzILOpPure *op_LSHIFT_12 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_AND_10, rz_il_op_new_bitv_from_st64(32, 24)); + RzILOpPure *op_OR_13 = rz_il_op_new_log_or(op_OR_8, op_LSHIFT_12); + RzILOpPure *op_AND_15 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_bitv_from_ut64(64, 0xff000000)); + RzILOpPure *op_LSHIFT_17 = rz_il_op_new_shiftl(rz_il_op_new_b0(), op_AND_15, rz_il_op_new_bitv_from_st64(32, 8)); + RzILOpPure *op_OR_18 = rz_il_op_new_log_or(op_OR_13, op_LSHIFT_17); + RzILOpPure *op_AND_20 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_bitv_from_ut64(64, 0xff00000000)); + RzILOpPure *op_RSHIFT_22 = rz_il_op_new_shiftr(rz_il_op_new_b0(), op_AND_20, rz_il_op_new_bitv_from_st64(32, 8)); + RzILOpPure *op_OR_23 = rz_il_op_new_log_or(op_OR_18, op_RSHIFT_22); + RzILOpPure *op_AND_25 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_bitv_from_ut64(64, 0xff0000000000)); + RzILOpPure *op_RSHIFT_27 = rz_il_op_new_shiftr(rz_il_op_new_b0(), op_AND_25, rz_il_op_new_bitv_from_st64(32, 24)); + RzILOpPure *op_OR_28 = rz_il_op_new_log_or(op_OR_23, op_RSHIFT_27); + RzILOpPure *op_AND_30 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_bitv_from_ut64(64, 0xff000000000000)); + RzILOpPure *op_RSHIFT_32 = rz_il_op_new_shiftr(rz_il_op_new_b0(), op_AND_30, rz_il_op_new_bitv_from_st64(32, 0x28)); + RzILOpPure *op_OR_33 = rz_il_op_new_log_or(op_OR_28, op_RSHIFT_32); + RzILOpPure *op_AND_35 = rz_il_op_new_log_and(rz_il_op_pure_dup(t), rz_il_op_new_bitv_from_ut64(64, 0xff00000000000000)); + RzILOpPure *op_RSHIFT_37 = rz_il_op_new_shiftr(rz_il_op_new_b0(), op_AND_35, rz_il_op_new_bitv_from_st64(32, 0x38)); + RzILOpPure *op_OR_38 = rz_il_op_new_log_or(op_OR_33, op_RSHIFT_37); + return op_OR_38; +} diff --git a/librz/il/meson.build b/librz/il/meson.build index 00bde3d5702..3db7fceaabd 100644 --- a/librz/il/meson.build +++ b/librz/il/meson.build @@ -16,6 +16,7 @@ rz_il_sources = [ 'il_export_json.c', 'il_graph.c', 'il_opcodes.c', + 'il_routines.c', 'il_reg.c', 'il_validate.c', 'il_vm.c', diff --git a/librz/include/rz_il/rz_il_opbuilder_begin.h b/librz/include/rz_il/rz_il_opbuilder_begin.h index b414260998d..7c6e1dfde7a 100644 --- a/librz/include/rz_il/rz_il_opbuilder_begin.h +++ b/librz/include/rz_il/rz_il_opbuilder_begin.h @@ -166,4 +166,19 @@ #define JMP(tgt) rz_il_op_new_jmp(tgt) #define GOTO(lbl) rz_il_op_new_goto(lbl) +#define NOT_IMPLEMENTED \ + do { \ + RZ_LOG_INFO("IL instruction not implemented."); \ + return NULL; \ + } while (0) + +#define EXTRACT32(value, start, length) rz_il_extract32(value, start, length) +#define EXTRACT64(value, start, length) rz_il_extract64(value, start, length) +#define SEXTRACT64(value, start, length) rz_il_sextract64(value, start, length) +#define DEPOSIT32(value, start, length, fieldval) rz_il_deposit32(value, start, length, fieldval) +#define DEPOSIT64(value, start, length, fieldval) rz_il_deposit64(value, start, length, fieldval) +#define BSWAP16(t) rz_il_bswap16(t) +#define BSWAP32(t) rz_il_bswap32(t) +#define BSWAP64(t) rz_il_bswap64(t) + #endif diff --git a/librz/include/rz_il/rz_il_opbuilder_end.h b/librz/include/rz_il/rz_il_opbuilder_end.h index 05ceb30591e..2f896bbb293 100644 --- a/librz/include/rz_il/rz_il_opbuilder_end.h +++ b/librz/include/rz_il/rz_il_opbuilder_end.h @@ -129,4 +129,15 @@ #undef JMP #undef GOTO +#undef NOT_IMPLEMENTED + +#undef EXTRACT32 +#undef EXTRACT64 +#undef SEXTRACT64 +#undef DEPOSIT32 +#undef DEPOSIT64 +#undef BSWAP16 +#undef BSWAP32 +#undef BSWAP64 + #undef RZ_IL_OPBUILDER_BEGIN_H diff --git a/librz/include/rz_il/rz_il_opcodes.h b/librz/include/rz_il/rz_il_opcodes.h index 578a9614fb5..e52f1d49cfb 100644 --- a/librz/include/rz_il/rz_il_opcodes.h +++ b/librz/include/rz_il/rz_il_opcodes.h @@ -769,6 +769,15 @@ RZ_API RZ_OWN RzILOpFloat *rz_il_op_new_frootn(RzFloatRMode rmode, RZ_NONNULL Rz RZ_API RZ_OWN RzILOpFloat *rz_il_op_new_fpown(RzFloatRMode rmode, RZ_NONNULL RzILOpFloat *x, RZ_NONNULL RzILOpBitVector *n); RZ_API RZ_OWN RzILOpFloat *rz_il_op_new_fcompound(RzFloatRMode rmode, RZ_NONNULL RzILOpFloat *x, RZ_NONNULL RzILOpBitVector *n); +RZ_API RZ_OWN RzILOpBitVector *rz_il_extract32(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length); +RZ_API RZ_OWN RzILOpBitVector *rz_il_extract64(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length); +RZ_API RZ_OWN RzILOpBitVector *rz_il_sextract64(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length); +RZ_API RZ_OWN RzILOpBitVector *rz_il_deposit64(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length, RZ_BORROW RzILOpBitVector *fieldval); +RZ_API RZ_OWN RzILOpBitVector *rz_il_deposit32(RZ_BORROW RzILOpBitVector *value, RZ_BORROW RzILOpBitVector *start, RZ_BORROW RzILOpBitVector *length, RZ_BORROW RzILOpBitVector *fieldval); +RZ_API RZ_OWN RzILOpBitVector *rz_il_bswap16(RZ_BORROW RzILOpBitVector *t); +RZ_API RZ_OWN RzILOpBitVector *rz_il_bswap32(RZ_BORROW RzILOpBitVector *t); +RZ_API RZ_OWN RzILOpBitVector *rz_il_bswap64(RZ_BORROW RzILOpBitVector *t); + /////////////////////////////// // Opcodes of type 'a effect //