From 25fbdbee565a9a977782d1a1ac8e6253bd4426a0 Mon Sep 17 00:00:00 2001 From: MatejKastak Date: Thu, 6 Sep 2018 23:33:04 +0200 Subject: [PATCH 001/107] Capstone2llvmirtool default basic modes for architectures Run tool with reasonable Capstone basic modes for specified architecture. Default values are as follows: -a arm : CS_MODE_ARM -a arm64 : CS_MODE_ARM [looks like keystone doesn't like this] -a mips : CS_MODE_MIPS32 -a x86 : CS_MODE_32 -a ppc : CS_MODE_32 -a : CS_MODE_LITTLE_ENDIAN --- src/capstone2llvmirtool/capstone2llvmir.cpp | 34 +++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/capstone2llvmirtool/capstone2llvmir.cpp b/src/capstone2llvmirtool/capstone2llvmir.cpp index 9c728037c..f6934c805 100644 --- a/src/capstone2llvmirtool/capstone2llvmir.cpp +++ b/src/capstone2llvmirtool/capstone2llvmir.cpp @@ -74,6 +74,7 @@ class ProgramOptions else if (c == "-m") { _basicMode = getParamOrDie(argc, argv, i); + _useDefaultBasicMode = false; if (_basicMode == "arm") basicMode = CS_MODE_ARM; else if (_basicMode == "thumb") basicMode = CS_MODE_THUMB; else if (_basicMode == "16") basicMode = CS_MODE_16; @@ -109,6 +110,11 @@ class ProgramOptions printHelpAndDie(); } } + + if (_useDefaultBasicMode) + { + basicMode = getDefaultBasicModeFromArch(arch); + } } std::string getParamOrDie(int argc, char *argv[], int& i) @@ -124,6 +130,27 @@ class ProgramOptions } } + cs_mode getDefaultBasicModeFromArch(cs_arch a) + { + switch (a) + { + case CS_ARCH_ARM: return CS_MODE_ARM; // CS_MODE_THUMB + case CS_ARCH_ARM64: return CS_MODE_ARM; + case CS_ARCH_MIPS: return CS_MODE_MIPS32; // CS_MODE_MIPS{32, 64, 32R6} + case CS_ARCH_X86: return CS_MODE_32; // CS_MODE_{16, 32, 64} + case CS_ARCH_PPC: return CS_MODE_32; + case CS_ARCH_SPARC: return CS_MODE_LITTLE_ENDIAN; // 0 + case CS_ARCH_SYSZ: return CS_MODE_LITTLE_ENDIAN; + case CS_ARCH_XCORE: return CS_MODE_LITTLE_ENDIAN; + case CS_ARCH_MAX: + case CS_ARCH_ALL: + default: + cerr << "Can not get Capstone arch to default Capstone basic mode." << endl; + exit(1); + } + } + + void dump() { cout << endl; @@ -180,6 +207,7 @@ class ProgramOptions string _code; string _basicMode; string _extraMode; + bool _useDefaultBasicMode = true; }; /** @@ -238,6 +266,12 @@ ks_mode capstoneModeBasicToKeystoneMode(cs_arch a, cs_mode m) { return KS_MODE_THUMB; } + else if (a == CS_ARCH_ARM64 && m == CS_MODE_ARM) // 0 + { + return KS_MODE_LITTLE_ENDIAN; + // In the keystone examples, only little endian mode is used with CS_ARCH_ARM64 + // test_ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN, "ldr w1, [sp, #0x8]", 0); + } else if (a == CS_ARCH_MIPS && m == CS_MODE_MIPS3) // 1 << 5 { return KS_MODE_MIPS3; From 7b921675539d9ba458bafdda70c9af6a6d526228 Mon Sep 17 00:00:00 2001 From: MatejKastak Date: Mon, 10 Sep 2018 15:31:49 +0200 Subject: [PATCH 002/107] Base for the ARM64 translator - register maps(_reg2type) - instructions map(_i2fm) Modified ARM Translator unit, Work in progress. --- include/retdec/capstone2llvmir/arm64/arm64.h | 28 + .../retdec/capstone2llvmir/arm64/arm64_defs.h | 21 + .../retdec/capstone2llvmir/capstone2llvmir.h | 1 + src/capstone2llvmir/CMakeLists.txt | 2 + src/capstone2llvmir/arm64/arm64.cpp | 269 ++++++++ src/capstone2llvmir/arm64/arm64_impl.h | 107 +++ src/capstone2llvmir/arm64/arm64_init.cpp | 640 ++++++++++++++++++ src/capstone2llvmir/capstone2llvmir.cpp | 4 +- src/capstone2llvmir/capstone2llvmir_impl.cpp | 1 + 9 files changed, 1071 insertions(+), 2 deletions(-) create mode 100644 include/retdec/capstone2llvmir/arm64/arm64.h create mode 100644 include/retdec/capstone2llvmir/arm64/arm64_defs.h create mode 100644 src/capstone2llvmir/arm64/arm64.cpp create mode 100644 src/capstone2llvmir/arm64/arm64_impl.h create mode 100644 src/capstone2llvmir/arm64/arm64_init.cpp diff --git a/include/retdec/capstone2llvmir/arm64/arm64.h b/include/retdec/capstone2llvmir/arm64/arm64.h new file mode 100644 index 000000000..14c4eba2e --- /dev/null +++ b/include/retdec/capstone2llvmir/arm64/arm64.h @@ -0,0 +1,28 @@ +/** + * @file include/retdec/capstone2llvmir/arm64/arm64.h + * @brief ARM64 specialization of translator's abstract public interface. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_CAPSTONE2LLVMIR_ARM64_ARM64_H +#define RETDEC_CAPSTONE2LLVMIR_ARM64_ARM64_H + +#include "retdec/capstone2llvmir/arm64/arm64_defs.h" +#include "retdec/capstone2llvmir/capstone2llvmir.h" + +namespace retdec { +namespace capstone2llvmir { + +/** + * ARM64 specialization of translator's abstract public interface. + */ +class Capstone2LlvmIrTranslatorArm64 : virtual public Capstone2LlvmIrTranslator +{ + public: + virtual ~Capstone2LlvmIrTranslatorArm64() {}; +}; + +} // namespace capstone2llvmir +} // namespace retdec + +#endif /* RETDEC_CAPSTONE2LLVMIR_ARM64_ARM64_H */ diff --git a/include/retdec/capstone2llvmir/arm64/arm64_defs.h b/include/retdec/capstone2llvmir/arm64/arm64_defs.h new file mode 100644 index 000000000..01bf5af52 --- /dev/null +++ b/include/retdec/capstone2llvmir/arm64/arm64_defs.h @@ -0,0 +1,21 @@ +/** + * @file include/retdec/capstone2llvmir/arm64/arm64_defs.h + * @brief Additional (on top of Capstone) definitions for ARM64 translator. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_CAPSTONE2LLVMIR_ARM64_ARM64_DEFS_H +#define RETDEC_CAPSTONE2LLVMIR_ARM64_ARM64_DEFS_H + +#include + +// TODO: Not relevant yet +//enum arm64_reg_cpsr_flags +//{ +// ARM_REG_CPSR_N = ARM_REG_ENDING + 1, +// ARM_REG_CPSR_Z, +// ARM_REG_CPSR_C, +// ARM_REG_CPSR_V, +//}; + +#endif /* RETDEC_CAPSTONE2LLVMIR_ARM64_ARM64_DEFS_H */ diff --git a/include/retdec/capstone2llvmir/capstone2llvmir.h b/include/retdec/capstone2llvmir/capstone2llvmir.h index fbf29dc37..1053ab366 100644 --- a/include/retdec/capstone2llvmir/capstone2llvmir.h +++ b/include/retdec/capstone2llvmir/capstone2llvmir.h @@ -23,6 +23,7 @@ // These are additions to capstone - include them all here. #include "retdec/capstone2llvmir/arm/arm_defs.h" +#include "retdec/capstone2llvmir/arm64/arm64_defs.h" #include "retdec/capstone2llvmir/mips/mips_defs.h" #include "retdec/capstone2llvmir/powerpc/powerpc_defs.h" #include "retdec/capstone2llvmir/x86/x86_defs.h" diff --git a/src/capstone2llvmir/CMakeLists.txt b/src/capstone2llvmir/CMakeLists.txt index 2382525fc..a1bfd9066 100644 --- a/src/capstone2llvmir/CMakeLists.txt +++ b/src/capstone2llvmir/CMakeLists.txt @@ -1,6 +1,8 @@ set(CAPSTONE2LLVMIR_SOURCES arm/arm_init.cpp arm/arm.cpp + arm64/arm64_init.cpp + arm64/arm64.cpp mips/mips_init.cpp mips/mips.cpp powerpc/powerpc_init.cpp diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp new file mode 100644 index 000000000..395bdc374 --- /dev/null +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -0,0 +1,269 @@ +/** + * @file src/capstone2llvmir/arm64/arm64.cpp + * @brief ARM64 implementation of @c Capstone2LlvmIrTranslator. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include +#include + +#include "capstone2llvmir/arm64/arm64_impl.h" + +namespace retdec { +namespace capstone2llvmir { + +Capstone2LlvmIrTranslatorArm64_impl::Capstone2LlvmIrTranslatorArm64_impl( + llvm::Module* m, + cs_mode basic, + cs_mode extra) + : + Capstone2LlvmIrTranslator_impl(CS_ARCH_ARM, basic, extra, m) +{ + initialize(); +} + +Capstone2LlvmIrTranslatorArm64_impl::~Capstone2LlvmIrTranslatorArm64_impl() +{ + +} + +// +//============================================================================== +// Mode query & modification methods - from Capstone2LlvmIrTranslator. +//============================================================================== +// + +bool Capstone2LlvmIrTranslatorArm64_impl::isAllowedBasicMode(cs_mode m) +{ + return m == CS_MODE_ARM; + // || m == CS_MODE_THUMB; +} + +bool Capstone2LlvmIrTranslatorArm64_impl::isAllowedExtraMode(cs_mode m) +{ + return m == CS_MODE_LITTLE_ENDIAN + || m == CS_MODE_BIG_ENDIAN; +} + +uint32_t Capstone2LlvmIrTranslatorArm64_impl::getArchByteSize() +{ + return 8; +} + +// +//============================================================================== +// Pure virtual methods from Capstone2LlvmIrTranslator_impl +//============================================================================== +// + +void Capstone2LlvmIrTranslatorArm64_impl::generateEnvironmentArchSpecific() +{ + // Nothing. +} + +void Capstone2LlvmIrTranslatorArm64_impl::generateDataLayout() +{ + _module->setDataLayout("e-p:32:32:32-f80:32:32"); + // TODO: Modify data layout. +} + +void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() +{ + // General purpose registers. + // + createRegister(ARM64_REG_X0, _regLt); + createRegister(ARM64_REG_X1, _regLt); + createRegister(ARM64_REG_X2, _regLt); + createRegister(ARM64_REG_X3, _regLt); + createRegister(ARM64_REG_X4, _regLt); + createRegister(ARM64_REG_X5, _regLt); + createRegister(ARM64_REG_X6, _regLt); + createRegister(ARM64_REG_X7, _regLt); + createRegister(ARM64_REG_X8, _regLt); + createRegister(ARM64_REG_X9, _regLt); + createRegister(ARM64_REG_X10, _regLt); + createRegister(ARM64_REG_X11, _regLt); + createRegister(ARM64_REG_X12, _regLt); + createRegister(ARM64_REG_X13, _regLt); + createRegister(ARM64_REG_X14, _regLt); + createRegister(ARM64_REG_X15, _regLt); + createRegister(ARM64_REG_X16, _regLt); + createRegister(ARM64_REG_X17, _regLt); + createRegister(ARM64_REG_X18, _regLt); + createRegister(ARM64_REG_X19, _regLt); + createRegister(ARM64_REG_X20, _regLt); + createRegister(ARM64_REG_X21, _regLt); + createRegister(ARM64_REG_X22, _regLt); + createRegister(ARM64_REG_X23, _regLt); + createRegister(ARM64_REG_X24, _regLt); + createRegister(ARM64_REG_X25, _regLt); + createRegister(ARM64_REG_X26, _regLt); + createRegister(ARM64_REG_X27, _regLt); + createRegister(ARM64_REG_X28, _regLt); + + // Lower 32 bits of 64 arm{xN} bit regs. + // + createRegister(ARM64_REG_W0, _regLt); + createRegister(ARM64_REG_W1, _regLt); + createRegister(ARM64_REG_W2, _regLt); + createRegister(ARM64_REG_W3, _regLt); + createRegister(ARM64_REG_W4, _regLt); + createRegister(ARM64_REG_W5, _regLt); + createRegister(ARM64_REG_W6, _regLt); + createRegister(ARM64_REG_W7, _regLt); + createRegister(ARM64_REG_W8, _regLt); + createRegister(ARM64_REG_W9, _regLt); + createRegister(ARM64_REG_W10, _regLt); + createRegister(ARM64_REG_W11, _regLt); + createRegister(ARM64_REG_W12, _regLt); + createRegister(ARM64_REG_W13, _regLt); + createRegister(ARM64_REG_W14, _regLt); + createRegister(ARM64_REG_W15, _regLt); + createRegister(ARM64_REG_W16, _regLt); + createRegister(ARM64_REG_W17, _regLt); + createRegister(ARM64_REG_W18, _regLt); + createRegister(ARM64_REG_W19, _regLt); + createRegister(ARM64_REG_W20, _regLt); + createRegister(ARM64_REG_W21, _regLt); + createRegister(ARM64_REG_W22, _regLt); + createRegister(ARM64_REG_W23, _regLt); + createRegister(ARM64_REG_W24, _regLt); + createRegister(ARM64_REG_W25, _regLt); + createRegister(ARM64_REG_W26, _regLt); + createRegister(ARM64_REG_W27, _regLt); + createRegister(ARM64_REG_W28, _regLt); + createRegister(ARM64_REG_W29, _regLt); + createRegister(ARM64_REG_W30, _regLt); + + // Special registers. + + // FP Frame pointer. + createRegister(ARM64_REG_X29, _regLt); + + // LP Link register. + createRegister(ARM64_REG_X30, _regLt); + + // Stack pointer. + createRegister(ARM64_REG_SP, _regLt); + createRegister(ARM64_REG_WSP, _regLt); + + // Zero. + createRegister(ARM64_REG_XZR, _regLt); + createRegister(ARM64_REG_WZR, _regLt); +} + +uint32_t Capstone2LlvmIrTranslatorArm64_impl::getCarryRegister() +{ + return 0; /* TODO: ARM_REG_CPSR_C; */ +} + +void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( + cs_insn* i, + llvm::IRBuilder<>& irb) +{ + _insn = i; + + cs_detail* d = i->detail; + cs_arm64* ai = &d->arm64; + + auto fIt = _i2fm.find(i->id); + if (fIt != _i2fm.end() && fIt->second != nullptr) + { + auto f = fIt->second; + + //bool branchInsn = i->id == ARM_INS_B || i->id == ARM_INS_BX + // || i->id == ARM_INS_BL || i->id == ARM_INS_BLX + // || i->id == ARM_INS_CBZ || i->id == ARM_INS_CBNZ; + if (ai->cc == ARM64_CC_AL || ai->cc == ARM64_CC_NV /* || branchInsn */) + { + _inCondition = false; + (this->*f)(i, ai, irb); + } + else + { + + assert(false && "NOT YET IMPLEMENTED"); + + _inCondition = true; + //auto* cond = generateInsnConditionCode(irb, ai); + //auto bodyIrb = generateIfThen(cond, irb); + + //(this->*f)(i, ai, bodyIrb); + } + } + else + { + assert(false && "NOT YET IMPLEMENTED"); + // TODO: Automatically generate pseudo asm call. + } +} + +// +//============================================================================== +// ARM64-specific methods. +//============================================================================== +// + +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::getCurrentPc(cs_insn* i) +{ + return llvm::ConstantInt::get( + getDefaultType(), + ((i->address + (2*i->size)) >> 2) << 2); +} + +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadRegister( + uint32_t r, + llvm::IRBuilder<>& irb, + llvm::Type* dstType, + eOpConv ct) +{ + assert(false && "NOT YET IMPLEMENTED"); + return nullptr; +} + +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadOp( + cs_arm64_op& op, + llvm::IRBuilder<>& irb, + llvm::Type* ty, + bool lea) +{ + assert(false && "NOT YET IMPLEMENTED"); + return nullptr; +} + +llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeRegister( + uint32_t r, + llvm::Value* val, + llvm::IRBuilder<>& irb, + eOpConv ct) +{ + assert(false && "NOT YET IMPLEMENTED"); + return nullptr; +} + +llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeOp( + cs_arm64_op& op, + llvm::Value* val, + llvm::IRBuilder<>& irb, + eOpConv ct) +{ + assert(false && "NOT YET IMPLEMENTED"); + return nullptr; +} + +// +//============================================================================== +// ARM64 instruction translation methods. +//============================================================================== +// + +/** + * ARM64_INS_ADD + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + assert(false && "NOT YET IMPLEMENTED"); +} + +} // namespace capstone2llvmir +} // namespace retdec diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h new file mode 100644 index 000000000..98f2f7593 --- /dev/null +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -0,0 +1,107 @@ +/** + * @file src/capstone2llvmir/arm64/arm64_impl.h + * @brief ARM implementation of @c Capstone2LlvmIrTranslator. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef CAPSTONE2LLVMIR_ARM64_ARM64_IMPL_H +#define CAPSTONE2LLVMIR_ARM64_ARM64_IMPL_H + +#include "retdec/capstone2llvmir/arm64/arm64.h" +#include "capstone2llvmir/capstone2llvmir_impl.h" + +namespace retdec { +namespace capstone2llvmir { + +class Capstone2LlvmIrTranslatorArm64_impl : + public Capstone2LlvmIrTranslator_impl, + public Capstone2LlvmIrTranslatorArm64 +{ + public: + Capstone2LlvmIrTranslatorArm64_impl( + llvm::Module* m, + cs_mode basic = CS_MODE_ARM, + cs_mode extra = CS_MODE_LITTLE_ENDIAN); + virtual ~Capstone2LlvmIrTranslatorArm64_impl(); +// +//============================================================================== +// Mode query & modification methods - from Capstone2LlvmIrTranslator. +//============================================================================== +// + public: + virtual bool isAllowedBasicMode(cs_mode m) override; + virtual bool isAllowedExtraMode(cs_mode m) override; + virtual uint32_t getArchByteSize() override; +// +//============================================================================== +// Pure virtual methods from Capstone2LlvmIrTranslator_impl +//============================================================================== +// + protected: + virtual void initializeArchSpecific() override; + virtual void initializeRegNameMap() override; + virtual void initializeRegTypeMap() override; + virtual void initializePseudoCallInstructionIDs() override; + virtual void generateEnvironmentArchSpecific() override; + virtual void generateDataLayout() override; + virtual void generateRegisters() override; + virtual uint32_t getCarryRegister() override; + + virtual void translateInstruction( + cs_insn* i, + llvm::IRBuilder<>& irb) override; +// +//============================================================================== +// ARM64-specific methods. +//============================================================================== +// + protected: + llvm::Value* getCurrentPc(cs_insn* i); + + virtual llvm::Value* loadRegister( + uint32_t r, + llvm::IRBuilder<>& irb, + llvm::Type* dstType = nullptr, + eOpConv ct = eOpConv::THROW) override; + virtual llvm::Value* loadOp( + cs_arm64_op& op, + llvm::IRBuilder<>& irb, + llvm::Type* ty = nullptr, + bool lea = false) override; + + virtual llvm::Instruction* storeRegister( + uint32_t r, + llvm::Value* val, + llvm::IRBuilder<>& irb, + eOpConv ct = eOpConv::SEXT_TRUNC) override; + virtual llvm::Instruction* storeOp( + cs_arm64_op& op, + llvm::Value* val, + llvm::IRBuilder<>& irb, + eOpConv ct = eOpConv::SEXT_TRUNC) override; +// +//============================================================================== +// ARM64 implementation data. +//============================================================================== +// + protected: + static std::map< + std::size_t, + void (Capstone2LlvmIrTranslatorArm64_impl::*)( + cs_insn* i, + cs_arm64*, + llvm::IRBuilder<>&)> _i2fm; +// +//============================================================================== +// ARM64 instruction translation methods. +//============================================================================== +// + protected: + void translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + +}; + +} // namespace capstone2llvmir +} // namespace retdec + +#endif /* CAPSTONE2LLVMIR_ARM64_ARM64_IMPL_H */ diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp new file mode 100644 index 000000000..e8b10e9dd --- /dev/null +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -0,0 +1,640 @@ +/** + * @file src/capstone2llvmir/arm64/arm64_init.cpp + * @brief Initializations for ARM64 implementation of @c Capstone2LlvmIrTranslator. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "capstone2llvmir/arm64/arm64_impl.h" + +namespace retdec { +namespace capstone2llvmir { + +// +//============================================================================== +// Pure virtual methods from Capstone2LlvmIrTranslator_impl +//============================================================================== +// + +void Capstone2LlvmIrTranslatorArm64_impl::initializeArchSpecific() +{ + // Nothing. +} + +void Capstone2LlvmIrTranslatorArm64_impl::initializeRegNameMap() +{ + std::map r2n = + { + // TODO: Status register + }; + + _reg2name = std::move(r2n); +} + +void Capstone2LlvmIrTranslatorArm64_impl::initializeRegTypeMap() +{ + // TODO: Add Status Register flags + //auto* i1 = llvm::IntegerType::getInt1Ty(_module->getContext()); + auto* i32 = llvm::IntegerType::getInt32Ty(_module->getContext()); + auto* defTy = getDefaultType(); + + std::map r2t = + { + // General purpose registers. + // + {ARM64_REG_X0, defTy}, + {ARM64_REG_X1, defTy}, + {ARM64_REG_X2, defTy}, + {ARM64_REG_X3, defTy}, + {ARM64_REG_X4, defTy}, + {ARM64_REG_X5, defTy}, + {ARM64_REG_X6, defTy}, + {ARM64_REG_X7, defTy}, + {ARM64_REG_X8, defTy}, + {ARM64_REG_X9, defTy}, + {ARM64_REG_X10, defTy}, + {ARM64_REG_X11, defTy}, + {ARM64_REG_X12, defTy}, + {ARM64_REG_X13, defTy}, + {ARM64_REG_X14, defTy}, + {ARM64_REG_X15, defTy}, + {ARM64_REG_X16, defTy}, + {ARM64_REG_X17, defTy}, + {ARM64_REG_X18, defTy}, + {ARM64_REG_X19, defTy}, + {ARM64_REG_X20, defTy}, + {ARM64_REG_X21, defTy}, + {ARM64_REG_X22, defTy}, + {ARM64_REG_X23, defTy}, + {ARM64_REG_X24, defTy}, + {ARM64_REG_X25, defTy}, + {ARM64_REG_X26, defTy}, + {ARM64_REG_X27, defTy}, + {ARM64_REG_X28, defTy}, + + // Lower 32 bits of 64{xN} regs + // + {ARM64_REG_W0, i32}, + {ARM64_REG_W1, i32}, + {ARM64_REG_W2, i32}, + {ARM64_REG_W3, i32}, + {ARM64_REG_W4, i32}, + {ARM64_REG_W5, i32}, + {ARM64_REG_W6, i32}, + {ARM64_REG_W7, i32}, + {ARM64_REG_W8, i32}, + {ARM64_REG_W9, i32}, + {ARM64_REG_W10, i32}, + {ARM64_REG_W11, i32}, + {ARM64_REG_W12, i32}, + {ARM64_REG_W13, i32}, + {ARM64_REG_W14, i32}, + {ARM64_REG_W15, i32}, + {ARM64_REG_W16, i32}, + {ARM64_REG_W17, i32}, + {ARM64_REG_W18, i32}, + {ARM64_REG_W19, i32}, + {ARM64_REG_W20, i32}, + {ARM64_REG_W21, i32}, + {ARM64_REG_W22, i32}, + {ARM64_REG_W23, i32}, + {ARM64_REG_W24, i32}, + {ARM64_REG_W25, i32}, + {ARM64_REG_W26, i32}, + {ARM64_REG_W27, i32}, + {ARM64_REG_W28, i32}, + {ARM64_REG_W29, i32}, + {ARM64_REG_W30, i32}, + + // Special registers. + + // FP Frame pointer + {ARM64_REG_X29, defTy}, + + // LP Link register + {ARM64_REG_X30, defTy}, + + // Stack pointer + {ARM64_REG_SP, defTy}, + {ARM64_REG_WSP, i32}, + + // Zero + {ARM64_REG_XZR, defTy}, + {ARM64_REG_WZR, i32}, + + // CPSR flags. + // + }; + + _reg2type = std::move(r2t); +} + +void Capstone2LlvmIrTranslatorArm64_impl::initializePseudoCallInstructionIDs() +{ + _callInsnIds = + { + + }; + + _returnInsnIds = + { + + }; + + _branchInsnIds = + { + + }; + + _condBranchInsnIds = + { + + }; + + _controlFlowInsnIds = + { + + }; +} + +// +//============================================================================== +// Instruction translation map initialization. +//============================================================================== +// + +std::map< + std::size_t, + void (Capstone2LlvmIrTranslatorArm64_impl::*)( + cs_insn* i, + cs_arm64*, + llvm::IRBuilder<>&)> +Capstone2LlvmIrTranslatorArm64_impl::_i2fm = +{ + {ARM_INS_INVALID, nullptr}, + + {ARM64_INS_ABS, nullptr}, + {ARM64_INS_ADC, nullptr}, + {ARM64_INS_ADDHN, nullptr}, + {ARM64_INS_ADDHN2, nullptr}, + {ARM64_INS_ADDP, nullptr}, + {ARM64_INS_ADD, &Capstone2LlvmIrTranslatorArm64_impl::translateAdd}, + {ARM64_INS_ADDV, nullptr}, + {ARM64_INS_ADR, nullptr}, + {ARM64_INS_ADRP, nullptr}, + {ARM64_INS_AESD, nullptr}, + {ARM64_INS_AESE, nullptr}, + {ARM64_INS_AESIMC, nullptr}, + {ARM64_INS_AESMC, nullptr}, + {ARM64_INS_AND, nullptr}, + {ARM64_INS_ASR, nullptr}, + {ARM64_INS_B, nullptr}, + {ARM64_INS_BFM, nullptr}, + {ARM64_INS_BIC, nullptr}, + {ARM64_INS_BIF, nullptr}, + {ARM64_INS_BIT, nullptr}, + {ARM64_INS_BL, nullptr}, + {ARM64_INS_BLR, nullptr}, + {ARM64_INS_BR, nullptr}, + {ARM64_INS_BRK, nullptr}, + {ARM64_INS_BSL, nullptr}, + {ARM64_INS_CBNZ, nullptr}, + {ARM64_INS_CBZ, nullptr}, + {ARM64_INS_CCMN, nullptr}, + {ARM64_INS_CCMP, nullptr}, + {ARM64_INS_CLREX, nullptr}, + {ARM64_INS_CLS, nullptr}, + {ARM64_INS_CLZ, nullptr}, + {ARM64_INS_CMEQ, nullptr}, + {ARM64_INS_CMGE, nullptr}, + {ARM64_INS_CMGT, nullptr}, + {ARM64_INS_CMHI, nullptr}, + {ARM64_INS_CMHS, nullptr}, + {ARM64_INS_CMLE, nullptr}, + {ARM64_INS_CMLT, nullptr}, + {ARM64_INS_CMTST, nullptr}, + {ARM64_INS_CNT, nullptr}, + {ARM64_INS_MOV, nullptr}, + {ARM64_INS_CRC32B, nullptr}, + {ARM64_INS_CRC32CB, nullptr}, + {ARM64_INS_CRC32CH, nullptr}, + {ARM64_INS_CRC32CW, nullptr}, + {ARM64_INS_CRC32CX, nullptr}, + {ARM64_INS_CRC32H, nullptr}, + {ARM64_INS_CRC32W, nullptr}, + {ARM64_INS_CRC32X, nullptr}, + {ARM64_INS_CSEL, nullptr}, + {ARM64_INS_CSINC, nullptr}, + {ARM64_INS_CSINV, nullptr}, + {ARM64_INS_CSNEG, nullptr}, + {ARM64_INS_DCPS1, nullptr}, + {ARM64_INS_DCPS2, nullptr}, + {ARM64_INS_DCPS3, nullptr}, + {ARM64_INS_DMB, nullptr}, + {ARM64_INS_DRPS, nullptr}, + {ARM64_INS_DSB, nullptr}, + {ARM64_INS_DUP, nullptr}, + {ARM64_INS_EON, nullptr}, + {ARM64_INS_EOR, nullptr}, + {ARM64_INS_ERET, nullptr}, + {ARM64_INS_EXTR, nullptr}, + {ARM64_INS_EXT, nullptr}, + {ARM64_INS_FABD, nullptr}, + {ARM64_INS_FABS, nullptr}, + {ARM64_INS_FACGE, nullptr}, + {ARM64_INS_FACGT, nullptr}, + {ARM64_INS_FADD, nullptr}, + {ARM64_INS_FADDP, nullptr}, + {ARM64_INS_FCCMP, nullptr}, + {ARM64_INS_FCCMPE, nullptr}, + {ARM64_INS_FCMEQ, nullptr}, + {ARM64_INS_FCMGE, nullptr}, + {ARM64_INS_FCMGT, nullptr}, + {ARM64_INS_FCMLE, nullptr}, + {ARM64_INS_FCMLT, nullptr}, + {ARM64_INS_FCMP, nullptr}, + {ARM64_INS_FCMPE, nullptr}, + {ARM64_INS_FCSEL, nullptr}, + {ARM64_INS_FCVTAS, nullptr}, + {ARM64_INS_FCVTAU, nullptr}, + {ARM64_INS_FCVT, nullptr}, + {ARM64_INS_FCVTL, nullptr}, + {ARM64_INS_FCVTL2, nullptr}, + {ARM64_INS_FCVTMS, nullptr}, + {ARM64_INS_FCVTMU, nullptr}, + {ARM64_INS_FCVTNS, nullptr}, + {ARM64_INS_FCVTNU, nullptr}, + {ARM64_INS_FCVTN, nullptr}, + {ARM64_INS_FCVTN2, nullptr}, + {ARM64_INS_FCVTPS, nullptr}, + {ARM64_INS_FCVTPU, nullptr}, + {ARM64_INS_FCVTXN, nullptr}, + {ARM64_INS_FCVTXN2, nullptr}, + {ARM64_INS_FCVTZS, nullptr}, + {ARM64_INS_FCVTZU, nullptr}, + {ARM64_INS_FDIV, nullptr}, + {ARM64_INS_FMADD, nullptr}, + {ARM64_INS_FMAX, nullptr}, + {ARM64_INS_FMAXNM, nullptr}, + {ARM64_INS_FMAXNMP, nullptr}, + {ARM64_INS_FMAXNMV, nullptr}, + {ARM64_INS_FMAXP, nullptr}, + {ARM64_INS_FMAXV, nullptr}, + {ARM64_INS_FMIN, nullptr}, + {ARM64_INS_FMINNM, nullptr}, + {ARM64_INS_FMINNMP, nullptr}, + {ARM64_INS_FMINNMV, nullptr}, + {ARM64_INS_FMINP, nullptr}, + {ARM64_INS_FMINV, nullptr}, + {ARM64_INS_FMLA, nullptr}, + {ARM64_INS_FMLS, nullptr}, + {ARM64_INS_FMOV, nullptr}, + {ARM64_INS_FMSUB, nullptr}, + {ARM64_INS_FMUL, nullptr}, + {ARM64_INS_FMULX, nullptr}, + {ARM64_INS_FNEG, nullptr}, + {ARM64_INS_FNMADD, nullptr}, + {ARM64_INS_FNMSUB, nullptr}, + {ARM64_INS_FNMUL, nullptr}, + {ARM64_INS_FRECPE, nullptr}, + {ARM64_INS_FRECPS, nullptr}, + {ARM64_INS_FRECPX, nullptr}, + {ARM64_INS_FRINTA, nullptr}, + {ARM64_INS_FRINTI, nullptr}, + {ARM64_INS_FRINTM, nullptr}, + {ARM64_INS_FRINTN, nullptr}, + {ARM64_INS_FRINTP, nullptr}, + {ARM64_INS_FRINTX, nullptr}, + {ARM64_INS_FRINTZ, nullptr}, + {ARM64_INS_FRSQRTE, nullptr}, + {ARM64_INS_FRSQRTS, nullptr}, + {ARM64_INS_FSQRT, nullptr}, + {ARM64_INS_FSUB, nullptr}, + {ARM64_INS_HINT, nullptr}, + {ARM64_INS_HLT, nullptr}, + {ARM64_INS_HVC, nullptr}, + {ARM64_INS_INS, nullptr}, + + {ARM64_INS_ISB, nullptr}, + {ARM64_INS_LD1, nullptr}, + {ARM64_INS_LD1R, nullptr}, + {ARM64_INS_LD2R, nullptr}, + {ARM64_INS_LD2, nullptr}, + {ARM64_INS_LD3R, nullptr}, + {ARM64_INS_LD3, nullptr}, + {ARM64_INS_LD4, nullptr}, + {ARM64_INS_LD4R, nullptr}, + + {ARM64_INS_LDARB, nullptr}, + {ARM64_INS_LDARH, nullptr}, + {ARM64_INS_LDAR, nullptr}, + {ARM64_INS_LDAXP, nullptr}, + {ARM64_INS_LDAXRB, nullptr}, + {ARM64_INS_LDAXRH, nullptr}, + {ARM64_INS_LDAXR, nullptr}, + {ARM64_INS_LDNP, nullptr}, + {ARM64_INS_LDP, nullptr}, + {ARM64_INS_LDPSW, nullptr}, + {ARM64_INS_LDRB, nullptr}, + {ARM64_INS_LDR, nullptr}, + {ARM64_INS_LDRH, nullptr}, + {ARM64_INS_LDRSB, nullptr}, + {ARM64_INS_LDRSH, nullptr}, + {ARM64_INS_LDRSW, nullptr}, + {ARM64_INS_LDTRB, nullptr}, + {ARM64_INS_LDTRH, nullptr}, + {ARM64_INS_LDTRSB, nullptr}, + + {ARM64_INS_LDTRSH, nullptr}, + {ARM64_INS_LDTRSW, nullptr}, + {ARM64_INS_LDTR, nullptr}, + {ARM64_INS_LDURB, nullptr}, + {ARM64_INS_LDUR, nullptr}, + {ARM64_INS_LDURH, nullptr}, + {ARM64_INS_LDURSB, nullptr}, + {ARM64_INS_LDURSH, nullptr}, + {ARM64_INS_LDURSW, nullptr}, + {ARM64_INS_LDXP, nullptr}, + {ARM64_INS_LDXRB, nullptr}, + {ARM64_INS_LDXRH, nullptr}, + {ARM64_INS_LDXR, nullptr}, + {ARM64_INS_LSL, nullptr}, + {ARM64_INS_LSR, nullptr}, + {ARM64_INS_MADD, nullptr}, + {ARM64_INS_MLA, nullptr}, + {ARM64_INS_MLS, nullptr}, + {ARM64_INS_MOVI, nullptr}, + {ARM64_INS_MOVK, nullptr}, + {ARM64_INS_MOVN, nullptr}, + {ARM64_INS_MOVZ, nullptr}, + {ARM64_INS_MRS, nullptr}, + {ARM64_INS_MSR, nullptr}, + {ARM64_INS_MSUB, nullptr}, + {ARM64_INS_MUL, nullptr}, + {ARM64_INS_MVNI, nullptr}, + {ARM64_INS_NEG, nullptr}, + {ARM64_INS_NOT, nullptr}, + {ARM64_INS_ORN, nullptr}, + {ARM64_INS_ORR, nullptr}, + {ARM64_INS_PMULL2, nullptr}, + {ARM64_INS_PMULL, nullptr}, + {ARM64_INS_PMUL, nullptr}, + {ARM64_INS_PRFM, nullptr}, + {ARM64_INS_PRFUM, nullptr}, + {ARM64_INS_RADDHN, nullptr}, + {ARM64_INS_RADDHN2, nullptr}, + {ARM64_INS_RBIT, nullptr}, + {ARM64_INS_RET, nullptr}, + {ARM64_INS_REV16, nullptr}, + {ARM64_INS_REV32, nullptr}, + {ARM64_INS_REV64, nullptr}, + {ARM64_INS_REV, nullptr}, + {ARM64_INS_ROR, nullptr}, + {ARM64_INS_RSHRN2, nullptr}, + {ARM64_INS_RSHRN, nullptr}, + {ARM64_INS_RSUBHN, nullptr}, + {ARM64_INS_RSUBHN2, nullptr}, + {ARM64_INS_SABAL2, nullptr}, + {ARM64_INS_SABAL, nullptr}, + + {ARM64_INS_SABA, nullptr}, + {ARM64_INS_SABDL2, nullptr}, + {ARM64_INS_SABDL, nullptr}, + {ARM64_INS_SABD, nullptr}, + {ARM64_INS_SADALP, nullptr}, + {ARM64_INS_SADDLP, nullptr}, + {ARM64_INS_SADDLV, nullptr}, + {ARM64_INS_SADDL2, nullptr}, + {ARM64_INS_SADDL, nullptr}, + {ARM64_INS_SADDW2, nullptr}, + {ARM64_INS_SADDW, nullptr}, + {ARM64_INS_SBC, nullptr}, + {ARM64_INS_SBFM, nullptr}, + {ARM64_INS_SCVTF, nullptr}, + {ARM64_INS_SDIV, nullptr}, + {ARM64_INS_SHA1C, nullptr}, + {ARM64_INS_SHA1H, nullptr}, + {ARM64_INS_SHA1M, nullptr}, + {ARM64_INS_SHA1P, nullptr}, + {ARM64_INS_SHA1SU0, nullptr}, + {ARM64_INS_SHA1SU1, nullptr}, + {ARM64_INS_SHA256H2, nullptr}, + {ARM64_INS_SHA256H, nullptr}, + {ARM64_INS_SHA256SU0, nullptr}, + {ARM64_INS_SHA256SU1, nullptr}, + {ARM64_INS_SHADD, nullptr}, + {ARM64_INS_SHLL2, nullptr}, + {ARM64_INS_SHLL, nullptr}, + {ARM64_INS_SHL, nullptr}, + {ARM64_INS_SHRN2, nullptr}, + {ARM64_INS_SHRN, nullptr}, + {ARM64_INS_SHSUB, nullptr}, + {ARM64_INS_SLI, nullptr}, + {ARM64_INS_SMADDL, nullptr}, + {ARM64_INS_SMAXP, nullptr}, + {ARM64_INS_SMAXV, nullptr}, + {ARM64_INS_SMAX, nullptr}, + {ARM64_INS_SMC, nullptr}, + {ARM64_INS_SMINP, nullptr}, + {ARM64_INS_SMINV, nullptr}, + {ARM64_INS_SMIN, nullptr}, + {ARM64_INS_SMLAL2, nullptr}, + {ARM64_INS_SMLAL, nullptr}, + {ARM64_INS_SMLSL2, nullptr}, + {ARM64_INS_SMLSL, nullptr}, + {ARM64_INS_SMOV, nullptr}, + {ARM64_INS_SMSUBL, nullptr}, + {ARM64_INS_SMULH, nullptr}, + {ARM64_INS_SMULL2, nullptr}, + {ARM64_INS_SMULL, nullptr}, + {ARM64_INS_SQABS, nullptr}, + {ARM64_INS_SQADD, nullptr}, + {ARM64_INS_SQDMLAL, nullptr}, + {ARM64_INS_SQDMLAL2, nullptr}, + {ARM64_INS_SQDMLSL, nullptr}, + {ARM64_INS_SQDMLSL2, nullptr}, + {ARM64_INS_SQDMULH, nullptr}, + {ARM64_INS_SQDMULL, nullptr}, + {ARM64_INS_SQDMULL2, nullptr}, + {ARM64_INS_SQNEG, nullptr}, + {ARM64_INS_SQRDMULH, nullptr}, + {ARM64_INS_SQRSHL, nullptr}, + {ARM64_INS_SQRSHRN, nullptr}, + {ARM64_INS_SQRSHRN2, nullptr}, + {ARM64_INS_SQRSHRUN, nullptr}, + {ARM64_INS_SQRSHRUN2, nullptr}, + {ARM64_INS_SQSHLU, nullptr}, + {ARM64_INS_SQSHL, nullptr}, + {ARM64_INS_SQSHRN, nullptr}, + {ARM64_INS_SQSHRN2, nullptr}, + {ARM64_INS_SQSHRUN, nullptr}, + {ARM64_INS_SQSHRUN2, nullptr}, + {ARM64_INS_SQSUB, nullptr}, + {ARM64_INS_SQXTN2, nullptr}, + {ARM64_INS_SQXTN, nullptr}, + {ARM64_INS_SQXTUN2, nullptr}, + {ARM64_INS_SQXTUN, nullptr}, + {ARM64_INS_SRHADD, nullptr}, + {ARM64_INS_SRI, nullptr}, + {ARM64_INS_SRSHL, nullptr}, + {ARM64_INS_SRSHR, nullptr}, + {ARM64_INS_SRSRA, nullptr}, + {ARM64_INS_SSHLL2, nullptr}, + {ARM64_INS_SSHLL, nullptr}, + {ARM64_INS_SSHL, nullptr}, + {ARM64_INS_SSHR, nullptr}, + {ARM64_INS_SSRA, nullptr}, + {ARM64_INS_SSUBL2, nullptr}, + {ARM64_INS_SSUBL, nullptr}, + {ARM64_INS_SSUBW2, nullptr}, + {ARM64_INS_SSUBW, nullptr}, + {ARM64_INS_ST1, nullptr}, + {ARM64_INS_ST2, nullptr}, + {ARM64_INS_ST3, nullptr}, + {ARM64_INS_ST4, nullptr}, + {ARM64_INS_STLRB, nullptr}, + {ARM64_INS_STLRH, nullptr}, + {ARM64_INS_STLR, nullptr}, + {ARM64_INS_STLXP, nullptr}, + {ARM64_INS_STLXRB, nullptr}, + {ARM64_INS_STLXRH, nullptr}, + {ARM64_INS_STLXR, nullptr}, + {ARM64_INS_STNP, nullptr}, + {ARM64_INS_STP, nullptr}, + {ARM64_INS_STRB, nullptr}, + {ARM64_INS_STR, nullptr}, + {ARM64_INS_STRH, nullptr}, + {ARM64_INS_STTRB, nullptr}, + {ARM64_INS_STTRH, nullptr}, + {ARM64_INS_STTR, nullptr}, + {ARM64_INS_STURB, nullptr}, + {ARM64_INS_STUR, nullptr}, + {ARM64_INS_STURH, nullptr}, + {ARM64_INS_STXP, nullptr}, + {ARM64_INS_STXRB, nullptr}, + {ARM64_INS_STXRH, nullptr}, + {ARM64_INS_STXR, nullptr}, + {ARM64_INS_SUBHN, nullptr}, + {ARM64_INS_SUBHN2, nullptr}, + {ARM64_INS_SUB, nullptr}, + {ARM64_INS_SUQADD, nullptr}, + {ARM64_INS_SVC, nullptr}, + {ARM64_INS_SYSL, nullptr}, + {ARM64_INS_SYS, nullptr}, + {ARM64_INS_TBL, nullptr}, + {ARM64_INS_TBNZ, nullptr}, + {ARM64_INS_TBX, nullptr}, + {ARM64_INS_TBZ, nullptr}, + {ARM64_INS_TRN1, nullptr}, + {ARM64_INS_TRN2, nullptr}, + {ARM64_INS_UABAL2, nullptr}, + {ARM64_INS_UABAL, nullptr}, + {ARM64_INS_UABA, nullptr}, + {ARM64_INS_UABDL2, nullptr}, + {ARM64_INS_UABDL, nullptr}, + {ARM64_INS_UABD, nullptr}, + {ARM64_INS_UADALP, nullptr}, + {ARM64_INS_UADDLP, nullptr}, + {ARM64_INS_UADDLV, nullptr}, + {ARM64_INS_UADDL2, nullptr}, + {ARM64_INS_UADDL, nullptr}, + {ARM64_INS_UADDW2, nullptr}, + {ARM64_INS_UADDW, nullptr}, + {ARM64_INS_UBFM, nullptr}, + {ARM64_INS_UCVTF, nullptr}, + {ARM64_INS_UDIV, nullptr}, + {ARM64_INS_UHADD, nullptr}, + {ARM64_INS_UHSUB, nullptr}, + {ARM64_INS_UMADDL, nullptr}, + {ARM64_INS_UMAXP, nullptr}, + {ARM64_INS_UMAXV, nullptr}, + {ARM64_INS_UMAX, nullptr}, + {ARM64_INS_UMINP, nullptr}, + {ARM64_INS_UMINV, nullptr}, + {ARM64_INS_UMIN, nullptr}, + {ARM64_INS_UMLAL2, nullptr}, + {ARM64_INS_UMLAL, nullptr}, + {ARM64_INS_UMLSL2, nullptr}, + {ARM64_INS_UMLSL, nullptr}, + {ARM64_INS_UMOV, nullptr}, + {ARM64_INS_UMSUBL, nullptr}, + {ARM64_INS_UMULH, nullptr}, + {ARM64_INS_UMULL2, nullptr}, + {ARM64_INS_UMULL, nullptr}, + {ARM64_INS_UQADD, nullptr}, + {ARM64_INS_UQRSHL, nullptr}, + {ARM64_INS_UQRSHRN, nullptr}, + {ARM64_INS_UQRSHRN2, nullptr}, + {ARM64_INS_UQSHL, nullptr}, + {ARM64_INS_UQSHRN, nullptr}, + {ARM64_INS_UQSHRN2, nullptr}, + {ARM64_INS_UQSUB, nullptr}, + {ARM64_INS_UQXTN2, nullptr}, + {ARM64_INS_UQXTN, nullptr}, + {ARM64_INS_URECPE, nullptr}, + {ARM64_INS_URHADD, nullptr}, + {ARM64_INS_URSHL, nullptr}, + {ARM64_INS_URSHR, nullptr}, + {ARM64_INS_URSQRTE, nullptr}, + {ARM64_INS_URSRA, nullptr}, + {ARM64_INS_USHLL2, nullptr}, + {ARM64_INS_USHLL, nullptr}, + {ARM64_INS_USHL, nullptr}, + {ARM64_INS_USHR, nullptr}, + {ARM64_INS_USQADD, nullptr}, + {ARM64_INS_USRA, nullptr}, + {ARM64_INS_USUBL2, nullptr}, + {ARM64_INS_USUBL, nullptr}, + {ARM64_INS_USUBW2, nullptr}, + {ARM64_INS_USUBW, nullptr}, + {ARM64_INS_UZP1, nullptr}, + {ARM64_INS_UZP2, nullptr}, + {ARM64_INS_XTN2, nullptr}, + {ARM64_INS_XTN, nullptr}, + {ARM64_INS_ZIP1, nullptr}, + {ARM64_INS_ZIP2, nullptr}, + + // alias insn + {ARM64_INS_MNEG, nullptr}, + {ARM64_INS_UMNEGL, nullptr}, + {ARM64_INS_SMNEGL, nullptr}, + {ARM64_INS_NOP, nullptr}, + {ARM64_INS_YIELD, nullptr}, + {ARM64_INS_WFE, nullptr}, + {ARM64_INS_WFI, nullptr}, + {ARM64_INS_SEV, nullptr}, + {ARM64_INS_SEVL, nullptr}, + {ARM64_INS_NGC, nullptr}, + {ARM64_INS_SBFIZ, nullptr}, + {ARM64_INS_UBFIZ, nullptr}, + {ARM64_INS_SBFX, nullptr}, + {ARM64_INS_UBFX, nullptr}, + {ARM64_INS_BFI, nullptr}, + {ARM64_INS_BFXIL, nullptr}, + {ARM64_INS_CMN, nullptr}, + {ARM64_INS_MVN, nullptr}, + {ARM64_INS_TST, nullptr}, + {ARM64_INS_CSET, nullptr}, + {ARM64_INS_CINC, nullptr}, + {ARM64_INS_CSETM, nullptr}, + {ARM64_INS_CINV, nullptr}, + {ARM64_INS_CNEG, nullptr}, + {ARM64_INS_SXTB, nullptr}, + {ARM64_INS_SXTH, nullptr}, + {ARM64_INS_SXTW, nullptr}, + {ARM64_INS_CMP, nullptr}, + {ARM64_INS_UXTB, nullptr}, + {ARM64_INS_UXTH, nullptr}, + {ARM64_INS_UXTW, nullptr}, + {ARM64_INS_IC, nullptr}, + {ARM64_INS_DC, nullptr}, + {ARM64_INS_AT, nullptr}, + {ARM64_INS_TLBI, nullptr}, + + {ARM64_INS_NEGS, nullptr}, + {ARM64_INS_NGCS, nullptr}, + + {ARM64_INS_ENDING, nullptr} +}; + +} // namespace capstone2llvmir +} // namespace retdec diff --git a/src/capstone2llvmir/capstone2llvmir.cpp b/src/capstone2llvmir/capstone2llvmir.cpp index 872953f66..ddb29db4c 100644 --- a/src/capstone2llvmir/capstone2llvmir.cpp +++ b/src/capstone2llvmir/capstone2llvmir.cpp @@ -7,6 +7,7 @@ #include "retdec/capstone2llvmir/capstone2llvmir.h" #include "capstone2llvmir/arm/arm_impl.h" +#include "capstone2llvmir/arm64/arm64_impl.h" #include "capstone2llvmir/mips/mips_impl.h" #include "capstone2llvmir/powerpc/powerpc_impl.h" #include "capstone2llvmir/x86/x86_impl.h" @@ -93,8 +94,7 @@ std::unique_ptr Capstone2LlvmIrTranslator::createArm6 llvm::Module* m, cs_mode extra) { - assert(false && "not implemented"); - return nullptr; + return std::make_unique(m, CS_MODE_ARM, extra); } std::unique_ptr Capstone2LlvmIrTranslator::createMips32( diff --git a/src/capstone2llvmir/capstone2llvmir_impl.cpp b/src/capstone2llvmir/capstone2llvmir_impl.cpp index d5c8d71c3..e048f41f3 100644 --- a/src/capstone2llvmir/capstone2llvmir_impl.cpp +++ b/src/capstone2llvmir/capstone2llvmir_impl.cpp @@ -1516,6 +1516,7 @@ llvm::Value* Capstone2LlvmIrTranslator_impl::generateTypeConvers } template class Capstone2LlvmIrTranslator_impl; +template class Capstone2LlvmIrTranslator_impl; template class Capstone2LlvmIrTranslator_impl; template class Capstone2LlvmIrTranslator_impl; template class Capstone2LlvmIrTranslator_impl; From 7007eadf63ddcd79bbcca139bd76baa383537637 Mon Sep 17 00:00:00 2001 From: MatejKastak Date: Tue, 11 Sep 2018 15:33:49 +0200 Subject: [PATCH 003/107] Fix the cs_reg_name - register name could not be found because of the wrong cs_arch in constructor --- src/capstone2llvmir/arm64/arm64.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 395bdc374..d495b1c6a 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -17,7 +17,7 @@ Capstone2LlvmIrTranslatorArm64_impl::Capstone2LlvmIrTranslatorArm64_impl( cs_mode basic, cs_mode extra) : - Capstone2LlvmIrTranslator_impl(CS_ARCH_ARM, basic, extra, m) + Capstone2LlvmIrTranslator_impl(CS_ARCH_ARM64, basic, extra, m) { initialize(); } @@ -71,6 +71,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() { // General purpose registers. // + createRegister(ARM64_REG_X0, _regLt); createRegister(ARM64_REG_X1, _regLt); createRegister(ARM64_REG_X2, _regLt); From 952def8391c9ef3e499d16bce785a6bcd1df482e Mon Sep 17 00:00:00 2001 From: MatejKastak Date: Tue, 11 Sep 2018 15:34:42 +0200 Subject: [PATCH 004/107] Add ARM64 support for capstone dependency - capstone was configured without the ARM64 support, this caused cs_open to fail --- deps/capstone/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/capstone/CMakeLists.txt b/deps/capstone/CMakeLists.txt index 3b53ebb8a..4b945dc6d 100644 --- a/deps/capstone/CMakeLists.txt +++ b/deps/capstone/CMakeLists.txt @@ -21,11 +21,11 @@ ExternalProject_Add(capstone-project -DCAPSTONE_X86_ATT_DISABLE=OFF # Enabled architectures. -DCAPSTONE_ARM_SUPPORT=ON + -DCAPSTONE_ARM64_SUPPORT=ON -DCAPSTONE_MIPS_SUPPORT=ON -DCAPSTONE_PPC_SUPPORT=ON -DCAPSTONE_X86_SUPPORT=ON # Disabled architectures. - -DCAPSTONE_ARM64_SUPPORT=OFF -DCAPSTONE_M68K_SUPPORT=OFF -DCAPSTONE_SPARC_SUPPORT=OFF -DCAPSTONE_SYSZ_SUPPORT=OFF From 8a79401add5274f9df933f3b2a1173589ec40a6c Mon Sep 17 00:00:00 2001 From: MatejKastak Date: Tue, 11 Sep 2018 15:35:51 +0200 Subject: [PATCH 005/107] Temporary solution to call translate function --- src/capstone2llvmir/arm64/arm64.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index d495b1c6a..7e951787d 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -182,6 +182,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( } else { + (this->*f)(i, ai, irb); assert(false && "NOT YET IMPLEMENTED"); From 446820df98a8e7e01c48d4d83564f239e5b3eae9 Mon Sep 17 00:00:00 2001 From: MatejKastak Date: Tue, 11 Sep 2018 19:38:20 +0200 Subject: [PATCH 006/107] Status register and program counter added to environment - flags from status register added to arm64 env - program counter added to arm64 env --- .../retdec/capstone2llvmir/arm64/arm64_defs.h | 16 ++++++++-------- src/capstone2llvmir/arm64/arm64.cpp | 9 +++++++++ src/capstone2llvmir/arm64/arm64_init.cpp | 16 +++++++++++++--- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/include/retdec/capstone2llvmir/arm64/arm64_defs.h b/include/retdec/capstone2llvmir/arm64/arm64_defs.h index 01bf5af52..996a809eb 100644 --- a/include/retdec/capstone2llvmir/arm64/arm64_defs.h +++ b/include/retdec/capstone2llvmir/arm64/arm64_defs.h @@ -9,13 +9,13 @@ #include -// TODO: Not relevant yet -//enum arm64_reg_cpsr_flags -//{ -// ARM_REG_CPSR_N = ARM_REG_ENDING + 1, -// ARM_REG_CPSR_Z, -// ARM_REG_CPSR_C, -// ARM_REG_CPSR_V, -//}; +enum arm64_reg_cpsr_flags +{ + ARM64_REG_CPSR_N = ARM64_REG_ENDING + 1, + ARM64_REG_CPSR_Z, + ARM64_REG_CPSR_C, + ARM64_REG_CPSR_V, + ARM64_REG_PC, +}; #endif /* RETDEC_CAPSTONE2LLVMIR_ARM64_ARM64_DEFS_H */ diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 7e951787d..cbbac16a5 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -151,6 +151,15 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() // Zero. createRegister(ARM64_REG_XZR, _regLt); createRegister(ARM64_REG_WZR, _regLt); + + // Flags. + createRegister(ARM64_REG_CPSR_N, _regLt); + createRegister(ARM64_REG_CPSR_Z, _regLt); + createRegister(ARM64_REG_CPSR_C, _regLt); + createRegister(ARM64_REG_CPSR_V, _regLt); + + // Program counter. + createRegister(ARM64_REG_PC, _regLt); } uint32_t Capstone2LlvmIrTranslatorArm64_impl::getCarryRegister() diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index e8b10e9dd..cc427738a 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -24,7 +24,11 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializeRegNameMap() { std::map r2n = { - // TODO: Status register + {ARM64_REG_CPSR_N, "cpsr_n"}, + {ARM64_REG_CPSR_Z, "cpsr_z"}, + {ARM64_REG_CPSR_C, "cpsr_c"}, + {ARM64_REG_CPSR_V, "cpsr_v"}, + {ARM64_REG_PC, "pc"}, }; _reg2name = std::move(r2n); @@ -32,8 +36,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializeRegNameMap() void Capstone2LlvmIrTranslatorArm64_impl::initializeRegTypeMap() { - // TODO: Add Status Register flags - //auto* i1 = llvm::IntegerType::getInt1Ty(_module->getContext()); + auto* i1 = llvm::IntegerType::getInt1Ty(_module->getContext()); auto* i32 = llvm::IntegerType::getInt32Ty(_module->getContext()); auto* defTy = getDefaultType(); @@ -123,6 +126,13 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializeRegTypeMap() // CPSR flags. // + {ARM64_REG_CPSR_N, i1}, + {ARM64_REG_CPSR_Z, i1}, + {ARM64_REG_CPSR_C, i1}, + {ARM64_REG_CPSR_V, i1}, + + // Program counter. + {ARM64_REG_PC, defTy}, }; _reg2type = std::move(r2t); From 94f6426aee88ec56ce51c26a7c8dbc7748e79f36 Mon Sep 17 00:00:00 2001 From: MatejKastak Date: Tue, 11 Sep 2018 22:38:13 +0200 Subject: [PATCH 007/107] Methods store/load registers/operands skeletons + add instruction - basic implementation of functions needed for loading and storing operands - translateAdd is for testing purposes --- src/capstone2llvmir/arm64/arm64.cpp | 115 +++++++++++++++++++++-- src/capstone2llvmir/arm64/arm64_impl.h | 5 + src/capstone2llvmir/arm64/arm64_init.cpp | 10 +- 3 files changed, 116 insertions(+), 14 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index cbbac16a5..76392f077 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -228,8 +228,24 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadRegister( llvm::Type* dstType, eOpConv ct) { - assert(false && "NOT YET IMPLEMENTED"); - return nullptr; + if (r == ARM64_REG_INVALID) + { + return nullptr; + } + + if (r == ARM64_REG_PC) + { + return getCurrentPc(_insn); + // TODO: Check + } + + auto* llvmReg = getRegister(r); + if (llvmReg == nullptr) + { + throw Capstone2LlvmIrError("loadRegister() unhandled reg."); + } + + return irb.CreateLoad(llvmReg); } llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadOp( @@ -238,8 +254,37 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadOp( llvm::Type* ty, bool lea) { - assert(false && "NOT YET IMPLEMENTED"); - return nullptr; + switch (op.type) + { + case ARM64_OP_SYS: + case ARM64_OP_REG: + { + auto* val = loadRegister(op.reg, irb); + return generateOperandShift(irb, op, val); + } + case ARM64_OP_IMM: + { + auto* val = llvm::ConstantInt::getSigned(getDefaultType(), op.imm); + return generateOperandShift(irb, op, val); + } + case ARM64_OP_MEM: + { + // TODO: MEM OP + } + case ARM64_OP_FP: + case ARM64_OP_INVALID: + case ARM64_OP_CIMM: + case ARM64_OP_REG_MRS: + case ARM64_OP_REG_MSR: + case ARM64_OP_PSTATE: + case ARM64_OP_PREFETCH: + case ARM64_OP_BARRIER: + default: + { + assert(false && "loadOp(): unhandled operand type."); + return nullptr; + } + } } llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeRegister( @@ -248,8 +293,25 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeRegister( llvm::IRBuilder<>& irb, eOpConv ct) { - assert(false && "NOT YET IMPLEMENTED"); - return nullptr; + if (r == ARM64_REG_INVALID) + { + return nullptr; + } + + if (r == ARM64_REG_PC) + { + return nullptr; + // TODO: Check? + } + + auto* llvmReg = getRegister(r); + if (llvmReg == nullptr) + { + throw Capstone2LlvmIrError("storeRegister() unhandled reg."); + } + val = generateTypeConversion(irb, val, llvmReg->getValueType(), ct); + + return irb.CreateStore(val, llvmReg); } llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeOp( @@ -258,8 +320,41 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeOp( llvm::IRBuilder<>& irb, eOpConv ct) { - assert(false && "NOT YET IMPLEMENTED"); - return nullptr; + switch (op.type) + { + case ARM64_OP_SYS: + case ARM64_OP_REG: + { + return storeRegister(op.reg, val, irb, ct); + } + case ARM64_OP_MEM: + { + // TODO: OP MEM + } + case ARM64_OP_INVALID: + case ARM64_OP_IMM: + case ARM64_OP_FP: + case ARM64_OP_CIMM: + case ARM64_OP_REG_MRS: + case ARM64_OP_REG_MSR: + case ARM64_OP_PSTATE: + case ARM64_OP_PREFETCH: + case ARM64_OP_BARRIER: + default: + { + assert(false && "stroreOp(): unhandled operand type."); + return nullptr; + } + } +} + +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateOperandShift( + llvm::IRBuilder<>& irb, + cs_arm64_op& op, + llvm::Value* val) +{ + return val; + // TODO: NOT YET IMPLEMENTED } // @@ -273,7 +368,9 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeOp( */ void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { - assert(false && "NOT YET IMPLEMENTED"); + std::tie(op1, op2) = loadOpTernaryOp1Op2(ai, irb); + auto *val = irb.CreateAdd(op1, op2); + storeOp(ai->operands[0], val, irb); } } // namespace capstone2llvmir diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 98f2f7593..e838e35d5 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -79,6 +79,11 @@ class Capstone2LlvmIrTranslatorArm64_impl : llvm::Value* val, llvm::IRBuilder<>& irb, eOpConv ct = eOpConv::SEXT_TRUNC) override; + + llvm::Value* generateOperandShift( + llvm::IRBuilder<>& irb, + cs_arm64_op& op, + llvm::Value* val); // //============================================================================== // ARM64 implementation data. diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index cc427738a..97b655722 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -24,11 +24,11 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializeRegNameMap() { std::map r2n = { - {ARM64_REG_CPSR_N, "cpsr_n"}, - {ARM64_REG_CPSR_Z, "cpsr_z"}, - {ARM64_REG_CPSR_C, "cpsr_c"}, - {ARM64_REG_CPSR_V, "cpsr_v"}, - {ARM64_REG_PC, "pc"}, + {ARM64_REG_CPSR_N, "cpsr_n"}, // Negative + {ARM64_REG_CPSR_Z, "cpsr_z"}, // Zero + {ARM64_REG_CPSR_C, "cpsr_c"}, // Carry + {ARM64_REG_CPSR_V, "cpsr_v"}, // Overflow + {ARM64_REG_PC, "pc"}, // Program counter }; _reg2name = std::move(r2n); From 623aef99cd2fde985ec0ad6a6a47dde809834871 Mon Sep 17 00:00:00 2001 From: MatejKastak Date: Wed, 12 Sep 2018 18:12:38 +0200 Subject: [PATCH 008/107] Store instruction base - started implementation of MEM operand type - Store register instruction translation method e.g. retdec-capstone2llvmir -a arm64 -t 'str x0, [x1]' --- src/capstone2llvmir/arm64/arm64.cpp | 98 ++++++++++++++++++++++-- src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- 3 files changed, 95 insertions(+), 6 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 76392f077..80a580b9e 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -176,6 +176,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( cs_detail* d = i->detail; cs_arm64* ai = &d->arm64; + std::cerr << "Translating instruction: " << cs_insn_name(_handle, i->id) << std::endl; auto fIt = _i2fm.find(i->id); if (fIt != _i2fm.end() && fIt->second != nullptr) { @@ -193,9 +194,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( { (this->*f)(i, ai, irb); - assert(false && "NOT YET IMPLEMENTED"); - - _inCondition = true; + //_inCondition = true; //auto* cond = generateInsnConditionCode(irb, ai); //auto bodyIrb = generateIfThen(cond, irb); @@ -204,7 +203,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( } else { - assert(false && "NOT YET IMPLEMENTED"); + assert(false && "Instruction is not implemented"); // TODO: Automatically generate pseudo asm call. } } @@ -329,7 +328,64 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeOp( } case ARM64_OP_MEM: { - // TODO: OP MEM + auto* baseR = loadRegister(op.mem.base, irb); + auto* t = baseR ? baseR->getType() : getDefaultType(); + llvm::Value* disp = op.mem.disp + ? llvm::ConstantInt::get(t, op.mem.disp) + : nullptr; + + auto* idxR = loadRegister(op.mem.index, irb); + if (idxR) + { + //struct { + // arm64_shifter type; // shifter type of this operand + // unsigned int value; // shifter value of this operand + //} shift; + //if (op.mem.lshift) + //{ + // auto* lshift = llvm::ConstantInt::get( + // idxR->getType(), + // op.mem.lshift); + // idxR = irb.CreateShl(idxR, lshift); + //} + + // If there is a shift in memory operand, it is applied to + // the index register. + idxR = generateOperandShift(irb, op, idxR); + } + + llvm::Value* addr = nullptr; + if (baseR && disp == nullptr) + { + addr = baseR; + } + else if (disp && baseR == nullptr) + { + addr = disp; + } + else if (baseR && disp) + { + disp = irb.CreateSExtOrTrunc(disp, baseR->getType()); + addr = irb.CreateAdd(baseR, disp); + } + else if (idxR) + { + addr = idxR; + } + else + { + addr = llvm::ConstantInt::get(getDefaultType(), 0); + } + + if (idxR && addr != idxR) + { + idxR = irb.CreateZExtOrTrunc(idxR, addr->getType()); + addr = irb.CreateAdd(addr, idxR); + } + + auto* pt = llvm::PointerType::get(val->getType(), 0); + addr = irb.CreateIntToPtr(addr, pt); + return irb.CreateStore(val, addr); } case ARM64_OP_INVALID: case ARM64_OP_IMM: @@ -373,5 +429,37 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_STR + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + op0 = loadOp(ai->operands[0], irb); + op0 = irb.CreateZExtOrTrunc(op0, getDefaultType()); + + uint32_t baseR = ARM_REG_INVALID; + llvm::Value* idx = nullptr; + bool subtract = false; + storeOp(ai->operands[1], op0, irb); + baseR = ai->operands[1].mem.base; + if (auto disp = ai->operands[1].mem.disp) + { + idx = llvm::ConstantInt::getSigned(getDefaultType(), disp); + } + else if (ai->operands[1].mem.index != ARM64_REG_INVALID) + { + idx = loadRegister(ai->operands[1].mem.index, irb); + } + + if (ai->writeback && idx && baseR != ARM64_REG_INVALID) + { + auto* b = loadRegister(baseR, irb); + auto* v = subtract + ? irb.CreateSub(b, idx) + : irb.CreateAdd(b, idx); + storeRegister(baseR, v, irb); + } +} + } // namespace capstone2llvmir } // namespace retdec diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index e838e35d5..e70f9297c 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -103,6 +103,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : // protected: void translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); }; diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 97b655722..a77eabd7e 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -511,7 +511,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_STNP, nullptr}, {ARM64_INS_STP, nullptr}, {ARM64_INS_STRB, nullptr}, - {ARM64_INS_STR, nullptr}, + {ARM64_INS_STR, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, {ARM64_INS_STRH, nullptr}, {ARM64_INS_STTRB, nullptr}, {ARM64_INS_STTRH, nullptr}, From 32781de1fbd65ea690568ef6b04af6d55fa2d3ab Mon Sep 17 00:00:00 2001 From: MatejKastak Date: Thu, 13 Sep 2018 11:20:17 +0200 Subject: [PATCH 009/107] Operand shifts ported from ARM and MOV instruction tranlation - MOV, MVN and MOVZ instructions - operand shift functions moved and changed for ARM64 - instructions like 'movz x0, #3 LSL 16' work now --- src/capstone2llvmir/arm64/arm64.cpp | 198 +++++++++++++++++++++-- src/capstone2llvmir/arm64/arm64_impl.h | 30 +++- src/capstone2llvmir/arm64/arm64_init.cpp | 6 +- 3 files changed, 218 insertions(+), 16 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 80a580b9e..291ed6caa 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -221,6 +221,166 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::getCurrentPc(cs_insn* i) ((i->address + (2*i->size)) >> 2) << 2); } +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateOperandShift( + llvm::IRBuilder<>& irb, + cs_arm64_op& op, + llvm::Value* val) +{ + llvm::Value* n = nullptr; + if (op.shift.type == ARM64_SFT_INVALID) + { + return val; + } + else + { + n = llvm::ConstantInt::get(val->getType(), op.shift.value); + } + + if (n == nullptr) + { + assert(false && "should not be possible"); + return val; + } + n = irb.CreateZExtOrTrunc(n, val->getType()); + + switch (op.shift.type) + { + case ARM64_SFT_ASR: + { + return generateShiftAsr(irb, val, n); + } + case ARM64_SFT_LSL: + { + return generateShiftLsl(irb, val, n); + } + case ARM64_SFT_LSR: + { + return generateShiftLsr(irb, val, n); + } + case ARM64_SFT_ROR: + { + return generateShiftRor(irb, val, n); + } + case ARM64_SFT_MSL: + { + assert(false && "CHECK IMPLEMENTATION"); + return generateShiftMsl(irb, val, n); + } + case ARM64_SFT_INVALID: + default: + { + return val; + } + } +} + +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftAsr( + llvm::IRBuilder<>& irb, + llvm::Value* val, + llvm::Value* n) +{ + // TODO: In the old semantics, there is: + // n = (n == 0) ? 32 : n; + // It looks like capstone does not allow op.shift.value to be zero, + // in such a case, Capstone throws away the shift. + // But there still might be zero in register, if register variant + // is used. + + auto* cfOp1 = irb.CreateSub(n, llvm::ConstantInt::get(n->getType(), 1)); + auto* cfShl = irb.CreateShl(llvm::ConstantInt::get(cfOp1->getType(), 1), cfOp1); + auto* cfAnd = irb.CreateAnd(cfShl, val); + auto* cfIcmp = irb.CreateICmpNE(cfAnd, llvm::ConstantInt::get(cfAnd->getType(), 0)); + storeRegister(ARM64_REG_CPSR_C, cfIcmp, irb); + + return irb.CreateAShr(val, n); +} + +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftLsl( + llvm::IRBuilder<>& irb, + llvm::Value* val, + llvm::Value* n) +{ + auto* cfOp1 = irb.CreateSub(n, llvm::ConstantInt::get(n->getType(), 1)); + auto* cfShl = irb.CreateShl(val, cfOp1); + auto* cfIntT = llvm::cast(cfShl->getType()); + auto* cfRightCount = llvm::ConstantInt::get(cfIntT, cfIntT->getBitWidth() - 1); + auto* cfLow = irb.CreateLShr(cfShl, cfRightCount); + storeRegister(ARM64_REG_CPSR_C, cfLow, irb); + + return irb.CreateShl(val, n); +} + +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftLsr( + llvm::IRBuilder<>& irb, + llvm::Value* val, + llvm::Value* n) +{ + // TODO: In the old semantics, there is: + // n = (n == 0) ? 32 : n; + + auto* cfOp1 = irb.CreateSub(n, llvm::ConstantInt::get(n->getType(), 1)); + auto* cfShl = irb.CreateShl(llvm::ConstantInt::get(cfOp1->getType(), 1), cfOp1); + auto* cfAnd = irb.CreateAnd(cfShl, val); + auto* cfIcmp = irb.CreateICmpNE(cfAnd, llvm::ConstantInt::get(cfAnd->getType(), 0)); + storeRegister(ARM64_REG_CPSR_C, cfIcmp, irb); + + return irb.CreateLShr(val, n); +} + +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftRor( + llvm::IRBuilder<>& irb, + llvm::Value* val, + llvm::Value* n) +{ + // TODO: In the old semantics, there is same more complicated code + // if n == 0. + unsigned op0BitW = llvm::cast(n->getType())->getBitWidth(); + + auto* srl = irb.CreateLShr(val, n); + auto* sub = irb.CreateSub(llvm::ConstantInt::get(n->getType(), op0BitW), n); + auto* shl = irb.CreateShl(val, sub); + auto* orr = irb.CreateOr(srl, shl); + + auto* cfSrl = irb.CreateLShr(orr, llvm::ConstantInt::get(orr->getType(), op0BitW - 1)); + auto* cfIcmp = irb.CreateICmpNE(cfSrl, llvm::ConstantInt::get(cfSrl->getType(), 0)); + storeRegister(ARM64_REG_CPSR_C, cfIcmp, irb); + + return orr; +} + +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftMsl( + llvm::IRBuilder<>& irb, + llvm::Value* val, + llvm::Value* n) +{ + unsigned op0BitW = llvm::cast(n->getType())->getBitWidth(); + auto* doubleT = llvm::Type::getIntNTy(_module->getContext(), op0BitW*2); + + auto* cf = loadRegister(ARM_REG_CPSR_C, irb); + cf = irb.CreateZExtOrTrunc(cf, n->getType()); + + auto* srl = irb.CreateLShr(val, n); + auto* srlZext = irb.CreateZExt(srl, doubleT); + auto* op0Zext = irb.CreateZExt(val, doubleT); + auto* sub = irb.CreateSub(llvm::ConstantInt::get(n->getType(), op0BitW + 1), n); + auto* subZext = irb.CreateZExt(sub, doubleT); + auto* shl = irb.CreateShl(op0Zext, subZext); + auto* sub2 = irb.CreateSub(llvm::ConstantInt::get(n->getType(), op0BitW), n); + auto* shl2 = irb.CreateShl(cf, sub2); + auto* shl2Zext = irb.CreateZExt(shl2, doubleT); + auto* or1 = irb.CreateOr(shl, srlZext); + auto* or2 = irb.CreateOr(or1, shl2Zext); + auto* or2Trunc = irb.CreateTrunc(or2, val->getType()); + + auto* sub3 = irb.CreateSub(n, llvm::ConstantInt::get(n->getType(), 1)); + auto* shl3 = irb.CreateShl(llvm::ConstantInt::get(sub3->getType(), 1), sub3); + auto* and1 = irb.CreateAnd(shl3, val); + auto* cfIcmp = irb.CreateICmpNE(and1, llvm::ConstantInt::get(and1->getType(), 0)); + storeRegister(ARM64_REG_CPSR_C, cfIcmp, irb); + + return or2Trunc; +} + llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadRegister( uint32_t r, llvm::IRBuilder<>& irb, @@ -404,15 +564,6 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeOp( } } -llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateOperandShift( - llvm::IRBuilder<>& irb, - cs_arm64_op& op, - llvm::Value* val) -{ - return val; - // TODO: NOT YET IMPLEMENTED -} - // //============================================================================== // ARM64 instruction translation methods. @@ -429,6 +580,35 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_MOV, ARM64_INS_MVN, ARM64_INS_MOVZ + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + if (ai->op_count != 2) + { + return; + } + + op1 = loadOpBinaryOp1(ai, irb); + if (i->id == ARM64_INS_MVN) + { + op1 = generateValueNegate(irb, op1); + } + + // If S is specified, the MOV instruction: + // - updates the N and Z flags according to the result + // - can update the C flag during the calculation of Operand2 (shifts?) + // - does not affect the V flag. + if (ai->update_flags) + { + llvm::Value* zero = llvm::ConstantInt::get(op1->getType(), 0); + storeRegister(ARM64_REG_CPSR_N, irb.CreateICmpSLT(op1, zero), irb); + storeRegister(ARM64_REG_CPSR_Z, irb.CreateICmpEQ(op1, zero), irb); + } + storeOp(ai->operands[0], op1, irb); +} + /** * ARM64_INS_STR */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index e70f9297c..416d2f3a6 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -58,6 +58,31 @@ class Capstone2LlvmIrTranslatorArm64_impl : protected: llvm::Value* getCurrentPc(cs_insn* i); + llvm::Value* generateOperandShift( + llvm::IRBuilder<>& irb, + cs_arm64_op& op, + llvm::Value* val); + llvm::Value* generateShiftAsr( + llvm::IRBuilder<>& irb, + llvm::Value* val, + llvm::Value* n); + llvm::Value* generateShiftLsl( + llvm::IRBuilder<>& irb, + llvm::Value* val, + llvm::Value* n); + llvm::Value* generateShiftLsr( + llvm::IRBuilder<>& irb, + llvm::Value* val, + llvm::Value* n); + llvm::Value* generateShiftRor( + llvm::IRBuilder<>& irb, + llvm::Value* val, + llvm::Value* n); + llvm::Value* generateShiftMsl( + llvm::IRBuilder<>& irb, + llvm::Value* val, + llvm::Value* n); + virtual llvm::Value* loadRegister( uint32_t r, llvm::IRBuilder<>& irb, @@ -80,10 +105,6 @@ class Capstone2LlvmIrTranslatorArm64_impl : llvm::IRBuilder<>& irb, eOpConv ct = eOpConv::SEXT_TRUNC) override; - llvm::Value* generateOperandShift( - llvm::IRBuilder<>& irb, - cs_arm64_op& op, - llvm::Value* val); // //============================================================================== // ARM64 implementation data. @@ -103,6 +124,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : // protected: void translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); }; diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index a77eabd7e..2869dec71 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -223,7 +223,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_CMLT, nullptr}, {ARM64_INS_CMTST, nullptr}, {ARM64_INS_CNT, nullptr}, - {ARM64_INS_MOV, nullptr}, + {ARM64_INS_MOV, &Capstone2LlvmIrTranslatorArm64_impl::translateMov}, {ARM64_INS_CRC32B, nullptr}, {ARM64_INS_CRC32CB, nullptr}, {ARM64_INS_CRC32CH, nullptr}, @@ -375,7 +375,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_MOVI, nullptr}, {ARM64_INS_MOVK, nullptr}, {ARM64_INS_MOVN, nullptr}, - {ARM64_INS_MOVZ, nullptr}, + {ARM64_INS_MOVZ, &Capstone2LlvmIrTranslatorArm64_impl::translateMov}, {ARM64_INS_MRS, nullptr}, {ARM64_INS_MSR, nullptr}, {ARM64_INS_MSUB, nullptr}, @@ -621,7 +621,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_BFI, nullptr}, {ARM64_INS_BFXIL, nullptr}, {ARM64_INS_CMN, nullptr}, - {ARM64_INS_MVN, nullptr}, + {ARM64_INS_MVN, &Capstone2LlvmIrTranslatorArm64_impl::translateMov}, {ARM64_INS_TST, nullptr}, {ARM64_INS_CSET, nullptr}, {ARM64_INS_CINC, nullptr}, From 5edc4ba435303099919d8a7dc21798752127a592 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 15 Sep 2018 15:02:47 +0200 Subject: [PATCH 010/107] Arm64 - tests ported from Arm - test framework capstone2llvmirtranslator - first INS_ADD test - cmake compilation --- tests/capstone2llvmir/CMakeLists.txt | 1 + tests/capstone2llvmir/arm64_tests.cpp | 99 +++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 tests/capstone2llvmir/arm64_tests.cpp diff --git a/tests/capstone2llvmir/CMakeLists.txt b/tests/capstone2llvmir/CMakeLists.txt index 29c47f046..9459f9670 100644 --- a/tests/capstone2llvmir/CMakeLists.txt +++ b/tests/capstone2llvmir/CMakeLists.txt @@ -1,5 +1,6 @@ set(RETDEC_TESTS_CAPSTONE2LLVMIR_SOURCES arm_tests.cpp + arm64_tests.cpp mips_tests.cpp powerpc_tests.cpp x86_tests.cpp diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp new file mode 100644 index 000000000..538e52979 --- /dev/null +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -0,0 +1,99 @@ +/** + * @file tests/capstone2llvmir/arm64_tests.cpp + * @brief Capstone2LlvmIrTranslatorArm64 unit tests. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include + +#include "capstone2llvmir/capstone2llvmir_tests.h" +#include "retdec/capstone2llvmir/arm64/arm64.h" + +using namespace ::testing; +using namespace llvm; + +namespace retdec { +namespace capstone2llvmir { +namespace tests { + +class Capstone2LlvmIrTranslatorArm64Tests : + public Capstone2LlvmIrTranslatorTests, + public ::testing::WithParamInterface +{ + protected: + virtual void initKeystoneEngine() override + { + ks_mode mode = KS_MODE_ARM; + switch(GetParam()) + { + // Basic modes. + case CS_MODE_ARM: mode = KS_MODE_LITTLE_ENDIAN; break; + // Extra modes. + case CS_MODE_MCLASS: mode = KS_MODE_LITTLE_ENDIAN; break; // Missing in Keystone. + case CS_MODE_V8: mode = KS_MODE_V8; break; + // Unhandled modes. + default: throw std::runtime_error("ERROR: unknown mode.\n"); + } + if (ks_open(KS_ARCH_ARM64, mode, &_assembler) != KS_ERR_OK) + { + throw std::runtime_error("ERROR: failed on ks_open().\n"); + } + } + + virtual void initCapstone2LlvmIrTranslator() override + { + switch(GetParam()) + { + case CS_MODE_ARM: + _translator = Capstone2LlvmIrTranslator::createArm64(&_module); + break; + default: + throw std::runtime_error("ERROR: unknown mode.\n"); + } + } + +}; + +struct PrintCapstoneModeToString_Arm64 +{ + template + std::string operator()(const TestParamInfo& info) const + { + switch (info.param) + { + case CS_MODE_ARM: return "CS_MODE_ARM"; + case CS_MODE_MCLASS: return "CS_MODE_MCLASS"; + case CS_MODE_V8: return "CS_MODE_V8"; + default: return "UNHANDLED CS_MODE"; + } + } +}; + +INSTANTIATE_TEST_CASE_P( + InstantiateArm64WithAllModes, + Capstone2LlvmIrTranslatorArm64Tests, + ::testing::Values(CS_MODE_ARM), + PrintCapstoneModeToString_Arm64()); + +// +// ARM_INS_ADD +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_r_r_i) +{ + + setRegisters({ + {ARM64_REG_X1, 0x1230}, + }); + + emulate("add x0, x1, #3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x1233},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +} // namespace tests +} // namespace capstone2llvmir +} // namespace retdec From 8caa63e7f65b2013e66dfa02f11cd5aca2832b3b Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sun, 16 Sep 2018 20:10:32 +0200 Subject: [PATCH 011/107] Basic MOV tests - MOV, MOVZ --- tests/capstone2llvmir/arm64_tests.cpp | 54 ++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 538e52979..88599d651 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -76,7 +76,7 @@ INSTANTIATE_TEST_CASE_P( PrintCapstoneModeToString_Arm64()); // -// ARM_INS_ADD +// ARM64_INS_ADD // TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_r_r_i) @@ -94,6 +94,58 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_r_r_i) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_MOV +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOV_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xcafebabecafebabe}, + }); + + emulate("mov x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xcafebabecafebabe}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVZ_r_i) +{ + setRegisters({ + {ARM64_REG_X0, 0xcafebabecafebabe}, + }); + + emulate("mov x0, #0xa"); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xa}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MVN_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x0123456789abcdef}, + }); + + emulate("mvn x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xfedcba9876543210}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + } // namespace tests } // namespace capstone2llvmir } // namespace retdec From 649d74d359651ae5a65bbdbe157d956e6d89e207 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 20 Sep 2018 12:04:30 +0200 Subject: [PATCH 012/107] Test for STR instruction and test header comments --- tests/capstone2llvmir/arm64_tests.cpp | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 88599d651..10f912b39 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -114,6 +114,10 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOV_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_MOVZ +// + TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVZ_r_i) { setRegisters({ @@ -130,6 +134,10 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVZ_r_i) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_MVN +// + TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MVN_r_r) { setRegisters({ @@ -146,6 +154,28 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MVN_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_STR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STR_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0xcafebabecafebabe}, + {ARM64_REG_X1, 0x1234}, + }); + + emulate("str x0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X0, ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1234, 0xcafebabecafebabe} + }); + EXPECT_NO_VALUE_CALLED(); +} + } // namespace tests } // namespace capstone2llvmir } // namespace retdec From 928f3e3a22b9ed557f89c36295b9d2d299a7c7fa Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 20 Sep 2018 22:12:16 +0200 Subject: [PATCH 013/107] STP instruction + tests, pc in new enum, get op addr function - Store pair instruction{pre-index, post-index, signed-offset} - test for all cases except 32bit operands - pc moved to its own enum - generateGetOperandAddr to generate address from instruction operand --- src/capstone2llvmir/arm64/arm64.cpp | 210 ++++++++++++++++------- src/capstone2llvmir/arm64/arm64_impl.h | 5 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 68 ++++++++ 4 files changed, 224 insertions(+), 61 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 291ed6caa..bd7ab3883 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -69,9 +69,8 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateDataLayout() void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() { - // General purpose registers. - // - + // General purpose registers. + // createRegister(ARM64_REG_X0, _regLt); createRegister(ARM64_REG_X1, _regLt); createRegister(ARM64_REG_X2, _regLt); @@ -160,6 +159,8 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() // Program counter. createRegister(ARM64_REG_PC, _regLt); + + // TODO: Generate parent register map } uint32_t Capstone2LlvmIrTranslatorArm64_impl::getCarryRegister() @@ -356,7 +357,7 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftMsl( unsigned op0BitW = llvm::cast(n->getType())->getBitWidth(); auto* doubleT = llvm::Type::getIntNTy(_module->getContext(), op0BitW*2); - auto* cf = loadRegister(ARM_REG_CPSR_C, irb); + auto* cf = loadRegister(ARM64_REG_CPSR_C, irb); cf = irb.CreateZExtOrTrunc(cf, n->getType()); auto* srl = irb.CreateLShr(val, n); @@ -381,6 +382,54 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftMsl( return or2Trunc; } +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateGetOperandMemAddr( + cs_arm64_op& op, + llvm::IRBuilder<>& irb) +{ + // TODO: generateGetOperandAddr? + auto* baseR = loadRegister(op.mem.base, irb); + auto* t = baseR ? baseR->getType() : getDefaultType(); + llvm::Value* disp = op.mem.disp + ? llvm::ConstantInt::get(t, op.mem.disp) + : nullptr; + + auto* idxR = loadRegister(op.mem.index, irb); + if (idxR) + { + idxR = generateOperandShift(irb, op, idxR); + } + + llvm::Value* addr = nullptr; + if (baseR && disp == nullptr) + { + addr = baseR; + } + else if (disp && baseR == nullptr) + { + addr = disp; + } + else if (baseR && disp) + { + disp = irb.CreateSExtOrTrunc(disp, baseR->getType()); + addr = irb.CreateAdd(baseR, disp); + } + else if (idxR) + { + addr = idxR; + } + else + { + addr = llvm::ConstantInt::get(getDefaultType(), 0); + } + + if (idxR && addr != idxR) + { + idxR = irb.CreateZExtOrTrunc(idxR, addr->getType()); + addr = irb.CreateAdd(addr, idxR); + } + return addr; +} + llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadRegister( uint32_t r, llvm::IRBuilder<>& irb, @@ -428,7 +477,54 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadOp( } case ARM64_OP_MEM: { - // TODO: MEM OP + /* + auto* baseR = loadRegister(op.mem.base, irb); + auto* t = baseR ? baseR->getType() : getDefaultType(); + llvm::Value* disp = op.mem.disp + ? llvm::ConstantInt::get(t, op.mem.disp) + : nullptr; + + auto* idxR = loadRegister(op.mem.index, irb); + if (idxR) + { + idxR = generateOperandShift(irb, op, idxR); + } + + llvm::Value* addr = nullptr; + if (baseR && disp == nullptr) + { + addr = baseR; + } + else if (disp && baseR == nullptr) + { + addr = disp; + } + else if (baseR && disp) + { + disp = irb.CreateSExtOrTrunc(disp, baseR->getType()); + addr = irb.CreateAdd(baseR, disp); + } + else if (idxR) + { + addr = idxR; + } + else + { + addr = llvm::ConstantInt::get(getDefaultType(), 0); + } + + if (idxR && addr != idxR) + { + idxR = irb.CreateZExtOrTrunc(idxR, addr->getType()); + addr = irb.CreateAdd(addr, idxR); + } + */ + auto* addr = generateGetOperandMemAddr(op, irb); + + auto* lty = ty ? ty : getDefaultType(); + auto* pt = llvm::PointerType::get(lty, 0); + addr = irb.CreateIntToPtr(addr, pt); + return irb.CreateLoad(addr); } case ARM64_OP_FP: case ARM64_OP_INVALID: @@ -488,60 +584,7 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeOp( } case ARM64_OP_MEM: { - auto* baseR = loadRegister(op.mem.base, irb); - auto* t = baseR ? baseR->getType() : getDefaultType(); - llvm::Value* disp = op.mem.disp - ? llvm::ConstantInt::get(t, op.mem.disp) - : nullptr; - - auto* idxR = loadRegister(op.mem.index, irb); - if (idxR) - { - //struct { - // arm64_shifter type; // shifter type of this operand - // unsigned int value; // shifter value of this operand - //} shift; - //if (op.mem.lshift) - //{ - // auto* lshift = llvm::ConstantInt::get( - // idxR->getType(), - // op.mem.lshift); - // idxR = irb.CreateShl(idxR, lshift); - //} - - // If there is a shift in memory operand, it is applied to - // the index register. - idxR = generateOperandShift(irb, op, idxR); - } - - llvm::Value* addr = nullptr; - if (baseR && disp == nullptr) - { - addr = baseR; - } - else if (disp && baseR == nullptr) - { - addr = disp; - } - else if (baseR && disp) - { - disp = irb.CreateSExtOrTrunc(disp, baseR->getType()); - addr = irb.CreateAdd(baseR, disp); - } - else if (idxR) - { - addr = idxR; - } - else - { - addr = llvm::ConstantInt::get(getDefaultType(), 0); - } - - if (idxR && addr != idxR) - { - idxR = irb.CreateZExtOrTrunc(idxR, addr->getType()); - addr = irb.CreateAdd(addr, idxR); - } + auto* addr = generateGetOperandMemAddr(op, irb); auto* pt = llvm::PointerType::get(val->getType(), 0); addr = irb.CreateIntToPtr(addr, pt); @@ -617,7 +660,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, op0 = loadOp(ai->operands[0], irb); op0 = irb.CreateZExtOrTrunc(op0, getDefaultType()); - uint32_t baseR = ARM_REG_INVALID; + uint32_t baseR = ARM64_REG_INVALID; llvm::Value* idx = nullptr; bool subtract = false; storeOp(ai->operands[1], op0, irb); @@ -641,5 +684,52 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, } } +/** + * ARM64_INS_STP + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + op0 = loadOp(ai->operands[0], irb); + op1 = loadOp(ai->operands[1], irb); + + uint32_t baseR = ARM64_REG_INVALID; + llvm::Value* newDest = nullptr; + auto* dest = generateGetOperandMemAddr(ai->operands[2], irb); + auto* registerSize = llvm::ConstantInt::get(getDefaultType(), getRegisterByteSize(ai->operands[0].reg)); + storeOp(ai->operands[2], op0, irb); + if(ai->op_count == 3) + { + newDest = irb.CreateAdd(dest, registerSize); + + auto* pt = llvm::PointerType::get(op1->getType(), 0); + auto* addr = irb.CreateIntToPtr(newDest, pt); + irb.CreateStore(op1, addr); + + baseR = ai->operands[2].mem.base; + } + else if(ai->op_count == 4) + { + auto* disp = llvm::ConstantInt::get(getDefaultType(), ai->operands[3].imm); + newDest = irb.CreateAdd(dest, registerSize); + + auto* pt = llvm::PointerType::get(op1->getType(), 0); + auto* addr = irb.CreateIntToPtr(newDest, pt); + irb.CreateStore(op1, addr); + + baseR = ai->operands[2].mem.base; + + newDest = irb.CreateAdd(dest, disp); + } + else + { + assert(false && "unsupported STP format"); + } + + if(ai->writeback && baseR != ARM64_REG_INVALID) + { + storeRegister(baseR, newDest, irb); + } +} + } // namespace capstone2llvmir } // namespace retdec diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 416d2f3a6..1da9a8e9a 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -83,6 +83,10 @@ class Capstone2LlvmIrTranslatorArm64_impl : llvm::Value* val, llvm::Value* n); + llvm::Value* generateGetOperandMemAddr( + cs_arm64_op& op, + llvm::IRBuilder<>& irb); + virtual llvm::Value* loadRegister( uint32_t r, llvm::IRBuilder<>& irb, @@ -126,6 +130,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateStp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); }; diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 2869dec71..538323159 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -509,7 +509,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_STLXRH, nullptr}, {ARM64_INS_STLXR, nullptr}, {ARM64_INS_STNP, nullptr}, - {ARM64_INS_STP, nullptr}, + {ARM64_INS_STP, &Capstone2LlvmIrTranslatorArm64_impl::translateStp}, {ARM64_INS_STRB, nullptr}, {ARM64_INS_STR, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, {ARM64_INS_STRH, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 10f912b39..444565496 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -176,6 +176,74 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STR_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_STP +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STP_r_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0x0123456789abcdef}, + {ARM64_REG_X2, 0xfedcba9876543210}, + {ARM64_REG_SP, 0x1234}, + }); + + emulate("stp x0, x2, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X0, ARM64_REG_X2, ARM64_REG_SP}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1234, 0x0123456789abcdef_qw}, + {0x123c, 0xfedcba9876543210_qw} + }); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STP_r_r_mw) +{ + setRegisters({ + {ARM64_REG_X0, 0x0123456789abcdef}, + {ARM64_REG_X2, 0xfedcba9876543210}, + {ARM64_REG_SP, 0x1234}, + }); + + emulate("stp x0, x2, [sp, #-0x20]!"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X0, ARM64_REG_X2, ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_SP, 0x121c} + }); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1214, 0x0123456789abcdef_qw}, + {0x121c, 0xfedcba9876543210_qw} + }); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STP_r_r_m_i) +{ + setRegisters({ + {ARM64_REG_X0, 0x0123456789abcdef}, + {ARM64_REG_X2, 0xfedcba9876543210}, + {ARM64_REG_SP, 0x1234}, + }); + + emulate("stp x0, x2, [sp], #-0x20"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X0, ARM64_REG_X2, ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_SP, 0x1214} + }); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1234, 0x0123456789abcdef_qw}, + {0x123c, 0xfedcba9876543210_qw} + }); + EXPECT_NO_VALUE_CALLED(); +} + } // namespace tests } // namespace capstone2llvmir } // namespace retdec From bf88c1e4e1f66162de93320eb8c36d688bcdb795 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 21 Sep 2018 22:41:17 +0200 Subject: [PATCH 014/107] LDR + STR, LDR tests from ARM, LDP stub - LDR{pre-index, post-index, signed-offset} instruction implemented - STR{pre-index, post-index, signed-offset} instruction implemented - LDR tests ported from ARM - LDP todo --- src/capstone2llvmir/arm64/arm64.cpp | 127 ++++++++------- src/capstone2llvmir/arm64/arm64_impl.h | 2 + src/capstone2llvmir/arm64/arm64_init.cpp | 8 +- tests/capstone2llvmir/arm64_tests.cpp | 190 +++++++++++++++++++++++ 4 files changed, 265 insertions(+), 62 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index bd7ab3883..9894c1ec5 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -477,48 +477,6 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadOp( } case ARM64_OP_MEM: { - /* - auto* baseR = loadRegister(op.mem.base, irb); - auto* t = baseR ? baseR->getType() : getDefaultType(); - llvm::Value* disp = op.mem.disp - ? llvm::ConstantInt::get(t, op.mem.disp) - : nullptr; - - auto* idxR = loadRegister(op.mem.index, irb); - if (idxR) - { - idxR = generateOperandShift(irb, op, idxR); - } - - llvm::Value* addr = nullptr; - if (baseR && disp == nullptr) - { - addr = baseR; - } - else if (disp && baseR == nullptr) - { - addr = disp; - } - else if (baseR && disp) - { - disp = irb.CreateSExtOrTrunc(disp, baseR->getType()); - addr = irb.CreateAdd(baseR, disp); - } - else if (idxR) - { - addr = idxR; - } - else - { - addr = llvm::ConstantInt::get(getDefaultType(), 0); - } - - if (idxR && addr != idxR) - { - idxR = irb.CreateZExtOrTrunc(idxR, addr->getType()); - addr = irb.CreateAdd(addr, idxR); - } - */ auto* addr = generateGetOperandMemAddr(op, irb); auto* lty = ty ? ty : getDefaultType(); @@ -658,29 +616,33 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMov(cs_insn* i, cs_arm64* ai, void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { op0 = loadOp(ai->operands[0], irb); - op0 = irb.CreateZExtOrTrunc(op0, getDefaultType()); + auto* dest = generateGetOperandMemAddr(ai->operands[1], irb); + + auto* pt = llvm::PointerType::get(op0->getType(), 0); + auto* addr = irb.CreateIntToPtr(dest, pt); + irb.CreateStore(op0, addr); uint32_t baseR = ARM64_REG_INVALID; - llvm::Value* idx = nullptr; - bool subtract = false; - storeOp(ai->operands[1], op0, irb); - baseR = ai->operands[1].mem.base; - if (auto disp = ai->operands[1].mem.disp) + if(ai->op_count == 2) + { + baseR = ai->operands[1].reg; + } + else if(ai->op_count == 3) { - idx = llvm::ConstantInt::getSigned(getDefaultType(), disp); + baseR = ai->operands[1].reg; + + auto* disp = llvm::ConstantInt::get(getDefaultType(), ai->operands[2].imm); + dest = irb.CreateAdd(dest, disp); + // post-index -> always writeback } - else if (ai->operands[1].mem.index != ARM64_REG_INVALID) + else { - idx = loadRegister(ai->operands[1].mem.index, irb); + assert(false && "unsupported STR format"); } - if (ai->writeback && idx && baseR != ARM64_REG_INVALID) + if(ai->writeback && baseR != ARM64_REG_INVALID) { - auto* b = loadRegister(baseR, irb); - auto* v = subtract - ? irb.CreateSub(b, idx) - : irb.CreateAdd(b, idx); - storeRegister(baseR, v, irb); + storeRegister(baseR, dest, irb); } } @@ -727,8 +689,57 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, if(ai->writeback && baseR != ARM64_REG_INVALID) { - storeRegister(baseR, newDest, irb); + storeRegister(baseR, newDest, irb); + } +} + +/** + * ARM64_INS_LDR + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + auto* regType = getRegisterType(ai->operands[0].reg); + auto* dest = generateGetOperandMemAddr(ai->operands[1], irb); + auto* pt = llvm::PointerType::get(regType, 0); + auto* addr = irb.CreateIntToPtr(dest, pt); + + auto* newRegValue = irb.CreateLoad(addr); + storeRegister(ai->operands[0].reg, newRegValue, irb); + + uint32_t baseR = ARM64_REG_INVALID; + if(ai->op_count == 2) + { + baseR = ai->operands[1].reg; } + else if(ai->op_count == 3) + { + baseR = ai->operands[1].reg; + + auto* disp = llvm::ConstantInt::get(getDefaultType(), ai->operands[2].imm); + dest = irb.CreateAdd(dest, disp); + // post-index -> always writeback + } + else + { + assert(false && "unsupported LDR format"); + } + + if(ai->writeback && baseR != ARM64_REG_INVALID) + { + storeRegister(baseR, dest, irb); + } +} + +/** + * ARM64_INS_LDP + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + // TODO: Implement + // TODO: Get adress from op2 + // TODO: Load op0 from op2 addr + // TODO: Add registerSize to op2 addr + // TODO: Load op2 from op2 addr + registerSize } } // namespace capstone2llvmir diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 1da9a8e9a..4351cc3a3 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -131,6 +131,8 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateStp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateLdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateLdp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); }; diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 538323159..267b2d0c8 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -342,10 +342,10 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_LDAXRH, nullptr}, {ARM64_INS_LDAXR, nullptr}, {ARM64_INS_LDNP, nullptr}, - {ARM64_INS_LDP, nullptr}, + {ARM64_INS_LDP, &Capstone2LlvmIrTranslatorArm64_impl::translateLdp}, {ARM64_INS_LDPSW, nullptr}, {ARM64_INS_LDRB, nullptr}, - {ARM64_INS_LDR, nullptr}, + {ARM64_INS_LDR, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDRH, nullptr}, {ARM64_INS_LDRSB, nullptr}, {ARM64_INS_LDRSH, nullptr}, @@ -358,7 +358,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_LDTRSW, nullptr}, {ARM64_INS_LDTR, nullptr}, {ARM64_INS_LDURB, nullptr}, - {ARM64_INS_LDUR, nullptr}, + {ARM64_INS_LDUR, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDURH, nullptr}, {ARM64_INS_LDURSB, nullptr}, {ARM64_INS_LDURSH, nullptr}, @@ -517,7 +517,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_STTRH, nullptr}, {ARM64_INS_STTR, nullptr}, {ARM64_INS_STURB, nullptr}, - {ARM64_INS_STUR, nullptr}, + {ARM64_INS_STUR, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, {ARM64_INS_STURH, nullptr}, {ARM64_INS_STXP, nullptr}, {ARM64_INS_STXRB, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 444565496..9a04ffe53 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -244,6 +244,196 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STP_r_r_m_i) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_LDR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x123456789abcdef0_qw}, + }); + + emulate("ldr x0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR_plus_imm) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1008, 0x123456789abcdef0_qw}, + }); + + emulate("ldr x0, [x1, #8]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1008}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR_minus_imm) +{ + setRegisters({ + {ARM64_REG_X1, 0x1010}, + }); + setMemory({ + {0x1008, 0x123456789abcdef0_qw}, + }); + + emulate("ldr x0, [x1, #-8]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1008}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR_plus_reg) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000}, + {ARM64_REG_X2, 0x8}, + }); + setMemory({ + {0x1008, 0x123456789abcdef0_qw}, + }); + + emulate("ldr x0, [x1, x2]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1008}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR_minus_reg) +{ + setRegisters({ + {ARM64_REG_X1, 0x1010}, + {ARM64_REG_X2, -0x8}, + }); + setMemory({ + {0x1008, 0x123456789abcdef0_qw}, + }); + + emulate("ldr x0, [x1, x2]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1008}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR_plus_imm_preindexed_writeback) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1008, 0x123456789abcdef0_qw}, + }); + + emulate("ldr x0, [x1, #8]!"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_X1, 0x1008}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1008}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR_minus_imm_preindexed_writeback) +{ + setRegisters({ + {ARM64_REG_X1, 0x1010}, + }); + setMemory({ + {0x1008, 0x123456789abcdef0_qw}, + }); + + emulate("ldr x0, [x1, #-8]!"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_X1, 0x1008}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1008}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR_plus_imm_postindexed_writeback) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x123456789abcdef0_qw}, + }); + + emulate("ldr x0, [x1], #8"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_X1, 0x1008}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR_minus_imm_postindexed_writeback) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x123456789abcdef0_qw}, + }); + + emulate("ldr x0, [x1], #-8"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_X1, 0xff8}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + } // namespace tests } // namespace capstone2llvmir } // namespace retdec From 8916e1279e4b4efb09dedf2490755712d019cded Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 22 Sep 2018 21:03:51 +0200 Subject: [PATCH 015/107] Implemented parent register handling - Register parent map - Storing registers - Loading registers - Headers - Need more changes to conversions, I think 'mov w0, #3' zeroes out the upper 32bits of x0 register. But need to investigate further. --- include/retdec/capstone2llvmir/arm64/arm64.h | 7 ++ src/capstone2llvmir/arm64/arm64.cpp | 71 +++++++++++++++++--- src/capstone2llvmir/arm64/arm64_impl.h | 18 +++++ src/capstone2llvmir/arm64/arm64_init.cpp | 59 ++++++++++++++++ 4 files changed, 145 insertions(+), 10 deletions(-) diff --git a/include/retdec/capstone2llvmir/arm64/arm64.h b/include/retdec/capstone2llvmir/arm64/arm64.h index 14c4eba2e..76d089b37 100644 --- a/include/retdec/capstone2llvmir/arm64/arm64.h +++ b/include/retdec/capstone2llvmir/arm64/arm64.h @@ -20,6 +20,13 @@ class Capstone2LlvmIrTranslatorArm64 : virtual public Capstone2LlvmIrTranslator { public: virtual ~Capstone2LlvmIrTranslatorArm64() {}; + + public: + /** + * @return Capstone register that is parent to the specified Capstone + * register @p r. Register can be its own parent. + */ + virtual uint32_t getParentRegister(uint32_t r) const = 0; }; } // namespace capstone2llvmir diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 9894c1ec5..bef66674c 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -17,7 +17,8 @@ Capstone2LlvmIrTranslatorArm64_impl::Capstone2LlvmIrTranslatorArm64_impl( cs_mode basic, cs_mode extra) : - Capstone2LlvmIrTranslator_impl(CS_ARCH_ARM64, basic, extra, m) + Capstone2LlvmIrTranslator_impl(CS_ARCH_ARM64, basic, extra, m), + _reg2parentMap(ARM64_REG_ENDING, ARM64_REG_INVALID) { initialize(); } @@ -58,7 +59,7 @@ uint32_t Capstone2LlvmIrTranslatorArm64_impl::getArchByteSize() void Capstone2LlvmIrTranslatorArm64_impl::generateEnvironmentArchSpecific() { - // Nothing. + initializeRegistersParentMap(); } void Capstone2LlvmIrTranslatorArm64_impl::generateDataLayout() @@ -103,6 +104,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() // Lower 32 bits of 64 arm{xN} bit regs. // + /* createRegister(ARM64_REG_W0, _regLt); createRegister(ARM64_REG_W1, _regLt); createRegister(ARM64_REG_W2, _regLt); @@ -134,6 +136,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() createRegister(ARM64_REG_W28, _regLt); createRegister(ARM64_REG_W29, _regLt); createRegister(ARM64_REG_W30, _regLt); + */ // Special registers. @@ -145,11 +148,11 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() // Stack pointer. createRegister(ARM64_REG_SP, _regLt); - createRegister(ARM64_REG_WSP, _regLt); + //createRegister(ARM64_REG_WSP, _regLt); // Zero. createRegister(ARM64_REG_XZR, _regLt); - createRegister(ARM64_REG_WZR, _regLt); + //createRegister(ARM64_REG_WZR, _regLt); // Flags. createRegister(ARM64_REG_CPSR_N, _regLt); @@ -159,8 +162,6 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() // Program counter. createRegister(ARM64_REG_PC, _regLt); - - // TODO: Generate parent register map } uint32_t Capstone2LlvmIrTranslatorArm64_impl::getCarryRegister() @@ -209,6 +210,12 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( } } +uint32_t Capstone2LlvmIrTranslatorArm64_impl::getParentRegister(uint32_t r) const +{ + return r < _reg2parentMap.size() ? _reg2parentMap[r] : r; +} + + // //============================================================================== // ARM64-specific methods. @@ -447,13 +454,22 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadRegister( // TODO: Check } - auto* llvmReg = getRegister(r); + auto* rt = getRegisterType(r); + auto pr = getParentRegister(r); + auto* llvmReg = getRegister(pr); if (llvmReg == nullptr) { throw Capstone2LlvmIrError("loadRegister() unhandled reg."); } - return irb.CreateLoad(llvmReg); + llvm::Value* ret = irb.CreateLoad(llvmReg); + if (r != pr) + { + ret = irb.CreateTrunc(ret, rt); + } + + ret = generateTypeConversion(irb, ret, dstType, ct); + return ret; } llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadOp( @@ -517,14 +533,49 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeRegister( // TODO: Check? } - auto* llvmReg = getRegister(r); + auto* rt = getRegisterType(r); + auto pr = getParentRegister(r); + auto* llvmReg = getRegister(pr); if (llvmReg == nullptr) { throw Capstone2LlvmIrError("storeRegister() unhandled reg."); } + val = generateTypeConversion(irb, val, llvmReg->getValueType(), ct); - return irb.CreateStore(val, llvmReg); + llvm::StoreInst* ret = nullptr; + if (r == pr + // Zext for 64-bit target llvmRegs & 32-bit source regs. + || (getRegisterBitSize(pr) == 64 && getRegisterBitSize(r) == 32)) + { + ret = irb.CreateStore(val, llvmReg); + } + else + { + llvm::Value* l = irb.CreateLoad(llvmReg); + if (!(l->getType()->isIntegerTy(16) + || l->getType()->isIntegerTy(32) + || l->getType()->isIntegerTy(64))) + { + throw Capstone2LlvmIrError("Unexpected parent type."); + } + + llvm::Value* andC = nullptr; + if (rt->isIntegerTy(32)) + { + if (l->getType()->isIntegerTy(64)) + { + andC = irb.getInt64(0xffffffff00000000); + } + } + assert(andC); + l = irb.CreateAnd(l, andC); + + auto* o = irb.CreateOr(l, val); + ret = irb.CreateStore(o, llvmReg); + } + + return ret; } llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeOp( diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 4351cc3a3..a4069afb8 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -32,6 +32,15 @@ class Capstone2LlvmIrTranslatorArm64_impl : virtual bool isAllowedBasicMode(cs_mode m) override; virtual bool isAllowedExtraMode(cs_mode m) override; virtual uint32_t getArchByteSize() override; + +// +//============================================================================== +// x86 specialization methods - from Capstone2LlvmIrTranslatorX86 +//============================================================================== +// + public: + + virtual uint32_t getParentRegister(uint32_t r) const override; // //============================================================================== // Pure virtual methods from Capstone2LlvmIrTranslator_impl @@ -58,6 +67,12 @@ class Capstone2LlvmIrTranslatorArm64_impl : protected: llvm::Value* getCurrentPc(cs_insn* i); + void initializeRegistersParentMapToOther( + const std::vector& rs, + arm64_reg other); + + void initializeRegistersParentMap(); + llvm::Value* generateOperandShift( llvm::IRBuilder<>& irb, cs_arm64_op& op, @@ -115,6 +130,9 @@ class Capstone2LlvmIrTranslatorArm64_impl : //============================================================================== // protected: + + std::vector _reg2parentMap; + static std::map< std::size_t, void (Capstone2LlvmIrTranslatorArm64_impl::*)( diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 267b2d0c8..9616224ee 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -166,6 +166,65 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializePseudoCallInstructionIDs() }; } +void Capstone2LlvmIrTranslatorArm64_impl::initializeRegistersParentMapToOther( + const std::vector& rs, + arm64_reg other) +{ + for (auto r : rs) + { + assert(r < _reg2parentMap.size()); + _reg2parentMap[r] = other; + } +} + + +void Capstone2LlvmIrTranslatorArm64_impl::initializeRegistersParentMap() +{ + // Last element in vector is its own parent. + std::vector> rss = + { + {ARM64_REG_W0, ARM64_REG_X0}, + {ARM64_REG_W1, ARM64_REG_X1}, + {ARM64_REG_W2, ARM64_REG_X2}, + {ARM64_REG_W3, ARM64_REG_X3}, + {ARM64_REG_W4, ARM64_REG_X4}, + {ARM64_REG_W5, ARM64_REG_X5}, + {ARM64_REG_W6, ARM64_REG_X6}, + {ARM64_REG_W7, ARM64_REG_X7}, + {ARM64_REG_W8, ARM64_REG_X8}, + {ARM64_REG_W9, ARM64_REG_X9}, + {ARM64_REG_W10, ARM64_REG_X10}, + {ARM64_REG_W11, ARM64_REG_X11}, + {ARM64_REG_W12, ARM64_REG_X12}, + {ARM64_REG_W13, ARM64_REG_X13}, + {ARM64_REG_W14, ARM64_REG_X14}, + {ARM64_REG_W15, ARM64_REG_X15}, + {ARM64_REG_W16, ARM64_REG_X16}, + {ARM64_REG_W17, ARM64_REG_X17}, + {ARM64_REG_W18, ARM64_REG_X18}, + {ARM64_REG_W19, ARM64_REG_X19}, + {ARM64_REG_W20, ARM64_REG_X20}, + {ARM64_REG_W21, ARM64_REG_X21}, + {ARM64_REG_W22, ARM64_REG_X22}, + {ARM64_REG_W23, ARM64_REG_X23}, + {ARM64_REG_W24, ARM64_REG_X24}, + {ARM64_REG_W25, ARM64_REG_X25}, + {ARM64_REG_W26, ARM64_REG_X26}, + {ARM64_REG_W27, ARM64_REG_X27}, + {ARM64_REG_W28, ARM64_REG_X28}, + {ARM64_REG_W29, ARM64_REG_X29}, + {ARM64_REG_W30, ARM64_REG_X30}, + + {ARM64_REG_WSP, ARM64_REG_SP}, + {ARM64_REG_WZR, ARM64_REG_XZR} + }; + + for (std::vector& rs : rss) + { + initializeRegistersParentMapToOther(rs, rs.back()); + } +} + // //============================================================================== // Instruction translation map initialization. From 9b627691928afbd47754fcb558eca696e55dbe1d Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 22 Sep 2018 21:37:04 +0200 Subject: [PATCH 016/107] LLVM data layout modified for ARM64 - taken from uname -a in qemu arm64 machine Linux debian-aarch64 4.9.0-4-arm64 #1 SMP Debian 4.9.65-3+deb9u1 (2017-12-23) aarch64 GNU/Linux --- src/capstone2llvmir/arm64/arm64.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index bef66674c..64ac16631 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -64,8 +64,8 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateEnvironmentArchSpecific() void Capstone2LlvmIrTranslatorArm64_impl::generateDataLayout() { - _module->setDataLayout("e-p:32:32:32-f80:32:32"); - // TODO: Modify data layout. + // clang -x c /dev/null -emit-llvm -S -o - + _module->setDataLayout("e-m:e-i64:64-i128:128-n32:64-S128"); } void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() From 372f8964dc14cfb68da670e4ea8b00e94bff4167 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sun, 23 Sep 2018 10:36:53 +0200 Subject: [PATCH 017/107] Removed useless debug output --- src/capstone2llvmir/arm64/arm64.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 64ac16631..7a11f3c56 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -178,7 +178,6 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( cs_detail* d = i->detail; cs_arm64* ai = &d->arm64; - std::cerr << "Translating instruction: " << cs_insn_name(_handle, i->id) << std::endl; auto fIt = _i2fm.find(i->id); if (fIt != _i2fm.end() && fIt->second != nullptr) { From d369bfb5948c952c0db1c01b3a870ce9bc74c361 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sun, 23 Sep 2018 10:39:23 +0200 Subject: [PATCH 018/107] getCarryRegister for ARM64 fixed --- src/capstone2llvmir/arm64/arm64.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 7a11f3c56..855d39974 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -166,7 +166,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() uint32_t Capstone2LlvmIrTranslatorArm64_impl::getCarryRegister() { - return 0; /* TODO: ARM_REG_CPSR_C; */ + return ARM64_REG_CPSR_C; } void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( From 8631ae756a30d357cbecc2e8438f03ff907c27dd Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sun, 23 Sep 2018 16:11:27 +0200 Subject: [PATCH 019/107] Store register ZEXT_TRUNC, 32bit tests baseline + tests - when writing value to 32bit reg the 64bit, the value is zero extended to the vhole register - parent register mapping enabled in tests - 32bit version of tests --- src/capstone2llvmir/arm64/arm64.cpp | 4 +- src/capstone2llvmir/arm64/arm64_impl.h | 4 +- tests/capstone2llvmir/arm64_tests.cpp | 183 +++++++++++++++++++++++++ 3 files changed, 188 insertions(+), 3 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 855d39974..547c39768 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -214,7 +214,6 @@ uint32_t Capstone2LlvmIrTranslatorArm64_impl::getParentRegister(uint32_t r) cons return r < _reg2parentMap.size() ? _reg2parentMap[r] : r; } - // //============================================================================== // ARM64-specific methods. @@ -627,6 +626,9 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeOp( void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { std::tie(op1, op2) = loadOpTernaryOp1Op2(ai, irb); + // In case of 32bit reg, trunc the imm + op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); + auto *val = irb.CreateAdd(op1, op2); storeOp(ai->operands[0], val, irb); } diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index a4069afb8..861b9cdf0 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -117,12 +117,12 @@ class Capstone2LlvmIrTranslatorArm64_impl : uint32_t r, llvm::Value* val, llvm::IRBuilder<>& irb, - eOpConv ct = eOpConv::SEXT_TRUNC) override; + eOpConv ct = eOpConv::ZEXT_TRUNC) override; virtual llvm::Instruction* storeOp( cs_arm64_op& op, llvm::Value* val, llvm::IRBuilder<>& irb, - eOpConv ct = eOpConv::SEXT_TRUNC) override; + eOpConv ct = eOpConv::ZEXT_TRUNC) override; // //============================================================================== diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 9a04ffe53..3af7b1960 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -52,6 +52,83 @@ class Capstone2LlvmIrTranslatorArm64Tests : } } + protected: + Capstone2LlvmIrTranslatorArm64* getArm64Translator() + { + return dynamic_cast(_translator.get()); + } + + // Some of these (or their parts) might be moved to abstract parent class. + // + protected: + uint32_t getParentRegister(uint32_t reg) + { + return getArm64Translator()->getParentRegister(reg); + } + + virtual llvm::GlobalVariable* getRegister(uint32_t reg) override + { + return _translator->getRegister(getParentRegister(reg)); + } + + virtual uint64_t getRegisterValueUnsigned(uint32_t reg) override + { + auto preg = getParentRegister(reg); + auto* gv = getRegister(preg); + auto val = _emulator->getGlobalVariableValue(gv).IntVal.getZExtValue(); + + if (reg == preg) + { + return val; + } + + switch (_translator->getRegisterBitSize(reg)) + { + case 32: return static_cast(val); + case 64: return static_cast(val); + default: throw std::runtime_error("Unknown reg bit size."); + } + } + + virtual void setRegisterValueUnsigned(uint32_t reg, uint64_t val) override + { + auto preg = getParentRegister(reg); + auto* gv = getRegister(preg); + auto* t = cast(gv->getValueType()); + + GenericValue v = _emulator->getGlobalVariableValue(gv); + + if (reg == preg) + { + bool isSigned = false; + v.IntVal = APInt(t->getBitWidth(), val, isSigned); + _emulator->setGlobalVariableValue(gv, v); + return; + } + + uint64_t old = v.IntVal.getZExtValue(); + + switch (_translator->getRegisterBitSize(reg)) + { + case 32: + val = val & 0x00000000ffffffff; + old = old & 0xffffffff00000000; + break; + case 64: + val = val & 0xffffffffffffffff; + old = old & 0x0000000000000000; + break; + default: + throw std::runtime_error("Unknown reg bit size."); + } + + val = old | val; + bool isSigned = false; + v.IntVal = APInt(t->getBitWidth(), val, isSigned); + _emulator->setGlobalVariableValue(gv, v); + return; + } + }; struct PrintCapstoneModeToString_Arm64 @@ -94,6 +171,21 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_r_r_i) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD32_r_r_i) +{ + + setRegisters({ + {ARM64_REG_W1, 0x1230}, + }); + + emulate("add w0, w1, #3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x1233},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MOV // @@ -114,6 +206,22 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOV_r_r) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOV32_r_r) +{ + setRegisters({ + {ARM64_REG_W1, 0xcafebabe}, + }); + + emulate("mov w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_W0, 0xcafebabe}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MOVZ // @@ -154,6 +262,22 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MVN_r_r) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MVN32_r_r) +{ + setRegisters({ + {ARM64_REG_W1, 0x89abcdef}, + }); + + emulate("mvn w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_W0, 0x76543210}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_STR // @@ -176,6 +300,24 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STR_r_r) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STR32_r_r) +{ + setRegisters({ + {ARM64_REG_W0, 0xcafebabe}, + {ARM64_REG_X1, 0x1234}, + }); + + emulate("str w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W0, ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1234, 0xcafebabe} + }); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_STP // @@ -200,6 +342,26 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STP_r_r_r) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STP32_r_r_r) +{ + setRegisters({ + {ARM64_REG_W0, 0x01234567}, + {ARM64_REG_W2, 0xfedcba98}, + {ARM64_REG_SP, 0x1234}, + }); + + emulate("stp w0, w2, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W0, ARM64_REG_W2, ARM64_REG_SP}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1234, 0x01234567_dw}, + {0x1238, 0xfedcba98_dw} + }); + EXPECT_NO_VALUE_CALLED(); +} + TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STP_r_r_mw) { setRegisters({ @@ -268,6 +430,27 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR32) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000}, + //{ARM64_REG_X0, 0xcafebabecafebabe}, + }); + setMemory({ + {0x1000, 0x12345678_dw}, + }); + + emulate("ldr w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_W0, 0x12345678}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR_plus_imm) { setRegisters({ From 762666291664e26d017acd7d9b4598acb454766d Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sun, 23 Sep 2018 17:04:41 +0200 Subject: [PATCH 020/107] Zero extension tests for ADD and MOV 32bit variants --- tests/capstone2llvmir/arm64_tests.cpp | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 3af7b1960..a04c09e8f 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -186,6 +186,22 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD32_r_r_i) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD32_r_r_i_extend_test) +{ + // Value should be Zero extended into 64bit register + setRegisters({ + {ARM64_REG_X0, 0xcafebabecafebabe}, + {ARM64_REG_W1, 0xf0000000}, + }); + + emulate("add w0, w1, #1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0xf0000001},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MOV // @@ -206,6 +222,23 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOV_r_r) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOV32_r_r_extend_test) +{ + setRegisters({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_W1, 0xf0000000}, + }); + + emulate("mov w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_W0, 0xf0000000}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOV32_r_r) { setRegisters({ From 58381bb952d8e66083888c8cba4a32fb21d7da10 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sun, 23 Sep 2018 20:22:21 +0200 Subject: [PATCH 021/107] Implemented BL instruction - added tests for label and imm branch --- src/capstone2llvmir/arm64/arm64.cpp | 10 ++++++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 32 ++++++++++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 547c39768..d8ee7c2cd 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -794,5 +794,15 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, // TODO: Load op2 from op2 addr + registerSize } +/** + * ARM64_INS_BL + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateBl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + storeRegister(ARM64_REG_LR, getNextInsnAddress(i), irb); + op0 = loadOpUnary(ai, irb); + generateCallFunctionCall(irb, op0); +} + } // namespace capstone2llvmir } // namespace retdec diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 861b9cdf0..ecc882548 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -151,6 +151,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateStp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateLdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateLdp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateBl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); }; diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 9616224ee..8a7c58c7d 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -261,7 +261,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_BIC, nullptr}, {ARM64_INS_BIF, nullptr}, {ARM64_INS_BIT, nullptr}, - {ARM64_INS_BL, nullptr}, + {ARM64_INS_BL, &Capstone2LlvmIrTranslatorArm64_impl::translateBl}, {ARM64_INS_BLR, nullptr}, {ARM64_INS_BR, nullptr}, {ARM64_INS_BRK, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index a04c09e8f..323e25b19 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -650,6 +650,38 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR_minus_imm_postindexed_ EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_BL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_BL) +{ + emulate("bl #0x110d8", 0x1107C); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_LR, 0x11080}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCallFunction(), {0x110d8}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_BL_label) +{ + emulate("label_test:; bl label_test", 0x1000); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_LR, 0x1004}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCallFunction(), {0x1000}}, + }); +} + } // namespace tests } // namespace capstone2llvmir } // namespace retdec From f0f9195e83c5b29c7e336c90cddad2e4d067b6f0 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sun, 23 Sep 2018 20:36:22 +0200 Subject: [PATCH 022/107] Implemented RET instruction - added tests --- src/capstone2llvmir/arm64/arm64.cpp | 9 +++++++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 21 +++++++++++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index d8ee7c2cd..b7bbbfc74 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -804,5 +804,14 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateBl(cs_insn* i, cs_arm64* ai, generateCallFunctionCall(irb, op0); } +/** + * ARM64_INS_RET + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + op0 = loadRegister(ARM64_REG_LR, irb); + generateReturnFunctionCall(irb, op0); +} + } // namespace capstone2llvmir } // namespace retdec diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index ecc882548..da279628a 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -152,6 +152,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateLdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateLdp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateBl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); }; diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 8a7c58c7d..9a8ecd3f0 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -452,7 +452,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_RADDHN, nullptr}, {ARM64_INS_RADDHN2, nullptr}, {ARM64_INS_RBIT, nullptr}, - {ARM64_INS_RET, nullptr}, + {ARM64_INS_RET, &Capstone2LlvmIrTranslatorArm64_impl::translateRet}, {ARM64_INS_REV16, nullptr}, {ARM64_INS_REV32, nullptr}, {ARM64_INS_REV64, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 323e25b19..9f44336a8 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -682,6 +682,27 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_BL_label) }); } +// +// ARM64_INS_RET +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_RET) +{ + setRegisters({ + {ARM64_REG_LR, 0xcafebabe}, + }); + + emulate("ret"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_LR}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getReturnFunction(), {0xcafebabe}}, + }); +} + + } // namespace tests } // namespace capstone2llvmir } // namespace retdec From 8af607ce40aeadb77b2d32fc5f5b8103ac5060f1 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sun, 23 Sep 2018 21:10:40 +0200 Subject: [PATCH 023/107] Implemented LDP instruction - added tests for instruction --- src/capstone2llvmir/arm64/arm64.cpp | 48 ++++++++++++-- tests/capstone2llvmir/arm64_tests.cpp | 96 ++++++++++++++++++++++++++- 2 files changed, 138 insertions(+), 6 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index b7bbbfc74..d98079473 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -787,11 +787,49 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, */ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { - // TODO: Implement - // TODO: Get adress from op2 - // TODO: Load op0 from op2 addr - // TODO: Add registerSize to op2 addr - // TODO: Load op2 from op2 addr + registerSize + auto* regType = getRegisterType(ai->operands[0].reg); + auto* dest = generateGetOperandMemAddr(ai->operands[2], irb); + auto* pt = llvm::PointerType::get(regType, 0); + auto* addr = irb.CreateIntToPtr(dest, pt); + auto* registerSize = llvm::ConstantInt::get(getDefaultType(), getRegisterByteSize(ai->operands[0].reg)); + + auto* newReg1Value = irb.CreateLoad(addr); + + llvm::Value* newDest = nullptr; + llvm::Value* newReg2Value = nullptr; + uint32_t baseR = ARM64_REG_INVALID; + if(ai->op_count == 3) + { + storeRegister(ai->operands[0].reg, newReg1Value, irb); + newDest = irb.CreateAdd(dest, registerSize); + addr = irb.CreateIntToPtr(newDest, pt); + newReg2Value = irb.CreateLoad(addr); + storeRegister(ai->operands[1].reg, newReg2Value, irb); + + baseR = ai->operands[2].mem.base; + } + else if(ai->op_count == 4) + { + + storeRegister(ai->operands[0].reg, newReg1Value, irb); + newDest = irb.CreateAdd(dest, registerSize); + addr = irb.CreateIntToPtr(newDest, pt); + newReg2Value = irb.CreateLoad(addr); + storeRegister(ai->operands[1].reg, newReg2Value, irb); + + auto* disp = llvm::ConstantInt::get(getDefaultType(), ai->operands[3].imm); + dest = irb.CreateAdd(dest, disp); + baseR = ai->operands[2].mem.base; + } + else + { + assert(false && "unsupported LDP format"); + } + + if(ai->writeback && baseR != ARM64_REG_INVALID) + { + storeRegister(baseR, dest, irb); + } } /** diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 9f44336a8..d1d825338 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -467,7 +467,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR32) { setRegisters({ {ARM64_REG_X1, 0x1000}, - //{ARM64_REG_X0, 0xcafebabecafebabe}, + {ARM64_REG_X0, 0xcafebabecafebabe}, }); setMemory({ {0x1000, 0x12345678_dw}, @@ -650,6 +650,100 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR_minus_imm_postindexed_ EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_LDP +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDP_r_r_r) +{ + setRegisters({ + {ARM64_REG_SP, 0x1000}, + }); + setMemory({ + {0x1000, 0x123456789abcdef0_qw}, + {0x1008, 0xfedcba9876543210_qw}, + }); + + emulate("ldp x0, x1, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_X1, 0xfedcba9876543210}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000, 0x1008}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDP32_r_r_r) +{ + setRegisters({ + {ARM64_REG_SP, 0x1000}, + }); + setMemory({ + {0x1000, 0x12345678_dw}, + {0x1004, 0x9abcdef0_dw}, + }); + + emulate("ldp w0, w1, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_W0, 0x12345678}, + {ARM64_REG_W1, 0x9abcdef0}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000, 0x1004}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDP_r_r_mw) +{ + setRegisters({ + {ARM64_REG_SP, 0x1020}, + }); + setMemory({ + {0x1000, 0x123456789abcdef0_qw}, + {0x1008, 0xfedcba9876543210_qw}, + }); + + emulate("ldp x0, x1, [sp, #-32]!"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_X1, 0xfedcba9876543210}, + {ARM64_REG_SP, 0x1000}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000, 0x1008}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDP_r_r_r_i) +{ + setRegisters({ + {ARM64_REG_SP, 0x1000}, + }); + setMemory({ + {0x1000, 0x123456789abcdef0_qw}, + {0x1008, 0xfedcba9876543210_qw}, + }); + + emulate("ldp x0, x1, [sp], #32"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_X1, 0xfedcba9876543210}, + {ARM64_REG_SP, 0x1020}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000, 0x1008}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_BL // From ed53e67642d108e33ea2a074857727d669703bb3 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Mon, 24 Sep 2018 14:51:36 +0200 Subject: [PATCH 024/107] Implemeneted ADRP instruction - real binary testing is needed - without tests --- src/capstone2llvmir/arm64/arm64.cpp | 15 ++++++++++++++- src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index d98079473..d824b3880 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -224,7 +224,7 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::getCurrentPc(cs_insn* i) { return llvm::ConstantInt::get( getDefaultType(), - ((i->address + (2*i->size)) >> 2) << 2); + i->address + i->size); } llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateOperandShift( @@ -832,6 +832,19 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, } } +/** + * ARM64_INS_ADRP + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateAdrp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + auto* imm = loadOpBinaryOp1(ai, irb); + auto* base = llvm::ConstantInt::get(getDefaultType(), (((i->address + i->size) >> 12) << 12)); + + auto* res = irb.CreateAdd(base, imm); + + storeRegister(ai->operands[0].reg, res, irb); +} + /** * ARM64_INS_BL */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index da279628a..d8bb8eab6 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -151,6 +151,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateStp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateLdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateLdp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateAdrp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateBl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 9a8ecd3f0..2155725ec 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -249,7 +249,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_ADD, &Capstone2LlvmIrTranslatorArm64_impl::translateAdd}, {ARM64_INS_ADDV, nullptr}, {ARM64_INS_ADR, nullptr}, - {ARM64_INS_ADRP, nullptr}, + {ARM64_INS_ADRP, &Capstone2LlvmIrTranslatorArm64_impl::translateAdrp}, {ARM64_INS_AESD, nullptr}, {ARM64_INS_AESE, nullptr}, {ARM64_INS_AESIMC, nullptr}, From 8c24571b3b26f3e3487cd6731de7ece358e7eee2 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Wed, 26 Sep 2018 21:22:30 +0200 Subject: [PATCH 025/107] enable arm64 in decompiler.py and add arm64 architecture in Architecture::setArch() ARM64 needs to be set before ARM because "arm" from ARM matches the "arm aarch64" from ARM64 --- include/retdec/config/architecture.h | 2 ++ scripts/retdec-decompiler.py | 12 ++++++------ src/config/architecture.cpp | 6 ++++++ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/retdec/config/architecture.h b/include/retdec/config/architecture.h index af6579194..dee16b660 100644 --- a/include/retdec/config/architecture.h +++ b/include/retdec/config/architecture.h @@ -28,6 +28,7 @@ class Architecture bool isPic32() const; bool isMipsOrPic32() const; bool isArm() const; + bool isArm64() const; bool isThumb() const; bool isArmOrThumb() const; bool isX86() const; @@ -82,6 +83,7 @@ class Architecture PIC32, ARM, THUMB, + ARM64, X86, PPC, }; diff --git a/scripts/retdec-decompiler.py b/scripts/retdec-decompiler.py index 50e7fcfc2..b5b84dae4 100644 --- a/scripts/retdec-decompiler.py +++ b/scripts/retdec-decompiler.py @@ -37,8 +37,8 @@ def parse_args(args): parser.add_argument('-a', '--arch', dest='arch', metavar='ARCH', - choices=['mips', 'pic32', 'arm', 'thumb', 'powerpc', 'x86'], - help='Specify target architecture [mips|pic32|arm|thumb|powerpc|x86].' + choices=['mips', 'pic32', 'arm', 'arm64', 'thumb', 'powerpc', 'x86'], + help='Specify target architecture [mips|pic32|arm|arm64|thumb|powerpc|x86].' ' Required if it cannot be autodetected from the input (e.g. raw mode, Intel HEX).') parser.add_argument('-e', '--endian', @@ -937,7 +937,7 @@ def decompile(self): ords_dir = '' # Check whether the correct target architecture was specified. - if self.arch in ['arm', 'thumb']: + if self.arch in ['arm', 'thumb', 'arm64']: ords_dir = config.ARM_ORDS_DIR elif self.arch in ['x86']: ords_dir = config.X86_ORDS_DIR @@ -949,20 +949,20 @@ def decompile(self): self._cleanup() utils.print_error('Unsupported target architecture \'%s\'. Supported architectures: ' - 'Intel x86, ARM, ARM + Thumb, MIPS, PIC32, PowerPC.' % self.arch) + 'Intel x86, ARM, ARM + Thumb, ARM64, MIPS, PIC32, PowerPC.' % self.arch) return 1 # Check file class (e.g. 'ELF32', 'ELF64'). At present, we can only decompile 32-bit files. # Note: we prefer to report the 'unsupported architecture' error (above) than this 'generic' error. fileclass, _, _ = cmd.run_cmd([config.CONFIGTOOL, self.config_file, '--read', '--file-class'], buffer_output=True) - if fileclass not in ['16', '32']: + if fileclass not in ['16', '32', '64']: if self.args.generate_log: self._generate_log() self._cleanup() utils.print_error( - 'Unsupported target format \'%s%s\'. Supported formats: ELF32, PE32, Intel HEX 32, Mach-O 32.' % ( + 'Unsupported target format \'%s%s\'. Supported formats: ELF32, ELF64, PE32, Intel HEX 32, Mach-O 32.' % ( self.format.upper(), fileclass)) return 1 diff --git a/src/config/architecture.cpp b/src/config/architecture.cpp index 4a21b177a..31ef781de 100644 --- a/src/config/architecture.cpp +++ b/src/config/architecture.cpp @@ -15,6 +15,7 @@ const std::string ARCH_UNKNOWN = "unknown"; const std::string ARCH_MIPS = "mips"; const std::string ARCH_PIC32 = "pic32"; const std::string ARCH_ARM = "arm"; +const std::string ARCH_ARM64 = "aarch64"; const std::string ARCH_THUMB = "thumb"; const std::string ARCH_x86 = "x86"; const std::string ARCH_PPC = "powerpc"; @@ -34,6 +35,7 @@ namespace config { bool Architecture::isArmOrThumb() const { return isArm() || isThumb(); } bool Architecture::isPic32() const { return isArch(eArch::PIC32); } bool Architecture::isArm() const { return isArch(eArch::ARM); } +bool Architecture::isArm64() const { return isArch(eArch::ARM64); } bool Architecture::isThumb() const { return isArch(eArch::THUMB); } bool Architecture::isX86() const { return isArch(eArch::X86); } bool Architecture::isX86_16() const { return isX86() && getBitSize() == 16; } @@ -114,6 +116,10 @@ void Architecture::setArch() { _arch = eArch::PIC32; } + else if (retdec::utils::containsCaseInsensitive(_name, ARCH_ARM64)) + { + _arch = eArch::ARM64; + } else if (retdec::utils::containsCaseInsensitive(_name, ARCH_ARM)) { _arch = eArch::ARM; From 69b78f76b169e1ee2973a0ad15300870856882ee Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Wed, 26 Sep 2018 21:30:25 +0200 Subject: [PATCH 026/107] Arm64 ABI implementation --- include/retdec/bin2llvmir/providers/abi/abi.h | 1 + .../retdec/bin2llvmir/providers/abi/arm64.h | 37 ++++++++++++ src/bin2llvmir/CMakeLists.txt | 1 + src/bin2llvmir/providers/abi/abi.cpp | 11 ++++ src/bin2llvmir/providers/abi/arm64.cpp | 59 +++++++++++++++++++ 5 files changed, 109 insertions(+) create mode 100644 include/retdec/bin2llvmir/providers/abi/arm64.h create mode 100644 src/bin2llvmir/providers/abi/arm64.cpp diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 30947f1d9..15f76b5f9 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -81,6 +81,7 @@ class Abi public: bool isMips() const; bool isArm() const; + bool isArm64() const; bool isX86() const; bool isPowerPC() const; diff --git a/include/retdec/bin2llvmir/providers/abi/arm64.h b/include/retdec/bin2llvmir/providers/abi/arm64.h new file mode 100644 index 000000000..671812e25 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/arm64.h @@ -0,0 +1,37 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/arm64.h + * @brief ABI information for ARM64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_ARM64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_ARM64_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiArm64 : public Abi +{ + // Ctors, dtors. + // + public: + AbiArm64(llvm::Module* m, Config* c); + virtual ~AbiArm64(); + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 8ad7aec72..250f46752 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -65,6 +65,7 @@ set(BIN2LLVMIR_SOURCES optimizations/unreachable_funcs/unreachable_funcs.cpp providers/abi/abi.cpp providers/abi/arm.cpp + providers/abi/arm64.cpp providers/abi/mips.cpp providers/abi/powerpc.cpp providers/abi/x86.cpp diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index c4eafa858..8358f35a5 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -6,6 +6,7 @@ #include "retdec/bin2llvmir/providers/abi/abi.h" #include "retdec/bin2llvmir/providers/abi/arm.h" +#include "retdec/bin2llvmir/providers/abi/arm64.h" #include "retdec/bin2llvmir/providers/abi/mips.h" #include "retdec/bin2llvmir/providers/abi/powerpc.h" #include "retdec/bin2llvmir/providers/abi/x86.h" @@ -178,6 +179,11 @@ bool Abi::isArm() const return _config->getConfig().architecture.isArmOrThumb(); } +bool Abi::isArm64() const +{ + return _config->getConfig().architecture.isArm64(); +} + bool Abi::isX86() const { return _config->getConfig().architecture.isX86(); @@ -210,6 +216,11 @@ Abi* AbiProvider::addAbi( auto p = _module2abi.emplace(m, std::make_unique(m, c)); return p.first->second.get(); } + else if (c->getConfig().architecture.isArm64()) + { + auto p = _module2abi.emplace(m, std::make_unique(m, c)); + return p.first->second.get(); + } else if (c->getConfig().architecture.isMipsOrPic32()) { auto p = _module2abi.emplace(m, std::make_unique(m, c)); diff --git a/src/bin2llvmir/providers/abi/arm64.cpp b/src/bin2llvmir/providers/abi/arm64.cpp new file mode 100644 index 000000000..02281a62a --- /dev/null +++ b/src/bin2llvmir/providers/abi/arm64.cpp @@ -0,0 +1,59 @@ +/** + * @file src/bin2llvmir/providers/abi/arm64.cpp + * @brief ABI information for ARM64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/arm64.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiArm64::AbiArm64(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _regs.reserve(ARM64_REG_ENDING); + _id2regs.resize(ARM64_REG_ENDING, nullptr); + //_regStackPointerId = ARM64_REG_SP; + // TODO: Stack analysis fails in ARM64 + _regStackPointerId = ARM64_REG_INVALID; + + // system calls + _regSyscallId = ARM64_REG_X7; + _regSyscallReturn = ARM64_REG_X0; + _syscallRegs = { + ARM64_REG_X0, + ARM64_REG_X1, + ARM64_REG_X2, + ARM64_REG_X3, + ARM64_REG_X4, + ARM64_REG_X5}; +} + +AbiArm64::~AbiArm64() +{ + +} + +bool AbiArm64::isGeneralPurposeRegister(const llvm::Value* val) +{ + uint32_t rid = getRegisterId(val); + return ARM64_REG_X0 <= rid && rid <= ARM64_REG_X30; +} + +bool AbiArm64::isNopInstruction(cs_insn* insn) +{ + // True NOP variants. + // + if (insn->id == ARM64_INS_NOP) + { + return true; + } + + return false; +} + +} // namespace bin2llvmir +} // namespace retdec From f04458bfb2b7b8b34e4aa116404eb4bf2f8bf84f Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Wed, 26 Sep 2018 21:35:44 +0200 Subject: [PATCH 027/107] Arm64 decoder ported from Arm --- .../optimizations/decoder/decoder.h | 15 ++ src/bin2llvmir/CMakeLists.txt | 1 + .../optimizations/decoder/arm64.cpp | 227 ++++++++++++++++++ .../optimizations/decoder/decoder.cpp | 4 + .../optimizations/decoder/decoder_init.cpp | 6 + .../decoder/ir_modifications.cpp | 4 + src/bin2llvmir/providers/config.cpp | 7 + src/capstone2llvmir/arm64/arm64.cpp | 3 +- 8 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 src/bin2llvmir/optimizations/decoder/arm64.cpp diff --git a/include/retdec/bin2llvmir/optimizations/decoder/decoder.h b/include/retdec/bin2llvmir/optimizations/decoder/decoder.h index cb550ce2c..d69c1a0c5 100644 --- a/include/retdec/bin2llvmir/optimizations/decoder/decoder.h +++ b/include/retdec/bin2llvmir/optimizations/decoder/decoder.h @@ -206,6 +206,21 @@ class Decoder : public llvm::ModulePass void patternsPseudoCall_arm(llvm::CallInst*& call, AsmInstruction& pAi); cs_mode determineMode_arm(cs_insn* insn, utils::Address& target); + // ARM64 specific. + // + private: + std::size_t decodeJumpTargetDryRun_arm64( + const JumpTarget& jt, + ByteData bytes, + bool strict = false); + std::size_t decodeJumpTargetDryRun_arm64( + const JumpTarget& jt, + ByteData bytes, + cs_mode mode, + std::size_t &decodedSz, + bool strict = false); + void patternsPseudoCall_arm64(llvm::CallInst*& call, AsmInstruction& pAi); + // MIPS specific. // private: diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 250f46752..c94fcbcb6 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -17,6 +17,7 @@ set(BIN2LLVMIR_SOURCES optimizations/cond_branch_opt/cond_branch_opt.cpp optimizations/constants/constants.cpp optimizations/decoder/arm.cpp + optimizations/decoder/arm64.cpp optimizations/decoder/bbs.cpp optimizations/decoder/decoder_ranges.cpp optimizations/decoder/decoder_init.cpp diff --git a/src/bin2llvmir/optimizations/decoder/arm64.cpp b/src/bin2llvmir/optimizations/decoder/arm64.cpp new file mode 100644 index 000000000..a58f038dd --- /dev/null +++ b/src/bin2llvmir/optimizations/decoder/arm64.cpp @@ -0,0 +1,227 @@ +/** +* @file src/bin2llvmir/optimizations/decoder/arm64.cpp +* @brief Decoding methods specific to ARM64 architecture. +* @copyright (c) 2017 Avast Software, licensed under the MIT license +*/ + +#include "retdec/bin2llvmir/optimizations/decoder/decoder.h" +#include "retdec/bin2llvmir/utils/capstone.h" +#include "retdec/utils/string.h" + +using namespace retdec::utils; +using namespace retdec::capstone2llvmir; +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +bool insnWrittesPcArm64(csh& ce, cs_insn* insn) +{ + //auto& arm64 = insn->detail->arm64; + + return insn->id == ARM64_INS_BL; + + // TODO: Arm64 doesn't allow PC to be an explicit operand + // Create list of instructions that modify PC? + + /* + // Implicit write. + // + if (cs_reg_write(ce, insn, ARM64_REG_PC)) + { + return true; + } + + // Explicit write. + // + for (std::size_t i = 0; i < arm64.op_count; ++i) + { + auto& op = arm64.operands[i]; + if (op.type == ARM64_OP_REG + && op.reg == ARM64_REG_PC + && op.access == CS_AC_WRITE) + { + return true; + } + } + + return false; + */ +} + +std::size_t Decoder::decodeJumpTargetDryRun_arm64( + const JumpTarget& jt, + ByteData bytes, + bool strict) +{ + std::size_t decodedSzArm64 = 0; + auto skipArm64 = decodeJumpTargetDryRun_arm64( + jt, + bytes, + CS_MODE_ARM, + decodedSzArm64, + strict); + + std::size_t decodedSzThumb = 0; + auto skipThumb = decodeJumpTargetDryRun_arm64( + jt, + bytes, + CS_MODE_THUMB, + decodedSzThumb, + strict); + + // ARM64 ok. + // + if (skipArm64 == 0 && skipThumb) + { + jt.setMode(CS_MODE_ARM); + return skipArm64; + } + // THUMB ok. + // + else if (skipArm64 && skipThumb == 0) + { + jt.setMode(CS_MODE_THUMB); + return skipThumb; + } + // Both OK. + // + else if (skipArm64 == 0 && skipThumb == 0) + { + // Prefer ARM64. + jt.setMode(CS_MODE_ARM); + return 0; + } + // Both bad. + // + else + { + return skipArm64 < skipThumb ? skipArm64 : skipThumb; + } +} + +bool looksLikeArm64FunctionStart(cs_insn* insn) +{ + //return insn->id == ARM64_INS_PUSH; + return insn->id == ARM64_INS_STP; +} + +std::size_t Decoder::decodeJumpTargetDryRun_arm64( + const JumpTarget& jt, + ByteData bytes, + cs_mode mode, + std::size_t &decodedSz, + bool strict) +{ + + auto basicMode = _c2l->getBasicMode(); + if (mode != basicMode) _c2l->modifyBasicMode(mode); + + static csh ce = _c2l->getCapstoneEngine(); + + decodedSz = 0; + uint64_t addr = jt.getAddress(); + std::size_t nops = 0; + bool first = true; + while (cs_disasm_iter(ce, &bytes.first, &bytes.second, &addr, _dryCsInsn)) + { + decodedSz += _dryCsInsn->size; + + if (strict && first && !looksLikeArm64FunctionStart(_dryCsInsn)) + { + return true; + } + + if (jt.getType() == JumpTarget::eType::LEFTOVER + && (first || nops > 0) + && _abi->isNopInstruction(_dryCsInsn)) + { + nops += _dryCsInsn->size; + } + else if (jt.getType() == JumpTarget::eType::LEFTOVER + && nops > 0) + { + if (mode != basicMode) _c2l->modifyBasicMode(basicMode); + return nops; + } + + if (_c2l->isControlFlowInstruction(*_dryCsInsn) + || insnWrittesPcArm64(ce, _dryCsInsn)) + { + if (mode != basicMode) _c2l->modifyBasicMode(basicMode); + return false; + } + + first = false; + } + + if (nops > 0) + { + if (mode != basicMode) _c2l->modifyBasicMode(basicMode); + return nops; + } + + // There is a BB right after, that is not a function start. + // + if (getBasicBlockAtAddress(addr) && getFunctionAtAddress(addr) == nullptr) + { + if (mode != basicMode) _c2l->modifyBasicMode(basicMode); + return false; + } + + if (mode != basicMode) _c2l->modifyBasicMode(basicMode); + return true; +} + +/** + * Recognize some ARM64-specific patterns. + */ +void Decoder::patternsPseudoCall_arm64(llvm::CallInst*& call, AsmInstruction& ai) +{ + // TODO: We could detect this using architecture-agnostic approach by using + // ABI info on LR reg. + // + // 113A0 0F E0 A0 E1 MOV LR, PC // PC = current insn + 2*insn_size + // 113A4 03 F0 A0 E1 MOV PC, R3 // branch -> call + // 113A8 00 20 94 E5 LDR R2, [R4] // next insn = return point + // + // Check that both instructions have the same cond code: + // 112E8 0F E0 A0 11 MOVNE LR, PC + // 112EC 03 F0 A0 11 MOVNE PC, R3 + // + /* + if (_c2l->isBranchFunctionCall(call)) + { + AsmInstruction prev = ai.getPrev(); + if (prev.isInvalid()) + { + return; + } + auto* insn = ai.getCapstoneInsn(); + auto& arm64 = insn->detail->arm64; + auto* pInsn = prev.getCapstoneInsn(); + auto& pArm64 = pInsn->detail->arm64; + + if (pInsn->id == ARM64_INS_MOV + && arm64.cc == pArm64.cc + && pArm64.op_count == 2 + && pArm64.operands[0].type == ARM64_OP_REG + && pArm64.operands[0].reg == ARM64_REG_LR + && pArm64.operands[1].type == ARM64_OP_REG + && pArm64.operands[1].reg == ARM64_REG_PC) + { + // Replace pseudo branch with pseudo call. + auto* nc = CallInst::Create( + _c2l->getCallFunction(), + {call->getArgOperand(0)}, + "", + call); + call->eraseFromParent(); + call = nc; + } + } + */ +} + +} // namespace bin2llvmir +} // namespace retdec diff --git a/src/bin2llvmir/optimizations/decoder/decoder.cpp b/src/bin2llvmir/optimizations/decoder/decoder.cpp index db28c5983..4a92560b3 100644 --- a/src/bin2llvmir/optimizations/decoder/decoder.cpp +++ b/src/bin2llvmir/optimizations/decoder/decoder.cpp @@ -380,6 +380,10 @@ std::size_t Decoder::decodeJumpTargetDryRun( { return decodeJumpTargetDryRun_arm(jt, bytes, strict); } + else if (_config->getConfig().architecture.isArm64()) + { + return decodeJumpTargetDryRun_arm64(jt, bytes, strict); + } else if (_config->getConfig().architecture.isMipsOrPic32()) { return decodeJumpTargetDryRun_mips(jt, bytes, strict); diff --git a/src/bin2llvmir/optimizations/decoder/decoder_init.cpp b/src/bin2llvmir/optimizations/decoder/decoder_init.cpp index 655104d14..ed954f367 100644 --- a/src/bin2llvmir/optimizations/decoder/decoder_init.cpp +++ b/src/bin2llvmir/optimizations/decoder/decoder_init.cpp @@ -67,6 +67,11 @@ void Decoder::initTranslator() arch = CS_ARCH_ARM; basicMode = CS_MODE_ARM; // We start with ARM mode even for THUMB. } + else if (a.isArm64()) + { + arch = CS_ARCH_ARM64; + basicMode = CS_MODE_ARM; + } else { throw std::runtime_error("Unsupported architecture."); @@ -185,6 +190,7 @@ void Decoder::initRanges() auto& arch = _config->getConfig().architecture; unsigned a = 0; a = arch.isArmOrThumb() ? 2 : a; + a = arch.isArm64() ? 4 : a; a = arch.isMipsOrPic32() ? 4 : a; a = arch.isPpc() ? 4 : a; _ranges.setArchitectureInstructionAlignment(a); diff --git a/src/bin2llvmir/optimizations/decoder/ir_modifications.cpp b/src/bin2llvmir/optimizations/decoder/ir_modifications.cpp index b5db0f628..48e77331b 100644 --- a/src/bin2llvmir/optimizations/decoder/ir_modifications.cpp +++ b/src/bin2llvmir/optimizations/decoder/ir_modifications.cpp @@ -168,6 +168,10 @@ llvm::GlobalVariable* Decoder::getCallReturnObject() { return _config->getLlvmRegister("r0"); } + else if (_config->getConfig().architecture.isArm64()) + { + return _config->getLlvmRegister("r0"); + } assert(false); return nullptr; diff --git a/src/bin2llvmir/providers/config.cpp b/src/bin2llvmir/providers/config.cpp index 2db298e36..70b3aa58d 100644 --- a/src/bin2llvmir/providers/config.cpp +++ b/src/bin2llvmir/providers/config.cpp @@ -452,6 +452,13 @@ bool Config::isGeneralPurposeRegister(const llvm::Value* val) auto rn = r->getStorage().getRegisterNumber(); return MIPS_REG_0 <= rn && rn <= MIPS_REG_31; } + else if (getConfig().architecture.isArm64()) + { + // TODO +// return r->getStorage().getRegisterClass() == "regs"; + auto rn = r->getStorage().getRegisterNumber(); + return ARM64_REG_X0 <= rn && rn <= ARM64_REG_X30; + } else if (getConfig().architecture.isArmOrThumb()) { // TODO diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index d824b3880..364d1cdf2 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -37,7 +37,6 @@ Capstone2LlvmIrTranslatorArm64_impl::~Capstone2LlvmIrTranslatorArm64_impl() bool Capstone2LlvmIrTranslatorArm64_impl::isAllowedBasicMode(cs_mode m) { return m == CS_MODE_ARM; - // || m == CS_MODE_THUMB; } bool Capstone2LlvmIrTranslatorArm64_impl::isAllowedExtraMode(cs_mode m) @@ -204,7 +203,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( } else { - assert(false && "Instruction is not implemented"); + //assert(false && "Instruction is not implemented"); // TODO: Automatically generate pseudo asm call. } } From f225f0cac902cd205bee126d7f5b2631bcac92fb Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 27 Sep 2018 11:56:34 +0200 Subject: [PATCH 028/107] Arm64 imm operand shifts should not update flags by default. - Added the option to switch this behaviour - add one ADD test with shift --- src/capstone2llvmir/arm64/arm64.cpp | 101 +++++++++++++------------ src/capstone2llvmir/arm64/arm64_impl.h | 18 +++-- tests/capstone2llvmir/arm64_tests.cpp | 16 ++++ 3 files changed, 80 insertions(+), 55 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 364d1cdf2..1e794ece3 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -41,8 +41,7 @@ bool Capstone2LlvmIrTranslatorArm64_impl::isAllowedBasicMode(cs_mode m) bool Capstone2LlvmIrTranslatorArm64_impl::isAllowedExtraMode(cs_mode m) { - return m == CS_MODE_LITTLE_ENDIAN - || m == CS_MODE_BIG_ENDIAN; + return m == CS_MODE_LITTLE_ENDIAN || m == CS_MODE_BIG_ENDIAN; } uint32_t Capstone2LlvmIrTranslatorArm64_impl::getArchByteSize() @@ -229,7 +228,8 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::getCurrentPc(cs_insn* i) llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateOperandShift( llvm::IRBuilder<>& irb, cs_arm64_op& op, - llvm::Value* val) + llvm::Value* val, + bool updateFlags) { llvm::Value* n = nullptr; if (op.shift.type == ARM64_SFT_INVALID) @@ -252,24 +252,23 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateOperandShift( { case ARM64_SFT_ASR: { - return generateShiftAsr(irb, val, n); + return generateShiftAsr(irb, val, n, updateFlags); } case ARM64_SFT_LSL: { - return generateShiftLsl(irb, val, n); + return generateShiftLsl(irb, val, n, updateFlags); } case ARM64_SFT_LSR: { - return generateShiftLsr(irb, val, n); + return generateShiftLsr(irb, val, n, updateFlags); } case ARM64_SFT_ROR: { - return generateShiftRor(irb, val, n); + return generateShiftRor(irb, val, n, updateFlags); } case ARM64_SFT_MSL: { - assert(false && "CHECK IMPLEMENTATION"); - return generateShiftMsl(irb, val, n); + return generateShiftMsl(irb, val, n, updateFlags); } case ARM64_SFT_INVALID: default: @@ -282,52 +281,52 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateOperandShift( llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftAsr( llvm::IRBuilder<>& irb, llvm::Value* val, - llvm::Value* n) -{ - // TODO: In the old semantics, there is: - // n = (n == 0) ? 32 : n; - // It looks like capstone does not allow op.shift.value to be zero, - // in such a case, Capstone throws away the shift. - // But there still might be zero in register, if register variant - // is used. - - auto* cfOp1 = irb.CreateSub(n, llvm::ConstantInt::get(n->getType(), 1)); - auto* cfShl = irb.CreateShl(llvm::ConstantInt::get(cfOp1->getType(), 1), cfOp1); - auto* cfAnd = irb.CreateAnd(cfShl, val); - auto* cfIcmp = irb.CreateICmpNE(cfAnd, llvm::ConstantInt::get(cfAnd->getType(), 0)); - storeRegister(ARM64_REG_CPSR_C, cfIcmp, irb); - + llvm::Value *n, + bool updateFlags) +{ + if(updateFlags) + { + auto* cfOp1 = irb.CreateSub(n, llvm::ConstantInt::get(n->getType(), 1)); + auto* cfShl = irb.CreateShl(llvm::ConstantInt::get(cfOp1->getType(), 1), cfOp1); + auto* cfAnd = irb.CreateAnd(cfShl, val); + auto* cfIcmp = irb.CreateICmpNE(cfAnd, llvm::ConstantInt::get(cfAnd->getType(), 0)); + storeRegister(ARM64_REG_CPSR_C, cfIcmp, irb); + } return irb.CreateAShr(val, n); } llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftLsl( llvm::IRBuilder<>& irb, llvm::Value* val, - llvm::Value* n) + llvm::Value *n, + bool updateFlags) { - auto* cfOp1 = irb.CreateSub(n, llvm::ConstantInt::get(n->getType(), 1)); - auto* cfShl = irb.CreateShl(val, cfOp1); - auto* cfIntT = llvm::cast(cfShl->getType()); - auto* cfRightCount = llvm::ConstantInt::get(cfIntT, cfIntT->getBitWidth() - 1); - auto* cfLow = irb.CreateLShr(cfShl, cfRightCount); - storeRegister(ARM64_REG_CPSR_C, cfLow, irb); - + if(updateFlags) + { + auto* cfOp1 = irb.CreateSub(n, llvm::ConstantInt::get(n->getType(), 1)); + auto* cfShl = irb.CreateShl(val, cfOp1); + auto* cfIntT = llvm::cast(cfShl->getType()); + auto* cfRightCount = llvm::ConstantInt::get(cfIntT, cfIntT->getBitWidth() - 1); + auto* cfLow = irb.CreateLShr(cfShl, cfRightCount); + storeRegister(ARM64_REG_CPSR_C, cfLow, irb); + } return irb.CreateShl(val, n); } llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftLsr( llvm::IRBuilder<>& irb, llvm::Value* val, - llvm::Value* n) + llvm::Value *n, + bool updateFlags) { - // TODO: In the old semantics, there is: - // n = (n == 0) ? 32 : n; - - auto* cfOp1 = irb.CreateSub(n, llvm::ConstantInt::get(n->getType(), 1)); - auto* cfShl = irb.CreateShl(llvm::ConstantInt::get(cfOp1->getType(), 1), cfOp1); - auto* cfAnd = irb.CreateAnd(cfShl, val); - auto* cfIcmp = irb.CreateICmpNE(cfAnd, llvm::ConstantInt::get(cfAnd->getType(), 0)); - storeRegister(ARM64_REG_CPSR_C, cfIcmp, irb); + if(updateFlags) + { + auto* cfOp1 = irb.CreateSub(n, llvm::ConstantInt::get(n->getType(), 1)); + auto* cfShl = irb.CreateShl(llvm::ConstantInt::get(cfOp1->getType(), 1), cfOp1); + auto* cfAnd = irb.CreateAnd(cfShl, val); + auto* cfIcmp = irb.CreateICmpNE(cfAnd, llvm::ConstantInt::get(cfAnd->getType(), 0)); + storeRegister(ARM64_REG_CPSR_C, cfIcmp, irb); + } return irb.CreateLShr(val, n); } @@ -335,20 +334,22 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftLsr( llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftRor( llvm::IRBuilder<>& irb, llvm::Value* val, - llvm::Value* n) + llvm::Value *n, + bool updateFlags) { - // TODO: In the old semantics, there is same more complicated code - // if n == 0. unsigned op0BitW = llvm::cast(n->getType())->getBitWidth(); auto* srl = irb.CreateLShr(val, n); auto* sub = irb.CreateSub(llvm::ConstantInt::get(n->getType(), op0BitW), n); auto* shl = irb.CreateShl(val, sub); auto* orr = irb.CreateOr(srl, shl); + if(updateFlags) + { - auto* cfSrl = irb.CreateLShr(orr, llvm::ConstantInt::get(orr->getType(), op0BitW - 1)); - auto* cfIcmp = irb.CreateICmpNE(cfSrl, llvm::ConstantInt::get(cfSrl->getType(), 0)); - storeRegister(ARM64_REG_CPSR_C, cfIcmp, irb); + auto* cfSrl = irb.CreateLShr(orr, llvm::ConstantInt::get(orr->getType(), op0BitW - 1)); + auto* cfIcmp = irb.CreateICmpNE(cfSrl, llvm::ConstantInt::get(cfSrl->getType(), 0)); + storeRegister(ARM64_REG_CPSR_C, cfIcmp, irb); + } return orr; } @@ -356,8 +357,10 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftRor( llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftMsl( llvm::IRBuilder<>& irb, llvm::Value* val, - llvm::Value* n) + llvm::Value *n, + bool updateFlags) { + assert(false && "Check implementation"); unsigned op0BitW = llvm::cast(n->getType())->getBitWidth(); auto* doubleT = llvm::Type::getIntNTy(_module->getContext(), op0BitW*2); @@ -856,7 +859,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateBl(cs_insn* i, cs_arm64* ai, /** * ARM64_INS_RET - */ +*/ void Capstone2LlvmIrTranslatorArm64_impl::translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { op0 = loadRegister(ARM64_REG_LR, irb); diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index d8bb8eab6..490c82bed 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -76,27 +76,33 @@ class Capstone2LlvmIrTranslatorArm64_impl : llvm::Value* generateOperandShift( llvm::IRBuilder<>& irb, cs_arm64_op& op, - llvm::Value* val); + llvm::Value* val, + bool updateFlags = false); llvm::Value* generateShiftAsr( llvm::IRBuilder<>& irb, llvm::Value* val, - llvm::Value* n); + llvm::Value* n, + bool updateFlags = false); llvm::Value* generateShiftLsl( llvm::IRBuilder<>& irb, llvm::Value* val, - llvm::Value* n); + llvm::Value* n, + bool updateFlags = false); llvm::Value* generateShiftLsr( llvm::IRBuilder<>& irb, llvm::Value* val, - llvm::Value* n); + llvm::Value* n, + bool updateFlags = false); llvm::Value* generateShiftRor( llvm::IRBuilder<>& irb, llvm::Value* val, - llvm::Value* n); + llvm::Value* n, + bool updateFlags = false); llvm::Value* generateShiftMsl( llvm::IRBuilder<>& irb, llvm::Value* val, - llvm::Value* n); + llvm::Value* n, + bool updateFlags = false); llvm::Value* generateGetOperandMemAddr( cs_arm64_op& op, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index d1d825338..64eb515e1 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -186,6 +186,22 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD32_r_r_i) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD32_r_r_ishift) +{ + + setRegisters({ + {ARM64_REG_X1, 0x1230}, + }); + + // Valid shifts are: LSL #0 and LSL #12 + emulate("add x0, x1, #1, LSL #12"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x2230_qw},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD32_r_r_i_extend_test) { // Value should be Zero extended into 64bit register From f8848905ce9655243a71bf270a8f8cec6d38a958 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 27 Sep 2018 22:58:10 +0200 Subject: [PATCH 029/107] Operand register extension generator + 64bit variant extension tests - Arm supports the extension of operand e.g. 'add x0, x1, w2, SXTW' will sign-extend the w2 register to 64 bit and after that add the values - test for 64bit variant implemented - need to check the optional imm(shift VM outputs weird values) --- src/capstone2llvmir/arm64/arm64.cpp | 101 ++++++++++++++++++++---- src/capstone2llvmir/arm64/arm64_impl.h | 6 ++ tests/capstone2llvmir/arm64_tests.cpp | 104 ++++++++++++++++++++++++- 3 files changed, 191 insertions(+), 20 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 1e794ece3..5bc3a4eea 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -225,6 +225,72 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::getCurrentPc(cs_insn* i) i->address + i->size); } +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateOperandExtension( + llvm::IRBuilder<>& irb, + arm64_extender ext, + llvm::Value* val, + llvm::Type* destType) +{ + auto* i8 = llvm::IntegerType::getInt8Ty(_module->getContext()); + auto* i16 = llvm::IntegerType::getInt16Ty(_module->getContext()); + auto* i32 = llvm::IntegerType::getInt32Ty(_module->getContext()); + auto* i64 = llvm::IntegerType::getInt64Ty(_module->getContext()); + + auto* ty = destType ? destType : getDefaultType(); + + llvm::Value* trunc = nullptr; + switch(ext) + { + case ARM64_EXT_INVALID: + { + return val; + } + case ARM64_EXT_UXTB: + { + trunc = irb.CreateTrunc(val, i8); + return irb.CreateZExt(trunc, ty); + } + case ARM64_EXT_UXTH: + { + trunc = irb.CreateTrunc(val, i16); + return irb.CreateZExt(trunc, ty); + } + case ARM64_EXT_UXTW: + { + trunc = irb.CreateTrunc(val, i32); + return irb.CreateZExt(trunc, ty); + } + case ARM64_EXT_UXTX: + { + trunc = irb.CreateTrunc(val, i64); + return irb.CreateZExt(trunc, ty); + } + case ARM64_EXT_SXTB: + { + trunc = irb.CreateTrunc(val, i8); + return irb.CreateSExt(trunc, ty); + } + case ARM64_EXT_SXTH: + { + trunc = irb.CreateTrunc(val, i16); + return irb.CreateSExt(trunc, ty); + } + case ARM64_EXT_SXTW: + { + trunc = irb.CreateTrunc(val, i32); + return irb.CreateSExt(trunc, ty); + } + case ARM64_EXT_SXTX: + { + trunc = irb.CreateTrunc(val, i64); + return irb.CreateSExt(trunc, ty); + } + default: + assert(false && "generateOperandExtension(): Unsupported extension type"); + } + return val; +} + llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateOperandShift( llvm::IRBuilder<>& irb, cs_arm64_op& op, @@ -284,7 +350,7 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftAsr( llvm::Value *n, bool updateFlags) { - if(updateFlags) + if (updateFlags) { auto* cfOp1 = irb.CreateSub(n, llvm::ConstantInt::get(n->getType(), 1)); auto* cfShl = irb.CreateShl(llvm::ConstantInt::get(cfOp1->getType(), 1), cfOp1); @@ -301,7 +367,7 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftLsl( llvm::Value *n, bool updateFlags) { - if(updateFlags) + if (updateFlags) { auto* cfOp1 = irb.CreateSub(n, llvm::ConstantInt::get(n->getType(), 1)); auto* cfShl = irb.CreateShl(val, cfOp1); @@ -319,7 +385,7 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftLsr( llvm::Value *n, bool updateFlags) { - if(updateFlags) + if (updateFlags) { auto* cfOp1 = irb.CreateSub(n, llvm::ConstantInt::get(n->getType(), 1)); auto* cfShl = irb.CreateShl(llvm::ConstantInt::get(cfOp1->getType(), 1), cfOp1); @@ -343,7 +409,7 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateShiftRor( auto* sub = irb.CreateSub(llvm::ConstantInt::get(n->getType(), op0BitW), n); auto* shl = irb.CreateShl(val, sub); auto* orr = irb.CreateOr(srl, shl); - if(updateFlags) + if (updateFlags) { auto* cfSrl = irb.CreateLShr(orr, llvm::ConstantInt::get(orr->getType(), op0BitW - 1)); @@ -484,7 +550,8 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadOp( case ARM64_OP_REG: { auto* val = loadRegister(op.reg, irb); - return generateOperandShift(irb, op, val); + auto* ext = generateOperandExtension(irb, op.ext, val, ty); + return generateOperandShift(irb, op, ext); } case ARM64_OP_IMM: { @@ -677,11 +744,11 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, irb.CreateStore(op0, addr); uint32_t baseR = ARM64_REG_INVALID; - if(ai->op_count == 2) + if (ai->op_count == 2) { baseR = ai->operands[1].reg; } - else if(ai->op_count == 3) + else if (ai->op_count == 3) { baseR = ai->operands[1].reg; @@ -694,7 +761,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, assert(false && "unsupported STR format"); } - if(ai->writeback && baseR != ARM64_REG_INVALID) + if (ai->writeback && baseR != ARM64_REG_INVALID) { storeRegister(baseR, dest, irb); } @@ -713,7 +780,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, auto* dest = generateGetOperandMemAddr(ai->operands[2], irb); auto* registerSize = llvm::ConstantInt::get(getDefaultType(), getRegisterByteSize(ai->operands[0].reg)); storeOp(ai->operands[2], op0, irb); - if(ai->op_count == 3) + if (ai->op_count == 3) { newDest = irb.CreateAdd(dest, registerSize); @@ -723,7 +790,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, baseR = ai->operands[2].mem.base; } - else if(ai->op_count == 4) + else if (ai->op_count == 4) { auto* disp = llvm::ConstantInt::get(getDefaultType(), ai->operands[3].imm); newDest = irb.CreateAdd(dest, registerSize); @@ -741,7 +808,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, assert(false && "unsupported STP format"); } - if(ai->writeback && baseR != ARM64_REG_INVALID) + if (ai->writeback && baseR != ARM64_REG_INVALID) { storeRegister(baseR, newDest, irb); } @@ -761,11 +828,11 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, storeRegister(ai->operands[0].reg, newRegValue, irb); uint32_t baseR = ARM64_REG_INVALID; - if(ai->op_count == 2) + if (ai->op_count == 2) { baseR = ai->operands[1].reg; } - else if(ai->op_count == 3) + else if (ai->op_count == 3) { baseR = ai->operands[1].reg; @@ -778,7 +845,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, assert(false && "unsupported LDR format"); } - if(ai->writeback && baseR != ARM64_REG_INVALID) + if (ai->writeback && baseR != ARM64_REG_INVALID) { storeRegister(baseR, dest, irb); } @@ -800,7 +867,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, llvm::Value* newDest = nullptr; llvm::Value* newReg2Value = nullptr; uint32_t baseR = ARM64_REG_INVALID; - if(ai->op_count == 3) + if (ai->op_count == 3) { storeRegister(ai->operands[0].reg, newReg1Value, irb); newDest = irb.CreateAdd(dest, registerSize); @@ -810,7 +877,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, baseR = ai->operands[2].mem.base; } - else if(ai->op_count == 4) + else if (ai->op_count == 4) { storeRegister(ai->operands[0].reg, newReg1Value, irb); @@ -828,7 +895,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, assert(false && "unsupported LDP format"); } - if(ai->writeback && baseR != ARM64_REG_INVALID) + if (ai->writeback && baseR != ARM64_REG_INVALID) { storeRegister(baseR, dest, irb); } diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 490c82bed..aa72c33db 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -73,6 +73,12 @@ class Capstone2LlvmIrTranslatorArm64_impl : void initializeRegistersParentMap(); + llvm::Value* generateOperandExtension( + llvm::IRBuilder<>& irb, + arm64_extender ext, + llvm::Value* val, + llvm::Type* destType = nullptr); + llvm::Value* generateOperandShift( llvm::IRBuilder<>& irb, cs_arm64_op& op, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 64eb515e1..378a2f14f 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -158,7 +158,6 @@ INSTANTIATE_TEST_CASE_P( TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_r_r_i) { - setRegisters({ {ARM64_REG_X1, 0x1230}, }); @@ -173,7 +172,6 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_r_r_i) TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD32_r_r_i) { - setRegisters({ {ARM64_REG_W1, 0x1230}, }); @@ -188,7 +186,6 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD32_r_r_i) TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD32_r_r_ishift) { - setRegisters({ {ARM64_REG_X1, 0x1230}, }); @@ -218,6 +215,107 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD32_r_r_i_extend_test) EXPECT_NO_VALUE_CALLED(); } +// +// Extended registers +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_r_r_w_UXTB) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000}, + {ARM64_REG_X2, 0x123456789abcdef0}, + }); + + emulate("add x0, x1, w2, UXTB"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x10f0},}); + // 0x1000 + 0x00000000000000f0 + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_r_r_w_UXTH) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000}, + {ARM64_REG_X2, 0x123456789abcdef0}, + }); + + emulate("add x0, x1, w2, UXTH"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0xeef0},}); + // 0x1000 + 0x000000000000def0 + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_r_r_w_UXTW) +{ + // This means no extend just the optional shift, used in instruction aliases + setRegisters({ + {ARM64_REG_X1, 0x1000000000000000}, + {ARM64_REG_X2, 0x123456789abcdef0}, + }); + + emulate("add x0, x1, w2, UXTW"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x100000009abcdef0_qw},}); + // 0x1000000000000000 + 0x000000009abcdef0 + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_r_r_w_SXTB) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, // -1 + {ARM64_REG_X2, 0x123456789abcdef0}, // -16 + }); + + emulate("add x0, x1, w2, SXTB"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0xffffffffffffffef},}); + // 0xffffffffffffffff + 0xfffffffffffffff0 = -17 + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_r_r_w_SXTH) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, // -1 + {ARM64_REG_X2, 0x123456789abcfffb}, // -5 + }); + + emulate("add x0, x1, w2, SXTH"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0xfffffffffffffffa},}); + // 0xffffffffffffffff + 0xfffffffffffffffb = -6 + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_r_r_w_SXTW) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, // -1 + {ARM64_REG_X2, 0x12345678fffffffb}, // -5 + }); + + emulate("add x0, x1, w2, SXTW"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0xfffffffffffffffa},}); + // 0xffffffffffffffff + 0xfffffffffffffffb = -6 + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MOV // From 8ed7de9b4d168aa2631153fc6fc1264652b4e01a Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 28 Sep 2018 10:59:18 +0200 Subject: [PATCH 030/107] Arm64 Zero/Sign extension 32bit variant tests --- tests/capstone2llvmir/arm64_tests.cpp | 102 ++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 378a2f14f..53a75c34f 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -316,6 +316,108 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_r_r_w_SXTW) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_w_w_w_UXTB) +{ + setRegisters({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_X1, 0x1000000}, + {ARM64_REG_X2, 0x1234567800000123}, + }); + + emulate("add w0, w1, w2, UXTB"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x1000023},}); + // 0x1000000 + 0x00000023 + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_w_w_w_UXTH) +{ + setRegisters({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_X1, 0x1000000}, + {ARM64_REG_X2, 0x1234567800000123}, + }); + + emulate("add w0, w1, w2, UXTH"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x1000123},}); + // 0x1000000 + 0x00000123 + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_w_w_w_UXTW) +{ + setRegisters({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_X1, 0x1000000}, + {ARM64_REG_X2, 0x1234567812345678}, + }); + + emulate("add w0, w1, w2, UXTW"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x13345678},}); + // 0x1000000 + 0x12345678 + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_w_w_w_SXTB) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, // -1 + {ARM64_REG_X1, 0xffffffffffffffff}, // -1 + {ARM64_REG_X2, 0x123456789abcdef0}, // -16 + }); + + emulate("add w0, w1, w2, SXTB"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x00000000ffffffef},}); + // 0x00000000ffffffff + 0x00000000fffffff0 = -17 + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_w_w_w_SXTH) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, // -1 + {ARM64_REG_X1, 0xffffffffffffffff}, // -1 + {ARM64_REG_X2, 0x123456789abcfffb}, // -5 + }); + + emulate("add w0, w1, w2, SXTH"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x00000000fffffffa},}); + // 0x00000000ffffffff + 0x00000000fffffffb = -6 + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_w_w_w_SXTW) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, // -1 + {ARM64_REG_X1, 0xffffffffffffffff}, // -1 + {ARM64_REG_X2, 0x12345678fffffffb}, // -5 + }); + + emulate("add w0, w1, w2, SXTW"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x00000000fffffffa},}); + // 0x00000000ffffffff + 0x00000000fffffffb = -6 + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MOV // From 4c90fca5f9e7d2bb26ff186ca5b9badf34ec6013 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 28 Sep 2018 11:14:30 +0200 Subject: [PATCH 031/107] Implemented SUB instruction - added tests for instruction --- src/capstone2llvmir/arm64/arm64.cpp | 13 +++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 63 ++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 5bc3a4eea..90fe04b12 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -702,6 +702,19 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_SUB + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + std::tie(op1, op2) = loadOpTernaryOp1Op2(ai, irb); + // In case of 32bit reg, trunc the imm + op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); + + auto *val = irb.CreateSub(op1, op2); + storeOp(ai->operands[0], val, irb); +} + /** * ARM64_INS_MOV, ARM64_INS_MVN, ARM64_INS_MOVZ */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index aa72c33db..c9b571fbd 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -158,6 +158,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : // protected: void translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateStp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 2155725ec..2d3c9afc2 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -584,7 +584,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_STXR, nullptr}, {ARM64_INS_SUBHN, nullptr}, {ARM64_INS_SUBHN2, nullptr}, - {ARM64_INS_SUB, nullptr}, + {ARM64_INS_SUB, &Capstone2LlvmIrTranslatorArm64_impl::translateSub}, {ARM64_INS_SUQADD, nullptr}, {ARM64_INS_SVC, nullptr}, {ARM64_INS_SYSL, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 53a75c34f..4e7a9ad79 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -418,6 +418,69 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_w_w_w_SXTW) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_SUB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SUB_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0x1230}, + }); + + emulate("sub x0, x1, #3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x122d},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SUB32_r_r_i) +{ + setRegisters({ + {ARM64_REG_W1, 0x1230}, + }); + + emulate("sub w0, w1, #3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x122d},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SUB32_r_r_ishift) +{ + setRegisters({ + {ARM64_REG_X1, 0x1230}, + }); + + // Valid shifts are: LSL #0 and LSL #12 + emulate("sub x0, x1, #1, LSL #12"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x0230_qw},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SUB32_r_r_i_extend_test) +{ + // Value should be Zero extended into 64bit register + setRegisters({ + {ARM64_REG_X0, 0xcafebabecafebabe}, + {ARM64_REG_W1, 0xf0000000}, + }); + + emulate("sub w0, w1, #1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0xefffffff},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MOV // From f1da674730dcf1203b4ef6bb5d525754c81c1747 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 28 Sep 2018 11:53:39 +0200 Subject: [PATCH 032/107] Implemented BR instruction - added tests for instruction --- src/capstone2llvmir/arm64/arm64.cpp | 10 ++++++++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 20 ++++++++++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 90fe04b12..f84e01a7a 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -202,6 +202,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( } else { + std::cerr << "Instruction not implemented " << cs_insn_name(_handle, i->id) << " " << i->op_str << std::endl; //assert(false && "Instruction is not implemented"); // TODO: Automatically generate pseudo asm call. } @@ -927,6 +928,15 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdrp(cs_insn* i, cs_arm64* ai storeRegister(ai->operands[0].reg, res, irb); } +/** + * ARM64_INS_BR + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateBr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + op0 = loadOpUnary(ai, irb); + generateBranchFunctionCall(irb, op0); +} + /** * ARM64_INS_BL */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index c9b571fbd..ec95e0a5b 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -166,6 +166,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateLdp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateAdrp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateBl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateBr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); }; diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 2d3c9afc2..deb54cd29 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -263,7 +263,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_BIT, nullptr}, {ARM64_INS_BL, &Capstone2LlvmIrTranslatorArm64_impl::translateBl}, {ARM64_INS_BLR, nullptr}, - {ARM64_INS_BR, nullptr}, + {ARM64_INS_BR, &Capstone2LlvmIrTranslatorArm64_impl::translateBr}, {ARM64_INS_BRK, nullptr}, {ARM64_INS_BSL, nullptr}, {ARM64_INS_CBNZ, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 4e7a9ad79..2c8cd439b 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -1055,6 +1055,26 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_BL_label) }); } +// +// ARM64_INS_BR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_BR) +{ + setRegisters({ + {ARM64_REG_X1, 0xcafebabecafebabe}, + }); + + emulate("br x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getBranchFunction(), {0xcafebabecafebabe}}, + }); +} + // // ARM64_INS_RET // From e5519416af08a870c78f5ef23a55434645e9ad59 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 28 Sep 2018 12:18:12 +0200 Subject: [PATCH 033/107] Arm64 syscall id register is X8 --- src/bin2llvmir/optimizations/decoder/arm64.cpp | 2 +- src/bin2llvmir/providers/abi/arm64.cpp | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/bin2llvmir/optimizations/decoder/arm64.cpp b/src/bin2llvmir/optimizations/decoder/arm64.cpp index a58f038dd..f30204154 100644 --- a/src/bin2llvmir/optimizations/decoder/arm64.cpp +++ b/src/bin2llvmir/optimizations/decoder/arm64.cpp @@ -102,7 +102,7 @@ std::size_t Decoder::decodeJumpTargetDryRun_arm64( bool looksLikeArm64FunctionStart(cs_insn* insn) { - //return insn->id == ARM64_INS_PUSH; + // Create stack frame 'stp x29, x30, [sp, -48]!' return insn->id == ARM64_INS_STP; } diff --git a/src/bin2llvmir/providers/abi/arm64.cpp b/src/bin2llvmir/providers/abi/arm64.cpp index 02281a62a..1d5ed19b8 100644 --- a/src/bin2llvmir/providers/abi/arm64.cpp +++ b/src/bin2llvmir/providers/abi/arm64.cpp @@ -21,7 +21,7 @@ AbiArm64::AbiArm64(llvm::Module* m, Config* c) : _regStackPointerId = ARM64_REG_INVALID; // system calls - _regSyscallId = ARM64_REG_X7; + _regSyscallId = ARM64_REG_X8; _regSyscallReturn = ARM64_REG_X0; _syscallRegs = { ARM64_REG_X0, @@ -29,7 +29,8 @@ AbiArm64::AbiArm64(llvm::Module* m, Config* c) : ARM64_REG_X2, ARM64_REG_X3, ARM64_REG_X4, - ARM64_REG_X5}; + ARM64_REG_X5 + }; } AbiArm64::~AbiArm64() From 118eada996a4610d08322e308fb430edce692018 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 28 Sep 2018 12:18:32 +0200 Subject: [PATCH 034/107] Specified call and return instruction ID for implemented instruction - BL Branch link is hinting the function call - RET is hinting the function return --- src/capstone2llvmir/arm64/arm64_init.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index deb54cd29..770ee0b3e 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -142,12 +142,12 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializePseudoCallInstructionIDs() { _callInsnIds = { - + ARM64_INS_BL, }; _returnInsnIds = { - + ARM64_INS_RET, }; _branchInsnIds = From d7bc4c3e775d4c978a62ded90704c72d866588ce Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 31 Jan 2019 11:17:00 +0100 Subject: [PATCH 035/107] Fixed compilation after merge - new methods added isOperandRegister, getOperandAccess - loadOpTernaryop1op2 probably changed to loadOpBinaryOrTernaryOp1Op2 - made sure all unit tests passed - TODO: implement new conventions from master --- src/capstone2llvmir/arm64/arm64.cpp | 21 ++++++++++++++++----- src/capstone2llvmir/arm64/arm64_impl.h | 9 ++++++++- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index f84e01a7a..c181bf8ba 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -526,7 +526,7 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadRegister( auto* llvmReg = getRegister(pr); if (llvmReg == nullptr) { - throw Capstone2LlvmIrError("loadRegister() unhandled reg."); + //throw Capstone2LlvmIrError("loadRegister() unhandled reg."); } llvm::Value* ret = irb.CreateLoad(llvmReg); @@ -606,7 +606,7 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeRegister( auto* llvmReg = getRegister(pr); if (llvmReg == nullptr) { - throw Capstone2LlvmIrError("storeRegister() unhandled reg."); + //throw Capstone2LlvmIrError("storeRegister() unhandled reg."); } val = generateTypeConversion(irb, val, llvmReg->getValueType(), ct); @@ -625,7 +625,7 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeRegister( || l->getType()->isIntegerTy(32) || l->getType()->isIntegerTy(64))) { - throw Capstone2LlvmIrError("Unexpected parent type."); + //throw Capstone2LlvmIrError("Unexpected parent type."); } llvm::Value* andC = nullptr; @@ -684,6 +684,17 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeOp( } } +bool Capstone2LlvmIrTranslatorArm64_impl::isOperandRegister(cs_arm64_op& op) +{ + return op.type == ARM64_OP_REG; +} + +uint8_t Capstone2LlvmIrTranslatorArm64_impl::getOperandAccess(cs_arm64_op& op) +{ + return op.access; +} + + // //============================================================================== // ARM64 instruction translation methods. @@ -695,7 +706,7 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeOp( */ void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { - std::tie(op1, op2) = loadOpTernaryOp1Op2(ai, irb); + std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); // In case of 32bit reg, trunc the imm op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); @@ -708,7 +719,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, */ void Capstone2LlvmIrTranslatorArm64_impl::translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { - std::tie(op1, op2) = loadOpTernaryOp1Op2(ai, irb); + std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); // In case of 32bit reg, trunc the imm op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index ec95e0a5b..31b566202 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -135,7 +135,14 @@ class Capstone2LlvmIrTranslatorArm64_impl : llvm::Value* val, llvm::IRBuilder<>& irb, eOpConv ct = eOpConv::ZEXT_TRUNC) override; - +// +//============================================================================== +// Helper methods. +//============================================================================== +// + protected: + virtual bool isOperandRegister(cs_arm64_op& op) override; + virtual uint8_t getOperandAccess(cs_arm64_op& op) override; // //============================================================================== // ARM64 implementation data. From 51645be8e6855c5fa0ff714467fb731e07628e8f Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 31 Jan 2019 13:17:43 +0100 Subject: [PATCH 036/107] Generate pseudoasm instruction when translation routine is not found - Function to generate condition code --- src/capstone2llvmir/arm64/arm64.cpp | 139 +++++++++++++++++++++++-- src/capstone2llvmir/arm64/arm64_impl.h | 4 + 2 files changed, 137 insertions(+), 6 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index c181bf8ba..7f7cc24cf 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -181,9 +181,6 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( { auto f = fIt->second; - //bool branchInsn = i->id == ARM_INS_B || i->id == ARM_INS_BX - // || i->id == ARM_INS_BL || i->id == ARM_INS_BLX - // || i->id == ARM_INS_CBZ || i->id == ARM_INS_CBNZ; if (ai->cc == ARM64_CC_AL || ai->cc == ARM64_CC_NV /* || branchInsn */) { _inCondition = false; @@ -202,9 +199,22 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( } else { - std::cerr << "Instruction not implemented " << cs_insn_name(_handle, i->id) << " " << i->op_str << std::endl; - //assert(false && "Instruction is not implemented"); - // TODO: Automatically generate pseudo asm call. + throwUnhandledInstructions(i); + + if (ai->cc == ARM64_CC_AL || ai->cc == ARM64_CC_INVALID) + { + _inCondition = false; + translatePseudoAsmGeneric(i, ai, irb); + } + else + { + _inCondition = true; + + auto* cond = generateInsnConditionCode(irb, ai); + auto bodyIrb = generateIfThen(cond, irb); + + translatePseudoAsmGeneric(i, ai, bodyIrb); + } } } @@ -684,6 +694,123 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeOp( } } +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateInsnConditionCode( + llvm::IRBuilder<>& irb, + cs_arm64* ai) +{ + switch (ai->cc) + { + // Equal = Zero set + case ARM64_CC_EQ: + { + auto* z = loadRegister(ARM64_REG_CPSR_Z, irb); + return z; + } + // Not equal = Zero clear + case ARM64_CC_NE: + { + auto* z = loadRegister(ARM64_REG_CPSR_Z, irb); + return generateValueNegate(irb, z); + } + // Unsigned higher or same = Carry set + case ARM64_CC_HS: + { + auto* c = loadRegister(ARM64_REG_CPSR_C, irb); + return c; + } + // Unsigned lower = Carry clear + case ARM64_CC_LO: + { + auto* c = loadRegister(ARM64_REG_CPSR_C, irb); + return generateValueNegate(irb, c); + } + // Negative = N set + case ARM64_CC_MI: + { + auto* n = loadRegister(ARM64_REG_CPSR_N, irb); + return n; + } + // Positive or zero = N clear + case ARM64_CC_PL: + { + auto* n = loadRegister(ARM64_REG_CPSR_N, irb); + return generateValueNegate(irb, n); + } + // Overflow = V set + case ARM64_CC_VS: + { + auto* v = loadRegister(ARM64_REG_CPSR_V, irb); + return v; + } + // No overflow = V clear + case ARM64_CC_VC: + { + auto* v = loadRegister(ARM64_REG_CPSR_V, irb); + return generateValueNegate(irb, v); + } + // Unsigned higher = Carry set & Zero clear + case ARM64_CC_HI: + { + auto* c = loadRegister(ARM64_REG_CPSR_C, irb); + auto* z = loadRegister(ARM64_REG_CPSR_Z, irb); + auto* nz = generateValueNegate(irb, z); + return irb.CreateAnd(c, nz); + } + // Unsigned lower or same = Carry clear or Zero set + case ARM64_CC_LS: + { + auto* z = loadRegister(ARM64_REG_CPSR_Z, irb); + auto* c = loadRegister(ARM64_REG_CPSR_C, irb); + auto* nc = generateValueNegate(irb, c); + return irb.CreateOr(z, nc); + } + // Greater than or equal = N set and V set || N clear and V clear + // (N & V) || (!N & !V) == !(N xor V) + case ARM64_CC_GE: + { + auto* n = loadRegister(ARM64_REG_CPSR_N, irb); + auto* v = loadRegister(ARM64_REG_CPSR_V, irb); + auto* x = irb.CreateXor(n, v); + return generateValueNegate(irb, x); + } + // Less than = N set and V clear || N clear and V set + // (N & !V) || (!N & V) == (N xor V) + case ARM64_CC_LT: + { + auto* n = loadRegister(ARM64_REG_CPSR_N, irb); + auto* v = loadRegister(ARM64_REG_CPSR_V, irb); + return irb.CreateXor(n, v); + } + // Greater than = Z clear, and either N set and V set, or N clear and V set + case ARM64_CC_GT: + { + auto* z = loadRegister(ARM64_REG_CPSR_Z, irb); + auto* n = loadRegister(ARM64_REG_CPSR_N, irb); + auto* v = loadRegister(ARM64_REG_CPSR_V, irb); + auto* xor1 = irb.CreateXor(n, v); + auto* or1 = irb.CreateOr(z, xor1); + return generateValueNegate(irb, or1); + } + // Less than or equal = Z set, or N set and V clear, or N clear and V set + case ARM64_CC_LE: + { + auto* z = loadRegister(ARM64_REG_CPSR_Z, irb); + auto* n = loadRegister(ARM64_REG_CPSR_N, irb); + auto* v = loadRegister(ARM64_REG_CPSR_V, irb); + auto* xor1 = irb.CreateXor(n, v); + return irb.CreateOr(z, xor1); + } + case ARM64_CC_AL: + case ARM64_CC_NV: + case ARM64_CC_INVALID: + default: + { + throw GenericError("should not be possible"); + } + } +} + + bool Capstone2LlvmIrTranslatorArm64_impl::isOperandRegister(cs_arm64_op& op) { return op.type == ARM64_OP_REG; diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 31b566202..019ca18d2 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -110,6 +110,10 @@ class Capstone2LlvmIrTranslatorArm64_impl : llvm::Value* n, bool updateFlags = false); + llvm::Value* generateInsnConditionCode( + llvm::IRBuilder<>& irb, + cs_arm64* ai); + llvm::Value* generateGetOperandMemAddr( cs_arm64_op& op, llvm::IRBuilder<>& irb); From 8000ed71373114475025205241a20e77d8d1695d Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 31 Jan 2019 13:40:01 +0100 Subject: [PATCH 037/107] Check preconditions in implemented arm64 instructions --- src/capstone2llvmir/arm64/arm64.cpp | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 7f7cc24cf..404bb8f7c 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -833,6 +833,8 @@ uint8_t Capstone2LlvmIrTranslatorArm64_impl::getOperandAccess(cs_arm64_op& op) */ void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { + EXPECT_IS_TERNARY(i, ai, irb); + std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); // In case of 32bit reg, trunc the imm op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); @@ -846,6 +848,8 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, */ void Capstone2LlvmIrTranslatorArm64_impl::translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { + EXPECT_IS_TERNARY(i, ai, irb); + std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); // In case of 32bit reg, trunc the imm op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); @@ -859,10 +863,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateSub(cs_insn* i, cs_arm64* ai, */ void Capstone2LlvmIrTranslatorArm64_impl::translateMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { - if (ai->op_count != 2) - { - return; - } + EXPECT_IS_BINARY(i, ai, irb); op1 = loadOpBinaryOp1(ai, irb); if (i->id == ARM64_INS_MVN) @@ -888,6 +889,8 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMov(cs_insn* i, cs_arm64* ai, */ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { + EXPECT_IS_BINARY_OR_TERNARY(i, ai, irb); + op0 = loadOp(ai->operands[0], irb); auto* dest = generateGetOperandMemAddr(ai->operands[1], irb); @@ -924,6 +927,8 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, */ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { + EXPECT_IS_EXPR(i, ai, irb, (2 <= ai->op_count && ai->op_count <= 4)); + op0 = loadOp(ai->operands[0], irb); op1 = loadOp(ai->operands[1], irb); @@ -971,6 +976,8 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, */ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { + EXPECT_IS_BINARY_OR_TERNARY(i, ai, irb); + auto* regType = getRegisterType(ai->operands[0].reg); auto* dest = generateGetOperandMemAddr(ai->operands[1], irb); auto* pt = llvm::PointerType::get(regType, 0); @@ -1008,6 +1015,8 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, */ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { + EXPECT_IS_EXPR(i, ai, irb, (2 <= ai->op_count && ai->op_count <= 4)); + auto* regType = getRegisterType(ai->operands[0].reg); auto* dest = generateGetOperandMemAddr(ai->operands[2], irb); auto* pt = llvm::PointerType::get(regType, 0); @@ -1058,6 +1067,8 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, */ void Capstone2LlvmIrTranslatorArm64_impl::translateAdrp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { + EXPECT_IS_BINARY(i, ai, irb); + auto* imm = loadOpBinaryOp1(ai, irb); auto* base = llvm::ConstantInt::get(getDefaultType(), (((i->address + i->size) >> 12) << 12)); @@ -1071,6 +1082,8 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdrp(cs_insn* i, cs_arm64* ai */ void Capstone2LlvmIrTranslatorArm64_impl::translateBr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { + EXPECT_IS_UNARY(i, ai, irb); + op0 = loadOpUnary(ai, irb); generateBranchFunctionCall(irb, op0); } @@ -1080,6 +1093,8 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateBr(cs_insn* i, cs_arm64* ai, */ void Capstone2LlvmIrTranslatorArm64_impl::translateBl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { + EXPECT_IS_UNARY(i, ai, irb); + storeRegister(ARM64_REG_LR, getNextInsnAddress(i), irb); op0 = loadOpUnary(ai, irb); generateCallFunctionCall(irb, op0); @@ -1090,6 +1105,9 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateBl(cs_insn* i, cs_arm64* ai, */ void Capstone2LlvmIrTranslatorArm64_impl::translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { + EXPECT_IS_NULLARY_OR_UNARY(i, ai, irb); + + // TODO: Unary variant op0 = loadRegister(ARM64_REG_LR, irb); generateReturnFunctionCall(irb, op0); } From d5f629689111c42c5f4c76b7ab06314eddd1edbe Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 31 Jan 2019 13:48:03 +0100 Subject: [PATCH 038/107] Changed register generation to match other modules. --- src/capstone2llvmir/arm64/arm64.cpp | 102 ++-------------------------- 1 file changed, 7 insertions(+), 95 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 404bb8f7c..6831fad2a 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -68,98 +68,10 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateDataLayout() void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() { - // General purpose registers. - // - createRegister(ARM64_REG_X0, _regLt); - createRegister(ARM64_REG_X1, _regLt); - createRegister(ARM64_REG_X2, _regLt); - createRegister(ARM64_REG_X3, _regLt); - createRegister(ARM64_REG_X4, _regLt); - createRegister(ARM64_REG_X5, _regLt); - createRegister(ARM64_REG_X6, _regLt); - createRegister(ARM64_REG_X7, _regLt); - createRegister(ARM64_REG_X8, _regLt); - createRegister(ARM64_REG_X9, _regLt); - createRegister(ARM64_REG_X10, _regLt); - createRegister(ARM64_REG_X11, _regLt); - createRegister(ARM64_REG_X12, _regLt); - createRegister(ARM64_REG_X13, _regLt); - createRegister(ARM64_REG_X14, _regLt); - createRegister(ARM64_REG_X15, _regLt); - createRegister(ARM64_REG_X16, _regLt); - createRegister(ARM64_REG_X17, _regLt); - createRegister(ARM64_REG_X18, _regLt); - createRegister(ARM64_REG_X19, _regLt); - createRegister(ARM64_REG_X20, _regLt); - createRegister(ARM64_REG_X21, _regLt); - createRegister(ARM64_REG_X22, _regLt); - createRegister(ARM64_REG_X23, _regLt); - createRegister(ARM64_REG_X24, _regLt); - createRegister(ARM64_REG_X25, _regLt); - createRegister(ARM64_REG_X26, _regLt); - createRegister(ARM64_REG_X27, _regLt); - createRegister(ARM64_REG_X28, _regLt); - - // Lower 32 bits of 64 arm{xN} bit regs. - // - /* - createRegister(ARM64_REG_W0, _regLt); - createRegister(ARM64_REG_W1, _regLt); - createRegister(ARM64_REG_W2, _regLt); - createRegister(ARM64_REG_W3, _regLt); - createRegister(ARM64_REG_W4, _regLt); - createRegister(ARM64_REG_W5, _regLt); - createRegister(ARM64_REG_W6, _regLt); - createRegister(ARM64_REG_W7, _regLt); - createRegister(ARM64_REG_W8, _regLt); - createRegister(ARM64_REG_W9, _regLt); - createRegister(ARM64_REG_W10, _regLt); - createRegister(ARM64_REG_W11, _regLt); - createRegister(ARM64_REG_W12, _regLt); - createRegister(ARM64_REG_W13, _regLt); - createRegister(ARM64_REG_W14, _regLt); - createRegister(ARM64_REG_W15, _regLt); - createRegister(ARM64_REG_W16, _regLt); - createRegister(ARM64_REG_W17, _regLt); - createRegister(ARM64_REG_W18, _regLt); - createRegister(ARM64_REG_W19, _regLt); - createRegister(ARM64_REG_W20, _regLt); - createRegister(ARM64_REG_W21, _regLt); - createRegister(ARM64_REG_W22, _regLt); - createRegister(ARM64_REG_W23, _regLt); - createRegister(ARM64_REG_W24, _regLt); - createRegister(ARM64_REG_W25, _regLt); - createRegister(ARM64_REG_W26, _regLt); - createRegister(ARM64_REG_W27, _regLt); - createRegister(ARM64_REG_W28, _regLt); - createRegister(ARM64_REG_W29, _regLt); - createRegister(ARM64_REG_W30, _regLt); - */ - - // Special registers. - - // FP Frame pointer. - createRegister(ARM64_REG_X29, _regLt); - - // LP Link register. - createRegister(ARM64_REG_X30, _regLt); - - // Stack pointer. - createRegister(ARM64_REG_SP, _regLt); - //createRegister(ARM64_REG_WSP, _regLt); - - // Zero. - createRegister(ARM64_REG_XZR, _regLt); - //createRegister(ARM64_REG_WZR, _regLt); - - // Flags. - createRegister(ARM64_REG_CPSR_N, _regLt); - createRegister(ARM64_REG_CPSR_Z, _regLt); - createRegister(ARM64_REG_CPSR_C, _regLt); - createRegister(ARM64_REG_CPSR_V, _regLt); - - // Program counter. - createRegister(ARM64_REG_PC, _regLt); + for (auto& p : _reg2type) + { + createRegister(p.first, _regLt); + } } uint32_t Capstone2LlvmIrTranslatorArm64_impl::getCarryRegister() @@ -536,7 +448,7 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadRegister( auto* llvmReg = getRegister(pr); if (llvmReg == nullptr) { - //throw Capstone2LlvmIrError("loadRegister() unhandled reg."); + throw GenericError("loadRegister() unhandled reg."); } llvm::Value* ret = irb.CreateLoad(llvmReg); @@ -616,7 +528,7 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeRegister( auto* llvmReg = getRegister(pr); if (llvmReg == nullptr) { - //throw Capstone2LlvmIrError("storeRegister() unhandled reg."); + throw GenericError("storeRegister() unhandled reg."); } val = generateTypeConversion(irb, val, llvmReg->getValueType(), ct); @@ -635,7 +547,7 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeRegister( || l->getType()->isIntegerTy(32) || l->getType()->isIntegerTy(64))) { - //throw Capstone2LlvmIrError("Unexpected parent type."); + throw GenericError("Unexpected parent type."); } llvm::Value* andC = nullptr; From 81e47e2f7e8ac276f3f7ae315ba3d73dd148cc43 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 2 Feb 2019 13:03:36 +0100 Subject: [PATCH 039/107] LDR instruction all 3 formats + tests - register - imm - literal (label) --- src/bin2llvmir/providers/abi/arm64.cpp | 2 +- src/capstone2llvmir/arm64/arm64.cpp | 26 ++++++++++++++++++-------- tests/capstone2llvmir/arm64_tests.cpp | 17 +++++++++++++++++ 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/src/bin2llvmir/providers/abi/arm64.cpp b/src/bin2llvmir/providers/abi/arm64.cpp index 1d5ed19b8..d04f3a87b 100644 --- a/src/bin2llvmir/providers/abi/arm64.cpp +++ b/src/bin2llvmir/providers/abi/arm64.cpp @@ -16,7 +16,7 @@ AbiArm64::AbiArm64(llvm::Module* m, Config* c) : { _regs.reserve(ARM64_REG_ENDING); _id2regs.resize(ARM64_REG_ENDING, nullptr); - //_regStackPointerId = ARM64_REG_SP; + _regStackPointerId = ARM64_REG_SP; // TODO: Stack analysis fails in ARM64 _regStackPointerId = ARM64_REG_INVALID; diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 6831fad2a..e73495560 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -382,7 +382,9 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateGetOperandMemAddr( cs_arm64_op& op, llvm::IRBuilder<>& irb) { - // TODO: generateGetOperandAddr? + // TODO: Check the operand types + // TODO: If the type is IMM return load of that value, or variable + // TODO: name, maybe generateGetOperandValue? auto* baseR = loadRegister(op.mem.base, irb); auto* t = baseR ? baseR->getType() : getDefaultType(); llvm::Value* disp = op.mem.disp @@ -485,10 +487,18 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadOp( { auto* addr = generateGetOperandMemAddr(op, irb); - auto* lty = ty ? ty : getDefaultType(); - auto* pt = llvm::PointerType::get(lty, 0); - addr = irb.CreateIntToPtr(addr, pt); - return irb.CreateLoad(addr); + if (lea) + { + return addr; + } + else + { + auto* lty = ty ? ty : getDefaultType(); + auto* pt = llvm::PointerType::get(lty, 0); + addr = irb.CreateIntToPtr(addr, pt); + return irb.CreateLoad(addr); + } + } case ARM64_OP_FP: case ARM64_OP_INVALID: @@ -891,7 +901,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, EXPECT_IS_BINARY_OR_TERNARY(i, ai, irb); auto* regType = getRegisterType(ai->operands[0].reg); - auto* dest = generateGetOperandMemAddr(ai->operands[1], irb); + auto* dest = loadOp(ai->operands[1], irb, nullptr, true); auto* pt = llvm::PointerType::get(regType, 0); auto* addr = irb.CreateIntToPtr(dest, pt); @@ -903,16 +913,16 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, { baseR = ai->operands[1].reg; } - else if (ai->op_count == 3) + else if (ai->op_count == 3) // POST-index { baseR = ai->operands[1].reg; auto* disp = llvm::ConstantInt::get(getDefaultType(), ai->operands[2].imm); dest = irb.CreateAdd(dest, disp); - // post-index -> always writeback } else { + // TODO: This should not be posible, throw error? assert(false && "unsupported LDR format"); } diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 2c8cd439b..63535e2fe 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -929,6 +929,23 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR_minus_imm_postindexed_ EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR_label) +{ + // Load the memory at given label, or imm in this case + setMemory({ + {0x15000, 0x123456789abcdef0_qw}, + }); + emulate("ldr x0, #0x15000"); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0_qw}, + }); + EXPECT_JUST_MEMORY_LOADED({0x15000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_LDP // From 65d54ef83d498ca666f3c2c1a53efdad7e32d107 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sun, 3 Feb 2019 11:55:55 +0100 Subject: [PATCH 040/107] Binaries can now be decompiled - jumpTargetDryRun updated --- .../optimizations/decoder/decoder.h | 6 ---- .../optimizations/decoder/arm64.cpp | 35 ++++++++++--------- .../optimizations/decoder/jump_targets.cpp | 1 + src/bin2llvmir/utils/capstone.cpp | 5 +++ 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/include/retdec/bin2llvmir/optimizations/decoder/decoder.h b/include/retdec/bin2llvmir/optimizations/decoder/decoder.h index 50521ef52..81600a7c4 100644 --- a/include/retdec/bin2llvmir/optimizations/decoder/decoder.h +++ b/include/retdec/bin2llvmir/optimizations/decoder/decoder.h @@ -213,12 +213,6 @@ class Decoder : public llvm::ModulePass const JumpTarget& jt, ByteData bytes, bool strict = false); - std::size_t decodeJumpTargetDryRun_arm64( - const JumpTarget& jt, - ByteData bytes, - cs_mode mode, - std::size_t &decodedSz, - bool strict = false); void patternsPseudoCall_arm64(llvm::CallInst*& call, AsmInstruction& pAi); // MIPS specific. diff --git a/src/bin2llvmir/optimizations/decoder/arm64.cpp b/src/bin2llvmir/optimizations/decoder/arm64.cpp index f30204154..850cf5aa4 100644 --- a/src/bin2llvmir/optimizations/decoder/arm64.cpp +++ b/src/bin2llvmir/optimizations/decoder/arm64.cpp @@ -49,6 +49,13 @@ bool insnWrittesPcArm64(csh& ce, cs_insn* insn) */ } +bool looksLikeArm64FunctionStart(cs_insn* insn) +{ + // Create stack frame 'stp x29, x30, [sp, -48]!' + return insn->id == ARM64_INS_STP; +} + + /* std::size_t Decoder::decodeJumpTargetDryRun_arm64( const JumpTarget& jt, ByteData bytes, @@ -99,33 +106,32 @@ std::size_t Decoder::decodeJumpTargetDryRun_arm64( return skipArm64 < skipThumb ? skipArm64 : skipThumb; } } - -bool looksLikeArm64FunctionStart(cs_insn* insn) -{ - // Create stack frame 'stp x29, x30, [sp, -48]!' - return insn->id == ARM64_INS_STP; -} + */ std::size_t Decoder::decodeJumpTargetDryRun_arm64( const JumpTarget& jt, ByteData bytes, - cs_mode mode, - std::size_t &decodedSz, bool strict) { - auto basicMode = _c2l->getBasicMode(); - if (mode != basicMode) _c2l->modifyBasicMode(mode); + if (strict) + { + return true; + } + + //auto basicMode = _c2l->getBasicMode(); + //if (mode != basicMode) _c2l->modifyBasicMode(mode); static csh ce = _c2l->getCapstoneEngine(); - decodedSz = 0; uint64_t addr = jt.getAddress(); std::size_t nops = 0; bool first = true; + // bytes.first -> Code + // bytes.second -> Code size + // addr -> Address of first instruction while (cs_disasm_iter(ce, &bytes.first, &bytes.second, &addr, _dryCsInsn)) { - decodedSz += _dryCsInsn->size; if (strict && first && !looksLikeArm64FunctionStart(_dryCsInsn)) { @@ -141,14 +147,12 @@ std::size_t Decoder::decodeJumpTargetDryRun_arm64( else if (jt.getType() == JumpTarget::eType::LEFTOVER && nops > 0) { - if (mode != basicMode) _c2l->modifyBasicMode(basicMode); return nops; } if (_c2l->isControlFlowInstruction(*_dryCsInsn) || insnWrittesPcArm64(ce, _dryCsInsn)) { - if (mode != basicMode) _c2l->modifyBasicMode(basicMode); return false; } @@ -157,7 +161,6 @@ std::size_t Decoder::decodeJumpTargetDryRun_arm64( if (nops > 0) { - if (mode != basicMode) _c2l->modifyBasicMode(basicMode); return nops; } @@ -165,11 +168,9 @@ std::size_t Decoder::decodeJumpTargetDryRun_arm64( // if (getBasicBlockAtAddress(addr) && getFunctionAtAddress(addr) == nullptr) { - if (mode != basicMode) _c2l->modifyBasicMode(basicMode); return false; } - if (mode != basicMode) _c2l->modifyBasicMode(basicMode); return true; } diff --git a/src/bin2llvmir/optimizations/decoder/jump_targets.cpp b/src/bin2llvmir/optimizations/decoder/jump_targets.cpp index 98f3d7e5d..9394b1a3d 100644 --- a/src/bin2llvmir/optimizations/decoder/jump_targets.cpp +++ b/src/bin2llvmir/optimizations/decoder/jump_targets.cpp @@ -199,6 +199,7 @@ const JumpTarget* JumpTargets::push( if ((arch.isArmOrThumb() && m == CS_MODE_ARM && a % 4) || (arch.isArmOrThumb() && m == CS_MODE_THUMB && a % 2) + || (arch.isArm64() && a % 4) || (arch.isMipsOrPic32() && a % 4) || (arch.isPpc() && a % 4)) { diff --git a/src/bin2llvmir/utils/capstone.cpp b/src/bin2llvmir/utils/capstone.cpp index 05bb35592..5d44a2e27 100644 --- a/src/bin2llvmir/utils/capstone.cpp +++ b/src/bin2llvmir/utils/capstone.cpp @@ -33,6 +33,11 @@ std::string mode2string(const config::Architecture& arch, cs_mode m) ret += m & CS_MODE_MIPS32R6 ? ", CS_MODE_MIPS32R6" : ""; ret += m & CS_MODE_MIPS2 ? ", CS_MODE_MIPS2" : ""; } + else if (arch.isArm64()) + { + ret += m & CS_MODE_V8 ? ", CS_MODE_V8" : ", CS_MODE_ARM"; + ret += m & CS_MODE_MCLASS ? ", CS_MODE_MCLASS" : ""; + } else if (arch.isArmOrThumb()) { ret += m & CS_MODE_THUMB ? ", CS_MODE_THUMB" : ", CS_MODE_ARM"; From a3702328730719f0fc98b421e4ab879e23ebba23 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Wed, 6 Feb 2019 13:18:32 +0100 Subject: [PATCH 041/107] Generate condition codes for conditional instructions. --- src/bin2llvmir/providers/abi/arm64.cpp | 2 -- src/capstone2llvmir/arm64/arm64.cpp | 20 +++++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/bin2llvmir/providers/abi/arm64.cpp b/src/bin2llvmir/providers/abi/arm64.cpp index d04f3a87b..89c3460db 100644 --- a/src/bin2llvmir/providers/abi/arm64.cpp +++ b/src/bin2llvmir/providers/abi/arm64.cpp @@ -17,8 +17,6 @@ AbiArm64::AbiArm64(llvm::Module* m, Config* c) : _regs.reserve(ARM64_REG_ENDING); _id2regs.resize(ARM64_REG_ENDING, nullptr); _regStackPointerId = ARM64_REG_SP; - // TODO: Stack analysis fails in ARM64 - _regStackPointerId = ARM64_REG_INVALID; // system calls _regSyscallId = ARM64_REG_X8; diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index e73495560..a57f034d4 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -88,32 +88,34 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( cs_detail* d = i->detail; cs_arm64* ai = &d->arm64; + std::cout << i->mnemonic << " " << i->op_str << std::endl; + auto fIt = _i2fm.find(i->id); if (fIt != _i2fm.end() && fIt->second != nullptr) { auto f = fIt->second; - if (ai->cc == ARM64_CC_AL || ai->cc == ARM64_CC_NV /* || branchInsn */) + if (ai->cc == ARM64_CC_AL + || ai->cc == ARM64_CC_INVALID /* || branchInsn */) { _inCondition = false; (this->*f)(i, ai, irb); } else { - (this->*f)(i, ai, irb); - - //_inCondition = true; - //auto* cond = generateInsnConditionCode(irb, ai); - //auto bodyIrb = generateIfThen(cond, irb); + _inCondition = true; + auto* cond = generateInsnConditionCode(irb, ai); + auto bodyIrb = generateIfThen(cond, irb); - //(this->*f)(i, ai, bodyIrb); + (this->*f)(i, ai, bodyIrb); } } else { throwUnhandledInstructions(i); - if (ai->cc == ARM64_CC_AL || ai->cc == ARM64_CC_INVALID) + if (ai->cc == ARM64_CC_AL + || ai->cc == ARM64_CC_INVALID) { _inCondition = false; translatePseudoAsmGeneric(i, ai, irb); @@ -727,7 +729,7 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateInsnConditionCode( case ARM64_CC_INVALID: default: { - throw GenericError("should not be possible"); + throw GenericError("Probably wrong condition code."); } } } From 16e07254cc659fac4464d45e58c92fe22b7ce750 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Wed, 6 Feb 2019 13:53:08 +0100 Subject: [PATCH 042/107] ARM64: strb, strh instructions + tests --- src/capstone2llvmir/arm64/arm64.cpp | 17 +++++ src/capstone2llvmir/arm64/arm64_init.cpp | 4 +- tests/capstone2llvmir/arm64_tests.cpp | 81 ++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index a57f034d4..4aa7a70b8 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -815,7 +815,24 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, { EXPECT_IS_BINARY_OR_TERNARY(i, ai, irb); + auto ty = getDefaultType(); + + switch (i->id) + { + case ARM64_INS_STRB: + { + ty = irb.getInt8Ty(); + break; + } + case ARM64_INS_STRH: + { + ty = irb.getInt16Ty(); + break; + } + } + op0 = loadOp(ai->operands[0], irb); + op0 = irb.CreateZExtOrTrunc(op0, ty); auto* dest = generateGetOperandMemAddr(ai->operands[1], irb); auto* pt = llvm::PointerType::get(op0->getType(), 0); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 770ee0b3e..80409a2bf 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -569,9 +569,9 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_STLXR, nullptr}, {ARM64_INS_STNP, nullptr}, {ARM64_INS_STP, &Capstone2LlvmIrTranslatorArm64_impl::translateStp}, - {ARM64_INS_STRB, nullptr}, + {ARM64_INS_STRB, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, {ARM64_INS_STR, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, - {ARM64_INS_STRH, nullptr}, + {ARM64_INS_STRH, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, {ARM64_INS_STTRB, nullptr}, {ARM64_INS_STTRH, nullptr}, {ARM64_INS_STTR, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 63535e2fe..1371fc4a2 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -630,6 +630,87 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STR32_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_STRB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STRB_r_r) +{ + setRegisters({ + {ARM64_REG_W0, 0xcafebabe}, + {ARM64_REG_X1, 0x1234}, + }); + + emulate("strb w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W0, ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1234, 0xbe} + }); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STRB_r_r_r) +{ + setRegisters({ + {ARM64_REG_W0, 0xcafebabe}, + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x10}, + }); + + emulate("strb w0, [x1, x2]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W0, ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1244, 0xbe} + }); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_STRH +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STRH_r_r) +{ + setRegisters({ + {ARM64_REG_W0, 0xcafebabe}, + {ARM64_REG_X1, 0x1234}, + }); + + emulate("strh w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W0, ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1234, 0xbabe} + }); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STRH_r_r_i) +{ + setRegisters({ + {ARM64_REG_W0, 0xcafebabe}, + {ARM64_REG_X1, 0x1234}, + }); + + emulate("strh w0, [x1, #0x10]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W0, ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1244, 0xbabe} + }); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_STP // From 41add946bafcbefeb07072129d28976a567cfd1a Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Wed, 6 Feb 2019 16:40:44 +0100 Subject: [PATCH 043/107] Arm64: conditional and unconditional branch instruction + tests - removed the generation of conditional code in translate instruction function, this is not necessary because condition is generated in body of given instruction and arm64 support only specific instruction to be conditional. --- src/capstone2llvmir/arm64/arm64.cpp | 37 +++++++++++++++--------- src/capstone2llvmir/arm64/arm64_impl.h | 2 ++ src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 28 ++++++++++++++++++ 4 files changed, 54 insertions(+), 15 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 4aa7a70b8..c92566bd8 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -95,20 +95,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( { auto f = fIt->second; - if (ai->cc == ARM64_CC_AL - || ai->cc == ARM64_CC_INVALID /* || branchInsn */) - { - _inCondition = false; - (this->*f)(i, ai, irb); - } - else - { - _inCondition = true; - auto* cond = generateInsnConditionCode(irb, ai); - auto bodyIrb = generateIfThen(cond, irb); - - (this->*f)(i, ai, bodyIrb); - } + (this->*f)(i, ai, irb); } else { @@ -745,6 +732,9 @@ uint8_t Capstone2LlvmIrTranslatorArm64_impl::getOperandAccess(cs_arm64_op& op) return op.access; } +bool Capstone2LlvmIrTranslatorArm64_impl::isCondIns(cs_arm64 * i) { + return (i->cc == ARM64_CC_AL || i->cc == ARM64_CC_INVALID) ? false : true; +} // //============================================================================== @@ -1029,6 +1019,25 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateBr(cs_insn* i, cs_arm64* ai, generateBranchFunctionCall(irb, op0); } +/** + * ARM64_INS_B + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateB(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_UNARY(i, ai, irb); + + op0 = loadOpUnary(ai, irb); + + if (isCondIns(ai)) { + auto* cond = generateInsnConditionCode(irb, ai); + generateCondBranchFunctionCall(irb, cond, op0); + } + else + { + generateBranchFunctionCall(irb, op0); + } +} + /** * ARM64_INS_BL */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 019ca18d2..ac255f538 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -139,6 +139,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : llvm::Value* val, llvm::IRBuilder<>& irb, eOpConv ct = eOpConv::ZEXT_TRUNC) override; + bool isCondIns(cs_arm64 * i); // //============================================================================== // Helper methods. @@ -176,6 +177,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateLdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateLdp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateAdrp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateB(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateBl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateBr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 80409a2bf..ce0414867 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -256,7 +256,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_AESMC, nullptr}, {ARM64_INS_AND, nullptr}, {ARM64_INS_ASR, nullptr}, - {ARM64_INS_B, nullptr}, + {ARM64_INS_B, &Capstone2LlvmIrTranslatorArm64_impl::translateB}, {ARM64_INS_BFM, nullptr}, {ARM64_INS_BIC, nullptr}, {ARM64_INS_BIF, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 1371fc4a2..589fbee11 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -1121,6 +1121,34 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDP_r_r_r_i) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_B +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_B) +{ + emulate("b #0x110d8", 0x1107C); + + EXPECT_NO_REGISTERS_LOADED_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getBranchFunction(), {0x110d8}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_B_cond) +{ + emulate("b.ne #0x110d8", 0x1107C); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_Z}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + // TODO: How to test this? + //EXPECT_JUST_VALUES_CALLED({ + // {_translator->getCondBranchFunction(), {0x110d8}}, + //}); +} + // // ARM64_INS_BL // From f4332baa0f8c26f111b1fbdc2ed4c49989a7ebf8 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Wed, 6 Feb 2019 16:52:01 +0100 Subject: [PATCH 044/107] Arm64: Instruction ret can have optional register operand + test --- src/capstone2llvmir/arm64/arm64.cpp | 12 ++++++++++-- tests/capstone2llvmir/arm64_tests.cpp | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index c92566bd8..e13270c7c 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1057,8 +1057,16 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateRet(cs_insn* i, cs_arm64* ai, { EXPECT_IS_NULLARY_OR_UNARY(i, ai, irb); - // TODO: Unary variant - op0 = loadRegister(ARM64_REG_LR, irb); + // If the register operand is present + if (ai->op_count == 1) + { + op0 = loadOp(ai->operands[0], irb); + } + else + { + // Default use x30 + op0 = loadRegister(ARM64_REG_LR, irb); + } generateReturnFunctionCall(irb, op0); } diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 589fbee11..8131aa843 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -1221,6 +1221,22 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_RET) }); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_RET_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xcafebabe}, + }); + + emulate("ret x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getReturnFunction(), {0xcafebabe}}, + }); +} + } // namespace tests } // namespace capstone2llvmir From 732e021045932472ec0cf6c95c8ff834187a7b8b Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Wed, 6 Feb 2019 21:40:10 +0100 Subject: [PATCH 045/107] Arm64: BLR instruction + test --- src/capstone2llvmir/arm64/arm64.cpp | 8 +++++++- src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 22 ++++++++++++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index e13270c7c..13ec3575d 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1009,12 +1009,18 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdrp(cs_insn* i, cs_arm64* ai } /** - * ARM64_INS_BR + * ARM64_INS_BR, ARM64_INS_BRL */ void Capstone2LlvmIrTranslatorArm64_impl::translateBr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { EXPECT_IS_UNARY(i, ai, irb); + // Branch with link to register + if (i->id == ARM64_INS_BLR) + { + storeRegister(ARM64_REG_LR, getNextInsnAddress(i), irb); + } + op0 = loadOpUnary(ai, irb); generateBranchFunctionCall(irb, op0); } diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index ce0414867..754ac67b6 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -262,7 +262,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_BIF, nullptr}, {ARM64_INS_BIT, nullptr}, {ARM64_INS_BL, &Capstone2LlvmIrTranslatorArm64_impl::translateBl}, - {ARM64_INS_BLR, nullptr}, + {ARM64_INS_BLR, &Capstone2LlvmIrTranslatorArm64_impl::translateBr}, {ARM64_INS_BR, &Capstone2LlvmIrTranslatorArm64_impl::translateBr}, {ARM64_INS_BRK, nullptr}, {ARM64_INS_BSL, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 8131aa843..a0e1cede2 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -1201,6 +1201,28 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_BR) }); } +// +// ARM64_INS_BLR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_BLR) +{ + setRegisters({ + {ARM64_REG_X2, 0x123456789abcdef0}, + }); + + emulate("blr x2", 0x2000); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_LR, 0x2004}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getBranchFunction(), {0x123456789abcdef0}}, + }); +} + // // ARM64_INS_RET // From c55d1d45d94e0be24371e4b056536c814f3cc68e Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 7 Feb 2019 10:54:56 +0100 Subject: [PATCH 046/107] Arm64: CBNZ, CBZ instruction + test --- src/capstone2llvmir/arm64/arm64.cpp | 24 ++++++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 4 +- tests/capstone2llvmir/arm64_tests.cpp | 72 ++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 13ec3575d..0ad7cc411 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1056,6 +1056,30 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateBl(cs_insn* i, cs_arm64* ai, generateCallFunctionCall(irb, op0); } +/** + * ARM64_INS_CBNZ, ARM64_INS_CBZ + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateCbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + std::tie(op0, op1) = loadOpBinary(ai, irb); + llvm::Value* cond = nullptr; + if (i->id == ARM64_INS_CBNZ) + { + cond = irb.CreateICmpNE(op0, llvm::ConstantInt::get(op0->getType(), 0)); + } + else if (i->id == ARM64_INS_CBZ) + { + cond = irb.CreateICmpEQ(op0, llvm::ConstantInt::get(op0->getType(), 0)); + } + else + { + throw GenericError("cbnz, cbz: Instruction id error"); + } + generateCondBranchFunctionCall(irb, cond, op1); +} + /** * ARM64_INS_RET */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index ac255f538..e08b24ba2 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -180,6 +180,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateB(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateBl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateBr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateCbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); }; diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 754ac67b6..c7d480ca6 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -266,8 +266,8 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_BR, &Capstone2LlvmIrTranslatorArm64_impl::translateBr}, {ARM64_INS_BRK, nullptr}, {ARM64_INS_BSL, nullptr}, - {ARM64_INS_CBNZ, nullptr}, - {ARM64_INS_CBZ, nullptr}, + {ARM64_INS_CBNZ, &Capstone2LlvmIrTranslatorArm64_impl::translateCbnz}, + {ARM64_INS_CBZ, &Capstone2LlvmIrTranslatorArm64_impl::translateCbnz}, {ARM64_INS_CCMN, nullptr}, {ARM64_INS_CCMP, nullptr}, {ARM64_INS_CLREX, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index a0e1cede2..ee5d22d88 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -1223,6 +1223,78 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_BLR) }); } +// +// ARM64_INS_CBNZ +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CBNZ_true) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + }); + + emulate("cbnz x1, #0x1000"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {true, 0x1000}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CBNZ_false) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + }); + + emulate("cbnz x1, #0x1234"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {false, 0x1234}}, + }); +} + +// +// ARM64_INS_CBZ +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CBZ_true) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + }); + + emulate("cbz x1, #0x1000"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {false, 0x1000}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CBZ_false) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + }); + + emulate("cbz x1, #0x1234"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {true, 0x1234}}, + }); +} + // // ARM64_INS_RET // From 29d4f888ad53262dff5e629b64acfa052f24af5b Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 7 Feb 2019 12:44:58 +0100 Subject: [PATCH 047/107] Arm64: TBNZ, TBZ implementation + tests --- src/capstone2llvmir/arm64/arm64.cpp | 30 +++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 4 +- tests/capstone2llvmir/arm64_tests.cpp | 136 +++++++++++++++++++++++ 4 files changed, 169 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 0ad7cc411..70c7b48e8 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1080,6 +1080,36 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateCbnz(cs_insn* i, cs_arm64* ai generateCondBranchFunctionCall(irb, cond, op1); } +/** + * ARM64_INS_TBNZ, ARM64_INS_TBZ + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateTbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + std::tie(op0, op1, op2) = loadOpTernary(ai, irb); + + // Get the needed bit + auto* ext_imm = irb.CreateZExtOrTrunc(op1, op0->getType()); + auto* shifted_one = irb.CreateShl(llvm::ConstantInt::get(op0->getType(), 1), ext_imm); + auto* test_bit = irb.CreateAnd(shifted_one, op0); + + llvm::Value* cond = nullptr; + if (i->id == ARM64_INS_TBNZ) + { + cond = irb.CreateICmpNE(test_bit, llvm::ConstantInt::get(op0->getType(), 0)); + } + else if (i->id == ARM64_INS_TBZ) + { + cond = irb.CreateICmpEQ(test_bit, llvm::ConstantInt::get(op0->getType(), 0)); + } + else + { + throw GenericError("cbnz, cbz: Instruction id error"); + } + generateCondBranchFunctionCall(irb, cond, op2); +} + /** * ARM64_INS_RET */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index e08b24ba2..4d80183a8 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -181,6 +181,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateBl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateBr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateCbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateTbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); }; diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index c7d480ca6..7309212d8 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -590,9 +590,9 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_SYSL, nullptr}, {ARM64_INS_SYS, nullptr}, {ARM64_INS_TBL, nullptr}, - {ARM64_INS_TBNZ, nullptr}, + {ARM64_INS_TBNZ, &Capstone2LlvmIrTranslatorArm64_impl::translateTbnz}, {ARM64_INS_TBX, nullptr}, - {ARM64_INS_TBZ, nullptr}, + {ARM64_INS_TBZ, &Capstone2LlvmIrTranslatorArm64_impl::translateTbnz}, {ARM64_INS_TRN1, nullptr}, {ARM64_INS_TRN2, nullptr}, {ARM64_INS_UABAL2, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index ee5d22d88..2569b1d73 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -1295,6 +1295,142 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CBZ_false) }); } +// +// ARM64_INS_TBNZ +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TBNZ_true) +{ + setRegisters({ + {ARM64_REG_X1, 0x000000000000000f}, + }); + + emulate("tbnz x1, #0, #0x1000"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {true, 0x1000}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TBNZ_false) +{ + setRegisters({ + {ARM64_REG_X1, 0xfffffffffffffff0}, + }); + + emulate("tbnz x1, #0, #0x1000"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {false, 0x1000}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TBNZ_63_true) +{ + setRegisters({ + {ARM64_REG_X1, 0x8000000000000000}, + }); + + emulate("tbnz x1, #63, #0x1000"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {true, 0x1000}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TBNZ_32_true) +{ + setRegisters({ + {ARM64_REG_X1, 0x100000000}, + }); + + emulate("tbnz x1, #32, #0x1000"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {true, 0x1000}}, + }); +} + +// +// ARM64_INS_TBZ +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TBZ_false) +{ + setRegisters({ + {ARM64_REG_X1, 0x000000000000000f}, + }); + + emulate("tbz x1, #0, #0x1000"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {false, 0x1000}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TBZ_true) +{ + setRegisters({ + {ARM64_REG_X1, 0xfffffffffffffff0}, + }); + + emulate("tbz x1, #0, #0x1000"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {true, 0x1000}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TBZ_63_false) +{ + setRegisters({ + {ARM64_REG_X1, 0x8000000000000000}, + }); + + emulate("tbz x1, #63, #0x1000"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {false, 0x1000}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TBZ_32_false) +{ + setRegisters({ + {ARM64_REG_X1, 0x100000000}, + }); + + emulate("tbz x1, #32, #0x1000"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {false, 0x1000}}, + }); +} + // // ARM64_INS_RET // From 6cf11dd288229a166e5df1299b04e49360399453 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 7 Feb 2019 19:21:30 +0100 Subject: [PATCH 048/107] Arm64: LDR different size variants, sign/zero extend + tests --- src/capstone2llvmir/arm64/arm64.cpp | 68 +++++++++- src/capstone2llvmir/arm64/arm64_init.cpp | 20 +-- tests/capstone2llvmir/arm64_tests.cpp | 157 +++++++++++++++++++++++ 3 files changed, 230 insertions(+), 15 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 70c7b48e8..7e2e9dbff 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -904,18 +904,77 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, /** * ARM64_INS_LDR + * ARM64_INS_LDURB, ARM64_INS_LDUR, ARM64_INS_LDURH, ARM64_INS_LDURSB, ARM64_INS_LDURSH, ARM64_INS_LDURSW + * ARM64_INS_LDRB, ARM64_INS_LDRH, ARM64_INS_LDRSB, ARM64_INS_LDRSH, ARM64_INS_LDRSW */ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { EXPECT_IS_BINARY_OR_TERNARY(i, ai, irb); + llvm::Type* ty = nullptr; + bool sext = false; + switch (i->id) + { + case ARM64_INS_LDR: + case ARM64_INS_LDUR: + { + ty = irb.getInt32Ty(); + sext = false; + break; + } + case ARM64_INS_LDRB: + case ARM64_INS_LDURB: + { + ty = irb.getInt8Ty(); + sext = false; + break; + } + case ARM64_INS_LDRH: + case ARM64_INS_LDURH: + { + ty = irb.getInt16Ty(); + sext = false; + break; + } + // Signed loads + case ARM64_INS_LDRSB: + case ARM64_INS_LDURSB: + { + ty = irb.getInt8Ty(); + sext = true; + break; + } + case ARM64_INS_LDRSH: + case ARM64_INS_LDURSH: + { + ty = irb.getInt16Ty(); + sext = true; + break; + } + case ARM64_INS_LDRSW: + case ARM64_INS_LDURSW: + { + ty = irb.getInt32Ty(); + sext = true; + break; + } + default: + { + throw GenericError("Arm64: unhandled LDR id"); + } + } + auto* regType = getRegisterType(ai->operands[0].reg); auto* dest = loadOp(ai->operands[1], irb, nullptr, true); - auto* pt = llvm::PointerType::get(regType, 0); + auto* pt = llvm::PointerType::get(ty, 0); auto* addr = irb.CreateIntToPtr(dest, pt); - auto* newRegValue = irb.CreateLoad(addr); - storeRegister(ai->operands[0].reg, newRegValue, irb); + auto* loaded_value = irb.CreateLoad(addr); + auto* ext_value = sext + ? irb.CreateSExtOrTrunc(loaded_value, regType) + : irb.CreateZExtOrTrunc(loaded_value, regType); + + storeRegister(ai->operands[0].reg, ext_value, irb); uint32_t baseR = ARM64_REG_INVALID; if (ai->op_count == 2) @@ -931,8 +990,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, } else { - // TODO: This should not be posible, throw error? - assert(false && "unsupported LDR format"); + throw GenericError("Arm64: unsupported ldr format"); } if (ai->writeback && baseR != ARM64_REG_INVALID) diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 7309212d8..09c2b5e06 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -403,12 +403,12 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_LDNP, nullptr}, {ARM64_INS_LDP, &Capstone2LlvmIrTranslatorArm64_impl::translateLdp}, {ARM64_INS_LDPSW, nullptr}, - {ARM64_INS_LDRB, nullptr}, + {ARM64_INS_LDRB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDR, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, - {ARM64_INS_LDRH, nullptr}, - {ARM64_INS_LDRSB, nullptr}, - {ARM64_INS_LDRSH, nullptr}, - {ARM64_INS_LDRSW, nullptr}, + {ARM64_INS_LDRH, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDRSB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDRSH, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDRSW, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDTRB, nullptr}, {ARM64_INS_LDTRH, nullptr}, {ARM64_INS_LDTRSB, nullptr}, @@ -416,12 +416,12 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_LDTRSH, nullptr}, {ARM64_INS_LDTRSW, nullptr}, {ARM64_INS_LDTR, nullptr}, - {ARM64_INS_LDURB, nullptr}, + {ARM64_INS_LDURB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDUR, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, - {ARM64_INS_LDURH, nullptr}, - {ARM64_INS_LDURSB, nullptr}, - {ARM64_INS_LDURSH, nullptr}, - {ARM64_INS_LDURSW, nullptr}, + {ARM64_INS_LDURH, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDURSB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDURSH, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDURSW, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDXP, nullptr}, {ARM64_INS_LDXRB, nullptr}, {ARM64_INS_LDXRH, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 2569b1d73..15dca3374 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -1027,6 +1027,131 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDR_label) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_LDRB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDRB) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0xf1_b}, + }); + + emulate("ldrb w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xf1}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LDRSB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDRSB) +{ + setRegisters({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x80_b}, + }); + + emulate("ldrsb w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffff80}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LDRH +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDRH) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x8182_w}, + }); + + emulate("ldrh w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x8182}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LDRSH +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDRSH) +{ + setRegisters({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x8182_w}, + }); + + emulate("ldrsh w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffff8182}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LDRSW +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDRSW) +{ + setRegisters({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x81828384_dw}, + }); + + emulate("ldrsw x0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffff81828384}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_LDP // @@ -1259,6 +1384,22 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CBNZ_false) }); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CBNZ32_true) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + }); + + emulate("cbnz w1, #0x1000"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {true, 0x1000}}, + }); +} + // // ARM64_INS_CBZ // @@ -1295,6 +1436,22 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CBZ_false) }); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CBZ32_true) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + }); + + emulate("cbz w1, #0x1000"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {false, 0x1000}}, + }); +} + // // ARM64_INS_TBNZ // From e84259e50225f011019132403b696bd2c8dd7a33 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 8 Feb 2019 17:43:16 +0100 Subject: [PATCH 049/107] Arm64: LDPSW instruction + tests - minor warning fix in STR instruction --- src/capstone2llvmir/arm64/arm64.cpp | 58 +++++++++++++----- src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 77 ++++++++++++++++++++++++ 3 files changed, 120 insertions(+), 17 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 7e2e9dbff..ad40cccdb 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -88,7 +88,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( cs_detail* d = i->detail; cs_arm64* ai = &d->arm64; - std::cout << i->mnemonic << " " << i->op_str << std::endl; + //std::cout << i->mnemonic << " " << i->op_str << std::endl; auto fIt = _i2fm.find(i->id); if (fIt != _i2fm.end() && fIt->second != nullptr) @@ -799,16 +799,20 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMov(cs_insn* i, cs_arm64* ai, } /** - * ARM64_INS_STR + * ARM64_INS_STR, ARM64_INS_STRB, ARM64_INS_STRH */ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { EXPECT_IS_BINARY_OR_TERNARY(i, ai, irb); - auto ty = getDefaultType(); - + llvm::Type* ty = nullptr; switch (i->id) { + case ARM64_INS_STR: + { + ty = getDefaultType(); + break; + } case ARM64_INS_STRB: { ty = irb.getInt8Ty(); @@ -819,6 +823,10 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, ty = irb.getInt16Ty(); break; } + default: + { + throw GenericError("Arm64: unhandled STR id"); + } } op0 = loadOp(ai->operands[0], irb); @@ -1000,17 +1008,35 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, } /** - * ARM64_INS_LDP + * ARM64_INS_LDP, ARM64_INS_LDPSW */ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { EXPECT_IS_EXPR(i, ai, irb, (2 <= ai->op_count && ai->op_count <= 4)); - auto* regType = getRegisterType(ai->operands[0].reg); - auto* dest = generateGetOperandMemAddr(ai->operands[2], irb); - auto* pt = llvm::PointerType::get(regType, 0); + llvm::Value* data_size = nullptr; + llvm::Type* ty = nullptr; + eOpConv ct = eOpConv::THROW; + if(i->id == ARM64_INS_LDP) + { + data_size = llvm::ConstantInt::get(getDefaultType(), getRegisterByteSize(ai->operands[0].reg)); + ty = getRegisterType(ai->operands[0].reg); + ct = eOpConv::ZEXT_TRUNC; + } + else if(i->id == ARM64_INS_LDPSW) + { + data_size = llvm::ConstantInt::get(getDefaultType(), 4); + ty = irb.getInt32Ty(); + ct = eOpConv::SEXT_TRUNC; + } + else + { + throw GenericError("ldp, ldpsw: Instruction id error"); + } + + auto* dest = loadOp(ai->operands[2], irb, nullptr, true); + auto* pt = llvm::PointerType::get(ty, 0); auto* addr = irb.CreateIntToPtr(dest, pt); - auto* registerSize = llvm::ConstantInt::get(getDefaultType(), getRegisterByteSize(ai->operands[0].reg)); auto* newReg1Value = irb.CreateLoad(addr); @@ -1019,22 +1045,22 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, uint32_t baseR = ARM64_REG_INVALID; if (ai->op_count == 3) { - storeRegister(ai->operands[0].reg, newReg1Value, irb); - newDest = irb.CreateAdd(dest, registerSize); + storeRegister(ai->operands[0].reg, newReg1Value, irb, ct); + newDest = irb.CreateAdd(dest, data_size); addr = irb.CreateIntToPtr(newDest, pt); newReg2Value = irb.CreateLoad(addr); - storeRegister(ai->operands[1].reg, newReg2Value, irb); + storeRegister(ai->operands[1].reg, newReg2Value, irb, ct); baseR = ai->operands[2].mem.base; } else if (ai->op_count == 4) { - storeRegister(ai->operands[0].reg, newReg1Value, irb); - newDest = irb.CreateAdd(dest, registerSize); + storeRegister(ai->operands[0].reg, newReg1Value, irb, ct); + newDest = irb.CreateAdd(dest, data_size); addr = irb.CreateIntToPtr(newDest, pt); newReg2Value = irb.CreateLoad(addr); - storeRegister(ai->operands[1].reg, newReg2Value, irb); + storeRegister(ai->operands[1].reg, newReg2Value, irb, ct); auto* disp = llvm::ConstantInt::get(getDefaultType(), ai->operands[3].imm); dest = irb.CreateAdd(dest, disp); @@ -1042,7 +1068,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, } else { - assert(false && "unsupported LDP format"); + throw GenericError("ldp, ldpsw: Unsupported instruction format"); } if (ai->writeback && baseR != ARM64_REG_INVALID) diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 09c2b5e06..407d80ce1 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -402,7 +402,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_LDAXR, nullptr}, {ARM64_INS_LDNP, nullptr}, {ARM64_INS_LDP, &Capstone2LlvmIrTranslatorArm64_impl::translateLdp}, - {ARM64_INS_LDPSW, nullptr}, + {ARM64_INS_LDPSW, &Capstone2LlvmIrTranslatorArm64_impl::translateLdp}, {ARM64_INS_LDRB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDR, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDRH, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 15dca3374..156e6655e 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -1246,6 +1246,83 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDP_r_r_r_i) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_LDPSW +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDPSW_r_r_r) +{ + setRegisters({ + {ARM64_REG_SP, 0x1000}, + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x0}, + }); + setMemory({ + {0x1000, 0x12345678_dw}, + {0x1004, 0xfedcba98_dw}, + }); + + emulate("ldpsw x0, x1, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x12345678}, + {ARM64_REG_X1, 0xfffffffffedcba98}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000, 0x1004}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDPSW1_r_r_r) +{ + setRegisters({ + {ARM64_REG_SP, 0x1000}, + {ARM64_REG_X0, 0x0}, + {ARM64_REG_X1, 0xffffffffffffffff}, + }); + setMemory({ + {0x1000, 0x12345678_dw}, + {0x1004, 0xfedcba98_dw}, + }); + + emulate("ldpsw x1, x0, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xfffffffffedcba98}, + {ARM64_REG_X1, 0x12345678}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000, 0x1004}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDPSW_r_r_r_i) +{ + setRegisters({ + {ARM64_REG_SP, 0x1000}, + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x0}, + }); + setMemory({ + {0x1000, 0x12345678_dw}, + {0x1004, 0xfedcba98_dw}, + }); + + emulate("ldpsw x0, x1, [sp], #32"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x12345678}, + {ARM64_REG_X1, 0xfffffffffedcba98}, + {ARM64_REG_SP, 0x1020}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000, 0x1004}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_B // From ece1754c7871229dc4830429b42ada9c0a7b0522 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 8 Feb 2019 19:54:03 +0100 Subject: [PATCH 050/107] Arm64: ADC instruction + tests - including flag setting for ADC and ADD instructions - ADDS tests --- src/capstone2llvmir/arm64/arm64.cpp | 37 +++- src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 213 +++++++++++++++++++++++ 4 files changed, 250 insertions(+), 3 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index ad40cccdb..226abbddf 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -742,6 +742,32 @@ bool Capstone2LlvmIrTranslatorArm64_impl::isCondIns(cs_arm64 * i) { //============================================================================== // +/** + * ARM64_INS_ADC + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateAdc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); + op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); + auto* carry = loadRegister(ARM64_REG_CPSR_C, irb); + + auto* val = irb.CreateAdd(op1, op2); + val = irb.CreateAdd(val, irb.CreateZExtOrTrunc(carry, val->getType())); + + storeOp(ai->operands[0], val, irb); + + if (ai->update_flags) + { + llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); + storeRegister(ARM64_REG_CPSR_C, generateCarryAddC(op1, op2, irb, carry), irb); + storeRegister(ARM64_REG_CPSR_V, generateOverflowAddC(val, op1, op2, irb, carry), irb); + storeRegister(ARM64_REG_CPSR_N, irb.CreateICmpSLT(val, zero), irb); + storeRegister(ARM64_REG_CPSR_Z, irb.CreateICmpEQ(val, zero), irb); + } +} + /** * ARM64_INS_ADD */ @@ -750,11 +776,19 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, EXPECT_IS_TERNARY(i, ai, irb); std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); - // In case of 32bit reg, trunc the imm op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); auto *val = irb.CreateAdd(op1, op2); storeOp(ai->operands[0], val, irb); + + if (ai->update_flags) + { + llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); + storeRegister(ARM64_REG_CPSR_C, generateCarryAdd(val, op1, irb), irb); + storeRegister(ARM64_REG_CPSR_V, generateOverflowAdd(val, op1, op2, irb), irb); + storeRegister(ARM64_REG_CPSR_N, irb.CreateICmpSLT(val, zero), irb); + storeRegister(ARM64_REG_CPSR_Z, irb.CreateICmpEQ(val, zero), irb); + } } /** @@ -765,7 +799,6 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateSub(cs_insn* i, cs_arm64* ai, EXPECT_IS_TERNARY(i, ai, irb); std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); - // In case of 32bit reg, trunc the imm op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); auto *val = irb.CreateSub(op1, op2); diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 4d80183a8..a2b1b818b 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -169,6 +169,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : //============================================================================== // protected: + void translateAdc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 407d80ce1..5df6b002a 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -242,7 +242,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM_INS_INVALID, nullptr}, {ARM64_INS_ABS, nullptr}, - {ARM64_INS_ADC, nullptr}, + {ARM64_INS_ADC, &Capstone2LlvmIrTranslatorArm64_impl::translateAdc}, {ARM64_INS_ADDHN, nullptr}, {ARM64_INS_ADDHN2, nullptr}, {ARM64_INS_ADDP, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 156e6655e..6de5e310a 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -152,6 +152,134 @@ INSTANTIATE_TEST_CASE_P( ::testing::Values(CS_MODE_ARM), PrintCapstoneModeToString_Arm64()); +// +// ARM64_INS_ADC +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_r_r_i_false) +{ + setRegisters({ + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_X1, 0x1230}, + {ARM64_REG_X2, 0x4}, + }); + + emulate("adc x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1234}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_r_r_i_true) +{ + setRegisters({ + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_X1, 0x1230}, + {ARM64_REG_X2, 0x4}, + }); + + emulate("adc x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1235}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_s_r_r_i_false) +{ + setRegisters({ + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_X1, 0x1230}, + {ARM64_REG_X2, 0x4}, + }); + + emulate("adcs x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1234}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_flags) +{ + setRegisters({ + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_X1, 0xfffffffffffffffe}, + {ARM64_REG_X2, 0x1}, + }); + + emulate("adcs x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_flags1) +{ + setRegisters({ + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_X1, 0xfffffffffffffffe}, + {ARM64_REG_X2, 0xffffffffffffffff}, + }); + + emulate("adcs x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xfffffffffffffffe}, + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_flags2) +{ + setRegisters({ + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_X1, 0xfffffffffffffffe}, + {ARM64_REG_X2, 0x0}, + }); + + emulate("adcs x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_ADD // @@ -418,6 +546,91 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_w_w_w_SXTW) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_s_zero_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + {ARM64_REG_X2, 0x0}, + }); + + emulate("adds x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_s_negative_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xffff000000000000}, + {ARM64_REG_X2, 0x1234}, + }); + + emulate("adds x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffff000000001234}, + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_s_carry_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0x1}, + }); + + emulate("adds x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_s_overflow_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x0fffffffffffffff}, + {ARM64_REG_X2, 0x7408089100000000}, + }); + + emulate("adds x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x84080890ffffffff}, + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + + // // ARM64_INS_SUB // From 950f92f6c5591c0b97bc205d2ca2e084defcc052 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 8 Feb 2019 20:08:30 +0100 Subject: [PATCH 051/107] Arm64: ADCS 32bit tests for flags --- tests/capstone2llvmir/arm64_tests.cpp | 69 +++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 6de5e310a..dbef52004 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -156,7 +156,7 @@ INSTANTIATE_TEST_CASE_P( // ARM64_INS_ADC // -TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_r_r_i_false) +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_r_r_r_false) { setRegisters({ {ARM64_REG_CPSR_C, false}, @@ -174,7 +174,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_r_r_i_false) EXPECT_NO_VALUE_CALLED(); } -TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_r_r_i_true) +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_r_r_r_true) { setRegisters({ {ARM64_REG_CPSR_C, true}, @@ -192,7 +192,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_r_r_i_true) EXPECT_NO_VALUE_CALLED(); } -TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_s_r_r_i_false) +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_s_r_r_r_false) { setRegisters({ {ARM64_REG_CPSR_C, false}, @@ -214,6 +214,69 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_s_r_r_i_false) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC32_r_r_r_true) +{ + setRegisters({ + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_X1, 0x1230}, + {ARM64_REG_X2, 0x4}, + }); + + emulate("adc w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1235}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC32_s_r_r_r_false) +{ + setRegisters({ + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_X1, 0x1230}, + {ARM64_REG_X2, 0x4}, + }); + + emulate("adcs w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1234}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC32_flags) +{ + setRegisters({ + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_X1, 0xfffffffffffffffe}, + {ARM64_REG_X2, 0x1}, + }); + + emulate("adcs w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + + TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADC_flags) { setRegisters({ From aa58cf0231860ca8e13201565a93cde48444aea7 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 9 Feb 2019 13:45:10 +0100 Subject: [PATCH 052/107] Arm64: ADR, ADRP instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 20 ++++++++++++--- src/capstone2llvmir/arm64/arm64_impl.h | 2 +- src/capstone2llvmir/arm64/arm64_init.cpp | 4 +-- tests/capstone2llvmir/arm64_tests.cpp | 31 ++++++++++++++++++++++++ 4 files changed, 50 insertions(+), 7 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 226abbddf..64f152a7a 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1111,18 +1111,30 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, } /** - * ARM64_INS_ADRP + * ARM64_INS_ADR, ARM64_INS_ADRP */ -void Capstone2LlvmIrTranslatorArm64_impl::translateAdrp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +void Capstone2LlvmIrTranslatorArm64_impl::translateAdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { EXPECT_IS_BINARY(i, ai, irb); auto* imm = loadOpBinaryOp1(ai, irb); - auto* base = llvm::ConstantInt::get(getDefaultType(), (((i->address + i->size) >> 12) << 12)); + // Eventhough the semantics for this instruction is + // base = PC[] + // X[t] = base + imm + // It looks like capstone is already doing this work for us and + // second operand has calculated value already + /* + auto* base = loadRegister(ARM64_REG_PC, irb); + // ADRP loads address to 4KB page + if (i->id == ARM64_INS_ADRP) + { + base = llvm::ConstantInt::get(getDefaultType(), (((i->address + i->size) >> 12) << 12)); + } auto* res = irb.CreateAdd(base, imm); + */ - storeRegister(ai->operands[0].reg, res, irb); + storeRegister(ai->operands[0].reg, imm, irb); } /** diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index a2b1b818b..d67a77bb7 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -177,7 +177,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateStp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateLdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateLdp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); - void translateAdrp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateAdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateB(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateBl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateBr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 5df6b002a..8ba361740 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -248,8 +248,8 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_ADDP, nullptr}, {ARM64_INS_ADD, &Capstone2LlvmIrTranslatorArm64_impl::translateAdd}, {ARM64_INS_ADDV, nullptr}, - {ARM64_INS_ADR, nullptr}, - {ARM64_INS_ADRP, &Capstone2LlvmIrTranslatorArm64_impl::translateAdrp}, + {ARM64_INS_ADR, &Capstone2LlvmIrTranslatorArm64_impl::translateAdr}, + {ARM64_INS_ADRP, &Capstone2LlvmIrTranslatorArm64_impl::translateAdr}, {ARM64_INS_AESD, nullptr}, {ARM64_INS_AESE, nullptr}, {ARM64_INS_AESIMC, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index dbef52004..865dea1ba 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -693,6 +693,37 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADD_s_overflow_r_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_ADR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADR) +{ + emulate("test:; adr x0, test", 0x40578); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x40578}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_ADRP +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADRP) +{ + emulate("test:; adrp x0, test", 0x41578); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x82000}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} // // ARM64_INS_SUB From 52c893231d55a9739f802f99a73629b5153c9b14 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 9 Feb 2019 14:25:50 +0100 Subject: [PATCH 053/107] Arm64: AND, ANDS instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 24 ++++++- src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 91 ++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 64f152a7a..e90bfc8cd 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1119,7 +1119,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdr(cs_insn* i, cs_arm64* ai, auto* imm = loadOpBinaryOp1(ai, irb); - // Eventhough the semantics for this instruction is + // Even though the semantics for this instruction is // base = PC[] // X[t] = base + imm // It looks like capstone is already doing this work for us and @@ -1137,6 +1137,28 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdr(cs_insn* i, cs_arm64* ai, storeRegister(ai->operands[0].reg, imm, irb); } +/** + * ARM64_INS_AND + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateAnd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY_OR_TERNARY(i, ai, irb); + + std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); + op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); + + auto* val = irb.CreateAnd(op1, op2); + + storeOp(ai->operands[0], val, irb); + + if (ai->update_flags) + { + llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); + storeRegister(ARM64_REG_CPSR_N, irb.CreateICmpSLT(val, zero), irb); + storeRegister(ARM64_REG_CPSR_Z, irb.CreateICmpEQ(val, zero), irb); + } +} + /** * ARM64_INS_BR, ARM64_INS_BRL */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index d67a77bb7..7b11c7748 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -171,6 +171,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : protected: void translateAdc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateAnd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 8ba361740..002ae6cd8 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -254,7 +254,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_AESE, nullptr}, {ARM64_INS_AESIMC, nullptr}, {ARM64_INS_AESMC, nullptr}, - {ARM64_INS_AND, nullptr}, + {ARM64_INS_AND, &Capstone2LlvmIrTranslatorArm64_impl::translateAnd}, {ARM64_INS_ASR, nullptr}, {ARM64_INS_B, &Capstone2LlvmIrTranslatorArm64_impl::translateB}, {ARM64_INS_BFM, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 865dea1ba..cb62aa7a4 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -725,6 +725,97 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ADRP) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_AND +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_AND_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234567890abcdef}, + }); + + emulate("and x0, x1, #0xf0"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000000000e0}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_AND_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234567890abcdef}, + {ARM64_REG_X2, 0xff00ff00ff00ff00}, + }); + + emulate("and x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x120056009000cd00}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_AND32_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234567890abcdef}, + }); + + emulate("and w0, w1, #0x0f"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x000000000000000f}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_AND_s_zero_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x12345678}, + {ARM64_REG_X2, 0x0}, + }); + + emulate("ands x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_AND32_s_negative_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234567880abcdef}, + {ARM64_REG_X2, 0xf0000000}, + }); + + emulate("ands w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x80000000}, + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_SUB // From 00b2b83029471e6bfd038ee1187a034878fb1f0a Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 9 Feb 2019 16:24:48 +0100 Subject: [PATCH 054/107] Arm64: ASR instruction + tests - ASRV variant --- src/capstone2llvmir/arm64/arm64.cpp | 28 +++++++++++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 53 ++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index e90bfc8cd..de8e4b6f6 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1159,6 +1159,34 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAnd(cs_insn* i, cs_arm64* ai, } } +/** + * ARM64_INS_ASR + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateShifts(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY_OR_TERNARY(i, ai, irb); + + std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); + op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); + + llvm::Value* val = nullptr; + switch(i->id) + { + // TODO: Other shifts + case ARM64_INS_ASR: + { + val = irb.CreateAShr(op1, op2); + break; + } + default: + { + throw GenericError("Shifts: unhandled insn ID"); + } + } + + storeOp(ai->operands[0], val, irb); +} + /** * ARM64_INS_BR, ARM64_INS_BRL */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 7b11c7748..395c3621d 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -172,6 +172,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateAdc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateAnd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateShifts(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 002ae6cd8..b461bd56f 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -255,7 +255,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_AESIMC, nullptr}, {ARM64_INS_AESMC, nullptr}, {ARM64_INS_AND, &Capstone2LlvmIrTranslatorArm64_impl::translateAnd}, - {ARM64_INS_ASR, nullptr}, + {ARM64_INS_ASR, &Capstone2LlvmIrTranslatorArm64_impl::translateShifts}, {ARM64_INS_B, &Capstone2LlvmIrTranslatorArm64_impl::translateB}, {ARM64_INS_BFM, nullptr}, {ARM64_INS_BIC, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index cb62aa7a4..33dd4220b 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -816,6 +816,59 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_AND32_s_negative_r_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_ASR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ASR_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000000000000000}, + {ARM64_REG_X2, 0x20}, + }); + + emulate("asr x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000010000000}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ASR_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0x8000000000000000}, + }); + + emulate("asr x0, x1, #63"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ASR32_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0x0000000080000000}, + }); + + emulate("asr w0, w1, #31"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000ffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_SUB // From c9046dfb1854f3f95e835a2e6feb24243219fd5d Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 9 Feb 2019 16:55:17 +0100 Subject: [PATCH 055/107] Arm64: LSL, LSR, ROR instructions + tests - all major shifts implemented --- src/capstone2llvmir/arm64/arm64.cpp | 15 +++ src/capstone2llvmir/arm64/arm64_init.cpp | 6 +- tests/capstone2llvmir/arm64_tests.cpp | 160 +++++++++++++++++++++++ 3 files changed, 178 insertions(+), 3 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index de8e4b6f6..3014f791b 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1178,6 +1178,21 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateShifts(cs_insn* i, cs_arm64* val = irb.CreateAShr(op1, op2); break; } + case ARM64_INS_LSL: + { + val = irb.CreateShl(op1, op2); + break; + } + case ARM64_INS_LSR: + { + val = irb.CreateLShr(op1, op2); + break; + } + case ARM64_INS_ROR: + { + val = generateShiftRor(irb, op1, op2); + break; + } default: { throw GenericError("Shifts: unhandled insn ID"); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index b461bd56f..66a567be5 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -426,8 +426,8 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_LDXRB, nullptr}, {ARM64_INS_LDXRH, nullptr}, {ARM64_INS_LDXR, nullptr}, - {ARM64_INS_LSL, nullptr}, - {ARM64_INS_LSR, nullptr}, + {ARM64_INS_LSL, &Capstone2LlvmIrTranslatorArm64_impl::translateShifts}, + {ARM64_INS_LSR, &Capstone2LlvmIrTranslatorArm64_impl::translateShifts}, {ARM64_INS_MADD, nullptr}, {ARM64_INS_MLA, nullptr}, {ARM64_INS_MLS, nullptr}, @@ -457,7 +457,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_REV32, nullptr}, {ARM64_INS_REV64, nullptr}, {ARM64_INS_REV, nullptr}, - {ARM64_INS_ROR, nullptr}, + {ARM64_INS_ROR, &Capstone2LlvmIrTranslatorArm64_impl::translateShifts}, {ARM64_INS_RSHRN2, nullptr}, {ARM64_INS_RSHRN, nullptr}, {ARM64_INS_RSUBHN, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 33dd4220b..de9dbbd3a 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -1774,6 +1774,113 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDPSW_r_r_r_i) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_LSL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LSL_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffff00000001}, + {ARM64_REG_X2, 0x20}, + }); + + emulate("lsl x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000100000000}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LSL_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0x0000000000000001}, + }); + + emulate("lsl x0, x1, #63"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x8000000000000000}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LSL32_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0x0000000000000001}, + {ARM64_REG_X2, 31}, + }); + + emulate("lsl w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000080000000}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LSR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LSR_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000000000000000}, + {ARM64_REG_X2, 0x20}, + }); + + emulate("lsr x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000010000000}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LSR_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0x8000000000000000}, + }); + + emulate("lsr x0, x1, #63"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000000000001}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LSR32_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0x0000000080000000}, + }); + + emulate("lsr w0, w1, #31"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000000000001}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_B // @@ -2152,6 +2259,59 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_RET_r) }); } +// +// ARM64_INS_ROR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ROR_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x0000000000000001}, + {ARM64_REG_X2, 63}, + }); + + emulate("ror x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000000000002}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ROR_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffff00000000}, + }); + + emulate("ror x0, x1, #32"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000ffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ROR32_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffff00001234}, + {ARM64_REG_X2, 16}, + }); + + emulate("ror w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000012340000}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} } // namespace tests } // namespace capstone2llvmir From e66c51a4ab05dd08f7373d8f95be3de8970cc5c9 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 9 Feb 2019 17:55:19 +0100 Subject: [PATCH 056/107] Arm64: SUB, SBC flags + tests - changed asserts to exceptions --- src/capstone2llvmir/arm64/arm64.cpp | 49 ++++++-- src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 146 +++++++++++++++++++++++ 4 files changed, 188 insertions(+), 10 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 3014f791b..c3e758264 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -198,7 +198,7 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateOperandExtension( return irb.CreateSExt(trunc, ty); } default: - assert(false && "generateOperandExtension(): Unsupported extension type"); + throw GenericError("Arm64: generateOperandExtension(): Unsupported extension type"); } return val; } @@ -499,7 +499,7 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadOp( case ARM64_OP_BARRIER: default: { - assert(false && "loadOp(): unhandled operand type."); + throw GenericError("Arm64: loadOp(): unhandled operand type"); return nullptr; } } @@ -599,7 +599,7 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeOp( case ARM64_OP_BARRIER: default: { - assert(false && "stroreOp(): unhandled operand type."); + throw GenericError("storeOp(): unhandled operand type"); return nullptr; } } @@ -803,6 +803,41 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateSub(cs_insn* i, cs_arm64* ai, auto *val = irb.CreateSub(op1, op2); storeOp(ai->operands[0], val, irb); + + if (ai->update_flags) + { + llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); + storeRegister(ARM64_REG_CPSR_C, generateValueNegate(irb, generateBorrowSub(op1, op2, irb)), irb); + storeRegister(ARM64_REG_CPSR_V, generateOverflowSub(val, op1, op2, irb), irb); + storeRegister(ARM64_REG_CPSR_N, irb.CreateICmpSLT(val, zero), irb); + storeRegister(ARM64_REG_CPSR_Z, irb.CreateICmpEQ(val, zero), irb); + } +} + +/** + * ARM64_INS_SBC + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateSbc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); + op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); + auto* carry = loadRegister(ARM64_REG_CPSR_C, irb); + + auto* val = irb.CreateSub(op1, op2); + val = irb.CreateSub(val, irb.CreateZExtOrTrunc(carry, val->getType())); + + storeOp(ai->operands[0], val, irb); + + if (ai->update_flags) + { + llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); + storeRegister(ARM64_REG_CPSR_C, generateValueNegate(irb, generateBorrowSubC(val, op1, op2, irb, carry)), irb); + storeRegister(ARM64_REG_CPSR_V, generateOverflowSubC(val, op1, op2, irb, carry), irb); + storeRegister(ARM64_REG_CPSR_N, irb.CreateICmpSLT(val, zero), irb); + storeRegister(ARM64_REG_CPSR_Z, irb.CreateICmpEQ(val, zero), irb); + } } /** @@ -818,10 +853,6 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMov(cs_insn* i, cs_arm64* ai, op1 = generateValueNegate(irb, op1); } - // If S is specified, the MOV instruction: - // - updates the N and Z flags according to the result - // - can update the C flag during the calculation of Operand2 (shifts?) - // - does not affect the V flag. if (ai->update_flags) { llvm::Value* zero = llvm::ConstantInt::get(op1->getType(), 0); @@ -885,7 +916,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, } else { - assert(false && "unsupported STR format"); + throw GenericError("STR: unsupported STR format"); } if (ai->writeback && baseR != ARM64_REG_INVALID) @@ -934,7 +965,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, } else { - assert(false && "unsupported STP format"); + throw GenericError("STR: unsupported STP format"); } if (ai->writeback && baseR != ARM64_REG_INVALID) diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 395c3621d..77f2bbf78 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -174,6 +174,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateAnd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateShifts(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateSbc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateStp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 66a567be5..77667c7e5 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -476,7 +476,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_SADDL, nullptr}, {ARM64_INS_SADDW2, nullptr}, {ARM64_INS_SADDW, nullptr}, - {ARM64_INS_SBC, nullptr}, + {ARM64_INS_SBC, &Capstone2LlvmIrTranslatorArm64_impl::translateSbc}, {ARM64_INS_SBFM, nullptr}, {ARM64_INS_SCVTF, nullptr}, {ARM64_INS_SDIV, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index de9dbbd3a..bc321c35b 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -932,6 +932,152 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SUB32_r_r_i_extend_test) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SUB_s_zero_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + {ARM64_REG_X2, 0x0}, + }); + + emulate("subs x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SUB_s_negative_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xffff0000000fffff}, + {ARM64_REG_X2, 0x1234}, + }); + + emulate("subs x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffff0000000fedcb}, + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SUB_s_carry_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + {ARM64_REG_X2, 0x1}, + }); + + emulate("subs x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SUB_s_overflow_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x0fffffffffffffff}, + {ARM64_REG_X2, 0x7408089100000000}, + }); + + emulate("subs x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x9bf7f76effffffff}, + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_SBC +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SBC_r_r_r_false) +{ + setRegisters({ + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x4}, + }); + + emulate("sbc x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1230}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SBC_r_r_r_true) +{ + setRegisters({ + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_X1, 0x1235}, + {ARM64_REG_X2, 0x4}, + }); + + emulate("sbc x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1230}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SBC_s_r_r_r_false) +{ + setRegisters({ + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x4}, + }); + + emulate("sbcs x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1230}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MOV // From 8832ed1c8de287920da5cf83c46da16e685e3571 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 9 Feb 2019 18:21:36 +0100 Subject: [PATCH 057/107] Arm64: CMP, CMN instructions + tests --- src/capstone2llvmir/arm64/arm64.cpp | 20 +-- src/capstone2llvmir/arm64/arm64_init.cpp | 4 +- tests/capstone2llvmir/arm64_tests.cpp | 148 +++++++++++++++++++++++ 3 files changed, 163 insertions(+), 9 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index c3e758264..47583ab76 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -769,19 +769,22 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdc(cs_insn* i, cs_arm64* ai, } /** - * ARM64_INS_ADD + * ARM64_INS_ADD, ARM64_INS_CMN */ void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { - EXPECT_IS_TERNARY(i, ai, irb); + EXPECT_IS_BINARY_OR_TERNARY(i, ai, irb); std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); auto *val = irb.CreateAdd(op1, op2); - storeOp(ai->operands[0], val, irb); + if (i->id != ARM64_INS_CMN) + { + storeOp(ai->operands[0], val, irb); + } - if (ai->update_flags) + if (ai->update_flags || i->id == ARM64_INS_CMN) { llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); storeRegister(ARM64_REG_CPSR_C, generateCarryAdd(val, op1, irb), irb); @@ -796,15 +799,18 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, */ void Capstone2LlvmIrTranslatorArm64_impl::translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { - EXPECT_IS_TERNARY(i, ai, irb); + EXPECT_IS_BINARY_OR_TERNARY(i, ai, irb); std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); auto *val = irb.CreateSub(op1, op2); - storeOp(ai->operands[0], val, irb); + if (i->id != ARM64_INS_CMP) + { + storeOp(ai->operands[0], val, irb); + } - if (ai->update_flags) + if (ai->update_flags || i->id == ARM64_INS_CMP) { llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); storeRegister(ARM64_REG_CPSR_C, generateValueNegate(irb, generateBorrowSub(op1, op2, irb)), irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 77667c7e5..4a26af7e1 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -679,7 +679,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_UBFX, nullptr}, {ARM64_INS_BFI, nullptr}, {ARM64_INS_BFXIL, nullptr}, - {ARM64_INS_CMN, nullptr}, + {ARM64_INS_CMN, &Capstone2LlvmIrTranslatorArm64_impl::translateAdd}, {ARM64_INS_MVN, &Capstone2LlvmIrTranslatorArm64_impl::translateMov}, {ARM64_INS_TST, nullptr}, {ARM64_INS_CSET, nullptr}, @@ -690,7 +690,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_SXTB, nullptr}, {ARM64_INS_SXTH, nullptr}, {ARM64_INS_SXTW, nullptr}, - {ARM64_INS_CMP, nullptr}, + {ARM64_INS_CMP, &Capstone2LlvmIrTranslatorArm64_impl::translateSub}, {ARM64_INS_UXTB, nullptr}, {ARM64_INS_UXTH, nullptr}, {ARM64_INS_UXTW, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index bc321c35b..7901adb2d 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -869,6 +869,154 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ASR32_r_r_i) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_CMN +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMN_zero_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + {ARM64_REG_X2, 0x0}, + }); + + emulate("cmn x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMN_negative_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffff00000000}, + {ARM64_REG_X2, 0x12345678}, + }); + + emulate("cmn x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMN_carry_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0x1}, + }); + + emulate("cmn x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMN_overflow_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x0fffffffffffffff}, + {ARM64_REG_X2, 0x7408089100000000}, + }); + + emulate("cmn x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_CMP +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMP_zero_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x1234}, + }); + + emulate("cmp x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMP_s_negative_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xffff0000000fffff}, + {ARM64_REG_X2, 0x1234}, + }); + + emulate("cmp x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMP_s_carry_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + {ARM64_REG_X2, 0x1}, + }); + + emulate("cmp x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_SUB // From a0e1ff20fc5dead4f2944948a08c3f4cfabf189a Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sun, 10 Feb 2019 22:00:33 +0100 Subject: [PATCH 058/107] Arm64: CSEL instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 15 ++++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 63 ++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 47583ab76..8f20a7666 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1311,6 +1311,21 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateCbnz(cs_insn* i, cs_arm64* ai generateCondBranchFunctionCall(irb, cond, op1); } +/** + * ARM64_INS_CSEL + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateCsel(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); + + auto* cond = generateInsnConditionCode(irb, ai); + auto* val = irb.CreateSelect(cond, op1, op2); + + storeOp(ai->operands[0], val, irb); +} + /** * ARM64_INS_TBNZ, ARM64_INS_TBZ */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 77f2bbf78..d69da8753 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -185,6 +185,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateBl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateBr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateCbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateCsel(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateTbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 4a26af7e1..db4697ff8 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -291,7 +291,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_CRC32H, nullptr}, {ARM64_INS_CRC32W, nullptr}, {ARM64_INS_CRC32X, nullptr}, - {ARM64_INS_CSEL, nullptr}, + {ARM64_INS_CSEL, &Capstone2LlvmIrTranslatorArm64_impl::translateCsel}, {ARM64_INS_CSINC, nullptr}, {ARM64_INS_CSINV, nullptr}, {ARM64_INS_CSNEG, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 7901adb2d..73f9bf8aa 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -2381,6 +2381,69 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CBZ32_true) }); } +// +// ARM64_INS_CSEL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSEL_true) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0x0000000000000001}, + {ARM64_REG_CPSR_Z, false}, + }); + + emulate("csel x0, x1, x2, ne"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSEL_false) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0x0000000000000001}, + {ARM64_REG_CPSR_V, false}, + }); + + emulate("csel x0, x1, x2, vs"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_V}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSEL32_true) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x0000000000000001}, + {ARM64_REG_X2, 0xffffffffffffffff}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_V, true}, + }); + + emulate("csel w0, w1, w2, lt"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, + ARM64_REG_CPSR_N, ARM64_REG_CPSR_V}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_TBNZ // From d689563d4baecff7fc00da8d27e1df2195715758 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sun, 10 Feb 2019 22:22:20 +0100 Subject: [PATCH 059/107] Arm64: CSET, CSETM instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 30 ++++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 4 +- tests/capstone2llvmir/arm64_tests.cpp | 115 +++++++++++++++++++++++ 4 files changed, 148 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 8f20a7666..53761cb60 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1326,6 +1326,36 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateCsel(cs_insn* i, cs_arm64* ai storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_CSET, ARM64_INS_CSETM + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateCset(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_UNARY(i, ai, irb); + + auto* rt = getRegisterType(ai->operands[0].reg); + auto* zero = llvm::ConstantInt::get(rt, 0); + llvm::Value* one = nullptr; + if (i->id == ARM64_INS_CSET) + { + one = llvm::ConstantInt::get(rt, 1); + } + else if (i->id == ARM64_INS_CSETM) + { + one = llvm::ConstantInt::get(rt, ~0); + // 0xffffffffffffffff - one in all bits + } + else + { + throw GenericError("cset, csetm: Instruction id error"); + } + + auto* cond = generateInsnConditionCode(irb, ai); + auto* val = irb.CreateSelect(cond, one, zero); + + storeOp(ai->operands[0], val, irb); +} + /** * ARM64_INS_TBNZ, ARM64_INS_TBZ */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index d69da8753..d0b732480 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -186,6 +186,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateBr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateCbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateCsel(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateCset(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateTbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index db4697ff8..dbc0977b2 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -682,9 +682,9 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_CMN, &Capstone2LlvmIrTranslatorArm64_impl::translateAdd}, {ARM64_INS_MVN, &Capstone2LlvmIrTranslatorArm64_impl::translateMov}, {ARM64_INS_TST, nullptr}, - {ARM64_INS_CSET, nullptr}, + {ARM64_INS_CSET, &Capstone2LlvmIrTranslatorArm64_impl::translateCset}, {ARM64_INS_CINC, nullptr}, - {ARM64_INS_CSETM, nullptr}, + {ARM64_INS_CSETM, &Capstone2LlvmIrTranslatorArm64_impl::translateCset}, {ARM64_INS_CINV, nullptr}, {ARM64_INS_CNEG, nullptr}, {ARM64_INS_SXTB, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 73f9bf8aa..3f646374b 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -2444,6 +2444,121 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSEL32_true) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_CSET +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSET_true) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_Z, false}, + }); + + emulate("cset x0, hi"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_Z, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSET_false) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_V, true}, + }); + + emulate("cset x0, ge"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_N, ARM64_REG_CPSR_V}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSET32_true) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_V, true}, + }); + + emulate("cset w0, ge"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_N, ARM64_REG_CPSR_V}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_CSETM +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSETM_true) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_Z, false}, + }); + + emulate("csetm x0, hi"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_Z, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSETM_false) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_V, true}, + }); + + emulate("csetm x0, ge"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_N, ARM64_REG_CPSR_V}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSETM32_true) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_CPSR_C, true}, + }); + + emulate("csetm w0, hs"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000ffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_TBNZ // From e4261a87888e5871836df8ed99d01d65663bd599 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Mon, 11 Feb 2019 12:09:54 +0100 Subject: [PATCH 060/107] Arm64: MUL instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 14 +++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 72 ++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 53761cb60..614bacc8b 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1356,6 +1356,20 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateCset(cs_insn* i, cs_arm64* ai storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_MUL + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY_OR_TERNARY(i, ai, irb); + + std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); + op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); + + auto *val = irb.CreateMul(op1, op2); + storeOp(ai->operands[0], val, irb); +} + /** * ARM64_INS_TBNZ, ARM64_INS_TBZ */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index d0b732480..d761ced05 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -187,6 +187,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateCbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateCsel(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateCset(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateTbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index dbc0977b2..cdef1231f 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -438,7 +438,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_MRS, nullptr}, {ARM64_INS_MSR, nullptr}, {ARM64_INS_MSUB, nullptr}, - {ARM64_INS_MUL, nullptr}, + {ARM64_INS_MUL, &Capstone2LlvmIrTranslatorArm64_impl::translateMul}, {ARM64_INS_MVNI, nullptr}, {ARM64_INS_NEG, nullptr}, {ARM64_INS_NOT, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 3f646374b..bd4b650d8 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -2559,6 +2559,78 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSETM32_true) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_MUL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MUL_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x4}, + {ARM64_REG_X2, 0x1}, + }); + + emulate("mul x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x4}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MUL_r_r_r_1) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0xffffffffffffffff}, + }); + + emulate("mul x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MUL_r_r_r_2) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + {ARM64_REG_X2, 0xffffffffffffffff}, + }); + + emulate("mul x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MUL_r_r_r_3) +{ + setRegisters({ + {ARM64_REG_X1, 0x2}, + {ARM64_REG_X2, 0xffffffffffffffff}, + }); + + emulate("mul x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xfffffffffffffffe}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_TBNZ // From fe1786944aed16984bdbc71e7a975309428a6527 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Mon, 11 Feb 2019 12:32:57 +0100 Subject: [PATCH 061/107] Arm64: MADD instruction + tests - 32bit tests for MUL --- src/capstone2llvmir/arm64/arm64.cpp | 12 +- src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 150 +++++++++++++++++++++++ 3 files changed, 160 insertions(+), 4 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 614bacc8b..87066c972 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1357,16 +1357,22 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateCset(cs_insn* i, cs_arm64* ai } /** - * ARM64_INS_MUL + * ARM64_INS_MUL, ARM64_INS_MADD */ void Capstone2LlvmIrTranslatorArm64_impl::translateMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { - EXPECT_IS_BINARY_OR_TERNARY(i, ai, irb); + EXPECT_IS_EXPR(i, ai, irb, (3 <= ai->op_count && ai->op_count <= 4)); - std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); + auto* op1 = loadOp(ai->operands[1], irb); + auto* op2 = loadOp(ai->operands[2], irb); op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); auto *val = irb.CreateMul(op1, op2); + if (i->id == ARM64_INS_MADD) + { + auto* op3 = loadOp(ai->operands[3], irb); + val = irb.CreateAdd(val, op3); + } storeOp(ai->operands[0], val, irb); } diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index cdef1231f..d31863e1b 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -428,7 +428,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_LDXR, nullptr}, {ARM64_INS_LSL, &Capstone2LlvmIrTranslatorArm64_impl::translateShifts}, {ARM64_INS_LSR, &Capstone2LlvmIrTranslatorArm64_impl::translateShifts}, - {ARM64_INS_MADD, nullptr}, + {ARM64_INS_MADD, &Capstone2LlvmIrTranslatorArm64_impl::translateMul}, {ARM64_INS_MLA, nullptr}, {ARM64_INS_MLS, nullptr}, {ARM64_INS_MOVI, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index bd4b650d8..02540a5dc 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -2631,6 +2631,156 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MUL_r_r_r_3) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MUL32_r_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x2}, + {ARM64_REG_X2, 0x50}, + }); + + emulate("mul w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xa0}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MUL32_r_r_r_1) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x2}, + {ARM64_REG_X2, 0xffffffffffffffff}, + }); + + emulate("mul w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000fffffffe}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_MADD +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MADD_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x4}, + {ARM64_REG_X2, 0x1}, + {ARM64_REG_X3, 0x100}, + }); + + emulate("madd x0, x1, x2, x3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x104}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MADD_r_r_r_1) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0xffffffffffffffff}, + {ARM64_REG_X3, 0x123}, + }); + + emulate("madd x0, x1, x2, x3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x124}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MADD_r_r_r_2) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + {ARM64_REG_X2, 0xffffffffffffffff}, + {ARM64_REG_X3, 0xffffffffffffffff}, + }); + + emulate("madd x0, x1, x2, x3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MADD_r_r_r_3) +{ + setRegisters({ + {ARM64_REG_X1, 0x2}, + {ARM64_REG_X2, 0xffffffffffffffff}, + {ARM64_REG_X3, 0x2}, + }); + + emulate("madd x0, x1, x2, x3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MADD32_r_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x2}, + {ARM64_REG_X2, 0x50}, + {ARM64_REG_X3, 0xffffffffffffffff}, + }); + + emulate("madd w0, w1, w2, w3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x9f}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MADD32_r_r_r_1) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x2}, + {ARM64_REG_X2, 0xffffffffffffffff}, + {ARM64_REG_X3, 0x3}, + }); + + emulate("madd w0, w1, w2, w3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_TBNZ // From 293615a49b1efe59a758c2b7ffd84ae3cbeb148f Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Mon, 11 Feb 2019 12:51:10 +0100 Subject: [PATCH 062/107] Arm64: MSUB instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 5 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 114 +++++++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 87066c972..587880487 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1373,6 +1373,11 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMul(cs_insn* i, cs_arm64* ai, auto* op3 = loadOp(ai->operands[3], irb); val = irb.CreateAdd(val, op3); } + else if (i->id == ARM64_INS_MSUB) + { + auto* op3 = loadOp(ai->operands[3], irb); + val = irb.CreateSub(op3, val); + } storeOp(ai->operands[0], val, irb); } diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index d31863e1b..4128a9b7b 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -437,7 +437,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_MOVZ, &Capstone2LlvmIrTranslatorArm64_impl::translateMov}, {ARM64_INS_MRS, nullptr}, {ARM64_INS_MSR, nullptr}, - {ARM64_INS_MSUB, nullptr}, + {ARM64_INS_MSUB, &Capstone2LlvmIrTranslatorArm64_impl::translateMul}, {ARM64_INS_MUL, &Capstone2LlvmIrTranslatorArm64_impl::translateMul}, {ARM64_INS_MVNI, nullptr}, {ARM64_INS_NEG, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 02540a5dc..e4e85871d 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -2781,6 +2781,120 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MADD32_r_r_r_1) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_MSUB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MSUB_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x4}, + {ARM64_REG_X2, 0x1}, + {ARM64_REG_X3, 0x3}, + }); + + emulate("msub x0, x1, x2, x3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MSUB_r_r_r_1) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0xffffffffffffffff}, + {ARM64_REG_X3, 0x123}, + }); + + emulate("msub x0, x1, x2, x3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x122}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MSUB_r_r_r_2) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + {ARM64_REG_X2, 0xffffffffffffffff}, + {ARM64_REG_X3, 0xffffffffffffffff}, + }); + + emulate("msub x0, x1, x2, x3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MSUB_r_r_r_3) +{ + setRegisters({ + {ARM64_REG_X1, 0x2}, + {ARM64_REG_X2, 0xffffffffffffffff}, + {ARM64_REG_X3, 0xfffffffffffffffe}, + }); + + emulate("msub x0, x1, x2, x3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MSUB32_r_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x2}, + {ARM64_REG_X2, 0x50}, + {ARM64_REG_X3, 0xffffffffffffffff}, + }); + + emulate("msub w0, w1, w2, w3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000ffffff5f}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MSUB32_r_r_r_1) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x2}, + {ARM64_REG_X2, 0xffffffffffffffff}, + {ARM64_REG_X3, 0x3}, + }); + + emulate("msub w0, w1, w2, w3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x5}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_TBNZ // From 945497533b07ed4d99216b4cd18d982b1f582041 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Mon, 11 Feb 2019 13:07:28 +0100 Subject: [PATCH 063/107] Arm64: MNEG instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 8 +- src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 108 +++++++++++++++++++++++ 3 files changed, 116 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 587880487..17702bcd2 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1357,7 +1357,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateCset(cs_insn* i, cs_arm64* ai } /** - * ARM64_INS_MUL, ARM64_INS_MADD + * ARM64_INS_MUL, ARM64_INS_MADD, ARM64_INS_MSUB, ARM64_INS_MNEG */ void Capstone2LlvmIrTranslatorArm64_impl::translateMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1378,6 +1378,12 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMul(cs_insn* i, cs_arm64* ai, auto* op3 = loadOp(ai->operands[3], irb); val = irb.CreateSub(op3, val); } + + if (i->id == ARM64_INS_MNEG) + { + llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); + val = irb.CreateSub(zero, val); + } storeOp(ai->operands[0], val, irb); } diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 4128a9b7b..46e1502f7 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -663,7 +663,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_ZIP2, nullptr}, // alias insn - {ARM64_INS_MNEG, nullptr}, + {ARM64_INS_MNEG, &Capstone2LlvmIrTranslatorArm64_impl::translateMul}, {ARM64_INS_UMNEGL, nullptr}, {ARM64_INS_SMNEGL, nullptr}, {ARM64_INS_NOP, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index e4e85871d..5ea255d4f 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -2781,6 +2781,114 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MADD32_r_r_r_1) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_MNEG +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MNEG_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x4}, + {ARM64_REG_X2, 0x1}, + }); + + emulate("mneg x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xfffffffffffffffc}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MNEG_r_r_r_1) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0xffffffffffffffff}, + }); + + emulate("mneg x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MNEG_r_r_r_2) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + {ARM64_REG_X2, 0xffffffffffffffff}, + }); + + emulate("mneg x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MNEG_r_r_r_3) +{ + setRegisters({ + {ARM64_REG_X1, 0x2}, + {ARM64_REG_X2, 0xffffffffffffffff}, + }); + + emulate("mneg x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x2}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MNEG32_r_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x2}, + {ARM64_REG_X2, 0x50}, + }); + + emulate("mneg w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000ffffff60}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MNEG32_r_r_r_1) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x2}, + {ARM64_REG_X2, 0x1}, + }); + + emulate("mneg w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000fffffffe}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MSUB // From 81f9c83f2c82b63f6d63d20bd29a1ba8cba7a346 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Mon, 11 Feb 2019 14:30:16 +0100 Subject: [PATCH 064/107] Arm64: NEG, NEGS instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 25 +++- src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 4 +- tests/capstone2llvmir/arm64_tests.cpp | 149 +++++++++++++++++++++++ 4 files changed, 176 insertions(+), 3 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 17702bcd2..1056f071a 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -820,6 +820,30 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateSub(cs_insn* i, cs_arm64* ai, } } +/** + * ARM64_INS_NEG + * ARM64_INS_NEGS for some reason capstone includes this instruction as alias. + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateNeg(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + auto* op2 = loadOpBinaryOp1(ai, irb); + llvm::Value* zero = llvm::ConstantInt::get(op2->getType(), 0); + + auto* val = irb.CreateSub(zero, op2); + storeOp(ai->operands[0], val, irb); + + if (ai->update_flags) + { + llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); + storeRegister(ARM64_REG_CPSR_C, generateValueNegate(irb, generateBorrowSub(zero, op2, irb)), irb); + storeRegister(ARM64_REG_CPSR_V, generateOverflowSub(val, zero, op2, irb), irb); + storeRegister(ARM64_REG_CPSR_N, irb.CreateICmpSLT(val, zero), irb); + storeRegister(ARM64_REG_CPSR_Z, irb.CreateICmpEQ(val, zero), irb); + } +} + /** * ARM64_INS_SBC */ @@ -1365,7 +1389,6 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMul(cs_insn* i, cs_arm64* ai, auto* op1 = loadOp(ai->operands[1], irb); auto* op2 = loadOp(ai->operands[2], irb); - op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); auto *val = irb.CreateMul(op1, op2); if (i->id == ARM64_INS_MADD) diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index d761ced05..f73f2d2c9 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -174,6 +174,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateAnd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateShifts(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateNeg(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateSbc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 46e1502f7..f6d7ef8ff 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -440,7 +440,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_MSUB, &Capstone2LlvmIrTranslatorArm64_impl::translateMul}, {ARM64_INS_MUL, &Capstone2LlvmIrTranslatorArm64_impl::translateMul}, {ARM64_INS_MVNI, nullptr}, - {ARM64_INS_NEG, nullptr}, + {ARM64_INS_NEG, &Capstone2LlvmIrTranslatorArm64_impl::translateNeg}, {ARM64_INS_NOT, nullptr}, {ARM64_INS_ORN, nullptr}, {ARM64_INS_ORR, nullptr}, @@ -699,7 +699,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_AT, nullptr}, {ARM64_INS_TLBI, nullptr}, - {ARM64_INS_NEGS, nullptr}, + {ARM64_INS_NEGS, &Capstone2LlvmIrTranslatorArm64_impl::translateNeg}, {ARM64_INS_NGCS, nullptr}, {ARM64_INS_ENDING, nullptr} diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 5ea255d4f..ed117ff7c 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -1164,6 +1164,155 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SUB_s_overflow_r_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_NEG +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NEG_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + }); + + emulate("neg x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffedcc}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NEG_r_r_1) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + }); + + emulate("neg x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NEG_r_r_2) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + }); + + emulate("neg x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NEG32_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + }); + + emulate("neg w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000ffffedcc}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NEGS_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + }); + + emulate("negs x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NEGS_r_r_1) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + }); + + emulate("negs x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NEGS_r_r_2) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + }); + + emulate("negs x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffedcc}, + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NEGS32_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_X1, 0x1}, + }); + + emulate("negs w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000ffffffff}, + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_SBC // From 62a7b9b1f701ae9fbcb560baaa5bccc97d5d6161 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Mon, 11 Feb 2019 16:50:20 +0100 Subject: [PATCH 065/107] Arm64: NGC, NGCS initial implementation + tests - Check the carry flags + add tests --- src/capstone2llvmir/arm64/arm64.cpp | 27 +++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 4 +- tests/capstone2llvmir/arm64_tests.cpp | 142 +++++++++++++++++++++++ 4 files changed, 172 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 1056f071a..876f1bc6d 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -849,6 +849,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateNeg(cs_insn* i, cs_arm64* ai, */ void Capstone2LlvmIrTranslatorArm64_impl::translateSbc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { + // TODO: Reimplement as add EXPECT_IS_TERNARY(i, ai, irb); std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); @@ -870,6 +871,32 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateSbc(cs_insn* i, cs_arm64* ai, } } +/** + * ARM64_INS_NGC, ARM64_INS_NGCS + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateNgc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + auto* op2 = loadOpBinaryOp1(ai, irb); + llvm::Value* zero = llvm::ConstantInt::get(op2->getType(), 0); + auto* carry = loadRegister(ARM64_REG_CPSR_C, irb); + + auto* val = irb.CreateSub(zero, op2); + val = irb.CreateSub(val, irb.CreateZExtOrTrunc(carry, val->getType())); + + storeOp(ai->operands[0], val, irb); + + if (ai->update_flags) + { + llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); + storeRegister(ARM64_REG_CPSR_C, generateValueNegate(irb, generateBorrowSubC(val, zero, op2, irb, carry)), irb); + storeRegister(ARM64_REG_CPSR_V, generateOverflowSubC(val, zero, op2, irb, carry), irb); + storeRegister(ARM64_REG_CPSR_N, irb.CreateICmpSLT(val, zero), irb); + storeRegister(ARM64_REG_CPSR_Z, irb.CreateICmpEQ(val, zero), irb); + } +} + /** * ARM64_INS_MOV, ARM64_INS_MVN, ARM64_INS_MOVZ */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index f73f2d2c9..a08d26fd9 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -175,6 +175,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateShifts(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateNeg(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateNgc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateSbc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index f6d7ef8ff..9ed9477ec 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -672,7 +672,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_WFI, nullptr}, {ARM64_INS_SEV, nullptr}, {ARM64_INS_SEVL, nullptr}, - {ARM64_INS_NGC, nullptr}, + {ARM64_INS_NGC, &Capstone2LlvmIrTranslatorArm64_impl::translateNgc}, {ARM64_INS_SBFIZ, nullptr}, {ARM64_INS_UBFIZ, nullptr}, {ARM64_INS_SBFX, nullptr}, @@ -700,7 +700,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_TLBI, nullptr}, {ARM64_INS_NEGS, &Capstone2LlvmIrTranslatorArm64_impl::translateNeg}, - {ARM64_INS_NGCS, nullptr}, + {ARM64_INS_NGCS, &Capstone2LlvmIrTranslatorArm64_impl::translateNgc}, {ARM64_INS_ENDING, nullptr} }; diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index ed117ff7c..40d12812d 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -1313,6 +1313,148 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NEGS32_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_NGC +// + +/* +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGC_r_r_true) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_CPSR_C, true}, + }); + + emulate("ngc x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffedcb}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGC_r_r_false) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_CPSR_C, false}, + }); + + emulate("ngc x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGC32_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_CPSR_C, true}, + }); + + emulate("ngc w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000ffffedcb}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGCS_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + {ARM64_REG_CPSR_C, false}, + }); + + emulate("ngcs x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGCS_r_r_1) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_CPSR_C, true}, + }); + + emulate("ngcs x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGCS_r_r_2) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_CPSR_C, true}, + }); + + emulate("ngcs x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffedcb}, + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGCS32_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_X1, 0x2}, + {ARM64_REG_CPSR_C, true}, + }); + + emulate("ngcs w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000fffffffd}, + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} +*/ + // // ARM64_INS_SBC // From f8b029f776b53fbaec7a57a3ab135067d8ae5703 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 14 Feb 2019 15:11:05 +0100 Subject: [PATCH 066/107] Arm64: SDIV, UDIV instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 35 ++++ src/capstone2llvmir/arm64/arm64_impl.h | 3 +- src/capstone2llvmir/arm64/arm64_init.cpp | 4 +- tests/capstone2llvmir/arm64_tests.cpp | 236 +++++++++++++++++++++++ 4 files changed, 275 insertions(+), 3 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 876f1bc6d..fcc8bc8ba 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1407,6 +1407,41 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateCset(cs_insn* i, cs_arm64* ai storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_UDIV, ARM64_INS_SDIV + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateDiv(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); + + // Zero division yelds zero as result in this case we + // don't want undefined behaviour so we + // check for zero division and manualy set the result, for now. + llvm::Value* zero = llvm::ConstantInt::get(op1->getType(), 0); + auto* cond = irb.CreateICmpEQ(op2, zero); + auto irbP = generateIfThenElse(cond, irb); + llvm::IRBuilder<>& bodyIf(irbP.first), bodyElse(irbP.second); + + //IF - store zero + storeOp(ai->operands[0], zero, bodyIf); + + //ELSE - store result of division + llvm::Value *val = nullptr; + if (i->id == ARM64_INS_UDIV) + { + val = bodyElse.CreateUDiv(op1, op2); + } + else if (i->id == ARM64_INS_SDIV) + { + val = bodyElse.CreateSDiv(op1, op2); + } + + storeOp(ai->operands[0], val, bodyElse); + //ENDIF +} + /** * ARM64_INS_MUL, ARM64_INS_MADD, ARM64_INS_MSUB, ARM64_INS_MNEG */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index a08d26fd9..f17bcc1c0 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -35,7 +35,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : // //============================================================================== -// x86 specialization methods - from Capstone2LlvmIrTranslatorX86 +// Arm64 specialization methods - from Capstone2LlvmIrTranslatorX86 //============================================================================== // public: @@ -189,6 +189,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateCbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateCsel(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateCset(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateDiv(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateTbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 9ed9477ec..a4290d8b2 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -479,7 +479,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_SBC, &Capstone2LlvmIrTranslatorArm64_impl::translateSbc}, {ARM64_INS_SBFM, nullptr}, {ARM64_INS_SCVTF, nullptr}, - {ARM64_INS_SDIV, nullptr}, + {ARM64_INS_SDIV, &Capstone2LlvmIrTranslatorArm64_impl::translateDiv}, {ARM64_INS_SHA1C, nullptr}, {ARM64_INS_SHA1H, nullptr}, {ARM64_INS_SHA1M, nullptr}, @@ -610,7 +610,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_UADDW, nullptr}, {ARM64_INS_UBFM, nullptr}, {ARM64_INS_UCVTF, nullptr}, - {ARM64_INS_UDIV, nullptr}, + {ARM64_INS_UDIV, &Capstone2LlvmIrTranslatorArm64_impl::translateDiv}, {ARM64_INS_UHADD, nullptr}, {ARM64_INS_UHSUB, nullptr}, {ARM64_INS_UMADDL, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 40d12812d..06b034be8 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -3520,6 +3520,242 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ROR32_r_r_i) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_SDIV +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SDIV_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x1230}, + {ARM64_REG_X2, 0x1230}, + }); + + emulate("sdiv x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x1},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SDIV_r_r_r_1) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0xffffffffffffffff}, + }); + + emulate("sdiv x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffedcc}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SDIV_r_r_r_2) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffedcc}, + {ARM64_REG_X2, 0xffffffffffffedcc}, + }); + + emulate("sdiv x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 1}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SDIV_r_r_r_3) +{ + setRegisters({ + {ARM64_REG_X1, 0x5}, + {ARM64_REG_X2, 0x2}, + }); + + emulate("sdiv x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x2}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SDIV_r_r_r_4) +{ + setRegisters({ + {ARM64_REG_X1, 0xfffffffffffffffc}, + {ARM64_REG_X2, 0xfffffffffffffffe}, + }); + + emulate("sdiv x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x2}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SDIV32_r_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0xa}, + {ARM64_REG_X2, 0x00000000fffffffe}, + }); + + emulate("sdiv w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000fffffffb}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SDIV_r_r_r_zero_div) +{ + setRegisters({ + {ARM64_REG_X1, 0x1230}, + {ARM64_REG_X2, 0x0}, + }); + + emulate("sdiv x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x0},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UDIV_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x1230}, + {ARM64_REG_X2, 0x1230}, + }); + + emulate("udiv x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x1},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UDIV_r_r_r_1) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0xffffffffffffffff}, + }); + + emulate("udiv x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UDIV_r_r_r_2) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffedcc}, + {ARM64_REG_X2, 0xffffffffffffedcc}, + }); + + emulate("udiv x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 1}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UDIV_r_r_r_3) +{ + setRegisters({ + {ARM64_REG_X1, 0x5}, + {ARM64_REG_X2, 0x2}, + }); + + emulate("udiv x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x2}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UDIV_r_r_r_4) +{ + setRegisters({ + {ARM64_REG_X1, 0xfffffffffffffffe}, + {ARM64_REG_X2, 0xfffffffffffffffc}, + }); + + emulate("udiv x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UDIV32_r_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x00000000fffffffe}, + {ARM64_REG_X2, 0xa}, + }); + + emulate("udiv w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000019999999}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UDIV_r_r_r_zero_div) +{ + setRegisters({ + {ARM64_REG_X1, 0x1230}, + {ARM64_REG_X2, 0x0}, + }); + + emulate("udiv x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x0},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + } // namespace tests } // namespace capstone2llvmir } // namespace retdec From d145dc6426522b4e5909d55517e54ffb9286285a Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 15 Feb 2019 12:31:24 +0100 Subject: [PATCH 067/107] Arm64: Fix correct semantics for SBC and NEG instructions --- src/capstone2llvmir/arm64/arm64.cpp | 31 +++++++++++++++++---------- tests/capstone2llvmir/arm64_tests.cpp | 30 ++++++++++++-------------- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index fcc8bc8ba..f0f43b2c7 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -849,23 +849,27 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateNeg(cs_insn* i, cs_arm64* ai, */ void Capstone2LlvmIrTranslatorArm64_impl::translateSbc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { - // TODO: Reimplement as add EXPECT_IS_TERNARY(i, ai, irb); std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); - op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); + auto* carry = loadRegister(ARM64_REG_CPSR_C, irb); - auto* val = irb.CreateSub(op1, op2); - val = irb.CreateSub(val, irb.CreateZExtOrTrunc(carry, val->getType())); + // NOT(OP2) + op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); + op2 = generateValueNegate(irb, op2); + + // OP1 + NOT(OP2) + CARRY + auto* val = irb.CreateAdd(op1, op2); + val = irb.CreateAdd(val, irb.CreateZExtOrTrunc(carry, val->getType())); storeOp(ai->operands[0], val, irb); if (ai->update_flags) { llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); - storeRegister(ARM64_REG_CPSR_C, generateValueNegate(irb, generateBorrowSubC(val, op1, op2, irb, carry)), irb); - storeRegister(ARM64_REG_CPSR_V, generateOverflowSubC(val, op1, op2, irb, carry), irb); + storeRegister(ARM64_REG_CPSR_C, generateCarryAddC(op1, op2, irb, carry), irb); + storeRegister(ARM64_REG_CPSR_V, generateOverflowAddC(val, op1, op2, irb, carry), irb); storeRegister(ARM64_REG_CPSR_N, irb.CreateICmpSLT(val, zero), irb); storeRegister(ARM64_REG_CPSR_Z, irb.CreateICmpEQ(val, zero), irb); } @@ -879,19 +883,24 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateNgc(cs_insn* i, cs_arm64* ai, EXPECT_IS_BINARY(i, ai, irb); auto* op2 = loadOpBinaryOp1(ai, irb); - llvm::Value* zero = llvm::ConstantInt::get(op2->getType(), 0); + llvm::Value* op1 = llvm::ConstantInt::get(op2->getType(), 0); auto* carry = loadRegister(ARM64_REG_CPSR_C, irb); - auto* val = irb.CreateSub(zero, op2); - val = irb.CreateSub(val, irb.CreateZExtOrTrunc(carry, val->getType())); + // NOT(OP2) + op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); + op2 = generateValueNegate(irb, op2); + + // OP1 + NOT(OP2) + CARRY + auto* val = irb.CreateAdd(op1, op2); + val = irb.CreateAdd(val, irb.CreateZExtOrTrunc(carry, val->getType())); storeOp(ai->operands[0], val, irb); if (ai->update_flags) { llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); - storeRegister(ARM64_REG_CPSR_C, generateValueNegate(irb, generateBorrowSubC(val, zero, op2, irb, carry)), irb); - storeRegister(ARM64_REG_CPSR_V, generateOverflowSubC(val, zero, op2, irb, carry), irb); + storeRegister(ARM64_REG_CPSR_C, generateCarryAddC(op1, op2, irb, carry), irb); + storeRegister(ARM64_REG_CPSR_V, generateOverflowAddC(val, op1, op2, irb, carry), irb); storeRegister(ARM64_REG_CPSR_N, irb.CreateICmpSLT(val, zero), irb); storeRegister(ARM64_REG_CPSR_Z, irb.CreateICmpEQ(val, zero), irb); } diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 06b034be8..d01d747f9 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -1317,7 +1317,6 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NEGS32_r_r) // ARM64_INS_NGC // -/* TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGC_r_r_true) { setRegisters({ @@ -1329,7 +1328,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGC_r_r_true) EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_CPSR_C}); EXPECT_JUST_REGISTERS_STORED({ - {ARM64_REG_X0, 0xffffffffffffedcb}, + {ARM64_REG_X0, 0xffffffffffffedcc}, }); EXPECT_NO_MEMORY_LOADED_STORED(); EXPECT_NO_VALUE_CALLED(); @@ -1346,7 +1345,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGC_r_r_false) EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_CPSR_C}); EXPECT_JUST_REGISTERS_STORED({ - {ARM64_REG_X0, 0x1}, + {ARM64_REG_X0, 0x0}, }); EXPECT_NO_MEMORY_LOADED_STORED(); EXPECT_NO_VALUE_CALLED(); @@ -1363,7 +1362,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGC32_r_r) EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_CPSR_C}); EXPECT_JUST_REGISTERS_STORED({ - {ARM64_REG_X0, 0x00000000ffffedcb}, + {ARM64_REG_X0, 0x00000000ffffedcc}, }); EXPECT_NO_MEMORY_LOADED_STORED(); EXPECT_NO_VALUE_CALLED(); @@ -1380,11 +1379,11 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGCS_r_r) EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_CPSR_C}); EXPECT_JUST_REGISTERS_STORED({ - {ARM64_REG_X0, 0x0}, - {ARM64_REG_CPSR_N, false}, - {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, {ARM64_REG_CPSR_V, false}, - {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_C, false}, }); EXPECT_NO_MEMORY_LOADED_STORED(); EXPECT_NO_VALUE_CALLED(); @@ -1401,9 +1400,9 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGCS_r_r_1) EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_CPSR_C}); EXPECT_JUST_REGISTERS_STORED({ - {ARM64_REG_X0, 0x0}, + {ARM64_REG_X0, 0x1}, {ARM64_REG_CPSR_N, false}, - {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_Z, false}, {ARM64_REG_CPSR_V, false}, {ARM64_REG_CPSR_C, false}, }); @@ -1422,7 +1421,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGCS_r_r_2) EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_CPSR_C}); EXPECT_JUST_REGISTERS_STORED({ - {ARM64_REG_X0, 0xffffffffffffedcb}, + {ARM64_REG_X0, 0xffffffffffffedcc}, {ARM64_REG_CPSR_N, true}, {ARM64_REG_CPSR_Z, false}, {ARM64_REG_CPSR_V, false}, @@ -1444,7 +1443,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGCS32_r_r) EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_CPSR_C}); EXPECT_JUST_REGISTERS_STORED({ - {ARM64_REG_X0, 0x00000000fffffffd}, + {ARM64_REG_X0, 0x00000000fffffffe}, {ARM64_REG_CPSR_N, true}, {ARM64_REG_CPSR_Z, false}, {ARM64_REG_CPSR_V, false}, @@ -1453,7 +1452,6 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NGCS32_r_r) EXPECT_NO_MEMORY_LOADED_STORED(); EXPECT_NO_VALUE_CALLED(); } -*/ // // ARM64_INS_SBC @@ -1471,7 +1469,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SBC_r_r_r_false) EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); EXPECT_JUST_REGISTERS_STORED({ - {ARM64_REG_X0, 0x1230}, + {ARM64_REG_X0, 0x122f}, }); EXPECT_NO_MEMORY_LOADED_STORED(); EXPECT_NO_VALUE_CALLED(); @@ -1489,7 +1487,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SBC_r_r_r_true) EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); EXPECT_JUST_REGISTERS_STORED({ - {ARM64_REG_X0, 0x1230}, + {ARM64_REG_X0, 0x1231}, }); EXPECT_NO_MEMORY_LOADED_STORED(); EXPECT_NO_VALUE_CALLED(); @@ -1507,7 +1505,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SBC_s_r_r_r_false) EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_C}); EXPECT_JUST_REGISTERS_STORED({ - {ARM64_REG_X0, 0x1230}, + {ARM64_REG_X0, 0x122f}, {ARM64_REG_CPSR_N, false}, {ARM64_REG_CPSR_Z, false}, {ARM64_REG_CPSR_C, true}, From 2f45d2d476c6102947e51e19b0a8db585bcc0a83 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 15 Feb 2019 13:28:09 +0100 Subject: [PATCH 068/107] Arm64: SMADDL, UMADDL instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 42 ++++++++++++++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 4 +- tests/capstone2llvmir/arm64_tests.cpp | 62 ++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index f0f43b2c7..128839cab 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1451,6 +1451,48 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateDiv(cs_insn* i, cs_arm64* ai, //ENDIF } +/** + * ARM64_INS_UMADDL, ARM64_INS_SMADDL + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateMaddl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_EXPR(i, ai, irb, (3 <= ai->op_count && ai->op_count <= 4)); + + bool sext = true; + switch(i->id) { + case ARM64_INS_UMADDL: + sext = false; + break; + case ARM64_INS_SMADDL: + sext = true; + break; + default: + throw GenericError("Maddl: Unhandled instruction ID"); + } + + auto* res_type = getDefaultType(); + + auto* op1 = loadOp(ai->operands[1], irb); + auto* op2 = loadOp(ai->operands[2], irb); + if (sext) + { + op1 = irb.CreateSExtOrTrunc(op1, res_type); + op2 = irb.CreateSExtOrTrunc(op2, res_type); + } + else + { + op1 = irb.CreateZExtOrTrunc(op1, res_type); + op2 = irb.CreateZExtOrTrunc(op2, res_type); + } + + auto *val = irb.CreateMul(op1, op2); + + auto* op3 = loadOp(ai->operands[3], irb); + val = irb.CreateAdd(val, op3); + + storeOp(ai->operands[0], val, irb); +} + /** * ARM64_INS_MUL, ARM64_INS_MADD, ARM64_INS_MSUB, ARM64_INS_MNEG */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index f17bcc1c0..ccd77b81e 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -191,6 +191,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateCset(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateDiv(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateMaddl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateTbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index a4290d8b2..12a273356 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -498,7 +498,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_SHRN, nullptr}, {ARM64_INS_SHSUB, nullptr}, {ARM64_INS_SLI, nullptr}, - {ARM64_INS_SMADDL, nullptr}, + {ARM64_INS_SMADDL, &Capstone2LlvmIrTranslatorArm64_impl::translateMaddl}, {ARM64_INS_SMAXP, nullptr}, {ARM64_INS_SMAXV, nullptr}, {ARM64_INS_SMAX, nullptr}, @@ -613,7 +613,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_UDIV, &Capstone2LlvmIrTranslatorArm64_impl::translateDiv}, {ARM64_INS_UHADD, nullptr}, {ARM64_INS_UHSUB, nullptr}, - {ARM64_INS_UMADDL, nullptr}, + {ARM64_INS_UMADDL, &Capstone2LlvmIrTranslatorArm64_impl::translateMaddl}, {ARM64_INS_UMAXP, nullptr}, {ARM64_INS_UMAXV, nullptr}, {ARM64_INS_UMAX, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index d01d747f9..8da04c2db 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -3070,6 +3070,68 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MADD32_r_r_r_1) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_UMADDL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UMADDL_r_w_w_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x00000000ffffffff}, + {ARM64_REG_X2, 0x2}, + {ARM64_REG_X3, 0x100}, + }); + + emulate("umaddl x0, w1, w2, x3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x2000000fe}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UMADDL_r_w_w_r_1) +{ + setRegisters({ + {ARM64_REG_X1, 0x00000000ffffffff}, + {ARM64_REG_X2, 0x2}, + {ARM64_REG_X3, 0x100000000}, + }); + + emulate("umaddl x0, w1, w2, x3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x2fffffffe}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_SMADDL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SMADDL_r_w_w_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x00000000ffffffff}, + {ARM64_REG_X2, 0x2}, + {ARM64_REG_X3, 0xfffffffffffffffb}, + }); + + emulate("smaddl x0, w1, w2, x3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xfffffffffffffff9}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MNEG // From 3a666ed6bc3951899766aca3fbe8b4e75eabe317 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 15 Feb 2019 15:12:02 +0100 Subject: [PATCH 069/107] Arm64: UMSUBL, SMSUBL instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 23 ++++++++- src/capstone2llvmir/arm64/arm64_impl.h | 2 +- src/capstone2llvmir/arm64/arm64_init.cpp | 8 +-- tests/capstone2llvmir/arm64_tests.cpp | 62 ++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 7 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 128839cab..26c75c77c 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1453,18 +1453,30 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateDiv(cs_insn* i, cs_arm64* ai, /** * ARM64_INS_UMADDL, ARM64_INS_SMADDL + * ARM64_INS_UMSUBL, ARM64_INS_SMSUBL */ -void Capstone2LlvmIrTranslatorArm64_impl::translateMaddl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +void Capstone2LlvmIrTranslatorArm64_impl::translateMull(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { EXPECT_IS_EXPR(i, ai, irb, (3 <= ai->op_count && ai->op_count <= 4)); bool sext = true; + bool add_operation = true; switch(i->id) { case ARM64_INS_UMADDL: sext = false; + add_operation = true; break; case ARM64_INS_SMADDL: sext = true; + add_operation = true; + break; + case ARM64_INS_UMSUBL: + sext = false; + add_operation = false; + break; + case ARM64_INS_SMSUBL: + sext = true; + add_operation = false; break; default: throw GenericError("Maddl: Unhandled instruction ID"); @@ -1488,7 +1500,14 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMaddl(cs_insn* i, cs_arm64* a auto *val = irb.CreateMul(op1, op2); auto* op3 = loadOp(ai->operands[3], irb); - val = irb.CreateAdd(val, op3); + if (add_operation) + { + val = irb.CreateAdd(op3, val); + } + else + { + val = irb.CreateSub(op3, val); + } storeOp(ai->operands[0], val, irb); } diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index ccd77b81e..8697ff18f 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -191,7 +191,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateCset(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateDiv(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); - void translateMaddl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateMull(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateTbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 12a273356..b2a44e846 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -498,7 +498,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_SHRN, nullptr}, {ARM64_INS_SHSUB, nullptr}, {ARM64_INS_SLI, nullptr}, - {ARM64_INS_SMADDL, &Capstone2LlvmIrTranslatorArm64_impl::translateMaddl}, + {ARM64_INS_SMADDL, &Capstone2LlvmIrTranslatorArm64_impl::translateMull}, {ARM64_INS_SMAXP, nullptr}, {ARM64_INS_SMAXV, nullptr}, {ARM64_INS_SMAX, nullptr}, @@ -511,7 +511,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_SMLSL2, nullptr}, {ARM64_INS_SMLSL, nullptr}, {ARM64_INS_SMOV, nullptr}, - {ARM64_INS_SMSUBL, nullptr}, + {ARM64_INS_SMSUBL, &Capstone2LlvmIrTranslatorArm64_impl::translateMull}, {ARM64_INS_SMULH, nullptr}, {ARM64_INS_SMULL2, nullptr}, {ARM64_INS_SMULL, nullptr}, @@ -613,7 +613,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_UDIV, &Capstone2LlvmIrTranslatorArm64_impl::translateDiv}, {ARM64_INS_UHADD, nullptr}, {ARM64_INS_UHSUB, nullptr}, - {ARM64_INS_UMADDL, &Capstone2LlvmIrTranslatorArm64_impl::translateMaddl}, + {ARM64_INS_UMADDL, &Capstone2LlvmIrTranslatorArm64_impl::translateMull}, {ARM64_INS_UMAXP, nullptr}, {ARM64_INS_UMAXV, nullptr}, {ARM64_INS_UMAX, nullptr}, @@ -625,7 +625,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_UMLSL2, nullptr}, {ARM64_INS_UMLSL, nullptr}, {ARM64_INS_UMOV, nullptr}, - {ARM64_INS_UMSUBL, nullptr}, + {ARM64_INS_UMSUBL, &Capstone2LlvmIrTranslatorArm64_impl::translateMull}, {ARM64_INS_UMULH, nullptr}, {ARM64_INS_UMULL2, nullptr}, {ARM64_INS_UMULL, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 8da04c2db..2675bf11a 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -3132,6 +3132,68 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SMADDL_r_w_w_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_UMSUBL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UMSUBL_r_w_w_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x00000000ffffffff}, + {ARM64_REG_X2, 0x2}, + {ARM64_REG_X3, 0x100}, + }); + + emulate("umsubl x0, w1, w2, x3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xfffffffe00000102}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UMSUBL_r_w_w_r_1) +{ + setRegisters({ + {ARM64_REG_X1, 0x00000000ffffffff}, + {ARM64_REG_X2, 0x2}, + {ARM64_REG_X3, 0x11fffffffe}, + }); + + emulate("umsubl x0, w1, w2, x3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1000000000}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_SMSUBL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SMSUBL_r_w_w_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x00000000ffffffff}, + {ARM64_REG_X2, 0x2}, + {ARM64_REG_X3, 0xfffffffffffffffb}, + }); + + emulate("smsubl x0, w1, w2, x3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_X3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xfffffffffffffffd}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MNEG // From 3684a9b94a4b757bccb4a0cfbc7d663341b961df Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 15 Feb 2019 23:09:19 +0100 Subject: [PATCH 070/107] Arm64: SMNEG, UMNEG instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 23 ++++++++++++- src/capstone2llvmir/arm64/arm64_init.cpp | 4 +-- tests/capstone2llvmir/arm64_tests.cpp | 43 ++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 26c75c77c..10784f03e 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1454,6 +1454,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateDiv(cs_insn* i, cs_arm64* ai, /** * ARM64_INS_UMADDL, ARM64_INS_SMADDL * ARM64_INS_UMSUBL, ARM64_INS_SMSUBL + * ARM64_INS_UMNEGL, ARM64_INS_SMNEGL */ void Capstone2LlvmIrTranslatorArm64_impl::translateMull(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1461,6 +1462,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMull(cs_insn* i, cs_arm64* ai bool sext = true; bool add_operation = true; + bool op3_zero = false; switch(i->id) { case ARM64_INS_UMADDL: sext = false; @@ -1478,6 +1480,16 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMull(cs_insn* i, cs_arm64* ai sext = true; add_operation = false; break; + case ARM64_INS_UMNEGL: + sext = false; + add_operation = false; + op3_zero = true; + break; + case ARM64_INS_SMNEGL: + sext = true; + add_operation = false; + op3_zero = true; + break; default: throw GenericError("Maddl: Unhandled instruction ID"); } @@ -1499,7 +1511,16 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMull(cs_insn* i, cs_arm64* ai auto *val = irb.CreateMul(op1, op2); - auto* op3 = loadOp(ai->operands[3], irb); + llvm::Value* op3; + if (op3_zero) + { + op3 = llvm::ConstantInt::get(res_type, 0); + } + else + { + op3 = loadOp(ai->operands[3], irb); + } + if (add_operation) { val = irb.CreateAdd(op3, val); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index b2a44e846..0e08bd42d 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -664,8 +664,8 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = // alias insn {ARM64_INS_MNEG, &Capstone2LlvmIrTranslatorArm64_impl::translateMul}, - {ARM64_INS_UMNEGL, nullptr}, - {ARM64_INS_SMNEGL, nullptr}, + {ARM64_INS_UMNEGL, &Capstone2LlvmIrTranslatorArm64_impl::translateMull}, + {ARM64_INS_SMNEGL, &Capstone2LlvmIrTranslatorArm64_impl::translateMull}, {ARM64_INS_NOP, nullptr}, {ARM64_INS_YIELD, nullptr}, {ARM64_INS_WFE, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 2675bf11a..48f85d586 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -3194,6 +3194,49 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SMSUBL_r_w_w_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_UMNEGL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UMNEGL_r_w_w_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x00000000ffffffff}, + {ARM64_REG_X2, 0x2}, + }); + + emulate("umnegl x0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xfffffffe00000002}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_SMNEGL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SMNEGL_r_w_w_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x00000000ffffffff}, + {ARM64_REG_X2, 0x2}, + }); + + emulate("smnegl x0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x2}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + + // // ARM64_INS_MNEG // From 7a87054634543620296d9cae46c2d5097157b56d Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 16 Feb 2019 15:20:23 +0100 Subject: [PATCH 071/107] Arm64: UMULL, SMULL, UMULH, SMULH instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 87 ++++++++++++++- src/capstone2llvmir/arm64/arm64_impl.h | 2 + src/capstone2llvmir/arm64/arm64_init.cpp | 20 ++-- tests/capstone2llvmir/arm64_tests.cpp | 134 +++++++++++++++++++++++ 4 files changed, 232 insertions(+), 11 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 10784f03e..197569a9a 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1451,12 +1451,97 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateDiv(cs_insn* i, cs_arm64* ai, //ENDIF } +/** + * ARM64_INS_UMULH, ARM64_INS_SMULH + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateMulh(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + bool sext = true; + if (i->id == ARM64_INS_UMULH) + { + sext = false; + } + else if (i->id == ARM64_INS_SMULH) + { + sext = true; + } + else + { + throw GenericError("Mulh: Unhandled instruction ID"); + } + + auto* res_type = llvm::IntegerType::getInt128Ty(_module->getContext()); + auto* op1 = loadOp(ai->operands[1], irb); + auto* op2 = loadOp(ai->operands[2], irb); + if (sext) + { + op1 = irb.CreateSExtOrTrunc(op1, res_type); + op2 = irb.CreateSExtOrTrunc(op2, res_type); + } + else + { + op1 = irb.CreateZExtOrTrunc(op1, res_type); + op2 = irb.CreateZExtOrTrunc(op2, res_type); + } + + auto *val = irb.CreateMul(op1, op2); + + // Get the high bits of the result + val = irb.CreateAShr(val, llvm::ConstantInt::get(val->getType(), 64)); + + val = irb.CreateSExtOrTrunc(val, getDefaultType()); + + storeOp(ai->operands[0], val, irb); +} + +/** + * ARM64_INS_UMULL, ARM64_INS_SMULL + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateMull(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + bool sext = true; + if (i->id == ARM64_INS_UMULL) + { + sext = false; + } + else if (i->id == ARM64_INS_SMULL) + { + sext = true; + } + else + { + throw GenericError("Mull: Unhandled instruction ID"); + } + + auto* res_type = getDefaultType(); + auto* op1 = loadOp(ai->operands[1], irb); + auto* op2 = loadOp(ai->operands[2], irb); + if (sext) + { + op1 = irb.CreateSExtOrTrunc(op1, res_type); + op2 = irb.CreateSExtOrTrunc(op2, res_type); + } + else + { + op1 = irb.CreateZExtOrTrunc(op1, res_type); + op2 = irb.CreateZExtOrTrunc(op2, res_type); + } + + auto *val = irb.CreateMul(op1, op2); + + storeOp(ai->operands[0], val, irb); +} + /** * ARM64_INS_UMADDL, ARM64_INS_SMADDL * ARM64_INS_UMSUBL, ARM64_INS_SMSUBL * ARM64_INS_UMNEGL, ARM64_INS_SMNEGL */ -void Capstone2LlvmIrTranslatorArm64_impl::translateMull(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +void Capstone2LlvmIrTranslatorArm64_impl::translateMulOpl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { EXPECT_IS_EXPR(i, ai, irb, (3 <= ai->op_count && ai->op_count <= 4)); diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 8697ff18f..c85fad25b 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -191,7 +191,9 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateCset(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateDiv(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateMulOpl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMull(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateMulh(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateTbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 0e08bd42d..ee37bffec 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -498,7 +498,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_SHRN, nullptr}, {ARM64_INS_SHSUB, nullptr}, {ARM64_INS_SLI, nullptr}, - {ARM64_INS_SMADDL, &Capstone2LlvmIrTranslatorArm64_impl::translateMull}, + {ARM64_INS_SMADDL, &Capstone2LlvmIrTranslatorArm64_impl::translateMulOpl}, {ARM64_INS_SMAXP, nullptr}, {ARM64_INS_SMAXV, nullptr}, {ARM64_INS_SMAX, nullptr}, @@ -511,10 +511,10 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_SMLSL2, nullptr}, {ARM64_INS_SMLSL, nullptr}, {ARM64_INS_SMOV, nullptr}, - {ARM64_INS_SMSUBL, &Capstone2LlvmIrTranslatorArm64_impl::translateMull}, - {ARM64_INS_SMULH, nullptr}, + {ARM64_INS_SMSUBL, &Capstone2LlvmIrTranslatorArm64_impl::translateMulOpl}, + {ARM64_INS_SMULH, &Capstone2LlvmIrTranslatorArm64_impl::translateMulh}, {ARM64_INS_SMULL2, nullptr}, - {ARM64_INS_SMULL, nullptr}, + {ARM64_INS_SMULL, &Capstone2LlvmIrTranslatorArm64_impl::translateMull}, {ARM64_INS_SQABS, nullptr}, {ARM64_INS_SQADD, nullptr}, {ARM64_INS_SQDMLAL, nullptr}, @@ -613,7 +613,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_UDIV, &Capstone2LlvmIrTranslatorArm64_impl::translateDiv}, {ARM64_INS_UHADD, nullptr}, {ARM64_INS_UHSUB, nullptr}, - {ARM64_INS_UMADDL, &Capstone2LlvmIrTranslatorArm64_impl::translateMull}, + {ARM64_INS_UMADDL, &Capstone2LlvmIrTranslatorArm64_impl::translateMulOpl}, {ARM64_INS_UMAXP, nullptr}, {ARM64_INS_UMAXV, nullptr}, {ARM64_INS_UMAX, nullptr}, @@ -625,10 +625,10 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_UMLSL2, nullptr}, {ARM64_INS_UMLSL, nullptr}, {ARM64_INS_UMOV, nullptr}, - {ARM64_INS_UMSUBL, &Capstone2LlvmIrTranslatorArm64_impl::translateMull}, - {ARM64_INS_UMULH, nullptr}, + {ARM64_INS_UMSUBL, &Capstone2LlvmIrTranslatorArm64_impl::translateMulOpl}, + {ARM64_INS_UMULH, &Capstone2LlvmIrTranslatorArm64_impl::translateMulh}, {ARM64_INS_UMULL2, nullptr}, - {ARM64_INS_UMULL, nullptr}, + {ARM64_INS_UMULL, &Capstone2LlvmIrTranslatorArm64_impl::translateMull}, {ARM64_INS_UQADD, nullptr}, {ARM64_INS_UQRSHL, nullptr}, {ARM64_INS_UQRSHRN, nullptr}, @@ -664,8 +664,8 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = // alias insn {ARM64_INS_MNEG, &Capstone2LlvmIrTranslatorArm64_impl::translateMul}, - {ARM64_INS_UMNEGL, &Capstone2LlvmIrTranslatorArm64_impl::translateMull}, - {ARM64_INS_SMNEGL, &Capstone2LlvmIrTranslatorArm64_impl::translateMull}, + {ARM64_INS_UMNEGL, &Capstone2LlvmIrTranslatorArm64_impl::translateMulOpl}, + {ARM64_INS_SMNEGL, &Capstone2LlvmIrTranslatorArm64_impl::translateMulOpl}, {ARM64_INS_NOP, nullptr}, {ARM64_INS_YIELD, nullptr}, {ARM64_INS_WFE, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 48f85d586..1caf63523 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -3236,6 +3236,140 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SMNEGL_r_w_w_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_UMULL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UMULL_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x4}, + {ARM64_REG_X2, 0x1}, + }); + + emulate("umull x0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x4}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UMULL_r_r_r_1) +{ + setRegisters({ + {ARM64_REG_X1, 0x4}, + {ARM64_REG_X2, 0xffffffff}, + }); + + emulate("umull x0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x3fffffffc}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_SMULL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SMULL_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x4}, + {ARM64_REG_X2, 0x1}, + }); + + emulate("smull x0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x4}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SMULL_r_r_r_1) +{ + setRegisters({ + {ARM64_REG_X1, 0x4}, + {ARM64_REG_X2, 0xffffffff}, + }); + + emulate("smull x0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xfffffffffffffffc}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_UMULH +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UMULH_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x4}, + {ARM64_REG_X2, 0x1}, + }); + + emulate("umulh x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_SMULH +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SMULH_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x4}, + {ARM64_REG_X2, 0x1}, + }); + + emulate("smulh x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SMULH_r_r_r_1) +{ + setRegisters({ + {ARM64_REG_X1, 0x4}, + {ARM64_REG_X2, 0xffffffffffffffff}, + }); + + emulate("smulh x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} // // ARM64_INS_MNEG From 48772deb6e0b1ab2813e81789a7e67cac2841b6c Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 16 Feb 2019 19:11:26 +0100 Subject: [PATCH 072/107] Arm64: Conditional select operation instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 85 +++++++++++++++ src/capstone2llvmir/arm64/arm64_impl.h | 2 + src/capstone2llvmir/arm64/arm64_init.cpp | 12 +- tests/capstone2llvmir/arm64_tests.cpp | 133 +++++++++++++++++++++++ 4 files changed, 226 insertions(+), 6 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 197569a9a..0895821a1 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1386,6 +1386,91 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateCsel(cs_insn* i, cs_arm64* ai storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_CINC, ARM64_INS_CINV, ARM64_INS_CNEG + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateCondOp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + + auto* cond = generateInsnConditionCode(irb, ai); + // Invert the condition + cond = generateValueNegate(irb, cond); + auto irbP = generateIfThenElse(cond, irb); + llvm::IRBuilder<>& bodyIf(irbP.first), bodyElse(irbP.second); + + //IF - store first operand + storeOp(ai->operands[0], op1, bodyIf); + + //ELSE + llvm::Value *val = nullptr; + switch(i->id) + { + case ARM64_INS_CINC: + val = bodyElse.CreateAdd(op1, llvm::ConstantInt::get(op1->getType(), 1)); + break; + case ARM64_INS_CINV: + val = generateValueNegate(bodyElse, op1); + break; + case ARM64_INS_CNEG: + val = generateValueNegate(bodyElse, op1); + val = bodyElse.CreateAdd(val, llvm::ConstantInt::get(val->getType(), 1)); + //TODO: Express this as: (zero - op1) ? + //llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); + //val = irb.CreateSub(zero, val); + break; + default: + throw GenericError("translateCondOp: Instruction id error"); + break; + } + storeOp(ai->operands[0], val, bodyElse); + //ENDIF +} + +/** + * ARM64_INS_CSINC, ARM64_INS_CSINV, ARM64_INS_CSNEG + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateCondSelOp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + op2 = loadOp(ai->operands[2], irb); + + auto* cond = generateInsnConditionCode(irb, ai); + auto irbP = generateIfThenElse(cond, irb); + llvm::IRBuilder<>& bodyIf(irbP.first), bodyElse(irbP.second); + + //IF + storeOp(ai->operands[0], op1, bodyIf); + + //ELSE + llvm::Value *val = nullptr; + switch(i->id) + { + case ARM64_INS_CSINC: + val = bodyElse.CreateAdd(op2, llvm::ConstantInt::get(op2->getType(), 1)); + break; + case ARM64_INS_CSINV: + val = generateValueNegate(bodyElse, op2); + break; + case ARM64_INS_CSNEG: + val = generateValueNegate(bodyElse, op2); + val = bodyElse.CreateAdd(val, llvm::ConstantInt::get(val->getType(), 1)); + //TODO: Express this as: (zero - op2) ? + //llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); + //val = irb.CreateSub(zero, val); + break; + default: + throw GenericError("translateCondSelOp: Instruction id error"); + break; + } + storeOp(ai->operands[0], val, bodyElse); + //ENDIF +} + /** * ARM64_INS_CSET, ARM64_INS_CSETM */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index c85fad25b..0290e6022 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -172,6 +172,8 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateAdc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateAnd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateCondOp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateCondSelOp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateShifts(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateNeg(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index ee37bffec..a8da27c3c 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -292,9 +292,9 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_CRC32W, nullptr}, {ARM64_INS_CRC32X, nullptr}, {ARM64_INS_CSEL, &Capstone2LlvmIrTranslatorArm64_impl::translateCsel}, - {ARM64_INS_CSINC, nullptr}, - {ARM64_INS_CSINV, nullptr}, - {ARM64_INS_CSNEG, nullptr}, + {ARM64_INS_CSINC, &Capstone2LlvmIrTranslatorArm64_impl::translateCondSelOp}, + {ARM64_INS_CSINV, &Capstone2LlvmIrTranslatorArm64_impl::translateCondSelOp}, + {ARM64_INS_CSNEG, &Capstone2LlvmIrTranslatorArm64_impl::translateCondSelOp}, {ARM64_INS_DCPS1, nullptr}, {ARM64_INS_DCPS2, nullptr}, {ARM64_INS_DCPS3, nullptr}, @@ -683,10 +683,10 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_MVN, &Capstone2LlvmIrTranslatorArm64_impl::translateMov}, {ARM64_INS_TST, nullptr}, {ARM64_INS_CSET, &Capstone2LlvmIrTranslatorArm64_impl::translateCset}, - {ARM64_INS_CINC, nullptr}, + {ARM64_INS_CINC, &Capstone2LlvmIrTranslatorArm64_impl::translateCondOp}, {ARM64_INS_CSETM, &Capstone2LlvmIrTranslatorArm64_impl::translateCset}, - {ARM64_INS_CINV, nullptr}, - {ARM64_INS_CNEG, nullptr}, + {ARM64_INS_CINV, &Capstone2LlvmIrTranslatorArm64_impl::translateCondOp}, + {ARM64_INS_CNEG, &Capstone2LlvmIrTranslatorArm64_impl::translateCondOp}, {ARM64_INS_SXTB, nullptr}, {ARM64_INS_SXTH, nullptr}, {ARM64_INS_SXTW, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 1caf63523..26a1951ff 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -2848,6 +2848,138 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSETM32_true) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_CSINC +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSINC_true) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0x1}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_Z, false}, + }); + + emulate("csinc x0, x1, x2, hi"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_Z, ARM64_REG_CPSR_C, ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSINC_false) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1}, + {ARM64_REG_X2, 0x1234}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_V, true}, + }); + + emulate("csinc x0, x1, x2, ge"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_N, ARM64_REG_CPSR_V, ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1235}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_CSINV +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSINV_true) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0x1}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_Z, false}, + }); + + emulate("csinv x0, x1, x2, hi"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_Z, ARM64_REG_CPSR_C, ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSINV_false) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x1}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_V, true}, + }); + + emulate("csinv x0, x1, x2, ge"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_N, ARM64_REG_CPSR_V, ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xfffffffffffffffe}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_CSNEG +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSNEG_true) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0x1}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_Z, false}, + }); + + emulate("csneg x0, x1, x2, hi"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_Z, ARM64_REG_CPSR_C, ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSNEG_false) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x5}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_V, true}, + }); + + emulate("csneg x0, x1, x2, ge"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_N, ARM64_REG_CPSR_V, ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xfffffffffffffffb}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MUL // @@ -3321,6 +3453,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UMULH_r_r_r) setRegisters({ {ARM64_REG_X1, 0x4}, {ARM64_REG_X2, 0x1}, + //{ARM64_REG_X2, 0xffffffffffffffff}, }); emulate("umulh x0, x1, x2"); From f410655df34e25e26ba49e6efd95e1d0979834ab Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sun, 17 Feb 2019 16:57:10 +0100 Subject: [PATCH 073/107] Arm64: CINC, CINV, CNEG tests --- tests/capstone2llvmir/arm64_tests.cpp | 126 ++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 26a1951ff..2a48ece19 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -2980,6 +2980,132 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CSNEG_false) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_CINC +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CINC_true) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_Z, false}, + }); + + emulate("cinc x0, x1, ls"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_Z, ARM64_REG_CPSR_C, ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CINC_false) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_V, true}, + }); + + emulate("cinc x0, x1, lt"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_N, ARM64_REG_CPSR_V, ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x2}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_CINV +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CINV_true) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_Z, false}, + }); + + emulate("cinv x0, x1, ls"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_Z, ARM64_REG_CPSR_C, ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CINV_false) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_V, true}, + }); + + emulate("cinv x0, x1, lt"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_N, ARM64_REG_CPSR_V, ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffedcb}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_CNEG +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CNEG_true) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_Z, false}, + }); + + emulate("cneg x0, x1, ls"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_Z, ARM64_REG_CPSR_C, ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CNEG_false) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_V, true}, + }); + + emulate("cneg x0, x1, lt"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_N, ARM64_REG_CPSR_V, ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MUL // From 18045b9b74614690beb42a0e00e0a828a4a2cfe9 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Mon, 18 Feb 2019 15:28:45 +0100 Subject: [PATCH 074/107] Arm64: EON, EOR instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 20 ++++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 4 +- tests/capstone2llvmir/arm64_tests.cpp | 84 ++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 0895821a1..28f259adb 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1501,6 +1501,26 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateCset(cs_insn* i, cs_arm64* ai storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_EOR, ARM64_INS_EON + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateEor(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY_OR_TERNARY(i, ai, irb); + + std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); + op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); + + if (i->id == ARM64_INS_EON) + { + op2 = generateValueNegate(irb, op2); + } + + auto* val = irb.CreateXor(op1, op2); + + storeOp(ai->operands[0], val, irb); +} + /** * ARM64_INS_UDIV, ARM64_INS_SDIV */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 0290e6022..db2b03f4c 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -192,6 +192,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateCsel(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateCset(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateDiv(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateEor(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMulOpl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMull(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index a8da27c3c..2a86559ed 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -302,8 +302,8 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_DRPS, nullptr}, {ARM64_INS_DSB, nullptr}, {ARM64_INS_DUP, nullptr}, - {ARM64_INS_EON, nullptr}, - {ARM64_INS_EOR, nullptr}, + {ARM64_INS_EON, &Capstone2LlvmIrTranslatorArm64_impl::translateEor}, + {ARM64_INS_EOR, &Capstone2LlvmIrTranslatorArm64_impl::translateEor}, {ARM64_INS_ERET, nullptr}, {ARM64_INS_EXTR, nullptr}, {ARM64_INS_EXT, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 2a48ece19..70db41c0a 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -816,6 +816,90 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_AND32_s_negative_r_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_EOR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_EOR_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0x00000000ffffffff}, + }); + + emulate("eor x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0xffffffff00000000},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_EOR_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + }); + + emulate("eor x0, x1, #3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0xfffffffffffffffc},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_EOR32_r_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0xffff0000}, + {ARM64_REG_X2, 0xffffffff}, + }); + + emulate("eor w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0xffff},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_EON +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_EON_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x00000000ffffffff}, + {ARM64_REG_X2, 0xffffffffffffffff}, + }); + + emulate("eon x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x00000000ffffffff},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_EON32_r_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0xffffffff}, + {ARM64_REG_X2, 0x0000ffff}, + }); + + emulate("eon w0, w1, w2, LSL #16"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0xffff0000},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_ASR // From 1f7f82c9d604c3e2c023b56cef237717580848b9 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Tue, 19 Feb 2019 13:50:04 +0100 Subject: [PATCH 075/107] Arm64: ORN, ORR instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 20 ++++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 4 +- tests/capstone2llvmir/arm64_tests.cpp | 84 ++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 28f259adb..c1bb3f50b 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1521,6 +1521,26 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateEor(cs_insn* i, cs_arm64* ai, storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_ORR, ARM64_INS_ORN + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateOrr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY_OR_TERNARY(i, ai, irb); + + std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); + op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); + + if (i->id == ARM64_INS_ORN) + { + op2 = generateValueNegate(irb, op2); + } + + auto* val = irb.CreateOr(op1, op2); + + storeOp(ai->operands[0], val, irb); +} + /** * ARM64_INS_UDIV, ARM64_INS_SDIV */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index db2b03f4c..4bf419ba2 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -193,6 +193,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateCset(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateDiv(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateEor(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateOrr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMulOpl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMull(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 2a86559ed..34bb8725c 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -442,8 +442,8 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_MVNI, nullptr}, {ARM64_INS_NEG, &Capstone2LlvmIrTranslatorArm64_impl::translateNeg}, {ARM64_INS_NOT, nullptr}, - {ARM64_INS_ORN, nullptr}, - {ARM64_INS_ORR, nullptr}, + {ARM64_INS_ORN, &Capstone2LlvmIrTranslatorArm64_impl::translateOrr}, + {ARM64_INS_ORR, &Capstone2LlvmIrTranslatorArm64_impl::translateOrr}, {ARM64_INS_PMULL2, nullptr}, {ARM64_INS_PMULL, nullptr}, {ARM64_INS_PMUL, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 70db41c0a..3e4696658 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -900,6 +900,90 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_EON32_r_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_ORR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ORR_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0x00000000ffffffff}, + }); + + emulate("orr x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0xffffffffffffffff},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ORR_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + }); + + emulate("orr x0, x1, #3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0xffffffffffffffff},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ORR32_r_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0xffff0000}, + {ARM64_REG_X2, 0xffffffff}, + }); + + emulate("orr w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0xffffffff},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_ORN +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ORN_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x00000000ffffffff}, + {ARM64_REG_X2, 0xffffffffffffffff}, + }); + + emulate("orn x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x00000000ffffffff},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ORN32_r_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0xffffffff}, + {ARM64_REG_X2, 0x0000ffff}, + }); + + emulate("orn w0, w1, w2, LSL #16"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0xffffffff},}); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_ASR // From 22a3f145dc13ac84b7fc0f7dae17aa296af6047e Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Tue, 19 Feb 2019 15:56:51 +0100 Subject: [PATCH 076/107] Arm64: TST instruction + tests - fixed the AND instruction to set carry and overflow flags to zero --- src/capstone2llvmir/arm64/arm64.cpp | 17 ++-- src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 108 +++++++++++++++++++++++ 3 files changed, 118 insertions(+), 9 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index c1bb3f50b..dfaab91ba 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -919,12 +919,6 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMov(cs_insn* i, cs_arm64* ai, op1 = generateValueNegate(irb, op1); } - if (ai->update_flags) - { - llvm::Value* zero = llvm::ConstantInt::get(op1->getType(), 0); - storeRegister(ARM64_REG_CPSR_N, irb.CreateICmpSLT(op1, zero), irb); - storeRegister(ARM64_REG_CPSR_Z, irb.CreateICmpEQ(op1, zero), irb); - } storeOp(ai->operands[0], op1, irb); } @@ -1235,7 +1229,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdr(cs_insn* i, cs_arm64* ai, } /** - * ARM64_INS_AND + * ARM64_INS_AND, ARM64_INS_TST */ void Capstone2LlvmIrTranslatorArm64_impl::translateAnd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1246,13 +1240,20 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAnd(cs_insn* i, cs_arm64* ai, auto* val = irb.CreateAnd(op1, op2); - storeOp(ai->operands[0], val, irb); + if (i->id != ARM64_INS_TST) + { + storeOp(ai->operands[0], val, irb); + } if (ai->update_flags) { llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); storeRegister(ARM64_REG_CPSR_N, irb.CreateICmpSLT(val, zero), irb); storeRegister(ARM64_REG_CPSR_Z, irb.CreateICmpEQ(val, zero), irb); + // According to documentation carry and overflow should be + // set to zero. + storeRegister(ARM64_REG_CPSR_C, zero, irb); + storeRegister(ARM64_REG_CPSR_V, zero, irb); } } diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 34bb8725c..e01b3c5b5 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -681,7 +681,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_BFXIL, nullptr}, {ARM64_INS_CMN, &Capstone2LlvmIrTranslatorArm64_impl::translateAdd}, {ARM64_INS_MVN, &Capstone2LlvmIrTranslatorArm64_impl::translateMov}, - {ARM64_INS_TST, nullptr}, + {ARM64_INS_TST, &Capstone2LlvmIrTranslatorArm64_impl::translateAnd}, {ARM64_INS_CSET, &Capstone2LlvmIrTranslatorArm64_impl::translateCset}, {ARM64_INS_CINC, &Capstone2LlvmIrTranslatorArm64_impl::translateCondOp}, {ARM64_INS_CSETM, &Capstone2LlvmIrTranslatorArm64_impl::translateCset}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 3e4696658..9200f908e 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -792,6 +792,8 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_AND_s_zero_r_r_r) {ARM64_REG_X0, 0x0}, {ARM64_REG_CPSR_N, false}, {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, }); EXPECT_NO_MEMORY_LOADED_STORED(); EXPECT_NO_VALUE_CALLED(); @@ -811,6 +813,8 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_AND32_s_negative_r_r_r) {ARM64_REG_X0, 0x80000000}, {ARM64_REG_CPSR_N, true}, {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, }); EXPECT_NO_MEMORY_LOADED_STORED(); EXPECT_NO_VALUE_CALLED(); @@ -4482,6 +4486,110 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UDIV_r_r_r_zero_div) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_TST +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TST_zero_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0x12345678}, + }); + + emulate("tst x1, #1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TST_zero_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x12345678}, + {ARM64_REG_X2, 0x0}, + }); + + emulate("tst x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TST_minus_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0x8000000000000000}, + }); + + emulate("tst x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TST32_zero_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234567880abcdef}, + {ARM64_REG_X2, 0x00000000}, + }); + + emulate("tst w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TST32_negative_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234567880abcdef}, + {ARM64_REG_X2, 0xf0000000}, + }); + + emulate("tst w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + } // namespace tests } // namespace capstone2llvmir } // namespace retdec From 6455608072a26cbbc766c27ebc3af72f529fbbef Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Tue, 19 Feb 2019 18:01:58 +0100 Subject: [PATCH 077/107] Arm64: EXTR instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 22 ++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 140 +++++++++++++++++++++++ 4 files changed, 164 insertions(+), 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index dfaab91ba..5b4b24609 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1522,6 +1522,28 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateEor(cs_insn* i, cs_arm64* ai, storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_EXTR +*/ +void Capstone2LlvmIrTranslatorArm64_impl::translateExtr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_QUATERNARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + op2 = loadOp(ai->operands[2], irb); + auto* lsb1 = loadOp(ai->operands[3], irb); + lsb1 = irb.CreateZExtOrTrunc(lsb1, op1->getType()); + llvm::Value* lsb2 = llvm::ConstantInt::get(op1->getType(), llvm::cast(op2->getType())->getBitWidth()); + lsb2 = irb.CreateSub(lsb2, lsb1); + + auto* left_val = irb.CreateLShr(op2, lsb1); + auto* right_val = irb.CreateShl(op1, lsb2); + + auto* val = irb.CreateOr(left_val, right_val); + + storeOp(ai->operands[0], val, irb); +} + /** * ARM64_INS_ORR, ARM64_INS_ORN */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 4bf419ba2..77c9600d7 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -193,6 +193,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateCset(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateDiv(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateEor(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateExtr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateOrr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMulOpl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index e01b3c5b5..042b60c9c 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -305,7 +305,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_EON, &Capstone2LlvmIrTranslatorArm64_impl::translateEor}, {ARM64_INS_EOR, &Capstone2LlvmIrTranslatorArm64_impl::translateEor}, {ARM64_INS_ERET, nullptr}, - {ARM64_INS_EXTR, nullptr}, + {ARM64_INS_EXTR, &Capstone2LlvmIrTranslatorArm64_impl::translateExtr}, {ARM64_INS_EXT, nullptr}, {ARM64_INS_FABD, nullptr}, {ARM64_INS_FABS, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 9200f908e..af13b8f26 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -988,6 +988,146 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ORN32_r_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_EXTR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_EXTR_r_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0x1111111111111111}, + {ARM64_REG_X2, 0x9999999999999999}, + }); + + emulate("extr x0, x1, x2, #63"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x2222222222222223}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_EXTR_r_r_r_i_1) +{ + setRegisters({ + {ARM64_REG_X1, 0x1111111111111111}, + {ARM64_REG_X2, 0x9999999999999999}, + }); + + emulate("extr x0, x1, x2, #48"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1111111111119999}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_EXTR_r_r_r_i_2) +{ + setRegisters({ + {ARM64_REG_X1, 0x1111111111111111}, + {ARM64_REG_X2, 0x9999999999999999}, + }); + + emulate("extr x0, x1, x2, #16"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1111999999999999}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_EXTR_r_r_r_i_3) +{ + setRegisters({ + {ARM64_REG_X1, 0x1111111111111111}, + {ARM64_REG_X2, 0x9999999999999999}, + }); + + emulate("extr x0, x1, x2, #10"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x4466666666666666}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_EXTR_r_r_r_i_5) +{ + setRegisters({ + {ARM64_REG_X1, 0x1111111111111111}, + {ARM64_REG_X2, 0x9999999999999999}, + }); + + emulate("extr x0, x1, x2, #0"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x9999999999999999}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_EXTR_r_r_r_i_6) +{ + setRegisters({ + {ARM64_REG_X2, 0x1234567890abcdef}, + }); + + emulate("extr x0, x2, x2, #32"); + // alias ROR x0, x2, #32 + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x90abcdef12345678}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_EXTR32_r_r_r_i) +{ + setRegisters({ + {ARM64_REG_X1, 0x1111111111111111}, + {ARM64_REG_X2, 0x9999999999999999}, + }); + + emulate("extr w0, w1, w2, #31"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000022222223}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_EXTR32_r_r_r_i_1) +{ + setRegisters({ + {ARM64_REG_X1, 0x1111111111111111}, + {ARM64_REG_X2, 0x9999999999999999}, + }); + + emulate("extr w0, w1, w2, #16"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000011119999}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_ASR // From a89a6774dc93b8172683b9f2e1b1a77da6070db7 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Wed, 20 Feb 2019 14:57:11 +0100 Subject: [PATCH 078/107] Arm64: Extend instructions + tests --- src/capstone2llvmir/arm64/arm64.cpp | 63 ++++++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 12 +- tests/capstone2llvmir/arm64_tests.cpp | 181 +++++++++++++++++++++++ 4 files changed, 251 insertions(+), 6 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 5b4b24609..ab1615dab 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1522,6 +1522,69 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateEor(cs_insn* i, cs_arm64* ai, storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_ +*/ +void Capstone2LlvmIrTranslatorArm64_impl::translateExtensions(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + auto* val = loadOp(ai->operands[1], irb); + + auto* i8 = llvm::IntegerType::getInt8Ty(_module->getContext()); + auto* i16 = llvm::IntegerType::getInt16Ty(_module->getContext()); + auto* i32 = llvm::IntegerType::getInt32Ty(_module->getContext()); + + auto* ty = getRegisterType(ai->operands[0].reg); + + llvm::Value* trunc = nullptr; + switch(i->id) + { + case ARM64_INS_UXTB: + { + trunc = irb.CreateTrunc(val, i8); + val = irb.CreateZExt(trunc, ty); + break; + } + case ARM64_INS_UXTH: + { + trunc = irb.CreateTrunc(val, i16); + val = irb.CreateZExt(trunc, ty); + break; + } + /* + case ARM64_INS_UXTW: + { + trunc = irb.CreateTrunc(val, i32); + val = irb.CreateZExt(trunc, ty); + break; + } + */ + case ARM64_INS_SXTB: + { + trunc = irb.CreateTrunc(val, i8); + val = irb.CreateSExt(trunc, ty); + break; + } + case ARM64_INS_SXTH: + { + trunc = irb.CreateTrunc(val, i16); + val = irb.CreateSExt(trunc, ty); + break; + } + case ARM64_INS_SXTW: + { + trunc = irb.CreateTrunc(val, i32); + val = irb.CreateSExt(trunc, ty); + break; + } + default: + throw GenericError("Arm64 translateExtension(): Unsupported extension type"); + } + + storeOp(ai->operands[0], val, irb); +} + /** * ARM64_INS_EXTR */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 77c9600d7..905a25817 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -193,6 +193,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateCset(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateDiv(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateEor(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateExtensions(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateExtr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateOrr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 042b60c9c..8aabfce3c 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -687,13 +687,13 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_CSETM, &Capstone2LlvmIrTranslatorArm64_impl::translateCset}, {ARM64_INS_CINV, &Capstone2LlvmIrTranslatorArm64_impl::translateCondOp}, {ARM64_INS_CNEG, &Capstone2LlvmIrTranslatorArm64_impl::translateCondOp}, - {ARM64_INS_SXTB, nullptr}, - {ARM64_INS_SXTH, nullptr}, - {ARM64_INS_SXTW, nullptr}, + {ARM64_INS_SXTB, &Capstone2LlvmIrTranslatorArm64_impl::translateExtensions}, + {ARM64_INS_SXTH, &Capstone2LlvmIrTranslatorArm64_impl::translateExtensions}, + {ARM64_INS_SXTW, &Capstone2LlvmIrTranslatorArm64_impl::translateExtensions}, {ARM64_INS_CMP, &Capstone2LlvmIrTranslatorArm64_impl::translateSub}, - {ARM64_INS_UXTB, nullptr}, - {ARM64_INS_UXTH, nullptr}, - {ARM64_INS_UXTW, nullptr}, + {ARM64_INS_UXTB, &Capstone2LlvmIrTranslatorArm64_impl::translateExtensions}, + {ARM64_INS_UXTH, &Capstone2LlvmIrTranslatorArm64_impl::translateExtensions}, + {ARM64_INS_UXTW, &Capstone2LlvmIrTranslatorArm64_impl::translateExtensions}, {ARM64_INS_IC, nullptr}, {ARM64_INS_DC, nullptr}, {ARM64_INS_AT, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index af13b8f26..3ae5eb40e 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -4164,6 +4164,187 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MSUB32_r_r_r_1) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_SXTB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SXTB_r_r_true) +{ + setRegisters({ + {ARM64_REG_X1, 0x80}, + }); + + emulate("sxtb w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000ffffff80}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SXTB_r_r_false) +{ + setRegisters({ + {ARM64_REG_X1, 0x7f}, + }); + + emulate("sxtb w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x000000000000007f}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_SXTH +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SXTH_r_r_true) +{ + setRegisters({ + {ARM64_REG_X1, 0x8000}, + }); + + emulate("sxth w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000ffff8000}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SXTH_r_r_false) +{ + setRegisters({ + {ARM64_REG_X1, 0x7fff}, + }); + + emulate("sxth w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000000007fff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_SXTW +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SXTW_r_r_true) +{ + setRegisters({ + {ARM64_REG_X1, 0x80000000}, + }); + + emulate("sxtw x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffff80000000}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SXTW_r_r_false) +{ + setRegisters({ + {ARM64_REG_X1, 0x7fffffff}, + }); + + emulate("sxtw x0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x000000007fffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_UXTB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UXTB_r_r_true) +{ + setRegisters({ + {ARM64_REG_X1, 0x80}, + }); + + emulate("uxtb w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000000000080}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UXTB_r_r_false) +{ + setRegisters({ + {ARM64_REG_X1, 0x7f}, + }); + + emulate("uxtb w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x000000000000007f}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_UXTH +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UXTH_r_r_true) +{ + setRegisters({ + {ARM64_REG_X1, 0x8000}, + }); + + emulate("uxth w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000000008000}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UXTH_r_r_false) +{ + setRegisters({ + {ARM64_REG_X1, 0x7fff}, + }); + + emulate("uxth w0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000000007fff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + + // // ARM64_INS_TBNZ // From 96c944df208b64418b40fd76cd359a592c5fed05 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 21 Feb 2019 13:12:10 +0100 Subject: [PATCH 079/107] Arm64: CCMN, CCMP instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 60 ++- src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 4 +- tests/capstone2llvmir/arm64_tests.cpp | 472 ++++++++++++++++++++++- 4 files changed, 529 insertions(+), 8 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index ab1615dab..a10eda257 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -784,7 +784,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, storeOp(ai->operands[0], val, irb); } - if (ai->update_flags || i->id == ARM64_INS_CMN) + if (ai->update_flags) { llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); storeRegister(ARM64_REG_CPSR_C, generateCarryAdd(val, op1, irb), irb); @@ -795,7 +795,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdd(cs_insn* i, cs_arm64* ai, } /** - * ARM64_INS_SUB + * ARM64_INS_SUB, ARM64_INS_CMP */ void Capstone2LlvmIrTranslatorArm64_impl::translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -810,7 +810,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateSub(cs_insn* i, cs_arm64* ai, storeOp(ai->operands[0], val, irb); } - if (ai->update_flags || i->id == ARM64_INS_CMP) + if (ai->update_flags) { llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); storeRegister(ARM64_REG_CPSR_C, generateValueNegate(irb, generateBorrowSub(op1, op2, irb)), irb); @@ -1372,6 +1372,57 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateCbnz(cs_insn* i, cs_arm64* ai generateCondBranchFunctionCall(irb, cond, op1); } +/** + * ARM64_INS_CCMN, ARM64_INS_CCMP + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateCondCompare(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + op1 = loadOp(ai->operands[0], irb); + op2 = loadOp(ai->operands[1], irb); + auto* nzvc = loadOp(ai->operands[2], irb); + + op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); + + auto* cond = generateInsnConditionCode(irb, ai); + auto irbP = generateIfThenElse(cond, irb); + llvm::IRBuilder<>& bodyIf(irbP.first), bodyElse(irbP.second); + + //IF - condition holds + llvm::Value* val = nullptr; + if (i->id == ARM64_INS_CCMP) + { + val = bodyIf.CreateSub(op1, op2); + llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); + storeRegister(ARM64_REG_CPSR_C, generateValueNegate(bodyIf, generateBorrowSub(op1, op2, bodyIf)), bodyIf); + storeRegister(ARM64_REG_CPSR_V, generateOverflowSub(val, op1, op2, bodyIf), bodyIf); + storeRegister(ARM64_REG_CPSR_N, bodyIf.CreateICmpSLT(val, zero), bodyIf); + storeRegister(ARM64_REG_CPSR_Z, bodyIf.CreateICmpEQ(val, zero), bodyIf); + } + else if (i->id == ARM64_INS_CCMN) + { + val = bodyIf.CreateAdd(op1, op2); + llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); + storeRegister(ARM64_REG_CPSR_C, generateCarryAdd(val, op1, bodyIf), bodyIf); + storeRegister(ARM64_REG_CPSR_V, generateOverflowAdd(val, op1, op2, bodyIf), bodyIf); + storeRegister(ARM64_REG_CPSR_N, bodyIf.CreateICmpSLT(val, zero), bodyIf); + storeRegister(ARM64_REG_CPSR_Z, bodyIf.CreateICmpEQ(val, zero), bodyIf); + } + else + { + throw GenericError("Arm64 ccmp, ccmn: Instruction id error"); + } + + //ELSE - Set the flags from IMM + // We only use shifts because the final value to be stored is truncated to i1. + storeRegister(ARM64_REG_CPSR_N, bodyElse.CreateLShr(nzvc, llvm::ConstantInt::get(nzvc->getType(), 3)), bodyElse); + storeRegister(ARM64_REG_CPSR_Z, bodyElse.CreateLShr(nzvc, llvm::ConstantInt::get(nzvc->getType(), 2)), bodyElse); + storeRegister(ARM64_REG_CPSR_C, bodyElse.CreateLShr(nzvc, llvm::ConstantInt::get(nzvc->getType(), 1)), bodyElse); + storeRegister(ARM64_REG_CPSR_V, nzvc, bodyElse); + +} + /** * ARM64_INS_CSEL */ @@ -1523,7 +1574,8 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateEor(cs_insn* i, cs_arm64* ai, } /** - * ARM64_INS_ + * ARM64_INS_SXTB, ARM64_INS_SXTH, ARM64_INS_SXTW + * ARM64_INS_UXTB, ARM64_INS_UXTH */ void Capstone2LlvmIrTranslatorArm64_impl::translateExtensions(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 905a25817..56095b608 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -174,6 +174,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateAnd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateCondOp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateCondSelOp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateCondCompare(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateShifts(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateNeg(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 8aabfce3c..42216852c 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -268,8 +268,8 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_BSL, nullptr}, {ARM64_INS_CBNZ, &Capstone2LlvmIrTranslatorArm64_impl::translateCbnz}, {ARM64_INS_CBZ, &Capstone2LlvmIrTranslatorArm64_impl::translateCbnz}, - {ARM64_INS_CCMN, nullptr}, - {ARM64_INS_CCMP, nullptr}, + {ARM64_INS_CCMN, &Capstone2LlvmIrTranslatorArm64_impl::translateCondCompare}, + {ARM64_INS_CCMP, &Capstone2LlvmIrTranslatorArm64_impl::translateCondCompare}, {ARM64_INS_CLREX, nullptr}, {ARM64_INS_CLS, nullptr}, {ARM64_INS_CLZ, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 3ae5eb40e..7f35caf02 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -1245,6 +1245,26 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMN_carry_r_r) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMN_carry_overflow_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x8000000000000000}, + {ARM64_REG_X2, 0x8000000000000000}, + }); + + emulate("cmn x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMN_overflow_r_r) { setRegisters({ @@ -1265,6 +1285,434 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMN_overflow_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_CCMP +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMP_r_r_r_c) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x1234}, + {ARM64_REG_CPSR_Z, false} + }); + + emulate("ccmp x1, x2, #0, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMP_r_r_r_c_1) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x1234}, + {ARM64_REG_CPSR_Z, false} + }); + + emulate("ccmp x1, x2, #1, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMP_r_r_r_c_2) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x1234}, + {ARM64_REG_CPSR_Z, false} + }); + + emulate("ccmp x1, x2, #2, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMP_r_r_r_c_3) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x1234}, + {ARM64_REG_CPSR_Z, false} + }); + + emulate("ccmp x1, x2, #4, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMP_r_r_r_c_4) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x1234}, + {ARM64_REG_CPSR_Z, false} + }); + + emulate("ccmp x1, x2, #8, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMP_r_r_r_c_5) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x1234}, + {ARM64_REG_CPSR_Z, false} + }); + + emulate("ccmp x1, x2, #15, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMP_negative_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xffff0000000fffff}, + {ARM64_REG_X2, 0x1234}, + {ARM64_REG_CPSR_Z, true} + }); + + emulate("ccmp x1, x2, #0, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMP_carry_zero_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x0}, + {ARM64_REG_X2, 0x1}, + {ARM64_REG_CPSR_Z, true} + }); + + emulate("ccmp x1, x2, #0, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMP_overflow_carry_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x8000000000000000}, + {ARM64_REG_X2, 0x7ffffffffffffffe}, + {ARM64_REG_CPSR_Z, true} + }); + + emulate("ccmp x1, x2, #0, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMP32_overflow_carry_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x80000000}, + {ARM64_REG_X2, 0x7ffffffe}, + {ARM64_REG_CPSR_Z, true} + }); + + emulate("ccmp w1, w2, #0, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_CCMN +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMN_r_r_r_c) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x1234}, + {ARM64_REG_CPSR_Z, false} + }); + + emulate("ccmn x1, x2, #0, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMN_r_r_r_c_1) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x1234}, + {ARM64_REG_CPSR_Z, false} + }); + + emulate("ccmn x1, x2, #3, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMN_r_r_r_c_2) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x1234}, + {ARM64_REG_CPSR_Z, false} + }); + + emulate("ccmn x1, x2, #7, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMN_r_r_r_c_3) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x1234}, + {ARM64_REG_CPSR_Z, false} + }); + + emulate("ccmn x1, x2, #10, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMN_r_r_r_c_4) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x1234}, + {ARM64_REG_CPSR_Z, false} + }); + + emulate("ccmn x1, x2, #12, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMN_r_r_r_c_5) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234}, + {ARM64_REG_X2, 0x1234}, + {ARM64_REG_CPSR_Z, false} + }); + + emulate("ccmn x1, x2, #14, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMN_negative_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xfffffffffffffffa}, + {ARM64_REG_X2, 0x2}, + {ARM64_REG_CPSR_Z, true} + }); + + emulate("ccmn x1, x2, #0, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMN_carry_negative_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + {ARM64_REG_X2, 0xffffffffffffffff}, + {ARM64_REG_CPSR_Z, true} + }); + + emulate("ccmn x1, x2, #0, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMN_overflow_carry_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x8000000000000000}, + {ARM64_REG_X2, 0x8000000000000000}, + {ARM64_REG_CPSR_Z, true} + }); + + emulate("ccmn x1, x2, #0, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CCMN32_overflow_carry_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x80000000}, + {ARM64_REG_X2, 0x80000000}, + {ARM64_REG_CPSR_Z, true} + }); + + emulate("ccmn w1, w2, #0, eq"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_CMP // @@ -1289,7 +1737,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMP_zero_r_r) EXPECT_NO_VALUE_CALLED(); } -TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMP_s_negative_r_r_r) +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMP_negative_r_r) { setRegisters({ {ARM64_REG_X1, 0xffff0000000fffff}, @@ -1309,7 +1757,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMP_s_negative_r_r_r) EXPECT_NO_VALUE_CALLED(); } -TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMP_s_carry_r_r_r) +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMP_carry_r_r) { setRegisters({ {ARM64_REG_X1, 0x0}, @@ -1329,6 +1777,26 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMP_s_carry_r_r_r) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CMP_overflow_carry_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x8000000000000000}, + {ARM64_REG_X2, 0x7ffffffffffffffe}, + }); + + emulate("cmp x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_SUB // From b2681338504a70ac797231160ea8d744c637ff90 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 22 Feb 2019 10:55:57 +0100 Subject: [PATCH 080/107] Arm64: NOP instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 8 ++++++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 14 ++++++++++++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index a10eda257..21367c077 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -906,6 +906,14 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateNgc(cs_insn* i, cs_arm64* ai, } } +/** + * ARM64_INS_NOP + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateNop(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + // Don't translate anything. +} + /** * ARM64_INS_MOV, ARM64_INS_MVN, ARM64_INS_MOVZ */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 56095b608..cefff29d6 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -201,6 +201,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateMulOpl(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMull(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMulh(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateNop(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateTbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 42216852c..aeeb631ba 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -666,7 +666,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_MNEG, &Capstone2LlvmIrTranslatorArm64_impl::translateMul}, {ARM64_INS_UMNEGL, &Capstone2LlvmIrTranslatorArm64_impl::translateMulOpl}, {ARM64_INS_SMNEGL, &Capstone2LlvmIrTranslatorArm64_impl::translateMulOpl}, - {ARM64_INS_NOP, nullptr}, + {ARM64_INS_NOP, &Capstone2LlvmIrTranslatorArm64_impl::translateNop}, {ARM64_INS_YIELD, nullptr}, {ARM64_INS_WFE, nullptr}, {ARM64_INS_WFI, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 7f35caf02..f07463d80 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -2404,6 +2404,20 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MVN32_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_NOP +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_NOP) +{ + emulate("nop"); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_STR // From b6b2fa97e09a19a74252f48756384ea92a56dc22 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 22 Feb 2019 12:21:07 +0100 Subject: [PATCH 081/107] Arm64: REV, RBIT, CLZ instructions + tests --- src/capstone2llvmir/arm64/arm64.cpp | 51 +++++++ src/capstone2llvmir/arm64/arm64_impl.h | 2 + src/capstone2llvmir/arm64/arm64_init.cpp | 6 +- tests/capstone2llvmir/arm64_tests.cpp | 175 ++++++++++++++++++++++- 4 files changed, 230 insertions(+), 4 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 21367c077..600c82a4a 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1356,6 +1356,24 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateBl(cs_insn* i, cs_arm64* ai, generateCallFunctionCall(irb, op0); } +/** + * ARM64_INS_CLZ + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateClz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + op1 = loadOpBinaryOp1(ai, irb); + + auto* f = llvm::Intrinsic::getDeclaration( + _module, + llvm::Intrinsic::ctlz, + op1->getType()); + + auto* val = irb.CreateCall(f, {op1, irb.getTrue()}); + storeOp(ai->operands[0], val, irb); +} + /** * ARM64_INS_CBNZ, ARM64_INS_CBZ */ @@ -1969,5 +1987,38 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateRet(cs_insn* i, cs_arm64* ai, generateReturnFunctionCall(irb, op0); } +/** + * ARM64_INS_REV, ARM64_INS_RBIT + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateRev(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + op1 = loadOpBinaryOp1(ai, irb); + + llvm::Function* f = nullptr; + if (i->id == ARM64_INS_REV) + { + f = llvm::Intrinsic::getDeclaration( + _module, + llvm::Intrinsic::bswap, + op1->getType()); + } + else if (i->id == ARM64_INS_RBIT) + { + f = llvm::Intrinsic::getDeclaration( + _module, + llvm::Intrinsic::bitreverse, + op1->getType()); + } + else + { + throw GenericError("Arm64 REV, RBIT: Unhandled instruction id"); + } + + auto* val = irb.CreateCall(f, {op1}); + storeOp(ai->operands[0], val, irb); +} + } // namespace capstone2llvmir } // namespace retdec diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index cefff29d6..2dfe5c886 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -175,6 +175,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateCondOp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateCondSelOp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateCondCompare(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateClz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateShifts(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateNeg(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); @@ -204,6 +205,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateNop(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateTbnz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateRev(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); }; diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index aeeb631ba..d16dcc6e5 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -272,7 +272,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_CCMP, &Capstone2LlvmIrTranslatorArm64_impl::translateCondCompare}, {ARM64_INS_CLREX, nullptr}, {ARM64_INS_CLS, nullptr}, - {ARM64_INS_CLZ, nullptr}, + {ARM64_INS_CLZ, &Capstone2LlvmIrTranslatorArm64_impl::translateClz}, {ARM64_INS_CMEQ, nullptr}, {ARM64_INS_CMGE, nullptr}, {ARM64_INS_CMGT, nullptr}, @@ -451,12 +451,12 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_PRFUM, nullptr}, {ARM64_INS_RADDHN, nullptr}, {ARM64_INS_RADDHN2, nullptr}, - {ARM64_INS_RBIT, nullptr}, + {ARM64_INS_RBIT, &Capstone2LlvmIrTranslatorArm64_impl::translateRev}, {ARM64_INS_RET, &Capstone2LlvmIrTranslatorArm64_impl::translateRet}, {ARM64_INS_REV16, nullptr}, {ARM64_INS_REV32, nullptr}, {ARM64_INS_REV64, nullptr}, - {ARM64_INS_REV, nullptr}, + {ARM64_INS_REV, &Capstone2LlvmIrTranslatorArm64_impl::translateRev}, {ARM64_INS_ROR, &Capstone2LlvmIrTranslatorArm64_impl::translateShifts}, {ARM64_INS_RSHRN2, nullptr}, {ARM64_INS_RSHRN, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index f07463d80..349c0a701 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -1181,6 +1181,106 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_ASR32_r_r_i) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_CLZ +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CLZ_r_r) +{ + setRegisters({ + {ARM64_REG_X2, 0x0}, + }); + + emulate("clz x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X1, 0x40}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CLZ_r_r_1) +{ + setRegisters({ + {ARM64_REG_X2, 0x1}, + }); + + emulate("clz x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X1, 0x3f}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CLZ_r_r_2) +{ + setRegisters({ + {ARM64_REG_X2, 0x100000000}, + }); + + emulate("clz x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X1, 0x1f}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CLZ32_r_r) +{ + setRegisters({ + {ARM64_REG_X2, 0x0}, + }); + + emulate("clz w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X1, 0x20}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CLZ32_r_r_1) +{ + setRegisters({ + {ARM64_REG_X2, 0x10000000}, + }); + + emulate("clz w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X1, 0x3}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_CLZ32_r_r_2) +{ + setRegisters({ + {ARM64_REG_X2, 0x00000008}, + }); + + emulate("clz w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X1, 0x1c}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_CMN // @@ -5312,7 +5412,6 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TST_zero_r_i) EXPECT_NO_VALUE_CALLED(); } - TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TST_zero_r_r) { setRegisters({ @@ -5393,6 +5492,80 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TST32_negative_r_r) EXPECT_NO_VALUE_CALLED(); } +/* TODO: LLVM ERROR: Code generator does not support intrinsic function 'llvm.bitreverse.i64'! +// +// ARM64_INS_RBIT +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_RBIT_r_r) +{ + setRegisters({ + {ARM64_REG_X2, 0x1234567890abcdef}, + }); + + emulate("rbit x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X1, 0xf7b3d5091e6a2c48}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_RBIT32_r_r) +{ + setRegisters({ + {ARM64_REG_X2, 0x1234567890abcdef}, + }); + + emulate("rev w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X1, 0x00000000f7b3d509}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} +*/ + +// +// ARM64_INS_REV +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_REV_r_r) +{ + setRegisters({ + {ARM64_REG_X2, 0x1234567890abcdef}, + }); + + emulate("rev x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X1, 0xefcdab9078563412}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_REV32_r_r) +{ + setRegisters({ + {ARM64_REG_X2, 0x1234567890abcdef}, + }); + + emulate("rev w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X1, 0x00000000efcdab90}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + } // namespace tests } // namespace capstone2llvmir } // namespace retdec From 7dc12870c5c6c870c3848d60fb1e4446e463985d Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 22 Feb 2019 12:31:50 +0100 Subject: [PATCH 082/107] Arm64: BIC instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 6 ++- src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 63 ++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 600c82a4a..634f3243f 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1237,7 +1237,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAdr(cs_insn* i, cs_arm64* ai, } /** - * ARM64_INS_AND, ARM64_INS_TST + * ARM64_INS_AND, ARM64_INS_BIC, ARM64_INS_TST */ void Capstone2LlvmIrTranslatorArm64_impl::translateAnd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1246,6 +1246,10 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAnd(cs_insn* i, cs_arm64* ai, std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); op2 = irb.CreateZExtOrTrunc(op2, op1->getType()); + if (i->id == ARM64_INS_BIC) + { + op2 = generateValueNegate(irb, op2); + } auto* val = irb.CreateAnd(op1, op2); if (i->id != ARM64_INS_TST) diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index d16dcc6e5..c51615989 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -258,7 +258,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_ASR, &Capstone2LlvmIrTranslatorArm64_impl::translateShifts}, {ARM64_INS_B, &Capstone2LlvmIrTranslatorArm64_impl::translateB}, {ARM64_INS_BFM, nullptr}, - {ARM64_INS_BIC, nullptr}, + {ARM64_INS_BIC, &Capstone2LlvmIrTranslatorArm64_impl::translateAnd}, {ARM64_INS_BIF, nullptr}, {ARM64_INS_BIT, nullptr}, {ARM64_INS_BL, &Capstone2LlvmIrTranslatorArm64_impl::translateBl}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 349c0a701..eec3f3af3 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -3460,6 +3460,69 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_BLR) }); } +// +// ARM64_INS_BIC +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_BIC_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234567890abcdef}, + {ARM64_REG_X2, 0xff00ff00ff00ff00}, + }); + + emulate("bic x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0034007800ab00ef}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_BIC_s_zero_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x12345678}, + {ARM64_REG_X2, 0xffffffffffffffff}, + }); + + emulate("bics x0, x1, x2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_BIC32_s_negative_r_r_r) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234567880abcdef}, + {ARM64_REG_X2, 0x0fffffff}, + }); + + emulate("bics w0, w1, w2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x80000000}, + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_V, false}, + {ARM64_REG_CPSR_C, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_CBNZ // From f1dc1e3dfc3e4028a0bbb948ee58c885e848eee4 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 23 Feb 2019 20:51:39 +0100 Subject: [PATCH 083/107] Arm64: Unpriviledged loads/stores instructions + tests --- src/capstone2llvmir/arm64/arm64.cpp | 34 ++- src/capstone2llvmir/arm64/arm64_init.cpp | 26 +- tests/capstone2llvmir/arm64_tests.cpp | 343 +++++++++++++++++++++++ 3 files changed, 381 insertions(+), 22 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 634f3243f..fddc9c515 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -932,6 +932,8 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMov(cs_insn* i, cs_arm64* ai, /** * ARM64_INS_STR, ARM64_INS_STRB, ARM64_INS_STRH + * ARM64_INS_STUR, ARM64_INS_STURB, ARM64_INS_STURH + * ARM64_INS_STTR, ARM64_INS_STTRB, ARM64_INS_STTRH */ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -941,16 +943,22 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, switch (i->id) { case ARM64_INS_STR: + case ARM64_INS_STUR: + case ARM64_INS_STTR: { ty = getDefaultType(); break; } case ARM64_INS_STRB: + case ARM64_INS_STURB: + case ARM64_INS_STTRB: { ty = irb.getInt8Ty(); break; } case ARM64_INS_STRH: + case ARM64_INS_STURH: + case ARM64_INS_STTRH: { ty = irb.getInt16Ty(); break; @@ -994,7 +1002,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, } /** - * ARM64_INS_STP + * ARM64_INS_STP, ARM64_INS_STNP */ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1046,6 +1054,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, * ARM64_INS_LDR * ARM64_INS_LDURB, ARM64_INS_LDUR, ARM64_INS_LDURH, ARM64_INS_LDURSB, ARM64_INS_LDURSH, ARM64_INS_LDURSW * ARM64_INS_LDRB, ARM64_INS_LDRH, ARM64_INS_LDRSB, ARM64_INS_LDRSH, ARM64_INS_LDRSW + * ARM64_INS_LDTR, ARM64_INS_LDTRB, ARM64_INS_LDTRSB, ARM64_INS_LDTRH, ARM64_INS_LDTRSH, ARM64_INS_LDTRSW */ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1057,6 +1066,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, { case ARM64_INS_LDR: case ARM64_INS_LDUR: + case ARM64_INS_LDTR: { ty = irb.getInt32Ty(); sext = false; @@ -1064,6 +1074,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, } case ARM64_INS_LDRB: case ARM64_INS_LDURB: + case ARM64_INS_LDTRB: { ty = irb.getInt8Ty(); sext = false; @@ -1071,6 +1082,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, } case ARM64_INS_LDRH: case ARM64_INS_LDURH: + case ARM64_INS_LDTRH: { ty = irb.getInt16Ty(); sext = false; @@ -1079,6 +1091,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, // Signed loads case ARM64_INS_LDRSB: case ARM64_INS_LDURSB: + case ARM64_INS_LDTRSB: { ty = irb.getInt8Ty(); sext = true; @@ -1086,6 +1099,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, } case ARM64_INS_LDRSH: case ARM64_INS_LDURSH: + case ARM64_INS_LDTRSH: { ty = irb.getInt16Ty(); sext = true; @@ -1093,6 +1107,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, } case ARM64_INS_LDRSW: case ARM64_INS_LDURSW: + case ARM64_INS_LDTRSW: { ty = irb.getInt32Ty(); sext = true; @@ -1140,7 +1155,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, } /** - * ARM64_INS_LDP, ARM64_INS_LDPSW + * ARM64_INS_LDP, ARM64_INS_LDPSW, ARM64_INS_LDNP */ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1149,20 +1164,21 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, llvm::Value* data_size = nullptr; llvm::Type* ty = nullptr; eOpConv ct = eOpConv::THROW; - if(i->id == ARM64_INS_LDP) + switch(i->id) { + case ARM64_INS_LDNP: + // Hints PE that the memory is not going to be used in near future + case ARM64_INS_LDP: data_size = llvm::ConstantInt::get(getDefaultType(), getRegisterByteSize(ai->operands[0].reg)); ty = getRegisterType(ai->operands[0].reg); ct = eOpConv::ZEXT_TRUNC; - } - else if(i->id == ARM64_INS_LDPSW) - { + break; + case ARM64_INS_LDPSW: data_size = llvm::ConstantInt::get(getDefaultType(), 4); ty = irb.getInt32Ty(); ct = eOpConv::SEXT_TRUNC; - } - else - { + break; + default: throw GenericError("ldp, ldpsw: Instruction id error"); } diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index c51615989..6e9f9247a 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -400,7 +400,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_LDAXRB, nullptr}, {ARM64_INS_LDAXRH, nullptr}, {ARM64_INS_LDAXR, nullptr}, - {ARM64_INS_LDNP, nullptr}, + {ARM64_INS_LDNP, &Capstone2LlvmIrTranslatorArm64_impl::translateLdp}, {ARM64_INS_LDP, &Capstone2LlvmIrTranslatorArm64_impl::translateLdp}, {ARM64_INS_LDPSW, &Capstone2LlvmIrTranslatorArm64_impl::translateLdp}, {ARM64_INS_LDRB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, @@ -409,13 +409,13 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_LDRSB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDRSH, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDRSW, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, - {ARM64_INS_LDTRB, nullptr}, - {ARM64_INS_LDTRH, nullptr}, - {ARM64_INS_LDTRSB, nullptr}, + {ARM64_INS_LDTRB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDTRH, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDTRSB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, - {ARM64_INS_LDTRSH, nullptr}, - {ARM64_INS_LDTRSW, nullptr}, - {ARM64_INS_LDTR, nullptr}, + {ARM64_INS_LDTRSH, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDTRSW, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDTR, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDURB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDUR, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDURH, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, @@ -567,17 +567,17 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_STLXRB, nullptr}, {ARM64_INS_STLXRH, nullptr}, {ARM64_INS_STLXR, nullptr}, - {ARM64_INS_STNP, nullptr}, + {ARM64_INS_STNP, &Capstone2LlvmIrTranslatorArm64_impl::translateStp}, {ARM64_INS_STP, &Capstone2LlvmIrTranslatorArm64_impl::translateStp}, {ARM64_INS_STRB, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, {ARM64_INS_STR, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, {ARM64_INS_STRH, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, - {ARM64_INS_STTRB, nullptr}, - {ARM64_INS_STTRH, nullptr}, - {ARM64_INS_STTR, nullptr}, - {ARM64_INS_STURB, nullptr}, + {ARM64_INS_STTRB, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, + {ARM64_INS_STTRH, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, + {ARM64_INS_STTR, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, + {ARM64_INS_STURB, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, {ARM64_INS_STUR, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, - {ARM64_INS_STURH, nullptr}, + {ARM64_INS_STURH, &Capstone2LlvmIrTranslatorArm64_impl::translateStr}, {ARM64_INS_STXP, nullptr}, {ARM64_INS_STXRB, nullptr}, {ARM64_INS_STXRH, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index eec3f3af3..5da0b63ac 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -2639,6 +2639,90 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STRH_r_r_i) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_STTR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STTR_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0xcafebabecafebabe}, + {ARM64_REG_X1, 0x1234}, + }); + + emulate("sttr x0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X0, ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1234, 0xcafebabecafebabe} + }); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_STTRB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STTRB_r_r) +{ + setRegisters({ + {ARM64_REG_W0, 0xcafebabe}, + {ARM64_REG_X1, 0x1234}, + }); + + emulate("sttrb w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W0, ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1234, 0xbe} + }); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_STTRH +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STTRH_r_r) +{ + setRegisters({ + {ARM64_REG_W0, 0xcafebabe}, + {ARM64_REG_X1, 0x1234}, + }); + + emulate("sttrh w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W0, ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1234, 0xbabe} + }); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STTRH_r_r_i) +{ + setRegisters({ + {ARM64_REG_W0, 0xcafebabe}, + {ARM64_REG_X1, 0x1234}, + }); + + emulate("sttrh w0, [x1, #0x10]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W0, ARM64_REG_X1}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1244, 0xbabe} + }); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_STP // @@ -2727,6 +2811,70 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STP_r_r_m_i) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_STNP +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STNP_r_r_r) +{ + setRegisters({ + {ARM64_REG_X0, 0x0123456789abcdef}, + {ARM64_REG_X2, 0xfedcba9876543210}, + {ARM64_REG_SP, 0x1234}, + }); + + emulate("stnp x0, x2, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X0, ARM64_REG_X2, ARM64_REG_SP}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1234, 0x0123456789abcdef_qw}, + {0x123c, 0xfedcba9876543210_qw} + }); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STNP32_r_r_r) +{ + setRegisters({ + {ARM64_REG_W0, 0x01234567}, + {ARM64_REG_W2, 0xfedcba98}, + {ARM64_REG_SP, 0x1234}, + }); + + emulate("stnp w0, w2, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W0, ARM64_REG_W2, ARM64_REG_SP}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1234, 0x01234567_dw}, + {0x1238, 0xfedcba98_dw} + }); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STNP_r_r_mw) +{ + setRegisters({ + {ARM64_REG_X0, 0x0123456789abcdef}, + {ARM64_REG_X2, 0xfedcba9876543210}, + {ARM64_REG_SP, 0x1234}, + }); + + emulate("stnp x0, x2, [sp, #-0x20]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X0, ARM64_REG_X2, ARM64_REG_SP}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1214, 0x0123456789abcdef_qw}, + {0x121c, 0xfedcba9876543210_qw} + }); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_LDR // @@ -3080,6 +3228,131 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDRSW) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_LDTRB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDTRB) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0xf1_b}, + }); + + emulate("ldtrb w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xf1}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LDTRSB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDTRSB) +{ + setRegisters({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x80_b}, + }); + + emulate("ldtrsb w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffff80}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LDTRH +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDTRH) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x8182_w}, + }); + + emulate("ldtrh w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x8182}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LDTRSH +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDTRSH) +{ + setRegisters({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x8182_w}, + }); + + emulate("ldtrsh w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffff8182}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LDTRSW +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDTRSW) +{ + setRegisters({ + {ARM64_REG_X0, 0x0}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x81828384_dw}, + }); + + emulate("ldtrsw x0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffff81828384}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_LDP // @@ -3174,6 +3447,76 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDP_r_r_r_i) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_LDNP +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDNP_r_r_r) +{ + setRegisters({ + {ARM64_REG_SP, 0x1000}, + }); + setMemory({ + {0x1000, 0x123456789abcdef0_qw}, + {0x1008, 0xfedcba9876543210_qw}, + }); + + emulate("ldnp x0, x1, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_X1, 0xfedcba9876543210}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000, 0x1008}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDNP32_r_r_r) +{ + setRegisters({ + {ARM64_REG_SP, 0x1000}, + }); + setMemory({ + {0x1000, 0x12345678_dw}, + {0x1004, 0x9abcdef0_dw}, + }); + + emulate("ldnp w0, w1, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_W0, 0x12345678}, + {ARM64_REG_W1, 0x9abcdef0}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000, 0x1004}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDNP_r_r_mw) +{ + setRegisters({ + {ARM64_REG_SP, 0x1020}, + }); + setMemory({ + {0x1000, 0x123456789abcdef0_qw}, + {0x1008, 0xfedcba9876543210_qw}, + }); + + emulate("ldnp x0, x1, [sp, #-32]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_X1, 0xfedcba9876543210}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000, 0x1008}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_LDPSW // From cde4008795ebe254bd8764dbed308e13867eb9d3 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 23 Feb 2019 21:26:45 +0100 Subject: [PATCH 084/107] Arm64: Load/Store exclusive instructions + tests --- src/capstone2llvmir/arm64/arm64.cpp | 16 ++- src/capstone2llvmir/arm64/arm64_init.cpp | 8 +- tests/capstone2llvmir/arm64_tests.cpp | 146 +++++++++++++++++++++++ 3 files changed, 164 insertions(+), 6 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index fddc9c515..c4adc53f3 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -934,6 +934,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMov(cs_insn* i, cs_arm64* ai, * ARM64_INS_STR, ARM64_INS_STRB, ARM64_INS_STRH * ARM64_INS_STUR, ARM64_INS_STURB, ARM64_INS_STURH * ARM64_INS_STTR, ARM64_INS_STTRB, ARM64_INS_STTRH + * TODO: Prob pseudo! ARM64_INS_STXR, ARM64_INS_STXRB, ARM64_INS_STXRH */ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -945,6 +946,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, case ARM64_INS_STR: case ARM64_INS_STUR: case ARM64_INS_STTR: + //case ARM64_INS_STXR: { ty = getDefaultType(); break; @@ -952,6 +954,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, case ARM64_INS_STRB: case ARM64_INS_STURB: case ARM64_INS_STTRB: + //case ARM64_INS_STXRB: { ty = irb.getInt8Ty(); break; @@ -959,6 +962,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, case ARM64_INS_STRH: case ARM64_INS_STURH: case ARM64_INS_STTRH: + //case ARM64_INS_STXRH: { ty = irb.getInt16Ty(); break; @@ -1003,6 +1007,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, /** * ARM64_INS_STP, ARM64_INS_STNP + * TODO: prob Pseudo! ARM64_INS_STXP */ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1055,6 +1060,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, * ARM64_INS_LDURB, ARM64_INS_LDUR, ARM64_INS_LDURH, ARM64_INS_LDURSB, ARM64_INS_LDURSH, ARM64_INS_LDURSW * ARM64_INS_LDRB, ARM64_INS_LDRH, ARM64_INS_LDRSB, ARM64_INS_LDRSH, ARM64_INS_LDRSW * ARM64_INS_LDTR, ARM64_INS_LDTRB, ARM64_INS_LDTRSB, ARM64_INS_LDTRH, ARM64_INS_LDTRSH, ARM64_INS_LDTRSW + * ARM64_INS_LDXR, ARM64_INS_LDXRB, ARM64_INS_LDXRH */ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1067,6 +1073,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, case ARM64_INS_LDR: case ARM64_INS_LDUR: case ARM64_INS_LDTR: + case ARM64_INS_LDXR: { ty = irb.getInt32Ty(); sext = false; @@ -1075,6 +1082,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, case ARM64_INS_LDRB: case ARM64_INS_LDURB: case ARM64_INS_LDTRB: + case ARM64_INS_LDXRB: { ty = irb.getInt8Ty(); sext = false; @@ -1083,6 +1091,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, case ARM64_INS_LDRH: case ARM64_INS_LDURH: case ARM64_INS_LDTRH: + case ARM64_INS_LDXRH: { ty = irb.getInt16Ty(); sext = false; @@ -1155,7 +1164,9 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, } /** - * ARM64_INS_LDP, ARM64_INS_LDPSW, ARM64_INS_LDNP + * ARM64_INS_LDP, ARM64_INS_LDPSW + * ARM64_INS_LDNP (Non-temporal) + * ARM64_INS_LDXP (Exclusive) */ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1169,6 +1180,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, case ARM64_INS_LDNP: // Hints PE that the memory is not going to be used in near future case ARM64_INS_LDP: + case ARM64_INS_LDXP: data_size = llvm::ConstantInt::get(getDefaultType(), getRegisterByteSize(ai->operands[0].reg)); ty = getRegisterType(ai->operands[0].reg); ct = eOpConv::ZEXT_TRUNC; @@ -1179,7 +1191,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, ct = eOpConv::SEXT_TRUNC; break; default: - throw GenericError("ldp, ldpsw: Instruction id error"); + throw GenericError("Arm64 Ldp: Instruction id error"); } auto* dest = loadOp(ai->operands[2], irb, nullptr, true); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 6e9f9247a..97c33cb1b 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -422,10 +422,10 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_LDURSB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDURSH, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDURSW, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, - {ARM64_INS_LDXP, nullptr}, - {ARM64_INS_LDXRB, nullptr}, - {ARM64_INS_LDXRH, nullptr}, - {ARM64_INS_LDXR, nullptr}, + {ARM64_INS_LDXP, &Capstone2LlvmIrTranslatorArm64_impl::translateLdp}, + {ARM64_INS_LDXRB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDXRH, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDXR, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LSL, &Capstone2LlvmIrTranslatorArm64_impl::translateShifts}, {ARM64_INS_LSR, &Capstone2LlvmIrTranslatorArm64_impl::translateShifts}, {ARM64_INS_MADD, &Capstone2LlvmIrTranslatorArm64_impl::translateMul}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 5da0b63ac..533ff4634 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -3228,6 +3228,30 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDRSW) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_LDTR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDTR) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x123456789abcdef0_qw}, + }); + + emulate("ldtr x0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_LDTRB // @@ -3353,6 +3377,80 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDTRSW) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_LDXR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDXR) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x123456789abcdef0_qw}, + }); + + emulate("ldxr x0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LDXRB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDXRB) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0xf1_b}, + }); + + emulate("ldxrb w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xf1}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LDXRH +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDXRH) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x8182_w}, + }); + + emulate("ldxrh w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x8182}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_LDP // @@ -3594,6 +3692,54 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDPSW_r_r_r_i) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_LDXP +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDXP_r_r_r) +{ + setRegisters({ + {ARM64_REG_SP, 0x1000}, + }); + setMemory({ + {0x1000, 0x123456789abcdef0_qw}, + {0x1008, 0xfedcba9876543210_qw}, + }); + + emulate("ldxp x0, x1, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_X1, 0xfedcba9876543210}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000, 0x1008}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDXP32_r_r_r) +{ + setRegisters({ + {ARM64_REG_SP, 0x1000}, + }); + setMemory({ + {0x1000, 0x12345678_dw}, + {0x1004, 0x9abcdef0_dw}, + }); + + emulate("ldxp w0, w1, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_W0, 0x12345678}, + {ARM64_REG_W1, 0x9abcdef0}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000, 0x1004}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_LSL // From 9833fbeb46a3c6eee54513b38f81af43571bb3d0 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sun, 24 Feb 2019 12:02:25 +0100 Subject: [PATCH 085/107] ARM64: LDAXR instruction variants + tests --- src/capstone2llvmir/arm64/arm64.cpp | 6 ++ src/capstone2llvmir/arm64/arm64_init.cpp | 8 +- tests/capstone2llvmir/arm64_tests.cpp | 122 +++++++++++++++++++++++ 3 files changed, 132 insertions(+), 4 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index c4adc53f3..5802ba514 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1061,6 +1061,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, * ARM64_INS_LDRB, ARM64_INS_LDRH, ARM64_INS_LDRSB, ARM64_INS_LDRSH, ARM64_INS_LDRSW * ARM64_INS_LDTR, ARM64_INS_LDTRB, ARM64_INS_LDTRSB, ARM64_INS_LDTRH, ARM64_INS_LDTRSH, ARM64_INS_LDTRSW * ARM64_INS_LDXR, ARM64_INS_LDXRB, ARM64_INS_LDXRH + * ARM64_INS_LDAXR, ARM64_INS_LDAXRB, ARM64_INS_LDAXRH */ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1074,6 +1075,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, case ARM64_INS_LDUR: case ARM64_INS_LDTR: case ARM64_INS_LDXR: + case ARM64_INS_LDAXR: { ty = irb.getInt32Ty(); sext = false; @@ -1083,6 +1085,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, case ARM64_INS_LDURB: case ARM64_INS_LDTRB: case ARM64_INS_LDXRB: + case ARM64_INS_LDAXRB: { ty = irb.getInt8Ty(); sext = false; @@ -1092,6 +1095,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, case ARM64_INS_LDURH: case ARM64_INS_LDTRH: case ARM64_INS_LDXRH: + case ARM64_INS_LDAXRH: { ty = irb.getInt16Ty(); sext = false; @@ -1167,6 +1171,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, * ARM64_INS_LDP, ARM64_INS_LDPSW * ARM64_INS_LDNP (Non-temporal) * ARM64_INS_LDXP (Exclusive) + * ARM64_INS_LDAXP (Exclusive Aquire) */ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1181,6 +1186,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdp(cs_insn* i, cs_arm64* ai, // Hints PE that the memory is not going to be used in near future case ARM64_INS_LDP: case ARM64_INS_LDXP: + case ARM64_INS_LDAXP: data_size = llvm::ConstantInt::get(getDefaultType(), getRegisterByteSize(ai->operands[0].reg)); ty = getRegisterType(ai->operands[0].reg); ct = eOpConv::ZEXT_TRUNC; diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 97c33cb1b..09e41a7bd 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -396,10 +396,10 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_LDARB, nullptr}, {ARM64_INS_LDARH, nullptr}, {ARM64_INS_LDAR, nullptr}, - {ARM64_INS_LDAXP, nullptr}, - {ARM64_INS_LDAXRB, nullptr}, - {ARM64_INS_LDAXRH, nullptr}, - {ARM64_INS_LDAXR, nullptr}, + {ARM64_INS_LDAXP, &Capstone2LlvmIrTranslatorArm64_impl::translateLdp}, + {ARM64_INS_LDAXRB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDAXRH, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDAXR, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDNP, &Capstone2LlvmIrTranslatorArm64_impl::translateLdp}, {ARM64_INS_LDP, &Capstone2LlvmIrTranslatorArm64_impl::translateLdp}, {ARM64_INS_LDPSW, &Capstone2LlvmIrTranslatorArm64_impl::translateLdp}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 533ff4634..f8f9a5384 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -3451,6 +3451,80 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDXRH) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_LDAXR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDAXR) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x123456789abcdef0_qw}, + }); + + emulate("ldaxr x0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LDAXRB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDAXRB) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0xf1_b}, + }); + + emulate("ldaxrb w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xf1}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LDAXRH +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDAXRH) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x8182_w}, + }); + + emulate("ldaxrh w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x8182}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_LDP // @@ -3740,6 +3814,54 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDXP32_r_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_LDAXP +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDAXP_r_r_r) +{ + setRegisters({ + {ARM64_REG_SP, 0x1000}, + }); + setMemory({ + {0x1000, 0x123456789abcdef0_qw}, + {0x1008, 0xfedcba9876543210_qw}, + }); + + emulate("ldaxp x0, x1, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + {ARM64_REG_X1, 0xfedcba9876543210}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000, 0x1008}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDAXP32_r_r_r) +{ + setRegisters({ + {ARM64_REG_SP, 0x1000}, + }); + setMemory({ + {0x1000, 0x12345678_dw}, + {0x1004, 0x9abcdef0_dw}, + }); + + emulate("ldaxp w0, w1, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_W0, 0x12345678}, + {ARM64_REG_W1, 0x9abcdef0}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000, 0x1004}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_LSL // From 3590595a9837600c9fba7271c92c11a92356239f Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sun, 24 Feb 2019 12:13:31 +0100 Subject: [PATCH 086/107] Arm64: LDAR instruction variants + tests --- src/capstone2llvmir/arm64/arm64.cpp | 4 ++ src/capstone2llvmir/arm64/arm64_init.cpp | 6 +- tests/capstone2llvmir/arm64_tests.cpp | 74 ++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 3 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 5802ba514..8a9f7e81b 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1062,6 +1062,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, * ARM64_INS_LDTR, ARM64_INS_LDTRB, ARM64_INS_LDTRSB, ARM64_INS_LDTRH, ARM64_INS_LDTRSH, ARM64_INS_LDTRSW * ARM64_INS_LDXR, ARM64_INS_LDXRB, ARM64_INS_LDXRH * ARM64_INS_LDAXR, ARM64_INS_LDAXRB, ARM64_INS_LDAXRH + * ARM64_INS_LDAR, ARM64_INS_LDARB, ARM64_INS_LDARH */ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1076,6 +1077,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, case ARM64_INS_LDTR: case ARM64_INS_LDXR: case ARM64_INS_LDAXR: + case ARM64_INS_LDAR: { ty = irb.getInt32Ty(); sext = false; @@ -1086,6 +1088,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, case ARM64_INS_LDTRB: case ARM64_INS_LDXRB: case ARM64_INS_LDAXRB: + case ARM64_INS_LDARB: { ty = irb.getInt8Ty(); sext = false; @@ -1096,6 +1099,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, case ARM64_INS_LDTRH: case ARM64_INS_LDXRH: case ARM64_INS_LDAXRH: + case ARM64_INS_LDARH: { ty = irb.getInt16Ty(); sext = false; diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 09e41a7bd..6c7424feb 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -393,9 +393,9 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_LD4, nullptr}, {ARM64_INS_LD4R, nullptr}, - {ARM64_INS_LDARB, nullptr}, - {ARM64_INS_LDARH, nullptr}, - {ARM64_INS_LDAR, nullptr}, + {ARM64_INS_LDARB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDARH, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, + {ARM64_INS_LDAR, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDAXP, &Capstone2LlvmIrTranslatorArm64_impl::translateLdp}, {ARM64_INS_LDAXRB, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, {ARM64_INS_LDAXRH, &Capstone2LlvmIrTranslatorArm64_impl::translateLdr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index f8f9a5384..c71b88f29 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -3525,6 +3525,80 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDAXRH) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_LDAR +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDAR) +{ + setRegisters({ + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x123456789abcdef0_qw}, + }); + + emulate("ldar x0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x123456789abcdef0}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LDARB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDARB) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0xf1_b}, + }); + + emulate("ldarb w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xf1}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_LDARH +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_LDARH) +{ + setRegisters({ + {ARM64_REG_X0, 0xffffffffffffffff}, + {ARM64_REG_X1, 0x1000}, + }); + setMemory({ + {0x1000, 0x8182_w}, + }); + + emulate("ldarh w0, [x1]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x8182}, + }); + EXPECT_JUST_MEMORY_LOADED({0x1000}); + EXPECT_NO_MEMORY_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_LDP // From 4d4ed83bf5a94c923717e33b175b829df4b19fc4 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Wed, 27 Feb 2019 18:32:00 +0100 Subject: [PATCH 087/107] Arm64, llvmir-emul: don't lower bitreverse intrinsic - updated tests to check if the correct intrinsic functions was called --- src/llvmir-emul/llvmir_emul.cpp | 3 ++- tests/capstone2llvmir/arm64_tests.cpp | 16 +++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/llvmir-emul/llvmir_emul.cpp b/src/llvmir-emul/llvmir_emul.cpp index b4775c29f..b00ade6ed 100644 --- a/src/llvmir-emul/llvmir_emul.cpp +++ b/src/llvmir-emul/llvmir_emul.cpp @@ -3058,7 +3058,8 @@ void LlvmIrEmulator::visitCallInst(llvm::CallInst& I) auto* cf = I.getCalledFunction(); if (cf && cf->isDeclaration() && cf->isIntrinsic() && - cf->getIntrinsicID() != Intrinsic::fabs) // can not lower fabs + !(cf->getIntrinsicID() == Intrinsic::bitreverse + || cf->getIntrinsicID() == Intrinsic::fabs)) // can not lower those functions { assert(cf->getIntrinsicID() != Intrinsic::vastart && cf->getIntrinsicID() != Intrinsic::vaend diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index c71b88f29..57c9d56b9 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -6240,7 +6240,6 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_TST32_negative_r_r) EXPECT_NO_VALUE_CALLED(); } -/* TODO: LLVM ERROR: Code generator does not support intrinsic function 'llvm.bitreverse.i64'! // // ARM64_INS_RBIT // @@ -6255,10 +6254,12 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_RBIT_r_r) EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X2}); EXPECT_JUST_REGISTERS_STORED({ - {ARM64_REG_X1, 0xf7b3d5091e6a2c48}, + {ARM64_REG_X1, ANY}, }); EXPECT_NO_MEMORY_LOADED_STORED(); - EXPECT_NO_VALUE_CALLED(); + EXPECT_VALUES_CALLED({ + {_module.getFunction("llvm.bitreverse.i64"), {0x1234567890abcdef}}, + }); } TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_RBIT32_r_r) @@ -6267,16 +6268,17 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_RBIT32_r_r) {ARM64_REG_X2, 0x1234567890abcdef}, }); - emulate("rev w1, w2"); + emulate("rbit w1, w2"); EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X2}); EXPECT_JUST_REGISTERS_STORED({ - {ARM64_REG_X1, 0x00000000f7b3d509}, + {ARM64_REG_X1, ANY}, }); EXPECT_NO_MEMORY_LOADED_STORED(); - EXPECT_NO_VALUE_CALLED(); + EXPECT_VALUES_CALLED({ + {_module.getFunction("llvm.bitreverse.i32"), {0x90abcdef}}, + }); } -*/ // // ARM64_INS_REV From 23bcf77238c46a1e7b87ec84d90b04284457c394 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 28 Feb 2019 16:33:04 +0100 Subject: [PATCH 088/107] Arm64: FP environment + basic unary and binary operations + tests --- src/capstone2llvmir/arm64/arm64.cpp | 441 +++++++++++-- src/capstone2llvmir/arm64/arm64_impl.h | 12 +- src/capstone2llvmir/arm64/arm64_init.cpp | 299 +++++++-- tests/capstone2llvmir/arm64_tests.cpp | 800 +++++++++++++++++++++++ 4 files changed, 1446 insertions(+), 106 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 8a9f7e81b..f0820a0d6 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -17,8 +17,7 @@ Capstone2LlvmIrTranslatorArm64_impl::Capstone2LlvmIrTranslatorArm64_impl( cs_mode basic, cs_mode extra) : - Capstone2LlvmIrTranslator_impl(CS_ARCH_ARM64, basic, extra, m), - _reg2parentMap(ARM64_REG_ENDING, ARM64_REG_INVALID) + Capstone2LlvmIrTranslator_impl(CS_ARCH_ARM64, basic, extra, m) { initialize(); } @@ -68,10 +67,229 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateDataLayout() void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() { - for (auto& p : _reg2type) - { - createRegister(p.first, _regLt); - } + // FP&SIMD registers + createRegister(ARM64_REG_Q0, _regLt); + createRegister(ARM64_REG_Q1, _regLt); + createRegister(ARM64_REG_Q2, _regLt); + createRegister(ARM64_REG_Q3, _regLt); + createRegister(ARM64_REG_Q4, _regLt); + createRegister(ARM64_REG_Q5, _regLt); + createRegister(ARM64_REG_Q6, _regLt); + createRegister(ARM64_REG_Q7, _regLt); + createRegister(ARM64_REG_Q8, _regLt); + createRegister(ARM64_REG_Q9, _regLt); + createRegister(ARM64_REG_Q10, _regLt); + createRegister(ARM64_REG_Q11, _regLt); + createRegister(ARM64_REG_Q12, _regLt); + createRegister(ARM64_REG_Q13, _regLt); + createRegister(ARM64_REG_Q14, _regLt); + createRegister(ARM64_REG_Q15, _regLt); + createRegister(ARM64_REG_Q16, _regLt); + createRegister(ARM64_REG_Q17, _regLt); + createRegister(ARM64_REG_Q18, _regLt); + createRegister(ARM64_REG_Q19, _regLt); + createRegister(ARM64_REG_Q20, _regLt); + createRegister(ARM64_REG_Q21, _regLt); + createRegister(ARM64_REG_Q22, _regLt); + createRegister(ARM64_REG_Q23, _regLt); + createRegister(ARM64_REG_Q24, _regLt); + createRegister(ARM64_REG_Q25, _regLt); + createRegister(ARM64_REG_Q26, _regLt); + createRegister(ARM64_REG_Q27, _regLt); + createRegister(ARM64_REG_Q28, _regLt); + createRegister(ARM64_REG_Q29, _regLt); + createRegister(ARM64_REG_Q30, _regLt); + createRegister(ARM64_REG_Q31, _regLt); + + createRegister(ARM64_REG_D0, _regLt); + createRegister(ARM64_REG_D1, _regLt); + createRegister(ARM64_REG_D2, _regLt); + createRegister(ARM64_REG_D3, _regLt); + createRegister(ARM64_REG_D4, _regLt); + createRegister(ARM64_REG_D5, _regLt); + createRegister(ARM64_REG_D6, _regLt); + createRegister(ARM64_REG_D7, _regLt); + createRegister(ARM64_REG_D8, _regLt); + createRegister(ARM64_REG_D9, _regLt); + createRegister(ARM64_REG_D10, _regLt); + createRegister(ARM64_REG_D11, _regLt); + createRegister(ARM64_REG_D12, _regLt); + createRegister(ARM64_REG_D13, _regLt); + createRegister(ARM64_REG_D14, _regLt); + createRegister(ARM64_REG_D15, _regLt); + createRegister(ARM64_REG_D16, _regLt); + createRegister(ARM64_REG_D17, _regLt); + createRegister(ARM64_REG_D18, _regLt); + createRegister(ARM64_REG_D19, _regLt); + createRegister(ARM64_REG_D20, _regLt); + createRegister(ARM64_REG_D21, _regLt); + createRegister(ARM64_REG_D22, _regLt); + createRegister(ARM64_REG_D23, _regLt); + createRegister(ARM64_REG_D24, _regLt); + createRegister(ARM64_REG_D25, _regLt); + createRegister(ARM64_REG_D26, _regLt); + createRegister(ARM64_REG_D27, _regLt); + createRegister(ARM64_REG_D28, _regLt); + createRegister(ARM64_REG_D29, _regLt); + createRegister(ARM64_REG_D30, _regLt); + createRegister(ARM64_REG_D31, _regLt); + + createRegister(ARM64_REG_S0, _regLt); + createRegister(ARM64_REG_S1, _regLt); + createRegister(ARM64_REG_S2, _regLt); + createRegister(ARM64_REG_S3, _regLt); + createRegister(ARM64_REG_S4, _regLt); + createRegister(ARM64_REG_S5, _regLt); + createRegister(ARM64_REG_S6, _regLt); + createRegister(ARM64_REG_S7, _regLt); + createRegister(ARM64_REG_S8, _regLt); + createRegister(ARM64_REG_S9, _regLt); + createRegister(ARM64_REG_S10, _regLt); + createRegister(ARM64_REG_S11, _regLt); + createRegister(ARM64_REG_S12, _regLt); + createRegister(ARM64_REG_S13, _regLt); + createRegister(ARM64_REG_S14, _regLt); + createRegister(ARM64_REG_S15, _regLt); + createRegister(ARM64_REG_S16, _regLt); + createRegister(ARM64_REG_S17, _regLt); + createRegister(ARM64_REG_S18, _regLt); + createRegister(ARM64_REG_S19, _regLt); + createRegister(ARM64_REG_S20, _regLt); + createRegister(ARM64_REG_S21, _regLt); + createRegister(ARM64_REG_S22, _regLt); + createRegister(ARM64_REG_S23, _regLt); + createRegister(ARM64_REG_S24, _regLt); + createRegister(ARM64_REG_S25, _regLt); + createRegister(ARM64_REG_S26, _regLt); + createRegister(ARM64_REG_S27, _regLt); + createRegister(ARM64_REG_S28, _regLt); + createRegister(ARM64_REG_S29, _regLt); + createRegister(ARM64_REG_S30, _regLt); + createRegister(ARM64_REG_S31, _regLt); + + /* + createRegister(ARM64_REG_H0, _regLt); + createRegister(ARM64_REG_H1, _regLt); + createRegister(ARM64_REG_H2, _regLt); + createRegister(ARM64_REG_H3, _regLt); + createRegister(ARM64_REG_H4, _regLt); + createRegister(ARM64_REG_H5, _regLt); + createRegister(ARM64_REG_H6, _regLt); + createRegister(ARM64_REG_H7, _regLt); + createRegister(ARM64_REG_H8, _regLt); + createRegister(ARM64_REG_H9, _regLt); + createRegister(ARM64_REG_H10, _regLt); + createRegister(ARM64_REG_H11, _regLt); + createRegister(ARM64_REG_H12, _regLt); + createRegister(ARM64_REG_H13, _regLt); + createRegister(ARM64_REG_H14, _regLt); + createRegister(ARM64_REG_H15, _regLt); + createRegister(ARM64_REG_H16, _regLt); + createRegister(ARM64_REG_H17, _regLt); + createRegister(ARM64_REG_H18, _regLt); + createRegister(ARM64_REG_H19, _regLt); + createRegister(ARM64_REG_H20, _regLt); + createRegister(ARM64_REG_H21, _regLt); + createRegister(ARM64_REG_H22, _regLt); + createRegister(ARM64_REG_H23, _regLt); + createRegister(ARM64_REG_H24, _regLt); + createRegister(ARM64_REG_H25, _regLt); + createRegister(ARM64_REG_H26, _regLt); + createRegister(ARM64_REG_H27, _regLt); + createRegister(ARM64_REG_H28, _regLt); + createRegister(ARM64_REG_H29, _regLt); + createRegister(ARM64_REG_H30, _regLt); + createRegister(ARM64_REG_H31, _regLt); + */ + + createRegister(ARM64_REG_B0, _regLt); + createRegister(ARM64_REG_B1, _regLt); + createRegister(ARM64_REG_B2, _regLt); + createRegister(ARM64_REG_B3, _regLt); + createRegister(ARM64_REG_B4, _regLt); + createRegister(ARM64_REG_B5, _regLt); + createRegister(ARM64_REG_B6, _regLt); + createRegister(ARM64_REG_B7, _regLt); + createRegister(ARM64_REG_B8, _regLt); + createRegister(ARM64_REG_B9, _regLt); + createRegister(ARM64_REG_B10, _regLt); + createRegister(ARM64_REG_B11, _regLt); + createRegister(ARM64_REG_B12, _regLt); + createRegister(ARM64_REG_B13, _regLt); + createRegister(ARM64_REG_B14, _regLt); + createRegister(ARM64_REG_B15, _regLt); + createRegister(ARM64_REG_B17, _regLt); + createRegister(ARM64_REG_B18, _regLt); + createRegister(ARM64_REG_B19, _regLt); + createRegister(ARM64_REG_B20, _regLt); + createRegister(ARM64_REG_B21, _regLt); + createRegister(ARM64_REG_B22, _regLt); + createRegister(ARM64_REG_B23, _regLt); + createRegister(ARM64_REG_B24, _regLt); + createRegister(ARM64_REG_B25, _regLt); + createRegister(ARM64_REG_B26, _regLt); + createRegister(ARM64_REG_B27, _regLt); + createRegister(ARM64_REG_B28, _regLt); + createRegister(ARM64_REG_B29, _regLt); + createRegister(ARM64_REG_B30, _regLt); + createRegister(ARM64_REG_B31, _regLt); + + // General purpose registers + createRegister(ARM64_REG_X0, _regLt); + createRegister(ARM64_REG_X1, _regLt); + createRegister(ARM64_REG_X2, _regLt); + createRegister(ARM64_REG_X3, _regLt); + createRegister(ARM64_REG_X4, _regLt); + createRegister(ARM64_REG_X5, _regLt); + createRegister(ARM64_REG_X6, _regLt); + createRegister(ARM64_REG_X7, _regLt); + createRegister(ARM64_REG_X8, _regLt); + createRegister(ARM64_REG_X9, _regLt); + createRegister(ARM64_REG_X10, _regLt); + createRegister(ARM64_REG_X11, _regLt); + createRegister(ARM64_REG_X12, _regLt); + createRegister(ARM64_REG_X13, _regLt); + createRegister(ARM64_REG_X14, _regLt); + createRegister(ARM64_REG_X15, _regLt); + createRegister(ARM64_REG_X16, _regLt); + createRegister(ARM64_REG_X17, _regLt); + createRegister(ARM64_REG_X18, _regLt); + createRegister(ARM64_REG_X19, _regLt); + createRegister(ARM64_REG_X20, _regLt); + createRegister(ARM64_REG_X21, _regLt); + createRegister(ARM64_REG_X22, _regLt); + createRegister(ARM64_REG_X23, _regLt); + createRegister(ARM64_REG_X24, _regLt); + createRegister(ARM64_REG_X25, _regLt); + createRegister(ARM64_REG_X26, _regLt); + createRegister(ARM64_REG_X27, _regLt); + createRegister(ARM64_REG_X28, _regLt); + + // Special registers. + + // FP Frame pointer. + createRegister(ARM64_REG_X29, _regLt); + + // LP Link register. + createRegister(ARM64_REG_X30, _regLt); + + // Stack pointer. + createRegister(ARM64_REG_SP, _regLt); + createRegister(ARM64_REG_WSP, _regLt); + + // Zero. + createRegister(ARM64_REG_XZR, _regLt); + createRegister(ARM64_REG_WZR, _regLt); + + // Flags. + createRegister(ARM64_REG_CPSR_N, _regLt); + createRegister(ARM64_REG_CPSR_Z, _regLt); + createRegister(ARM64_REG_CPSR_C, _regLt); + createRegister(ARM64_REG_CPSR_V, _regLt); + + // Program counter. + createRegister(ARM64_REG_PC, _regLt); + } uint32_t Capstone2LlvmIrTranslatorArm64_impl::getCarryRegister() @@ -121,7 +339,13 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( uint32_t Capstone2LlvmIrTranslatorArm64_impl::getParentRegister(uint32_t r) const { - return r < _reg2parentMap.size() ? _reg2parentMap[r] : r; + try { + return _reg2parentMap.at(r); + } + catch (std::out_of_range &e) + { + return r; + } } // @@ -490,6 +714,10 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadOp( } case ARM64_OP_FP: + { + auto* val = llvm::ConstantFP::get(irb.getDoubleTy(), op.fp); + return val; //generateOperandShift(irb, op, val); + } case ARM64_OP_INVALID: case ARM64_OP_CIMM: case ARM64_OP_REG_MRS: @@ -522,7 +750,7 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeRegister( // TODO: Check? } - auto* rt = getRegisterType(r); + //auto* rt = getRegisterType(r); auto pr = getParentRegister(r); auto* llvmReg = getRegister(pr); if (llvmReg == nullptr) @@ -532,39 +760,7 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeRegister( val = generateTypeConversion(irb, val, llvmReg->getValueType(), ct); - llvm::StoreInst* ret = nullptr; - if (r == pr - // Zext for 64-bit target llvmRegs & 32-bit source regs. - || (getRegisterBitSize(pr) == 64 && getRegisterBitSize(r) == 32)) - { - ret = irb.CreateStore(val, llvmReg); - } - else - { - llvm::Value* l = irb.CreateLoad(llvmReg); - if (!(l->getType()->isIntegerTy(16) - || l->getType()->isIntegerTy(32) - || l->getType()->isIntegerTy(64))) - { - throw GenericError("Unexpected parent type."); - } - - llvm::Value* andC = nullptr; - if (rt->isIntegerTy(32)) - { - if (l->getType()->isIntegerTy(64)) - { - andC = irb.getInt64(0xffffffff00000000); - } - } - assert(andC); - l = irb.CreateAnd(l, andC); - - auto* o = irb.CreateOr(l, val); - ret = irb.CreateStore(o, llvmReg); - } - - return ret; + return irb.CreateStore(val, llvmReg); } llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeOp( @@ -1308,7 +1504,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateAnd(cs_insn* i, cs_arm64* ai, } /** - * ARM64_INS_ASR + * ARM64_INS_ASR, ARM64_INS_LSL, ARM64_INS_LSR, ARM64_INS_ROR */ void Capstone2LlvmIrTranslatorArm64_impl::translateShifts(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1320,7 +1516,6 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateShifts(cs_insn* i, cs_arm64* llvm::Value* val = nullptr; switch(i->id) { - // TODO: Other shifts case ARM64_INS_ASR: { val = irb.CreateAShr(op1, op2); @@ -2062,5 +2257,165 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateRev(cs_insn* i, cs_arm64* ai, storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_FADD + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + op2 = loadOp(ai->operands[2], irb); + + auto *val = irb.CreateFAdd(op1, op2); + storeOp(ai->operands[0], val, irb); +} + +/** + * ARM64_INS_FCSEL + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFCsel(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + op2 = loadOp(ai->operands[2], irb); + + auto* cond = generateInsnConditionCode(irb, ai); + auto* val = irb.CreateSelect(cond, op1, op2); + + storeOp(ai->operands[0], val, irb); +} + +/** + * ARM64_INS_FDIV + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFDiv(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + op2 = loadOp(ai->operands[2], irb); + + auto *val = irb.CreateFDiv(op1, op2); + storeOp(ai->operands[0], val, irb); +} + +/** + * ARM64_INS_FMADD, ARM64_INS_FNMADD + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFMadd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_QUATERNARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + op2 = loadOp(ai->operands[2], irb); + op3 = loadOp(ai->operands[3], irb); + + auto *val = irb.CreateFMul(op1, op2); + val = irb.CreateFAdd(op3, val); + if (i->id == ARM64_INS_FNMADD) + { + val = irb.CreateFNeg(val); + } + storeOp(ai->operands[0], val, irb); +} + +/** + * ARM64_INS_FMOV + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + op1 = irb.CreateBitCast(op1, getRegisterType(ai->operands[0].reg)); + + storeOp(ai->operands[0], op1, irb); +} + +/** + * ARM64_INS_FMUL, ARM64_INS_FNMUL + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + op2 = loadOp(ai->operands[2], irb); + + auto *val = irb.CreateFMul(op1, op2); + if (i->id == ARM64_INS_FNMUL) + { + val = irb.CreateFNeg(val); + } + storeOp(ai->operands[0], val, irb); +} + +/** + * ARM64_INS_FMSUB, ARM64_INS_FNMSUB + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFMsub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_QUATERNARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + op2 = loadOp(ai->operands[2], irb); + op3 = loadOp(ai->operands[3], irb); + + auto *val = irb.CreateFMul(op1, op2); + val = irb.CreateFSub(op3, val); + if (i->id == ARM64_INS_FNMSUB) + { + val = irb.CreateFNeg(val); + } + storeOp(ai->operands[0], val, irb); +} + +/** + * ARM64_INS_FSUB + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + op2 = loadOp(ai->operands[2], irb); + + auto *val = irb.CreateFSub(op1, op2); + storeOp(ai->operands[0], val, irb); +} + +/** + * ARM64_INS_FNEG, ARM64_INS_FABS, ARM64_INS_FSQRT + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFUnaryOp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + + llvm::Value* val = nullptr; + llvm::Function* intrinsic = nullptr; + switch(i->id) + { + case ARM64_INS_FNEG: + val = irb.CreateFNeg(op1); + break; + case ARM64_INS_FABS: + intrinsic = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::fabs, op1->getType()); + val = irb.CreateCall(intrinsic, {op1}); + break; + case ARM64_INS_FSQRT: + intrinsic = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::sqrt, op1->getType()); + val = irb.CreateCall(intrinsic, {op1}); + break; + default: + throw GenericError("Arm64: translateFUnary(): Unsupported instruction id"); + } + + storeOp(ai->operands[0], val, irb); +} + } // namespace capstone2llvmir } // namespace retdec diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 2dfe5c886..5be2ea9ed 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -155,7 +155,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : // protected: - std::vector _reg2parentMap; + std::map _reg2parentMap; static std::map< std::size_t, @@ -207,6 +207,16 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateRet(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateRev(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + // FP - instructions + void translateFAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFCsel(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFDiv(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFMadd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFMsub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFUnaryOp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); }; } // namespace capstone2llvmir diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 6c7424feb..558ef1242 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -37,42 +37,51 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializeRegNameMap() void Capstone2LlvmIrTranslatorArm64_impl::initializeRegTypeMap() { auto* i1 = llvm::IntegerType::getInt1Ty(_module->getContext()); + auto* i8 = llvm::IntegerType::getInt8Ty(_module->getContext()); + //auto* i16 = llvm::IntegerType::getInt16Ty(_module->getContext()); auto* i32 = llvm::IntegerType::getInt32Ty(_module->getContext()); - auto* defTy = getDefaultType(); + auto* i64 = llvm::IntegerType::getInt64Ty(_module->getContext()); + //auto* i128 = llvm::IntegerType::getInt128Ty(_module->getContext()); + + auto* f16 = llvm::Type::getHalfTy(_module->getContext()); + auto* f32 = llvm::Type::getFloatTy(_module->getContext()); + auto* f64 = llvm::Type::getDoubleTy(_module->getContext()); + auto* f128 = llvm::Type::getFP128Ty(_module->getContext()); + std::map r2t = { // General purpose registers. // - {ARM64_REG_X0, defTy}, - {ARM64_REG_X1, defTy}, - {ARM64_REG_X2, defTy}, - {ARM64_REG_X3, defTy}, - {ARM64_REG_X4, defTy}, - {ARM64_REG_X5, defTy}, - {ARM64_REG_X6, defTy}, - {ARM64_REG_X7, defTy}, - {ARM64_REG_X8, defTy}, - {ARM64_REG_X9, defTy}, - {ARM64_REG_X10, defTy}, - {ARM64_REG_X11, defTy}, - {ARM64_REG_X12, defTy}, - {ARM64_REG_X13, defTy}, - {ARM64_REG_X14, defTy}, - {ARM64_REG_X15, defTy}, - {ARM64_REG_X16, defTy}, - {ARM64_REG_X17, defTy}, - {ARM64_REG_X18, defTy}, - {ARM64_REG_X19, defTy}, - {ARM64_REG_X20, defTy}, - {ARM64_REG_X21, defTy}, - {ARM64_REG_X22, defTy}, - {ARM64_REG_X23, defTy}, - {ARM64_REG_X24, defTy}, - {ARM64_REG_X25, defTy}, - {ARM64_REG_X26, defTy}, - {ARM64_REG_X27, defTy}, - {ARM64_REG_X28, defTy}, + {ARM64_REG_X0, i64}, + {ARM64_REG_X1, i64}, + {ARM64_REG_X2, i64}, + {ARM64_REG_X3, i64}, + {ARM64_REG_X4, i64}, + {ARM64_REG_X5, i64}, + {ARM64_REG_X6, i64}, + {ARM64_REG_X7, i64}, + {ARM64_REG_X8, i64}, + {ARM64_REG_X9, i64}, + {ARM64_REG_X10, i64}, + {ARM64_REG_X11, i64}, + {ARM64_REG_X12, i64}, + {ARM64_REG_X13, i64}, + {ARM64_REG_X14, i64}, + {ARM64_REG_X15, i64}, + {ARM64_REG_X16, i64}, + {ARM64_REG_X17, i64}, + {ARM64_REG_X18, i64}, + {ARM64_REG_X19, i64}, + {ARM64_REG_X20, i64}, + {ARM64_REG_X21, i64}, + {ARM64_REG_X22, i64}, + {ARM64_REG_X23, i64}, + {ARM64_REG_X24, i64}, + {ARM64_REG_X25, i64}, + {ARM64_REG_X26, i64}, + {ARM64_REG_X27, i64}, + {ARM64_REG_X28, i64}, // Lower 32 bits of 64{xN} regs // @@ -108,20 +117,186 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializeRegTypeMap() {ARM64_REG_W29, i32}, {ARM64_REG_W30, i32}, + // FP&SIMD Regs + // + {ARM64_REG_Q0, f128}, + {ARM64_REG_Q1, f128}, + {ARM64_REG_Q2, f128}, + {ARM64_REG_Q3, f128}, + {ARM64_REG_Q4, f128}, + {ARM64_REG_Q5, f128}, + {ARM64_REG_Q6, f128}, + {ARM64_REG_Q7, f128}, + {ARM64_REG_Q8, f128}, + {ARM64_REG_Q9, f128}, + {ARM64_REG_Q10, f128}, + {ARM64_REG_Q11, f128}, + {ARM64_REG_Q12, f128}, + {ARM64_REG_Q13, f128}, + {ARM64_REG_Q14, f128}, + {ARM64_REG_Q15, f128}, + {ARM64_REG_Q16, f128}, + {ARM64_REG_Q17, f128}, + {ARM64_REG_Q18, f128}, + {ARM64_REG_Q19, f128}, + {ARM64_REG_Q20, f128}, + {ARM64_REG_Q21, f128}, + {ARM64_REG_Q22, f128}, + {ARM64_REG_Q23, f128}, + {ARM64_REG_Q24, f128}, + {ARM64_REG_Q25, f128}, + {ARM64_REG_Q26, f128}, + {ARM64_REG_Q27, f128}, + {ARM64_REG_Q28, f128}, + {ARM64_REG_Q29, f128}, + {ARM64_REG_Q30, f128}, + {ARM64_REG_Q31, f128}, + + {ARM64_REG_D0, f64}, + {ARM64_REG_D1, f64}, + {ARM64_REG_D2, f64}, + {ARM64_REG_D3, f64}, + {ARM64_REG_D4, f64}, + {ARM64_REG_D5, f64}, + {ARM64_REG_D6, f64}, + {ARM64_REG_D7, f64}, + {ARM64_REG_D8, f64}, + {ARM64_REG_D9, f64}, + {ARM64_REG_D10, f64}, + {ARM64_REG_D11, f64}, + {ARM64_REG_D12, f64}, + {ARM64_REG_D13, f64}, + {ARM64_REG_D14, f64}, + {ARM64_REG_D15, f64}, + {ARM64_REG_D16, f64}, + {ARM64_REG_D17, f64}, + {ARM64_REG_D18, f64}, + {ARM64_REG_D19, f64}, + {ARM64_REG_D20, f64}, + {ARM64_REG_D21, f64}, + {ARM64_REG_D22, f64}, + {ARM64_REG_D23, f64}, + {ARM64_REG_D24, f64}, + {ARM64_REG_D25, f64}, + {ARM64_REG_D26, f64}, + {ARM64_REG_D27, f64}, + {ARM64_REG_D28, f64}, + {ARM64_REG_D29, f64}, + {ARM64_REG_D30, f64}, + {ARM64_REG_D31, f64}, + + {ARM64_REG_S0, f32}, + {ARM64_REG_S1, f32}, + {ARM64_REG_S2, f32}, + {ARM64_REG_S3, f32}, + {ARM64_REG_S4, f32}, + {ARM64_REG_S5, f32}, + {ARM64_REG_S6, f32}, + {ARM64_REG_S7, f32}, + {ARM64_REG_S8, f32}, + {ARM64_REG_S9, f32}, + {ARM64_REG_S10, f32}, + {ARM64_REG_S11, f32}, + {ARM64_REG_S12, f32}, + {ARM64_REG_S13, f32}, + {ARM64_REG_S14, f32}, + {ARM64_REG_S15, f32}, + {ARM64_REG_S16, f32}, + {ARM64_REG_S17, f32}, + {ARM64_REG_S18, f32}, + {ARM64_REG_S19, f32}, + {ARM64_REG_S20, f32}, + {ARM64_REG_S21, f32}, + {ARM64_REG_S22, f32}, + {ARM64_REG_S23, f32}, + {ARM64_REG_S24, f32}, + {ARM64_REG_S25, f32}, + {ARM64_REG_S26, f32}, + {ARM64_REG_S27, f32}, + {ARM64_REG_S28, f32}, + {ARM64_REG_S29, f32}, + {ARM64_REG_S30, f32}, + {ARM64_REG_S31, f32}, + + {ARM64_REG_H0, f16}, + {ARM64_REG_H1, f16}, + {ARM64_REG_H2, f16}, + {ARM64_REG_H3, f16}, + {ARM64_REG_H4, f16}, + {ARM64_REG_H5, f16}, + {ARM64_REG_H6, f16}, + {ARM64_REG_H7, f16}, + {ARM64_REG_H8, f16}, + {ARM64_REG_H9, f16}, + {ARM64_REG_H10, f16}, + {ARM64_REG_H11, f16}, + {ARM64_REG_H12, f16}, + {ARM64_REG_H13, f16}, + {ARM64_REG_H14, f16}, + {ARM64_REG_H15, f16}, + {ARM64_REG_H16, f16}, + {ARM64_REG_H17, f16}, + {ARM64_REG_H18, f16}, + {ARM64_REG_H19, f16}, + {ARM64_REG_H20, f16}, + {ARM64_REG_H21, f16}, + {ARM64_REG_H22, f16}, + {ARM64_REG_H23, f16}, + {ARM64_REG_H24, f16}, + {ARM64_REG_H25, f16}, + {ARM64_REG_H26, f16}, + {ARM64_REG_H27, f16}, + {ARM64_REG_H28, f16}, + {ARM64_REG_H29, f16}, + {ARM64_REG_H30, f16}, + {ARM64_REG_H31, f16}, + + {ARM64_REG_B0, i8}, + {ARM64_REG_B1, i8}, + {ARM64_REG_B2, i8}, + {ARM64_REG_B3, i8}, + {ARM64_REG_B4, i8}, + {ARM64_REG_B5, i8}, + {ARM64_REG_B6, i8}, + {ARM64_REG_B7, i8}, + {ARM64_REG_B8, i8}, + {ARM64_REG_B9, i8}, + {ARM64_REG_B10, i8}, + {ARM64_REG_B11, i8}, + {ARM64_REG_B12, i8}, + {ARM64_REG_B13, i8}, + {ARM64_REG_B14, i8}, + {ARM64_REG_B15, i8}, + {ARM64_REG_B17, i8}, + {ARM64_REG_B18, i8}, + {ARM64_REG_B19, i8}, + {ARM64_REG_B20, i8}, + {ARM64_REG_B21, i8}, + {ARM64_REG_B22, i8}, + {ARM64_REG_B23, i8}, + {ARM64_REG_B24, i8}, + {ARM64_REG_B25, i8}, + {ARM64_REG_B26, i8}, + {ARM64_REG_B27, i8}, + {ARM64_REG_B28, i8}, + {ARM64_REG_B29, i8}, + {ARM64_REG_B30, i8}, + {ARM64_REG_B31, i8}, + // Special registers. // FP Frame pointer - {ARM64_REG_X29, defTy}, + {ARM64_REG_X29, i64}, // LP Link register - {ARM64_REG_X30, defTy}, + {ARM64_REG_X30, i64}, // Stack pointer - {ARM64_REG_SP, defTy}, + {ARM64_REG_SP, i64}, {ARM64_REG_WSP, i32}, // Zero - {ARM64_REG_XZR, defTy}, + {ARM64_REG_XZR, i64}, {ARM64_REG_WZR, i32}, // CPSR flags. @@ -132,7 +307,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializeRegTypeMap() {ARM64_REG_CPSR_V, i1}, // Program counter. - {ARM64_REG_PC, defTy}, + {ARM64_REG_PC, i64}, }; _reg2type = std::move(r2t); @@ -172,8 +347,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializeRegistersParentMapToOther( { for (auto r : rs) { - assert(r < _reg2parentMap.size()); - _reg2parentMap[r] = other; + _reg2parentMap.insert(std::make_pair(r, other)); } } @@ -183,16 +357,17 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializeRegistersParentMap() // Last element in vector is its own parent. std::vector> rss = { - {ARM64_REG_W0, ARM64_REG_X0}, - {ARM64_REG_W1, ARM64_REG_X1}, - {ARM64_REG_W2, ARM64_REG_X2}, - {ARM64_REG_W3, ARM64_REG_X3}, - {ARM64_REG_W4, ARM64_REG_X4}, - {ARM64_REG_W5, ARM64_REG_X5}, - {ARM64_REG_W6, ARM64_REG_X6}, - {ARM64_REG_W7, ARM64_REG_X7}, - {ARM64_REG_W8, ARM64_REG_X8}, - {ARM64_REG_W9, ARM64_REG_X9}, + // 32 64 + {ARM64_REG_W0, ARM64_REG_X0}, + {ARM64_REG_W1, ARM64_REG_X1}, + {ARM64_REG_W2, ARM64_REG_X2}, + {ARM64_REG_W3, ARM64_REG_X3}, + {ARM64_REG_W4, ARM64_REG_X4}, + {ARM64_REG_W5, ARM64_REG_X5}, + {ARM64_REG_W6, ARM64_REG_X6}, + {ARM64_REG_W7, ARM64_REG_X7}, + {ARM64_REG_W8, ARM64_REG_X8}, + {ARM64_REG_W9, ARM64_REG_X9}, {ARM64_REG_W10, ARM64_REG_X10}, {ARM64_REG_W11, ARM64_REG_X11}, {ARM64_REG_W12, ARM64_REG_X12}, @@ -216,7 +391,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializeRegistersParentMap() {ARM64_REG_W30, ARM64_REG_X30}, {ARM64_REG_WSP, ARM64_REG_SP}, - {ARM64_REG_WZR, ARM64_REG_XZR} + {ARM64_REG_WZR, ARM64_REG_XZR}, }; for (std::vector& rs : rss) @@ -308,10 +483,10 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_EXTR, &Capstone2LlvmIrTranslatorArm64_impl::translateExtr}, {ARM64_INS_EXT, nullptr}, {ARM64_INS_FABD, nullptr}, - {ARM64_INS_FABS, nullptr}, + {ARM64_INS_FABS, &Capstone2LlvmIrTranslatorArm64_impl::translateFUnaryOp}, {ARM64_INS_FACGE, nullptr}, {ARM64_INS_FACGT, nullptr}, - {ARM64_INS_FADD, nullptr}, + {ARM64_INS_FADD, &Capstone2LlvmIrTranslatorArm64_impl::translateFAdd}, {ARM64_INS_FADDP, nullptr}, {ARM64_INS_FCCMP, nullptr}, {ARM64_INS_FCCMPE, nullptr}, @@ -322,7 +497,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_FCMLT, nullptr}, {ARM64_INS_FCMP, nullptr}, {ARM64_INS_FCMPE, nullptr}, - {ARM64_INS_FCSEL, nullptr}, + {ARM64_INS_FCSEL, &Capstone2LlvmIrTranslatorArm64_impl::translateFCsel}, {ARM64_INS_FCVTAS, nullptr}, {ARM64_INS_FCVTAU, nullptr}, {ARM64_INS_FCVT, nullptr}, @@ -340,8 +515,8 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_FCVTXN2, nullptr}, {ARM64_INS_FCVTZS, nullptr}, {ARM64_INS_FCVTZU, nullptr}, - {ARM64_INS_FDIV, nullptr}, - {ARM64_INS_FMADD, nullptr}, + {ARM64_INS_FDIV, &Capstone2LlvmIrTranslatorArm64_impl::translateFDiv}, + {ARM64_INS_FMADD, &Capstone2LlvmIrTranslatorArm64_impl::translateFMadd}, {ARM64_INS_FMAX, nullptr}, {ARM64_INS_FMAXNM, nullptr}, {ARM64_INS_FMAXNMP, nullptr}, @@ -356,14 +531,14 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_FMINV, nullptr}, {ARM64_INS_FMLA, nullptr}, {ARM64_INS_FMLS, nullptr}, - {ARM64_INS_FMOV, nullptr}, - {ARM64_INS_FMSUB, nullptr}, - {ARM64_INS_FMUL, nullptr}, + {ARM64_INS_FMOV, &Capstone2LlvmIrTranslatorArm64_impl::translateFMov}, + {ARM64_INS_FMSUB, &Capstone2LlvmIrTranslatorArm64_impl::translateFMsub}, + {ARM64_INS_FMUL, &Capstone2LlvmIrTranslatorArm64_impl::translateFMul}, {ARM64_INS_FMULX, nullptr}, - {ARM64_INS_FNEG, nullptr}, - {ARM64_INS_FNMADD, nullptr}, - {ARM64_INS_FNMSUB, nullptr}, - {ARM64_INS_FNMUL, nullptr}, + {ARM64_INS_FNEG, &Capstone2LlvmIrTranslatorArm64_impl::translateFUnaryOp}, + {ARM64_INS_FNMADD, &Capstone2LlvmIrTranslatorArm64_impl::translateFMadd}, + {ARM64_INS_FNMSUB, &Capstone2LlvmIrTranslatorArm64_impl::translateFMsub}, + {ARM64_INS_FNMUL, &Capstone2LlvmIrTranslatorArm64_impl::translateFMul}, {ARM64_INS_FRECPE, nullptr}, {ARM64_INS_FRECPS, nullptr}, {ARM64_INS_FRECPX, nullptr}, @@ -376,8 +551,8 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_FRINTZ, nullptr}, {ARM64_INS_FRSQRTE, nullptr}, {ARM64_INS_FRSQRTS, nullptr}, - {ARM64_INS_FSQRT, nullptr}, - {ARM64_INS_FSUB, nullptr}, + {ARM64_INS_FSQRT, &Capstone2LlvmIrTranslatorArm64_impl::translateFUnaryOp}, + {ARM64_INS_FSUB, &Capstone2LlvmIrTranslatorArm64_impl::translateFSub}, {ARM64_INS_HINT, nullptr}, {ARM64_INS_HLT, nullptr}, {ARM64_INS_HVC, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 57c9d56b9..785d228e8 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -6316,6 +6316,806 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_REV32_r_r) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_FABS +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FABS_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 40.42_f32}, + }); + + emulate("fabs s0, s1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, ANY}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_VALUES_CALLED({ + {_module.getFunction("llvm.fabs.f32"), {40.42_f32}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FABS_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 42.40_f64}, + }); + + emulate("fabs d0, d1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, ANY}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_VALUES_CALLED({ + {_module.getFunction("llvm.fabs.f64"), {42.40_f64}}, + }); +} + +// +// ARM64_INS_FADD +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FADD_s_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 100.5_f32}, + {ARM64_REG_S2, 3.141592_f32}, + }); + + emulate("fadd s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 103.641594_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FADD_d_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 0.141592141592141592141592_f64}, + {ARM64_REG_D2, 3.141592_f64}, + }); + + emulate("fadd d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 3.2831841415921419_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FADD_s_s_s_neg) +{ + setRegisters({ + {ARM64_REG_S1, 100.5_f32}, + {ARM64_REG_S2, static_cast(-3.141592)}, + }); + + emulate("fadd s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 97.3584061_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FADD_d_d_d_neg) +{ + setRegisters({ + {ARM64_REG_D1, 0.141592141592141592141592_f64}, + {ARM64_REG_D2, static_cast(-3.141592)}, + }); + + emulate("fadd d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, static_cast(-2.9999998584078584)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_FCSEL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCSEL_true) +{ + setRegisters({ + {ARM64_REG_D1, 3.141592_f64}, + {ARM64_REG_D2, 12.34567_f64}, + {ARM64_REG_CPSR_Z, false}, + }); + + emulate("fcsel d0, d1, d2, ne"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 3.141592_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCSEL_false) +{ + setRegisters({ + {ARM64_REG_D1, 3.141592_f64}, + {ARM64_REG_D2, 12.34567_f64}, + {ARM64_REG_CPSR_V, false}, + }); + + emulate("fcsel d0, d1, d2, vs"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2, ARM64_REG_CPSR_V}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 12.34567_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCSEL32_true) +{ + setRegisters({ + {ARM64_REG_S1, 3.141592_f64}, + {ARM64_REG_S2, 12.34567_f64}, + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_V, true}, + }); + + emulate("fcsel s0, s1, s2, lt"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2, + ARM64_REG_CPSR_N, ARM64_REG_CPSR_V}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 3.141592_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_FDIV +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FDIV_s_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 100.5_f32}, + {ARM64_REG_S2, 3.141592_f32}, + }); + + emulate("fdiv s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 31.9901524_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FDIV_d_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 0.141592141592141592141592_f64}, + {ARM64_REG_D2, 3.141592_f64}, + }); + + emulate("fdiv d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 0.045070187851300098_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FDIV_s_s_s_neg) +{ + setRegisters({ + {ARM64_REG_S1, 100.5_f32}, + {ARM64_REG_S2, static_cast(-3.141592)}, + }); + + emulate("fdiv s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, static_cast(-31.9901524)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FDIV_d_d_d_neg) +{ + setRegisters({ + {ARM64_REG_D1, 0.141592141592141592141592_f64}, + {ARM64_REG_D2, static_cast(-3.141592)}, + }); + + emulate("fdiv d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, static_cast(-0.045070187851300098)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_FMADD +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMADD_s_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 60.58365_f32}, + {ARM64_REG_S2, static_cast(-0.320193)}, + {ARM64_REG_S3, 100.2383073_f32}, + }); + + emulate("fmadd s0, s1, s2, s3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2, ARM64_REG_S3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 80.8398438_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMADD_d_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 123.62345_f64}, + {ARM64_REG_D2, static_cast(-563.24683)}, + {ARM64_REG_D3, 863.246983963_f64}, + }); + + emulate("fmadd d0, d1, d2, d3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2, ARM64_REG_D3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, static_cast(-68767.26934220051)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_FNMADD +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FNMADD_s_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 60.58365_f32}, + {ARM64_REG_S2, static_cast(-0.320193)}, + {ARM64_REG_S3, 100.2383073_f32}, + }); + + emulate("fnmadd s0, s1, s2, s3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2, ARM64_REG_S3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, static_cast(-80.8398438)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FNMADD_d_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 123.62345_f64}, + {ARM64_REG_D2, static_cast(-563.24683)}, + {ARM64_REG_D3, 863.246983963_f64}, + }); + + emulate("fnmadd d0, d1, d2, d3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2, ARM64_REG_D3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 68767.26934220051_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_FMOV +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMOV_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 3.141592_f32}, + }); + + emulate("fmov s0, s1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 3.141592_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMOV_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 3.141592_f64}, + }); + + emulate("fmov d0, d1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 3.141592_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMOV_s_w) +{ + setRegisters({ + {ARM64_REG_W1, 0x12345678}, + }); + + emulate("fmov s0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 5.69045661e-28_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMOV_w_s) +{ + setRegisters({ + {ARM64_REG_S1, 5.69045661e-28_f32}, + }); + + emulate("fmov w0, s1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_W0, 0x12345678}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMOV_x_d) +{ + setRegisters({ + {ARM64_REG_X1, 0x1234567890abcdef}, + }); + + emulate("fmov d0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 5.6263491089085159e-221_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMOV_d_x) +{ + setRegisters({ + {ARM64_REG_D1, 5.6263491089085159e-221_f64}, + }); + + emulate("fmov x0, d1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x1234567890abcdef}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_FMUL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMUL_s_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 100.5_f32}, + {ARM64_REG_S2, 3.141592_f32}, + }); + + emulate("fmul s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 315.72998_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMUL_d_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 0.141592141592141592141592_f64}, + {ARM64_REG_D2, 3.141592_f64}, + }); + + emulate("fmul d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 0.44482473928873928_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMUL_s_s_s_neg) +{ + setRegisters({ + {ARM64_REG_S1, 100.5_f32}, + {ARM64_REG_S2, static_cast(-3.141592)}, + }); + + emulate("fmul s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, static_cast(-315.72998)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMUL_d_d_d_neg) +{ + setRegisters({ + {ARM64_REG_D1, 0.141592141592141592141592_f64}, + {ARM64_REG_D2, static_cast(-3.141592)}, + }); + + emulate("fmul d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, static_cast(-0.44482473928873928)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_FNEG +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FNEG_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 3.141592_f32}, + }); + + emulate("fneg s0, s1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, static_cast(-3.141592)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FNEG_s_s_1) +{ + setRegisters({ + {ARM64_REG_S1, static_cast(-3.141592)}, + }); + + emulate("fneg s0, s1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 3.141592_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_FMSUB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMSUB_s_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 60.58365_f32}, + {ARM64_REG_S2, static_cast(-0.320193)}, + {ARM64_REG_S3, 100.2383073_f32}, + }); + + emulate("fmsub s0, s1, s2, s3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2, ARM64_REG_S3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 119.636765_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMSUB_d_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 123.62345_f64}, + {ARM64_REG_D2, static_cast(-563.24683)}, + {ARM64_REG_D3, 863.246983963_f64}, + }); + + emulate("fmsub d0, d1, d2, d3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2, ARM64_REG_D3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 70493.763310126509_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_FNMSUB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FNMSUB_s_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 60.58365_f32}, + {ARM64_REG_S2, static_cast(-0.320193)}, + {ARM64_REG_S3, 100.2383073_f32}, + }); + + emulate("fnmsub s0, s1, s2, s3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2, ARM64_REG_S3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, static_cast(-119.636765)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FNMSUB_d_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 123.62345_f64}, + {ARM64_REG_D2, static_cast(-563.24683)}, + {ARM64_REG_D3, 863.246983963_f64}, + }); + + emulate("fnmsub d0, d1, d2, d3"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2, ARM64_REG_D3}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, static_cast(-70493.763310126509)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_FNMUL +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FNMUL_s_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 100.5_f32}, + {ARM64_REG_S2, 3.141592_f32}, + }); + + emulate("fnmul s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, static_cast(-315.72998)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FNMUL_d_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 0.141592141592141592141592_f64}, + {ARM64_REG_D2, 3.141592_f64}, + }); + + emulate("fnmul d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, static_cast(-0.44482473928873928)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FNMUL_s_s_s_neg) +{ + setRegisters({ + {ARM64_REG_S1, 100.5_f32}, + {ARM64_REG_S2, static_cast(-3.141592)}, + }); + + emulate("fnmul s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 315.72998_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FNMUL_d_d_d_neg) +{ + setRegisters({ + {ARM64_REG_D1, 0.141592141592141592141592_f64}, + {ARM64_REG_D2, static_cast(-3.141592)}, + }); + + emulate("fnmul d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 0.44482473928873928_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_FSUB +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FSUB_s_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 100.5_f32}, + {ARM64_REG_S2, 3.141592_f32}, + }); + + emulate("fsub s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 97.3584061_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FSUB_d_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 0.141592141592141592141592_f64}, + {ARM64_REG_D2, 3.141592_f64}, + }); + + emulate("fsub d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, static_cast(-2.9999998584078584)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FSUB_s_s_s_neg) +{ + setRegisters({ + {ARM64_REG_S1, 100.5_f32}, + {ARM64_REG_S2, static_cast(-3.141592)}, + }); + + emulate("fsub s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 103.641594_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FSUB_d_d_d_neg) +{ + setRegisters({ + {ARM64_REG_D1, 0.141592141592141592141592_f64}, + {ARM64_REG_D2, static_cast(-3.141592)}, + }); + + emulate("fsub d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 3.2831841415921419_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +/* TODO: Check why those tests are failing +// +// ARM64_INS_FSQRT +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FSQRT_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 40.32_f32}, + }); + + emulate("fsqrt s0, s1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, ANY}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + //EXPECT_NO_VALUE_CALLED(); + EXPECT_VALUES_CALLED({ + {_module.getFunction("llvm.fsqrt.f32"), {40.32}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FSQRT_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 32.40_f64}, + }); + + emulate("fsqrt d0, d1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, ANY}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); + //EXPECT_VALUES_CALLED({ + // {_module.getFunction("llvm.fsqrt.f64"), {32.40_f64}}, + //}); +} +*/ + } // namespace tests } // namespace capstone2llvmir } // namespace retdec From 881876cb25ed241d16050ef5f4b8b10c1c29b524 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 28 Feb 2019 20:13:59 +0100 Subject: [PATCH 089/107] Arm64: FMIN, FMINNM, FMAX, FMAXNM instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 55 ++++++ src/capstone2llvmir/arm64/arm64_impl.h | 2 + src/capstone2llvmir/arm64/arm64_init.cpp | 8 +- src/llvmir-emul/llvmir_emul.cpp | 2 + tests/capstone2llvmir/arm64_tests.cpp | 230 +++++++++++++++++++++++ 5 files changed, 293 insertions(+), 4 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index f0820a0d6..edeb15f14 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -2321,6 +2321,61 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateFMadd(cs_insn* i, cs_arm64* a storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_FMAX, ARM64_INS_FMIN + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFMinMax(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + op2 = loadOp(ai->operands[2], irb); + + llvm::Value* cond; + switch(i->id) + { + case ARM64_INS_FMIN: + cond = irb.CreateFCmpULE(op1, op2); + break; + case ARM64_INS_FMAX: + cond = irb.CreateFCmpUGE(op1, op2); + break; + default: + throw GenericError("Arm64: translateFMinMax(): Unsupported instruction id"); + } + + auto* val = irb.CreateSelect(cond, op1, op2); + storeOp(ai->operands[0], val, irb); +} + +/** + * ARM64_INS_FMAXNM, ARM64_INS_FMINNM + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFMinMaxNum(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + op2 = loadOp(ai->operands[2], irb); + + llvm::Value* val = nullptr; + llvm::Function* intrinsic = nullptr; + switch(i->id) + { + case ARM64_INS_FMINNM: + intrinsic = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::minnum, op1->getType()); + break; + case ARM64_INS_FMAXNM: + intrinsic = llvm::Intrinsic::getDeclaration(_module, llvm::Intrinsic::maxnum, op1->getType()); + break; + default: + throw GenericError("Arm64: translateFMinMaxNum(): Unsupported instruction id"); + } + + val = irb.CreateCall(intrinsic, {op1, op2}); + storeOp(ai->operands[0], val, irb); +} + /** * ARM64_INS_FMOV */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 5be2ea9ed..c9d640688 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -212,6 +212,8 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateFCsel(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFDiv(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFMadd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFMinMax(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFMinMaxNum(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFMsub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 558ef1242..e1a48b212 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -517,14 +517,14 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_FCVTZU, nullptr}, {ARM64_INS_FDIV, &Capstone2LlvmIrTranslatorArm64_impl::translateFDiv}, {ARM64_INS_FMADD, &Capstone2LlvmIrTranslatorArm64_impl::translateFMadd}, - {ARM64_INS_FMAX, nullptr}, - {ARM64_INS_FMAXNM, nullptr}, + {ARM64_INS_FMAX, &Capstone2LlvmIrTranslatorArm64_impl::translateFMinMax}, + {ARM64_INS_FMAXNM, &Capstone2LlvmIrTranslatorArm64_impl::translateFMinMaxNum}, {ARM64_INS_FMAXNMP, nullptr}, {ARM64_INS_FMAXNMV, nullptr}, {ARM64_INS_FMAXP, nullptr}, {ARM64_INS_FMAXV, nullptr}, - {ARM64_INS_FMIN, nullptr}, - {ARM64_INS_FMINNM, nullptr}, + {ARM64_INS_FMIN, &Capstone2LlvmIrTranslatorArm64_impl::translateFMinMax}, + {ARM64_INS_FMINNM, &Capstone2LlvmIrTranslatorArm64_impl::translateFMinMaxNum}, {ARM64_INS_FMINNMP, nullptr}, {ARM64_INS_FMINNMV, nullptr}, {ARM64_INS_FMINP, nullptr}, diff --git a/src/llvmir-emul/llvmir_emul.cpp b/src/llvmir-emul/llvmir_emul.cpp index b00ade6ed..2daa3ac8d 100644 --- a/src/llvmir-emul/llvmir_emul.cpp +++ b/src/llvmir-emul/llvmir_emul.cpp @@ -3059,6 +3059,8 @@ void LlvmIrEmulator::visitCallInst(llvm::CallInst& I) auto* cf = I.getCalledFunction(); if (cf && cf->isDeclaration() && cf->isIntrinsic() && !(cf->getIntrinsicID() == Intrinsic::bitreverse + || cf->getIntrinsicID() == Intrinsic::maxnum + || cf->getIntrinsicID() == Intrinsic::minnum || cf->getIntrinsicID() == Intrinsic::fabs)) // can not lower those functions { assert(cf->getIntrinsicID() != Intrinsic::vastart diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 785d228e8..09ecf84f5 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -6640,6 +6640,236 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FNMADD_d_d_d) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_FMAX +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMAX_d_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 3.141592_f64}, + {ARM64_REG_D2, 12.34567_f64}, + }); + + emulate("fmax d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 12.34567_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMAX_d_d_d_1) +{ + setRegisters({ + {ARM64_REG_D1, 3.141592_f64}, + {ARM64_REG_D2, static_cast(-12.34567)}, + }); + + emulate("fmax d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 3.141592_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMAX_s_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 3.141592_f32}, + {ARM64_REG_S2, 12.34567_f32}, + }); + + emulate("fmax s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 12.34567_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMAX_s_s_s_1) +{ + setRegisters({ + {ARM64_REG_S1, 3.141592_f32}, + {ARM64_REG_S2, static_cast(-12.34567)}, + }); + + emulate("fmax s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 3.141592_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_FMAXNM +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMAXNM_d_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 3.141592_f64}, + {ARM64_REG_D2, 12.34567_f64}, + }); + + emulate("fmaxnm d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, ANY}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_VALUES_CALLED({ + {_module.getFunction("llvm.maxnum.f64"), {3.141592_f64, 12.34567_f64}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMAXNM_s_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 3.141592_f32}, + {ARM64_REG_S2, 12.34567_f32}, + }); + + emulate("fmaxnm s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, ANY}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_VALUES_CALLED({ + {_module.getFunction("llvm.maxnum.f32"), {3.141592_f32, 12.34567_f32}}, + }); +} + +// +// ARM64_INS_FMIN +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMIN_d_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 3.141592_f64}, + {ARM64_REG_D2, 12.34567_f64}, + }); + + emulate("fmin d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 3.141592_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMIN_d_d_d_1) +{ + setRegisters({ + {ARM64_REG_D1, 3.141592_f64}, + {ARM64_REG_D2, static_cast(-12.34567)}, + }); + + emulate("fmin d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, static_cast(-12.34567)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMIN_s_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 3.141592_f32}, + {ARM64_REG_S2, 12.34567_f32}, + }); + + emulate("fmin s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 3.141592_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMIN_s_s_s_1) +{ + setRegisters({ + {ARM64_REG_S1, 3.141592_f32}, + {ARM64_REG_S2, static_cast(-12.34567)}, + }); + + emulate("fmin s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, static_cast(-12.34567)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_FMINNM +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMINNM_d_d_d) +{ + setRegisters({ + {ARM64_REG_D1, 3.141592_f64}, + {ARM64_REG_D2, 12.34567_f64}, + }); + + emulate("fminnm d0, d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, ANY}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_VALUES_CALLED({ + {_module.getFunction("llvm.minnum.f64"), {3.141592_f64, 12.34567_f64}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMINNM_s_s_s) +{ + setRegisters({ + {ARM64_REG_S1, 3.141592_f32}, + {ARM64_REG_S2, 12.34567_f32}, + }); + + emulate("fminnm s0, s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, ANY}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_VALUES_CALLED({ + {_module.getFunction("llvm.minnum.f32"), {3.141592_f32, 12.34567_f32}}, + }); +} + // // ARM64_INS_FMOV // From 35b2d355720055b89a187dcc6df906674876a551 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 1 Mar 2019 14:51:45 +0100 Subject: [PATCH 090/107] Arm64: FCMP, FCCMP, FCVT, {U, S}CVTF instructions + tests --- src/capstone2llvmir/arm64/arm64.cpp | 142 ++++++++ src/capstone2llvmir/arm64/arm64_impl.h | 4 + src/capstone2llvmir/arm64/arm64_init.cpp | 10 +- tests/capstone2llvmir/arm64_tests.cpp | 407 +++++++++++++++++++++++ 4 files changed, 558 insertions(+), 5 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index edeb15f14..ed398b82b 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -2271,6 +2271,115 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateFAdd(cs_insn* i, cs_arm64* ai storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_FCCMP + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFCCmp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_TERNARY(i, ai, irb); + + op0 = loadOp(ai->operands[0], irb); + op1 = loadOp(ai->operands[1], irb); + auto* nzvc = loadOp(ai->operands[2], irb); + + auto* cond = generateInsnConditionCode(irb, ai); + auto irbCond = generateIfThenElse(cond, irb); + llvm::IRBuilder<>& condIf(irbCond.first), condElse(irbCond.second); + + // IF condition holds + + // IF op1 == op2 + auto* fcmpOeq = condIf.CreateFCmpOEQ(op0, op1); + auto irbP = generateIfThenElse(fcmpOeq, condIf); + llvm::IRBuilder<>& bodyIf(irbP.first), bodyElse(irbP.second); + + storeRegister(ARM64_REG_CPSR_N, bodyIf.getFalse(), bodyIf); + storeRegister(ARM64_REG_CPSR_Z, bodyIf.getTrue(), bodyIf); + storeRegister(ARM64_REG_CPSR_C, bodyIf.getTrue(), bodyIf); + storeRegister(ARM64_REG_CPSR_V, bodyIf.getFalse(), bodyIf); + + // ELSE IF op1 < op2 + auto* fcmpOgt = bodyElse.CreateFCmpOGT(op0, op1); + auto irbP1 = generateIfThenElse(fcmpOgt, bodyElse); + llvm::IRBuilder<>& bodyIf1(irbP1.first), bodyElse1(irbP1.second); + + storeRegister(ARM64_REG_CPSR_N, bodyIf1.getTrue(), bodyIf1); + storeRegister(ARM64_REG_CPSR_Z, bodyIf1.getFalse(), bodyIf1); + storeRegister(ARM64_REG_CPSR_C, bodyIf1.getFalse(), bodyIf1); + storeRegister(ARM64_REG_CPSR_V, bodyIf1.getFalse(), bodyIf1); + + // ELSE IF op1 > op2 + auto* fcmpOlt = bodyElse1.CreateFCmpOLT(op0, op1); + auto irbP2 = generateIfThenElse(fcmpOlt, bodyElse1); + llvm::IRBuilder<>& bodyIf2(irbP2.first), bodyElse2(irbP2.second); + + storeRegister(ARM64_REG_CPSR_N, bodyIf2.getFalse(), bodyIf2); + storeRegister(ARM64_REG_CPSR_Z, bodyIf2.getFalse(), bodyIf2); + storeRegister(ARM64_REG_CPSR_C, bodyIf2.getTrue(), bodyIf2); + storeRegister(ARM64_REG_CPSR_V, bodyIf2.getFalse(), bodyIf2); + + // ELSE - NAN + storeRegister(ARM64_REG_CPSR_N, bodyElse2.getFalse(), bodyElse2); + storeRegister(ARM64_REG_CPSR_Z, bodyElse2.getFalse(), bodyElse2); + storeRegister(ARM64_REG_CPSR_C, bodyElse2.getTrue(), bodyElse2); + storeRegister(ARM64_REG_CPSR_V, bodyElse2.getTrue(), bodyElse2); + + //ELSE - Set the flags from IMM + // We only use shifts because the final value to be stored is truncated to i1. + storeRegister(ARM64_REG_CPSR_N, bodyElse.CreateLShr(nzvc, llvm::ConstantInt::get(nzvc->getType(), 3)), condElse); + storeRegister(ARM64_REG_CPSR_Z, bodyElse.CreateLShr(nzvc, llvm::ConstantInt::get(nzvc->getType(), 2)), condElse); + storeRegister(ARM64_REG_CPSR_C, bodyElse.CreateLShr(nzvc, llvm::ConstantInt::get(nzvc->getType(), 1)), condElse); + storeRegister(ARM64_REG_CPSR_V, nzvc, condElse); + +} + +/** + * ARM64_INS_FCMP + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFCmp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + op0 = loadOp(ai->operands[0], irb); + op1 = loadOp(ai->operands[1], irb); + + // IF op1 == op2 + auto* fcmpOeq = irb.CreateFCmpOEQ(op0, op1); + auto irbP = generateIfThenElse(fcmpOeq, irb); + llvm::IRBuilder<>& bodyIf(irbP.first), bodyElse(irbP.second); + + storeRegister(ARM64_REG_CPSR_N, bodyIf.getFalse(), bodyIf); + storeRegister(ARM64_REG_CPSR_Z, bodyIf.getTrue(), bodyIf); + storeRegister(ARM64_REG_CPSR_C, bodyIf.getTrue(), bodyIf); + storeRegister(ARM64_REG_CPSR_V, bodyIf.getFalse(), bodyIf); + + // ELSE IF op1 < op2 + auto* fcmpOgt = bodyElse.CreateFCmpOGT(op0, op1); + auto irbP1 = generateIfThenElse(fcmpOgt, bodyElse); + llvm::IRBuilder<>& bodyIf1(irbP1.first), bodyElse1(irbP1.second); + + storeRegister(ARM64_REG_CPSR_N, bodyIf1.getTrue(), bodyIf1); + storeRegister(ARM64_REG_CPSR_Z, bodyIf1.getFalse(), bodyIf1); + storeRegister(ARM64_REG_CPSR_C, bodyIf1.getFalse(), bodyIf1); + storeRegister(ARM64_REG_CPSR_V, bodyIf1.getFalse(), bodyIf1); + + // ELSE IF op1 > op2 + auto* fcmpOlt = bodyElse1.CreateFCmpOLT(op0, op1); + auto irbP2 = generateIfThenElse(fcmpOlt, bodyElse1); + llvm::IRBuilder<>& bodyIf2(irbP2.first), bodyElse2(irbP2.second); + + storeRegister(ARM64_REG_CPSR_N, bodyIf2.getFalse(), bodyIf2); + storeRegister(ARM64_REG_CPSR_Z, bodyIf2.getFalse(), bodyIf2); + storeRegister(ARM64_REG_CPSR_C, bodyIf2.getTrue(), bodyIf2); + storeRegister(ARM64_REG_CPSR_V, bodyIf2.getFalse(), bodyIf2); + + // ELSE + storeRegister(ARM64_REG_CPSR_N, bodyElse2.getFalse(), bodyElse2); + storeRegister(ARM64_REG_CPSR_Z, bodyElse2.getFalse(), bodyElse2); + storeRegister(ARM64_REG_CPSR_C, bodyElse2.getTrue(), bodyElse2); + storeRegister(ARM64_REG_CPSR_V, bodyElse2.getTrue(), bodyElse2); +} + /** * ARM64_INS_FCSEL */ @@ -2287,6 +2396,39 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateFCsel(cs_insn* i, cs_arm64* a storeOp(ai->operands[0], val, irb); } +/** + * ARM64_INS_FCVT + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFCvt(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + storeOp(ai->operands[0], op1, irb); +} + +/** + * ARM64_INS_UCVTF, ARM64_INS_SCVTF + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFCvtf(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + + switch(i->id) + { + case ARM64_INS_UCVTF: + storeOp(ai->operands[0], op1, irb, eOpConv::UITOFP); + break; + case ARM64_INS_SCVTF: + storeOp(ai->operands[0], op1, irb, eOpConv::SITOFP); + break; + default: + throw GenericError("Arm64: translateFCvtf(): Unsupported instruction id"); + } +} + /** * ARM64_INS_FDIV */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index c9d640688..bc4e8643b 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -209,7 +209,11 @@ class Capstone2LlvmIrTranslatorArm64_impl : // FP - instructions void translateFAdd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFCmp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFCCmp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFCsel(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFCvt(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFCvtf(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFDiv(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFMadd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFMinMax(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index e1a48b212..19b09e1a4 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -488,19 +488,19 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_FACGT, nullptr}, {ARM64_INS_FADD, &Capstone2LlvmIrTranslatorArm64_impl::translateFAdd}, {ARM64_INS_FADDP, nullptr}, - {ARM64_INS_FCCMP, nullptr}, + {ARM64_INS_FCCMP, &Capstone2LlvmIrTranslatorArm64_impl::translateFCCmp}, {ARM64_INS_FCCMPE, nullptr}, {ARM64_INS_FCMEQ, nullptr}, {ARM64_INS_FCMGE, nullptr}, {ARM64_INS_FCMGT, nullptr}, {ARM64_INS_FCMLE, nullptr}, {ARM64_INS_FCMLT, nullptr}, - {ARM64_INS_FCMP, nullptr}, + {ARM64_INS_FCMP, &Capstone2LlvmIrTranslatorArm64_impl::translateFCmp}, {ARM64_INS_FCMPE, nullptr}, {ARM64_INS_FCSEL, &Capstone2LlvmIrTranslatorArm64_impl::translateFCsel}, {ARM64_INS_FCVTAS, nullptr}, {ARM64_INS_FCVTAU, nullptr}, - {ARM64_INS_FCVT, nullptr}, + {ARM64_INS_FCVT, &Capstone2LlvmIrTranslatorArm64_impl::translateFCvt}, {ARM64_INS_FCVTL, nullptr}, {ARM64_INS_FCVTL2, nullptr}, {ARM64_INS_FCVTMS, nullptr}, @@ -653,7 +653,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_SADDW, nullptr}, {ARM64_INS_SBC, &Capstone2LlvmIrTranslatorArm64_impl::translateSbc}, {ARM64_INS_SBFM, nullptr}, - {ARM64_INS_SCVTF, nullptr}, + {ARM64_INS_SCVTF, &Capstone2LlvmIrTranslatorArm64_impl::translateFCvtf}, {ARM64_INS_SDIV, &Capstone2LlvmIrTranslatorArm64_impl::translateDiv}, {ARM64_INS_SHA1C, nullptr}, {ARM64_INS_SHA1H, nullptr}, @@ -784,7 +784,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_UADDW2, nullptr}, {ARM64_INS_UADDW, nullptr}, {ARM64_INS_UBFM, nullptr}, - {ARM64_INS_UCVTF, nullptr}, + {ARM64_INS_UCVTF, &Capstone2LlvmIrTranslatorArm64_impl::translateFCvtf}, {ARM64_INS_UDIV, &Capstone2LlvmIrTranslatorArm64_impl::translateDiv}, {ARM64_INS_UHADD, nullptr}, {ARM64_INS_UHSUB, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 09ecf84f5..8fb864bd1 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -6428,6 +6428,241 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FADD_d_d_d_neg) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_FCMP +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCMP_s_s_eq) +{ + setRegisters({ + {ARM64_REG_S1, 321.321_f32}, + {ARM64_REG_S2, 321.321_f32}, + }); + + emulate("fcmp s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCMP_s_s_gt) +{ + setRegisters({ + {ARM64_REG_S1, 321.321_f32}, + {ARM64_REG_S2, 123.456_f32}, + }); + + emulate("fcmp s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCMP_s_s_lt) +{ + setRegisters({ + {ARM64_REG_S1, 123.456_f32}, + {ARM64_REG_S2, 321.321_f32}, + }); + + emulate("fcmp s1, s2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCMP_d_d_eq) +{ + setRegisters({ + {ARM64_REG_D1, 321.3938216392863_f64}, + {ARM64_REG_D2, 321.3938216392863_f64}, + }); + + emulate("fcmp d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCMP_d_d_gt) +{ + setRegisters({ + {ARM64_REG_D1, 321.3938216392863_f64}, + {ARM64_REG_D2, 123.45632918321_f64}, + }); + + emulate("fcmp d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCMP_d_d_lt) +{ + setRegisters({ + {ARM64_REG_D1, 123.45632918321_f64}, + {ARM64_REG_D2, 321.3938216392863_f64}, + }); + + emulate("fcmp d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +/* TODO: Check Ordered vs Unordered +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCMP_d_d_NAN) +{ + setRegisters({ + {ARM64_REG_D1, NAN}, + {ARM64_REG_D2, NAN}, + }); + + emulate("fcmp d1, d2"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} +*/ + +// +// ARM64_INS_FCCMP +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCCMP_s_s_f_false) +{ + setRegisters({ + {ARM64_REG_S1, 321.321_f32}, + {ARM64_REG_S2, 321.321_f32}, + {ARM64_REG_CPSR_Z, false}, + }); + + emulate("fccmp s1, s2, #12, ne"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCCMP_s_s_f_true) +{ + setRegisters({ + {ARM64_REG_S1, 321.321_f32}, + {ARM64_REG_S2, 123.456_f32}, + {ARM64_REG_CPSR_C, true}, + {ARM64_REG_CPSR_Z, false}, + }); + + emulate("fccmp s1, s2, #12, hi"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1, ARM64_REG_S2, ARM64_REG_CPSR_C, ARM64_REG_CPSR_Z}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCCMP_d_d_f_true) +{ + setRegisters({ + {ARM64_REG_D1, 321.3938216392863_f64}, + {ARM64_REG_D2, 321.3938216392863_f64}, + {ARM64_REG_CPSR_C, true}, + }); + + emulate("fccmp d1, d2, #5, cc"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, false}, + {ARM64_REG_CPSR_Z, true}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, true}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCCMP_d_d_f_false) +{ + setRegisters({ + {ARM64_REG_D1, 321.3938216392863_f64}, + {ARM64_REG_D2, 123.45632918321_f64}, + {ARM64_REG_CPSR_C, false}, + }); + + emulate("fccmp d1, d2, #1, lo"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2, ARM64_REG_CPSR_C}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_Z, false}, + {ARM64_REG_CPSR_C, false}, + {ARM64_REG_CPSR_V, false}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_FCSEL // @@ -6488,6 +6723,178 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCSEL32_true) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_FCVT +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCVT_s_d) +{ + setRegisters({ + {ARM64_REG_D1, 3.141592_f64}, + }); + + emulate("fcvt s0, d1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 3.141592_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCVT_d_s) +{ + setRegisters({ + {ARM64_REG_S1, 3.141592_f32}, + }); + + emulate("fcvt d0, s1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 3.141592_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_SCVTF +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SCVTF_s_w) +{ + setRegisters({ + {ARM64_REG_W1, 0xffffffff}, + }); + + emulate("scvtf s0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, static_cast(-1)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SCVTF_d_w) +{ + setRegisters({ + {ARM64_REG_W1, 123}, + }); + + emulate("scvtf d0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 123.0_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SCVTF_s_x) +{ + setRegisters({ + {ARM64_REG_X1, 0xffffffffffffffff}, + }); + + emulate("scvtf s0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, static_cast(-1)}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SCVTF_d_x) +{ + setRegisters({ + {ARM64_REG_X1, 123}, + }); + + emulate("scvtf d0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 123.0_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_UCVTF +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UCVTF_s_w) +{ + setRegisters({ + {ARM64_REG_W1, 0xffffffff}, + }); + + emulate("ucvtf s0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 4294967295.0_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UCVTF_d_w) +{ + setRegisters({ + {ARM64_REG_W1, 123}, + }); + + emulate("ucvtf d0, w1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 123.0_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UCVTF_s_x) +{ + setRegisters({ + {ARM64_REG_X1, 0x8000000000000000}, + }); + + emulate("ucvtf s0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 9.22337204e+18_f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UCVTF_d_x) +{ + setRegisters({ + {ARM64_REG_X1, 123}, + }); + + emulate("ucvtf d0, x1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 123.0_f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_FDIV // From d9803287c50e8a87a9929e8efcb8235936f02bfc Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 1 Mar 2019 15:54:08 +0100 Subject: [PATCH 091/107] Arm64: FCVTZS, FCVTZU instructions + tests - let's start testing --- src/capstone2llvmir/arm64/arm64.cpp | 23 ++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 4 +- tests/capstone2llvmir/arm64_tests.cpp | 136 +++++++++++++++++++++++ 4 files changed, 162 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index ed398b82b..05100b6b2 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -2429,6 +2429,29 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateFCvtf(cs_insn* i, cs_arm64* a } } +/** + * ARM64_INS_FCVTZS, ARM64_INS_FCVTZU + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateFCvtz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + op1 = loadOp(ai->operands[1], irb); + + switch(i->id) + { + case ARM64_INS_FCVTZU: + op1 = irb.CreateFPToSI(op1, getRegisterType(ai->operands[0].reg)); + break; + case ARM64_INS_FCVTZS: + op1 = irb.CreateFPToUI(op1, getRegisterType(ai->operands[0].reg)); + break; + default: + throw GenericError("Arm64: translateFCvtz(): Unsupported instruction id"); + } + storeOp(ai->operands[0], op1, irb); +} + /** * ARM64_INS_FDIV */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index bc4e8643b..ca6ca021f 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -214,6 +214,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateFCsel(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFCvt(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFCvtf(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateFCvtz(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFDiv(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFMadd(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFMinMax(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 19b09e1a4..84753cabf 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -513,8 +513,8 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_FCVTPU, nullptr}, {ARM64_INS_FCVTXN, nullptr}, {ARM64_INS_FCVTXN2, nullptr}, - {ARM64_INS_FCVTZS, nullptr}, - {ARM64_INS_FCVTZU, nullptr}, + {ARM64_INS_FCVTZS, &Capstone2LlvmIrTranslatorArm64_impl::translateFCvtz}, + {ARM64_INS_FCVTZU, &Capstone2LlvmIrTranslatorArm64_impl::translateFCvtz}, {ARM64_INS_FDIV, &Capstone2LlvmIrTranslatorArm64_impl::translateFDiv}, {ARM64_INS_FMADD, &Capstone2LlvmIrTranslatorArm64_impl::translateFMadd}, {ARM64_INS_FMAX, &Capstone2LlvmIrTranslatorArm64_impl::translateFMinMax}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 8fb864bd1..c442ce73f 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -6895,6 +6895,142 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UCVTF_d_x) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_FCVTZS +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCVTZS_w_s) +{ + setRegisters({ + {ARM64_REG_S1, static_cast(-1.0)}, + }); + + emulate("fcvtzs w0, s1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_W0, 0xffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCVTZS_w_d) +{ + setRegisters({ + {ARM64_REG_D1, 123.9_f64}, + }); + + emulate("fcvtzs w0, d1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_W0, 123}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCVTZS_x_s) +{ + setRegisters({ + {ARM64_REG_S1, static_cast(-1)}, + }); + + emulate("fcvtzs x0, s1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCVTZS_x_d) +{ + setRegisters({ + {ARM64_REG_D1, 123.3_f64}, + }); + + emulate("fcvtzs x0, d1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 123}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +// +// ARM64_INS_FCVTZU +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCVTZU_w_s) +{ + setRegisters({ + {ARM64_REG_S1, 31232321.0_f32}, + }); + + emulate("fcvtzu w0, s1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_W0, 0x1dc9140}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCVTZU_w_d) +{ + setRegisters({ + {ARM64_REG_D1, 123.5_f64}, + }); + + emulate("fcvtzu w0, d1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_W0, 123}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCVTZU_x_s) +{ + setRegisters({ + {ARM64_REG_S1, 9.22337204e+18_f32}, + }); + + emulate("fcvtzu x0, s1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x8000000000000000}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCVTZU_x_d) +{ + setRegisters({ + {ARM64_REG_D1, 123.0_f64}, + }); + + emulate("fcvtzu x0, d1"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 123}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_FDIV // From 7b884752806408dd37ade5881a57e670fecc63b2 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 1 Mar 2019 16:18:52 +0100 Subject: [PATCH 092/107] Arm64, bin2llvmir: Decoder should not analyse stack. --- include/retdec/bin2llvmir/analyses/symbolic_tree.h | 2 ++ src/bin2llvmir/analyses/symbolic_tree.cpp | 10 +++++++++- src/bin2llvmir/optimizations/decoder/decoder.cpp | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/include/retdec/bin2llvmir/analyses/symbolic_tree.h b/include/retdec/bin2llvmir/analyses/symbolic_tree.h index 06f6cf590..aaa48df69 100644 --- a/include/retdec/bin2llvmir/analyses/symbolic_tree.h +++ b/include/retdec/bin2llvmir/analyses/symbolic_tree.h @@ -109,6 +109,7 @@ class SymbolicTree static void setToDefaultConfiguration(); static void setTrackThroughAllocaLoads(bool b); static void setTrackThroughGeneralRegisterLoads(bool b); + static void setTrackThroughStackPointerRegister(bool b); static void setTrackOnlyFlagRegisters(bool b); static void setSimplifyAtCreation(bool b); static void setNaryLimit(unsigned n); @@ -119,6 +120,7 @@ class SymbolicTree static bool _val2valUsed; static bool _trackThroughAllocaLoads; static bool _trackThroughGeneralRegisterLoads; + static bool _trackThroughStackPointerRegister; static bool _trackOnlyFlagRegisters; static bool _simplifyAtCreation; static unsigned _naryLimit; diff --git a/src/bin2llvmir/analyses/symbolic_tree.cpp b/src/bin2llvmir/analyses/symbolic_tree.cpp index f7b4fa84b..48a710488 100644 --- a/src/bin2llvmir/analyses/symbolic_tree.cpp +++ b/src/bin2llvmir/analyses/symbolic_tree.cpp @@ -301,7 +301,8 @@ void SymbolicTree::expandNode( || isa(value) || (_abi && _abi->isRegister(value) - && !_abi->isStackPointerRegister(value) + && (!_trackThroughStackPointerRegister + || !_abi->isStackPointerRegister(value)) && !_abi->isZeroRegister(value) && value != _abi->getRegister(MIPS_REG_GP, _abi->isMips()))) { @@ -702,6 +703,7 @@ Config* SymbolicTree::_config = nullptr; bool SymbolicTree::_val2valUsed = false; bool SymbolicTree::_trackThroughAllocaLoads = true; bool SymbolicTree::_trackThroughGeneralRegisterLoads = true; +bool SymbolicTree::_trackThroughStackPointerRegister = true; bool SymbolicTree::_trackOnlyFlagRegisters = false; bool SymbolicTree::_simplifyAtCreation = true; unsigned SymbolicTree::_naryLimit = 3; @@ -710,6 +712,7 @@ void SymbolicTree::setToDefaultConfiguration() { _trackThroughAllocaLoads = true; _trackThroughGeneralRegisterLoads = true; + _trackThroughStackPointerRegister = true; _trackOnlyFlagRegisters = false; _simplifyAtCreation = true; _naryLimit = 3; @@ -740,6 +743,11 @@ void SymbolicTree::setTrackThroughGeneralRegisterLoads(bool b) _trackThroughGeneralRegisterLoads = b; } +void SymbolicTree::setTrackThroughStackPointerRegister(bool b) +{ + _trackThroughStackPointerRegister = b; +} + void SymbolicTree::setTrackOnlyFlagRegisters(bool b) { _trackOnlyFlagRegisters = b; diff --git a/src/bin2llvmir/optimizations/decoder/decoder.cpp b/src/bin2llvmir/optimizations/decoder/decoder.cpp index 508db09ca..ca959dbd8 100644 --- a/src/bin2llvmir/optimizations/decoder/decoder.cpp +++ b/src/bin2llvmir/optimizations/decoder/decoder.cpp @@ -104,6 +104,8 @@ bool Decoder::run() return false; } + SymbolicTree::setTrackThroughStackPointerRegister(false); + initTranslator(); initDryRunCsInstruction(); initEnvironment(); @@ -139,6 +141,8 @@ bool Decoder::run() initializeGpReg_mips(); + SymbolicTree::setToDefaultConfiguration(); + return false; } From bac43b4fdaea3bd067cb5359734917dee7a9ea35 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Tue, 5 Mar 2019 16:54:51 +0100 Subject: [PATCH 093/107] Arm64: MOVK instruction + tests --- src/capstone2llvmir/arm64/arm64.cpp | 32 ++++++++ src/capstone2llvmir/arm64/arm64_impl.h | 1 + src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 100 +++++++++++++++++++++++ 4 files changed, 134 insertions(+), 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 05100b6b2..41beacd1c 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1126,6 +1126,38 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMov(cs_insn* i, cs_arm64* ai, storeOp(ai->operands[0], op1, irb); } +/** + * ARM64_INS_MOVK + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateMovk(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + // Load the destination register + op0 = loadOp(ai->operands[0], irb); + + // Create simple imm16 bit inverted mask + llvm::Value* and_mask = llvm::ConstantInt::get(op0->getType(), 0xffff); + + // Get the operand shift value + auto shift_val = (ai->operands[1].shift.type == ARM64_SFT_INVALID) ? 0 : ai->operands[1].shift.value; + + // Shift the mask to proper place in case of LSL imm shift (example: movk x0, #123, LSL #32) + and_mask = irb.CreateShl(and_mask, llvm::ConstantInt::get(op0->getType(), shift_val)); + + // Invert the mask + and_mask = generateValueNegate(irb, and_mask); + + op0 = irb.CreateAnd(op0, and_mask); + + op1 = loadOp(ai->operands[1], irb); + op1 = irb.CreateZExtOrTrunc(op1, op0->getType()); + // Move the value keeping the original data in register changing only the 16bit imm + auto *val = irb.CreateOr(op0, op1); + + storeOp(ai->operands[0], val, irb); +} + /** * ARM64_INS_STR, ARM64_INS_STRB, ARM64_INS_STRH * ARM64_INS_STUR, ARM64_INS_STURB, ARM64_INS_STURH diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index ca6ca021f..0d350da31 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -182,6 +182,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateNgc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateSbc(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateMovk(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateStp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateLdr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 84753cabf..ef0eaba98 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -607,7 +607,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_MLA, nullptr}, {ARM64_INS_MLS, nullptr}, {ARM64_INS_MOVI, nullptr}, - {ARM64_INS_MOVK, nullptr}, + {ARM64_INS_MOVK, &Capstone2LlvmIrTranslatorArm64_impl::translateMovk}, {ARM64_INS_MOVN, nullptr}, {ARM64_INS_MOVZ, &Capstone2LlvmIrTranslatorArm64_impl::translateMov}, {ARM64_INS_MRS, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index c442ce73f..ecbfd7189 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -2468,6 +2468,106 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVZ_r_i) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_MOVK +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVK_r_i) +{ + setRegisters({ + {ARM64_REG_X0, 0xcafebabecafebabe}, + }); + + emulate("movk x0, #0x8f01"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X0}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xcafebabecafe8f01}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVK_r_i_16) +{ + setRegisters({ + {ARM64_REG_X0, 0xcafebabecafebabe}, + }); + + emulate("movk x0, #0x8f01, LSL #16"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X0}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xcafebabe8f01babe}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVK_r_i_32) +{ + setRegisters({ + {ARM64_REG_X0, 0xcafebabecafebabe}, + }); + + emulate("movk x0, #0x8f01, LSL #32"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X0}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xcafe8f01cafebabe}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVK_r_i_48) +{ + setRegisters({ + {ARM64_REG_X0, 0xcafebabecafebabe}, + }); + + emulate("movk x0, #0x8f01, LSL #48"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X0}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x8f01babecafebabe}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVK_w_i) +{ + setRegisters({ + {ARM64_REG_W0, 0xcafebabe}, + }); + + emulate("movk w0, #0x8f01"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W0}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xcafe8f01}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVK_w_i_16) +{ + setRegisters({ + {ARM64_REG_W0, 0xcafebabe}, + }); + + emulate("movk w0, #0x8f01, LSL #16"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_W0}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x8f01babe}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MVN // From b8b28ec39dee8304129679620921f2b711411199 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Tue, 5 Mar 2019 17:59:20 +0100 Subject: [PATCH 094/107] Arm64: MOVN instructions + tests --- src/capstone2llvmir/arm64/arm64.cpp | 7 +- src/capstone2llvmir/arm64/arm64_init.cpp | 2 +- tests/capstone2llvmir/arm64_tests.cpp | 100 +++++++++++++++++++++++ 3 files changed, 105 insertions(+), 4 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 41beacd1c..17f4f8d48 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -1111,14 +1111,15 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateNop(cs_insn* i, cs_arm64* ai, } /** - * ARM64_INS_MOV, ARM64_INS_MVN, ARM64_INS_MOVZ + * ARM64_INS_MOV, ARM64_INS_MVN, ARM64_INS_MOVZ, ARM64_INS_MOVN */ void Capstone2LlvmIrTranslatorArm64_impl::translateMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { EXPECT_IS_BINARY(i, ai, irb); - op1 = loadOpBinaryOp1(ai, irb); - if (i->id == ARM64_INS_MVN) + op1 = loadOp(ai->operands[1], irb); + op1 = irb.CreateZExtOrTrunc(op1, getRegisterType(ai->operands[0].reg)); + if (i->id == ARM64_INS_MVN || i->id == ARM64_INS_MOVN) { op1 = generateValueNegate(irb, op1); } diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index ef0eaba98..918adf5ea 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -608,7 +608,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_MLS, nullptr}, {ARM64_INS_MOVI, nullptr}, {ARM64_INS_MOVK, &Capstone2LlvmIrTranslatorArm64_impl::translateMovk}, - {ARM64_INS_MOVN, nullptr}, + {ARM64_INS_MOVN, &Capstone2LlvmIrTranslatorArm64_impl::translateMov}, {ARM64_INS_MOVZ, &Capstone2LlvmIrTranslatorArm64_impl::translateMov}, {ARM64_INS_MRS, nullptr}, {ARM64_INS_MSR, nullptr}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index ecbfd7189..989dab8d7 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -2568,6 +2568,106 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVK_w_i_16) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_MOVN +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVN_r_i) +{ + setRegisters({ + {ARM64_REG_X0, 0xcafebabecafebabe}, + }); + + emulate("movn x0, #0x8f01"); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffffffff70fe}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVN_r_i_16) +{ + setRegisters({ + {ARM64_REG_X0, 0xcafebabecafebabe}, + }); + + emulate("movn x0, #0x8f01, LSL #16"); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffffffff70feffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVN_r_i_32) +{ + setRegisters({ + {ARM64_REG_X0, 0xcafebabecafebabe}, + }); + + emulate("movn x0, #0x8f01, LSL #32"); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0xffff70feffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVN_r_i_48) +{ + setRegisters({ + {ARM64_REG_X0, 0xcafebabecafebabe}, + }); + + emulate("movn x0, #0x8f01, LSL #48"); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x70feffffffffffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVN_w_i) +{ + setRegisters({ + {ARM64_REG_W0, 0xcafebabe}, + }); + + emulate("movn w0, #0x8f01"); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x00000000ffff70fe}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVN_w_i_16) +{ + setRegisters({ + {ARM64_REG_W0, 0xcafebabe}, + }); + + emulate("movn w0, #0x8f01, LSL #16"); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_X0, 0x0000000070feffff}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MVN // From affd7d371e45f901b7130ff25aecea5c83d12a4b Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Wed, 6 Mar 2019 18:59:00 +0100 Subject: [PATCH 095/107] Merge master with arm-prep --- .travis.yml | 18 +- CHANGELOG.md | 6 + README.md | 2 +- cmake/install-share.py | 4 +- deps/yaracpp/CMakeLists.txt | 4 +- deps/yaramod/CMakeLists.txt | 4 +- .../param_return/collector/collector.h | 101 + .../param_return/collector/pic32.h | 32 + .../optimizations/param_return/data_entries.h | 185 + .../param_return/filter/filter.h | 199 + .../param_return/filter/ms_x64.h | 38 + .../optimizations/param_return/param_return.h | 157 +- include/retdec/bin2llvmir/providers/abi/abi.h | 54 +- include/retdec/bin2llvmir/providers/abi/arm.h | 2 +- .../retdec/bin2llvmir/providers/abi/arm64.h | 2 +- .../retdec/bin2llvmir/providers/abi/mips.h | 2 +- .../retdec/bin2llvmir/providers/abi/mips64.h | 37 + .../retdec/bin2llvmir/providers/abi/ms_x64.h | 37 + .../retdec/bin2llvmir/providers/abi/pic32.h | 43 + .../retdec/bin2llvmir/providers/abi/powerpc.h | 2 +- .../bin2llvmir/providers/abi/powerpc64.h | 37 + include/retdec/bin2llvmir/providers/abi/x64.h | 37 + include/retdec/bin2llvmir/providers/abi/x86.h | 8 +- .../calling_convention/arm/arm_conv.h | 33 + .../calling_convention/arm64/arm64_conv.h | 33 + .../calling_convention/calling_convention.h | 154 + .../calling_convention/mips/mips_conv.h | 33 + .../calling_convention/mips/mips_psp.h | 27 + .../calling_convention/mips64/mips64_conv.h | 33 + .../calling_convention/pic32/pic32_conv.h | 33 + .../calling_convention/powerpc/powerpc_conv.h | 33 + .../powerpc64/powerpc64_conv.h | 33 + .../calling_convention/x64/x64_conv.h | 26 + .../calling_convention/x64/x64_microsoft.h | 27 + .../calling_convention/x64/x64_systemv.h | 27 + .../calling_convention/x86/x86_cdecl.h | 32 + .../calling_convention/x86/x86_conv.h | 31 + .../calling_convention/x86/x86_fastcall.h | 41 + .../calling_convention/x86/x86_pascal.h | 32 + .../calling_convention/x86/x86_thiscall.h | 32 + .../calling_convention/x86/x86_watcom.h | 32 + include/retdec/config/architecture.h | 3 + include/retdec/config/calling_convention.h | 24 +- .../compiler_detector/compiler_detector.h | 1 - .../fileformat/file_format/pe/pe_format.h | 14 + .../types/resource_table/bitmap_image.h | 5 - .../types/visual_basic/visual_basic_extern.h | 43 + .../types/visual_basic/visual_basic_info.h | 166 + .../types/visual_basic/visual_basic_object.h | 49 + .../visual_basic/visual_basic_structures.h | 227 + include/retdec/fileformat/utils/other.h | 1 + .../unpacker/decompression/compressed_data.h | 4 +- .../unpacker/decompression/nrv/bit_parsers.h | 4 +- include/retdec/unpacker/signature.h | 13 +- include/retdec/unpacker/unpacking_stub.h | 2 +- .../{unpacker => utils}/dynamic_buffer.h | 12 +- include/retdec/utils/string.h | 3 + scripts/retdec-config.py | 9 +- scripts/retdec-decompiler.py | 27 +- src/bin2llvmir/CMakeLists.txt | 28 + .../optimizations/decoder/decoder.cpp | 4 +- .../param_return/collector/collector.cpp | 626 +++ .../param_return/collector/pic32.cpp | 48 + .../param_return/data_entries.cpp | 449 ++ .../param_return/filter/filter.cpp | 1353 +++++ .../param_return/filter/ms_x64.cpp | 189 + .../param_return/param_return.cpp | 2292 ++------ .../optimizations/x87_fpu/x87_fpu.cpp | 254 +- src/bin2llvmir/providers/abi/abi.cpp | 118 +- src/bin2llvmir/providers/abi/arm.cpp | 4 +- src/bin2llvmir/providers/abi/arm64.cpp | 9 +- src/bin2llvmir/providers/abi/mips.cpp | 4 +- src/bin2llvmir/providers/abi/mips64.cpp | 63 + src/bin2llvmir/providers/abi/ms_x64.cpp | 105 + src/bin2llvmir/providers/abi/pic32.cpp | 79 + src/bin2llvmir/providers/abi/powerpc.cpp | 4 +- src/bin2llvmir/providers/abi/powerpc64.cpp | 49 + src/bin2llvmir/providers/abi/x64.cpp | 105 + src/bin2llvmir/providers/abi/x86.cpp | 18 +- .../calling_convention/arm/arm_conv.cpp | 49 + .../calling_convention/arm64/arm64_conv.cpp | 78 + .../calling_convention/calling_convention.cpp | 234 + .../calling_convention/mips/mips_conv.cpp | 65 + .../calling_convention/mips/mips_psp.cpp | 58 + .../calling_convention/mips64/mips64_conv.cpp | 64 + .../calling_convention/pic32/pic32_conv.cpp | 48 + .../powerpc/powerpc_conv.cpp | 66 + .../powerpc64/powerpc64_conv.cpp | 68 + .../calling_convention/x64/x64_conv.cpp | 36 + .../calling_convention/x64/x64_microsoft.cpp | 44 + .../calling_convention/x64/x64_systemv.cpp | 69 + .../calling_convention/x86/x86_cdecl.cpp | 43 + .../calling_convention/x86/x86_conv.cpp | 26 + .../calling_convention/x86/x86_fastcall.cpp | 93 + .../calling_convention/x86/x86_pascal.cpp | 46 + .../calling_convention/x86/x86_thiscall.cpp | 48 + .../calling_convention/x86/x86_watcom.cpp | 51 + src/capstone2llvmir/arm/arm.cpp | 20 +- src/capstone2llvmir/x86/x86.cpp | 2 +- src/config/architecture.cpp | 5 + src/config/calling_convention.cpp | 16 +- .../compiler_detector/compiler_detector.cpp | 1 + src/fileformat/CMakeLists.txt | 3 + src/fileformat/file_format/file_format.cpp | 16 +- src/fileformat/file_format/pe/pe_format.cpp | 548 +- .../visual_basic/visual_basic_extern.cpp | 66 + .../types/visual_basic/visual_basic_info.cpp | 773 +++ .../visual_basic/visual_basic_object.cpp | 76 + src/fileformat/utils/format_detection.cpp | 27 +- src/fileformat/utils/other.cpp | 207 + src/fileinfo/CMakeLists.txt | 4 + src/fileinfo/file_detector/pe_detector.cpp | 15 + src/fileinfo/file_detector/pe_detector.h | 1 + .../file_information/file_information.cpp | 353 ++ .../file_information/file_information.h | 44 + .../file_information_types.h | 1 + .../visual_basic_info.cpp | 416 ++ .../visual_basic_info.h | 81 + ...visual_basic_extern_table_plain_getter.cpp | 100 + .../visual_basic_extern_table_plain_getter.h | 31 + .../file_presentation/getters/json_getters.h | 1 + .../file_presentation/getters/plain_getters.h | 2 + .../visual_basic_json_getter.cpp | 91 + .../simple_getter/visual_basic_json_getter.h | 28 + .../visual_basic_plain_getter.cpp | 91 + .../simple_getter/visual_basic_plain_getter.h | 28 + .../file_presentation/json_presentation.cpp | 73 + .../file_presentation/json_presentation.h | 1 + .../file_presentation/plain_presentation.cpp | 43 + .../file_presentation/plain_presentation.h | 1 + .../pattern_detector/pattern_detector.cpp | 1 + .../pattern_detector/pattern_detector.h | 5 +- src/stacofin/stacofin.cpp | 8 +- src/unpacker/CMakeLists.txt | 1 - src/unpacker/signature.cpp | 2 + src/unpackertool/plugins/mpress/mpress.cpp | 5 +- src/unpackertool/plugins/mpress/mpress.h | 22 +- .../upx/decompressors/decompressor.cpp | 1 + .../plugins/upx/decompressors/decompressor.h | 33 +- .../decompressor_direct_jump.cpp | 1 + .../decompressors/decompressor_direct_jump.h | 4 +- .../upx/decompressors/decompressor_lzma.cpp | 1 + .../upx/decompressors/decompressor_lzma.h | 27 +- .../upx/decompressors/decompressor_nrv.cpp | 3 +- .../upx/decompressors/decompressor_nrv.h | 24 +- .../decompressors/decompressor_scrambler.h | 18 +- .../upx/decompressors/decompressor_upxshit.h | 6 +- .../plugins/upx/elf/elf_upx_stub.cpp | 7 +- .../plugins/upx/elf/elf_upx_stub.h | 16 +- .../plugins/upx/macho/macho_upx_stub.cpp | 5 +- .../plugins/upx/macho/macho_upx_stub.h | 14 +- .../plugins/upx/pe/pe_upx_stub.cpp | 12 +- src/unpackertool/plugins/upx/pe/pe_upx_stub.h | 50 +- src/unpackertool/plugins/upx/unfilter.cpp | 3 +- src/unpackertool/plugins/upx/unfilter.h | 22 +- src/unpackertool/plugins/upx/upx_stub.cpp | 13 +- src/unpackertool/plugins/upx/upx_stub.h | 18 +- .../plugins/upx/upx_stub_signatures.cpp | 1 + .../plugins/upx/upx_stub_signatures.h | 6 +- src/utils/CMakeLists.txt | 1 + src/{unpacker => utils}/dynamic_buffer.cpp | 6 +- src/utils/string.cpp | 96 +- .../tools/macho/arm/compilers.yara | 4 +- .../tools/macho/arm/packers.yara | 8 +- .../tools/macho/ppc/compilers.yara | 6 +- .../tools/macho/ppc/packers.yara | 32 +- .../tools/macho/ppc64/compilers.yara | 4 +- .../tools/macho/x64/compilers.yara | 6 +- .../tools/macho/x64/packers.yara | 32 +- .../tools/macho/x86/compilers.yara | 12 +- .../tools/macho/x86/packers.yara | 24 +- .../param_return/param_return_tests.cpp | 4663 +++++++++++++---- tests/bin2llvmir/utils/llvmir_tests.h | 1 + tests/capstone2llvmir/arm_tests.cpp | 50 +- tests/config/architecture_tests.cpp | 5 + tests/fileformat/macho_format_tests.cpp | 692 +-- tests/unpacker/dynamic_buffer_tests.cpp | 2 +- tests/unpacker/signature_tests.cpp | 3 +- 178 files changed, 14590 insertions(+), 3848 deletions(-) create mode 100644 include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h create mode 100644 include/retdec/bin2llvmir/optimizations/param_return/collector/pic32.h create mode 100644 include/retdec/bin2llvmir/optimizations/param_return/data_entries.h create mode 100644 include/retdec/bin2llvmir/optimizations/param_return/filter/filter.h create mode 100644 include/retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h create mode 100644 include/retdec/bin2llvmir/providers/abi/mips64.h create mode 100644 include/retdec/bin2llvmir/providers/abi/ms_x64.h create mode 100644 include/retdec/bin2llvmir/providers/abi/pic32.h create mode 100644 include/retdec/bin2llvmir/providers/abi/powerpc64.h create mode 100644 include/retdec/bin2llvmir/providers/abi/x64.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/calling_convention.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h create mode 100644 include/retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h create mode 100644 include/retdec/fileformat/types/visual_basic/visual_basic_extern.h create mode 100644 include/retdec/fileformat/types/visual_basic/visual_basic_info.h create mode 100644 include/retdec/fileformat/types/visual_basic/visual_basic_object.h create mode 100644 include/retdec/fileformat/types/visual_basic/visual_basic_structures.h rename include/retdec/{unpacker => utils}/dynamic_buffer.h (94%) create mode 100644 src/bin2llvmir/optimizations/param_return/collector/collector.cpp create mode 100644 src/bin2llvmir/optimizations/param_return/collector/pic32.cpp create mode 100644 src/bin2llvmir/optimizations/param_return/data_entries.cpp create mode 100644 src/bin2llvmir/optimizations/param_return/filter/filter.cpp create mode 100644 src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp create mode 100644 src/bin2llvmir/providers/abi/mips64.cpp create mode 100644 src/bin2llvmir/providers/abi/ms_x64.cpp create mode 100644 src/bin2llvmir/providers/abi/pic32.cpp create mode 100644 src/bin2llvmir/providers/abi/powerpc64.cpp create mode 100644 src/bin2llvmir/providers/abi/x64.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/arm/arm_conv.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/arm64/arm64_conv.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/calling_convention.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/mips/mips_conv.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/mips/mips_psp.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/mips64/mips64_conv.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/pic32/pic32_conv.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x64/x64_conv.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x64/x64_microsoft.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x64/x64_systemv.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x86/x86_cdecl.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x86/x86_conv.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x86/x86_fastcall.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x86/x86_pascal.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x86/x86_thiscall.cpp create mode 100644 src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp create mode 100644 src/fileformat/types/visual_basic/visual_basic_extern.cpp create mode 100644 src/fileformat/types/visual_basic/visual_basic_info.cpp create mode 100644 src/fileformat/types/visual_basic/visual_basic_object.cpp create mode 100644 src/fileinfo/file_information/file_information_types/visual_basic_info.cpp create mode 100644 src/fileinfo/file_information/file_information_types/visual_basic_info.h create mode 100644 src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.cpp create mode 100644 src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.h create mode 100644 src/fileinfo/file_presentation/getters/simple_getter/visual_basic_json_getter.cpp create mode 100644 src/fileinfo/file_presentation/getters/simple_getter/visual_basic_json_getter.h create mode 100644 src/fileinfo/file_presentation/getters/simple_getter/visual_basic_plain_getter.cpp create mode 100644 src/fileinfo/file_presentation/getters/simple_getter/visual_basic_plain_getter.h rename src/{unpacker => utils}/dynamic_buffer.cpp (98%) diff --git a/.travis.yml b/.travis.yml index 3116dc6ed..f6f651022 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,21 +6,12 @@ matrix: fast_finish: true include: - os: linux - dist: trusty - compiler: gcc-4.9 + dist: xenial addons: apt: - sources: - - deadsnakes - - ubuntu-toolchain-r-test packages: - build-essential - - gcc-4.8-multilib - - gcc-4.9 - - g++-4.9 - - cmake - - perl - - python3.5 + - gcc-multilib - flex - bison - autoconf @@ -29,10 +20,9 @@ matrix: - pkg-config - m4 - zlib1g-dev - - upx - openssl env: - - MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9 && NPROC=$(nproc)" + - MATRIX_EVAL="NPROC=$(nproc)" # We need this so that ccache does not cause compilation errors. # e.g. retdec/tests/utils/string_tests.cpp:276:2: error: stray '\' in program - CCACHE_CPP2=true @@ -50,6 +40,8 @@ install: - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install ccache; fi # python 3 - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew upgrade python; fi + # install for os x the gnu time library + - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install gnu-time; fi before_script: - eval "${MATRIX_EVAL}" diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c1c52e49..a0025a678 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,13 @@ # dev +* New Feature: Added basic support of 64-bit x86 architecture ([#9](https://github.com/avast-tl/retdec/issues/9), [#513](https://github.com/avast-tl/retdec/pull/513)). * New Feature: Added presentation of imported types and TypeRef hashes for .NET binaries ([#363](https://github.com/avast-tl/retdec/issues/363), [#364](https://github.com/avast-tl/retdec/issues/364), [#428](https://github.com/avast-tl/retdec/issues/428)). +* New Feature: Added presentation of metadata from binaries written in Visual Basic and detection of P-code ([#138](https://github.com/avast-tl/retdec/issues/138), [#440](https://github.com/avast-tl/retdec/pull/440)). * New Feature: Added computation and presentation of icon hashes for exact and also similarity matching in PE files ([#339](https://github.com/avast-tl/retdec/issues/339)). +* Enhancement: Update YARA to version 3.8.1 ([#218](https://github.com/avast-tl/retdec/issues/218)). +* Enhancement: Make `--generate-log` option of `retdec-decompiler.py` work on macOS ([#383](https://github.com/avast-tl/retdec/issues/383), [#450](https://github.com/avast-tl/retdec/pull/450)). +* Enhancement: Replace recursion with iterative implementation in x87 FPU analysis in `retdec-bin2llvmir` ([#450](https://github.com/avast-tl/retdec/pull/450)). * Enhancement: The `new` LLVM IR to BIR converter is now the default (and only) back-end's converter. In most cases, this improves code structure and significantly speeds up decompilations ([#211](https://github.com/avast-tl/retdec/issues/211), [#508](https://github.com/avast-tl/retdec/issues/508), [#509](https://github.com/avast-tl/retdec/pull/509)). * Enhancement: The `fileformat` library, and all its object file modules, accept both `std::istream` and `(data, size)` pair, in addition to the original input file path. * Enhancement: Reduced the needed stack space in `retdec-llvmir2hll` ([#492](https://github.com/avast-tl/retdec/pull/492)). @@ -16,6 +21,7 @@ * Enhancement: Add a check into our scripts that they are run from an installation directory and not from the `scripts` directory ([#418](https://github.com/avast-tl/retdec/issues/418)). * Enhancement: Improved corruption checks in `retdec-fileinfo` to recognize cut PE files which are still loadable ([#463](https://github.com/avast-tl/retdec/issues/463)). * Enhancement: Redesign output files naming scheme ([#132](https://github.com/avast-tl/retdec/issues/132)). +* Fix: Fixed false COFF file format detections ([#421](https://github.com/avast-tl/retdec/issues/421), [#431](https://github.com/avast-tl/retdec/issues/431)). * Fix: Fixed LLVM IR syntax error: `Global variable initializer type does not match global variable type` ([#436](https://github.com/avast-tl/retdec/issues/436)). * Fix: Fixed translation of x86 `sbb` instruction ([#401](https://github.com/avast-tl/retdec/issues/401)). * Fix: Fixed `fileinfo` crash during `Asn1Sequence` initialization when parsing PE certificates ([#256](https://github.com/avast-tl/retdec/issues/256)). diff --git a/README.md b/README.md index 924a2e3a1..1ab5c1006 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ This section describes a local build and installation of RetDec. Instructions fo #### Linux -* A C++ compiler and standard C++ library supporting C++14 (e.g. GCC >= 4.9) +* A C++ compiler and standard C++ library supporting C++14 (e.g. GCC >= 5) * [CMake](https://cmake.org/) (version >= 3.6) * [Git](https://git-scm.com/) * [Perl](https://www.perl.org/) diff --git a/cmake/install-share.py b/cmake/install-share.py index 1406fab7d..b9ecacc78 100755 --- a/cmake/install-share.py +++ b/cmake/install-share.py @@ -16,8 +16,8 @@ version_filename = 'version.txt' arch_suffix = 'tar.xz' -sha256hash_ref = 'b54ba07e2f28143c9afe34a9d5b4114fb61f3c1175b9807caced471fec82001e' -version = '2018-02-08' +sha256hash_ref = '7a5b06ecbe97e7c90e733b74284bdce3c577af60916eddd219b42d26b5b274b0' +version = '2019-03-03' arch_name = 'retdec-support' + '_' + version + '.' + arch_suffix diff --git a/deps/yaracpp/CMakeLists.txt b/deps/yaracpp/CMakeLists.txt index 2cb969f34..7589381f1 100644 --- a/deps/yaracpp/CMakeLists.txt +++ b/deps/yaracpp/CMakeLists.txt @@ -8,8 +8,8 @@ if(CMAKE_CXX_COMPILER) endif() ExternalProject_Add(yaracpp-project - URL https://github.com/avast-tl/yaracpp/archive/b92bde0e59e3b75bc445227e04b71105771dee8b.zip - URL_HASH SHA256=c8282c51dcc71535cf39b9416dbc5576ed26477234c02f4294e25cdbdda75574 + URL https://github.com/avast-tl/yaracpp/archive/d3098245cfafe06f30995e7fbf0b4c60767cb817.zip + URL_HASH SHA256=5d730a053ae6bfdd3a323fc03ac716b6d8cbc040b7e2f3bddce0b8687e8d1f2b DOWNLOAD_NAME yaracpp.zip CMAKE_ARGS # This does not work on MSVC, but may be useful on Linux. diff --git a/deps/yaramod/CMakeLists.txt b/deps/yaramod/CMakeLists.txt index 7c7ddd93e..008528644 100644 --- a/deps/yaramod/CMakeLists.txt +++ b/deps/yaramod/CMakeLists.txt @@ -12,8 +12,8 @@ if(CMAKE_CXX_COMPILER) endif() ExternalProject_Add(yaramod-project - URL https://github.com/avast-tl/yaramod/archive/v2.2.2.zip - URL_HASH SHA256=e3da9130828d307ce4dd49b93f7ca14b5707abaf5c7a6a82de1ded51c65200e7 + URL https://github.com/avast-tl/yaramod/archive/v2.4.1.zip + URL_HASH SHA256=e8341feba2cea4d00a1f31a3b24823511cf0e77e80621b635e57643aa5c5acee DOWNLOAD_NAME yaramod.zip CMAKE_ARGS # This does not work on MSVC, but may be useful on Linux. diff --git a/include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h b/include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h new file mode 100644 index 000000000..c7c5173b3 --- /dev/null +++ b/include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h @@ -0,0 +1,101 @@ +/** +* @file include/retdec/bin2llvmir/optimizations/param_return/collector/collector.h +* @brief Collects possible arguments and returns of functions. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#ifndef RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_COLLECTOR_COLLECTOR_H +#define RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_COLLECTOR_COLLECTOR_H + +#include +#include + +#include +#include + +#include "retdec/bin2llvmir/analyses/reaching_definitions.h" +#include "retdec/bin2llvmir/optimizations/param_return/data_entries.h" +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class Collector +{ + public: + typedef std::unique_ptr Ptr; + + public: + Collector( + const Abi* abi, + llvm::Module* m, + const ReachingDefinitionsAnalysis* rda); + + virtual ~Collector(); + + public: + virtual void collectCallArgs(CallEntry* ce) const; + virtual void collectCallRets(CallEntry* ce) const; + + virtual void collectDefArgs(DataFlowEntry* de) const; + virtual void collectDefRets(DataFlowEntry* de) const; + + virtual void collectCallSpecificTypes(CallEntry* ce) const; + + protected: + + void collectRetStores(ReturnEntry* re) const; + + void collectStoresBeforeInstruction( + llvm::Instruction* i, + std::vector& stores) const; + + void collectLoadsAfterInstruction( + llvm::Instruction* i, + std::vector& loads) const; + + bool collectLoadsAfterInstruction( + llvm::Instruction* i, + std::vector& loads, + std::set& excluded) const; + + void collectStoresInSinglePredecessors( + llvm::Instruction* i, + std::vector& stores) const; + + void collectStoresRecursively( + llvm::Instruction* i, + std::vector& stores, + std::map>& seen) const; + + bool collectStoresInInstructionBlock( + llvm::Instruction* i, + std::set& values, + std::vector& stores) const; + + protected: + bool extractFormatString(CallEntry* ce) const; + + bool storesString(llvm::StoreInst* si, std::string& str) const; + llvm::Value* getRoot(llvm::Value* i, bool first = true) const; + + protected: + const Abi* _abi; + llvm::Module* _module; + const ReachingDefinitionsAnalysis* _rda; +}; + +class CollectorProvider +{ + public: + static Collector::Ptr createCollector( + const Abi* abi, + llvm::Module* m, + const ReachingDefinitionsAnalysis* rda); +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/include/retdec/bin2llvmir/optimizations/param_return/collector/pic32.h b/include/retdec/bin2llvmir/optimizations/param_return/collector/pic32.h new file mode 100644 index 000000000..e69ae762b --- /dev/null +++ b/include/retdec/bin2llvmir/optimizations/param_return/collector/pic32.h @@ -0,0 +1,32 @@ +/** +* @file include/retdec/bin2llvmir/optimizations/param_return/collector/pic32.h +* @brief Pic32 specific collection algorithms. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#ifndef RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_COLLECTOR_PIC32_H +#define RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_COLLECTOR_PIC32_H + +#include "retdec/bin2llvmir/optimizations/param_return/collector/collector.h" + +namespace retdec { +namespace bin2llvmir { + +class CollectorPic32 : public Collector +{ + public: + CollectorPic32( + const Abi* abi, + llvm::Module* m, + const ReachingDefinitionsAnalysis* rda); + + virtual ~CollectorPic32() override; + + public: + virtual void collectCallSpecificTypes(CallEntry* ce) const override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/include/retdec/bin2llvmir/optimizations/param_return/data_entries.h b/include/retdec/bin2llvmir/optimizations/param_return/data_entries.h new file mode 100644 index 000000000..7f6a350ba --- /dev/null +++ b/include/retdec/bin2llvmir/optimizations/param_return/data_entries.h @@ -0,0 +1,185 @@ +/** +* @file include/retdec/bin2llvmir/optimizations/param_return/data_entries.h +* @brief Data entries for parameter analysis. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#ifndef RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_DATA_ENTRIES_H +#define RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_DATA_ENTRIES_H + +#include + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +#include +#include + +namespace retdec { +namespace bin2llvmir { + +class ReturnEntry +{ + public: + ReturnEntry(llvm::ReturnInst* r); + + public: + void addRetStore(llvm::StoreInst* st); + + void setRetStores(std::vector&& stores); + void setRetStores(const std::vector& stores); + void setRetValues(std::vector&& values); + + void setRetValues(const std::vector& values); + + public: + llvm::ReturnInst* getRetInstruction() const; + + const std::vector& retStores() const; + const std::vector& retValues() const; + + + protected: + llvm::ReturnInst* _retInst = nullptr; + + std::vector _retStores; + std::vector _retValues; +}; + +class CallableEntry +{ + public: + bool isVoidarg() const; + + void addArg(llvm::Value* arg); + + void setVoidarg(bool voidarg = true); + void setArgTypes( + std::vector&& types, + std::vector&& names = {}); + + public: + const std::vector& args() const; + const std::vector& argTypes() const; + const std::vector& argNames() const; + + protected: + std::vector _args; + std::vector _argTypes; + std::vector _argNames; + + protected: + bool _voidarg = false; +}; + +class FunctionEntry : public CallableEntry +{ + public: + bool isVariadic() const; + bool isWrapper() const; + + public: + void addRetEntry(const ReturnEntry& ret); + ReturnEntry* createRetEntry(llvm::ReturnInst* ret); + + void setArgs(std::vector&& args); + void setVariadic(bool variadic = true); + void setWrappedCall(llvm::CallInst* wrap); + void setRetType(llvm::Type* type); + void setRetValue(llvm::Value* val); + void setCallingConvention(const CallingConvention::ID& cc); + + public: + llvm::Value* getRetValue() const; + llvm::Type* getRetType() const; + llvm::CallInst* getWrappedCall() const; + CallingConvention::ID getCallingConvention() const; + + const std::vector& retEntries() const; + std::vector& retEntries(); + + private: + llvm::CallInst* _wrap = nullptr; + llvm::Type* _retType = nullptr; + llvm::Value* _retVal = nullptr; + bool _variadic = false; + CallingConvention::ID _callconv = CallingConvention::ID::CC_UNKNOWN; + + std::vector _retEntries; +}; + +class CallEntry : public CallableEntry +{ + // Constructor. + // + public: + CallEntry( + llvm::CallInst* call, + const FunctionEntry* base = nullptr); + + // Usage data. + // + public: + void addRetLoad(llvm::LoadInst* load); + + void setFormatString(const std::string& fmt); + void setArgStores(std::vector&& stores); + void setArgs(std::vector&& args); + void setRetLoads(std::vector&& loads); + void setRetValues(std::vector&& values); + + llvm::CallInst* getCallInstruction() const; + const FunctionEntry* getBaseFunction() const; + std::string getFormatString() const; + + public: + const std::vector& argStores() const; + const std::vector& retValues() const; + const std::vector& retLoads() const; + + private: + const FunctionEntry* _baseFunction; + + llvm::CallInst* _callInst = nullptr; + std::string _fmtStr = ""; + + std::vector _retLoads; + std::vector _retValues; + std::vector _argStores; +}; + +class DataFlowEntry : public FunctionEntry +{ + // Constructor + // + public: + DataFlowEntry(llvm::Value* called); + + // Type information + // + public: + bool isFunction() const; + bool isValue() const; + bool hasDefinition() const; + + llvm::Function* getFunction() const; + llvm::Value* getValue() const; + + void setCalledValue(llvm::Value* called); + + // Usage data. + // + public: + CallEntry* createCallEntry(llvm::CallInst *call); + const std::vector& callEntries() const; + std::vector& callEntries(); + + private: + llvm::Value* _calledValue = nullptr; + + std::vector _calls; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/include/retdec/bin2llvmir/optimizations/param_return/filter/filter.h b/include/retdec/bin2llvmir/optimizations/param_return/filter/filter.h new file mode 100644 index 000000000..08d919eea --- /dev/null +++ b/include/retdec/bin2llvmir/optimizations/param_return/filter/filter.h @@ -0,0 +1,199 @@ +/** +* @file include/retdec/bin2llvmir/optimizations/param_return/filter/filter.h +* @brief Filters potential values according to calling convention. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#ifndef RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_FILTER_FILTER_H +#define RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_FILTER_FILTER_H + +#include + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" +#include "retdec/bin2llvmir/optimizations/param_return/collector/collector.h" +#include "retdec/bin2llvmir/optimizations/param_return/data_entries.h" + +namespace retdec { +namespace bin2llvmir { + +class FilterableLayout +{ + public: + enum class Order { + ORD_GPR, + ORD_GPR_GROUP, + ORD_FPR, + ORD_FPR_GROUP, + ORD_DOUBR, + ORD_DOUBR_GROUP, + ORD_VECR, + ORD_VECR_GROUP, + ORD_STACK, + ORD_STACK_GROUP + }; + + public: + std::vector gpRegisters; + std::vector fpRegisters; + std::vector doubleRegisters; + std::vector vectorRegisters; + std::vector stacks; + std::vector knownTypes; + std::vector knownOrder; +}; + +typedef FilterableLayout::Order OrderID; + +class Filter +{ + public: + typedef std::unique_ptr Ptr; + + public: + Filter(const Abi* _abi, const CallingConvention* _cc); + virtual ~Filter(); + + void filterDefinition(DataFlowEntry* de) const; + void filterCalls(DataFlowEntry* de) const; + void filterCallsVariadic( + DataFlowEntry* de, + const Collector* collector) const; + + void estimateRetValue(DataFlowEntry* de) const; + + protected: + virtual void filterDefinitionArgs( + FilterableLayout& args, + bool isVoidarg) const; + + virtual void filterCallArgs( + FilterableLayout& args, + bool isVoidarg) const; + + virtual void filterCallArgsByDefLayout( + FilterableLayout& args, + const FilterableLayout& def) const; + + virtual void filterRets( + FilterableLayout& rets) const; + + virtual void filterRetsByDefLayout( + FilterableLayout& args, + const FilterableLayout& def) const; + + virtual void filterArgsByKnownTypes(FilterableLayout& lay) const; + virtual void filterRetsByKnownTypes(FilterableLayout& lay) const; + + protected: + void leaveCommonArgs( + std::vector& allArgs) const; + + void leaveCommonRets( + std::vector& allRets) const; + + void leaveCommon( + std::vector& allRets) const; + + void orderFiterableLayout(FilterableLayout& lay) const; + + void orderStacks( + std::vector& stacks, + bool asc = true) const; + + void orderRegistersBy( + std::vector& regs, + const std::vector& orderedVector) const; + + protected: + FilterableLayout createArgsFilterableLayout( + const std::vector& group, + const std::vector& knownTypes) const; + + FilterableLayout createRetsFilterableLayout( + const std::vector& group, + llvm::Type* knownType) const; + + FilterableLayout createRetsFilterableLayout( + const std::vector& group, + const std::vector& knownTypes) const; + + virtual FilterableLayout separateArgValues( + const std::vector& paramValues) const; + + virtual FilterableLayout separateRetValues( + const std::vector& paramValues) const; + + virtual std::vector createGroupedArgValues( + const FilterableLayout& lay) const; + + virtual std::vector createGroupedRetValues( + const FilterableLayout& lay) const; + + FilterableLayout separateValues( + const std::vector& paramValues, + const std::vector& gpRegs, + const std::vector& fpRegs, + const std::vector& doubleRegs, + const std::vector& vecRegs) const; + + std::vector createGroupedValues( + const FilterableLayout& lay) const; + + std::vector expandTypes( + const std::vector& types) const; + + protected: + std::size_t fetchGPRegsForType( + llvm::Type* type, + FilterableLayout& lay) const; + + std::size_t fetchFPRegsForType( + llvm::Type* type, + FilterableLayout& lay) const; + + std::size_t fetchDoubleRegsForType( + llvm::Type* type, + FilterableLayout& lay) const; + + std::size_t fetchVecRegsForType( + llvm::Type* type, + FilterableLayout& lay) const; + + std::size_t fetchRegsForType( + llvm::Type* type, + std::vector& store, + const std::vector& regs, + std::size_t maxRegsPerObject) const; + + protected: + std::size_t getNumberOfStacksForType(llvm::Type* type) const; + + protected: + void leaveOnlyPositiveStacks(FilterableLayout& lay) const; + void leaveOnlyContinuousStack(FilterableLayout& lay) const; + void leaveOnlyContinuousArgRegisters(FilterableLayout& lay) const; + void leaveOnlyContinuousRetRegisters(FilterableLayout& lay) const; + void leaveSameStacks(FilterableLayout& lay, const FilterableLayout& fig) const; + + void leaveOnlyContinuousRegisters( + std::vector& regs, + const std::vector& templRegs) const; + + void createContinuousArgRegisters(FilterableLayout& lay) const; + + protected: + const Abi* _abi; + const CallingConvention* _cc; +}; + +class FilterProvider +{ + public: + static Filter::Ptr createFilter(Abi* abi, const CallingConvention::ID& id); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h b/include/retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h new file mode 100644 index 000000000..76e5ecbde --- /dev/null +++ b/include/retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h @@ -0,0 +1,38 @@ +/** +* @file include/retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h +* @brief Microsoft x64 specific filtration of registers. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#ifndef RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_FILTER_MS_X64_H +#define RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_FILTER_MS_X64_H + +#include "retdec/bin2llvmir/optimizations/param_return/filter/filter.h" + +namespace retdec { +namespace bin2llvmir { + +class MSX64Filter : public Filter +{ + public: + MSX64Filter(const Abi* _abi, const CallingConvention* _cc); + virtual ~MSX64Filter() override; + + virtual void filterDefinitionArgs( + FilterableLayout& args, + bool isVoidarg) const override; + + virtual void filterCallArgs( + FilterableLayout& args, + bool isVoidarg) const override; + + virtual void filterArgsByKnownTypes(FilterableLayout& lay) const override; + + private: + void leaveOnlyAlternatingArgRegisters(FilterableLayout& lay) const; +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h index 78ee990fe..179b506e1 100644 --- a/include/retdec/bin2llvmir/optimizations/param_return/param_return.h +++ b/include/retdec/bin2llvmir/optimizations/param_return/param_return.h @@ -1,7 +1,7 @@ /** * @file include/retdec/bin2llvmir/optimizations/param_return/param_return.h * @brief Detect functions' parameters and returns. -* @copyright (c) 2017 Avast Software, licensed under the MIT license +* @copyright (c) 2019 Avast Software, licensed under the MIT license */ #ifndef RETDEC_BIN2LLVMIR_OPTIMIZATIONS_PARAM_RETURN_PARAM_RETURN_H @@ -16,6 +16,8 @@ #include #include "retdec/bin2llvmir/analyses/reaching_definitions.h" +#include "retdec/bin2llvmir/optimizations/param_return/collector/collector.h" +#include "retdec/bin2llvmir/optimizations/param_return/data_entries.h" #include "retdec/bin2llvmir/providers/abi/abi.h" #include "retdec/bin2llvmir/providers/config.h" #include "retdec/bin2llvmir/providers/debugformat.h" @@ -25,115 +27,6 @@ namespace retdec { namespace bin2llvmir { -class CallEntry -{ - public: - CallEntry(llvm::CallInst* c); - - public: - void filterRegisters(Abi* _abi, Config* _config); - void filterSort(Config* _config); - void filterLeaveOnlyContinuousStackOffsets(Config* _config); - void filterLeaveOnlyNeededStackOffsets(Abi* _abi, Config* _config); - - void extractFormatString(ReachingDefinitionsAnalysis& _RDA); - - public: - llvm::CallInst* call = nullptr; - std::vector possibleArgStores; - std::vector possibleRetLoads; - std::string formatStr; -}; - -class ReturnEntry -{ - public: - ReturnEntry(llvm::ReturnInst* r); - - public: - llvm::ReturnInst* ret = nullptr; - std::vector possibleRetStores; -}; - -class DataFlowEntry -{ - public: - DataFlowEntry( - llvm::Module* m, - ReachingDefinitionsAnalysis& rda, - Config* c, - Abi* abi, - FileImage* img, - DebugFormat* dbg, - Lti* lti, - llvm::Value* v); - - bool isFunctionEntry() const; - bool isValueEntry() const; - llvm::Value* getValue() const; - llvm::Function* getFunction() const; - void dump() const; - - void addCall(llvm::CallInst* call); - - void filter(); - - void applyToIr(); - void applyToIrOrdinary(); - void applyToIrVariadic(); - void connectWrappers(); - - private: - void addArgLoads(); - void addRetStores(); - void addCallArgs(llvm::CallInst* call, CallEntry& ce); - void addCallReturns(llvm::CallInst* call, CallEntry& ce); - - void callsFilterCommonRegisters(); - void callsFilterSameNumberOfStacks(); - - void setTypeFromExtraInfo(); - void setTypeFromUseContext(); - void setReturnType(); - void setArgumentTypes(); - - void filterRegistersArgLoads(); - void filterSortArgLoads(); - - llvm::CallInst* isSimpleWrapper(llvm::Function* fnc); - - public: - llvm::Module* _module = nullptr; - ReachingDefinitionsAnalysis& _RDA; - Config* _config = nullptr; - Abi* _abi = nullptr; - FileImage* _image = nullptr; - Lti* _lti = nullptr; - - llvm::Value* called = nullptr; - retdec::config::Function* configFnc = nullptr; - retdec::config::Function* dbgFnc = nullptr; - - // In caller. - // - std::vector calls; - - // In called function. - // - std::vector argLoads; - std::vector retStores; - - // Result. - // - bool typeSet = false; - llvm::Type* retType = nullptr; - std::vector argTypes; - std::map specialArgStorage; - bool isVarArg = false; - llvm::CallInst* wrappedCall = nullptr; - std::vector argNames; -}; - class ParamReturn : public llvm::ModulePass { public: @@ -150,17 +43,50 @@ class ParamReturn : public llvm::ModulePass private: bool run(); - void dumpInfo(); + void dumpInfo() const; + void dumpInfo(const DataFlowEntry& de) const; + void dumpInfo(const CallEntry& ce) const; + void dumpInfo(const ReturnEntry& de) const; + // Collection of functions. + // + private: void collectAllCalls(); - std::string extractFormatString(llvm::CallInst* call); + DataFlowEntry createDataFlowEntry(llvm::Value* calledValue) const; + + private: + void collectExtraData(DataFlowEntry* de) const; + void collectExtraData(CallEntry* ce) const; + + void collectCallSpecificTypes(CallEntry* ce) const; + + // Collection of functions usage data. + // + private: + void addDataFromCall(DataFlowEntry* dataflow, llvm::CallInst* call) const; + + // Optimizations. + // + private: + llvm::CallInst* getWrapper(llvm::Function* fnc) const; + llvm::Type* extractType(llvm::Value* from) const; + + // Filtration of collected functions arguments. + // + private: void filterCalls(); - void filterSort(CallEntry& ce); - void filterLeaveOnlyContinuousStackOffsets(CallEntry& ce); - void filterLeaveOnlyNeededStackOffsets(CallEntry& ce); + void modifyType(DataFlowEntry& de) const; + // Modification of functions in IR. + // + private: void applyToIr(); + void applyToIr(DataFlowEntry& de); + void connectWrappers(const DataFlowEntry& de); + + std::map> fetchLoadsOfCalls( + const std::vector& calls) const; private: llvm::Module* _module = nullptr; @@ -172,6 +98,7 @@ class ParamReturn : public llvm::ModulePass std::map _fnc2calls; ReachingDefinitionsAnalysis _RDA; + Collector::Ptr _collector; }; } // namespace bin2llvmir diff --git a/include/retdec/bin2llvmir/providers/abi/abi.h b/include/retdec/bin2llvmir/providers/abi/abi.h index 02dd89885..d94ed39fc 100644 --- a/include/retdec/bin2llvmir/providers/abi/abi.h +++ b/include/retdec/bin2llvmir/providers/abi/abi.h @@ -16,6 +16,7 @@ #include "retdec/bin2llvmir/providers/asm_instruction.h" #include "retdec/bin2llvmir/providers/config.h" +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" //#include "retdec/capstone2llvmir/x86/x86_defs.h" @@ -39,18 +40,20 @@ class Abi // Registers. // public: - bool isRegister(const llvm::Value* val); - bool isRegister(const llvm::Value* val, uint32_t r); + bool isRegister(const llvm::Value* val) const; + bool isRegister(const llvm::Value* val, uint32_t r) const; bool isFlagRegister(const llvm::Value* val); - bool isStackPointerRegister(const llvm::Value* val); + bool isStackPointerRegister(const llvm::Value* val) const; bool isZeroRegister(const llvm::Value* val); - virtual bool isGeneralPurposeRegister(const llvm::Value* val) = 0; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const = 0; - llvm::GlobalVariable* getRegister(uint32_t r, bool use = true); - uint32_t getRegisterId(const llvm::Value* r); + llvm::GlobalVariable* getRegister(uint32_t r, bool use = true) const; + uint32_t getRegisterId(const llvm::Value* r) const; const std::vector& getRegisters() const; - llvm::GlobalVariable* getStackPointerRegister(); - llvm::GlobalVariable* getZeroRegister(); + llvm::GlobalVariable* getStackPointerRegister() const; + llvm::GlobalVariable* getZeroRegister() const; + + std::size_t getRegisterByteSize(uint32_t r) const; void addRegister(uint32_t id, llvm::GlobalVariable* reg); @@ -58,6 +61,11 @@ class Abi llvm::GlobalVariable* getSyscallReturnRegister(); llvm::GlobalVariable* getSyscallArgumentRegister(unsigned n); + // Stacks. + // + public: + bool isStackVariable(const llvm::Value* val) const; + // Instructions. // public: @@ -67,24 +75,43 @@ class Abi // Types. // public: - std::size_t getTypeByteSize(llvm::Type* t) const; - std::size_t getTypeBitSize(llvm::Type* t) const; + virtual std::size_t getTypeByteSize(llvm::Type* t) const; + virtual std::size_t getTypeBitSize(llvm::Type* t) const; llvm::IntegerType* getDefaultType() const; llvm::PointerType* getDefaultPointerType() const; + std::size_t getWordSize() const; static std::size_t getTypeByteSize(llvm::Module* m, llvm::Type* t); static std::size_t getTypeBitSize(llvm::Module* m, llvm::Type* t); static llvm::IntegerType* getDefaultType(llvm::Module* m); + static llvm::Type* getDefaultFPType(llvm::Module* m); static llvm::PointerType* getDefaultPointerType(llvm::Module* m); + static std::size_t getWordSize(llvm::Module* m); // Architectures. // public: bool isMips() const; + bool isMips64() const; bool isArm() const; bool isArm64() const; bool isX86() const; + bool isX64() const; bool isPowerPC() const; + bool isPowerPC64() const; + bool isPic32() const; + + // Calling conventions. + // + public: + CallingConvention* getCallingConvention( + const CallingConvention::ID& cc); + CallingConvention* getDefaultCallingConvention(); + + // Config. + // + public: + Config* getConfig() const; // Private data - misc. // @@ -117,6 +144,13 @@ class Abi uint32_t _regSyscallId = REG_INVALID; /// Register that is always equal to zero - not every arch have this. uint32_t _regZeroReg = REG_INVALID; + + // Private data - calling convention + // + protected: + std::map _id2cc; + CallingConvention::ID _defcc; + }; class AbiProvider diff --git a/include/retdec/bin2llvmir/providers/abi/arm.h b/include/retdec/bin2llvmir/providers/abi/arm.h index 33c58dd82..b4f9348c7 100644 --- a/include/retdec/bin2llvmir/providers/abi/arm.h +++ b/include/retdec/bin2llvmir/providers/abi/arm.h @@ -23,7 +23,7 @@ class AbiArm : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // diff --git a/include/retdec/bin2llvmir/providers/abi/arm64.h b/include/retdec/bin2llvmir/providers/abi/arm64.h index 671812e25..ea9078f96 100644 --- a/include/retdec/bin2llvmir/providers/abi/arm64.h +++ b/include/retdec/bin2llvmir/providers/abi/arm64.h @@ -23,7 +23,7 @@ class AbiArm64 : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // diff --git a/include/retdec/bin2llvmir/providers/abi/mips.h b/include/retdec/bin2llvmir/providers/abi/mips.h index af144ea6c..a573f6998 100644 --- a/include/retdec/bin2llvmir/providers/abi/mips.h +++ b/include/retdec/bin2llvmir/providers/abi/mips.h @@ -23,7 +23,7 @@ class AbiMips : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // diff --git a/include/retdec/bin2llvmir/providers/abi/mips64.h b/include/retdec/bin2llvmir/providers/abi/mips64.h new file mode 100644 index 000000000..7239227b6 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/mips64.h @@ -0,0 +1,37 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/mips64.h + * @brief ABI information for MIPS. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_MIPS64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_MIPS64_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiMips64 : public Abi +{ + // Ctors, dtors. + // + public: + AbiMips64(llvm::Module* m, Config* c); + virtual ~AbiMips64(); + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/include/retdec/bin2llvmir/providers/abi/ms_x64.h b/include/retdec/bin2llvmir/providers/abi/ms_x64.h new file mode 100644 index 000000000..8c64e5176 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/ms_x64.h @@ -0,0 +1,37 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/ms_x64.h + * @brief ABI information for x86_64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_MS_64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_MS_64_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiMS_X64 : public Abi +{ + // Ctors, dtors. + // + public: + AbiMS_X64(llvm::Module* m, Config* c); + virtual ~AbiMS_X64(); + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/include/retdec/bin2llvmir/providers/abi/pic32.h b/include/retdec/bin2llvmir/providers/abi/pic32.h new file mode 100644 index 000000000..e22863a33 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/pic32.h @@ -0,0 +1,43 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/pic32.h + * @brief ABI information for MIPS. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_PIC32_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_PIC32_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiPic32 : public Abi +{ + // Ctors, dtors. + // + public: + AbiPic32(llvm::Module* m, Config* c); + virtual ~AbiPic32(); + + // Types + // + public: + virtual std::size_t getTypeByteSize(llvm::Type* t) const override; + virtual std::size_t getTypeBitSize(llvm::Type* t) const override; + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/include/retdec/bin2llvmir/providers/abi/powerpc.h b/include/retdec/bin2llvmir/providers/abi/powerpc.h index 655087d17..0cf1df36d 100644 --- a/include/retdec/bin2llvmir/providers/abi/powerpc.h +++ b/include/retdec/bin2llvmir/providers/abi/powerpc.h @@ -23,7 +23,7 @@ class AbiPowerpc : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // diff --git a/include/retdec/bin2llvmir/providers/abi/powerpc64.h b/include/retdec/bin2llvmir/providers/abi/powerpc64.h new file mode 100644 index 000000000..1ad5b49d1 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/powerpc64.h @@ -0,0 +1,37 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/powerpc64.h + * @brief ABI information for PowerPC 64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_POWERPC64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_POWERPC64_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiPowerpc64 : public Abi +{ + // Ctors, dtors. + // + public: + AbiPowerpc64(llvm::Module* m, Config* c); + virtual ~AbiPowerpc64(); + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/include/retdec/bin2llvmir/providers/abi/x64.h b/include/retdec/bin2llvmir/providers/abi/x64.h new file mode 100644 index 000000000..2b5a1b34e --- /dev/null +++ b/include/retdec/bin2llvmir/providers/abi/x64.h @@ -0,0 +1,37 @@ +/** + * @file include/retdec/bin2llvmir/providers/abi/x64.h + * @brief ABI information for x86_64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_ABI_X64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_ABI_X64_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" + +namespace retdec { +namespace bin2llvmir { + +class AbiX64 : public Abi +{ + // Ctors, dtors. + // + public: + AbiX64(llvm::Module* m, Config* c); + virtual ~AbiX64(); + + // Registers. + // + public: + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; + + // Instructions. + // + public: + virtual bool isNopInstruction(cs_insn* insn) override; +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/include/retdec/bin2llvmir/providers/abi/x86.h b/include/retdec/bin2llvmir/providers/abi/x86.h index 2a135274a..d9cd25bf1 100644 --- a/include/retdec/bin2llvmir/providers/abi/x86.h +++ b/include/retdec/bin2llvmir/providers/abi/x86.h @@ -23,12 +23,18 @@ class AbiX86 : public Abi // Registers. // public: - virtual bool isGeneralPurposeRegister(const llvm::Value* val) override; + virtual bool isGeneralPurposeRegister(const llvm::Value* val) const override; // Instructions. // public: virtual bool isNopInstruction(cs_insn* insn) override; + + + // Calling conventions. + // + private: + CallingConvention::ID fetchDefaultCC() const; }; } // namespace bin2llvmir diff --git a/include/retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h new file mode 100644 index 000000000..b72f8112f --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h @@ -0,0 +1,33 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h + * @brief Calling conventions of ARM architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM_CONV_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class ArmCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + ArmCallingConvention(const Abi* a); + virtual ~ArmCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h new file mode 100644 index 000000000..ee9bf298c --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h @@ -0,0 +1,33 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h + * @brief Calling conventions of ARM64 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM64_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_ARM64_CONV_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class Arm64CallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + Arm64CallingConvention(const Abi* a); + virtual ~Arm64CallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/calling_convention.h b/include/retdec/bin2llvmir/providers/calling_convention/calling_convention.h new file mode 100644 index 000000000..f0d03bff8 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/calling_convention.h @@ -0,0 +1,154 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/calling_convention.h + * @brief Calling convention information. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_CALL_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_CALL_CONV_H + +#include + +#include + +#include "retdec/config/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class Abi; + +class CallingConvention +{ + // Typedefs. + // + public: + typedef std::unique_ptr Ptr; + typedef retdec::config::CallingConventionID ID; + + typedef Ptr (*ConstructorMethod)(const Abi*); + + // Constants. + // + public: + static const bool RTL; + static const bool LTR; + + // Ctors, dtors. + // + public: + CallingConvention(const Abi* abi); + virtual ~CallingConvention(); + + // Registers. + // + public: + const std::vector& getParamRegisters() const; + const std::vector& getParamFPRegisters() const; + const std::vector& getParamDoubleRegisters() const; + const std::vector& getParamVectorRegisters() const; + + const std::vector& getReturnRegisters() const; + const std::vector& getReturnFPRegisters() const; + const std::vector& getReturnDoubleRegisters() const; + const std::vector& getReturnVectorRegisters() const; + + bool usesFPRegistersForParameters() const; + + std::size_t getMaxNumOfRegsPerParam() const; + std::size_t getMaxNumOfFPRegsPerParam() const; + std::size_t getMaxNumOfDoubleRegsPerParam() const; + std::size_t getMaxNumOfVectorRegsPerParam() const; + + std::size_t getMaxNumOfRegsPerReturn() const; + std::size_t getMaxNumOfFPRegsPerReturn() const; + std::size_t getMaxNumOfDoubleRegsPerReturn() const; + std::size_t getMaxNumOfVectorRegsPerReturn() const; + + // Stacks. + public: + bool getStackParamOrder() const; + bool usesStackForParameters() const; + bool passesLargeObjectsByReference() const; + bool respectsRegisterCouples() const; + + virtual std::size_t getMaxBytesPerStackParam() const; + + // Values. + public: + virtual bool valueCanBeParameter(const llvm::Value* val) const; + virtual bool canHoldReturnValue(const llvm::Value* val) const; + + // Private data - misc. + // + protected: + const Abi* _abi; + CallingConvention::ID _ccType; + + // Private data - registers. + // + protected: + std::vector _paramRegs {}; + std::vector _paramFPRegs {}; + std::vector _paramDoubleRegs {}; + std::vector _paramVectorRegs {}; + + std::vector _returnRegs {}; + std::vector _returnFPRegs {}; + std::vector _returnDoubleRegs {}; + std::vector _returnVectorRegs {}; + + // Private data - registers informational. + // + protected: + size_t _numOfRegsPerParam = 1; + size_t _numOfFPRegsPerParam = 1; + size_t _numOfDoubleRegsPerParam = 1; + size_t _numOfVectorRegsPerParam = 1; + + size_t _numOfRegsPerReturn = 1; + size_t _numOfFPRegsPerReturn = 1; + size_t _numOfDoubleRegsPerReturn = 1; + size_t _numOfVectorRegsPerReturn = 1; + + // Private data - stacks informational. + // + protected: + bool _stackParamOrder = RTL; + bool _largeObjectsPassedByReference = false; + bool _respectsRegCouples = false; +}; + +class CallingConventionProvider +{ + // Private constructor. + // + private: + CallingConventionProvider(); + + // Destructor, singleton method. + public: + ~CallingConventionProvider(); + static CallingConventionProvider* getProvider(); + + // Factory methods. + public: + void registerCC( + const CallingConvention::ID& cc, + const CallingConvention::ConstructorMethod& con); + + CallingConvention::Ptr createCallingConvention( + const CallingConvention::ID& cc, + const Abi* a) const; + + // Private data - constrctor methods. + private: + std::vector _id2cc; + +}; + +} // namespace bin2llvmir +} // namespace retdec + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h new file mode 100644 index 000000000..0af41dadf --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h @@ -0,0 +1,33 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h + * @brief Calling convention of MIPS architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS_CONV_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class MipsCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + MipsCallingConvention(const Abi* a); + virtual ~MipsCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h b/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h new file mode 100644 index 000000000..8b1eacb13 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h @@ -0,0 +1,27 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h + * @brief Calling convention of MIPS architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS_MIPS_PSP_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS_MIPS_PSP_CONV_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class MipsPSPCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + MipsPSPCallingConvention(const Abi* a); + virtual ~MipsPSPCallingConvention(); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h new file mode 100644 index 000000000..2ade02f52 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h @@ -0,0 +1,33 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h + * @brief Calling convention of Mips64 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS64_MIPS64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_MIPS64_MIPS64_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class Mips64CallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + Mips64CallingConvention(const Abi* a); + virtual ~Mips64CallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h new file mode 100644 index 000000000..3af3180f6 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h @@ -0,0 +1,33 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h + * @brief Calling conventions of PIC32 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_PIC32_PIC32_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_PIC32_PIC32_CONV_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class Pic32CallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + Pic32CallingConvention(const Abi* a); + virtual ~Pic32CallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h new file mode 100644 index 000000000..ac2b11eca --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h @@ -0,0 +1,33 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h + * @brief Calling conventions of PowerPC architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_POWERPC_POWERPC_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_POWERPC_POWERPC_CONV_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class PowerPCCallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + PowerPCCallingConvention(const Abi* a); + virtual ~PowerPCCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h new file mode 100644 index 000000000..e8fd47637 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h @@ -0,0 +1,33 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h + * @brief Calling conventions of PowerPC64 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_PPC64_PPC64_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_PPC64_PPC64_CONV_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class PowerPC64CallingConvention: public CallingConvention +{ + // Ctors, dtors. + // + public: + PowerPC64CallingConvention(const Abi* a); + virtual ~PowerPC64CallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); + +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h new file mode 100644 index 000000000..0ca84ac24 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h @@ -0,0 +1,26 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h + * @brief Calling convention of X64 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_X64_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_X64_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class X64CallingConvention : public CallingConvention +{ + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h new file mode 100644 index 000000000..bf8cdbb64 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h @@ -0,0 +1,27 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h + * @brief MS Windows calling convention of X64 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_X64_MICROSOFT_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_X64_MICROSOFT_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class MicrosoftX64CallingConvention : public CallingConvention +{ + // Ctors, dtors. + // + public: + MicrosoftX64CallingConvention(const Abi* a); + virtual ~MicrosoftX64CallingConvention(); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h new file mode 100644 index 000000000..9e7ecaf98 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h @@ -0,0 +1,27 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h + * @brief System V calling convention of X64 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_X64_SYSV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X64_X64_SYSV_H + +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class SystemVX64CallingConvention : public CallingConvention +{ + // Ctors, dtors. + // + public: + SystemVX64CallingConvention(const Abi* a); + virtual ~SystemVX64CallingConvention(); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h new file mode 100644 index 000000000..28c6fe708 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h @@ -0,0 +1,32 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h + * @brief Cdecl calling convention of x86 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_CDECL_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_CDECL_H + +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h" + +namespace retdec { +namespace bin2llvmir { + +class CdeclCallingConvention: public X86CallingConvention +{ + // Ctors, dtors. + // + public: + CdeclCallingConvention(const Abi* a); + virtual ~CdeclCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h new file mode 100644 index 000000000..2f683b70c --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h @@ -0,0 +1,31 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h + * @brief Common calling convention of x86 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_CONV_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_CONV_H + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" + +namespace retdec { +namespace bin2llvmir { + +class X86CallingConvention: public CallingConvention +{ + // Ctors. + public: + X86CallingConvention(const Abi* a); + + // Stacks. + // + public: + virtual std::size_t getMaxBytesPerStackParam() const override; +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h new file mode 100644 index 000000000..adca69322 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h @@ -0,0 +1,41 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h + * @brief Fastcall calling convention of x86 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_FASTCALL_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_FASTCALL_H + +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h" + +namespace retdec { +namespace bin2llvmir { + +class FastcallCallingConvention: public X86CallingConvention +{ + // Ctors, dtors. + // + public: + FastcallCallingConvention(const Abi* a); + virtual ~FastcallCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +class PascalFastcallCallingConvention: public X86CallingConvention +{ + // Ctors, dtors. + // + public: + PascalFastcallCallingConvention(const Abi* a); + virtual ~PascalFastcallCallingConvention(); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h new file mode 100644 index 000000000..fa142f7fd --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h @@ -0,0 +1,32 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h + * @brief Pascal calling convention of x86 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_PASCAL_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_PASCAL_H + +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h" + +namespace retdec { +namespace bin2llvmir { + +class PascalCallingConvention: public X86CallingConvention +{ + // Ctors, dtors. + // + public: + PascalCallingConvention(const Abi* a); + virtual ~PascalCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h new file mode 100644 index 000000000..338382b81 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h @@ -0,0 +1,32 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h + * @brief Thiscall calling convention of x86 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_THISCALL_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_THISCALL_H + +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h" + +namespace retdec { +namespace bin2llvmir { + +class ThiscallCallingConvention: public X86CallingConvention +{ + // Ctors, dtors. + // + public: + ThiscallCallingConvention(const Abi* a); + virtual ~ThiscallCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +} +} + +#endif diff --git a/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h new file mode 100644 index 000000000..fc867e800 --- /dev/null +++ b/include/retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h @@ -0,0 +1,32 @@ +/** + * @file include/retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h + * @brief Common calling convention of x86 architecture. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_WATCOM_H +#define RETDEC_BIN2LLVMIR_PROVIDERS_CALL_CONV_X86_X86_WATCOM_H + +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h" + +namespace retdec { +namespace bin2llvmir { + +class WatcomCallingConvention: public X86CallingConvention +{ + // Ctors, dtors. + // + public: + WatcomCallingConvention(const Abi* a); + virtual ~WatcomCallingConvention(); + + // Construcor method. + // + public: + static CallingConvention::Ptr create(const Abi* a); +}; + +} +} + +#endif diff --git a/include/retdec/config/architecture.h b/include/retdec/config/architecture.h index dee16b660..f3ed217d2 100644 --- a/include/retdec/config/architecture.h +++ b/include/retdec/config/architecture.h @@ -25,6 +25,7 @@ class Architecture bool isUnknown() const; bool isKnown() const; bool isMips() const; + bool isMips64() const; bool isPic32() const; bool isMipsOrPic32() const; bool isArm() const; @@ -36,6 +37,7 @@ class Architecture bool isX86_32() const; bool isX86_64() const; bool isPpc() const; + bool isPpc64() const; bool isEndianLittle() const; bool isEndianBig() const; bool isEndianKnown() const; @@ -49,6 +51,7 @@ class Architecture void setIsPic32(); void setIsArm(); void setIsThumb(); + void setIsArm64(); void setIsX86(); void setIsPpc(); void setIsEndianLittle(); diff --git a/include/retdec/config/calling_convention.h b/include/retdec/config/calling_convention.h index af90e95f8..9743a9826 100644 --- a/include/retdec/config/calling_convention.h +++ b/include/retdec/config/calling_convention.h @@ -81,7 +81,7 @@ class CallingConvention Json::Value getJsonValue() const; void readJsonValue(const Json::Value& val); - private: + public: enum class eCallingConvention { CC_UNKNOWN = 0, @@ -96,14 +96,32 @@ class CallingConvention CC_SPOILED, CC_SPECIALE, CC_SPECIALP, - CC_SPECIAL + CC_SPECIAL, + CC_WATCOM, + CC_X64, + CC_ARM, + CC_ARM64, + CC_MIPS, + CC_MIPS64, + CC_POWERPC, + CC_POWERPC64, + CC_PIC32, + CC_ENDING, }; - eCallingConvention _callingConvention = eCallingConvention::CC_UNKNOWN; + + eCallingConvention getID() const; + + friend std::ostream& operator<< (std::ostream &out, const eCallingConvention& cc); private: CallingConvention(eCallingConvention cc); + + private: + eCallingConvention _callingConvention = eCallingConvention::CC_UNKNOWN; }; +typedef CallingConvention::eCallingConvention CallingConventionID; + } // namespace config } // namespace retdec diff --git a/include/retdec/cpdetect/compiler_detector/compiler_detector.h b/include/retdec/cpdetect/compiler_detector/compiler_detector.h index ebb6583c3..338bdb268 100644 --- a/include/retdec/cpdetect/compiler_detector/compiler_detector.h +++ b/include/retdec/cpdetect/compiler_detector/compiler_detector.h @@ -9,7 +9,6 @@ #include "retdec/utils/filesystem_path.h" #include "retdec/utils/non_copyable.h" -#include "yaracpp/yara_detector/yara_detector.h" #include "retdec/cpdetect/compiler_detector/heuristics/heuristics.h" #include "retdec/cpdetect/compiler_detector/search/search.h" diff --git a/include/retdec/fileformat/file_format/pe/pe_format.h b/include/retdec/fileformat/file_format/pe/pe_format.h index 013a432e4..a52dcc931 100644 --- a/include/retdec/fileformat/file_format/pe/pe_format.h +++ b/include/retdec/fileformat/file_format/pe/pe_format.h @@ -18,6 +18,7 @@ #include "retdec/fileformat/types/dotnet_headers/string_stream.h" #include "retdec/fileformat/types/dotnet_headers/user_string_stream.h" #include "retdec/fileformat/types/dotnet_types/dotnet_class.h" +#include "retdec/fileformat/types/visual_basic/visual_basic_info.h" namespace retdec { namespace fileformat { @@ -44,6 +45,7 @@ class PeFormat : public FileFormat std::string typeRefHashCrc32; ///< .NET typeref table hash as CRC32 std::string typeRefHashMd5; ///< .NET typeref table hash as MD5 std::string typeRefHashSha256; ///< .NET typeref table hash as SHA256 + VisualBasicInfo visualBasicInfo; ///< visual basic header information /// @name Initialization methods /// @{ @@ -65,6 +67,7 @@ class PeFormat : public FileFormat void loadSymbols(); void loadImports(); void loadExports(); + void loadVisualBasicHeader(); void loadPdbInfo(); void loadResourceNodes(std::vector &nodes, const std::vector &levels); void loadResources(); @@ -93,6 +96,16 @@ class PeFormat : public FileFormat std::uint64_t detectPossibleMetadataHeaderAddress() const; void computeTypeRefHashes(); /// @} + /// @name Visual Basic methods + /// @{ + bool parseVisualBasicProjectInfo(std::size_t structureOffset); + bool parseVisualBasicExternTable(std::size_t structureOffset, std::size_t nEntries); + bool parseVisualBasicObjectTable(std::size_t structureOffset); + bool parseVisualBasicObjects(std::size_t structureOffset, std::size_t nObjects); + bool parseVisualBasicComRegistrationData(std::size_t structureOffset); + bool parseVisualBasicComRegistrationInfo(std::size_t structureOffset, + std::size_t comRegDataOffset); + /// @} protected: PeLib::PeFile *file; ///< PeLib representation of PE file PeLib::PeHeaderT<32> *peHeader32; ///< header of 32-bit PE file @@ -180,6 +193,7 @@ class PeFormat : public FileFormat const std::string& getTypeRefhashCrc32() const; const std::string& getTypeRefhashMd5() const; const std::string& getTypeRefhashSha256() const; + const VisualBasicInfo* getVisualBasicInfo() const; /// @} }; diff --git a/include/retdec/fileformat/types/resource_table/bitmap_image.h b/include/retdec/fileformat/types/resource_table/bitmap_image.h index 315b96e15..8dfe67d3c 100644 --- a/include/retdec/fileformat/types/resource_table/bitmap_image.h +++ b/include/retdec/fileformat/types/resource_table/bitmap_image.h @@ -77,11 +77,6 @@ class BitmapImage const std::vector> &getImage() const; /// @} - /// @name Setters - /// @{ - // TODO - /// @} - /// @name Other methods /// @{ bool parseDibFormat(const ResourceIcon &icon); diff --git a/include/retdec/fileformat/types/visual_basic/visual_basic_extern.h b/include/retdec/fileformat/types/visual_basic/visual_basic_extern.h new file mode 100644 index 000000000..ff8bcf193 --- /dev/null +++ b/include/retdec/fileformat/types/visual_basic/visual_basic_extern.h @@ -0,0 +1,43 @@ +/** + * @file include/retdec/fileformat/types/visual_basic/visual_basic_extern.h + * @brief Class for visual basic extern. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_FILEFORMAT_TYPES_VISUAL_BASIC_VISUAL_BASIC_EXTERN_H +#define RETDEC_FILEFORMAT_TYPES_VISUAL_BASIC_VISUAL_BASIC_EXTERN_H + +#include + +namespace retdec { +namespace fileformat { + +/** + * Class for visual basic information + */ +class VisualBasicExtern +{ + private: + std::string moduleName; + std::string apiName; + public: + VisualBasicExtern(); + ~VisualBasicExtern(); + + /// @name Getters + /// @{ + const std::string &getModuleName() const; + const std::string &getApiName() const; + /// @} + + /// @name Setters + /// @{ + void setModuleName(const std::string &mName); + void setApiName(const std::string &aName); + /// @} +}; + +} // namespace fileformat +} // namespace retdec + +#endif diff --git a/include/retdec/fileformat/types/visual_basic/visual_basic_info.h b/include/retdec/fileformat/types/visual_basic/visual_basic_info.h new file mode 100644 index 000000000..a6281eef0 --- /dev/null +++ b/include/retdec/fileformat/types/visual_basic/visual_basic_info.h @@ -0,0 +1,166 @@ +/** + * @file include/retdec/fileformat/types/visual_basic/visual_basic_info.h + * @brief Class for visual basic information. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_FILEFORMAT_TYPES_VISUAL_BASIC_VISUAL_BASIC_INFO_H +#define RETDEC_FILEFORMAT_TYPES_VISUAL_BASIC_VISUAL_BASIC_INFO_H + +#include +#include +#include + +#include "retdec/fileformat/types/visual_basic/visual_basic_object.h" +#include "retdec/fileformat/types/visual_basic/visual_basic_extern.h" + +namespace retdec { +namespace fileformat { + +/** + * Class for visual basic information + */ +class VisualBasicInfo +{ + private: + // VB Header + std::string languageDLL; + std::string backupLanguageDLL; + std::string projectExeName; + std::string projectDescription; + std::string projectHelpFile; + std::string projectName; + std::uint32_t languageDLLPrimaryLCID; + std::uint32_t languageDLLSecondaryLCID; + + // VB Proj Info + std::string projectPath; + + // VB Object table + std::string objectTableGUID; + std::uint32_t projectPrimaryLCID; + std::uint32_t projectSecondaryLCID; + std::vector> objects; + + // VB extern table + std::vector> externs; + + // COM register data + std::string typeLibCLSID; + std::uint32_t typeLibLCID; + std::uint16_t typeLibMajorVersion; + std::uint16_t typeLibMinorVersion; + + // COM register info + std::string COMObjectName; + std::string COMObjectDescription; + std::string COMObjectCLSID; + std::string COMObjectInterfaceCLSID; + std::string COMObjectEventsCLSID; + std::string COMObjectType; + + // others + std::string externTableHashCrc32; + std::string externTableHashMd5; + std::string externTableHashSha256; + std::string objectTableHashCrc32; + std::string objectTableHashMd5; + std::string objectTableHashSha256; + + bool validLanguageDLLPrimaryLCID; + bool validLanguageDLLSecondaryLCID; + bool validProjectPrimaryLCID; + bool validProjectSecondaryLCID; + bool validTypeLibLCID; + bool validTypeLibMajorVersion; + bool validTypeLibMinorVersion; + bool pcodeFlag; + + std::string guidToStr(const std::uint8_t data[16]); + + public: + VisualBasicInfo(); + ~VisualBasicInfo(); + + /// @name Getters + /// @{ + const std::string &getLanguageDLL() const; + const std::string &getBackupLanguageDLL() const; + const std::string &getProjectExeName() const; + const std::string &getProjectDescription() const; + const std::string &getProjectHelpFile() const; + const std::string &getProjectName() const; + bool getLanguageDLLPrimaryLCID(std::uint32_t &res) const; + bool getLanguageDLLSecondaryLCID(std::uint32_t &res) const; + const std::string &getProjectPath() const; + bool getProjectPrimaryLCID(std::uint32_t &res) const; + bool getProjectSecondaryLCID(std::uint32_t &res) const; + const std::vector> &getObjects() const; + const std::vector> &getExterns() const; + const VisualBasicObject *getObject(std::size_t position) const; + const VisualBasicExtern *getExtern(std::size_t position) const; + std::size_t getNumberOfObjects() const; + std::size_t getNumberOfExterns() const; + const std::string &getObjectTableGUID() const; + const std::string &getTypeLibCLSID() const; + bool getTypeLibLCID(std::uint32_t &res) const; + bool getTypeLibMajorVersion(std::uint16_t &res) const; + bool getTypeLibMinorVersion(std::uint16_t &res) const; + const std::string &getCOMObjectName() const; + const std::string &getCOMObjectDescription() const; + const std::string &getCOMObjectCLSID() const; + const std::string &getCOMObjectInterfaceCLSID() const; + const std::string &getCOMObjectEventsCLSID() const; + const std::string &getCOMObjectType() const; + const std::string &getExternTableHashCrc32() const; + const std::string &getExternTableHashMd5() const; + const std::string &getExternTableHashSha256() const; + const std::string &getObjectTableHashCrc32() const; + const std::string &getObjectTableHashMd5() const; + const std::string &getObjectTableHashSha256() const; + /// @} + + /// @name Setters + /// @{ + void setLanguageDLL(const std::string &lDll); + void setBackupLanguageDLL(const std::string &blDll); + void setProjectExeName(const std::string &exeName); + void setProjectDescription(const std::string &desc); + void setProjectHelpFile(const std::string &helpFile); + void setProjectName(const std::string &name); + void setLanguageDLLPrimaryLCID(std::uint32_t lDllPrimLCID); + void setLanguageDLLSecondaryLCID(std::uint32_t lDllSecLCID); + void setProjectPath(const std::string &path); + void setProjectPrimaryLCID(std::uint32_t primLCID); + void setProjectSecondaryLCID(std::uint32_t secLCID); + void setTypeLibCLSID(const std::uint8_t data[16]); + void setTypeLibLCID(std::uint32_t tlbLCID); + void setPcode(bool set); + void setObjectTableGUID(const std::uint8_t data[16]); + void setTypeLibMajorVersion(std::uint16_t majVer); + void setTypeLibMinorVersion(std::uint16_t minVer); + void setCOMObjectName(const std::string &name); + void setCOMObjectDescription(const std::string &description); + void setCOMObjectCLSID(const std::uint8_t data[16]); + void setCOMObjectInterfaceCLSID(const std::uint8_t data[16]); + void setCOMObjectEventsCLSID(const std::uint8_t data[16]); + void setCOMObjectType(std::uint8_t type); + /// @} + + /// @name Other methods + /// @{ + void addObject(std::unique_ptr&& obj); + void addExtern(std::unique_ptr&& ext); + bool hasProjectName() const; + bool hasProjectDescription() const; + bool hasProjectHelpFile() const; + bool isPcode() const; + void computeExternTableHashes(); + void computeObjectTableHashes(); + /// @} +}; + +} // namespace fileformat +} // namespace retdec + +#endif diff --git a/include/retdec/fileformat/types/visual_basic/visual_basic_object.h b/include/retdec/fileformat/types/visual_basic/visual_basic_object.h new file mode 100644 index 000000000..0886ddf18 --- /dev/null +++ b/include/retdec/fileformat/types/visual_basic/visual_basic_object.h @@ -0,0 +1,49 @@ +/** + * @file include/retdec/fileformat/types/visual_basic/visual_basic_object.h + * @brief Class for visual basic object. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_FILEFORMAT_TYPES_VISUAL_BASIC_VISUAL_BASIC_OBJECT_H +#define RETDEC_FILEFORMAT_TYPES_VISUAL_BASIC_VISUAL_BASIC_OBJECT_H + +#include +#include + +namespace retdec { +namespace fileformat { + +/** + * Class for visual basic information + */ +class VisualBasicObject +{ + private: + std::string name; + std::vector methods; + public: + VisualBasicObject(); + ~VisualBasicObject(); + + /// @name Getters + /// @{ + const std::string &getName() const; + const std::vector &getMethods() const; + std::size_t getNumberOfMethods() const; + /// @} + + /// @name Setters + /// @{ + void setName(const std::string &n); + /// @} + + /// @name Other methods + /// @{ + void addMethod(const std::string &method); + /// @} +}; + +} // namespace fileformat +} // namespace retdec + +#endif diff --git a/include/retdec/fileformat/types/visual_basic/visual_basic_structures.h b/include/retdec/fileformat/types/visual_basic/visual_basic_structures.h new file mode 100644 index 000000000..56e70ff68 --- /dev/null +++ b/include/retdec/fileformat/types/visual_basic/visual_basic_structures.h @@ -0,0 +1,227 @@ +/** + * @file include/retdec/fileformat/types/visual_basic/visual_basic_structures.h + * @brief Visual basic metadata structures. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef RETDEC_FILEFORMAT_TYPES_VISUAL_BASIC_VISUAL_BASIC_STRUCTURES_H +#define RETDEC_FILEFORMAT_TYPES_VISUAL_BASIC_VISUAL_BASIC_STRUCTURES_H + +#include + +namespace retdec { +namespace fileformat { + +constexpr std::size_t VBHEADER_SIGNATURE = 0x21354256; +constexpr std::size_t VB_MAX_STRING_LEN = 100; + +enum class VBExternTableEntryType +{ + internal = 0x6, + external = 0x7 +}; + +struct VBHeader +{ + std::uint32_t signature; ///< "VB5!" signature + std::uint16_t runtimeBuild; ///< runtime flag + std::uint8_t languageDLL[14]; ///< language DLL + std::uint8_t backupLanguageDLL[14]; ///< backup language DLL + std::uint16_t runtimeDLLVersion; ///< version of the runtime DLL + std::uint32_t LCID1; ///< primary LCID + std::uint32_t LCID2; ///< backup LCID + std::uint32_t subMainAddr; ///< sub main code address + std::uint32_t projectInfoAddr; ///< ProjectInfo address + std::uint32_t MDLIntObjsFlags; ///< VB controll flags for IDs < 32 + std::uint32_t MDLIntObjsFlags2; ///< VB controll flags for IDs > 32 + std::uint32_t threadFlags; ///< thread flags + std::uint32_t nThreads; ///< number of threads to support in pool + std::uint16_t nForms; ///< number of forms in this application + std::uint16_t nExternals; ///< number of external OCX components + std::uint32_t nThunks; ///< number of thunks to create + std::uint32_t GUITableAddr; ///< GUITable address + std::uint32_t externalTableAddr; ///< ExternalTable address + std::uint32_t COMRegisterDataAddr; ///< ComRegisterData address + std::uint32_t projExeNameOffset; ///< offset to the string containing EXE filename + std::uint32_t projDescOffset; ///< offset to the string containing project's description + std::uint32_t helpFileOffset; ///< offset to the string containing name of the Help file + std::uint32_t projNameOffset; ///< offset to the string containing project's name + + static std::size_t structureSize() + { + return + sizeof(signature) + sizeof(runtimeBuild) + sizeof(languageDLL) + + sizeof(backupLanguageDLL) + sizeof(runtimeDLLVersion) + sizeof(LCID1) + + sizeof(LCID2) + sizeof(subMainAddr) + sizeof(projectInfoAddr) + + sizeof(MDLIntObjsFlags) + sizeof(MDLIntObjsFlags2) + sizeof(threadFlags) + + sizeof(nThreads) + sizeof(nForms) + sizeof(nExternals) + + sizeof(nThunks) + sizeof(GUITableAddr) + sizeof(externalTableAddr) + + sizeof(COMRegisterDataAddr) + sizeof(projExeNameOffset) + sizeof(projDescOffset) + + sizeof(helpFileOffset) + sizeof(projNameOffset); + } +}; + +struct VBProjInfo +{ + std::uint32_t version; ///< 5.00 in Hex (0x1F4), version + std::uint32_t objectTableAddr; ///< Object table address + std::uint32_t null; ///< unused value after compilation + std::uint32_t codeStartAddr; ///< etart of code address + std::uint32_t codeEndAddr; ///< end of code address + std::uint32_t dataSize; ///< size of VB object structures + std::uint32_t threadSpaceAddr; ///< eddress of address of thread object + std::uint32_t exHandlerAddr; ///< VBA exception handler address + std::uint32_t nativeCodeAddr; ///< .DATA section address + std::uint8_t pathInformation[528]; ///< path and id string, getSupportedFileFormats(); std::vector getSupportedArchitectures(); +std::string lcidToStr(std::size_t lcid); } // namespace fileformat } // namespace retdec diff --git a/include/retdec/unpacker/decompression/compressed_data.h b/include/retdec/unpacker/decompression/compressed_data.h index 46606555c..b2635df9f 100644 --- a/include/retdec/unpacker/decompression/compressed_data.h +++ b/include/retdec/unpacker/decompression/compressed_data.h @@ -10,7 +10,9 @@ #include #include -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" + +using namespace retdec::utils; namespace retdec { namespace unpacker { diff --git a/include/retdec/unpacker/decompression/nrv/bit_parsers.h b/include/retdec/unpacker/decompression/nrv/bit_parsers.h index 7e777325e..1f1405ff2 100644 --- a/include/retdec/unpacker/decompression/nrv/bit_parsers.h +++ b/include/retdec/unpacker/decompression/nrv/bit_parsers.h @@ -8,7 +8,9 @@ #define RETDEC_UNPACKER_DECOMPRESSION_NRV_BIT_PARSERS_H #include "retdec/fileformat/fftypes.h" -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" + +using namespace retdec::utils; namespace retdec { namespace unpacker { diff --git a/include/retdec/unpacker/signature.h b/include/retdec/unpacker/signature.h index aa6fee992..6be6f5c16 100644 --- a/include/retdec/unpacker/signature.h +++ b/include/retdec/unpacker/signature.h @@ -12,7 +12,7 @@ #include #include "retdec/loader/loader.h" -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" namespace retdec { namespace unpacker { @@ -153,17 +153,18 @@ class Signature uint64_t getCaptureSize() const; bool match(const MatchSettings& settings, retdec::loader::Image* file) const; - bool match(const MatchSettings& settings, const DynamicBuffer& data) const; - bool match(const MatchSettings& settings, retdec::loader::Image* file, DynamicBuffer& captures) const; - bool match(const MatchSettings& settings, const DynamicBuffer& data, DynamicBuffer& captures) const; + bool match(const MatchSettings& settings, const retdec::utils::DynamicBuffer& data) const; + bool match(const MatchSettings& settings, retdec::loader::Image* file, retdec::utils::DynamicBuffer& capturedData) const; + bool match(const MatchSettings& settings, const retdec::utils::DynamicBuffer& data, + retdec::utils::DynamicBuffer& capturedData) const; Signature& operator =(const std::initializer_list& initList); private: Signature& operator =(const Signature&); - bool searchMatchImpl(const std::vector& bytesToMatch, uint64_t offset, uint64_t maxSearchDist, DynamicBuffer* captureBuffer) const; - int64_t matchImpl(const std::vector& bytesToMatch, uint64_t offset, DynamicBuffer* captureBuffer) const; + bool searchMatchImpl(const std::vector& bytesToMatch, uint64_t offset, uint64_t maxSearchDist, retdec::utils::DynamicBuffer* captureBuffer) const; + int64_t matchImpl(const std::vector& bytesToMatch, uint64_t offset, retdec::utils::DynamicBuffer* captureBuffer) const; std::vector _buffer; ///< Signature bytes buffer. }; diff --git a/include/retdec/unpacker/unpacking_stub.h b/include/retdec/unpacker/unpacking_stub.h index 3027579c6..1a115ae58 100644 --- a/include/retdec/unpacker/unpacking_stub.h +++ b/include/retdec/unpacker/unpacking_stub.h @@ -13,7 +13,7 @@ namespace retdec { // Forward declarations namespace loader { class Image; } -namespace unpacker { class DynamicBuffer; } +namespace utils { class DynamicBuffer; } namespace unpacker { diff --git a/include/retdec/unpacker/dynamic_buffer.h b/include/retdec/utils/dynamic_buffer.h similarity index 94% rename from include/retdec/unpacker/dynamic_buffer.h rename to include/retdec/utils/dynamic_buffer.h index 9ad6cef78..e791c4ad1 100644 --- a/include/retdec/unpacker/dynamic_buffer.h +++ b/include/retdec/utils/dynamic_buffer.h @@ -1,5 +1,5 @@ /** - * @file include/retdec/unpacker/dynamic_buffer.h + * @file include/retdec/utils/dynamic_buffer.h * @brief Declaration of class for buffered data mainpulation. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ @@ -12,10 +12,10 @@ #include #include -#include "retdec/fileformat/fileformat.h" +#include "retdec/utils/byte_value_storage.h" namespace retdec { -namespace unpacker { +namespace utils { /** * @brief The class for dynamic buffered data manipulation taking the endianness of the data in account. @@ -70,7 +70,7 @@ class DynamicBuffer */ template T read(uint32_t pos, retdec::utils::Endianness endianness = retdec::utils::Endianness::UNKNOWN) const { - static_assert(std::is_integral::value, "retdec::unpacker::DynamicBuffer::read can only accept integral types"); + static_assert(std::is_integral::value, "retdec::utils::DynamicBuffer::read can only accept integral types"); // In case of non-specified endianness, use the default one assigned to DynamicBuffer itself if (endianness == retdec::utils::Endianness::UNKNOWN) @@ -94,7 +94,7 @@ class DynamicBuffer */ template void write(const T& data, uint32_t pos, retdec::utils::Endianness endianness = retdec::utils::Endianness::UNKNOWN) { - static_assert(std::is_integral::value, "retdec::unpacker::DynamicBuffer::write can only accept integral types"); + static_assert(std::is_integral::value, "retdec::utils::DynamicBuffer::write can only accept integral types"); // In case of non-specified endianness, use the default one assigned to DynamicBuffer itself if (endianness == retdec::utils::Endianness::UNKNOWN) @@ -182,7 +182,7 @@ class DynamicBuffer uint32_t _capacity; }; -} // namespace unpacker +} // namespace utils } // namespace retdec #endif diff --git a/include/retdec/utils/string.h b/include/retdec/utils/string.h index 021d7e519..1432708e9 100644 --- a/include/retdec/utils/string.h +++ b/include/retdec/utils/string.h @@ -51,6 +51,9 @@ std::string toLower(std::string str); std::string toUpper(std::string str); std::string toWide(const std::string &str, std::string::size_type length); +std::string unicodeToAscii(const std::uint8_t *bytes, std::size_t nBytes); +std::string readNullTerminatedAscii(const std::uint8_t *bytes, std::size_t bytesLen, + std::size_t offset = 0, std::size_t maxBytes = 0, bool failOnExceed = false); std::string trim(std::string str, const std::string &toTrim = " \t\r\n\v"); diff --git a/scripts/retdec-config.py b/scripts/retdec-config.py index 5b4323276..99cde3606 100644 --- a/scripts/retdec-config.py +++ b/scripts/retdec-config.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 import os - +from sys import platform SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) @@ -176,5 +176,10 @@ UNPACKER = os.path.join(INSTALL_BIN_DIR, 'retdec-unpacker') # Other. -LOG_TIME = ['/usr/bin/time', '-v'] + +if platform == "darwin": + # mac os x need the `gnu-time´ package + LOG_TIME = ['/usr/local/bin/gtime', '-v'] +else: + LOG_TIME = ['/usr/bin/time', '-v'] LOG_TIMEOUT = 300 diff --git a/scripts/retdec-decompiler.py b/scripts/retdec-decompiler.py index ee024af95..e16084fbd 100644 --- a/scripts/retdec-decompiler.py +++ b/scripts/retdec-decompiler.py @@ -38,8 +38,8 @@ def parse_args(args): parser.add_argument('-a', '--arch', dest='arch', metavar='ARCH', - choices=['mips', 'pic32', 'arm', 'arm64', 'thumb', 'powerpc', 'x86'], - help='Specify target architecture [mips|pic32|arm|arm64|thumb|powerpc|x86].' + choices=['mips', 'pic32', 'arm', 'thumb', 'arm64', 'powerpc', 'x86', 'x86-64'], + help='Specify target architecture [mips|pic32|arm|thumb|arm64|powerpc|x86|x86-64].' ' Required if it cannot be autodetected from the input (e.g. raw mode, Intel HEX).') parser.add_argument('-e', '--endian', @@ -882,7 +882,10 @@ def decompile(self): arch_full = arch_full.lower() # Strip comments in parentheses and all trailing whitespace - self.arch = arch_full.split(' ')[0] + if 'aarch64' in arch_full: + self.arch = 'arm64' + else: + self.arch = arch_full.split(' ')[0] # Get object file format. self.format, _, _ = CmdRunner.run_cmd([config.CONFIGTOOL, self.config_file, '--read', '--format'], buffer_output=True) @@ -907,7 +910,7 @@ def decompile(self): # Check whether the correct target architecture was specified. if self.arch in ['arm', 'thumb', 'arm64']: ords_dir = config.ARM_ORDS_DIR - elif self.arch in ['x86']: + elif self.arch in ['x86', 'x86-64']: ords_dir = config.X86_ORDS_DIR elif self.arch in ['powerpc', 'mips', 'pic32']: pass @@ -917,7 +920,7 @@ def decompile(self): self._cleanup() utils.print_error('Unsupported target architecture \'%s\'. Supported architectures: ' - 'Intel x86, ARM, ARM + Thumb, ARM64, MIPS, PIC32, PowerPC.' % self.arch) + 'Intel x86, Intel x86-64, ARM, ARM + Thumb, ARM64, MIPS, PIC32, PowerPC.' % self.arch) return 1 # Check file class (e.g. 'ELF32', 'ELF64'). At present, we can only decompile 32-bit files. @@ -934,6 +937,18 @@ def decompile(self): self.format.upper(), fileclass)) return 1 + # TODO this should be somehow connected somewhere else + if fileclass == '64' and self.arch in ['arm', 'mips', 'pic32', 'powerpc', 'x86']: + if self.args.generate_log: + self.generate_log() + + self._cleanup() + utils.print_error( + 'Unsupported target format and architecture combination: \'%s%s\' + \'%s\'.' % ( + self.format.upper(), fileclass, self.arch)) + + return 1 + # Set path to statically linked code signatures. # # TODO: Using ELF for IHEX is ok, but for raw, we probably should somehow decide between ELF and PE, @@ -961,6 +976,8 @@ def decompile(self): if sig_arch == 'pic32': sig_arch = 'mips' + elif sig_arch == 'x86-64': + sig_arch = 'x86'; signatures_dir = os.path.join(config.GENERIC_SIGNATURES_DIR, sig_format, fileclass, sig_endian, sig_arch) diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 06862c014..4992e0867 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -49,7 +49,12 @@ set(BIN2LLVMIR_SOURCES optimizations/inst_opt/inst_opt.cpp optimizations/local_vars/local_vars.cpp optimizations/main_detection/main_detection.cpp + optimizations/param_return/collector/collector.cpp + optimizations/param_return/collector/pic32.cpp + optimizations/param_return/filter/filter.cpp + optimizations/param_return/filter/ms_x64.cpp optimizations/param_return/param_return.cpp + optimizations/param_return/data_entries.cpp optimizations/phi2seq/phi2seq.cpp optimizations/provider_init/provider_init.cpp optimizations/x86_addr_spaces/x86_addr_spaces_pass.cpp @@ -69,8 +74,31 @@ set(BIN2LLVMIR_SOURCES providers/abi/arm.cpp providers/abi/arm64.cpp providers/abi/mips.cpp + providers/abi/mips64.cpp + providers/abi/ms_x64.cpp + providers/abi/pic32.cpp providers/abi/powerpc.cpp + providers/abi/powerpc64.cpp + providers/abi/x64.cpp providers/abi/x86.cpp + providers/calling_convention/calling_convention.cpp + providers/calling_convention/arm/arm_conv.cpp + providers/calling_convention/arm64/arm64_conv.cpp + providers/calling_convention/mips/mips_conv.cpp + providers/calling_convention/mips/mips_psp.cpp + providers/calling_convention/mips64/mips64_conv.cpp + providers/calling_convention/pic32/pic32_conv.cpp + providers/calling_convention/powerpc/powerpc_conv.cpp + providers/calling_convention/powerpc64/powerpc64_conv.cpp + providers/calling_convention/x64/x64_conv.cpp + providers/calling_convention/x64/x64_microsoft.cpp + providers/calling_convention/x64/x64_systemv.cpp + providers/calling_convention/x86/x86_cdecl.cpp + providers/calling_convention/x86/x86_conv.cpp + providers/calling_convention/x86/x86_fastcall.cpp + providers/calling_convention/x86/x86_pascal.cpp + providers/calling_convention/x86/x86_thiscall.cpp + providers/calling_convention/x86/x86_watcom.cpp providers/asm_instruction.cpp providers/config.cpp providers/debugformat.cpp diff --git a/src/bin2llvmir/optimizations/decoder/decoder.cpp b/src/bin2llvmir/optimizations/decoder/decoder.cpp index 07646ca11..c70f1a9e4 100644 --- a/src/bin2llvmir/optimizations/decoder/decoder.cpp +++ b/src/bin2llvmir/optimizations/decoder/decoder.cpp @@ -789,8 +789,8 @@ bool Decoder::getJumpTargetsFromInstruction( SymbolicTree st(_RDA, l->getPointerOperand(), nullptr, 8); st.simplifyNode(); - ConstantInt* ci = nullptr; - if (match(st, m_ConstantInt(ci))) + auto* ci = dyn_cast(st.value); + if (ci && !ci->isNegative()) { Address t(ci->getZExtValue()); auto sz = _abi->getTypeByteSize(l->getType()); diff --git a/src/bin2llvmir/optimizations/param_return/collector/collector.cpp b/src/bin2llvmir/optimizations/param_return/collector/collector.cpp new file mode 100644 index 000000000..4e61bc06b --- /dev/null +++ b/src/bin2llvmir/optimizations/param_return/collector/collector.cpp @@ -0,0 +1,626 @@ +/** +* @file src/bin2llvmir/optimizations/param_return/collector/collector.cpp +* @brief Collects possible arguments and returns of functions. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#include + +#include +#include + +#include "retdec/bin2llvmir/optimizations/param_return/collector/collector.h" +#include "retdec/bin2llvmir/optimizations/param_return/collector/pic32.h" + +using namespace retdec::utils; +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +Collector::Collector( + const Abi* abi, + Module* m, + const ReachingDefinitionsAnalysis* rda) : + _abi(abi), + _module(m), + _rda(rda) +{ +} + +Collector::~Collector() +{ +} + +void Collector::collectCallArgs(CallEntry* ce) const +{ + std::vector foundStores; + + collectStoresBeforeInstruction( + ce->getCallInstruction(), + foundStores); + + ce->setArgStores(std::move(foundStores)); +} + +void Collector::collectCallRets(CallEntry* ce) const +{ + std::vector foundLoads; + + collectLoadsAfterInstruction( + ce->getCallInstruction(), + foundLoads); + + ce->setRetLoads(std::move(foundLoads)); +} + +void Collector::collectDefArgs(DataFlowEntry* dataflow) const +{ + if (!dataflow->hasDefinition()) + { + return; + } + + auto* f = dataflow->getFunction(); + + std::set added; + for (auto it = inst_begin(f), end = inst_end(f); it != end; ++it) + { + if (auto* l = dyn_cast(&*it)) + { + auto* ptr = l->getPointerOperand(); + if (!_abi->isGeneralPurposeRegister(ptr) && !_abi->isStackVariable(ptr)) + { + continue; + } + + auto* use = _rda->getUse(l); + if (use == nullptr) + { + continue; + } + + if ((use->defs.empty() || use->isUndef()) + && added.find(ptr) == added.end()) + { + dataflow->addArg(ptr); + added.insert(ptr); + } + } + } +} + +void Collector::collectDefRets(DataFlowEntry* dataflow) const +{ + if (!dataflow->hasDefinition()) + { + return; + } + + auto* f = dataflow->getFunction(); + + for (auto it = inst_begin(f), end = inst_end(f); it != end; ++it) + { + if (auto* r = dyn_cast(&*it)) + { + ReturnEntry* re = dataflow->createRetEntry(r); + collectRetStores(re); + } + } +} + +void Collector::collectRetStores(ReturnEntry* re) const +{ + std::vector foundStores; + +// TODO: +// This method should be used only after +// speed comparation of below methods. +// +// In this implementation of parameter +// analysis return type is estimated +// only as last option from colelcted +// values. This iss reason why quicklier +// but not reliable method is used +// instead of more reliable one. +// +// collectStoresBeforeInstruction( +// re->getRetInstruction(), +// foundStores); + + collectStoresInSinglePredecessors( + re->getRetInstruction(), + foundStores); + + re->setRetStores(std::move(foundStores)); +} + +void Collector::collectStoresBeforeInstruction( + llvm::Instruction* i, + std::vector& stores) const +{ + if (i == nullptr) + { + return; + } + + std::map> seenBlocks; + + auto* block = i->getParent(); + + // In case of recursive call of same basic block. + std::set afterValues; + std::vector afterStores; + collectStoresInInstructionBlock( + &block->back(), + afterValues, + afterStores); + + seenBlocks[block] = std::move(afterValues); + + collectStoresRecursively(i->getPrevNode(), stores, seenBlocks); + + auto& values = seenBlocks[block]; + + stores.insert( + stores.end(), + std::make_move_iterator(afterStores.begin()), + std::make_move_iterator(afterStores.end())); + + stores.erase( + std::remove_if( + stores.begin(), + stores.end(), + [values](StoreInst* s) + { + return values.find( + s->getPointerOperand()) == values.end(); + }), + stores.end()); +} + +void Collector::collectStoresInSinglePredecessors( + llvm::Instruction* i, + std::vector& stores) const +{ + if (i == nullptr) + { + return; + } + + std::set seenBbs; + std::set disqualifiedValues; + + auto* b = i->getParent(); + seenBbs.insert(b); + Instruction* prev = i; + + while (true) + { + if (prev == &b->front()) + { + auto* spb = b->getSinglePredecessor(); + if (spb && !spb->empty() + && seenBbs.find(spb) == seenBbs.end()) + { + b = spb; + prev = &b->back(); + seenBbs.insert(b); + } + else + { + break; + } + } + else + { + prev = prev->getPrevNode(); + } + if (prev == nullptr) + { + break; + } + + if (isa(prev) || isa(prev)) + { + break; + } + else if (auto* store = dyn_cast(prev)) + { + auto* ptr = store->getPointerOperand(); + + if (disqualifiedValues.find(ptr) == disqualifiedValues.end() + && (_abi->isRegister(ptr) || _abi->isStackVariable(ptr))) + { + stores.push_back(store); + disqualifiedValues.insert(ptr); + } + } + else if (auto* load = dyn_cast(prev)) + { + auto* ptr = load->getPointerOperand(); + disqualifiedValues.insert(ptr); + } + } +} + +void Collector::collectStoresRecursively( + Instruction* i, + std::vector& stores, + std::map>& seen) const +{ + if (i == nullptr) + { + return; + } + + auto* block = i->getParent(); + + std::set values; + if (!collectStoresInInstructionBlock(i, values, stores)) + { + seen[block] = std::move(values); + return; + } + + seen.emplace(std::make_pair(block, values)); + std::set commonValues; + + for (BasicBlock* pred : predecessors(block)) + { + if (seen.find(pred) == seen.end()) + { + collectStoresRecursively( + &pred->back(), + stores, + seen); + } + + auto& foundValues = seen[pred]; + if (foundValues.empty()) + { + // Shorcut -> intersection would be empty set. + commonValues.clear(); + break; + } + + if (commonValues.empty()) + { + commonValues = foundValues; + } + else + { + std::set intersection; + std::set_intersection( + commonValues.begin(), + commonValues.end(), + foundValues.begin(), + foundValues.end(), + std::inserter(intersection, intersection.begin())); + + commonValues = std::move(intersection); + } + } + + values.insert(commonValues.begin(), commonValues.end()); + seen[block] = values; +} + + +bool Collector::collectStoresInInstructionBlock( + Instruction* start, + std::set& values, + std::vector& stores) const +{ + if (start == nullptr) + { + return false; + } + + std::set excluded; + + auto* block = start->getParent(); + + for (auto* inst = start; true; inst = inst->getPrevNode()) + { + if (inst == nullptr) + { + return false; + } + if (auto* call = dyn_cast(inst)) + { + auto* calledFnc = call->getCalledFunction(); + if (calledFnc == nullptr || !calledFnc->isIntrinsic()) + { + return false; + } + } + else if (isa(inst)) + { + return false; + } + else if (auto* store = dyn_cast(inst)) + { + auto* val = store->getValueOperand(); + auto* ptr = store->getPointerOperand(); + + if (!_abi->isRegister(ptr) && !_abi->isStackVariable(ptr)) + { + excluded.insert(ptr); + } + if (auto* l = dyn_cast(val)) + { + if (l->getPointerOperand() != store->getPointerOperand()) + { + excluded.insert(l->getPointerOperand()); + } + } + + if (excluded.find(ptr) == excluded.end()) + { + stores.push_back(store); + values.insert(ptr); + excluded.insert(ptr); + excluded.insert(val); + } + } + if (inst == &block->front()) + { + return true; + } + } + + return true; +} + +void Collector::collectLoadsAfterInstruction( + llvm::Instruction* start, + std::vector& loads) const +{ + if (start == nullptr) + { + return; + } + + std::queue next; + std::set excludedValues; + std::set seen; + + BasicBlock* beginBB = start->getParent(); + next.push(start->getNextNode()); + + while (!next.empty()) + { + auto* i = next.front(); + next.pop(); + + auto* block = i->getParent(); + seen.insert(block); + + if (collectLoadsAfterInstruction(i, loads, excludedValues)) + { + for (auto suc : successors(block)) + { + if (seen.find(suc) == seen.end()) + { + next.push(&suc->front()); + } + else if (suc == beginBB) + { + next.push(&beginBB->front()); + beginBB = nullptr; + } + } + } + } +} + +bool Collector::collectLoadsAfterInstruction( + llvm::Instruction* start, + std::vector& loads, + std::set& excluded) const +{ + if (start == nullptr) + { + return false; + } + + auto* block = start->getParent(); + for (auto* inst = start; true; inst = inst->getNextNode()) + { + if (inst == nullptr) + { + return false; + } + if (auto* call = dyn_cast(inst)) + { + auto* calledFnc = call->getCalledFunction(); + if (calledFnc == nullptr || !calledFnc->isIntrinsic()) + { + return false; + } + } + else if (isa(inst)) + { + return false; + } + else if (auto* store = dyn_cast(inst)) + { + auto* ptr = store->getPointerOperand(); + excluded.insert(ptr); + } + else if (auto* load = dyn_cast(inst)) + { + auto* ptr = load->getPointerOperand(); + + if (excluded.find(ptr) == excluded.end() + && ( _abi->isGeneralPurposeRegister(ptr) || _abi->isStackVariable(ptr) )) + { + loads.push_back(load); + } + } + + if (inst == &block->back()) + { + return true; + } + } + + return true; +} + +void Collector::collectCallSpecificTypes(CallEntry* ce) const +{ + if (!ce->getBaseFunction()->isVariadic()) + { + return; + } + + + if (!extractFormatString(ce)) + { + return; + } + + auto wrappedCall = ce->getBaseFunction()->getWrappedCall(); + + auto trueCall = wrappedCall ? wrappedCall : ce->getCallInstruction(); + + ce->setArgTypes( + llvm_utils::parseFormatString( + _module, + ce->getFormatString(), + trueCall->getCalledFunction()) + ); +} + +bool Collector::extractFormatString(CallEntry* ce) const +{ + for (auto& i : ce->args()) + { + auto inst = std::find_if( + ce->argStores().begin(), + ce->argStores().end(), + [i](StoreInst *st) + { + return st->getPointerOperand() == i; + }); + + if (inst != ce->argStores().end()) + { + std::string str; + if (storesString(*inst, str)) + { + ce->setFormatString(str); + return true; + } + } + } + + return false; +} + +bool Collector::storesString(StoreInst* si, std::string& str) const +{ + auto* v = getRoot(si->getValueOperand()); + auto* gv = dyn_cast_or_null(v); + + if (gv == nullptr || !gv->hasInitializer()) + { + return false; + } + + auto* init = dyn_cast_or_null(gv->getInitializer()); + if (init == nullptr) + { + if (auto* i = dyn_cast(gv->getInitializer())) + { + if (auto* igv = dyn_cast(i->getOperand(0))) + { + init = dyn_cast_or_null(igv->getInitializer()); + } + } + } + + if (init == nullptr || !init->isString()) + { + return false; + } + + str = init->getAsString(); + return true; +} + +llvm::Value* Collector::getRoot(llvm::Value* i, bool first) const +{ + static std::set seen; + if (first) + { + seen.clear(); + } + if (seen.count(i)) + { + return i; + } + seen.insert(i); + + i = llvm_utils::skipCasts(i); + if (auto* ii = dyn_cast(i)) + { + if (auto* u = _rda->getUse(ii)) + { + if (u->defs.size() == 1) + { + auto* d = (*u->defs.begin())->def; + if (auto* s = dyn_cast(d)) + { + return getRoot(s->getValueOperand(), false); + } + else + { + return d; + } + } + else if (auto* l = dyn_cast(ii)) + { + return getRoot(l->getPointerOperand(), false); + } + else + { + return i; + } + } + else if (auto* l = dyn_cast(ii)) + { + return getRoot(l->getPointerOperand(), false); + } + else + { + return i; + } + } + + return i; +} + +// +//============================================================================= +// CollectorProvider +//============================================================================= +// + +Collector::Ptr CollectorProvider::createCollector( + const Abi* abi, + Module* m, + const ReachingDefinitionsAnalysis* rda) +{ + if (abi->isPic32()) + { + return std::make_unique(abi, m, rda); + } + + return std::make_unique(abi, m, rda); +} + +} +} diff --git a/src/bin2llvmir/optimizations/param_return/collector/pic32.cpp b/src/bin2llvmir/optimizations/param_return/collector/pic32.cpp new file mode 100644 index 000000000..7d397ec59 --- /dev/null +++ b/src/bin2llvmir/optimizations/param_return/collector/pic32.cpp @@ -0,0 +1,48 @@ +/** +* @file src/bin2llvmir/optimizations/param_return/collector/pic32.cpp +* @brief Pic32 specific collection algorithms. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#include "retdec/bin2llvmir/optimizations/param_return/collector/pic32.h" + +using namespace retdec::utils; +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +CollectorPic32::CollectorPic32( + const Abi* abi, + llvm::Module* m, + const ReachingDefinitionsAnalysis* rda) : + Collector(abi, m, rda) +{ +} + +CollectorPic32::~CollectorPic32() +{ +} + +void CollectorPic32::collectCallSpecificTypes(CallEntry* ce) const +{ + Collector::collectCallSpecificTypes(ce); + + std::vector argTypes; + for (auto t : ce->argTypes()) + { + if (t->isDoubleTy()) + { + argTypes.push_back(Type::getFloatTy(_module->getContext())); + } + else + { + argTypes.push_back(t); + } + } + + ce->setArgTypes(std::move(argTypes)); +} + +} +} diff --git a/src/bin2llvmir/optimizations/param_return/data_entries.cpp b/src/bin2llvmir/optimizations/param_return/data_entries.cpp new file mode 100644 index 000000000..55bf8f935 --- /dev/null +++ b/src/bin2llvmir/optimizations/param_return/data_entries.cpp @@ -0,0 +1,449 @@ +/** +* @file src/bin2llvmir/optimizations/param_return/data_entries.cpp +* @brief Data entries for parameter analysis. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#include + +#include "retdec/bin2llvmir/optimizations/param_return/data_entries.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +// +//============================================================================= +// ReturnEntry +//============================================================================= +// + +ReturnEntry::ReturnEntry(llvm::ReturnInst* r) : + _retInst(r) +{ +} + +void ReturnEntry::addRetStore(llvm::StoreInst* st) +{ + _retStores.push_back(st); + + if (std::find( + _retValues.begin(), + _retValues.end(), + st->getPointerOperand()) != _retValues.end()) + { + _retValues.push_back(st->getPointerOperand()); + } +} + +void ReturnEntry::setRetStores(std::vector&& stores) +{ + _retStores = std::move(stores); + + std::set vals; + for (auto& i: _retStores) + { + vals.insert(i->getPointerOperand()); + } + + _retValues = std::vector( + std::make_move_iterator(vals.begin()), + std::make_move_iterator(vals.end())); +} + +void ReturnEntry::setRetStores(const std::vector& stores) +{ + _retStores = stores; + + std::set vals; + for (auto& i: _retStores) + { + vals.insert(i->getPointerOperand()); + } + + _retValues = std::vector( + std::make_move_iterator(vals.begin()), + std::make_move_iterator(vals.end())); +} + +void ReturnEntry::setRetValues(std::vector&& values) +{ + _retStores.erase(std::remove_if( + _retStores.begin(), + _retStores.end(), + [values](StoreInst* st) + { + auto* op = st->getPointerOperand(); + return std::find( + values.begin(), + values.end(), op) == values.end(); + }), + _retStores.end()); + + _retValues = std::move(values); +} + +void ReturnEntry::setRetValues(const std::vector& values) +{ + _retStores.erase(std::remove_if( + _retStores.begin(), + _retStores.end(), + [values](StoreInst* st) + { + auto* op = st->getPointerOperand(); + return std::find( + values.begin(), + values.end(), op) == values.end(); + }), + _retStores.end()); + + _retValues = values; +} + +ReturnInst* ReturnEntry::getRetInstruction() const +{ + return _retInst; +} + +const std::vector& ReturnEntry::retStores() const +{ + return _retStores; +} + +const std::vector& ReturnEntry::retValues() const +{ + return _retValues; +} + +// +//============================================================================= +// CallableEntry +//============================================================================= +// + +bool CallableEntry::isVoidarg() const +{ + return _voidarg; +} + +void CallableEntry::addArg(llvm::Value* arg) +{ + _args.push_back(arg); +} + +void CallableEntry::setVoidarg(bool voidarg) +{ + _voidarg = voidarg; +} + +void CallableEntry::setArgTypes( + std::vector&& types, + std::vector&& names) +{ + _argTypes = std::move(types); + _argNames = std::move(names); + + if (_argTypes.size() > _argNames.size()) + { + _argNames.resize(_argTypes.size(), ""); + } + else if (_argTypes.size() < _argNames.size()) + { + _argTypes.resize(_argNames.size(), nullptr); + } + + if (_argTypes.empty()) + { + setVoidarg(); + } +} + +const std::vector& CallableEntry::args() const +{ + return _args; +} + +const std::vector& CallableEntry::argTypes() const +{ + return _argTypes; +} + +const std::vector& CallableEntry::argNames() const +{ + return _argNames; +} + +// +//============================================================================= +// FunctionEntry +//============================================================================= +// + +bool FunctionEntry::isVariadic() const +{ + return _variadic; +} + +bool FunctionEntry::isWrapper() const +{ + return _wrap != nullptr; +} + +void FunctionEntry::addRetEntry(const ReturnEntry& ret) +{ + _retEntries.push_back(ret); +} + +ReturnEntry* FunctionEntry::createRetEntry(llvm::ReturnInst* ret) +{ + _retEntries.push_back(ReturnEntry(ret)); + + return &(_retEntries.back()); +} + +void FunctionEntry::setVariadic(bool variadic) +{ + _variadic = variadic; +} + +void FunctionEntry::setArgs(std::vector&& args) +{ + _args = std::move(args); +} + +void FunctionEntry::setWrappedCall(llvm::CallInst* wrap) +{ + _wrap = wrap; +} + +void FunctionEntry::setRetType(llvm::Type* type) +{ + _retType = type; +} + +void FunctionEntry::setRetValue(llvm::Value* val) +{ + _retVal = val; +} + +void FunctionEntry::setCallingConvention(const CallingConvention::ID& cc) +{ + if (cc == CallingConvention::ID::CC_VOIDARG) + { + setVoidarg(); + } + else + { + _callconv = cc; + } +} + +llvm::Type* FunctionEntry::getRetType() const +{ + return _retType; +} + +llvm::Value* FunctionEntry::getRetValue() const +{ + return _retVal; +} + +llvm::CallInst* FunctionEntry::getWrappedCall() const +{ + return _wrap; +} + +CallingConvention::ID FunctionEntry::getCallingConvention() const +{ + return _callconv; +} + +const std::vector& FunctionEntry::retEntries() const +{ + return _retEntries; +} + +std::vector& FunctionEntry::retEntries() +{ + return _retEntries; +} + +// +//============================================================================= +// CallEntry +//============================================================================= +// + +CallEntry::CallEntry(CallInst* call, const FunctionEntry* base) : + _baseFunction(base), + _callInst(call) +{ +} + +void CallEntry::addRetLoad(LoadInst* load) +{ + _retLoads.push_back(load); + _retValues.push_back(load->getPointerOperand()); + + // TODO duplicity and pointer operand? +} + +void CallEntry::setFormatString(const std::string &fmt) +{ + _fmtStr = fmt; +} + +void CallEntry::setArgStores(std::vector&& stores) +{ + _argStores = std::move(stores); + + std::set vals; + for (auto& i : _argStores) + { + vals.insert(i->getPointerOperand()); + } + + _args.assign( + std::make_move_iterator(vals.begin()), + std::make_move_iterator(vals.end())); +} + +void CallEntry::setArgs(std::vector&& args) +{ + _argStores.erase( + std::remove_if( + _argStores.begin(), + _argStores.end(), + [args](StoreInst* st) + { + auto* op = st->getPointerOperand(); + return std::find( + args.begin(), + args.end(), op) == args.end(); + }), + _argStores.end()); + + _args = std::move(args); +} + +void CallEntry::setRetLoads(std::vector&& loads) +{ + _retLoads = std::move(loads); + + std::set vals; + for (auto& i: _retLoads) + { + vals.insert(i->getPointerOperand()); + } + _retValues = std::vector( + std::make_move_iterator(vals.begin()), + std::make_move_iterator(vals.end())); +} + +void CallEntry::setRetValues(std::vector&& values) +{ + _retLoads.erase(std::remove_if( + _retLoads.begin(), + _retLoads.end(), + [values](llvm::LoadInst* st) + { + auto* op = st->getPointerOperand(); + return std::find( + values.begin(), + values.end(), op) == values.end(); + }), + _retLoads.end()); + + _retValues = std::move(values); +} + +CallInst* CallEntry::getCallInstruction() const +{ + return _callInst; +} + +const FunctionEntry* CallEntry::getBaseFunction() const +{ + return _baseFunction; +} + +std::string CallEntry::getFormatString() const +{ + return _fmtStr; +} + +const std::vector& CallEntry::argStores() const +{ + return _argStores; +} + +const std::vector& CallEntry::retValues() const +{ + return _retValues; +} + +const std::vector& CallEntry::retLoads() const +{ + return _retLoads; +} + +// +//============================================================================= +// DataFlowEntry +//============================================================================= +// + +DataFlowEntry::DataFlowEntry(Value* called): + _calledValue(called) +{ +} + +bool DataFlowEntry::isFunction() const +{ + return getFunction() != nullptr; +} + +bool DataFlowEntry::isValue() const +{ + return _calledValue && !isFunction(); +} + +bool DataFlowEntry::hasDefinition() const +{ + return isFunction() && !getFunction()->empty(); +} + +Function* DataFlowEntry::getFunction() const +{ + return dyn_cast_or_null(_calledValue); +} + +Value* DataFlowEntry::getValue() const +{ + return _calledValue; +} + +void DataFlowEntry::setCalledValue(llvm::Value* called) +{ + _calledValue = called; +} + +CallEntry* DataFlowEntry::createCallEntry(CallInst* call) +{ + _calls.push_back(CallEntry(call, this)); + return &(_calls.back()); +} + +const std::vector& DataFlowEntry::callEntries() const +{ + return _calls; +} + +std::vector& DataFlowEntry::callEntries() +{ + return _calls; +} + +} +} diff --git a/src/bin2llvmir/optimizations/param_return/filter/filter.cpp b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp new file mode 100644 index 000000000..45804ee9e --- /dev/null +++ b/src/bin2llvmir/optimizations/param_return/filter/filter.cpp @@ -0,0 +1,1353 @@ +/** +* @file src/bin2llvmir/optimizations/param_return/filter/filter.cpp +* @brief Filters potential values according to calling convention. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#include + +#include "retdec/bin2llvmir/optimizations/param_return/filter/filter.h" +#include "retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h" + +using namespace retdec::utils; +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +// +//============================================================================= +// Filter +//============================================================================= +// + +Filter::Filter( + const Abi* abi, + const CallingConvention* cc) : + _abi(abi), + _cc(cc) +{ +} + +Filter::~Filter() +{ +} + +void Filter::estimateRetValue(DataFlowEntry* de) const +{ + auto retValue = de->getRetValue(); + auto retType = de->getRetType(); + + if (retType == nullptr) + { + if (!de->retEntries().empty() + && !de->retEntries().front().retValues().empty()) + { + retType = de->retEntries().front().retValues().front()->getType(); + if (auto* p = dyn_cast(retType)) + { + retType = p->getElementType(); + } + retValue = de->retEntries().front().retValues().front(); + } + else + { + // This is hack -> retdec expects generation of + // implicit return for every funtion definition + // but not external calls. + // + // In fact this should return void type here. + // This is why retType is not set to any type. + if (!_cc->getReturnRegisters().empty()) + { + retValue = _abi->getRegister(_cc->getReturnRegisters().front()); + } + } + } + else + { +// TODO: double-read-modf.x86.clang-3.2.O0.g.elf +// In test above return type is found from configuration to be +// double but collector finds only stores to EAX which results in failure in +// decompilation. +// +// if (!de->retEntries().empty() +// && !de->retEntries().front().retValues().empty()) +// { +// retValue = de->retEntries().front().retValues().front(); +// } +// else + { + if (!_cc->getReturnRegisters().empty()) + { + retValue = _abi->getRegister(_cc->getReturnRegisters().front()); + } + + if (retType->isFloatingPointTy() && !_cc->getReturnFPRegisters().empty()) + { + retValue = _abi->getRegister(_cc->getReturnFPRegisters().front()); + } + + if (retType->isDoubleTy() && !_cc->getReturnDoubleRegisters().empty()) + { + retValue = _abi->getRegister(_cc->getReturnDoubleRegisters().front()); + } + } + } + + de->setRetType(retType); + de->setRetValue(retValue); +} + +void Filter::filterDefinition(DataFlowEntry* de) const +{ + if (!de->hasDefinition()) + { + return; + } + + FilterableLayout defArgs = createArgsFilterableLayout(de->args(), de->argTypes()); + filterDefinitionArgs(defArgs, de->isVoidarg()); + + de->setArgs(createGroupedArgValues(defArgs)); + + if (de->retEntries().empty()) + { + return; + } + + std::vector defRets; + for (auto& ret : de->retEntries()) + { + defRets.push_back( + createRetsFilterableLayout(ret.retValues(), de->getRetType())); + } + + leaveCommonRets(defRets); + filterRets(defRets.front()); + + FilterableLayout retTempl = defRets.front(); + + for (auto& ret : de->retEntries()) + { + filterRetsByDefLayout(defRets.front(), retTempl); + ret.setRetValues(createGroupedValues(defRets.front())); + + defRets.erase(defRets.begin()); + } +} + +void Filter::filterCalls(DataFlowEntry* de) const +{ + if (de->callEntries().empty()) + { + return; + } + + std::vector callArgs, callArgsCopy; + std::vector callRets; + + for (auto& call : de->callEntries()) + { + callArgs.push_back( + createArgsFilterableLayout(call.args(), de->argTypes())); + callRets.push_back( + createRetsFilterableLayout( + call.retValues(), + de->getRetType())); + } + + callArgsCopy = callArgs; + + FilterableLayout retTempl, argTempl; + + if (!callArgs.empty()) + { + if (!de->isVoidarg() && de->argTypes().empty()) + { + leaveCommonArgs(callArgs); + } + filterCallArgs(callArgs.front(), de->isVoidarg()); + argTempl = callArgs.front(); + } + + if (!callRets.empty()) + { + leaveCommonRets(callRets); + filterRets(callRets.front()); + retTempl = callRets.front(); + } + + if (de->hasDefinition()) + { + FilterableLayout defArgs; + defArgs = createArgsFilterableLayout( + de->args(), + de->argTypes()); + if (!de->isVoidarg() && !de->argTypes().empty()) + { + // This function is called because + // in case when we have info about + // types and order of the parameters + // we would loose it by plain creation + // of template. + // This order is estimated in function + // below. + filterArgsByKnownTypes(defArgs); + } + else if (de->args().empty()) + { + filterCallArgsByDefLayout(defArgs, argTempl); + de->setArgs(createGroupedArgValues(defArgs)); + } + else if (argTempl.stacks.size() > defArgs.stacks.size()) + { + if (argTempl.gpRegisters.size() == defArgs.gpRegisters.size() + && argTempl.fpRegisters.size() == defArgs.fpRegisters.size() + && argTempl.doubleRegisters.size() == defArgs.doubleRegisters.size() + && argTempl.vectorRegisters.size() == defArgs.vectorRegisters.size()) + { + leaveSameStacks(defArgs, argTempl); + de->setArgs(createGroupedArgValues(defArgs)); + } + } + + if (!de->retEntries().empty()) + { + retTempl = createRetsFilterableLayout( + de->retEntries().front().retValues(), + de->getRetType()); + } + + argTempl = std::move(defArgs); + } + + for (auto& call : de->callEntries()) + { + filterCallArgsByDefLayout(callArgsCopy.front(), argTempl); + filterRetsByDefLayout(callRets.front(), retTempl); + + call.setArgs(createGroupedArgValues(callArgsCopy.front())); + call.setRetValues(createGroupedRetValues(callRets.front())); + + callArgsCopy.erase(callArgsCopy.begin()); + callRets.erase(callRets.begin()); + } +} + +void Filter::filterCallsVariadic(DataFlowEntry* de, const Collector* collector) const +{ + if (de->callEntries().empty()) + { + return; + } + + std::vector callArgs; + std::vector callRets; + + for (auto& call : de->callEntries()) + { + auto argTypes = de->argTypes(); + + FilterableLayout argLayout = createArgsFilterableLayout(call.args(), {}); + + // To collect specific types, we need ordered values. + // Collector will find first occourence of string and parse it. + call.setArgs(createGroupedArgValues(argLayout)); + collector->collectCallSpecificTypes(&call); + + argTypes.insert( + argTypes.end(), + call.argTypes().begin(), + call.argTypes().end()); + + argLayout.knownTypes = std::move(argTypes); + + callArgs.push_back(argLayout); + callRets.push_back( + createRetsFilterableLayout( + call.retValues(), + call.getBaseFunction()->getRetType())); + } + + FilterableLayout retTempl; + + if (de->hasDefinition() && !de->retEntries().empty()) + { + retTempl = createRetsFilterableLayout( + de->retEntries().front().retValues(), + de->getRetType()); + } + else if (!callRets.empty()) + { + leaveCommonRets(callRets); + filterRets(callRets.front()); + retTempl = callRets.front(); + } + + for (auto& call : de->callEntries()) + { + filterCallArgs(callArgs.front(), de->isVoidarg() && !call.argTypes().empty()); + filterRetsByDefLayout(callRets.front(), retTempl); + + call.setArgs(createGroupedArgValues(callArgs.front())); + call.setRetValues(createGroupedRetValues(callRets.front())); + + callArgs.erase(callArgs.begin()); + callRets.erase(callRets.begin()); + } +} + +void Filter::filterDefinitionArgs(FilterableLayout& args, bool isVoidarg) const +{ + leaveOnlyPositiveStacks(args); + + if (isVoidarg) + { + args.gpRegisters.clear(); + args.fpRegisters.clear(); + args.doubleRegisters.clear(); + args.vectorRegisters.clear(); + args.stacks.clear(); + } + else if (!args.knownTypes.empty()) + { + filterArgsByKnownTypes(args); + } + else + { + createContinuousArgRegisters(args); + } + + leaveOnlyContinuousStack(args); +} + +void Filter::filterCallArgs(FilterableLayout& args, bool isVoidarg) const +{ + if (isVoidarg) + { + args.gpRegisters.clear(); + args.fpRegisters.clear(); + args.doubleRegisters.clear(); + args.vectorRegisters.clear(); + args.stacks.clear(); + } + else if (!args.knownTypes.empty()) + { + filterArgsByKnownTypes(args); + } + else + { + leaveOnlyContinuousArgRegisters(args); + } + + leaveOnlyContinuousStack(args); +} + +void Filter::filterCallArgsByDefLayout( + FilterableLayout& args, + const FilterableLayout& defArgs) const +{ + args.gpRegisters = std::vector(defArgs.gpRegisters); + args.fpRegisters = std::vector(defArgs.fpRegisters); + args.doubleRegisters = std::vector(defArgs.doubleRegisters); + args.vectorRegisters = std::vector(defArgs.vectorRegisters); + args.knownOrder = defArgs.knownOrder; + + leaveOnlyContinuousStack(args); + leaveSameStacks(args, defArgs); +} + +void Filter::filterRets(FilterableLayout& rets) const +{ + if (!rets.knownTypes.empty() && rets.knownTypes.front()) + { + filterRetsByKnownTypes(rets); + } + else + { + leaveOnlyContinuousRetRegisters(rets); + } +} + +void Filter::filterRetsByDefLayout( + FilterableLayout& rets, + const FilterableLayout& defRets) const +{ + rets.gpRegisters = std::vector(defRets.gpRegisters); + rets.fpRegisters = std::vector(defRets.fpRegisters); + rets.doubleRegisters = std::vector(defRets.doubleRegisters); + rets.vectorRegisters = std::vector(defRets.vectorRegisters); + rets.knownOrder = defRets.knownOrder; + + leaveOnlyContinuousStack(rets); + leaveSameStacks(rets, defRets); +} + +void Filter::filterArgsByKnownTypes(FilterableLayout& lay) const +{ + FilterableLayout newLayout; + auto& gpRegs = _cc->getParamRegisters(); + auto& fpRegs = _cc->getParamFPRegisters(); + auto& doubleRegs = _cc->getParamDoubleRegisters(); + auto& vecRegs = _cc->getParamVectorRegisters(); + + // Indexes of registers to be used next as particular parameter. + auto sIt = lay.stacks.begin(); + + std::size_t gpEnd = gpRegs.size(); + std::size_t fpEnd = fpRegs.size(); + std::size_t doubleEnd = doubleRegs.size(); + std::size_t vecEnd = vecRegs.size(); + + std::vector types = expandTypes(lay.knownTypes); + + for (auto t: types) + { + std::size_t requiredStacks = 0; + OrderID stackOrd = OrderID::ORD_STACK; + + if (!doubleRegs.empty() && t->isDoubleTy()) + { + if (newLayout.doubleRegisters.size() < doubleEnd) + { + requiredStacks = fetchDoubleRegsForType(t, newLayout); + stackOrd = OrderID::ORD_STACK_GROUP; + } + } + else if (!fpRegs.empty() && t->isFloatingPointTy()) + { + if (newLayout.fpRegisters.size() < fpEnd) + { + requiredStacks = fetchFPRegsForType(t, newLayout); + stackOrd = OrderID::ORD_STACK_GROUP; + } + } + else if (!vecRegs.empty() && t->isVectorTy()) + { + if (newLayout.vectorRegisters.size() < vecEnd) + { + requiredStacks = fetchVecRegsForType(t, newLayout); + stackOrd = OrderID::ORD_STACK_GROUP; + } + } + else if (!gpRegs.empty()) + { + if (newLayout.gpRegisters.size() < gpEnd) + { + requiredStacks = fetchGPRegsForType(t, newLayout); + stackOrd = OrderID::ORD_STACK_GROUP; + } + } + + + if (!requiredStacks && stackOrd == OrderID::ORD_STACK) + { + requiredStacks = getNumberOfStacksForType(t); + } + + for (std::size_t i = 0; i < requiredStacks; i++) + { + if (sIt != lay.stacks.end()) + { + newLayout.stacks.push_back(*sIt); + sIt++; + } + else + { + newLayout.stacks.push_back(nullptr); + } + + newLayout.knownOrder.push_back( + i == 0 ? stackOrd : + OrderID::ORD_STACK_GROUP); + } + } + + lay = newLayout; +} + +std::vector Filter::expandTypes(const std::vector& types) const +{ + if (_cc->passesLargeObjectsByReference()) + { + return types; + } + else + { + std::vector expanded; + + std::deque toExpand( + types.begin(), + types.end()); + + while (!toExpand.empty()) + { + auto t = toExpand.front(); + toExpand.pop_front(); + + if (auto* st = dyn_cast(t)) + { + for (auto& e : st->elements()) + { + toExpand.push_back(e); + } + } + else + { + expanded.push_back(t); + } + } + + return expanded; + } +} + +size_t Filter::fetchGPRegsForType(Type* type, FilterableLayout& lay) const +{ + std::size_t sizeBefore = lay.gpRegisters.size(); + std::size_t reqStacks = fetchRegsForType( + type, + lay.gpRegisters, + _cc->getParamRegisters(), + _cc->getMaxNumOfRegsPerParam()); + + std::size_t change = lay.gpRegisters.size() - sizeBefore; + if (change) + { + lay.knownOrder.push_back(OrderID::ORD_GPR); + lay.knownOrder.resize( + lay.knownOrder.size() + change - 1, OrderID::ORD_GPR_GROUP); + } + + return reqStacks; +} + +size_t Filter::fetchFPRegsForType(Type* type, FilterableLayout& lay) const +{ + std::size_t sizeBefore = lay.fpRegisters.size(); + std::size_t reqStacks = fetchRegsForType( + type, + lay.fpRegisters, + _cc->getParamFPRegisters(), + _cc->getMaxNumOfFPRegsPerParam()); + + std::size_t change = lay.fpRegisters.size() - sizeBefore; + if (change) + { + lay.knownOrder.push_back(OrderID::ORD_FPR); + lay.knownOrder.resize( + lay.knownOrder.size() + change - 1, OrderID::ORD_FPR_GROUP); + } + + return reqStacks; +} + +size_t Filter::fetchDoubleRegsForType(Type* type, FilterableLayout& lay) const +{ + std::size_t sizeBefore = lay.doubleRegisters.size(); + std::size_t reqStacks = fetchRegsForType( + type, + lay.doubleRegisters, + _cc->getParamDoubleRegisters(), + _cc->getMaxNumOfDoubleRegsPerParam()); + + std::size_t change = lay.doubleRegisters.size() - sizeBefore; + if (change) + { + lay.knownOrder.push_back(OrderID::ORD_DOUBR); + lay.knownOrder.resize( + lay.knownOrder.size() + change - 1, OrderID::ORD_DOUBR_GROUP); + } + + return reqStacks; +} + +size_t Filter::fetchVecRegsForType(Type* type, FilterableLayout& lay) const +{ + std::size_t sizeBefore = lay.vectorRegisters.size(); + std::size_t reqStacks = fetchRegsForType( + type, + lay.vectorRegisters, + _cc->getParamVectorRegisters(), + _cc->getMaxNumOfVectorRegsPerParam()); + + std::size_t change = lay.vectorRegisters.size() - sizeBefore; + if (change) + { + lay.knownOrder.push_back(OrderID::ORD_VECR); + lay.knownOrder.resize( + lay.knownOrder.size() + change - 1, OrderID::ORD_VECR_GROUP); + } + + return reqStacks; +} + +size_t Filter::fetchRegsForType( + Type* type, + std::vector& store, + const std::vector& regs, + std::size_t maxRegsPerObject) const +{ + if (regs.empty()) + { + return getNumberOfStacksForType(type); + } + + Type* registerType = _abi->getRegister(regs.front())->getType(); + std::size_t registerSize = _abi->getTypeByteSize(registerType); + std::size_t typeSize = type->isVoidTy() ? + _abi->getWordSize() : _abi->getTypeByteSize(type); + + if (typeSize <= registerSize) + { + if (regs.size() <= store.size()) + { + return getNumberOfStacksForType(registerType); + } + + auto reg = regs[store.size()]; + store.push_back(reg); + + return 0; + } + + if ((typeSize > registerSize) + && (typeSize <= registerSize*maxRegsPerObject)) + { + std::size_t numberOfRegs = typeSize / registerSize; + auto regIt = store.size(); + + if (_cc->respectsRegisterCouples()) + { + if ((regIt+1)%2 == 0) + { + regIt++; + } + } + + for (std::size_t i = 0; i < numberOfRegs; i++) + { + if (regs.size() <= regIt) + { + return getNumberOfStacksForType(registerType)*(numberOfRegs-i); + } + + auto reg = regs[regIt]; + store.push_back(reg); + regIt++; + } + + return 0; + } + + if (_cc->passesLargeObjectsByReference()) + { + if (regs.size() <= store.size()) + { + return getNumberOfStacksForType(registerType); + } + + auto reg = regs[store.size()]; + store.push_back(reg); + + return 0; + } + + return getNumberOfStacksForType(type); +} + +size_t Filter::getNumberOfStacksForType(Type* type) const +{ + auto maxBytesPerParam = _cc->getMaxBytesPerStackParam(); + + if (maxBytesPerParam == 0) + { + return 0; + } + + std::size_t num = _abi->getTypeByteSize(type) / maxBytesPerParam; + + return num < 1 ? 1 : num; +} + +void Filter::filterRetsByKnownTypes(FilterableLayout& lay) const +{ + std::vector regGPValues, regFPValues, regDoubleValues, regVecValues; + + auto& gpRegs = _cc->getReturnRegisters(); + auto& fpRegs = _cc->getReturnFPRegisters(); + auto& doubleRegs = _cc->getReturnDoubleRegisters(); + auto& vecRegs = _cc->getReturnVectorRegisters(); + + Type* retType = lay.knownTypes.empty() ? nullptr + : lay.knownTypes.front(); + + if (retType == nullptr) + { + return; + } + + if (retType->isVectorTy() && !vecRegs.empty()) + { + std::size_t typeSize = _abi->getTypeByteSize(retType); + Type* registerType = _abi->getRegister(vecRegs.front())->getType(); + std::size_t registerSize = _abi->getTypeByteSize(registerType); + + if (typeSize <= registerSize || + (typeSize > registerSize*vecRegs.size())) + { + regVecValues.push_back(vecRegs.front()); + } + + std::size_t numOfRegs = typeSize/registerSize; + for (std::size_t i = 0; i < numOfRegs && i < vecRegs.size(); i++) + { + regVecValues.push_back(vecRegs[i]); + } + } + else if (retType->isDoubleTy() && !doubleRegs.empty()) + { + std::size_t typeSize = _abi->getTypeByteSize(retType); + Type* registerType = _abi->getRegister(doubleRegs.front())->getType(); + std::size_t registerSize = _abi->getTypeByteSize(registerType); + + if (typeSize <= registerSize || + (typeSize > registerSize*doubleRegs.size())) + { + regDoubleValues.push_back(doubleRegs.front()); + } + + std::size_t numOfRegs = typeSize/registerSize; + for (std::size_t i = 0; i < numOfRegs && i < doubleRegs.size(); i++) + { + regDoubleValues.push_back(doubleRegs[i]); + } + } + else if (retType->isFloatingPointTy() && !fpRegs.empty()) + { + std::size_t typeSize = _abi->getTypeByteSize(retType); + Type* registerType = _abi->getRegister(fpRegs.front())->getType(); + std::size_t registerSize = _abi->getTypeByteSize(registerType); + + if (typeSize <= registerSize || + (typeSize > registerSize*fpRegs.size())) + { + regFPValues.push_back(fpRegs.front()); + } + + std::size_t numOfRegs = typeSize/registerSize; + for (std::size_t i = 0; i < numOfRegs && i < fpRegs.size(); i++) + { + regFPValues.push_back(fpRegs[i]); + } + } + else if (!retType->isVoidTy()) + { + assert(!gpRegs.empty()); + + std::size_t typeSize = _abi->getTypeByteSize(retType); + Type* registerType = _abi->getRegister(gpRegs.front())->getType(); + std::size_t registerSize = _abi->getTypeByteSize(registerType); + + if (typeSize <= registerSize || + (typeSize > registerSize*gpRegs.size())) + { + regGPValues.push_back(gpRegs.front()); + } + + std::size_t numOfRegs = typeSize/registerSize; + for (std::size_t i = 0; i < numOfRegs && i < gpRegs.size(); i++) + { + regGPValues.push_back(gpRegs[i]); + } + } + + lay.gpRegisters = std::move(regGPValues); + lay.fpRegisters = std::move(regFPValues); + lay.doubleRegisters = std::move(regDoubleValues); + lay.vectorRegisters = std::move(regVecValues); + lay.knownTypes = {retType}; +} + + +void Filter::leaveCommonArgs(std::vector& allArgs) const +{ + leaveCommon(allArgs); +} + +void Filter::leaveCommonRets(std::vector& allRets) const +{ + leaveCommon(allRets); +} + +void Filter::leaveCommon(std::vector& lays) const +{ + if (lays.empty()) + { + return; + } + + auto& firstGPR = lays.front().gpRegisters; + auto& firstFPR = lays.front().fpRegisters; + auto& firstDR = lays.front().doubleRegisters; + auto& firstVR = lays.front().vectorRegisters; + + std::set commonGPR(firstGPR.begin(), firstGPR.end()); + std::set commonFPR(firstFPR.begin(), firstFPR.end()); + std::set commonDR(firstDR.begin(), firstDR.end()); + std::set commonVR(firstVR.begin(), firstVR.end()); + + std::size_t minStacks = lays.front().stacks.size(); + + for (auto& lay : lays) + { + + auto& gpr = lay.gpRegisters; + auto& fpr = lay.fpRegisters; + auto& dr = lay.doubleRegisters; + auto& vr = lay.vectorRegisters; + + commonGPR.insert(gpr.begin(), gpr.end()); + commonFPR.insert(fpr.begin(), fpr.end()); + commonDR.insert(dr.begin(), dr.end()); + commonVR.insert(vr.begin(), vr.end()); + + // if (lay.stacks.empty()) + // { + // continue; + // } + // else if (!minStacks || (minStacks > lay.stacks.size())) + if (minStacks > lay.stacks.size()) + { + minStacks = lay.stacks.size(); + } + } + + for (auto& lay : lays) + { + lay.gpRegisters.assign(commonGPR.begin(), commonGPR.end()); + lay.fpRegisters.assign(commonFPR.begin(), commonFPR.end()); + lay.doubleRegisters.assign(commonDR.begin(), commonDR.end()); + lay.vectorRegisters.assign(commonVR.begin(), commonVR.end()); + lay.stacks.resize(minStacks, nullptr); + + orderFiterableLayout(lay); + } +} + +void Filter::orderFiterableLayout(FilterableLayout& lay) const +{ + orderStacks(lay.stacks, _cc->getStackParamOrder()); + orderRegistersBy(lay.gpRegisters, _cc->getParamRegisters()); + orderRegistersBy(lay.fpRegisters, _cc->getParamFPRegisters()); + orderRegistersBy(lay.doubleRegisters, _cc->getParamDoubleRegisters()); + orderRegistersBy(lay.vectorRegisters, _cc->getParamVectorRegisters()); +} + +void Filter::orderStacks(std::vector& stacks, bool asc) const +{ + if (stacks.empty()) + { + return; + } + + auto config = _abi->getConfig(); + + std::stable_sort( + stacks.begin(), + stacks.end(), + [config, asc](Value* a, Value* b) -> bool + { + auto aOff = config->getStackVariableOffset(a); + auto bOff = config->getStackVariableOffset(b); + + bool ascOrd = aOff < bOff; + + return asc ? ascOrd : !ascOrd; + }); +} + +void Filter::orderRegistersBy( + std::vector& regs, + const std::vector& orderedVector) const +{ + std::stable_sort( + regs.begin(), + regs.end(), + [orderedVector](uint32_t a, uint32_t b) -> bool + { + auto it1 = std::find(orderedVector.begin(), orderedVector.end(), a); + auto it2 = std::find(orderedVector.begin(), orderedVector.end(), b); + + return std::distance(it1, it2) > 0; + }); +} + +FilterableLayout Filter::createArgsFilterableLayout( + const std::vector& group, + const std::vector& knownTypes) const +{ + FilterableLayout layout = separateArgValues(group); + layout.knownTypes = knownTypes; + + orderFiterableLayout(layout); + + return layout; +} + +FilterableLayout Filter::createRetsFilterableLayout( + const std::vector& group, + llvm::Type* knownType) const +{ + std::vector knownTypes = {knownType}; + return createRetsFilterableLayout(group, knownTypes); +} + +FilterableLayout Filter::createRetsFilterableLayout( + const std::vector& group, + const std::vector& knownTypes) const +{ + FilterableLayout layout = separateRetValues(group); + layout.knownTypes = knownTypes; + + orderFiterableLayout(layout); + + return layout; +} + +FilterableLayout Filter::separateArgValues(const std::vector& paramValues) const +{ + auto& regs = _cc->getParamRegisters(); + auto& fpRegs = _cc->getParamFPRegisters(); + auto& doubleRegs = _cc->getParamDoubleRegisters(); + auto& vecRegs = _cc->getParamVectorRegisters(); + + return separateValues(paramValues, regs, fpRegs, doubleRegs, vecRegs); +} + +FilterableLayout Filter::separateRetValues(const std::vector& paramValues) const +{ + auto& regs = _cc->getReturnRegisters(); + auto& fpRegs = _cc->getReturnFPRegisters(); + auto& doubleRegs = _cc->getReturnDoubleRegisters(); + auto& vecRegs = _cc->getReturnVectorRegisters(); + + FilterableLayout lay = separateValues(paramValues, regs, fpRegs, doubleRegs, vecRegs); + lay.stacks.clear(); + + return lay; +} + +FilterableLayout Filter::separateValues( + const std::vector& paramValues, + const std::vector& gpRegs, + const std::vector& fpRegs, + const std::vector& doubleRegs, + const std::vector& vecRegs) const +{ + FilterableLayout layout; + + for (auto pv: paramValues) + { + if (_abi->isStackVariable(pv)) + { + layout.stacks.push_back(pv); + } + else if (!_abi->isRegister(pv)) + { + continue; + } + if (std::find(gpRegs.begin(), gpRegs.end(), + _abi->getRegisterId(pv)) != gpRegs.end()) + { + layout.gpRegisters.push_back(_abi->getRegisterId(pv)); + } + else if (std::find(doubleRegs.begin(), doubleRegs.end(), + _abi->getRegisterId(pv)) != doubleRegs.end()) + { + layout.doubleRegisters.push_back(_abi->getRegisterId(pv)); + } + else if (std::find(fpRegs.begin(), fpRegs.end(), + _abi->getRegisterId(pv)) != fpRegs.end()) + { + layout.fpRegisters.push_back(_abi->getRegisterId(pv)); + } + else if (std::find(vecRegs.begin(), vecRegs.end(), + _abi->getRegisterId(pv)) != vecRegs.end()) + { + layout.vectorRegisters.push_back(_abi->getRegisterId(pv)); + } + } + + return layout; +} + +std::vector Filter::createGroupedArgValues(const FilterableLayout& lay) const +{ + return createGroupedValues(lay); +} + +std::vector Filter::createGroupedRetValues(const FilterableLayout& lay) const +{ + return createGroupedValues(lay); +} + +std::vector Filter::createGroupedValues(const FilterableLayout& lay) const +{ + std::vector paramValues; + + auto ri = lay.gpRegisters.begin(); + auto fi = lay.fpRegisters.begin(); + auto di = lay.doubleRegisters.begin(); + auto vi = lay.vectorRegisters.begin(); + auto si = lay.stacks.begin(); + + if (!lay.knownOrder.empty()) + { + for (auto ord : lay.knownOrder) + { + switch (ord) + { + case OrderID::ORD_GPR: + if (ri != lay.gpRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*ri)); + ri++; + } + break; + + case OrderID::ORD_FPR: + if (fi != lay.fpRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*fi)); + fi++; + } + break; + + case OrderID::ORD_DOUBR: + if (di != lay.doubleRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*di)); + di++; + } + break; + + case OrderID::ORD_VECR: + if (vi != lay.vectorRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*vi)); + vi++; + } + break; + + case OrderID::ORD_STACK: + if (si != lay.stacks.end()) + { + paramValues.push_back(*si); + si++; + } + break; + + case OrderID::ORD_GPR_GROUP: + if (ri != lay.gpRegisters.end()) + { + ri++; + } + break; + + case OrderID::ORD_FPR_GROUP: + if (fi != lay.fpRegisters.end()) + { + fi++; + } + break; + + case OrderID::ORD_DOUBR_GROUP: + if (di != lay.doubleRegisters.end()) + { + di++; + } + break; + + case OrderID::ORD_VECR_GROUP: + + if (vi != lay.vectorRegisters.end()) + { + vi++; + } + break; + + case OrderID::ORD_STACK_GROUP: + if (si != lay.stacks.end()) + { + si++; + } + break; + + + default: + continue; + } + } + + return paramValues; + } + + while (ri != lay.gpRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*ri)); + ri++; + } + + while (fi != lay.fpRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*fi)); + fi++; + } + + while (di != lay.doubleRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*di)); + di++; + } + + while (vi != lay.vectorRegisters.end()) + { + paramValues.push_back(_abi->getRegister(*vi)); + vi++; + } + + paramValues.insert(paramValues.end(), si, lay.stacks.end()); + + return paramValues; +} + +void Filter::leaveOnlyPositiveStacks(FilterableLayout& lay) const +{ + auto* config = _abi->getConfig(); + + lay.stacks.erase( + std::remove_if(lay.stacks.begin(), lay.stacks.end(), + [config](const Value* li) + { + auto aOff = config->getStackVariableOffset(li); + return aOff.isDefined() && aOff < 0; + }), + lay.stacks.end()); +} + +void Filter::leaveOnlyContinuousStack(FilterableLayout& lay) const +{ + retdec::utils::Maybe prevOff; + int gap = _cc->getMaxBytesPerStackParam(); + auto* config = _abi->getConfig(); + + auto it = lay.stacks.begin(); + while (it != lay.stacks.end()) + { + auto off = config->getStackVariableOffset(*it); + + if (prevOff.isUndefined()) + { + prevOff = off; + } + else if (std::abs(prevOff - off) > gap) + { + it = lay.stacks.erase(it); + continue; + } + else + { + prevOff = off; + } + + ++it; + } +} + +void Filter::leaveOnlyContinuousArgRegisters(FilterableLayout& lay) const +{ + leaveOnlyContinuousRegisters(lay.gpRegisters, _cc->getParamRegisters()); + leaveOnlyContinuousRegisters(lay.fpRegisters, _cc->getParamFPRegisters()); + leaveOnlyContinuousRegisters(lay.doubleRegisters, _cc->getParamDoubleRegisters()); + leaveOnlyContinuousRegisters(lay.vectorRegisters, _cc->getParamVectorRegisters()); + + bool usingGPR = !_cc->getParamRegisters().empty(); + bool usingFPR = !_cc->getParamFPRegisters().empty(); + bool usingDR = !_cc->getParamDoubleRegisters().empty(); + bool usingVR = !_cc->getParamVectorRegisters().empty(); + + bool missingGPR = lay.gpRegisters.size() < _cc->getParamRegisters().size(); + bool missingFPR = lay.fpRegisters.size() < _cc->getParamFPRegisters().size(); + bool missingDR = lay.doubleRegisters.size() < _cc->getParamDoubleRegisters().size(); + bool missingVR = lay.vectorRegisters.size() < _cc->getParamVectorRegisters().size(); + + // If calling convention passes large objects on stacks (not by refetence) + // usage of another registers will be omitted. + // + // Stacks can be erased only if all types of registers that a cc + // uses are missing some register usage. + + bool eraseStacks = false; + if (_cc->passesLargeObjectsByReference()) + { + if (usingGPR) + { + eraseStacks = missingGPR; + } + + if (usingFPR) + { + eraseStacks = eraseStacks && missingFPR; + } + + if (usingDR) + { + eraseStacks = eraseStacks && missingDR; + } + + if (usingVR) + { + eraseStacks = eraseStacks && missingVR; + } + } + + if (eraseStacks) + { + lay.stacks.clear(); + } +} + +void Filter::createContinuousArgRegisters(FilterableLayout& lay) const +{ + std::vector gpRegs, fpRegs, dbRegs, veRegs; + + if (!lay.gpRegisters.empty()) + { + uint32_t regId = lay.gpRegisters.back(); + + for (auto ccR : _cc->getParamRegisters()) + { + gpRegs.push_back(ccR); + if (regId == ccR) + { + break; + } + } + } + + if (!lay.fpRegisters.empty()) + { + uint32_t regId = lay.fpRegisters.back(); + + for (auto ccR : _cc->getParamFPRegisters()) + { + fpRegs.push_back(ccR); + if (regId == ccR) + { + break; + } + } + } + + if (!lay.doubleRegisters.empty()) + { + uint32_t regId = lay.doubleRegisters.back(); + + for (auto ccR : _cc->getParamDoubleRegisters()) + { + dbRegs.push_back(ccR); + if (regId == ccR) + { + break; + } + } + } + + if (!lay.vectorRegisters.empty()) + { + uint32_t regId = lay.vectorRegisters.back(); + + for (auto ccR : _cc->getParamRegisters()) + { + veRegs.push_back(ccR); + if (regId == ccR) + { + break; + } + } + } + + lay.gpRegisters = std::move(gpRegs); + lay.fpRegisters = std::move(fpRegs); + lay.doubleRegisters = std::move(dbRegs); + lay.vectorRegisters = std::move(veRegs); +} + +void Filter::leaveOnlyContinuousRetRegisters(FilterableLayout& lay) const +{ + leaveOnlyContinuousRegisters(lay.gpRegisters, _cc->getReturnRegisters()); + leaveOnlyContinuousRegisters(lay.fpRegisters, _cc->getReturnFPRegisters()); + leaveOnlyContinuousRegisters(lay.doubleRegisters, _cc->getReturnDoubleRegisters()); + leaveOnlyContinuousRegisters(lay.vectorRegisters, _cc->getReturnVectorRegisters()); +} + +void Filter::leaveOnlyContinuousRegisters( + std::vector& regs, + const std::vector& templRegs) const +{ + auto itEnd = regs.end(); + auto it = regs.begin(); + for (auto regId : templRegs) + { + if (it == itEnd) + { + break; + } + + if (regId != *it) + { + regs.erase(it, itEnd); + break; + } + + it++; + } +} + +void Filter::leaveSameStacks(FilterableLayout& lay, const FilterableLayout& fig) const +{ + lay.stacks.resize(fig.stacks.size(), nullptr); +} + +// +//============================================================================= +// FilterProvider +//============================================================================= +// + +Filter::Ptr FilterProvider::createFilter(Abi* abi, const CallingConvention::ID& id) +{ + auto* cc = abi->getCallingConvention(id); + if (cc == nullptr) + { + cc = abi->getDefaultCallingConvention(); + } + + assert(cc); + + auto c = abi->getConfig(); + bool isMinGW = c->getConfig().tools.isGcc() + && c->getConfig().fileFormat.isPe(); + + if (abi->isX64() && (isMinGW || c->getConfig().tools.isMsvc())) + { + return std::make_unique(abi, cc); + } + + return std::make_unique(abi, cc); +} + +} +} diff --git a/src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp b/src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp new file mode 100644 index 000000000..f00a76887 --- /dev/null +++ b/src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp @@ -0,0 +1,189 @@ +/** +* @file src/bin2llvmir/optimizations/param_return/filter/ms_x64.cpp +* @brief Microsoft x64 specific filtration of registers. +* @copyright (c) 2019 Avast Software, licensed under the MIT license +*/ + +#include + +#include "retdec/bin2llvmir/optimizations/param_return/filter/ms_x64.h" + +using namespace retdec::utils; +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +MSX64Filter::MSX64Filter( + const Abi* abi, + const CallingConvention* cc) : + Filter(abi, cc) +{ +} + +MSX64Filter::~MSX64Filter() +{ +} + +void MSX64Filter::filterDefinitionArgs(FilterableLayout& args, bool isVoidarg) const +{ + leaveOnlyPositiveStacks(args); + + if (isVoidarg) + { + args.gpRegisters.clear(); + args.fpRegisters.clear(); + args.doubleRegisters.clear(); + args.vectorRegisters.clear(); + args.stacks.clear(); + } + else if (!args.knownTypes.empty()) + { + filterArgsByKnownTypes(args); + } + else + { + leaveOnlyAlternatingArgRegisters(args); + } + + leaveOnlyContinuousStack(args); +} + +void MSX64Filter::filterCallArgs(FilterableLayout& args, bool isVoidarg) const +{ + if (isVoidarg) + { + args.gpRegisters.clear(); + args.fpRegisters.clear(); + args.doubleRegisters.clear(); + args.vectorRegisters.clear(); + args.stacks.clear(); + } + else if (!args.knownTypes.empty()) + { + filterArgsByKnownTypes(args); + } + else + { + leaveOnlyAlternatingArgRegisters(args); + } + + leaveOnlyContinuousStack(args); +} + +void MSX64Filter::filterArgsByKnownTypes(FilterableLayout& lay) const +{ + FilterableLayout newLayout; + newLayout.knownTypes = lay.knownTypes; + + auto& gpRegs = _cc->getParamRegisters(); + + // Indexes of registers to be used next as particular parameter. + auto sIt = lay.stacks.begin(); + + std::size_t regEnd = gpRegs.size(); + + std::vector registers; + + std::vector types = expandTypes(lay.knownTypes); + + for (auto t: types) + { + std::size_t requiredStacks = 0; + OrderID stackOrd = OrderID::ORD_STACK; + + if (t->isFloatingPointTy() || t->isVectorTy()) + { + if (registers.size() < regEnd) + { + newLayout.fpRegisters = registers; + requiredStacks = fetchFPRegsForType(t, newLayout); + registers = newLayout.fpRegisters; + stackOrd = OrderID::ORD_STACK_GROUP; + } + } + else + { + if (registers.size() < regEnd) + { + newLayout.gpRegisters = registers; + requiredStacks = fetchGPRegsForType(t, newLayout); + registers = newLayout.gpRegisters; + stackOrd = OrderID::ORD_STACK_GROUP; + } + } + + if (!requiredStacks && stackOrd == OrderID::ORD_STACK) + { + requiredStacks = getNumberOfStacksForType(t); + } + + for (std::size_t i = 0; i < requiredStacks; i++) + { + if (sIt != lay.stacks.end()) + { + newLayout.stacks.push_back(*sIt); + sIt++; + } + else + { + newLayout.stacks.push_back(nullptr); + } + + newLayout.knownOrder.push_back( + i == 0 ? stackOrd : + OrderID::ORD_STACK_GROUP); + } + } + + std::vector regVals; + for (auto r : registers) + { + regVals.push_back(_abi->getRegister(r)); + } + + lay = separateArgValues(regVals); + lay.stacks = newLayout.stacks; + lay.knownOrder = newLayout.knownOrder; + lay.knownTypes = newLayout.knownTypes; +} + +void MSX64Filter::leaveOnlyAlternatingArgRegisters(FilterableLayout& lay) const +{ + auto& templRegs = _cc->getParamRegisters(); + auto& fpTemplRegs = _cc->getParamFPRegisters(); + + auto it = lay.gpRegisters.begin(); + auto fIt = lay.fpRegisters.begin(); + + std::size_t idx = 0; + while (idx < fpTemplRegs.size() && idx < templRegs.size()) + { + if (it == lay.gpRegisters.end() && fIt == lay.fpRegisters.end()) + { + lay.stacks.clear(); + return; + } + + if (it != lay.gpRegisters.end() && *it == templRegs[idx]) + { + it++; + } + else if (fIt != lay.fpRegisters.end() && *fIt == fpTemplRegs[idx]) + { + fIt++; + } + else + { + lay.gpRegisters.erase(it, lay.gpRegisters.end()); + lay.fpRegisters.erase(fIt, lay.fpRegisters.end()); + lay.stacks.clear(); + return; + } + + idx++; + } +} + +} +} diff --git a/src/bin2llvmir/optimizations/param_return/param_return.cpp b/src/bin2llvmir/optimizations/param_return/param_return.cpp index df4507900..ec5fa6a18 100644 --- a/src/bin2llvmir/optimizations/param_return/param_return.cpp +++ b/src/bin2llvmir/optimizations/param_return/param_return.cpp @@ -1,21 +1,7 @@ /** * @file src/bin2llvmir/optimizations/param_return/param_return.cpp * @brief Detect functions' parameters and returns. -* @copyright (c) 2017 Avast Software, licensed under the MIT license -* -* Original implementation: -* name -- position of format string, position of variadic arg start -* printf/scanf -- 0, 1 -* __printf_chk -- 1, 2 -* __fprintf_chk -- 2, 3 -* fprintf/fscanf/wsprintfA/wsprintf/sprintf/sscanf -- 1, 2 -* snprintf -- 2, 3 -* __snprintf_chk -- 4, 5 -* ioctl/open/FmtStr -- not handled -- erase arguments -* wprintf/wscanf -- 0, 1 -* error -- 2, 3 -* error_at_line -- 4, 5 -* other -- not handled -- copy arguments +* @copyright (c) 2019 Avast Software, licensed under the MIT license */ #include @@ -23,6 +9,7 @@ #include #include +#include #include #include #include @@ -30,6 +17,7 @@ #include "retdec/utils/container.h" #include "retdec/utils/string.h" +#include "retdec/bin2llvmir/optimizations/param_return/filter/filter.h" #include "retdec/bin2llvmir/optimizations/param_return/param_return.h" #define debug_enabled false #include "retdec/bin2llvmir/utils/llvm.h" @@ -42,58 +30,6 @@ using namespace llvm; namespace retdec { namespace bin2llvmir { -llvm::Value* getRoot(ReachingDefinitionsAnalysis& RDA, llvm::Value* i, bool first = true) -{ - static std::set seen; - if (first) - { - seen.clear(); - } - if (seen.count(i)) - { - return i; - } - seen.insert(i); - - i = llvm_utils::skipCasts(i); - if (auto* ii = dyn_cast(i)) - { - if (auto* u = RDA.getUse(ii)) - { - if (u->defs.size() == 1) - { - auto* d = (*u->defs.begin())->def; - if (auto* s = dyn_cast(d)) - { - return getRoot(RDA, s->getValueOperand(), false); - } - else - { - return d; - } - } - else if (auto* l = dyn_cast(ii)) - { - return getRoot(RDA, l->getPointerOperand(), false); - } - else - { - return i; - } - } - else if (auto* l = dyn_cast(ii)) - { - return getRoot(RDA, l->getPointerOperand(), false); - } - else - { - return i; - } - } - - return i; -} - // //============================================================================= // ParamReturn @@ -123,11 +59,13 @@ bool ParamReturn::runOnModule(Module& m) _image = FileImageProvider::getFileImage(_module); _dbgf = DebugFormatProvider::getDebugFormat(_module); _lti = LtiProvider::getLti(_module); + _collector = CollectorProvider::createCollector(_abi, _module, &_RDA); + return run(); } bool ParamReturn::runOnModuleCustom( - llvm::Module& m, + Module& m, Config* c, Abi* abi, FileImage* img, @@ -140,6 +78,8 @@ bool ParamReturn::runOnModuleCustom( _image = img; _dbgf = dbgf; _lti = lti; + _collector = CollectorProvider::createCollector(_abi, _module, &_RDA); + return run(); } @@ -151,21 +91,16 @@ bool ParamReturn::run() return false; } - _RDA.runOnModule(*_module, AbiProvider::getAbi(_module)); - -//dumpModuleToFile(_module); + _RDA.runOnModule(*_module, _abi); collectAllCalls(); - dumpInfo(); +// dumpInfo(); filterCalls(); - dumpInfo(); +// dumpInfo(); applyToIr(); _RDA.clear(); -//dumpModuleToFile(_module); -//exit(1); - return false; } @@ -183,18 +118,9 @@ void ParamReturn::collectAllCalls() continue; } - _fnc2calls.emplace( - std::make_pair( - &f, - DataFlowEntry( - _module, - _RDA, - _config, - _abi, - _image, - _dbgf, - _lti, - &f))); + _fnc2calls.emplace(std::make_pair( + &f, + createDataFlowEntry(&f))); } for (auto& f : _module->getFunctionList()) @@ -218,1579 +144,698 @@ void ParamReturn::collectAllCalls() auto fIt = _fnc2calls.find(calledVal); if (fIt == _fnc2calls.end()) { - fIt = _fnc2calls.emplace(std::make_pair( + fIt = _fnc2calls.emplace( + std::make_pair( calledVal, - DataFlowEntry( - _module, - _RDA, - _config, - _abi, - _image, - _dbgf, - _lti, - calledVal))).first; + createDataFlowEntry(calledVal))).first; } - fIt->second.addCall(call); - } -} - -void ParamReturn::filterCalls() -{ - for (auto& p : _fnc2calls) - { - p.second.filter(); - } -} - -void ParamReturn::applyToIr() -{ - for (auto& p : _fnc2calls) - { - p.second.applyToIr(); - } - - for (auto& p : _fnc2calls) - { - p.second.connectWrappers(); + addDataFromCall(&fIt->second, call); } } -/** - * Dump all the info collected and processed so far. - */ -void ParamReturn::dumpInfo() +DataFlowEntry ParamReturn::createDataFlowEntry(Value* calledValue) const { - LOG << std::endl << "_fnc2calls:" << std::endl; - for (auto& p : _fnc2calls) - { - p.second.dump(); - } -} + DataFlowEntry dataflow(calledValue); -// -//============================================================================= -// CallEntry -//============================================================================= -// + _collector->collectDefArgs(&dataflow); + _collector->collectDefRets(&dataflow); -CallEntry::CallEntry(llvm::CallInst* c) : - call(c) -{ + collectExtraData(&dataflow); + return dataflow; } -bool registerCanBeParameterAccordingToAbi(Abi* _abi, Config* _config, llvm::Value* val) +void ParamReturn::collectExtraData(DataFlowEntry* dataflow) const { - if (!_abi->isRegister(val)) + auto* fnc = dataflow->getFunction(); + if (fnc == nullptr) { - return true; + return; } - if (_config->getConfig().architecture.isX86()) - { - return false; - } - else if (_config->getConfig().architecture.isPpc()) - { - static std::set names = {"r3", "r4", "r5", "r6", "r7", "r8", "r9"}; - if (names.find(val->getName()) == names.end()) - { - return false; - } - } - else if (_config->getConfig().architecture.isArmOrThumb()) - { - static std::set names = {"r0", "r1", "r2", "r3"}; - if (names.find(val->getName()) == names.end()) - { - return false; - } - } - else if (_config->getConfig().architecture.isMipsOrPic32()) + // Main + // + if (fnc->getName() == "main") { - static std::set names = {"a0", "a1", "a2", "a3"}; - if (names.find(val->getName()) == names.end()) - { - return false; - } - } - - return true; -} + auto charPointer = PointerType::get( + Type::getInt8Ty(_module->getContext()), 0); -/** - * Remove all registers that are not used to pass argument according to ABI. - */ -void CallEntry::filterRegisters(Abi* _abi, Config* _config) -{ - auto it = possibleArgStores.begin(); - while (it != possibleArgStores.end()) - { - auto* op = (*it)->getPointerOperand(); - if (!registerCanBeParameterAccordingToAbi(_abi, _config, op)) + dataflow->setArgTypes( { - it = possibleArgStores.erase(it); - } - else + _abi->getDefaultType(), + PointerType::get(charPointer, 0) + }, { - ++it; - } + "argc", + "argv" + }); + + dataflow->setRetType(_abi->getDefaultType()); + return; } -} -void DataFlowEntry::filterRegistersArgLoads() -{ - auto it = argLoads.begin(); - while (it != argLoads.end()) + // LTI info. + // + auto* cf = _config->getConfigFunction(fnc); + if (cf && (cf->isDynamicallyLinked() || cf->isStaticallyLinked())) { - auto* op = (*it)->getPointerOperand(); - if (!registerCanBeParameterAccordingToAbi(_abi, _config, op)) - { - it = argLoads.erase(it); - } - else + auto fp = _lti->getPairFunctionFree(cf->getName()); + if (fp.first) { - auto aOff = _config->getStackVariableOffset(op); - if (aOff.isDefined() && aOff < 0) + std::vector argTypes; + std::vector argNames; + for (auto& a : fp.first->args()) + { + if (!a.getType()->isSized()) + { + continue; + } + argTypes.push_back(a.getType()); + argNames.push_back(a.getName()); + } + dataflow->setArgTypes( + std::move(argTypes), + std::move(argNames)); + + if (fp.first->isVarArg()) { - it = argLoads.erase(it); + dataflow->setVariadic(); } - else + dataflow->setRetType(fp.first->getReturnType()); + + std::string declr = fp.second->getDeclaration(); + if (!declr.empty()) { - ++it; + cf->setDeclarationString(declr); } + return; } } -} -/** - * Stack with the lowest (highest negative) offset is the first call argument. - */ -void CallEntry::filterSort(Config* _config) -{ - auto& stores = possibleArgStores; + auto dbgFnc = _dbgf ? _dbgf->getFunction( + _config->getFunctionAddress(fnc)) : nullptr; - std::stable_sort( - stores.begin(), - stores.end(), - [_config](StoreInst* a, StoreInst* b) -> bool + // Debug info. + // + if (dbgFnc) { - auto aOff = _config->getStackVariableOffset(a->getPointerOperand()); - auto bOff = _config->getStackVariableOffset(b->getPointerOperand()); - - if (aOff.isUndefined() && bOff.isUndefined()) - { - return _config->getConfigRegisterNumber(a->getPointerOperand()) < - _config->getConfigRegisterNumber(b->getPointerOperand()); - } - else if (aOff.isUndefined() && bOff.isDefined()) - { - return true; - } - else if (aOff.isDefined() && bOff.isUndefined()) - { - return false; - } - else + std::vector argTypes; + std::vector argNames; + for (auto& a : dbgFnc->parameters) { - return aOff < bOff; + auto* t = llvm_utils::stringToLlvmTypeDefault( + _module, a.type.getLlvmIr()); + if (!t->isSized()) + { + continue; + } + argTypes.push_back(t); + argNames.push_back(a.getName()); } - }); -} - -void DataFlowEntry::filterSortArgLoads() -{ - std::stable_sort( - argLoads.begin(), - argLoads.end(), - [this](LoadInst* a, LoadInst* b) -> bool - { - auto aOff = _config->getStackVariableOffset(a->getPointerOperand()); - auto bOff = _config->getStackVariableOffset(b->getPointerOperand()); + dataflow->setArgTypes( + std::move(argTypes), + std::move(argNames)); - if (aOff.isUndefined() && bOff.isUndefined()) - { - return _config->getConfigRegisterNumber(a->getPointerOperand()) < - _config->getConfigRegisterNumber(b->getPointerOperand()); - } - else if (aOff.isUndefined() && bOff.isDefined()) - { - return true; - } - else if (aOff.isDefined() && bOff.isUndefined()) - { - return false; - } - else + if (dbgFnc->isVariadic()) { - return aOff < bOff; + dataflow->setVariadic(); } - }); -} + dataflow->setRetType( + llvm_utils::stringToLlvmTypeDefault( + _module, + dbgFnc->returnType.getLlvmIr())); -/** - * Arguments are stored into stack variables which go one after another, - * there can be no big stack offset gaps. - */ -void CallEntry::filterLeaveOnlyContinuousStackOffsets(Config* _config) -{ - retdec::utils::Maybe prevOff; - auto it = possibleArgStores.begin(); - while (it != possibleArgStores.end()) - { - auto* s = *it; - auto off = _config->getStackVariableOffset(s->getPointerOperand()); - auto* val = llvm_utils::skipCasts(s->getValueOperand()); + return; + } - int gap = 8; -// int gap = 4; - if (val->getType()->isFloatingPointTy()) + auto configFnc = _config->getConfigFunction(fnc); + if (_config->getConfig().isIda() && configFnc) + { + std::vector argTypes; + std::vector argNames; + for (auto& a : configFnc->parameters) { - gap = 8; + auto* t = llvm_utils::stringToLlvmTypeDefault( + _module, + a.type.getLlvmIr()); + if (!t->isSized()) + { + continue; + } + argTypes.push_back(t); + argNames.push_back(a.getName()); } + dataflow->setArgTypes( + std::move(argTypes), + std::move(argNames)); - if (off.isUndefined()) - { - ++it; - continue; - } - if (prevOff.isUndefined()) - { - prevOff = off; - } - else if (std::abs(prevOff - off) > gap) - { - it = possibleArgStores.erase(it); - continue; - } - else + if (configFnc->isVariadic()) { - prevOff = off; + dataflow->setVariadic(); } - - ++it; + dataflow->setRetType( + llvm_utils::stringToLlvmTypeDefault( + _module, + configFnc->returnType.getLlvmIr())); + return; } -} -void CallEntry::filterLeaveOnlyNeededStackOffsets(Abi* _abi, Config* _config) -{ - int regNum = 0; - auto it = possibleArgStores.begin(); - while (it != possibleArgStores.end()) + // Calling convention. + if (configFnc) { - auto* s = *it; - auto* op = s->getPointerOperand(); - auto off = _config->getStackVariableOffset(op); + dataflow->setCallingConvention(configFnc->callingConvention.getID()); + } - if (_abi->isRegister(op)) - { - ++regNum; - ++it; - continue; - } - else if (off.isDefined()) + // Wrappers. + // + if (CallInst* wrappedCall = getWrapper(fnc)) + { + auto* wf = wrappedCall->getCalledFunction(); + auto* ltiFnc = _lti->getLlvmFunctionFree(wf->getName()); + if (ltiFnc) { - if (_config->getConfig().architecture.isX86()) - { - // nothing - } - else if (_config->getConfig().architecture.isPpc()) - { - if (regNum == 7) - { - // nothing - } - else - { - it = possibleArgStores.erase(it); - continue; - } - } - else if (_config->getConfig().architecture.isArmOrThumb() - || _config->getConfig().architecture.isMipsOrPic32()) + std::vector argTypes; + std::vector argNames; + for (auto& a : ltiFnc->args()) { - if (regNum == 4) + if (!a.getType()->isSized()) { - // nothing - } - else - { - it = possibleArgStores.erase(it); continue; } + argTypes.push_back(a.getType()); + argNames.push_back(a.getName()); } - else + dataflow->setArgTypes( + std::move(argTypes), + std::move(argNames)); + + if (ltiFnc->isVarArg()) { - // nothing + dataflow->setVariadic(); } - } + dataflow->setRetType(ltiFnc->getReturnType()); + dataflow->setWrappedCall(wrappedCall); - ++it; + return; + } } } -void CallEntry::extractFormatString(ReachingDefinitionsAnalysis& _RDA) +CallInst* ParamReturn::getWrapper(Function* fnc) const { - for (auto* s : possibleArgStores) + auto ai = AsmInstruction(fnc); + if (ai.isInvalid()) { - auto* v = getRoot(_RDA, s->getValueOperand()); - auto* gv = dyn_cast_or_null(v); + return nullptr; + } - if (gv == nullptr || !gv->hasInitializer()) + bool single = true; + auto next = ai.getNext(); + while (next.isValid()) + { + if (!next.empty() && !isa(next.front())) { - continue; + single = false; + break; } + next = next.getNext(); + } - auto* init = dyn_cast_or_null(gv->getInitializer()); - if (init == nullptr) + // Pattern + // .text:00008A38 LDR R0, =aCCc ; "C::cc()" + // .text:00008A3C B puts + // .text:00008A40 off_8A40 DCD aCCc + // TODO: make better wrapper detection. In wrapper, wrapped function params + // should not be set like in this example. + // + if (ai && next) + { + if (_image->getConstantDefault(next.getEndAddress())) { - if (auto* i = dyn_cast(gv->getInitializer())) + auto* l = ai.getInstructionFirst(); + auto* s = ai.getInstructionFirst(); + auto* c = next.getInstructionFirst(); + if (l && s && c && isa(l->getPointerOperand()) + && s->getPointerOperand()->getName() == "r0") { - if (auto* igv = dyn_cast(i->getOperand(0))) + auto gvA = _config->getGlobalAddress(cast(l->getPointerOperand())); + if (gvA == next.getEndAddress()) { - init = dyn_cast_or_null(igv->getInitializer()); + return nullptr; } } } + } - if (init == nullptr || !init->isString()) + if (single) + { + for (auto& i : ai) { - continue; + if (auto* c = dyn_cast(&i)) + { + auto* cf = c->getCalledFunction(); + if (cf && !cf->isIntrinsic()) // && cf->isDeclaration()) + { + return c; + } + } } - - formatStr = init->getAsString(); - break; } -} - -// -//============================================================================= -// ReturnEntry -//============================================================================= -// - -ReturnEntry::ReturnEntry(llvm::ReturnInst* r) : - ret(r) -{ - -} - -// -//============================================================================= -// DataFlowEntry -//============================================================================= -// -DataFlowEntry::DataFlowEntry( - llvm::Module* m, - ReachingDefinitionsAnalysis& rda, - Config* c, - Abi* abi, - FileImage* img, - DebugFormat* dbg, - Lti* lti, - llvm::Value* v) - : - _module(m), - _RDA(rda), - _config(c), - _abi(abi), - _image(img), - _lti(lti), - called(v) -{ - if (auto* f = getFunction()) + unsigned aiNum = 0; + bool isSmall = true; + next = ai; + while (next.isValid()) { - configFnc = c->getConfigFunction(f); - if (dbg) + ++aiNum; + next = next.getNext(); + if (aiNum > 4) { - dbgFnc = dbg->getFunction(c->getFunctionAddress(f)); + isSmall = false; + break; } - - if (!f->empty()) + } + auto* s = _image->getImage()->getSegmentFromAddress(ai.getAddress()); + if ((s && s->getName() == ".plt") || isSmall) + { + for (inst_iterator it = inst_begin(fnc), rIt = inst_end(fnc); + it != rIt; ++it) { - addArgLoads(); - addRetStores(); + if (auto* l = dyn_cast(&*it)) + { + std::string n = l->getPointerOperand()->getName(); + if (n == "lr" || n == "sp") + { + return nullptr; + } + } + else if (auto* s = dyn_cast(&*it)) + { + std::string n = s->getPointerOperand()->getName(); + if (n == "lr" || n == "sp") + { + return nullptr; + } + } + else if (auto* c = dyn_cast(&*it)) + { + auto* cf = c->getCalledFunction(); + if (cf && !cf->isIntrinsic() && cf->isDeclaration()) + { + return c; + } + } } } - setTypeFromExtraInfo(); + return nullptr; } -bool DataFlowEntry::isFunctionEntry() const +void ParamReturn::addDataFromCall(DataFlowEntry* dataflow, CallInst* call) const { - return getFunction() != nullptr; -} + CallEntry* ce = dataflow->createCallEntry(call); -bool DataFlowEntry::isValueEntry() const -{ - return called && !isFunctionEntry(); + _collector->collectCallArgs(ce); + + // TODO: Use info from collecting return loads. + // + // At this moment info return loads is not used + // as it is not reliable source of info + // about return value. To enable this + // collector must have redesigned and reimplemented + // collection algorithm. + // + //_collector->collectCallRets(ce); + + collectExtraData(ce); } -llvm::Value* DataFlowEntry::getValue() const +void ParamReturn::collectExtraData(CallEntry* ce) const { - return called; } -llvm::Function* DataFlowEntry::getFunction() const +void ParamReturn::dumpInfo() const { - return dyn_cast_or_null(called); + LOG << std::endl << "_fnc2calls:" << std::endl; + + for (auto& p : _fnc2calls) + { + dumpInfo(p.second); + } } -void DataFlowEntry::dump() const +void ParamReturn::dumpInfo(const DataFlowEntry& de) const { + auto called = de.getValue(); + auto fnc = de.getFunction(); + auto configFnc = _config->getConfigFunction(fnc); + auto dbgFnc = _dbgf ? _dbgf->getFunction( + _config->getFunctionAddress(fnc)) : nullptr; + auto wrappedCall = de.getWrappedCall(); + LOG << "\n\t>|" << called->getName().str() << std::endl; - LOG << "\t>|fnc call : " << isFunctionEntry() << std::endl; - LOG << "\t>|val call : " << isValueEntry() << std::endl; - LOG << "\t>|variadic : " << isVarArg << std::endl; + LOG << "\t>|fnc call : " << de.isFunction() << std::endl; + LOG << "\t>|val call : " << de.isValue() << std::endl; + LOG << "\t>|variadic : " << de.isVariadic() << std::endl; + LOG << "\t>|voidarg : " << de.isVoidarg() << std::endl; + LOG << "\t>|call conv: " << de.getCallingConvention() << std::endl; LOG << "\t>|config f : " << (configFnc != nullptr) << std::endl; LOG << "\t>|debug f : " << (dbgFnc != nullptr) << std::endl; LOG << "\t>|wrapp c : " << llvmObjToString(wrappedCall) << std::endl; - LOG << "\t>|type set : " << typeSet << std::endl; - LOG << "\t>|ret type : " << llvmObjToString(retType) << std::endl; + LOG << "\t>|type set : " << !de.argTypes().empty() << std::endl; + LOG << "\t>|ret type : " << llvmObjToString(de.getRetType()) << std::endl; + LOG << "\t>|ret value: " << llvmObjToString(de.getRetValue()) << std::endl; LOG << "\t>|arg types:" << std::endl; - for (auto* t : argTypes) + for (auto* t : de.argTypes()) { LOG << "\t\t>|" << llvmObjToString(t) << std::endl; } LOG << "\t>|arg names:" << std::endl; - for (auto& n : argNames) + for (auto& n : de.argNames()) { LOG << "\t\t>|" << n << std::endl; } LOG << "\t>|calls:" << std::endl; - for (auto& e : calls) + for (auto& e : de.callEntries()) { - LOG << "\t\t>|" << llvmObjToString(e.call) << std::endl; - LOG << "\t\t\targ stores:" << std::endl; - for (auto* s : e.possibleArgStores) - { - LOG << "\t\t\t>|" << llvmObjToString(s) << std::endl; - } - LOG << "\t\t\tret loads:" << std::endl; - for (auto* l : e.possibleRetLoads) - { - LOG << "\t\t\t>|" << llvmObjToString(l) << std::endl; - } - if (!e.formatStr.empty()) - { - LOG << "\t\t\t>|format str: " << e.formatStr << std::endl; - } + dumpInfo(e); } LOG << "\t>|arg loads:" << std::endl; - for (auto* l : argLoads) + for (auto* l : de.args()) { LOG << "\t\t\t>|" << llvmObjToString(l) << std::endl; } LOG << "\t>|return stores:" << std::endl; - for (auto& e : retStores) + for (auto& e : de.retEntries()) { - LOG << "\t\t>|" << llvmObjToString(e.ret) << std::endl; - for (auto* s : e.possibleRetStores) - { - LOG << "\t\t\t>|" << llvmObjToString(s) << std::endl; - } + dumpInfo(e); } } -void DataFlowEntry::addArgLoads() +void ParamReturn::dumpInfo(const CallEntry& ce) const { - auto* f = getFunction(); - if (f == nullptr) + LOG << "\t\t>|" << llvmObjToString(ce.getCallInstruction()) + << std::endl; + LOG << "\t\t\tvoidarg :" << ce.isVoidarg() << std::endl; + LOG << "\t\t\targ values:" << std::endl; + for (auto* s : ce.args()) { - return; + LOG << "\t\t\t>|" << llvmObjToString(s) << std::endl; } - - std::set added; - for (auto it = inst_begin(f), end = inst_end(f); it != end; ++it) + LOG << "\t\t\targ stores:" << std::endl; + for (auto* s : ce.argStores()) { - if (auto* l = dyn_cast(&*it)) - { - auto* ptr = l->getPointerOperand(); - if (!_config->isStackVariable(ptr) && !_abi->isRegister(ptr)) - { - continue; - } - if (_abi->isFlagRegister(ptr)) - { - continue; - } - - auto* use = _RDA.getUse(l); - if (use == nullptr) - { - continue; - } - - if ((use->defs.empty() || use->isUndef()) - && added.find(ptr) == added.end()) - { - argLoads.push_back(l); - added.insert(ptr); - } - } + LOG << "\t\t\t>|" << llvmObjToString(s) << std::endl; + } + LOG << "\t\t\tret values:" << std::endl; + for (auto* l : ce.retValues()) + { + LOG << "\t\t\t>|" << llvmObjToString(l) << std::endl; + } + LOG << "\t\t\tret loads:" << std::endl; + for (auto* l : ce.retLoads()) + { + LOG << "\t\t\t>|" << llvmObjToString(l) << std::endl; + } + LOG << "\t\t\targ types:" << std::endl; + for (auto* t : ce.getBaseFunction()->argTypes()) + { + LOG << "\t\t\t>|" << llvmObjToString(t); + LOG << " (size : " << _abi->getTypeByteSize(t) << "B)" << std::endl; + } + for (auto* t : ce.argTypes()) + { + LOG << "\t\t\t>|" << llvmObjToString(t); + LOG << " (size : " << _abi->getTypeByteSize(t) << "B)" << std::endl; } + LOG << "\t\t\tformat string: " << ce.getFormatString() << std::endl; } -void DataFlowEntry::addRetStores() +void ParamReturn::dumpInfo(const ReturnEntry& re) const { - auto* f = getFunction(); - if (f == nullptr) + LOG << "\t\t>|" << llvmObjToString(re.getRetInstruction()) + << std::endl; + + LOG << "\t\t\tret stores:" << std::endl; + for (auto* s : re.retStores()) { - return; + LOG << "\t\t\t>|" << llvmObjToString(s) << std::endl; } - for (auto it = inst_begin(f), end = inst_end(f); it != end; ++it) + LOG << "\t\t\tret values:" << std::endl; + for (auto* s : re.retValues()) { - if (auto* r = dyn_cast(&*it)) - { - ReturnEntry re(r); - - NonIterableSet seenBbs; - NonIterableSet disqualifiedValues; - auto* b = r->getParent(); - seenBbs.insert(b); - Instruction* prev = r; - while (true) - { - if (prev == &b->front()) - { - auto* spb = b->getSinglePredecessor(); - if (spb && !spb->empty() && seenBbs.hasNot(spb)) - { - b = spb; - prev = &b->back(); - seenBbs.insert(b); - } - else - { - break; - } - } - else - { - prev = prev->getPrevNode(); - } - if (prev == nullptr) - { - break; - } - - if (isa(prev) || isa(prev)) - { - break; - } - else if (auto* store = dyn_cast(prev)) - { - auto* ptr = store->getPointerOperand(); - - if (disqualifiedValues.hasNot(ptr) - && !_abi->isFlagRegister(ptr) - && (_config->isStackVariable(ptr) || _abi->isRegister(ptr))) - { - re.possibleRetStores.push_back(store); - disqualifiedValues.insert(ptr); - } - } - else if (auto* load = dyn_cast(prev)) - { - auto* ptr = load->getPointerOperand(); - disqualifiedValues.insert(ptr); - } - } - - retStores.push_back(re); - } + LOG << "\t\t\t>|" << llvmObjToString(s) << std::endl; } } -void DataFlowEntry::addCall(llvm::CallInst* call) +void ParamReturn::filterCalls() { - // Pattern: - // bc pc // call prantf() - // align 4 - // prantf(): - // ... - // Call has no args because it is stub, if we let it, it will destroy - // all arg from all other calls. - // - // TODO: - // => ignore - this is an ugly hack, solve somehow better. - // - if (_config->getConfig().architecture.isArmOrThumb()) + std::map filters; + + for (auto& p : _fnc2calls) { - if (auto ai = AsmInstruction(call)) + DataFlowEntry& de = p.second; + auto cc = de.getCallingConvention(); + if (filters.find(cc) == filters.end()) { - auto* cs = ai.getCapstoneInsn(); - if ((cs->id == ARM_INS_B || cs->id == ARM_INS_BX) - && cs->detail->arm.op_count == 1 - && cs->detail->arm.operands[0].type == ARM_OP_REG - && cs->detail->arm.operands[0].reg == ARM_REG_PC) - { - return; - } + filters[cc] = FilterProvider::createFilter(_abi, cc); } - } - - CallEntry ce(call); - - addCallArgs(call, ce); - addCallReturns(call, ce); - calls.push_back(ce); -} - -void DataFlowEntry::addCallArgs(llvm::CallInst* call, CallEntry& ce) -{ - NonIterableSet disqualifiedValues; - unsigned maxUsedRegNum = 0; - auto* b = call->getParent(); - Instruction* prev = call; - std::set seen; - seen.insert(b); - while (true) - { - if (prev == &b->front()) + if (de.hasDefinition()) { - auto* spb = b->getSinglePredecessor(); - if (spb && !spb->empty() && spb != b && seen.count(spb) == 0) - { - b = spb; - prev = &b->back(); - seen.insert(b); - } - else - { - break; - } + filters[cc]->filterDefinition(&de); } - else + + if (de.isVariadic()) { - prev = prev->getPrevNode(); + filters[cc]->filterCallsVariadic(&de, _collector.get()); } - if (prev == nullptr) + else { - break; + filters[cc]->filterCalls(&de); } - if (auto* call = dyn_cast(prev)) + filters[cc]->estimateRetValue(&de); + + modifyType(de); + } +} + +Type* ParamReturn::extractType(Value* from) const +{ + from = llvm_utils::skipCasts(from); + + if (from == nullptr) + { + return _abi->getDefaultType(); + } + + if (auto* p = dyn_cast(from->getType())) + { + return p->getElementType(); + } + + if (auto* p = dyn_cast(from->getType())) + { + if (auto* a = dyn_cast(p->getElementType())) { - auto* calledFnc = call->getCalledFunction(); - if (calledFnc == nullptr || !calledFnc->isIntrinsic()) - { - break; - } + return PointerType::get(a->getElementType(), 0); } - else if (auto* store = dyn_cast(prev)) - { - auto* val = store->getValueOperand(); - auto* ptr = store->getPointerOperand(); + } - if (!_config->isStackVariable(ptr) && !_abi->isRegister(ptr)) - { - disqualifiedValues.insert(ptr); - } + return from->getType(); +} + +void ParamReturn::modifyType(DataFlowEntry& de) const +{ + // TODO + // Based on large type we should do: + // + // If large type is encountered + // and if cc passes large type by reference + // just cast the reference + // + // else separate as much values as possible + // and call function that will create new structure + // and put this values in the elements of + // the structure set this structure as parameter - if (auto* l = dyn_cast(val)) + if (de.argTypes().empty()) + { + for (auto& call : de.callEntries()) + { + std::vector types; + for (auto& arg : call.args()) { - if (l->getPointerOperand()->getName() == "ebp" - || l->getPointerOperand()->getName() == "rbp") - { - disqualifiedValues.insert(ptr); - } - if (_abi->isRegister(ptr) - && _abi->isRegister(l->getPointerOperand()) - && ptr != l->getPointerOperand()) + if (arg == nullptr) { - disqualifiedValues.insert(l->getPointerOperand()); + types.push_back(_abi->getDefaultType()); + continue; } - } - if (disqualifiedValues.hasNot(ptr) - && !_abi->isFlagRegister(ptr) - && (isa(ptr) || _abi->isRegister(ptr))) - { - ce.possibleArgStores.push_back(store); - disqualifiedValues.insert(ptr); - disqualifiedValues.insert(store); - - if (_abi->isGeneralPurposeRegister(ptr) - || (_config->getConfig().architecture.isMipsOrPic32() - && _abi->isRegister(ptr) - && ptr->getType()->isFloatingPointTy())) + auto usage = std::find_if( + call.argStores().begin(), + call.argStores().end(), + [arg](StoreInst* s) + { + return s->getPointerOperand() + == arg; + }); + + if (usage == call.argStores().end()) { - auto rn = _config->getConfigRegisterNumber(ptr); - if (rn.isDefined() && rn > maxUsedRegNum) + + if (auto* p = dyn_cast(arg->getType())) + { + types.push_back(p->getElementType()); + } + else { - maxUsedRegNum = rn; + types.push_back(arg->getType()); } } + else + { + types.push_back(extractType((*usage)->getValueOperand())); + } } + + de.setArgTypes(std::move(types)); + break; } } -} -void DataFlowEntry::addCallReturns(llvm::CallInst* call, CallEntry& ce) -{ - NonIterableSet disqualifiedValues; - auto* b = call->getParent(); - Instruction* next = call; - std::set seen; - seen.insert(b); - while (true) + if (de.argTypes().empty()) { - if (next == &b->back()) + std::vector types; + std::vector args; + + for (auto i : de.args()) { - auto* ssb = b->getSingleSuccessor(); - if (ssb && !ssb->empty() && ssb != b && seen.count(ssb) == 0) + if (i == nullptr) { - b = ssb; - next = &b->front(); - seen.insert(b); + types.push_back(_abi->getDefaultType()); } - else + else if (auto* p = dyn_cast(i->getType())) { - break; + types.push_back(p->getElementType()); } - } - else - { - next = next->getNextNode(); - } - if (next == nullptr) - { - break; - } - - if (auto* call = dyn_cast(next)) - { - auto* calledFnc = call->getCalledFunction(); - if (calledFnc == nullptr || !calledFnc->isIntrinsic()) + else { - break; + types.push_back(i->getType()); } } - else if (auto* store = dyn_cast(next)) - { - auto* ptr = store->getPointerOperand(); - disqualifiedValues.insert(ptr); - } - else if (auto* load = dyn_cast(next)) - { - auto* ptr = load->getPointerOperand(); - if (disqualifiedValues.hasNot(ptr) - && !_abi->isFlagRegister(ptr) - && (_config->isStackVariable(ptr) || _abi->isRegister(ptr))) - { - ce.possibleRetLoads.push_back(load); - disqualifiedValues.insert(ptr); - } - } + de.setArgTypes(std::move(types)); } + + auto args = de.args(); + args.erase( + std::remove_if( + args.begin(), + args.end(), + [](Value* v){return v == nullptr;}), + args.end()); + de.setArgs(std::move(args)); } -void DataFlowEntry::filter() +void ParamReturn::applyToIr() { - if (!isVarArg) + for (auto& p : _fnc2calls) + { + applyToIr(p.second); + } + + for (auto& p : _fnc2calls) { - callsFilterCommonRegisters(); + + connectWrappers(p.second); } +} - filterRegistersArgLoads(); - filterSortArgLoads(); +void ParamReturn::applyToIr(DataFlowEntry& de) +{ + Function* fnc = de.getFunction(); - for (CallEntry& e : calls) + if (fnc == nullptr) { - e.filterRegisters(_abi, _config); - e.filterSort(_config); - e.filterLeaveOnlyContinuousStackOffsets(_config); - e.filterLeaveOnlyNeededStackOffsets(_abi, _config); + auto loadsOfCalls = fetchLoadsOfCalls(de.callEntries()); - if (isVarArg) + for (auto l : loadsOfCalls) { - e.extractFormatString(_RDA); + IrModifier::modifyCallInst(l.first, de.getRetType(), l.second); } + + return; } - if (!isVarArg) + if (fnc->arg_size() > 0) { - callsFilterSameNumberOfStacks(); + return; } - if (typeSet) - { - for (CallEntry& e : calls) - { - auto tIt = argTypes.begin(); - auto sIt = e.possibleArgStores.begin(); + auto loadsOfCalls = fetchLoadsOfCalls(de.callEntries()); - while (tIt != argTypes.end() && sIt != e.possibleArgStores.end()) - { - Type* t = *tIt; - auto nextIt = sIt; - ++nextIt; - if (t->isDoubleTy() - && nextIt != e.possibleArgStores.end() - && _abi->isRegister((*nextIt)->getPointerOperand())) - { - e.possibleArgStores.erase(nextIt); - } + std::map rets2vals; - ++tIt; - ++sIt; - } - } - } - else - { - if (_config->getConfig().architecture.isArmOrThumb()) - { - static std::vector armNames = - {"r0", "r1", "r2", "r3"}; - - for (CallEntry& e : calls) - { - std::size_t idx = 0; - auto sIt = e.possibleArgStores.begin(); - while (sIt != e.possibleArgStores.end() && idx < armNames.size()) - { - StoreInst* s = *sIt; - if (s->getPointerOperand()->getName() != armNames[idx]) - { - e.possibleArgStores.erase(sIt, e.possibleArgStores.end()); - break; - } - - ++sIt; - ++idx; - } - } - } - } - - setTypeFromUseContext(); -} - -void DataFlowEntry::callsFilterCommonRegisters() -{ - if (calls.empty()) - { - return; - } - - std::set commonRegs; - - for (auto* s : calls.front().possibleArgStores) - { - Value* r = s->getPointerOperand(); - if (_abi->isRegister(r)) - { - commonRegs.insert(r); - } - } - - for (auto& e : calls) - { - // TODO: sometimes, we do not find all arg stores. - // this is a hack, we should manufacture loads even if we do not have - // stores but know there are some arguments (debug, ...). - if (e.possibleArgStores.empty()) - { - continue; - } - - std::set regs; - for (auto* s : e.possibleArgStores) - { - Value* r = s->getPointerOperand(); - if (_abi->isRegister(r)) - { - regs.insert(r); - } - } - - std::set intersect; - std::set_intersection( - commonRegs.begin(), - commonRegs.end(), - regs.begin(), - regs.end(), - std::inserter(intersect, intersect.begin())); - commonRegs = std::move(intersect); - } - - // If common contains r3, then it should also contain r2, r1, and r0. - // Example for MIPS: if contains a2, it should a1 and a0. - // - static std::vector regNames; - if (regNames.empty()) - { - if (_config->getConfig().architecture.isMipsOrPic32()) - { - if (_config->getConfig().tools.isPspGcc()) - { - regNames = {"a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3"}; - } - else - { - regNames = {"a0", "a1", "a2", "a3"}; - } - } - else if (_config->getConfig().architecture.isArmOrThumb()) - { - regNames = {"r0", "r1", "r2", "r3"}; - } - else if (_config->getConfig().architecture.isPpc()) - { - regNames = {"r3", "r4", "r5", "r6", "r7", "r8", "r9"}; - } - } - for (auto it = regNames.rbegin(); it != regNames.rend(); ++it) - { - auto* r = _config->getLlvmRegister(*it); - if (commonRegs.count(r)) - { - ++it; - while (it != regNames.rend()) - { - r = _config->getLlvmRegister(*it); - commonRegs.insert(r); - ++it; - } - break; - } - } - - for (auto& e : calls) - { - auto it = e.possibleArgStores.begin(); - for ( ; it != e.possibleArgStores.end(); ) - { - Value* r = (*it)->getPointerOperand(); - if (_abi->isRegister(r) - && commonRegs.find(r) == commonRegs.end()) - { - it = e.possibleArgStores.erase(it); - } - else - { - ++it; - } - } - } -} - -void DataFlowEntry::callsFilterSameNumberOfStacks() -{ - if (calls.empty()) - { - return; - } - - std::size_t loads = 0; - for (auto* l : argLoads) - { - if (_config->isStackVariable(l->getPointerOperand())) - { - ++loads; - } - } - - std::size_t stacks = std::numeric_limits::max(); - for (auto& ce : calls) - { - std::size_t ss = 0; - for (auto* s : ce.possibleArgStores) - { - if (_config->isStackVariable(s->getPointerOperand())) - { - ++ss; - } - } - - // TODO: all but one have 2 params, receiving have 2 params, one has zero. - // - if (ss < stacks && ss != 0 && ss >= loads) - { - stacks = ss; - } - } - if (typeSet && stacks < argTypes.size()) - { - stacks = argTypes.size(); - } - - for (auto& ce : calls) - { - std::size_t cntr = 0; - auto it = ce.possibleArgStores.begin(); - while (it != ce.possibleArgStores.end()) - { - auto* s = *it; - if (!_config->isStackVariable(s->getPointerOperand())) - { - ++it; - continue; - } - - ++cntr; - if (cntr > stacks) - { - it = ce.possibleArgStores.erase(it); - } - else - { - ++it; - } - } - } -} - -void DataFlowEntry::applyToIr() -{ - if (isVarArg) - { - applyToIrVariadic(); - } - else - { - applyToIrOrdinary(); - } -} - -void DataFlowEntry::applyToIrOrdinary() -{ - if (Function* fnc = getFunction()) - { - if (fnc->arg_size() > 0) - { - return; - } - - std::map> calls2vals; - for (auto& e : calls) - { - std::vector loads; - auto* call = e.call; - for (auto* s : e.possibleArgStores) - { - auto fIt = specialArgStorage.find(loads.size()); - while (fIt != specialArgStorage.end()) - { - auto* sl = new LoadInst(fIt->second, "", call); - loads.push_back(sl); - fIt = specialArgStorage.find(loads.size()); - } - - auto* l = new LoadInst(s->getPointerOperand(), "", call); - loads.push_back(l); - } - - calls2vals[call] = loads; - } - - llvm::Value* retVal = nullptr; - std::map rets2vals; - if (_config->getConfig().architecture.isX86()) - { - if (retType->isFloatingPointTy()) - { - retVal = _config->getLlvmRegister("st7"); - } - else if (_config->getConfig().architecture.isX86_32()) - { - retVal = _config->getLlvmRegister("eax"); - } - else if (_config->getConfig().architecture.isX86_64()) - { - retVal = _config->getLlvmRegister("rax"); - } - } - else if (_config->getConfig().architecture.isMipsOrPic32()) - { - retVal = _config->getLlvmRegister("v0"); - } - else if (_config->getConfig().architecture.isArmOrThumb()) - { - retVal = _config->getLlvmRegister("r0"); - } - else if (_config->getConfig().architecture.isPpc()) - { - retVal = _config->getLlvmRegister("r3"); - } - if (retVal) - { - for (auto& e : retStores) - { - auto* l = new LoadInst(retVal, "", e.ret); - rets2vals[e.ret] = l; - } - } - - std::vector argStores; - for (LoadInst* l : argLoads) - { - auto fIt = specialArgStorage.find(argStores.size()); - while (fIt != specialArgStorage.end()) - { - argStores.push_back(fIt->second); - fIt = specialArgStorage.find(argStores.size()); - } - - argStores.push_back(l->getPointerOperand()); - } - - static std::vector ppcNames = - {"r3", "r4", "r5", "r6", "r7", "r8", "r9"}; - static std::vector armNames = - {"r0", "r1", "r2", "r3"}; - static std::vector mipsNames = - {"a0", "a1", "a2", "a3"}; - if (_config->getConfig().tools.isPspGcc()) - { - mipsNames = {"a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3"}; - } - for (auto& p : calls2vals) - { - retdec::utils::Maybe stackOff; - if (_config->getConfig().architecture.isX86()) - { - if (!p.second.empty()) - { - auto* l = cast(p.second.back()); - if (_config->isStackVariable(l->getPointerOperand())) - { - stackOff = _config->getStackVariableOffset(l->getPointerOperand()); - stackOff = stackOff + 4; - } - } - - if (stackOff.isUndefined()) - { - AsmInstruction ai(p.first); - while (ai.isValid()) - { - for (auto& i : ai) - { - if (auto* s = dyn_cast(&i)) - { - if (_config->isStackVariable(s->getPointerOperand())) - { - stackOff = _config->getStackVariableOffset(s->getPointerOperand()); - break; - } - } - } - if (stackOff.isDefined()) - { - break; - } - ai = ai.getPrev(); - } - } - } - - std::size_t idx = 0; - for (auto* t : argTypes) - { - (void) t; - if (p.second.size() <= idx) - { - if (_config->getConfig().architecture.isArmOrThumb()) - { - if (idx < armNames.size()) - { - auto* r = _config->getLlvmRegister(armNames[idx]); - auto* l = new LoadInst(r, "", p.first); - p.second.push_back(l); - } - } - else if (_config->getConfig().architecture.isMipsOrPic32()) - { - if (idx < mipsNames.size()) - { - auto* r = _config->getLlvmRegister(mipsNames[idx]); - auto* l = new LoadInst(r, "", p.first); - p.second.push_back(l); - } - } - else if (_config->getConfig().architecture.isPpc()) - { - if (idx < ppcNames.size()) - { - auto* r = _config->getLlvmRegister(ppcNames[idx]); - auto* l = new LoadInst(r, "", p.first); - p.second.push_back(l); - } - } - else if (_config->getConfig().architecture.isX86() - && stackOff.isDefined()) - { - auto* s = _config->getLlvmStackVariable(p.first->getFunction(), stackOff); - if (s) - { - auto* l = new LoadInst(s, "", p.first); - p.second.push_back(l); - stackOff = stackOff + 4; - } - else - { - stackOff.setUndefined(); - } - } - } - ++idx; - } - } - - auto* oldType = fnc->getType(); - IrModifier irm(_module, _config); - auto* newFnc = irm.modifyFunction( - fnc, - retType, - argTypes, - isVarArg, - rets2vals, - calls2vals, - retVal, - argStores, - argNames).first; - - LOG << "modify fnc: " << newFnc->getName().str() << " = " - << llvmObjToString(oldType) << " -> " - << llvmObjToString(newFnc->getType()) << std::endl; - - called = newFnc; - } - else - { - for (auto& e : calls) - { - auto* call = e.call; - LOG << "\tmodify call: " << llvmObjToString(call) << std::endl; - - std::vector loads; - for (auto* s : e.possibleArgStores) - { - auto* l = new LoadInst(s->getPointerOperand(), "", call); - loads.push_back(l); - LOG << "\t\t" << llvmObjToString(l) << std::endl; - } - - auto* ret = fnc ? fnc->getReturnType() : call->getType(); - IrModifier::modifyCallInst(call, ret, loads); - } - } -} - -void DataFlowEntry::applyToIrVariadic() -{ - std::vector ppcNames = - {"r3", "r4", "r5", "r6", "r7", "r8", "r9"}; - std::vector armNames = - {"r0", "r1", "r2", "r3"}; - std::vector mipsNames = - {"a0", "a1", "a2", "a3"}; - if (_config->getConfig().tools.isPspGcc()) - { - mipsNames = {"a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3"}; - } - - std::vector mipsFpNames = - {"fd12", "fd13", "fd14", "fd15", "fd16", "fd17", "fd18", "fd19", "fd20"}; - - llvm::Value* retVal = nullptr; - std::map rets2vals; - std::vector argStores; - std::map> calls2vals; - - for (CallEntry& ce : calls) - { - auto* fnc = ce.call->getFunction(); - auto* calledFnc = ce.call->getCalledFunction(); - - LOG << llvmObjToString(ce.call) << std::endl; - LOG << "\tformat : " << ce.formatStr << std::endl; - - // get lowest stack offset - // - int stackOff = std::numeric_limits::max(); - for (StoreInst* s : ce.possibleArgStores) - { - if (_config->isStackVariable(s->getPointerOperand())) - { - auto so = _config->getStackVariableOffset(s->getPointerOperand()); - if (so < stackOff) - { - stackOff = so; - } - } - } - LOG << "\tlowest : " << std::dec << stackOff << std::endl; - - // - // - auto* wrapCall = isSimpleWrapper(calledFnc); - auto* wrapFnc = wrapCall ? wrapCall->getCalledFunction() : calledFnc; - std::vector ttypes = llvm_utils::parseFormatString( - _module, - ce.formatStr, - wrapFnc); - - if (_config->getConfig().architecture.isPic32()) - { - for (size_t i = 0; i < ttypes.size(); ++i) - { - if (ttypes[i]->isDoubleTy()) - { - ttypes[i] = Type::getFloatTy(_module->getContext()); - } - } - } - - // - // - int off = stackOff; - std::vector args; - - size_t faIdx = 0; - size_t aIdx = 0; - - std::vector types = argTypes; - types.insert(types.end(), ttypes.begin(), ttypes.end()); - - for (Type* t : types) - { - LOG << "\ttype : " << llvmObjToString(t) << std::endl; - int sz = static_cast(_abi->getTypeByteSize(t)); - sz = sz > 4 ? 8 : 4; - - if (_config->getConfig().architecture.isX86()) - { - auto* st = _config->getLlvmStackVariable(fnc, off); - if (st) - { - args.push_back(st); - } - - off += sz; - } - else if (_config->getConfig().architecture.isPpc()) - { - if (aIdx < ppcNames.size()) - { - auto* r = _module->getNamedGlobal(ppcNames[aIdx]); - if (r) - { - args.push_back(r); - } - } - else - { - auto* st = _config->getLlvmStackVariable(fnc, off); - if (st) - { - args.push_back(st); - } - - off += sz; - } - } - else if (_config->getConfig().architecture.isArmOrThumb()) - { - if (aIdx < armNames.size()) - { - auto* r = _module->getNamedGlobal(armNames[aIdx]); - if (r) - { - args.push_back(r); - } - - if (sz > 4) - { - ++aIdx; - } - } - else - { - auto* st = _config->getLlvmStackVariable(fnc, off); - if (st) - { - args.push_back(st); - } - - off += sz; - } - } - else if (_config->getConfig().architecture.isPic32()) - { - if (aIdx < mipsNames.size()) - { - auto* r = _module->getNamedGlobal(mipsNames[aIdx]); - if (r) - { - args.push_back(r); - } - } - else - { - auto* st = _config->getLlvmStackVariable(fnc, off); - if (st) - { - args.push_back(st); - } - - off += sz; - } - } - else if (_config->getConfig().architecture.isMips()) - { - bool useStack = false; - if (t->isFloatingPointTy()) - { - --aIdx; - - if (faIdx < mipsFpNames.size()) - { - auto* r = _module->getNamedGlobal(mipsFpNames[faIdx]); - if (r) - { - args.push_back(r); - } - - if (sz > 4) - { - ++faIdx; - } - } - else - { - useStack = true; - } - - ++faIdx; - } - else - { - if (aIdx < mipsNames.size()) - { - auto* r = _module->getNamedGlobal(mipsNames[aIdx]); - if (r) - { - args.push_back(r); - } - } - else - { - useStack = true; - } - } - - if (useStack) - { - auto* st = _config->getLlvmStackVariable(fnc, off); - if (st) - { - args.push_back(st); - } - - off += sz; - } - } - - ++aIdx; - } - - // - // - unsigned idx = 0; - std::vector loads; - for (auto* a : args) - { - Value* l = new LoadInst(a, "", ce.call); - LOG << "\t\t" << llvmObjToString(l) << std::endl; - - if (types.size() > idx) - { - l = IrModifier::convertValueToType(l, types[idx], ce.call); - } - - loads.push_back(l); - ++idx; - } - - if (!loads.empty()) - { - calls2vals[ce.call] = loads; - } - } - - if (_config->getConfig().architecture.isX86()) - { - if (retType->isFloatingPointTy()) - { - retVal = _config->getLlvmRegister("st7"); - } - else if (_config->getConfig().architecture.isX86_32()) + if (de.getRetValue()) + { + if (de.getRetType() == nullptr) { - retVal = _config->getLlvmRegister("eax"); + if (auto* p = dyn_cast(de.getRetValue()->getType())) + { + de.setRetType(p->getElementType()); + } + else + { + de.setRetType(de.getRetValue()->getType()); + } } - else if (_config->getConfig().architecture.isX86_64()) + + for (auto& e : de.retEntries()) { - retVal = _config->getLlvmRegister("rax"); + auto* l = new LoadInst(de.getRetValue(), "", e.getRetInstruction()); + rets2vals[e.getRetInstruction()] = l; } } - else if (_config->getConfig().architecture.isMipsOrPic32()) - { - retVal = _config->getLlvmRegister("v0"); - } - else if (_config->getConfig().architecture.isArmOrThumb()) - { - retVal = _config->getLlvmRegister("r0"); - } - else if (_config->getConfig().architecture.isPpc()) + else { - retVal = _config->getLlvmRegister("r3"); + de.setRetType(Type::getVoidTy(_module->getContext())); } - if (retVal) + + std::vector definitionArgs; + for (auto& a : de.args()) { - for (auto& e : retStores) + if (a != nullptr) { - auto* l = new LoadInst(retVal, "", e.ret); - rets2vals[e.ret] = l; + definitionArgs.push_back(a); } } - auto* fnc = getFunction(); - auto* oldType = fnc->getType(); - IrModifier irm(_module, _config); auto* newFnc = irm.modifyFunction( fnc, - retType, - argTypes, - isVarArg, + de.getRetType(), + de.argTypes(), + de.isVariadic(), rets2vals, - calls2vals, - retVal, - argStores, - argNames).first; + loadsOfCalls, + de.getRetValue(), + definitionArgs, + de.argNames()).first; - LOG << "modify fnc: " << newFnc->getName().str() << " = " - << llvmObjToString(oldType) << " -> " - << llvmObjToString(newFnc->getType()) << std::endl; - - called = newFnc; + de.setCalledValue(newFnc); } -void DataFlowEntry::connectWrappers() +void ParamReturn::connectWrappers(const DataFlowEntry& de) { - auto* fnc = getFunction(); + auto* fnc = de.getFunction(); + auto* wrappedCall = de.getWrappedCall(); if (fnc == nullptr || wrappedCall == nullptr) { return; @@ -1878,359 +923,54 @@ void DataFlowEntry::connectWrappers() } } -llvm::CallInst* DataFlowEntry::isSimpleWrapper(llvm::Function* fnc) +std::map> ParamReturn::fetchLoadsOfCalls( + const std::vector& calls) const { - auto ai = AsmInstruction(fnc); - if (ai.isInvalid()) - { - return nullptr; - } + std::map> loadsOfCalls; - bool single = true; - auto next = ai.getNext(); - while (next.isValid()) + for (auto& e : calls) { - if (!next.empty() && !isa(next.front())) - { - single = false; - break; - } - next = next.getNext(); - } + std::vector loads; + auto* call = e.getCallInstruction(); - // Pattern - // .text:00008A38 LDR R0, =aCCc ; "C::cc()" - // .text:00008A3C B puts - // .text:00008A40 off_8A40 DCD aCCc - // TODO: make better wrapper detection. In wrapper, wrapped function params - // should not be set like in this example. - // - if (ai && next) - { - if (_image->getConstantDefault(next.getEndAddress())) - { - auto* l = ai.getInstructionFirst(); - auto* s = ai.getInstructionFirst(); - auto* c = next.getInstructionFirst(); - if (l && s && c && isa(l->getPointerOperand()) - && s->getPointerOperand()->getName() == "r0") - { - auto gvA = _config->getGlobalAddress(cast(l->getPointerOperand())); - if (gvA == next.getEndAddress()) - { - return nullptr; - } - } - } - } + auto types = e.getBaseFunction()->argTypes(); + types.insert( + types.end(), + e.argTypes().begin(), + e.argTypes().end()); - if (single) - { - for (auto& i : ai) - { - if (auto* c = dyn_cast(&i)) - { - auto* cf = c->getCalledFunction(); - if (cf && !cf->isIntrinsic()) // && cf->isDeclaration()) - { - return c; - } - } - } - } + auto tIt = types.begin(); + auto aIt = e.args().begin(); - unsigned aiNum = 0; - bool isSmall = true; - next = ai; - while (next.isValid()) - { - ++aiNum; - next = next.getNext(); - if (aiNum > 4) - { - isSmall = false; - break; - } - } - auto* s = _image->getImage()->getSegmentFromAddress(ai.getAddress()); - if ((s && s->getName() == ".plt") || isSmall) - { - for (inst_iterator it = inst_begin(fnc), rIt = inst_end(fnc); - it != rIt; ++it) + while (aIt != e.args().end()) { - if (auto* l = dyn_cast(&*it)) - { - std::string n = l->getPointerOperand()->getName(); - if (n == "lr" || n == "sp") - { - return nullptr; - } - } - else if (auto* s = dyn_cast(&*it)) - { - std::string n = s->getPointerOperand()->getName(); - if (n == "lr" || n == "sp") - { - return nullptr; - } - } - else if (auto* c = dyn_cast(&*it)) + if (*aIt == nullptr) { - auto* cf = c->getCalledFunction(); - if (cf && !cf->isIntrinsic() && cf->isDeclaration()) - { - return c; - } + aIt++; + continue; } - } - } - - return nullptr; -} - -void DataFlowEntry::setTypeFromExtraInfo() -{ - auto* fnc = getFunction(); - if (fnc == nullptr) - { - return; - } - // Main - // - if (fnc->getName() == "main") - { - argTypes.push_back(Type::getInt32Ty(_module->getContext())); - argTypes.push_back(PointerType::get( - PointerType::get( - Type::getInt8Ty(_module->getContext()), - 0), - 0)); - argNames.push_back("argc"); - argNames.push_back("argv"); - retType = Type::getInt32Ty(_module->getContext()); - typeSet = true; - return; - } + Value* l = new LoadInst(*aIt, "", call); - // LTI info. - // - auto* cf = _config->getConfigFunction(fnc); - if (cf && (cf->isDynamicallyLinked() || cf->isStaticallyLinked())) - { - auto fp = _lti->getPairFunctionFree(cf->getName()); - if (fp.first) - { - for (auto& a : fp.first->args()) - { - argTypes.push_back(a.getType()); - argNames.push_back(a.getName()); - } - if (fp.first->isVarArg()) + if (tIt != types.end()) { - isVarArg = true; + l = IrModifier::convertValueToType(l, *tIt, call); + tIt++; } - retType = fp.first->getReturnType(); - typeSet = true; - - std::string declr = fp.second->getDeclaration(); - if (!declr.empty()) + else { - cf->setDeclarationString(declr); + l = IrModifier::convertValueToType(l, _abi->getDefaultType(), call); } - // TODO: we could rename function if LTI name differs. - // e.g. scanf vs _scanf. - // -// if (fp.first->getName() != fnc->getName()) -// { -// IrModifier irmodif(_module, _config); -// irmodif.renameFunction(fnc, fp.first->getName()); -// } - - return; - } - } - - // Debug info. - // - if (dbgFnc) - { - for (auto& a : dbgFnc->parameters) - { - auto* t = llvm_utils::stringToLlvmTypeDefault(_module, a.type.getLlvmIr()); - argTypes.push_back(t); - argNames.push_back(a.getName()); - } - if (dbgFnc->isVariadic()) - { - isVarArg = true; - } - retType = llvm_utils::stringToLlvmTypeDefault( - _module, - dbgFnc->returnType.getLlvmIr()); - typeSet = true; - return; - } - - if (_config->getConfig().isIda() && configFnc) - { - for (auto& a : configFnc->parameters) - { - auto* t = llvm_utils::stringToLlvmTypeDefault(_module, a.type.getLlvmIr()); - argTypes.push_back(t); - argNames.push_back(a.getName()); - - if (_config->getConfig().architecture.isX86()) - { - std::string regName; - if (a.getStorage().isRegister(regName)) - { - if (auto* reg = _config->getLlvmRegister(regName)) - { - specialArgStorage[argTypes.size()-1] = reg; - } - } - } - } - if (configFnc->isVariadic()) - { - isVarArg = true; - } - retType = llvm_utils::stringToLlvmTypeDefault( - _module, - configFnc->returnType.getLlvmIr()); - if (!argTypes.empty()) - { - typeSet = true; + loads.push_back(l); + aIt++; } - return; - } - // Wrappers. - // - if ((wrappedCall = isSimpleWrapper(fnc))) - { - auto* wf = wrappedCall->getCalledFunction(); - auto* ltiFnc = _lti->getLlvmFunctionFree(wf->getName()); - if (ltiFnc) - { - for (auto& a : ltiFnc->args()) - { - argTypes.push_back(a.getType()); - argNames.push_back(a.getName()); - } - if (ltiFnc->isVarArg()) - { - isVarArg = true; - } - retType = ltiFnc->getReturnType(); - typeSet = true; - return; - } - else - { - wrappedCall = nullptr; - } + loadsOfCalls[call] = std::move(loads); } -} -void DataFlowEntry::setTypeFromUseContext() -{ - if (!typeSet) - { - setReturnType(); - setArgumentTypes(); - typeSet = true; - } + return loadsOfCalls; } -void DataFlowEntry::setReturnType() -{ - llvm::Value* retVal = nullptr; - if (_config->getConfig().architecture.isX86()) - { - bool hasEax = false; - bool hasRax = false; - bool hasSt0 = false; - for (auto& re : retStores) - { - for (StoreInst* s : re.possibleRetStores) - { - if (s->getPointerOperand()->getName() == "eax") - { - hasEax = true; - break; - } - else if (s->getPointerOperand()->getName() == "rax") - { - hasRax = true; - break; - } - else if (s->getPointerOperand()->getName() == "st7") - { - hasSt0 = true; - } - } - } - if (!hasEax && !hasRax && hasSt0) - { - retVal = _config->getLlvmRegister("st7"); - } - else if (_config->getLlvmRegister("rax")) - { - retVal = _config->getLlvmRegister("rax"); - } - else - { - retVal = _config->getLlvmRegister("eax"); - } - } - else if (_config->getConfig().architecture.isMipsOrPic32()) - { - retVal = _config->getLlvmRegister("v0"); - } - else if (_config->getConfig().architecture.isArmOrThumb()) - { - retVal = _config->getLlvmRegister("r0"); - } - else if (_config->getConfig().architecture.isPpc()) - { - retVal = _config->getLlvmRegister("r3"); - } - - retType = retVal ? - retVal->getType()->getPointerElementType() : - Type::getVoidTy(_module->getContext()); } - -void DataFlowEntry::setArgumentTypes() -{ - if (calls.empty()) - { - argTypes.insert( - argTypes.end(), - argLoads.size(), - Abi::getDefaultType(_module)); - } - else - { - CallEntry* ce = &calls.front(); - for (auto& c : calls) - { - if (!c.possibleArgStores.empty()) - { - ce = &c; - break; - } - } - - argTypes.insert( - argTypes.end(), - ce->possibleArgStores.size(), - Abi::getDefaultType(_module)); - } } - -} // namespace bin2llvmir -} // namespace retdec diff --git a/src/bin2llvmir/optimizations/x87_fpu/x87_fpu.cpp b/src/bin2llvmir/optimizations/x87_fpu/x87_fpu.cpp index e2bf3b066..daa936783 100644 --- a/src/bin2llvmir/optimizations/x87_fpu/x87_fpu.cpp +++ b/src/bin2llvmir/optimizations/x87_fpu/x87_fpu.cpp @@ -96,160 +96,148 @@ bool X87FpuAnalysis::analyzeBb( llvm::BasicBlock* bb, int topVal) { - LOG << "\t" << bb->getName().str() << std::endl; - bool changed = false; - if (seenBbs.has(bb)) - { - LOG << "\t\t" << "already seen" << std::endl; - return false; - } - seenBbs.insert(bb); + std::queue> queue; + queue.push({bb, topVal}); + bool changed = false; + while(!queue.empty()) { + auto pair = queue.front(); + auto currentBb = pair.first; + topVal = pair.second; + queue.pop(); + LOG << "\t" << currentBb->getName().str() << std::endl; + + if (seenBbs.has(currentBb)) { + LOG << "\t\t" << "already seen" << std::endl; + return false; + } + seenBbs.insert(currentBb); - auto it = bb->begin(); - while (it != bb->end()) - { - Instruction* i = &(*it); - ++it; + auto it = currentBb->begin(); + while (it != currentBb->end()) { + Instruction *i = &(*it); + ++it; - auto* l = dyn_cast(i); - auto* s = dyn_cast(i); - auto* add = dyn_cast(i); - auto* sub = dyn_cast(i); - auto* callStore = _config->isLlvmX87StorePseudoFunctionCall(i); - auto* callLoad = _config->isLlvmX87LoadPseudoFunctionCall(i); + auto *l = dyn_cast(i); + auto *s = dyn_cast(i); + auto *add = dyn_cast(i); + auto *sub = dyn_cast(i); + auto *callStore = _config->isLlvmX87StorePseudoFunctionCall(i); + auto *callLoad = _config->isLlvmX87LoadPseudoFunctionCall(i); - if (l && l->getPointerOperand() == top) - { - topVals[i] = topVal; + if (l && l->getPointerOperand() == top) { + topVals[i] = topVal; - LOG << "\t\t" << AsmInstruction(i).getAddress() + LOG << "\t\t" << AsmInstruction(i).getAddress() << " @ " << std::dec << topVal << std::endl; - } - else if (s - && s->getPointerOperand() == top - && topVals.find(s->getValueOperand()) != topVals.end()) - { - auto fIt = topVals.find(s->getValueOperand()); - topVal = fIt->second; + } else if (s + && s->getPointerOperand() == top + && topVals.find(s->getValueOperand()) != topVals.end()) { + auto fIt = topVals.find(s->getValueOperand()); + topVal = fIt->second; - LOG << "\t\t" << AsmInstruction(i).getAddress() + LOG << "\t\t" << AsmInstruction(i).getAddress() << " @ " << std::dec << fIt->second << std::endl; - } - else if (add - && topVals.find(add->getOperand(0)) != topVals.end() - && isa(add->getOperand(1))) - { - auto fIt = topVals.find(add->getOperand(0)); - auto* ci = cast(add->getOperand(1)); - // Constants are i3, so 7 can be represented as -1, we need to either - // use zext here (potentially dangerous if instructions were already - // modified and there are true negative values), or compute values - // in i3 arithmetics. - int tmp = fIt->second + ci->getZExtValue(); - if (tmp > 8) - { - LOG << "\t\t\t" << "overflow fix " << tmp << " -> " << 8 + } else if (add + && topVals.find(add->getOperand(0)) != topVals.end() + && isa(add->getOperand(1))) { + auto fIt = topVals.find(add->getOperand(0)); + auto *ci = cast(add->getOperand(1)); + // Constants are i3, so 7 can be represented as -1, we need to either + // use zext here (potentially dangerous if instructions were already + // modified and there are true negative values), or compute values + // in i3 arithmetics. + int tmp = fIt->second + ci->getZExtValue(); + if (tmp > 8) { + LOG << "\t\t\t" << "overflow fix " << tmp << " -> " << 8 << std::endl; - tmp = 8; - } - topVals[i] = tmp; + tmp = 8; + } + topVals[i] = tmp; - LOG << "\t\t" << AsmInstruction(i).getAddress() << std::dec + LOG << "\t\t" << AsmInstruction(i).getAddress() << std::dec << " @ " << fIt->second << " + " << ci->getZExtValue() << " = " << tmp << std::endl; - } - else if (sub - && topVals.find(sub->getOperand(0)) != topVals.end() - && isa(sub->getOperand(1))) - { - auto fIt = topVals.find(sub->getOperand(0)); - auto* ci = cast(sub->getOperand(1)); - // Constants are i3, so 7 can be represented as -1, we need to either - // use zext here (potentially dangerous if instructions were already - // modified and there are true negative values), or compute values - // in i3 arithmetics. - int tmp = fIt->second - ci->getZExtValue(); - if (tmp < 0) - { - LOG << "\t\t\t" << "undeflow fix " << tmp << " -> " << 7 + } else if (sub + && topVals.find(sub->getOperand(0)) != topVals.end() + && isa(sub->getOperand(1))) { + auto fIt = topVals.find(sub->getOperand(0)); + auto *ci = cast(sub->getOperand(1)); + // Constants are i3, so 7 can be represented as -1, we need to either + // use zext here (potentially dangerous if instructions were already + // modified and there are true negative values), or compute values + // in i3 arithmetics. + int tmp = fIt->second - ci->getZExtValue(); + if (tmp < 0) { + LOG << "\t\t\t" << "undeflow fix " << tmp << " -> " << 7 << std::endl; - tmp = 7; - } - topVals[i] = tmp; + tmp = 7; + } + topVals[i] = tmp; - LOG << "\t\t" << AsmInstruction(i).getAddress() << std::dec + LOG << "\t\t" << AsmInstruction(i).getAddress() << std::dec << " @ " << fIt->second << " - " << ci->getZExtValue() << " = " << tmp << std::endl; - } - else if (callStore - && topVals.find(callStore->getArgOperand(0)) != topVals.end()) - { - auto fIt = topVals.find(callStore->getArgOperand(0)); - int tmp = fIt->second; - - auto regBase = _config->isLlvmX87DataStorePseudoFunctionCall(callStore) - ? uint32_t(X86_REG_ST0) - : uint32_t(X87_REG_TAG0); - // Storing value to an empty stack -> suspicious. - if (tmp == 8) - { - tmp = 7; - topVal = 7; + } else if (callStore + && topVals.find(callStore->getArgOperand(0)) != topVals.end()) { + auto fIt = topVals.find(callStore->getArgOperand(0)); + auto tmp = fIt->second; + + auto regBase = _config->isLlvmX87DataStorePseudoFunctionCall(callStore) + ? uint32_t(X86_REG_ST0) + : uint32_t(X87_REG_TAG0); + // Storing value to an empty stack -> suspicious. + if (tmp == 8) { + tmp = 7; + topVal = 7; + } + int regNum = tmp % 8; + auto *reg = _abi->getRegister(regBase + regNum); + + LOG << "\t\t\t" << "store -- " << reg->getName().str() << std::endl; + + new StoreInst(callStore->getArgOperand(1), reg, callStore); + callStore->eraseFromParent(); + changed = true; + } else if (callLoad + && topVals.find(callLoad->getArgOperand(0)) != topVals.end()) { + auto fIt = topVals.find(callLoad->getArgOperand(0)); + auto tmp = fIt->second; + + auto regBase = _config->isLlvmX87DataLoadPseudoFunctionCall(callLoad) + ? uint32_t(X86_REG_ST0) + : uint32_t(X87_REG_TAG0); + // Loading value from an empty stack -> value may have been placed + // there without us knowing, e.g. return value of some other + // function. + if (tmp == 8) { + tmp = 7; + topVal = 7; + } + int regNum = tmp % 8; + auto *reg = _abi->getRegister(regBase + regNum); + + LOG << "\t\t\t" << "load -- " << reg->getName().str() << std::endl; + + auto *lTmp = new LoadInst(reg, "", callLoad); + auto *conv = IrModifier::convertValueToType(lTmp, callLoad->getType(), callLoad); + + callLoad->replaceAllUsesWith(conv); + callLoad->eraseFromParent(); + changed = true; + } else if (callStore || callLoad) { + LOG << "\t\t" << AsmInstruction(i).getAddress() << " @ " + << llvmObjToString(i) << std::endl; + assert(false && "some other pattern"); + return false; } - int regNum = tmp % 8; - auto* reg = _abi->getRegister(regBase + regNum); - - LOG << "\t\t\t" << "store -- " << reg->getName().str() << std::endl; - - new StoreInst(callStore->getArgOperand(1), reg, callStore); - callStore->eraseFromParent(); - changed = true; } - else if (callLoad - && topVals.find(callLoad->getArgOperand(0)) != topVals.end()) - { - auto fIt = topVals.find(callLoad->getArgOperand(0)); - int tmp = fIt->second; - - auto regBase = _config->isLlvmX87DataLoadPseudoFunctionCall(callLoad) - ? uint32_t(X86_REG_ST0) - : uint32_t(X87_REG_TAG0); - // Loading value from an empty stack -> value may have been placed - // there without us knowing, e.g. return value of some other - // function. - if (tmp == 8) - { - tmp = 7; - topVal = 7; - } - int regNum = tmp % 8; - auto* reg = _abi->getRegister(regBase + regNum); - - LOG << "\t\t\t" << "load -- " << reg->getName().str() << std::endl; - - auto* l = new LoadInst(reg, "", callLoad); - auto* conv = IrModifier::convertValueToType(l, callLoad->getType(), callLoad); - callLoad->replaceAllUsesWith(conv); - callLoad->eraseFromParent(); - changed = true; - } - else if (callStore || callLoad) - { - LOG << "\t\t" << AsmInstruction(i).getAddress() << " @ " - << llvmObjToString(i) << std::endl; - assert(false && "some other pattern"); - return false; + for (auto succIt = succ_begin(currentBb), e = succ_end(currentBb); succIt != e; ++succIt) { + auto *succ = *succIt; + queue.push({succ, topVal}); } } - - for (auto succIt = succ_begin(bb), e = succ_end(bb); succIt != e; ++succIt) - { - auto* succ = *succIt; - changed |= analyzeBb(seenBbs, topVals, succ, topVal); - } - return changed; } diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 2e665d8a1..360f589fa 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -8,8 +8,11 @@ #include "retdec/bin2llvmir/providers/abi/arm.h" #include "retdec/bin2llvmir/providers/abi/arm64.h" #include "retdec/bin2llvmir/providers/abi/mips.h" +#include "retdec/bin2llvmir/providers/abi/ms_x64.h" #include "retdec/bin2llvmir/providers/abi/powerpc.h" #include "retdec/bin2llvmir/providers/abi/x86.h" +#include "retdec/bin2llvmir/providers/abi/x64.h" +#include "retdec/bin2llvmir/providers/abi/pic32.h" using namespace llvm; @@ -37,12 +40,12 @@ Abi::~Abi() } -bool Abi::isRegister(const llvm::Value* val) +bool Abi::isRegister(const llvm::Value* val) const { return _regs2id.count(val); } -bool Abi::isRegister(const llvm::Value* val, uint32_t r) +bool Abi::isRegister(const llvm::Value* val, uint32_t r) const { return getRegister(r) == val; } @@ -53,7 +56,7 @@ bool Abi::isFlagRegister(const llvm::Value* val) && val->getType()->getPointerElementType()->isIntegerTy(1); } -bool Abi::isStackPointerRegister(const llvm::Value* val) +bool Abi::isStackPointerRegister(const llvm::Value* val) const { return getStackPointerRegister() == val; } @@ -71,7 +74,7 @@ bool Abi::isZeroRegister(const llvm::Value* val) * This solves the problem with overlapping IDs when used like this: * Abi::getRegister(MIPS_REG_GP, Abi::isMips()) */ -llvm::GlobalVariable* Abi::getRegister(uint32_t r, bool use) +llvm::GlobalVariable* Abi::getRegister(uint32_t r, bool use) const { if (!use) { @@ -81,7 +84,7 @@ llvm::GlobalVariable* Abi::getRegister(uint32_t r, bool use) return _id2regs[r]; } -uint32_t Abi::getRegisterId(const llvm::Value* r) +uint32_t Abi::getRegisterId(const llvm::Value* r) const { auto it = _regs2id.find(r); return it != _regs2id.end() ? it->second : Abi::REG_INVALID; @@ -92,16 +95,29 @@ const std::vector& Abi::getRegisters() const return _regs; } -llvm::GlobalVariable* Abi::getStackPointerRegister() +llvm::GlobalVariable* Abi::getStackPointerRegister() const { return getRegister(_regStackPointerId); } -llvm::GlobalVariable* Abi::getZeroRegister() +llvm::GlobalVariable* Abi::getZeroRegister() const { return getRegister(_regZeroReg); } +std::size_t Abi::getRegisterByteSize(uint32_t reg) const +{ + auto r = getRegister(reg); + assert(r); + + if (auto* p = dyn_cast(r->getType())) + { + return getTypeByteSize(p->getElementType()); + } + + return getTypeByteSize(r->getType()); +} + void Abi::addRegister(uint32_t id, llvm::GlobalVariable* reg) { if (id >= _id2regs.size()) @@ -128,6 +144,11 @@ llvm::GlobalVariable* Abi::getSyscallArgumentRegister(unsigned n) return n < _syscallRegs.size() ? getRegister(_syscallRegs[n]) : nullptr; } +bool Abi::isStackVariable(const Value* val) const +{ + return _config->isStackVariable(val); +} + bool Abi::isNopInstruction(AsmInstruction ai) { return isNopInstruction(ai.getCapstoneInsn()); @@ -153,15 +174,24 @@ llvm::PointerType* Abi::getDefaultPointerType() const return Abi::getDefaultPointerType(_module); } +std::size_t Abi::getWordSize() const +{ + return _config->getConfig().architecture.getBitSize() / 8; +} + std::size_t Abi::getTypeByteSize(llvm::Module* m, llvm::Type* t) { assert(m); + assert(t->isSized()); + return m->getDataLayout().getTypeStoreSize(t); } std::size_t Abi::getTypeBitSize(llvm::Module* m, llvm::Type* t) { assert(m); + assert(t->isSized()); + return m->getDataLayout().getTypeSizeInBits(t); } @@ -172,17 +202,33 @@ llvm::IntegerType* Abi::getDefaultType(llvm::Module* m) return Type::getIntNTy(m->getContext(), s); } +llvm::Type* Abi::getDefaultFPType(llvm::Module* m) +{ + assert(m); + return Type::getFloatTy(m->getContext()); +} + llvm::PointerType* Abi::getDefaultPointerType(llvm::Module* m) { assert(m); return PointerType::get(Abi::getDefaultType(m), 0); } +std::size_t Abi::getWordSize(llvm::Module* m) +{ + return m->getDataLayout().getPointerSize(0); +} + bool Abi::isMips() const { return _config->getConfig().architecture.isMipsOrPic32(); } +bool Abi::isMips64() const +{ + return _config->getConfig().architecture.isMips64(); +} + bool Abi::isArm() const { return _config->getConfig().architecture.isArmOrThumb(); @@ -198,11 +244,48 @@ bool Abi::isX86() const return _config->getConfig().architecture.isX86(); } +bool Abi::isX64() const +{ + return _config->getConfig().architecture.isX86_64(); +} + bool Abi::isPowerPC() const { return _config->getConfig().architecture.isPpc(); } +bool Abi::isPowerPC64() const +{ + return _config->getConfig().architecture.isPpc64(); +} + +bool Abi::isPic32() const +{ + return _config->getConfig().architecture.isPic32(); +} + +CallingConvention* Abi::getDefaultCallingConvention() +{ + return getCallingConvention(_defcc); +} + +CallingConvention* Abi::getCallingConvention( + const CallingConvention::ID& cc) +{ + if (_id2cc.find(cc) == _id2cc.end()) + { + auto provider = CallingConventionProvider::getProvider(); + _id2cc[cc] = provider->createCallingConvention(cc, this); + } + + return _id2cc[cc].get(); +} + +Config* Abi::getConfig() const +{ + return _config; +} + // //============================================================================== // AbiProvider @@ -230,16 +313,35 @@ Abi* AbiProvider::addAbi( auto p = _module2abi.emplace(m, std::make_unique(m, c)); return p.first->second.get(); } - else if (c->getConfig().architecture.isMipsOrPic32()) + else if (c->getConfig().architecture.isMips()) { auto p = _module2abi.emplace(m, std::make_unique(m, c)); return p.first->second.get(); } + else if (c->getConfig().architecture.isPic32()) + { + auto p = _module2abi.emplace(m, std::make_unique(m, c)); + return p.first->second.get(); + } else if (c->getConfig().architecture.isPpc()) { auto p = _module2abi.emplace(m, std::make_unique(m, c)); return p.first->second.get(); } + else if (c->getConfig().architecture.isX86_64()) + { + bool isMinGW = c->getConfig().tools.isGcc() + && c->getConfig().fileFormat.isPe(); + + if (isMinGW || c->getConfig().tools.isMsvc()) + { + auto p = _module2abi.emplace(m, std::make_unique(m, c)); + return p.first->second.get(); + } + + auto p = _module2abi.emplace(m, std::make_unique(m, c)); + return p.first->second.get(); + } else if (c->getConfig().architecture.isX86()) { auto p = _module2abi.emplace(m, std::make_unique(m, c)); diff --git a/src/bin2llvmir/providers/abi/arm.cpp b/src/bin2llvmir/providers/abi/arm.cpp index 70d3284a3..eee6a7a5a 100644 --- a/src/bin2llvmir/providers/abi/arm.cpp +++ b/src/bin2llvmir/providers/abi/arm.cpp @@ -28,6 +28,8 @@ AbiArm::AbiArm(llvm::Module* m, Config* c) : ARM_REG_R3, ARM_REG_R4, ARM_REG_R5}; + + _defcc = CallingConvention::ID::CC_ARM; } AbiArm::~AbiArm() @@ -35,7 +37,7 @@ AbiArm::~AbiArm() } -bool AbiArm::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiArm::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return ARM_REG_R0 <= rid && rid <= ARM_REG_R12; diff --git a/src/bin2llvmir/providers/abi/arm64.cpp b/src/bin2llvmir/providers/abi/arm64.cpp index 89c3460db..d9be3ba84 100644 --- a/src/bin2llvmir/providers/abi/arm64.cpp +++ b/src/bin2llvmir/providers/abi/arm64.cpp @@ -19,7 +19,7 @@ AbiArm64::AbiArm64(llvm::Module* m, Config* c) : _regStackPointerId = ARM64_REG_SP; // system calls - _regSyscallId = ARM64_REG_X8; + _regSyscallId = ARM64_REG_X7; _regSyscallReturn = ARM64_REG_X0; _syscallRegs = { ARM64_REG_X0, @@ -27,8 +27,9 @@ AbiArm64::AbiArm64(llvm::Module* m, Config* c) : ARM64_REG_X2, ARM64_REG_X3, ARM64_REG_X4, - ARM64_REG_X5 - }; + ARM64_REG_X5}; + + _defcc = CallingConvention::ID::CC_ARM64; } AbiArm64::~AbiArm64() @@ -36,7 +37,7 @@ AbiArm64::~AbiArm64() } -bool AbiArm64::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiArm64::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return ARM64_REG_X0 <= rid && rid <= ARM64_REG_X30; diff --git a/src/bin2llvmir/providers/abi/mips.cpp b/src/bin2llvmir/providers/abi/mips.cpp index bd2abc5b0..c29fc3184 100644 --- a/src/bin2llvmir/providers/abi/mips.cpp +++ b/src/bin2llvmir/providers/abi/mips.cpp @@ -27,6 +27,8 @@ AbiMips::AbiMips(llvm::Module* m, Config* c) : MIPS_REG_A1, MIPS_REG_A2, MIPS_REG_A3}; + + _defcc = CallingConvention::ID::CC_MIPS; } AbiMips::~AbiMips() @@ -34,7 +36,7 @@ AbiMips::~AbiMips() } -bool AbiMips::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiMips::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return MIPS_REG_0 <= rid && rid <= MIPS_REG_31; diff --git a/src/bin2llvmir/providers/abi/mips64.cpp b/src/bin2llvmir/providers/abi/mips64.cpp new file mode 100644 index 000000000..cc2edb2a7 --- /dev/null +++ b/src/bin2llvmir/providers/abi/mips64.cpp @@ -0,0 +1,63 @@ +/** + * @file src/bin2llvmir/providers/abi/mips64.cpp + * @brief ABI information for MIPS. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/mips64.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiMips64::AbiMips64(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _regs.reserve(MIPS_REG_ENDING); + _id2regs.resize(MIPS_REG_ENDING, nullptr); + _regStackPointerId = MIPS_REG_SP; + _regZeroReg = MIPS_REG_ZERO; + + // system calls + _regSyscallId = MIPS_REG_V0; + _regSyscallReturn = MIPS_REG_V0; + _syscallRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3, + MIPS_REG_T0, + MIPS_REG_T1, + MIPS_REG_T2, + MIPS_REG_T3}; + + _defcc = CallingConvention::ID::CC_MIPS64; +} + +AbiMips64::~AbiMips64() +{ + +} + +bool AbiMips64::isGeneralPurposeRegister(const llvm::Value* val) const +{ + uint32_t rid = getRegisterId(val); + return MIPS_REG_0 <= rid && rid <= MIPS_REG_31; +} + +bool AbiMips64::isNopInstruction(cs_insn* insn) +{ + // True NOP variants. + // + if (insn->id == MIPS_INS_NOP + || insn->id == MIPS_INS_SSNOP) + { + return true; + } + + return false; +} + +} // namespace bin2llvmir +} // namespace retdec diff --git a/src/bin2llvmir/providers/abi/ms_x64.cpp b/src/bin2llvmir/providers/abi/ms_x64.cpp new file mode 100644 index 000000000..f943bc5da --- /dev/null +++ b/src/bin2llvmir/providers/abi/ms_x64.cpp @@ -0,0 +1,105 @@ +/** + * @file src/bin2llvmir/providers/abi/ms_x64.cpp + * @brief ABI information for x86_64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/ms_x64.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiMS_X64::AbiMS_X64(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _regs.reserve(X86_REG_ENDING); + _id2regs.resize(X86_REG_ENDING, nullptr); + _regStackPointerId = X86_REG_RSP; + + // system calls + _regSyscallId = X86_REG_EAX; + _regSyscallReturn = X86_REG_EAX; + _syscallRegs = { + X86_REG_RDI, + X86_REG_RSI, + X86_REG_RDX, + X86_REG_R10, + X86_REG_R8, + X86_REG_R9}; + + _defcc = CallingConvention::ID::CC_X64; +} + +AbiMS_X64::~AbiMS_X64() +{ +} + +bool AbiMS_X64::isGeneralPurposeRegister(const llvm::Value* val) const +{ + uint32_t rid = getRegisterId(val); + return rid == X86_REG_RAX + || rid == X86_REG_RBX + || rid == X86_REG_RCX + || rid == X86_REG_RDX + || rid == X86_REG_RSP + || rid == X86_REG_RBP + || rid == X86_REG_RSI + || rid == X86_REG_RDI + || rid == X86_REG_R8 + || rid == X86_REG_R9 + || rid == X86_REG_R10 + || rid == X86_REG_R11 + || rid == X86_REG_R12 + || rid == X86_REG_R13 + || rid == X86_REG_R14 + || rid == X86_REG_R15; +} + +bool AbiMS_X64::isNopInstruction(cs_insn* insn) +{ + cs_x86& insn86 = insn->detail->x86; + + // True NOP variants. + // + if (insn->id == X86_INS_NOP + || insn->id == X86_INS_FNOP + || insn->id == X86_INS_FDISI8087_NOP + || insn->id == X86_INS_FENI8087_NOP + || insn->id == X86_INS_INT3) + { + return true; + } + // e.g. lea esi, [esi] + // + else if (insn->id == X86_INS_LEA + && insn86.disp == 0 + && insn86.op_count == 2 + && insn86.operands[0].type == X86_OP_REG + && insn86.operands[1].type == X86_OP_MEM + && insn86.operands[1].mem.segment == X86_REG_INVALID + && insn86.operands[1].mem.index == X86_REG_INVALID + && insn86.operands[1].mem.scale == 1 + && insn86.operands[1].mem.disp == 0 + && insn86.operands[1].mem.base == insn86.operands[0].reg) + { + return true; + } + // e.g. mov esi. esi + // + else if (insn->id == X86_INS_MOV + && insn86.disp == 0 + && insn86.op_count == 2 + && insn86.operands[0].type == X86_OP_REG + && insn86.operands[1].type == X86_OP_REG + && insn86.operands[0].reg == insn86.operands[1].reg) + { + return true; + } + + return false; +} + +} // namespace bin2llvmir +} // namespace retdec diff --git a/src/bin2llvmir/providers/abi/pic32.cpp b/src/bin2llvmir/providers/abi/pic32.cpp new file mode 100644 index 000000000..ff629e090 --- /dev/null +++ b/src/bin2llvmir/providers/abi/pic32.cpp @@ -0,0 +1,79 @@ +/** + * @file src/bin2llvmir/providers/abi/pic32.cpp + * @brief ABI information for MIPS. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/pic32.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiPic32::AbiPic32(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _regs.reserve(MIPS_REG_ENDING); + _id2regs.resize(MIPS_REG_ENDING, nullptr); + _regStackPointerId = MIPS_REG_SP; + _regZeroReg = MIPS_REG_ZERO; + + // system calls + _regSyscallId = MIPS_REG_V0; + _regSyscallReturn = MIPS_REG_V0; + _syscallRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3}; + + _defcc = CallingConvention::ID::CC_PIC32; +} + +AbiPic32::~AbiPic32() +{ + +} + +bool AbiPic32::isGeneralPurposeRegister(const llvm::Value* val) const +{ + uint32_t rid = getRegisterId(val); + return MIPS_REG_0 <= rid && rid <= MIPS_REG_31; +} + +bool AbiPic32::isNopInstruction(cs_insn* insn) +{ + // True NOP variants. + // + if (insn->id == MIPS_INS_NOP + || insn->id == MIPS_INS_SSNOP) + { + return true; + } + + return false; +} + +std::size_t AbiPic32::getTypeByteSize(llvm::Type* t) const +{ + if (t->isDoubleTy()) + { + t = Type::getFloatTy(_module->getContext()); + } + + return Abi::getTypeByteSize(t); +} + +std::size_t AbiPic32::getTypeBitSize(llvm::Type* t) const +{ + if (t->isDoubleTy()) + { + t = Type::getFloatTy(_module->getContext()); + } + + return Abi::getTypeByteSize(t); +} + +} // namespace bin2llvmir +} // namespace retdec diff --git a/src/bin2llvmir/providers/abi/powerpc.cpp b/src/bin2llvmir/providers/abi/powerpc.cpp index 92cbae6d8..e6983d27d 100644 --- a/src/bin2llvmir/providers/abi/powerpc.cpp +++ b/src/bin2llvmir/providers/abi/powerpc.cpp @@ -17,6 +17,8 @@ AbiPowerpc::AbiPowerpc(llvm::Module* m, Config* c) : _regs.reserve(PPC_REG_ENDING); _id2regs.resize(PPC_REG_ENDING, nullptr); _regStackPointerId = PPC_REG_R1; + + _defcc = CallingConvention::ID::CC_POWERPC; } AbiPowerpc::~AbiPowerpc() @@ -24,7 +26,7 @@ AbiPowerpc::~AbiPowerpc() } -bool AbiPowerpc::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiPowerpc::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return PPC_REG_R0 <= rid && rid <= PPC_REG_R31; diff --git a/src/bin2llvmir/providers/abi/powerpc64.cpp b/src/bin2llvmir/providers/abi/powerpc64.cpp new file mode 100644 index 000000000..662114db6 --- /dev/null +++ b/src/bin2llvmir/providers/abi/powerpc64.cpp @@ -0,0 +1,49 @@ +/** + * @file src/bin2llvmir/providers/abi/powerpc64.cpp + * @brief ABI information for PowerPC 64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/powerpc64.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiPowerpc64::AbiPowerpc64(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _regs.reserve(PPC_REG_ENDING); + _id2regs.resize(PPC_REG_ENDING, nullptr); + _regStackPointerId = PPC_REG_R1; + + _defcc = CallingConvention::ID::CC_POWERPC64; +} + +AbiPowerpc64::~AbiPowerpc64() +{ + +} + +bool AbiPowerpc64::isGeneralPurposeRegister(const llvm::Value* val) const +{ + uint32_t rid = getRegisterId(val); + return PPC_REG_R0 <= rid && rid <= PPC_REG_R31; +} + +bool AbiPowerpc64::isNopInstruction(cs_insn* insn) +{ + // True NOP variants. + // + if (insn->id == PPC_INS_NOP + || insn->id == PPC_INS_XNOP) + { + return true; + } + + return false; +} + +} // namespace bin2llvmir +} // namespace retdec diff --git a/src/bin2llvmir/providers/abi/x64.cpp b/src/bin2llvmir/providers/abi/x64.cpp new file mode 100644 index 000000000..304c20aa2 --- /dev/null +++ b/src/bin2llvmir/providers/abi/x64.cpp @@ -0,0 +1,105 @@ +/** + * @file src/bin2llvmir/providers/abi/x64.cpp + * @brief ABI information for x86_64. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/x64.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +AbiX64::AbiX64(llvm::Module* m, Config* c) : + Abi(m, c) +{ + _regs.reserve(X86_REG_ENDING); + _id2regs.resize(X86_REG_ENDING, nullptr); + _regStackPointerId = X86_REG_RSP; + + // system calls + _regSyscallId = X86_REG_EAX; + _regSyscallReturn = X86_REG_EAX; + _syscallRegs = { + X86_REG_RDI, + X86_REG_RSI, + X86_REG_RDX, + X86_REG_R10, + X86_REG_R8, + X86_REG_R9}; + + _defcc = CallingConvention::ID::CC_X64; +} + +AbiX64::~AbiX64() +{ +} + +bool AbiX64::isGeneralPurposeRegister(const llvm::Value* val) const +{ + uint32_t rid = getRegisterId(val); + return rid == X86_REG_RAX + || rid == X86_REG_RBX + || rid == X86_REG_RCX + || rid == X86_REG_RDX + || rid == X86_REG_RSP + || rid == X86_REG_RBP + || rid == X86_REG_RSI + || rid == X86_REG_RDI + || rid == X86_REG_R8 + || rid == X86_REG_R9 + || rid == X86_REG_R10 + || rid == X86_REG_R11 + || rid == X86_REG_R12 + || rid == X86_REG_R13 + || rid == X86_REG_R14 + || rid == X86_REG_R15; +} + +bool AbiX64::isNopInstruction(cs_insn* insn) +{ + cs_x86& insn86 = insn->detail->x86; + + // True NOP variants. + // + if (insn->id == X86_INS_NOP + || insn->id == X86_INS_FNOP + || insn->id == X86_INS_FDISI8087_NOP + || insn->id == X86_INS_FENI8087_NOP + || insn->id == X86_INS_INT3) + { + return true; + } + // e.g. lea esi, [esi] + // + else if (insn->id == X86_INS_LEA + && insn86.disp == 0 + && insn86.op_count == 2 + && insn86.operands[0].type == X86_OP_REG + && insn86.operands[1].type == X86_OP_MEM + && insn86.operands[1].mem.segment == X86_REG_INVALID + && insn86.operands[1].mem.index == X86_REG_INVALID + && insn86.operands[1].mem.scale == 1 + && insn86.operands[1].mem.disp == 0 + && insn86.operands[1].mem.base == insn86.operands[0].reg) + { + return true; + } + // e.g. mov esi. esi + // + else if (insn->id == X86_INS_MOV + && insn86.disp == 0 + && insn86.op_count == 2 + && insn86.operands[0].type == X86_OP_REG + && insn86.operands[1].type == X86_OP_REG + && insn86.operands[0].reg == insn86.operands[1].reg) + { + return true; + } + + return false; +} + +} // namespace bin2llvmir +} // namespace retdec diff --git a/src/bin2llvmir/providers/abi/x86.cpp b/src/bin2llvmir/providers/abi/x86.cpp index d1dde441a..361137b63 100644 --- a/src/bin2llvmir/providers/abi/x86.cpp +++ b/src/bin2llvmir/providers/abi/x86.cpp @@ -28,6 +28,8 @@ AbiX86::AbiX86(llvm::Module* m, Config* c) : X86_REG_ESI, X86_REG_EDI, X86_REG_EBP}; + + _defcc = fetchDefaultCC(); } AbiX86::~AbiX86() @@ -35,7 +37,7 @@ AbiX86::~AbiX86() } -bool AbiX86::isGeneralPurposeRegister(const llvm::Value* val) +bool AbiX86::isGeneralPurposeRegister(const llvm::Value* val) const { uint32_t rid = getRegisterId(val); return rid == X86_REG_EAX @@ -92,5 +94,19 @@ bool AbiX86::isNopInstruction(cs_insn* insn) return false; } +CallingConvention::ID AbiX86::fetchDefaultCC() const +{ + if (_config->getConfig().tools.isWatcom()) + { + return CallingConvention::ID::CC_WATCOM; + } + if (_config->getConfig().tools.isBorland()) + { + return CallingConvention::ID::CC_PASCAL; + } + + return CallingConvention::ID::CC_CDECL; +} + } // namespace bin2llvmir } // namespace retdec diff --git a/src/bin2llvmir/providers/calling_convention/arm/arm_conv.cpp b/src/bin2llvmir/providers/calling_convention/arm/arm_conv.cpp new file mode 100644 index 000000000..4e1ce53dc --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/arm/arm_conv.cpp @@ -0,0 +1,49 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/arm/arm_conv.cpp + * @brief Calling convention of ARM architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h" +#include "retdec/capstone2llvmir/arm/arm.h" + +namespace retdec { +namespace bin2llvmir { + +ArmCallingConvention::ArmCallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + ARM_REG_R0, + ARM_REG_R1, + ARM_REG_R2, + ARM_REG_R3}; + + _returnRegs = { + ARM_REG_R0, + ARM_REG_R1}; + + _largeObjectsPassedByReference = true; +// _respectsRegCouples = true; + _numOfRegsPerParam = 2; + _numOfFPRegsPerParam = 2; + _numOfVectorRegsPerParam = 4; +} + +ArmCallingConvention::~ArmCallingConvention() +{ +} + +CallingConvention::Ptr ArmCallingConvention::create(const Abi* a) +{ + if (!a->isArm()) + { + return nullptr; + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/arm64/arm64_conv.cpp b/src/bin2llvmir/providers/calling_convention/arm64/arm64_conv.cpp new file mode 100644 index 000000000..79a5af180 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/arm64/arm64_conv.cpp @@ -0,0 +1,78 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/arm64/arm64_conv.cpp + * @brief Calling conventions of ARM64 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h" + +namespace retdec { +namespace bin2llvmir { + +Arm64CallingConvention::Arm64CallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + ARM64_REG_X0, + ARM64_REG_X1, + ARM64_REG_X2, + ARM64_REG_X3, + ARM64_REG_X4, + ARM64_REG_X5, + ARM64_REG_X6, + ARM64_REG_X7 + }; + _paramFPRegs = { + ARM64_REG_V0, + ARM64_REG_V1, + ARM64_REG_V2, + ARM64_REG_V3, + ARM64_REG_V4, + ARM64_REG_V5, + ARM64_REG_V6, + ARM64_REG_V7 + }; + + _paramVectorRegs = { + ARM64_REG_V0, + ARM64_REG_V1, + ARM64_REG_V2, + ARM64_REG_V3, + ARM64_REG_V4, + ARM64_REG_V5, + ARM64_REG_V6, + ARM64_REG_V7 + }; + + _returnRegs = { + ARM64_REG_X0 + }; + + _returnFPRegs = { + ARM64_REG_V0 + }; + + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; + _numOfRegsPerParam = 2; +} + +Arm64CallingConvention::~Arm64CallingConvention() +{ +} + +CallingConvention::Ptr Arm64CallingConvention::create(const Abi* a) +{ + if (!a->isArm64()) + { + return nullptr; + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/calling_convention.cpp b/src/bin2llvmir/providers/calling_convention/calling_convention.cpp new file mode 100644 index 000000000..951a3016f --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/calling_convention.cpp @@ -0,0 +1,234 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/calling_convention.cpp + * @brief Calling convention information. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/calling_convention.h" +#include "retdec/bin2llvmir/providers/calling_convention/arm/arm_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/arm64/arm64_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h" +#include "retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h" + +using namespace llvm; + +namespace retdec { +namespace bin2llvmir { + +// +//============================================================================== +// CallingConvention +//============================================================================== +// + +const bool CallingConvention::RTL = true; +const bool CallingConvention::LTR = false; + +CallingConvention::CallingConvention( + const Abi* abi) : + _abi(abi) +{ +} + +CallingConvention::~CallingConvention() +{ +} + +const std::vector& CallingConvention::getParamRegisters() const +{ + return _paramRegs; +} + +const std::vector& CallingConvention::getParamFPRegisters() const +{ + return _paramFPRegs; +} + +const std::vector& CallingConvention::getParamDoubleRegisters() const +{ + return _paramDoubleRegs; +} + +const std::vector& CallingConvention::getParamVectorRegisters() const +{ + return _paramVectorRegs; +} + +const std::vector& CallingConvention::getReturnRegisters() const +{ + return _returnRegs; +} + +const std::vector& CallingConvention::getReturnFPRegisters() const +{ + return _returnFPRegs; +} + +const std::vector& CallingConvention::getReturnDoubleRegisters() const +{ + return _returnDoubleRegs; +} + +const std::vector& CallingConvention::getReturnVectorRegisters() const +{ + return _returnVectorRegs; +} + +bool CallingConvention::usesFPRegistersForParameters() const +{ + return !(_paramFPRegs.empty() && _paramDoubleRegs.empty()); +} + +std::size_t CallingConvention::getMaxNumOfRegsPerParam() const +{ + return _numOfRegsPerParam; +} + +std::size_t CallingConvention::getMaxNumOfFPRegsPerParam() const +{ + return _numOfFPRegsPerParam; +} + +std::size_t CallingConvention::getMaxNumOfDoubleRegsPerParam() const +{ + return _numOfDoubleRegsPerParam; +} + +std::size_t CallingConvention::getMaxNumOfVectorRegsPerParam() const +{ + return _numOfVectorRegsPerParam; +} + +bool CallingConvention::getStackParamOrder() const +{ + return _stackParamOrder; +} + +bool CallingConvention::passesLargeObjectsByReference() const +{ + return _largeObjectsPassedByReference; +} + +bool CallingConvention::respectsRegisterCouples() const +{ + return _respectsRegCouples; +} + +std::size_t CallingConvention::getMaxBytesPerStackParam() const +{ + return _abi->getWordSize(); +} + +bool CallingConvention::valueCanBeParameter(const Value *val) const +{ + if (_abi->isStackVariable(val)) + { + return true; + } + + auto rId = _abi->getRegisterId(val); + + if (rId == Abi::REG_INVALID) + { + return false; + } + + return std::count(_paramRegs.begin(), _paramRegs.end(), rId) + || std::count(_paramFPRegs.begin(), _paramFPRegs.end(), rId) + || std::count(_paramDoubleRegs.begin(), _paramDoubleRegs.end(), rId) + || std::count(_paramVectorRegs.begin(), _paramVectorRegs.end(), rId); +} + +bool CallingConvention::canHoldReturnValue(const Value* val) const +{ + auto rId = _abi->getRegisterId(val); + + if (rId == Abi::REG_INVALID) + { + return false; + } + + return std::count(_returnRegs.begin(), _returnRegs.end(), rId) + || std::count(_returnFPRegs.begin(), _returnFPRegs.end(), rId) + || std::count(_returnDoubleRegs.begin(), _returnDoubleRegs.end(), rId) + || std::count(_returnVectorRegs.begin(), _returnVectorRegs.end(), rId); +} + +// +//============================================================================== +// CallingConventionProvider +//============================================================================== +// + +CallingConventionProvider::CallingConventionProvider() +{ + registerCC(CallingConvention::ID::CC_CDECL, &CdeclCallingConvention::create); + registerCC(CallingConvention::ID::CC_ELLIPSIS, &CdeclCallingConvention::create); + registerCC(CallingConvention::ID::CC_STDCALL, &CdeclCallingConvention::create); + registerCC(CallingConvention::ID::CC_THISCALL, &ThiscallCallingConvention::create); + registerCC(CallingConvention::ID::CC_PASCAL, &PascalCallingConvention::create); + registerCC(CallingConvention::ID::CC_FASTCALL, &FastcallCallingConvention::create); + registerCC(CallingConvention::ID::CC_WATCOM, &WatcomCallingConvention::create); + registerCC(CallingConvention::ID::CC_X64, &X64CallingConvention::create); + registerCC(CallingConvention::ID::CC_ARM, &ArmCallingConvention::create); + registerCC(CallingConvention::ID::CC_ARM64, &Arm64CallingConvention::create); + registerCC(CallingConvention::ID::CC_POWERPC, &PowerPCCallingConvention::create); + registerCC(CallingConvention::ID::CC_POWERPC64, &PowerPC64CallingConvention::create); + registerCC(CallingConvention::ID::CC_MIPS, &MipsCallingConvention::create); + registerCC(CallingConvention::ID::CC_MIPS64, &Mips64CallingConvention::create); + registerCC(CallingConvention::ID::CC_PIC32, &Pic32CallingConvention::create); +} + +CallingConventionProvider::~CallingConventionProvider() +{ + _id2cc.clear(); +} + +CallingConventionProvider* CallingConventionProvider::getProvider() +{ + static CallingConventionProvider instance; + + return &instance; +} + +void CallingConventionProvider::registerCC( + const CallingConvention::ID& cc, + const CallingConvention::ConstructorMethod& con) +{ + auto ccId = static_cast(cc); + + if (ccId >= _id2cc.size()) + { + _id2cc.resize(ccId+1, nullptr); + } + + _id2cc[ccId] = con; +} + +CallingConvention::Ptr CallingConventionProvider::createCallingConvention( + const CallingConvention::ID& cc, + const Abi* a) const +{ + auto ccId = static_cast(cc); + + if (ccId >= _id2cc.size() || _id2cc[ccId] == nullptr) + { + return nullptr; + } + + return _id2cc[ccId](a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/mips/mips_conv.cpp b/src/bin2llvmir/providers/calling_convention/mips/mips_conv.cpp new file mode 100644 index 000000000..015b667c0 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/mips/mips_conv.cpp @@ -0,0 +1,65 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/mips/mips_conv.cpp + * @brief Calling conventions of MIPS architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/mips/mips_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h" +#include "retdec/capstone2llvmir/mips/mips.h" + +namespace retdec { +namespace bin2llvmir { + +MipsCallingConvention::MipsCallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3 + }; + _paramFPRegs = { + MIPS_REG_F12, + MIPS_REG_F14, + MIPS_REG_F16, + MIPS_REG_F18 + }; + _paramDoubleRegs = { + MIPS_REG_FD12, + MIPS_REG_FD14, + MIPS_REG_FD16, + }; + + _returnRegs = { + MIPS_REG_V0 + }; + + _numOfRegsPerParam = 2; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; +} + +MipsCallingConvention::~MipsCallingConvention() +{ +} + +CallingConvention::Ptr MipsCallingConvention::create(const Abi* a) +{ + if (!a->isMips()) + { + return nullptr; + } + + if (a->getConfig()->getConfig().tools.isPspGcc()) + { + return std::make_unique(a); + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/mips/mips_psp.cpp b/src/bin2llvmir/providers/calling_convention/mips/mips_psp.cpp new file mode 100644 index 000000000..28dc6a970 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/mips/mips_psp.cpp @@ -0,0 +1,58 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/mips/mips_psp.cpp + * @brief Calling conventions of MIPS architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/calling_convention/mips/mips_psp.h" +#include "retdec/capstone2llvmir/mips/mips.h" + +namespace retdec { +namespace bin2llvmir { + +MipsPSPCallingConvention::MipsPSPCallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3, + MIPS_REG_T0, + MIPS_REG_T1, + MIPS_REG_T2, + MIPS_REG_T3 + }; + _paramFPRegs = { + MIPS_REG_F12, + MIPS_REG_F14, + MIPS_REG_F16, + MIPS_REG_F18 + }; + _paramDoubleRegs = { + MIPS_REG_FD12, + MIPS_REG_FD14, + MIPS_REG_FD16, + }; + + _returnRegs = { + MIPS_REG_V0 + }; + _returnFPRegs = { + MIPS_REG_V0 + }; + _returnDoubleRegs = { + MIPS_REG_V0 + }; + + _numOfRegsPerParam = 2; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; +} + +MipsPSPCallingConvention::~MipsPSPCallingConvention() +{ +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/mips64/mips64_conv.cpp b/src/bin2llvmir/providers/calling_convention/mips64/mips64_conv.cpp new file mode 100644 index 000000000..c29bcdf9e --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/mips64/mips64_conv.cpp @@ -0,0 +1,64 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/mips64/mips64_conv.cpp + * @brief Calling convention of Mips64 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/mips64/mips64_conv.h" +#include "retdec/capstone2llvmir/mips/mips.h" + +namespace retdec { +namespace bin2llvmir { + +Mips64CallingConvention::Mips64CallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3, + MIPS_REG_T0, + MIPS_REG_T1, + MIPS_REG_T2, + MIPS_REG_T3 + }; + _paramFPRegs = { + MIPS_REG_F12, + MIPS_REG_F13, + MIPS_REG_F14, + MIPS_REG_F15, + MIPS_REG_F16, + MIPS_REG_F17, + MIPS_REG_F18 + }; + + _returnRegs = { + MIPS_REG_V0 + }; + _returnFPRegs = { + MIPS_REG_F1 + }; + + _numOfRegsPerParam = 2; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; +} + +Mips64CallingConvention::~Mips64CallingConvention() +{ +} + +CallingConvention::Ptr Mips64CallingConvention::create(const Abi* a) +{ + if (!a->isMips64()) + { + return nullptr; + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/pic32/pic32_conv.cpp b/src/bin2llvmir/providers/calling_convention/pic32/pic32_conv.cpp new file mode 100644 index 000000000..46f0bc03a --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/pic32/pic32_conv.cpp @@ -0,0 +1,48 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/pic32/pic32_conv.cpp + * @brief Calling conventions of PIC32 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/pic32/pic32_conv.h" +#include "retdec/capstone2llvmir/mips/mips.h" + +namespace retdec { +namespace bin2llvmir { + +Pic32CallingConvention::Pic32CallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + MIPS_REG_A0, + MIPS_REG_A1, + MIPS_REG_A2, + MIPS_REG_A3 + }; + + _returnRegs = { + MIPS_REG_V0 + }; + + _numOfRegsPerParam = 1; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; +} + +Pic32CallingConvention::~Pic32CallingConvention() +{ +} + +CallingConvention::Ptr Pic32CallingConvention::create(const Abi* a) +{ + if (!a->isPic32()) + { + return nullptr; + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.cpp b/src/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.cpp new file mode 100644 index 000000000..fcd9589c7 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.cpp @@ -0,0 +1,66 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.cpp + * @brief Calling conventions of PowerPC architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/powerpc/powerpc_conv.h" +#include "retdec/capstone2llvmir/powerpc/powerpc.h" + +namespace retdec { +namespace bin2llvmir { + +PowerPCCallingConvention::PowerPCCallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + PPC_REG_R3, + PPC_REG_R4, + PPC_REG_R5, + PPC_REG_R6, + PPC_REG_R7, + PPC_REG_R8, + PPC_REG_R9, + PPC_REG_R10 + }; + _paramFPRegs = { + PPC_REG_F1, + PPC_REG_F2, + PPC_REG_F3, + PPC_REG_F4, + PPC_REG_F5, + PPC_REG_F6, + PPC_REG_F7, + PPC_REG_F8 + }; + + _returnRegs = { + PPC_REG_R3, + PPC_REG_R4 + }; + _returnFPRegs = { + PPC_REG_F1 + }; + + _numOfRegsPerParam = 2; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; +} + +PowerPCCallingConvention::~PowerPCCallingConvention() +{ +} + +CallingConvention::Ptr PowerPCCallingConvention::create(const Abi* a) +{ + if (!a->isPowerPC()) + { + return nullptr; + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.cpp b/src/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.cpp new file mode 100644 index 000000000..c15373711 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.cpp @@ -0,0 +1,68 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.cpp + * @brief Calling conventions of PowerPC64 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/powerpc64/powerpc64_conv.h" +#include "retdec/capstone2llvmir/powerpc/powerpc.h" + +namespace retdec { +namespace bin2llvmir { + +PowerPC64CallingConvention::PowerPC64CallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + PPC_REG_R3, + PPC_REG_R4, + PPC_REG_R5, + PPC_REG_R6, + PPC_REG_R7, + PPC_REG_R8, + PPC_REG_R9, + PPC_REG_R10 + }; + _paramFPRegs = { + PPC_REG_F1, + PPC_REG_F2, + PPC_REG_F3, + PPC_REG_F4, + PPC_REG_F5, + PPC_REG_F6, + PPC_REG_F7, + PPC_REG_F8, + PPC_REG_F10, + PPC_REG_F11 + }; + + _returnRegs = { + PPC_REG_R3, + PPC_REG_R4 + }; + _returnFPRegs = { + PPC_REG_F1 + }; + + _numOfRegsPerParam = 2; + _largeObjectsPassedByReference = true; + _respectsRegCouples = true; +} + +PowerPC64CallingConvention::~PowerPC64CallingConvention() +{ +} + +CallingConvention::Ptr PowerPC64CallingConvention::create(const Abi* a) +{ + if (!a->isPowerPC64()) + { + return nullptr; + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x64/x64_conv.cpp b/src/bin2llvmir/providers/calling_convention/x64/x64_conv.cpp new file mode 100644 index 000000000..fe99afab6 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x64/x64_conv.cpp @@ -0,0 +1,36 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x64/x64_conv.cpp + * @brief Calling conventions of X64 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/x64/x64_conv.h" +#include "retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h" +#include "retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +CallingConvention::Ptr X64CallingConvention::create(const Abi* a) +{ + if (!a->isX64()) + { + return nullptr; + } + + auto c = a->getConfig(); + bool isMinGW = c->getConfig().tools.isGcc() + && c->getConfig().fileFormat.isPe(); + + if (isMinGW || c->getConfig().tools.isMsvc()) + { + return std::make_unique(a); + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x64/x64_microsoft.cpp b/src/bin2llvmir/providers/calling_convention/x64/x64_microsoft.cpp new file mode 100644 index 000000000..5e824052d --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x64/x64_microsoft.cpp @@ -0,0 +1,44 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x64/x64_microsoft.cpp + * @brief Microsoft calling convention of X64 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/calling_convention/x64/x64_microsoft.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +MicrosoftX64CallingConvention::MicrosoftX64CallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + X86_REG_RCX, + X86_REG_RDX, + X86_REG_R8, + X86_REG_R9 + }; + _paramFPRegs = { + X86_REG_XMM0, + X86_REG_XMM1, + X86_REG_XMM2, + X86_REG_XMM3 + }; + + _returnRegs = { + X86_REG_RAX + }; + _returnFPRegs = { + X86_REG_XMM0 + }; + + _largeObjectsPassedByReference = true; +} + +MicrosoftX64CallingConvention::~MicrosoftX64CallingConvention() +{ +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x64/x64_systemv.cpp b/src/bin2llvmir/providers/calling_convention/x64/x64_systemv.cpp new file mode 100644 index 000000000..56dd105cc --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x64/x64_systemv.cpp @@ -0,0 +1,69 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x64/x64_systemv.cpp + * @brief System V Calling convention of X64 architecture. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/calling_convention/x64/x64_systemv.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +SystemVX64CallingConvention::SystemVX64CallingConvention(const Abi* a) : + CallingConvention(a) +{ + _paramRegs = { + X86_REG_RDI, + X86_REG_RSI, + X86_REG_RDX, + X86_REG_RCX, + X86_REG_R8, + X86_REG_R9 + }; + _paramFPRegs = { + X86_REG_XMM0, + X86_REG_XMM1, + X86_REG_XMM2, + X86_REG_XMM3, + X86_REG_XMM4, + X86_REG_XMM5, + X86_REG_XMM6, + X86_REG_XMM7 + }; + _paramVectorRegs = { + X86_REG_XMM0, + X86_REG_XMM1, + X86_REG_XMM2, + X86_REG_XMM3, + X86_REG_XMM4, + X86_REG_XMM5, + X86_REG_XMM6, + X86_REG_XMM7 + }; + + _returnRegs = { + X86_REG_RAX, + X86_REG_RDX + }; + _returnFPRegs = { + X86_REG_XMM0, + X86_REG_XMM1 + }; + _returnVectorRegs = { + X86_REG_XMM0, + X86_REG_XMM1 + }; + + _largeObjectsPassedByReference = true; + _numOfRegsPerParam = 2; + _numOfFPRegsPerParam = 2; + _numOfVectorRegsPerParam = 2; +} + +SystemVX64CallingConvention::~SystemVX64CallingConvention() +{ +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x86/x86_cdecl.cpp b/src/bin2llvmir/providers/calling_convention/x86/x86_cdecl.cpp new file mode 100644 index 000000000..87ef9a78e --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x86/x86_cdecl.cpp @@ -0,0 +1,43 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x86/x86_cdecl.cpp + * @brief Cdecl calling convention of architecture x86. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_cdecl.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +CdeclCallingConvention::CdeclCallingConvention(const Abi* a) : + X86CallingConvention(a) +{ + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; +} + +CdeclCallingConvention::~CdeclCallingConvention() +{ +} + +CallingConvention::Ptr CdeclCallingConvention::create(const Abi* a) +{ + if (!a->isX86()) + { + return nullptr; + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x86/x86_conv.cpp b/src/bin2llvmir/providers/calling_convention/x86/x86_conv.cpp new file mode 100644 index 000000000..3c50f2983 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x86/x86_conv.cpp @@ -0,0 +1,26 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x86/x86_conv.cpp + * @brief Calling convention of architecture x86. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_conv.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +X86CallingConvention::X86CallingConvention(const Abi* a) : + CallingConvention(a) + +{ +} + +std::size_t X86CallingConvention::getMaxBytesPerStackParam() const +{ + return _abi->getWordSize()*2; +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x86/x86_fastcall.cpp b/src/bin2llvmir/providers/calling_convention/x86/x86_fastcall.cpp new file mode 100644 index 000000000..995620a79 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x86/x86_fastcall.cpp @@ -0,0 +1,93 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x86/x86_fastcall.cpp + * @brief Fastcall calling convention of architecture x86. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_fastcall.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +// +//============================================================================== +// PascalFastcallCallingConvention +//============================================================================== +// + +PascalFastcallCallingConvention::PascalFastcallCallingConvention(const Abi* a) : + X86CallingConvention(a) + +{ + _paramRegs = { + X86_REG_EAX, + X86_REG_EDX, + X86_REG_ECX + }; + + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; + + _stackParamOrder = LTR; +} + +PascalFastcallCallingConvention::~PascalFastcallCallingConvention() +{ +} + +// +//============================================================================== +// FastcallCallingConvention +//============================================================================== +// + +FastcallCallingConvention::FastcallCallingConvention(const Abi* a) : + X86CallingConvention(a) + +{ + _paramRegs = { + X86_REG_ECX, + X86_REG_EDX, + }; + + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; +} + +FastcallCallingConvention::~FastcallCallingConvention() +{ +} + +CallingConvention::Ptr FastcallCallingConvention::create(const Abi* a) +{ + if (!a->isX86()) + { + return nullptr; + } + + if (a->getConfig()->getConfig().tools.isBorland()) + { + return std::make_unique(a); + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x86/x86_pascal.cpp b/src/bin2llvmir/providers/calling_convention/x86/x86_pascal.cpp new file mode 100644 index 000000000..66fa1b155 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x86/x86_pascal.cpp @@ -0,0 +1,46 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x86/x86_pascal.cpp + * @brief Pascal calling convention of architecture x86. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_pascal.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +PascalCallingConvention::PascalCallingConvention(const Abi* a) : + X86CallingConvention(a) + +{ + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; + + _stackParamOrder = LTR; +} + +PascalCallingConvention::~PascalCallingConvention() +{ +} + +CallingConvention::Ptr PascalCallingConvention::create(const Abi* a) +{ + if (!a->isX86()) + { + return nullptr; + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x86/x86_thiscall.cpp b/src/bin2llvmir/providers/calling_convention/x86/x86_thiscall.cpp new file mode 100644 index 000000000..b5f9dd247 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x86/x86_thiscall.cpp @@ -0,0 +1,48 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x86/x86_thiscall.cpp + * @brief Thiscall calling convention of architecture x86. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_thiscall.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +ThiscallCallingConvention::ThiscallCallingConvention(const Abi* a) : + X86CallingConvention(a) + +{ + _paramRegs = { + X86_REG_ECX + }; + + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; +} + +ThiscallCallingConvention::~ThiscallCallingConvention() +{ +} + +CallingConvention::Ptr ThiscallCallingConvention::create(const Abi* a) +{ + if (!a->isX86()) + { + return nullptr; + } + + return std::make_unique(a); +} + +} +} diff --git a/src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp b/src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp new file mode 100644 index 000000000..34abcb773 --- /dev/null +++ b/src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp @@ -0,0 +1,51 @@ +/** + * @file src/bin2llvmir/providers/calling_convention/x86/x86_watcom.cpp + * @brief Watcom calling convention of architecture x86. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include "retdec/bin2llvmir/providers/abi/abi.h" +#include "retdec/bin2llvmir/providers/calling_convention/x86/x86_watcom.h" +#include "retdec/capstone2llvmir/x86/x86.h" + +namespace retdec { +namespace bin2llvmir { + +WatcomCallingConvention::WatcomCallingConvention(const Abi* a) : + X86CallingConvention(a) + +{ + _paramRegs = { + X86_REG_EAX, + X86_REG_EDX, + X86_REG_EBX, + X86_REG_ECX + }; + + _returnRegs = { + X86_REG_EAX, + X86_REG_EDX + }; + + _returnFPRegs = { + X86_REG_ST7, + X86_REG_ST0 + }; +} + +WatcomCallingConvention::~WatcomCallingConvention() +{ +} + +CallingConvention::Ptr WatcomCallingConvention::create(const Abi* a) +{ + if (!a->isX86()) + { + return nullptr; + } + + return std::make_unique(a); +} + +} +} diff --git a/src/capstone2llvmir/arm/arm.cpp b/src/capstone2llvmir/arm/arm.cpp index 2ce2c57a9..c10395eb4 100644 --- a/src/capstone2llvmir/arm/arm.cpp +++ b/src/capstone2llvmir/arm/arm.cpp @@ -1659,11 +1659,6 @@ void Capstone2LlvmIrTranslatorArm_impl::translateStr(cs_insn* i, cs_arm* ai, llv op0 = irb.CreateZExtOrTrunc(op0, irb.getInt16Ty()); break; } - // TODO: The new commented code is better, but without special handling - // in bin2llvmirl, it screws up some tests: - // e.g. "many-params.c -a arm -f elf -c gcc -C -O0 -g" - // Therefore, at the moment, we generate the same code as original sem. - // case ARM_INS_STRD: case ARM_INS_STREXD: { @@ -1687,12 +1682,15 @@ void Capstone2LlvmIrTranslatorArm_impl::translateStr(cs_insn* i, cs_arm* ai, llv bool subtract = false; if (i->id == ARM_INS_STRD || i->id == ARM_INS_STREXD) { - // TODO: op1 is not stored at all at the moment. See comment above. - if (ai->op_count == 3 && ai->operands[2].type == ARM_OP_MEM) { storeOp(ai->operands[2], op0, irb); + + auto op3 = ai->operands[2]; + op3.mem.disp += 4; + storeOp(op3, op1, irb); + baseR = ai->operands[2].mem.base; if (auto disp = ai->operands[2].mem.disp) { @@ -1702,11 +1700,19 @@ void Capstone2LlvmIrTranslatorArm_impl::translateStr(cs_insn* i, cs_arm* ai, llv { idx = loadRegister(ai->operands[2].mem.index, irb); } + // Maybe we should add +4 to idx? } else if (ai->op_count == 4 && ai->operands[2].type == ARM_OP_MEM) { storeOp(ai->operands[2], op0, irb); + + // We don't use op4 here, post-index offset is applied to source + // address only after the transfers at writeback. + auto op3 = ai->operands[2]; + op3.mem.disp += 4; + storeOp(op3, op1, irb); + baseR = ai->operands[2].mem.base; idx = loadOp(ai->operands[3], irb); subtract = ai->operands[3].subtracted; diff --git a/src/capstone2llvmir/x86/x86.cpp b/src/capstone2llvmir/x86/x86.cpp index 70bfdb589..24688bd41 100644 --- a/src/capstone2llvmir/x86/x86.cpp +++ b/src/capstone2llvmir/x86/x86.cpp @@ -224,7 +224,7 @@ void Capstone2LlvmIrTranslatorX86_impl::generateDataLayout() } case CS_MODE_64: { - _module->setDataLayout("e-i64:64-f80:128-n8:16:32:64-S128"); // clang + _module->setDataLayout("e-m:e-p:64:64-i64:64-f80:128-n8:16:32:64-S128"); // clang break; } default: diff --git a/src/config/architecture.cpp b/src/config/architecture.cpp index 31ef781de..904690bfb 100644 --- a/src/config/architecture.cpp +++ b/src/config/architecture.cpp @@ -13,12 +13,14 @@ namespace { const std::string ARCH_UNKNOWN = "unknown"; const std::string ARCH_MIPS = "mips"; +const std::string ARCH_MIPS64 = "mips64"; const std::string ARCH_PIC32 = "pic32"; const std::string ARCH_ARM = "arm"; const std::string ARCH_ARM64 = "aarch64"; const std::string ARCH_THUMB = "thumb"; const std::string ARCH_x86 = "x86"; const std::string ARCH_PPC = "powerpc"; +const std::string ARCH_PPC64 = "powerpc64"; const std::string JSON_name = "name"; const std::string JSON_endian = "endian"; @@ -42,9 +44,11 @@ bool Architecture::isX86_16() const { return isX86() && getBitSize() == 16; bool Architecture::isX86_32() const { return isX86() && getBitSize() == 32; } bool Architecture::isX86_64() const { return isX86() && getBitSize() == 64; } bool Architecture::isPpc() const { return isArch(eArch::PPC); } +bool Architecture::isPpc64() const { return isPpc() && getBitSize() == 64; } bool Architecture::isKnown() const { return !isUnknown(); } bool Architecture::isUnknown() const { return isArch(eArch::UNKNOWN); } bool Architecture::isMips() const { return isArch(eArch::MIPS); } +bool Architecture::isMips64() const { return isMips() && getBitSize() == 64; } bool Architecture::isMipsOrPic32() const{ return isMips() || isPic32(); } /** @@ -73,6 +77,7 @@ void Architecture::setIsMips() { setName(ARCH_MIPS); } void Architecture::setIsPic32() { setName(ARCH_PIC32); } void Architecture::setIsArm() { setName(ARCH_ARM); } void Architecture::setIsThumb() { setName(ARCH_THUMB); } +void Architecture::setIsArm64() { setName(ARCH_ARM64); } void Architecture::setIsX86() { setName(ARCH_x86); } void Architecture::setIsPpc() { setName(ARCH_PPC); } diff --git a/src/config/calling_convention.cpp b/src/config/calling_convention.cpp index 0f7de479a..60f98926c 100644 --- a/src/config/calling_convention.cpp +++ b/src/config/calling_convention.cpp @@ -46,6 +46,11 @@ CallingConvention::CallingConvention(eCallingConvention cc) : } +CallingConventionID CallingConvention::getID() const +{ + return _callingConvention; +} + CallingConvention CallingConvention::initVoidarg() { return CallingConvention(eCallingConvention::CC_VOIDARG); } CallingConvention CallingConvention::initCdecl() { return CallingConvention(eCallingConvention::CC_CDECL); } CallingConvention CallingConvention::initEllipsis() { return CallingConvention(eCallingConvention::CC_ELLIPSIS); } @@ -132,9 +137,9 @@ bool CallingConvention::operator<(const CallingConvention& cc) const return _callingConvention < cc._callingConvention; } -std::ostream& operator<<(std::ostream &out, const CallingConvention& cc) +std::ostream& operator<<(std::ostream &out, const CallingConventionID& cc) { - switch(cc._callingConvention) + switch(cc) { case CallingConvention::eCallingConvention::CC_UNKNOWN: out << "CC_UNKNOWN"; break; case CallingConvention::eCallingConvention::CC_VOIDARG: out << "CC_VOIDARG"; break; @@ -154,5 +159,12 @@ std::ostream& operator<<(std::ostream &out, const CallingConvention& cc) return out; } +std::ostream& operator<<(std::ostream &out, const CallingConvention& cc) +{ + out << cc._callingConvention; + + return out; +} + } // namespace config } // namespace retdec diff --git a/src/cpdetect/compiler_detector/compiler_detector.cpp b/src/cpdetect/compiler_detector/compiler_detector.cpp index 2e490ccd9..e59dd4a3c 100644 --- a/src/cpdetect/compiler_detector/compiler_detector.cpp +++ b/src/cpdetect/compiler_detector/compiler_detector.cpp @@ -12,6 +12,7 @@ #include "retdec/cpdetect/compiler_detector/compiler_detector.h" #include "retdec/cpdetect/settings.h" #include "retdec/cpdetect/utils/version_solver.h" +#include "yaracpp/yara_detector/yara_detector.h" using namespace retdec::fileformat; using namespace retdec::utils; diff --git a/src/fileformat/CMakeLists.txt b/src/fileformat/CMakeLists.txt index 4313460b4..e876011c2 100644 --- a/src/fileformat/CMakeLists.txt +++ b/src/fileformat/CMakeLists.txt @@ -21,6 +21,9 @@ set(FILEFORMAT_SOURCES types/symbol_table/elf_symbol.cpp types/rich_header/rich_header.cpp types/rich_header/linker_info.cpp + types/visual_basic/visual_basic_info.cpp + types/visual_basic/visual_basic_object.cpp + types/visual_basic/visual_basic_extern.cpp types/import_table/import.cpp types/import_table/import_table.cpp types/import_table/pe_import.cpp diff --git a/src/fileformat/file_format/file_format.cpp b/src/fileformat/file_format/file_format.cpp index fe50fbeaf..c86004182 100644 --- a/src/fileformat/file_format/file_format.cpp +++ b/src/fileformat/file_format/file_format.cpp @@ -1121,7 +1121,13 @@ bool FileFormat::getOffsetFromAddress(unsigned long long &result, unsigned long return false; } - result = secSeg->getOffset() + (address - secSeg->getAddress()); + auto secSegAddr = secSeg->getAddress(); + if (secSegAddr > address) + { + return false; + } + + result = secSeg->getOffset() + (address - secSegAddr); return true; } @@ -1141,7 +1147,13 @@ bool FileFormat::getAddressFromOffset(unsigned long long &result, unsigned long return false; } - result = secSeg->getAddress() + (offset - secSeg->getOffset()); + auto secSegOffset = secSeg->getOffset(); + if (secSegOffset > offset) + { + return false; + } + + result = secSeg->getAddress() + (offset - secSegOffset); return true; } diff --git a/src/fileformat/file_format/pe/pe_format.cpp b/src/fileformat/file_format/pe/pe_format.cpp index 6ac958a3f..85ac6e5ad 100644 --- a/src/fileformat/file_format/pe/pe_format.cpp +++ b/src/fileformat/file_format/pe/pe_format.cpp @@ -18,16 +18,19 @@ #include "retdec/utils/conversion.h" #include "retdec/utils/scope_exit.h" #include "retdec/utils/string.h" +#include "retdec/utils/dynamic_buffer.h" #include "retdec/fileformat/file_format/pe/pe_format.h" #include "retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser32.h" #include "retdec/fileformat/file_format/pe/pe_format_parser/pe_format_parser64.h" #include "retdec/fileformat/types/dotnet_headers/metadata_tables.h" #include "retdec/fileformat/types/dotnet_types/dotnet_type_reconstructor.h" +#include "retdec/fileformat/types/visual_basic/visual_basic_structures.h" #include "retdec/fileformat/utils/asn1.h" #include "retdec/fileformat/utils/conversions.h" #include "retdec/fileformat/utils/file_io.h" #include "retdec/crypto/crypto.h" + using namespace retdec::utils; using namespace PeLib; @@ -425,6 +428,7 @@ void PeFormat::initStructures() loadResources(); loadCertificates(); loadDotnetHeaders(); + loadVisualBasicHeader(); computeSectionTableHashes(); loadStrings(); } @@ -622,6 +626,544 @@ void PeFormat::loadRichHeader() richHeader->setBytes(header.getDecryptedHeaderBytes()); } +/** + * Load visual basic header + */ +void PeFormat::loadVisualBasicHeader() +{ + const auto &allBytes = getBytes(); + std::vector bytes; + unsigned long long version = 0; + unsigned long long vbHeaderAddress = 0; + unsigned long long vbHeaderOffset = 0; + unsigned long long vbProjectInfoOffset = 0; + unsigned long long vbComDataRegistrationOffset = 0; + std::string projLanguageDLL; + std::string projBackupLanguageDLL; + std::string projExeName; + std::string projDesc; + std::string helpFile; + std::string projName; + std::size_t offset = 0; + struct VBHeader vbh; + + if (!isVisualBasic(version)) + { + return; + } + + // first instruction is expected to be PUSH (0x68 ) + if (!getEpBytes(bytes, 5) || bytes.size() != 5 || bytes[0] != 0x68) + { + return; + } + + vbHeaderAddress = bytes[4] << 24 | bytes[3] << 16 | bytes[2] << 8 | bytes[1]; + if (!getOffsetFromAddress(vbHeaderOffset, vbHeaderAddress)) + { + return; + } + + if (!getBytes(bytes, vbHeaderOffset, vbh.structureSize()) || bytes.size() != vbh.structureSize()) + { + return; + } + + DynamicBuffer structContent(bytes, retdec::utils::Endianness::LITTLE); + vbh.signature = structContent.read(offset); offset += sizeof(vbh.signature); + vbh.runtimeBuild = structContent.read(offset); offset += sizeof(vbh.runtimeBuild); + std::memcpy(&vbh.languageDLL, static_cast(&bytes.data()[offset]), sizeof(vbh.languageDLL)); offset += sizeof(vbh.languageDLL); + std::memcpy(&vbh.backupLanguageDLL, static_cast(&bytes.data()[offset]), sizeof(vbh.backupLanguageDLL)); offset += sizeof(vbh.backupLanguageDLL); + vbh.runtimeDLLVersion = structContent.read(offset); offset += sizeof(vbh.runtimeDLLVersion); + vbh.LCID1 = structContent.read(offset); offset += sizeof(vbh.LCID1); + vbh.LCID2 = structContent.read(offset); offset += sizeof(vbh.LCID2); + vbh.subMainAddr = structContent.read(offset); offset += sizeof(vbh.subMainAddr); + vbh.projectInfoAddr = structContent.read(offset); offset += sizeof(vbh.projectInfoAddr); + vbh.MDLIntObjsFlags = structContent.read(offset); offset += sizeof(vbh.MDLIntObjsFlags); + vbh.MDLIntObjsFlags2 = structContent.read(offset); offset += sizeof(vbh.MDLIntObjsFlags2); + vbh.threadFlags = structContent.read(offset); offset += sizeof(vbh.threadFlags); + vbh.nThreads = structContent.read(offset); offset += sizeof(vbh.nThreads); + vbh.nForms = structContent.read(offset); offset += sizeof(vbh.nForms); + vbh.nExternals = structContent.read(offset); offset += sizeof(vbh.nExternals); + vbh.nThunks = structContent.read(offset); offset += sizeof(vbh.nThunks); + vbh.GUITableAddr = structContent.read(offset); offset += sizeof(vbh.GUITableAddr); + vbh.externalTableAddr = structContent.read(offset); offset += sizeof(vbh.externalTableAddr); + vbh.COMRegisterDataAddr = structContent.read(offset); offset += sizeof(vbh.COMRegisterDataAddr); + vbh.projExeNameOffset = structContent.read(offset); offset += sizeof(vbh.projExeNameOffset); + vbh.projDescOffset = structContent.read(offset); offset += sizeof(vbh.projDescOffset); + vbh.helpFileOffset = structContent.read(offset); offset += sizeof(vbh.helpFileOffset); + vbh.projNameOffset = structContent.read(offset); offset += sizeof(vbh.projNameOffset); + + if (vbh.signature != VBHEADER_SIGNATURE) + { + return; + } + + if (vbh.projExeNameOffset != 0) + { + projExeName = retdec::utils::readNullTerminatedAscii(allBytes.data(), allBytes.size(), + vbHeaderOffset + vbh.projExeNameOffset, VB_MAX_STRING_LEN, true); + visualBasicInfo.setProjectExeName(projExeName); + } + if (vbh.projDescOffset != 0) + { + projDesc = retdec::utils::readNullTerminatedAscii(allBytes.data(), allBytes.size(), + vbHeaderOffset + vbh.projDescOffset, VB_MAX_STRING_LEN, true); + visualBasicInfo.setProjectDescription(projDesc); + } + if (vbh.helpFileOffset != 0) + { + helpFile = retdec::utils::readNullTerminatedAscii(allBytes.data(), allBytes.size(), + vbHeaderOffset + vbh.helpFileOffset, VB_MAX_STRING_LEN, true); + visualBasicInfo.setProjectHelpFile(helpFile); + } + if (vbh.projNameOffset != 0) + { + projName = retdec::utils::readNullTerminatedAscii(allBytes.data(), allBytes.size(), + vbHeaderOffset + vbh.projNameOffset, VB_MAX_STRING_LEN, true); + visualBasicInfo.setProjectName(projName); + } + + for (size_t i = 0; i < sizeof(vbh.languageDLL) && vbh.languageDLL[i]; i++) + { + projLanguageDLL.push_back(vbh.languageDLL[i]); + } + for (size_t i = 0; i < sizeof(vbh.backupLanguageDLL) && vbh.backupLanguageDLL[i]; i++) + { + projBackupLanguageDLL.push_back(vbh.backupLanguageDLL[i]); + } + visualBasicInfo.setLanguageDLL(projLanguageDLL); + visualBasicInfo.setBackupLanguageDLL(projBackupLanguageDLL); + visualBasicInfo.setLanguageDLLPrimaryLCID(vbh.LCID1); + visualBasicInfo.setLanguageDLLSecondaryLCID(vbh.LCID2); + + + if (getOffsetFromAddress(vbProjectInfoOffset, vbh.projectInfoAddr)) + { + parseVisualBasicProjectInfo(vbProjectInfoOffset); + } + + if (getOffsetFromAddress(vbComDataRegistrationOffset, vbh.COMRegisterDataAddr)) + { + parseVisualBasicComRegistrationData(vbComDataRegistrationOffset); + } +} + +/** + * Parse visual basic COM registration data + * @param structureOffset Offset in file where the structure starts + * @return @c true if COM registration data was successfuly parsed, @c false otherwise + */ +bool PeFormat::parseVisualBasicComRegistrationData(std::size_t structureOffset) +{ + const auto &allBytes = getBytes(); + std::vector bytes; + std::size_t offset = 0; + struct VBCOMRData vbcrd; + std::string projName; + std::string helpFile; + std::string projDesc; + + if (!getBytes(bytes, structureOffset, vbcrd.structureSize()) || bytes.size() != vbcrd.structureSize()) + { + return false; + } + + DynamicBuffer structContent(bytes, retdec::utils::Endianness::LITTLE); + vbcrd.regInfoOffset = structContent.read(offset); offset += sizeof(vbcrd.regInfoOffset); + vbcrd.projNameOffset = structContent.read(offset); offset += sizeof(vbcrd.projNameOffset); + vbcrd.helpFileOffset = structContent.read(offset); offset += sizeof(vbcrd.helpFileOffset); + vbcrd.projDescOffset = structContent.read(offset); offset += sizeof(vbcrd.projDescOffset); + std::memcpy(&vbcrd.projCLSID, static_cast(&bytes.data()[offset]), sizeof(vbcrd.projCLSID)); offset += sizeof(vbcrd.projCLSID); + vbcrd.projTlbLCID = structContent.read(offset); offset += sizeof(vbcrd.projTlbLCID); + vbcrd.unknown = structContent.read(offset); offset += sizeof(vbcrd.unknown); + vbcrd.tlbVerMajor = structContent.read(offset); offset += sizeof(vbcrd.tlbVerMajor); + vbcrd.tlbVerMinor = structContent.read(offset); offset += sizeof(vbcrd.tlbVerMinor); + + visualBasicInfo.setTypeLibLCID(vbcrd.projTlbLCID); + visualBasicInfo.setTypeLibMajorVersion(vbcrd.tlbVerMajor); + visualBasicInfo.setTypeLibMinorVersion(vbcrd.tlbVerMinor); + + if (!visualBasicInfo.hasProjectName() && vbcrd.projNameOffset != 0) + { + projName = retdec::utils::readNullTerminatedAscii(allBytes.data(), allBytes.size(), + structureOffset + vbcrd.projNameOffset, VB_MAX_STRING_LEN, true); + } + if (!visualBasicInfo.hasProjectHelpFile() && vbcrd.helpFileOffset != 0) + { + helpFile = retdec::utils::readNullTerminatedAscii(allBytes.data(), allBytes.size(), + structureOffset + vbcrd.helpFileOffset, VB_MAX_STRING_LEN, true); + } + if (!visualBasicInfo.hasProjectDescription() && vbcrd.projDescOffset != 0) + { + projDesc = retdec::utils::readNullTerminatedAscii(allBytes.data(), allBytes.size(), + structureOffset + vbcrd.projDescOffset, VB_MAX_STRING_LEN, true); + } + + visualBasicInfo.setTypeLibCLSID(vbcrd.projCLSID); + + if (vbcrd.regInfoOffset != 0) + { + parseVisualBasicComRegistrationInfo(structureOffset + vbcrd.regInfoOffset, structureOffset); + } + + return true; +} + +/** + * Parse visual basic COM registration info + * @param structureOffset Offset in file where the structure starts + * @param comRegDataOffset Offset in file where the com registration data structure starts + * @return @c true if COM registration info was successfuly parsed, @c false otherwise + */ +bool PeFormat::parseVisualBasicComRegistrationInfo(std::size_t structureOffset, + std::size_t comRegDataOffset) +{ + const auto &allBytes = getBytes(); + std::vector bytes; + std::size_t offset = 0; + struct VBCOMRInfo vbcri; + std::string COMObjectName; + std::string COMObjectDesc; + + if (!getBytes(bytes, structureOffset, vbcri.structureSize()) || bytes.size() != vbcri.structureSize()) + { + return false; + } + + DynamicBuffer structContent(bytes, retdec::utils::Endianness::LITTLE); + vbcri.ifInfoOffset = structContent.read(offset); offset += sizeof(vbcri.ifInfoOffset); + vbcri.objNameOffset = structContent.read(offset); offset += sizeof(vbcri.objNameOffset); + vbcri.objDescOffset = structContent.read(offset); offset += sizeof(vbcri.objDescOffset); + vbcri.instancing = structContent.read(offset); offset += sizeof(vbcri.instancing); + vbcri.objID = structContent.read(offset); offset += sizeof(vbcri.objID); + std::memcpy(&vbcri.objCLSID, static_cast(&bytes.data()[offset]), sizeof(vbcri.objCLSID)); offset += sizeof(vbcri.objCLSID); + vbcri.isInterfaceFlag = structContent.read(offset); offset += sizeof(vbcri.isInterfaceFlag); + vbcri.ifCLSIDOffset = structContent.read(offset); offset += sizeof(vbcri.ifCLSIDOffset); + vbcri.eventCLSIDOffset = structContent.read(offset); offset += sizeof(vbcri.eventCLSIDOffset); + vbcri.hasEvents = structContent.read(offset); offset += sizeof(vbcri.hasEvents); + vbcri.olemicsFlags = structContent.read(offset); offset += sizeof(vbcri.olemicsFlags); + vbcri.classType = structContent.read(offset); offset += sizeof(vbcri.classType); + vbcri.objectType = structContent.read(offset); offset += sizeof(vbcri.objectType); + vbcri.toolboxBitmap32 = structContent.read(offset); offset += sizeof(vbcri.toolboxBitmap32); + vbcri.defaultIcon = structContent.read(offset); offset += sizeof(vbcri.defaultIcon); + vbcri.isDesignerFlag = structContent.read(offset); offset += sizeof(vbcri.isDesignerFlag); + vbcri.designerDataOffset = structContent.read(offset); offset += sizeof(vbcri.designerDataOffset); + + if (vbcri.objNameOffset != 0) + { + COMObjectName = retdec::utils::readNullTerminatedAscii(allBytes.data(), allBytes.size(), + comRegDataOffset + vbcri.objNameOffset, VB_MAX_STRING_LEN, true); + visualBasicInfo.setCOMObjectName(COMObjectName); + } + if (vbcri.objDescOffset != 0) + { + COMObjectDesc = retdec::utils::readNullTerminatedAscii(allBytes.data(), allBytes.size(), + comRegDataOffset + vbcri.objDescOffset, VB_MAX_STRING_LEN, true); + visualBasicInfo.setCOMObjectDescription(COMObjectDesc); + } + + visualBasicInfo.setCOMObjectCLSID(vbcri.objCLSID); + visualBasicInfo.setCOMObjectType(vbcri.objectType); + + if (vbcri.isInterfaceFlag != 0 && vbcri.ifCLSIDOffset != 0 && + getBytes(bytes, comRegDataOffset + vbcri.ifCLSIDOffset, 16) && bytes.size() == 16) + { + visualBasicInfo.setCOMObjectInterfaceCLSID(bytes.data()); + } + + if (vbcri.hasEvents != 0 && vbcri.eventCLSIDOffset != 0 && + getBytes(bytes, comRegDataOffset + vbcri.eventCLSIDOffset, 16) && bytes.size() == 16) + { + visualBasicInfo.setCOMObjectEventsCLSID(bytes.data()); + } + + return true; +} + +/** + * Parse visual basic project info + * @param structureOffset Offset in file where the structure starts + * @return @c true if project info was successfuly parsed, @c false otherwise + */ +bool PeFormat::parseVisualBasicProjectInfo(std::size_t structureOffset) +{ + std::vector bytes; + unsigned long long vbExternTableOffset = 0; + unsigned long long vbObjectTableOffset = 0; + std::string projPath; + std::size_t offset = 0; + struct VBProjInfo vbpi; + + if (!getBytes(bytes, structureOffset, vbpi.structureSize()) || bytes.size() != vbpi.structureSize()) + { + return false; + } + + DynamicBuffer structContent(bytes, retdec::utils::Endianness::LITTLE); + vbpi.version = structContent.read(offset); offset += sizeof(vbpi.version); + vbpi.objectTableAddr = structContent.read(offset); offset += sizeof(vbpi.objectTableAddr); + vbpi.null = structContent.read(offset); offset += sizeof(vbpi.null); + vbpi.codeStartAddr = structContent.read(offset); offset += sizeof(vbpi.codeStartAddr); + vbpi.codeEndAddr = structContent.read(offset); offset += sizeof(vbpi.codeEndAddr); + vbpi.dataSize = structContent.read(offset); offset += sizeof(vbpi.dataSize); + vbpi.threadSpaceAddr = structContent.read(offset); offset += sizeof(vbpi.threadSpaceAddr); + vbpi.exHandlerAddr = structContent.read(offset); offset += sizeof(vbpi.exHandlerAddr); + vbpi.nativeCodeAddr = structContent.read(offset); offset += sizeof(vbpi.nativeCodeAddr); + std::memcpy(&vbpi.pathInformation, static_cast(&bytes.data()[offset]), sizeof(vbpi.pathInformation)); offset += sizeof(vbpi.pathInformation); + vbpi.externalTableAddr = structContent.read(offset); offset += sizeof(vbpi.externalTableAddr); + vbpi.nExternals = structContent.read(offset); offset += sizeof(vbpi.nExternals); + + projPath = retdec::utils::unicodeToAscii(vbpi.pathInformation, sizeof(vbpi.pathInformation)); + visualBasicInfo.setProjectPath(projPath); + visualBasicInfo.setPcode(vbpi.nativeCodeAddr == 0); + + if (getOffsetFromAddress(vbExternTableOffset, vbpi.externalTableAddr)) + { + parseVisualBasicExternTable(vbExternTableOffset, vbpi.nExternals); + } + + if (getOffsetFromAddress(vbObjectTableOffset, vbpi.objectTableAddr)) + { + parseVisualBasicObjectTable(vbObjectTableOffset); + } + + return true; +} + +/** + * Parse visual basic extern table + * @param structureOffset Offset in file where the structure starts + * @param nEntries Number of entries in table + * @return @c true if extern table was successfuly parsed, @c false otherwise + */ +bool PeFormat::parseVisualBasicExternTable(std::size_t structureOffset, std::size_t nEntries) +{ + const auto &allBytes = getBytes(); + std::vector bytes; + struct VBExternTableEntry entry; + struct VBExternTableEntryData entryData; + unsigned long long vbExternEntryDataOffset = 0; + std::size_t offset = 0; + + for (std::size_t i = 0; i < nEntries; i++) + { + std::string moduleName; + std::string apiName; + + if (!getBytes(bytes, structureOffset + i * entry.structureSize(), entry.structureSize()) + || bytes.size() != entry.structureSize()) + { + break; + } + + offset = 0; + DynamicBuffer entryContent(bytes, retdec::utils::Endianness::LITTLE); + entry.type = entryContent.read(offset); offset += sizeof(entry.type); + entry.importDataAddr = entryContent.read(offset); offset += sizeof(entry.importDataAddr); + + if (entry.type != static_cast(VBExternTableEntryType::external)) + { + continue; + } + + if (!getOffsetFromAddress(vbExternEntryDataOffset, entry.importDataAddr)) + { + continue; + } + + if (!getBytes(bytes, vbExternEntryDataOffset, entryData.structureSize()) + || bytes.size() != entryData.structureSize()) + { + continue; + } + + offset = 0; + DynamicBuffer entryDataContent(bytes, retdec::utils::Endianness::LITTLE); + entryData.moduleNameAddr = entryDataContent.read(offset); offset += sizeof(entryData.moduleNameAddr); + entryData.apiNameAddr = entryDataContent.read(offset); offset += sizeof(entryData.apiNameAddr); + + unsigned long long moduleNameOffset; + if (getOffsetFromAddress(moduleNameOffset, entryData.moduleNameAddr)) + { + moduleName = retdec::utils::readNullTerminatedAscii(allBytes.data(), allBytes.size(), + moduleNameOffset, VB_MAX_STRING_LEN, true); + } + + unsigned long long apiNameOffset; + if (getOffsetFromAddress(apiNameOffset, entryData.apiNameAddr)) + { + apiName = retdec::utils::readNullTerminatedAscii(allBytes.data(), allBytes.size(), + apiNameOffset, VB_MAX_STRING_LEN, true); + } + + if (!moduleName.empty() || !apiName.empty()) + { + auto ext = std::make_unique(); + ext->setModuleName(moduleName); + ext->setApiName(apiName); + visualBasicInfo.addExtern(std::move(ext)); + } + } + + visualBasicInfo.computeExternTableHashes(); + + return true; +} + +/** + * Parse visual basic object table + * @param structureOffset Offset in file where the structure starts + * @return @c true if object table was successfuly parsed, @c false otherwise + */ +bool PeFormat::parseVisualBasicObjectTable(std::size_t structureOffset) +{ + const auto &allBytes = getBytes(); + std::vector bytes; + std::size_t offset = 0; + unsigned long long projectNameOffset = 0; + unsigned long long objectDescriptorsOffset = 0; + struct VBObjectTable vbot; + std::string projName; + + if (!getBytes(bytes, structureOffset, vbot.structureSize()) || bytes.size() != vbot.structureSize()) + { + return false; + } + + DynamicBuffer structContent(bytes, retdec::utils::Endianness::LITTLE); + vbot.null1 = structContent.read(offset); offset += sizeof(vbot.null1); + vbot.execCOMAddr = structContent.read(offset); offset += sizeof(vbot.execCOMAddr); + vbot.projecInfo2Addr = structContent.read(offset); offset += sizeof(vbot.projecInfo2Addr); + vbot.reserved = structContent.read(offset); offset += sizeof(vbot.reserved); + vbot.null2 = structContent.read(offset); offset += sizeof(vbot.null2); + vbot.projectObjectAddr = structContent.read(offset); offset += sizeof(vbot.projectObjectAddr); + std::memcpy(&vbot.objectGUID, static_cast(&bytes.data()[offset]), sizeof(vbot.objectGUID)); offset += sizeof(vbot.objectGUID); + vbot.flagsCompileState = structContent.read(offset); offset += sizeof(vbot.flagsCompileState); + vbot.nObjects = structContent.read(offset); offset += sizeof(vbot.nObjects); + vbot.nCompiledObjects = structContent.read(offset); offset += sizeof(vbot.nCompiledObjects); + vbot.nUsedObjects = structContent.read(offset); offset += sizeof(vbot.nUsedObjects); + vbot.objectDescriptorsAddr = structContent.read(offset); offset += sizeof(vbot.objectDescriptorsAddr); + vbot.IDE1 = structContent.read(offset); offset += sizeof(vbot.IDE1); + vbot.IDE2 = structContent.read(offset); offset += sizeof(vbot.IDE2); + vbot.IDE3 = structContent.read(offset); offset += sizeof(vbot.IDE3); + vbot.projectNameAddr = structContent.read(offset); offset += sizeof(vbot.projectNameAddr); + vbot.LCID1 = structContent.read(offset); offset += sizeof(vbot.LCID1); + vbot.LCID2 = structContent.read(offset); offset += sizeof(vbot.LCID2); + vbot.IDE4 = structContent.read(offset); offset += sizeof(vbot.IDE4); + vbot.templateVesion = structContent.read(offset); offset += sizeof(vbot.templateVesion); + + visualBasicInfo.setProjectPrimaryLCID(vbot.LCID1); + visualBasicInfo.setProjectSecondaryLCID(vbot.LCID2); + visualBasicInfo.setObjectTableGUID(vbot.objectGUID); + + if (!visualBasicInfo.hasProjectName() && getOffsetFromAddress(projectNameOffset, vbot.projectNameAddr)) + { + projName = retdec::utils::readNullTerminatedAscii(allBytes.data(), allBytes.size(), projectNameOffset, + VB_MAX_STRING_LEN, true); + visualBasicInfo.setProjectName(projName); + } + + if (getOffsetFromAddress(objectDescriptorsOffset, vbot.objectDescriptorsAddr)) + { + parseVisualBasicObjects(objectDescriptorsOffset, vbot.nObjects); + } + + visualBasicInfo.computeObjectTableHashes(); + return true; +} + +/** + * Parse visual basic objects + * @param structureOffset Offset in file where the public object descriptors array starts + * @param nObjects Number of objects in array + * @return @c true if objects were successfuly parsed, @c false otherwise + */ +bool PeFormat::parseVisualBasicObjects(std::size_t structureOffset, std::size_t nObjects) +{ + const auto &allBytes = getBytes(); + std::vector bytes; + struct VBPublicObjectDescriptor vbpod; + std::size_t offset = 0; + + for (std::size_t i = 0; i < nObjects; i++) + { + std::unique_ptr object; + if (!getBytes(bytes, structureOffset + i * vbpod.structureSize(), vbpod.structureSize()) + || bytes.size() != vbpod.structureSize()) + { + break; + } + + offset = 0; + DynamicBuffer structContent(bytes, retdec::utils::Endianness::LITTLE); + vbpod.objectInfoAddr = structContent.read(offset); offset += sizeof(vbpod.objectInfoAddr); + vbpod.reserved = structContent.read(offset); offset += sizeof(vbpod.reserved); + vbpod.publicBytesAddr = structContent.read(offset); offset += sizeof(vbpod.publicBytesAddr); + vbpod.staticBytesAddr = structContent.read(offset); offset += sizeof(vbpod.staticBytesAddr); + vbpod.modulePublicAddr = structContent.read(offset); offset += sizeof(vbpod.modulePublicAddr); + vbpod.moduleStaticAddr = structContent.read(offset); offset += sizeof(vbpod.moduleStaticAddr); + vbpod.objectNameAddr = structContent.read(offset); offset += sizeof(vbpod.objectNameAddr); + vbpod.nMethods = structContent.read(offset); offset += sizeof(vbpod.nMethods); + vbpod.methodNamesAddr = structContent.read(offset); offset += sizeof(vbpod.methodNamesAddr); + vbpod.staticVarsCopyAddr = structContent.read(offset); offset += sizeof(vbpod.staticVarsCopyAddr); + vbpod.objectType = structContent.read(offset); offset += sizeof(vbpod.objectType); + vbpod.null = structContent.read(offset); offset += sizeof(vbpod.null); + + unsigned long long objectNameOffset; + if (!getOffsetFromAddress(objectNameOffset, vbpod.objectNameAddr)) + { + continue; + } + + std::string objectName = readNullTerminatedAscii(allBytes.data(), allBytes.size(), objectNameOffset, + VB_MAX_STRING_LEN, true); + object = std::make_unique(); + object->setName(objectName); + + unsigned long long methodAddrOffset; + if (getOffsetFromAddress(methodAddrOffset, vbpod.methodNamesAddr)) + { + for (std::size_t mIdx = 0; mIdx < vbpod.nMethods; mIdx++) + { + if (!getBytes(bytes, methodAddrOffset + mIdx * sizeof(std::uint32_t), sizeof(std::uint32_t)) + || bytes.size() != sizeof(std::uint32_t)) + { + break; + } + + auto methodNameAddr = *reinterpret_cast(bytes.data()); + + if (!isLittleEndian()) + { + methodNameAddr = byteSwap32(methodNameAddr); + } + + unsigned long long methodNameOffset; + if (!getOffsetFromAddress(methodNameOffset, methodNameAddr)) + { + continue; + } + + std::string methodName = readNullTerminatedAscii(allBytes.data(), allBytes.size(), + methodNameOffset, VB_MAX_STRING_LEN, true); + + if (!methodName.empty()) + { + object->addMethod(methodName); + } + } + } + + if (!objectName.empty() || object->getNumberOfMethods() > 0) + { + visualBasicInfo.addObject(std::move(object)); + } + } + + return true; +} + /** * Load information about sections */ @@ -2738,7 +3280,6 @@ const std::vector>& PeFormat::getImportedDotnetClas return importedClasses; } - const std::string& PeFormat::getTypeRefhashCrc32() const { return typeRefHashCrc32; @@ -2754,5 +3295,10 @@ const std::string& PeFormat::getTypeRefhashSha256() const return typeRefHashSha256; } +const VisualBasicInfo* PeFormat::getVisualBasicInfo() const +{ + return &visualBasicInfo; +} + } // namespace fileformat } // namespace retdec diff --git a/src/fileformat/types/visual_basic/visual_basic_extern.cpp b/src/fileformat/types/visual_basic/visual_basic_extern.cpp new file mode 100644 index 000000000..59a04b54d --- /dev/null +++ b/src/fileformat/types/visual_basic/visual_basic_extern.cpp @@ -0,0 +1,66 @@ +/** + * @file src/fileformat/types/visual_basic/visual_basic_extern.cpp + * @brief Class visual basic extern. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/fileformat/types/visual_basic/visual_basic_extern.h" + +namespace retdec { +namespace fileformat { + +/** + * Constructor + */ +VisualBasicExtern::VisualBasicExtern() +{ + +} + +/** + * Destructor + */ +VisualBasicExtern::~VisualBasicExtern() +{ + +} + +/** + * Get module name + * @return Module name + */ +const std::string &VisualBasicExtern::getModuleName() const +{ + return moduleName; +} + +/** + * Get api name + * @return Api name + */ +const std::string &VisualBasicExtern::getApiName() const +{ + return apiName; +} + +/** + * Set module name + * @param mName Module name to set + */ +void VisualBasicExtern::setModuleName(const std::string &mName) +{ + moduleName = mName; +} + +/** + * Set api name + * @param aName Api name to set + */ +void VisualBasicExtern::setApiName(const std::string &aName) +{ + apiName = aName; +} + + +} // namespace fileformat +} // namespace retdec diff --git a/src/fileformat/types/visual_basic/visual_basic_info.cpp b/src/fileformat/types/visual_basic/visual_basic_info.cpp new file mode 100644 index 000000000..408864ecf --- /dev/null +++ b/src/fileformat/types/visual_basic/visual_basic_info.cpp @@ -0,0 +1,773 @@ +/** + * @file src/fileformat/types/visual_basic/visual_basic_info.cpp + * @brief Class visual basic information. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/crypto/crypto.h" +#include "retdec/utils/string.h" +#include "retdec/utils/system.h" +#include "retdec/utils/conversion.h" +#include "retdec/fileformat/types/visual_basic/visual_basic_info.h" + + +using namespace retdec::utils; + +namespace retdec { +namespace fileformat { + +/** + * Constructor + */ +VisualBasicInfo::VisualBasicInfo() : languageDLLPrimaryLCID(0), languageDLLSecondaryLCID(0), + projectPrimaryLCID(0), projectSecondaryLCID(0), typeLibLCID(0), typeLibMajorVersion(0), + typeLibMinorVersion(0), validLanguageDLLPrimaryLCID(false), validLanguageDLLSecondaryLCID(false), + validProjectPrimaryLCID(false), validProjectSecondaryLCID(false), validTypeLibLCID(false), + validTypeLibMajorVersion(false), validTypeLibMinorVersion(false), pcodeFlag(false) +{ + +} + +/** + * Destructor + */ +VisualBasicInfo::~VisualBasicInfo() +{ + +} + +/** + * Get language DLL + * @return language DLL + */ +const std::string &VisualBasicInfo::getLanguageDLL() const +{ + return languageDLL; +} + +/** + * Get backup language DLL + * @return backup language DLL + */ +const std::string &VisualBasicInfo::getBackupLanguageDLL() const +{ + return backupLanguageDLL; +} + +/** + * Get project exe name + * @return project exe name + */ +const std::string &VisualBasicInfo::getProjectExeName() const +{ + return projectExeName; +} + +/** + * Get project description + * @return project description + */ +const std::string &VisualBasicInfo::getProjectDescription() const +{ + return projectDescription; +} + +/** + * Get project help file + * @return project help file + */ +const std::string &VisualBasicInfo::getProjectHelpFile() const +{ + return projectHelpFile; +} + +/** + * Get project name + * @return project name + */ +const std::string &VisualBasicInfo::getProjectName() const +{ + return projectName; +} + +/** + * Get language DLL primary LCID + * @param res Variable to store the result to + * @return @c true if language DLL primary LCID is valid, @c false otherwise + */ +bool VisualBasicInfo::getLanguageDLLPrimaryLCID(std::uint32_t &res) const +{ + if (!validLanguageDLLPrimaryLCID) + { + return false; + } + res = languageDLLPrimaryLCID; + return true; +} +/** + * Get language DLL secondary LCID + * @param res Variable to store the result to + * @return @c true if language DLL secondary LCID is valid, @c false otherwise + */ +bool VisualBasicInfo::getLanguageDLLSecondaryLCID(std::uint32_t &res) const +{ + if (!validLanguageDLLSecondaryLCID) + { + return false; + } + res = languageDLLSecondaryLCID; + return true; +} + +/** + * Get project path + * @return project path + */ +const std::string &VisualBasicInfo::getProjectPath() const +{ + return projectPath; +} + +/** + * Get project primary LCID + * @param res Variable to store the result to + * @return @c true if project primary LCID is valid, @c false otherwise + */ +bool VisualBasicInfo::getProjectPrimaryLCID(std::uint32_t &res) const +{ + if (!validProjectPrimaryLCID) + { + return false; + } + res = projectPrimaryLCID; + return true; +} + +/** + * Get project secondary LCID + * @param res Variable to store the result to + * @return @c true if project secondary LCID is valid, @c false otherwise + */ +bool VisualBasicInfo::getProjectSecondaryLCID(std::uint32_t &res) const +{ + if (!validProjectSecondaryLCID) + { + return false; + } + res = projectSecondaryLCID; + return true; +} + +/** + * Get objects + * @return Visual basic objects + */ +const std::vector> &VisualBasicInfo::getObjects() const +{ + return objects; +} + +/** + * Get externs + * @return Visual basic externs + */ +const std::vector> &VisualBasicInfo::getExterns() const +{ + return externs; +} + +/** + * Get object + * @param position Index of selected visual basic object (indexed from 0) + * @return Visual basic object + */ +const VisualBasicObject *VisualBasicInfo::getObject(std::size_t position) const +{ + return (position < objects.size()) ? objects[position].get() : nullptr; +} + +/** + * Get extern + * @param position Index of selected visual basic extern (indexed from 0) + * @return Visual basic extern + */ +const VisualBasicExtern *VisualBasicInfo::getExtern(std::size_t position) const +{ + return (position < externs.size()) ? externs[position].get() : nullptr; +} + +/** + * Get number of objects + * @return Number of objects + */ +size_t VisualBasicInfo::getNumberOfObjects() const +{ + return objects.size(); +} + +/** + * Get number of externs + * @return Number of externs + */ +size_t VisualBasicInfo::getNumberOfExterns() const +{ + return externs.size(); +} + +/** + * Get object table GUID + * @return Object table GUID as string + */ +const std::string &VisualBasicInfo::getObjectTableGUID() const +{ + return objectTableGUID; +} + +/** + * Get typeLib CLSID + * @return typeLib CLSID as string + */ +const std::string &VisualBasicInfo::getTypeLibCLSID() const +{ + return typeLibCLSID; +} + +/** + * Get typeLib LCID + * @param res Variable to store the result to + * @return @c true if typeLib LCID is valid, @c false otherwise + */ +bool VisualBasicInfo::getTypeLibLCID(std::uint32_t &res) const +{ + if (!validTypeLibLCID) + { + return false; + } + res = typeLibLCID; + return true; +} + +/** + * Get typeLib major version + * @param res Variable to store result to + * @return @c true if typeLib major version is valid, @c false otherwise + */ +bool VisualBasicInfo::getTypeLibMajorVersion(std::uint16_t &res) const +{ + if (!validTypeLibMajorVersion) + { + return false; + } + res = typeLibMajorVersion; + return true; +} + +/** + * Get typeLib minor version + * @param res Variable to store result to + * @return @c true if typeLib minor version is valid, @c false otherwise + */ +bool VisualBasicInfo::getTypeLibMinorVersion(std::uint16_t &res) const +{ + if (!validTypeLibMinorVersion) + { + return false; + } + res = typeLibMinorVersion; + return true; +} + +/** + * Get COM object name + * @return COM object name + */ +const std::string &VisualBasicInfo::getCOMObjectName() const +{ + return COMObjectName; +} + +/** + * Get COM object description + * @return COM object description + */ +const std::string &VisualBasicInfo::getCOMObjectDescription() const +{ + return COMObjectDescription; +} + +/** + * Get COM object CLSID + * @return COM object CLSID + */ +const std::string &VisualBasicInfo::getCOMObjectCLSID() const +{ + return COMObjectCLSID; +} + +/** + * Get COM object interface CLSID + * @return COM object interface CLSID + */ +const std::string &VisualBasicInfo::getCOMObjectInterfaceCLSID() const +{ + return COMObjectInterfaceCLSID; +} + +/** + * Get COM object events CLSID + * @return COM object events CLSID + */ +const std::string &VisualBasicInfo::getCOMObjectEventsCLSID() const +{ + return COMObjectEventsCLSID; +} + +/** + * Get COM object type + * @return COM object type + */ +const std::string &VisualBasicInfo::getCOMObjectType() const +{ + return COMObjectType; +} + +/** + * Get extern table hash as CRC32 + * @return Extern table hash + */ +const std::string &VisualBasicInfo::getExternTableHashCrc32() const +{ + return externTableHashCrc32; +} + +/** + * Get extern table hash as MD5 + * @return Extern table hash + */ +const std::string &VisualBasicInfo::getExternTableHashMd5() const +{ + return externTableHashMd5; +} + +/** + * Get extern table hash as SHA256 + * @return Extern table hash + */ +const std::string &VisualBasicInfo::getExternTableHashSha256() const +{ + return externTableHashSha256; +} + +/** + * Get object table hash as CRC32 + * @return Object table hash + */ +const std::string &VisualBasicInfo::getObjectTableHashCrc32() const +{ + return objectTableHashCrc32; +} + +/** + * Get object table hash as MD5 + * @return Object table hash + */ +const std::string &VisualBasicInfo::getObjectTableHashMd5() const +{ + return objectTableHashMd5; +} + +/** + * Get object table hash as SHA256 + * @return Object table hash + */ +const std::string &VisualBasicInfo::getObjectTableHashSha256() const +{ + return objectTableHashSha256; +} + +/** + * Set language DLL + * @param lDLL Language DLL to set + */ +void VisualBasicInfo::setLanguageDLL(const std::string &lDLL) +{ + languageDLL = lDLL; +} + +/** + * Set backup language DLL + * @param blDLL Backup language DLL to set + */ +void VisualBasicInfo::setBackupLanguageDLL(const std::string &blDLL) +{ + backupLanguageDLL = blDLL; +} + +/** + * Set project exe name + * @param exeName Project exe name to set + */ +void VisualBasicInfo::setProjectExeName(const std::string &exeName) +{ + projectExeName = exeName; +} + +/** + * Set project description + * @param desc Project description to set + */ +void VisualBasicInfo::setProjectDescription(const std::string &desc) +{ + projectDescription = desc; +} + +/** + * Set project help file + * @param helpFile Project help file to set + */ +void VisualBasicInfo::setProjectHelpFile(const std::string &helpFile) +{ + projectHelpFile = helpFile; +} + +/** + * Set project name + * @param name Project name to set + */ +void VisualBasicInfo::setProjectName(const std::string &name) +{ + projectName = name; +} + +/** + * Set language DLL primary LCID + * @param lDLLPrimLCID Language DLL primary LCID to set + */ +void VisualBasicInfo::setLanguageDLLPrimaryLCID(std::uint32_t lDLLPrimLCID) +{ + languageDLLPrimaryLCID = lDLLPrimLCID; + validLanguageDLLPrimaryLCID = true; +} + +/** + * Set language DLL secondary LCID + * @param lDLLSecLCID Language DLL secondary LCID to set + */ +void VisualBasicInfo::setLanguageDLLSecondaryLCID(std::uint32_t lDLLSecLCID) +{ + languageDLLSecondaryLCID = lDLLSecLCID; + validLanguageDLLSecondaryLCID = true; +} + +/** + * Set project path + * @param path Project path to set + */ +void VisualBasicInfo::setProjectPath(const std::string &path) +{ + const std::string prefix = "*\\A"; + + if (prefix.size() > path.size()) + { + projectPath = path; + } + else + { + auto res = std::mismatch(prefix.begin(), prefix.end(), path.begin()); + if (res.first == prefix.end()) + { + projectPath = path.substr(prefix.size(), path.size() - prefix.size()); + } + else + { + projectPath = path; + } + } +} + +/** + * Set project primary LCID + * @param primLCID Project primary LCID to set + */ +void VisualBasicInfo::setProjectPrimaryLCID(std::uint32_t primLCID) +{ + projectPrimaryLCID = primLCID; + validProjectPrimaryLCID = true; +} + +/** + * Set project secondary LCID + * @param secLCID Project secondary LCID to set + */ +void VisualBasicInfo::setProjectSecondaryLCID(std::uint32_t secLCID) +{ + projectSecondaryLCID = secLCID; + validProjectSecondaryLCID = true; +} + +/** + * Set typeLib CLSID + * @param data CLSID raw data + */ +void VisualBasicInfo::setTypeLibCLSID(const std::uint8_t data[16]) +{ + typeLibCLSID = guidToStr(data); +} + +/** + * Set typeLib LCID + * @param tlbLCID TypeLib LCID to set + */ +void VisualBasicInfo::setTypeLibLCID(std::uint32_t tlbLCID) +{ + typeLibLCID = tlbLCID; + validTypeLibLCID = true; +} + +/** + * Set whether visual basic file is a P-code file. + * @param set @c true if file is a P-code, @c false otherwise. + */ +void VisualBasicInfo::setPcode(bool set) +{ + pcodeFlag = set; +} + +/** + * Set object table GUID + * @param data Raw GUID data + */ +void VisualBasicInfo::setObjectTableGUID(const std::uint8_t data[16]) +{ + objectTableGUID = guidToStr(data); +} + +/** + * Set typeLib major version + * @param majVer Version to set + */ +void VisualBasicInfo::setTypeLibMajorVersion(std::uint16_t majVer) +{ + typeLibMajorVersion = majVer; + validTypeLibMajorVersion = true; +} + +/** + * Set typeLib minor version + * @param minVer Version to set + */ +void VisualBasicInfo::setTypeLibMinorVersion(std::uint16_t minVer) +{ + typeLibMinorVersion = minVer; + validTypeLibMinorVersion = true; +} + +/** + * Set COM object name + * @param name COM object name to set + */ +void VisualBasicInfo::setCOMObjectName(const std::string &name) +{ + COMObjectName = name; +} + +/** + * Set COM object description + * @param description COM object description to set + */ +void VisualBasicInfo::setCOMObjectDescription(const std::string &description) +{ + COMObjectDescription = description; +} + +/** + * Set COM object CLSID + * @param data Raw CLSID data + */ +void VisualBasicInfo::setCOMObjectCLSID(const std::uint8_t data[16]) +{ + COMObjectCLSID = guidToStr(data); +} + +/** + * Set COM object interfaceCLSID + * @param data Raw CLSID data + */ +void VisualBasicInfo::setCOMObjectInterfaceCLSID(const std::uint8_t data[16]) +{ + COMObjectInterfaceCLSID = guidToStr(data); +} + +/** + * Set COM object eventsCLSID + * @param data Raw CLSID data + */ +void VisualBasicInfo::setCOMObjectEventsCLSID(const std::uint8_t data[16]) +{ + COMObjectEventsCLSID = guidToStr(data); +} + +/** + * Set COM object type + * @param type COM object type to set + */ +void VisualBasicInfo::setCOMObjectType(std::uint8_t type) +{ + switch (type) + { + case 0x2: COMObjectType = "Designer"; break; + case 0x10: COMObjectType = "ClassModule"; break; + case 0x20: COMObjectType = "ActiveXUserControl"; break; + case 0x80: COMObjectType = "UserDocument"; break; + default: COMObjectType = "unknown"; break; + } +} + +/** + * Add visual basic object + * @param obj Object to add + */ +void VisualBasicInfo::addObject(std::unique_ptr&& obj) +{ + objects.push_back(std::move(obj)); +} + +/** + * Add visual basic extern + * @param ext Extern to add + */ +void VisualBasicInfo::addExtern(std::unique_ptr&& ext) +{ + externs.push_back(std::move(ext)); +} + +/** + * Check if visual basic file has project name + * @return @c true if visual basic file has project name, @c false otherwise + */ +bool VisualBasicInfo::hasProjectName() const +{ + return !projectName.empty(); +} + +/** + * Check if visual basic file has project description + * @return @c true if visual basic file has project description, @c false otherwise + */ +bool VisualBasicInfo::hasProjectDescription() const +{ + return !projectDescription.empty(); +} + +/** + * Check if visual basic file has project help file + * @return @c true if visual basic file has project help file, @c false otherwise + */ +bool VisualBasicInfo::hasProjectHelpFile() const +{ + return !projectHelpFile.empty(); +} + +/** + * Check if visual basic file is a P-code file + * @return @c true if visual basic file is P-code, @c false otherwise + */ +bool VisualBasicInfo::isPcode() const +{ + return pcodeFlag; +} + +/** + * Compute external table hashes - CRC32, MD5, SHA256. + */ +void VisualBasicInfo::computeExternTableHashes() +{ + std::vector hashBytes; + + for (const auto& ext : externs) + { + auto moduleName = toLower(ext->getModuleName()); + auto apiName = toLower(ext->getApiName()); + + if(apiName.empty() || moduleName.empty()) + { + continue; + } + + if(!hashBytes.empty()) + { + hashBytes.push_back(static_cast(',')); + } + + for(const auto c : std::string(apiName + "." + moduleName)) + { + hashBytes.push_back(static_cast(c)); + } + } + + externTableHashCrc32 = retdec::crypto::getCrc32(hashBytes.data(), hashBytes.size()); + externTableHashMd5 = retdec::crypto::getMd5(hashBytes.data(), hashBytes.size()); + externTableHashSha256 = retdec::crypto::getSha256(hashBytes.data(), hashBytes.size()); +} + +/** + * Compute object table hashes - CRC32, MD5, SHA256. + */ +void VisualBasicInfo::computeObjectTableHashes() +{ + std::vector hashBytes; + + for (const auto& obj : objects) + { + auto objName = toLower(obj->getName()); + if(objName.empty()) + { + continue; + } + + std::string methods = ""; + for (const auto &method : obj->getMethods()) + { + if (!methods.empty()) + { + methods.push_back('.'); + } + + methods += method; + } + + if(!hashBytes.empty()) + { + hashBytes.push_back(static_cast(',')); + } + + for(const auto c : std::string(objName + "." + methods)) + { + hashBytes.push_back(static_cast(c)); + } + } + + objectTableHashCrc32 = retdec::crypto::getCrc32(hashBytes.data(), hashBytes.size()); + objectTableHashMd5 = retdec::crypto::getMd5(hashBytes.data(), hashBytes.size()); + objectTableHashSha256 = retdec::crypto::getSha256(hashBytes.data(), hashBytes.size()); +} + +/** + * Convert raw GUID data to string + * @param data Raw GUID data + */ +std::string VisualBasicInfo::guidToStr(const std::uint8_t data[16]) +{ + std::string r1, r2, r3, r4, r5; + bytesToHexString(data, 16, r1, 0, 4); + bytesToHexString(data, 16, r2, 4, 2); + bytesToHexString(data, 16, r3, 6, 2); + bytesToHexString(data, 16, r4, 8, 2); + bytesToHexString(data, 16, r5, 10, 6); + + return r1 + "-" + r2 + "-" + r3 + "-" + r4 + "-" + r5; +} + + +} // namespace fileformat +} // namespace retdec diff --git a/src/fileformat/types/visual_basic/visual_basic_object.cpp b/src/fileformat/types/visual_basic/visual_basic_object.cpp new file mode 100644 index 000000000..100a1b048 --- /dev/null +++ b/src/fileformat/types/visual_basic/visual_basic_object.cpp @@ -0,0 +1,76 @@ +/** + * @file src/fileformat/types/visual_basic/visual_basic_object.cpp + * @brief Class visual basic object. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/fileformat/types/visual_basic/visual_basic_object.h" + +namespace retdec { +namespace fileformat { + +/** + * Constructor + */ +VisualBasicObject::VisualBasicObject() +{ + +} + +/** + * Destructor + */ +VisualBasicObject::~VisualBasicObject() +{ + +} + +/** + * Get name + * @return name + */ +const std::string &VisualBasicObject::getName() const +{ + return name; +} + +/** + * Get methods + * @return Object methods + */ +const std::vector &VisualBasicObject::getMethods() const +{ + return methods; +} + +/** + * Get number of methods + * @return number of methods + */ +std::size_t VisualBasicObject::getNumberOfMethods() const +{ + return methods.size(); +} + +/** + * Set name + * @param n Name to set + */ +void VisualBasicObject::setName(const std::string &n) +{ + name = n; +} + +/** + * Add method + * @param method Method to add + */ +void VisualBasicObject::addMethod(const std::string &method) +{ + methods.push_back(method); +} + + + +} // namespace fileformat +} // namespace retdec diff --git a/src/fileformat/utils/format_detection.cpp b/src/fileformat/utils/format_detection.cpp index e8f36ca83..e1558620c 100644 --- a/src/fileformat/utils/format_detection.cpp +++ b/src/fileformat/utils/format_detection.cpp @@ -127,10 +127,22 @@ bool isCoff(std::istream& stream, const std::string &header) std::error_code errorCode; COFFObjectFile coff(buffer.get()->getMemBufferRef(), errorCode); + if (errorCode) + { + return false; + } + PELIB_IMAGE_FILE_MACHINE_ITERATOR it; - return !errorCode - && it.isValidMachineCode( - static_cast(coff.getMachine())); + bool validMachineCode = it.isValidMachineCode( + static_cast(coff.getMachine())); + bool unknownMachineCode = + coff.getMachine() == PELIB_IMAGE_FILE_MACHINE::PELIB_IMAGE_FILE_MACHINE_UNKNOWN; + if (!validMachineCode + || (unknownMachineCode && coff.getNumberOfSections() == 0)) + { + return false; + } + return true; } /** @@ -210,6 +222,11 @@ bool isStrangeFeedface(std::istream& stream) Format detectFileFormat(std::istream &inputStream, bool isRaw) { + if (isRaw) + { + return Format::RAW_DATA; + } + resetStream(inputStream); std::size_t magicSize = 0; @@ -266,10 +283,6 @@ Format detectFileFormat(std::istream &inputStream, bool isRaw) { return Format::COFF; } - else if(isRaw) - { - return Format::RAW_DATA; - } return Format::UNKNOWN; } diff --git a/src/fileformat/utils/other.cpp b/src/fileformat/utils/other.cpp index 21fb82dfd..3d831f52f 100644 --- a/src/fileformat/utils/other.cpp +++ b/src/fileformat/utils/other.cpp @@ -5,8 +5,10 @@ */ #include +#include #include "retdec/utils/container.h" +#include "retdec/utils/conversion.h" #include "retdec/fileformat/utils/other.h" using namespace retdec::utils; @@ -36,6 +38,196 @@ const std::map> architectureMap = {Architecture::MIPS, {"MIPS", "PIC32"}} }; +const std::unordered_map lcids = +{ + {1078, "Afrikaans"}, + {1052, "Albanian"}, + {1118, "Amharic"}, + {5121, "Arabic - Algeria"}, + {15361, "Arabic - Bahrain"}, + {3073, "Arabic - Egypt"}, + {2049, "Arabic - Iraq"}, + {11265, "Arabic - Jordan"}, + {13313, "Arabic - Kuwait"}, + {12289, "Arabic - Lebanon"}, + {4097, "Arabic - Libya"}, + {6145, "Arabic - Morocco"}, + {8193, "Arabic - Oman"}, + {16385, "Arabic - Qatar"}, + {1025, "Arabic - Saudi Arabia"}, + {10241, "Arabic - Syria"}, + {7169, "Arabic - Tunisia"}, + {14337, "Arabic - United Arab Emirates"}, + {9217, "Arabic - Yemen"}, + {1067, "Armenian"}, + {1101, "Assamese"}, + {2092, "Azeri - Cyrillic"}, + {1068, "Azeri - Latin"}, + {1069, "Basque"}, + {1059, "Belarusian"}, + {2117, "Bengali - Bangladesh"}, + {1093, "Bengali - India"}, + {5146, "Bosnian"}, + {1026, "Bulgarian"}, + {1109, "Burmese"}, + {1027, "Catalan"}, + {2052, "Chinese - China"}, + {3076, "Chinese - Hong Kong SAR"}, + {5124, "Chinese - Macau SAR"}, + {4100, "Chinese - Singapore"}, + {1028, "Chinese - Taiwan"}, + {1050, "Croatian"}, + {1029, "Czech"}, + {1030, "Danish"}, + {2067, "Dutch - Belgium"}, + {1043, "Dutch - Netherlands"}, + {1126, "Edo"}, + {3081, "English - Australia"}, + {10249, "English - Belize"}, + {4105, "English - Canada"}, + {9225, "English - Caribbean"}, + {2057, "English - Great Britain"}, + {16393, "English - India"}, + {6153, "English - Ireland"}, + {8201, "English - Jamaica"}, + {5129, "English - New Zealand"}, + {13321, "English - Phillippines"}, + {7177, "English - Southern Africa"}, + {11273, "English - Trinidad"}, + {1033, "English - United States"}, + {12297, "English - Zimbabwe"}, + {1061, "Estonian"}, + {1071, "FYRO Macedonia"}, + {1080, "Faroese"}, + {1065, "Farsi - Persian"}, + {1124, "Filipino"}, + {1035, "Finnish"}, + {2060, "French - Belgium"}, + {11276, "French - Cameroon"}, + {3084, "French - Canada"}, + {9228, "French - Congo"}, + {12300, "French - Cote d'Ivoire"}, + {1036, "French - France"}, + {5132, "French - Luxembourg"}, + {13324, "French - Mali"}, + {6156, "French - Monaco"}, + {14348, "French - Morocco"}, + {10252, "French - Senegal"}, + {4108, "French - Switzerland"}, + {7180, "French - West Indies"}, + {1122, "Frisian - Netherlands"}, + {2108, "Gaelic - Ireland"}, + {1084, "Gaelic - Scotland"}, + {1110, "Galician"}, + {1079, "Georgian"}, + {3079, "German - Austria"}, + {1031, "German - Germany"}, + {5127, "German - Liechtenstein"}, + {4103, "German - Luxembourg"}, + {2055, "German - Switzerland"}, + {1032, "Greek"}, + {1140, "Guarani - Paraguay"}, + {1095, "Gujarati"}, + {1279, "Human Interface Device"}, + {1037, "Hebrew"}, + {1081, "Hindi"}, + {1038, "Hungarian"}, + {1039, "Icelandic"}, + {1136, "Igbo - Nigeria"}, + {1057, "Indonesian"}, + {1040, "Italian - Italy"}, + {2064, "Italian - Switzerland"}, + {1041, "Japanese"}, + {1099, "Kannada"}, + {1120, "Kashmiri"}, + {1087, "Kazakh"}, + {1107, "Khmer"}, + {1111, "Konkani"}, + {1042, "Korean"}, + {1088, "Kyrgyz - Cyrillic"}, + {1108, "Lao"}, + {1142, "Latin"}, + {1062, "Latvian"}, + {1063, "Lithuanian"}, + {2110, "Malay - Brunei"}, + {1086, "Malay - Malaysia"}, + {1100, "Malayalam"}, + {1082, "Maltese"}, + {1112, "Manipuri"}, + {1153, "Maori"}, + {1102, "Marathi"}, + {2128, "Mongolian"}, + {1104, "Mongolian"}, + {1121, "Nepali"}, + {1044, "Norwegian - Bokml"}, + {2068, "Norwegian - Nynorsk"}, + {1096, "Oriya"}, + {1045, "Polish"}, + {1046, "Portuguese - Brazil"}, + {2070, "Portuguese - Portugal"}, + {1094, "Punjabi"}, + {1047, "Raeto-Romance"}, + {2072, "Romanian - Moldova"}, + {1048, "Romanian - Romania"}, + {1049, "Russian"}, + {2073, "Russian - Moldova"}, + {1083, "Sami Lappish"}, + {1103, "Sanskrit"}, + {3098, "Serbian - Cyrillic"}, + {2074, "Serbian - Latin"}, + {1072, "Sesotho"}, + {1074, "Setsuana"}, + {1113, "Sindhi"}, + {1115, "Sinhala"}, + {1051, "Slovak"}, + {1060, "Slovenian"}, + {1143, "Somali"}, + {1070, "Sorbian"}, + {11274, "Spanish - Argentina"}, + {16394, "Spanish - Bolivia"}, + {13322, "Spanish - Chile"}, + {9226, "Spanish - Colombia"}, + {5130, "Spanish - Costa Rica"}, + {7178, "Spanish - Dominican Republic"}, + {12298, "Spanish - Ecuador"}, + {17418, "Spanish - El Salvador"}, + {4106, "Spanish - Guatemala"}, + {18442, "Spanish - Honduras"}, + {2058, "Spanish - Mexico"}, + {19466, "Spanish - Nicaragua"}, + {6154, "Spanish - Panama"}, + {15370, "Spanish - Paraguay"}, + {10250, "Spanish - Peru"}, + {20490, "Spanish - Puerto Rico"}, + {1034, "Spanish - Spain (Traditional)"}, + {14346, "Spanish - Uruguay"}, + {8202, "Spanish - Venezuela"}, + {1089, "Swahili"}, + {2077, "Swedish - Finland"}, + {1053, "Swedish - Sweden"}, + {1114, "Syriac"}, + {1064, "Tajik"}, + {1097, "Tamil"}, + {1092, "Tatar"}, + {1098, "Telugu"}, + {1054, "Thai"}, + {1105, "Tibetan"}, + {1073, "Tsonga"}, + {1055, "Turkish"}, + {1090, "Turkmen"}, + {1058, "Ukrainian"}, + {0, "Unicode"}, + {1056, "Urdu"}, + {2115, "Uzbek - Cyrillic"}, + {1091, "Uzbek - Latin"}, + {1075, "Venda"}, + {1066, "Vietnamese"}, + {1106, "Welsh"}, + {1076, "Xhosa"}, + {1085, "Yiddish"}, + {1077, "Zulu"} +}; + } // anonymous namespace /** @@ -99,5 +291,20 @@ std::vector getSupportedArchitectures() return result; } +/** + * Get string representation of language code id + * @param lcid Language code id + * @return String representation of @a lcid + */ +std::string lcidToStr(std::size_t lcid) +{ + auto l = lcids.find(lcid); + if (l == lcids.end()) + { + return numToStr(lcid, std::dec); + } + return l->second; +} + } // namespace fileformat } // namespace retdec diff --git a/src/fileinfo/CMakeLists.txt b/src/fileinfo/CMakeLists.txt index a66f232df..2970c8162 100644 --- a/src/fileinfo/CMakeLists.txt +++ b/src/fileinfo/CMakeLists.txt @@ -30,6 +30,7 @@ set(FILEINFO_SOURCES file_information/file_information_types/resource_table/resource.cpp file_information/file_information_types/resource_table/resource_table.cpp file_information/file_information_types/rich_header.cpp + file_information/file_information_types/visual_basic_info.cpp file_information/file_information_types/special_information.cpp file_information/file_information_types/strings.cpp file_information/file_information_types/symbol_table/symbol.cpp @@ -51,6 +52,7 @@ set(FILEINFO_SOURCES file_presentation/getters/iterative_getter/iterative_distribution_getter/relocation_tables_plain_getter.cpp file_presentation/getters/iterative_getter/iterative_distribution_getter/resource_plain_getter.cpp file_presentation/getters/iterative_getter/iterative_distribution_getter/rich_header_plain_getter.cpp + file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.cpp file_presentation/getters/iterative_getter/iterative_distribution_getter/section_plain_getter.cpp file_presentation/getters/iterative_getter/iterative_distribution_getter/segment_plain_getter.cpp file_presentation/getters/iterative_getter/iterative_distribution_getter/strings_plain_getter.cpp @@ -79,6 +81,8 @@ set(FILEINFO_SOURCES file_presentation/getters/simple_getter/basic_plain_getter.cpp file_presentation/getters/simple_getter/dotnet_json_getter.cpp file_presentation/getters/simple_getter/dotnet_plain_getter.cpp + file_presentation/getters/simple_getter/visual_basic_plain_getter.cpp + file_presentation/getters/simple_getter/visual_basic_json_getter.cpp file_presentation/getters/simple_getter/entry_point_json_getter.cpp file_presentation/getters/simple_getter/header_json_getter.cpp file_presentation/getters/simple_getter/header_plain_getter.cpp diff --git a/src/fileinfo/file_detector/pe_detector.cpp b/src/fileinfo/file_detector/pe_detector.cpp index 4085ebff4..3b77a1915 100644 --- a/src/fileinfo/file_detector/pe_detector.cpp +++ b/src/fileinfo/file_detector/pe_detector.cpp @@ -337,6 +337,20 @@ void PeDetector::getDotnetInfo() fileInfo.setDotnetTypeRefhashSha256(peParser->getTypeRefhashSha256()); } +/** + * Get information about .NET + */ +void PeDetector::getVisualBasicInfo() +{ + unsigned long long version; + if (!peParser->isVisualBasic(version)) + { + return; + } + fileInfo.setVisualBasicUsed(true); + fileInfo.setVisualBasicInfo(peParser->getVisualBasicInfo()); +} + void PeDetector::detectFileClass() { switch(peParser->getPeClass()) @@ -494,6 +508,7 @@ void PeDetector::getAdditionalInfo() getCoffSymbols(); getRelocationTableInfo(); getDotnetInfo(); + getVisualBasicInfo(); /* In future we can detect more information about PE files: - TimeDateStamp diff --git a/src/fileinfo/file_detector/pe_detector.h b/src/fileinfo/file_detector/pe_detector.h index b39ea8b48..9f88a67db 100644 --- a/src/fileinfo/file_detector/pe_detector.h +++ b/src/fileinfo/file_detector/pe_detector.h @@ -30,6 +30,7 @@ class PeDetector : public FileDetector void getDirectories(); void getSections(); void getDotnetInfo(); + void getVisualBasicInfo(); /// @} protected: /// @name Detection methods diff --git a/src/fileinfo/file_information/file_information.cpp b/src/fileinfo/file_information/file_information.cpp index eaad8df13..280b45b0e 100644 --- a/src/fileinfo/file_information/file_information.cpp +++ b/src/fileinfo/file_information/file_information.cpp @@ -781,6 +781,341 @@ bool FileInformation::hasRichHeaderRecords() const return richHeader.hasRecords(); } +/** + * Check whether visual basic informations are used. + * @return @c true if it is used, otherwise @c false/ + */ +bool FileInformation::isVisualBasicUsed() const +{ + return visualBasicInfo.isUsed(); +} + +/** + * Check whether visual basic uses P-Code. + * @return @c true if it does, otherwise @c false/ + */ +bool FileInformation::getVisualBasicIsPcode() const +{ + return visualBasicInfo.isPcode(); +} + +/** + * Get visual basic language DLL + * @return Visual basic language DLL + */ +std::string FileInformation::getVisualBasicLanguageDLL() const +{ + return visualBasicInfo.getLanguageDLL(); +} + +/** + * Get visual basic backup language DLL + * @return Visual basic backup language DLL + */ +std::string FileInformation::getVisualBasicBackupLanguageDLL() const +{ + return visualBasicInfo.getBackupLanguageDLL(); +} + +/** + * Get visual basic project exe name + * @return Visual basic project exe name + */ +std::string FileInformation::getVisualBasicProjectExeName() const +{ + return visualBasicInfo.getProjectExeName(); +} + +/** + * Get visual basic project description + * @return Visual basic project description + */ +std::string FileInformation::getVisualBasicProjectDescription() const +{ + return visualBasicInfo.getProjectDescription(); +} + +/** + * Get visual basic project help file + * @return Visual basic project help file + */ +std::string FileInformation::getVisualBasicProjectHelpFile() const +{ + return visualBasicInfo.getProjectHelpFile(); +} + +/** + * Get visual basic project name + * @return Visual basic project name + */ +std::string FileInformation::getVisualBasicProjectName() const +{ + return visualBasicInfo.getProjectName(); +} + +/** + * Get visual basic language DLL primary LCID + * @return Visual basic language DLL primary LCID + */ +std::string FileInformation::getVisualBasicLanguageDLLPrimaryLCIDStr() const +{ + return visualBasicInfo.getLanguageDLLPrimaryLCIDStr(); +} + +/** + * Get visual basic language DLL secondary LCID + * @return Visual basic language DLL secondary LCID + */ +std::string FileInformation::getVisualBasicLanguageDLLSecondaryLCIDStr() const +{ + return visualBasicInfo.getLanguageDLLSecondaryLCIDStr(); +} + +/** + * Get visual basic project path + * @return Visual basic project path + */ +std::string FileInformation::getVisualBasicProjectPath() const +{ + return visualBasicInfo.getProjectPath(); +} + +/** + * Get visual basic project primary LCID + * @return Visual basic project primary LCID + */ +std::string FileInformation::getVisualBasicProjectPrimaryLCIDStr() const +{ + return visualBasicInfo.getProjectPrimaryLCIDStr(); +} + +/** + * Get visual basic project secondary LCID + * @return Visual basic project secondary LCID + */ +std::string FileInformation::getVisualBasicProjectSecondaryLCIDStr() const +{ + return visualBasicInfo.getProjectSecondaryLCIDStr(); +} + +/** + * Get visual basic object + * @param position Index of selected object (indexed from 0) + * @return Visual basic object + */ +const retdec::fileformat::VisualBasicObject *FileInformation::getVisualBasicObject(std::size_t position) const +{ + return visualBasicInfo.getObject(position); +} + +/** + * Get visual basic extern + * @param position Index of selected extern (indexed from 0) + * @return Visual basic extern + */ +const retdec::fileformat::VisualBasicExtern *FileInformation::getVisualBasicExtern(std::size_t position) const +{ + return visualBasicInfo.getExtern(position); +} + +/** + * Get visual basic number of objects + * @return Visual basic number of objects + */ +std::size_t FileInformation::getVisualBasicNumberOfObjects() const +{ + return visualBasicInfo.getNumberOfObjects(); +} + +/** + * Get visual basic number of externs + * @return Visual basic number of externs + */ +std::size_t FileInformation::getVisualBasicNumberOfExterns() const +{ + return visualBasicInfo.getNumberOfExterns(); +} + +/** + * Get visual basic extern module name + * @param position Index of selected extern (indexed from 0) + * @return Visual basic extern module name + */ +std::string FileInformation::getVisualBasicExternModuleName(std::size_t position) const +{ + return visualBasicInfo.getExternModuleName(position); +} + +/** + * Get visual basic extern api name + * @param position Index of selected extern (indexed from 0) + * @return Visual basic extern api name + */ +std::string FileInformation::getVisualBasicExternApiName(std::size_t position) const +{ + return visualBasicInfo.getExternApiName(position); +} + +/** + * Get visual basic object table GUID + * @return Object table GUID as string + */ +std::string FileInformation::getVisualBasicObjectTableGUID() const +{ + return visualBasicInfo.getObjectTableGUID(); +} + +/** + * Get visual basic typeLib CLSID + * @return typeLib CLSID as string + */ +std::string FileInformation::getVisualBasicTypeLibCLSID() const +{ + return visualBasicInfo.getTypeLibCLSID(); +} + +/** + * Get visual basic typeLib major version + * @return TypeLib major version + */ +std::string FileInformation::getVisualBasicTypeLibMajorVersionStr() const +{ + return visualBasicInfo.getTypeLibMajorVersionStr(); +} + +/** + * Get visual basic typeLib minor version + * @return TypeLib minor version + */ +std::string FileInformation::getVisualBasicTypeLibMinorVersionStr() const +{ + return visualBasicInfo.getTypeLibMinorVersionStr(); +} + +/** + * Get visual basic typeLib LCID + * @return Visual basic typeLib LCID + */ +std::string FileInformation::getVisualBasicTypeLibLCIDStr() const +{ + return visualBasicInfo.getTypeLibLCIDStr(); +} + +/** + * Get visual basic COM object name + * @return Visual basic COM object name + */ +std::string FileInformation::getVisualBasicCOMObjectName() const +{ + return visualBasicInfo.getCOMObjectName(); +} + +/** + * Get visual basic COM object description + * @return Visual basic COM object description + */ +std::string FileInformation::getVisualBasicCOMObjectDescription() const +{ + return visualBasicInfo.getCOMObjectDescription(); +} + +/** + * Get visual basic COM object CLSID + * @return Visual basic COM object CLSID + */ +std::string FileInformation::getVisualBasicCOMObjectCLSID() const +{ + return visualBasicInfo.getCOMObjectCLSID(); +} + +/** + * Get visual basic COM object interface CLSID + * @return Visual basic COM object interface CLSID + */ +std::string FileInformation::getVisualBasicCOMObjectInterfaceCLSID() const +{ + return visualBasicInfo.getCOMObjectInterfaceCLSID(); +} + +/** + * Get visual basic COM object events CLSID + * @return Visual basic COM object events CLSID + */ +std::string FileInformation::getVisualBasicCOMObjectEventsCLSID() const +{ + return visualBasicInfo.getCOMObjectEventsCLSID(); +} + +/** + * Get visual basic COM object type + * @return Visual basic COM object type + */ +std::string FileInformation::getVisualBasicCOMObjectType() const +{ + return visualBasicInfo.getCOMObjectType(); +} + +/** + * Get visual basic extern table hash as Crc32 + * @return Visual basic extern table hash + */ +std::string FileInformation::getVisualBasicExternTableHashCrc32() const +{ + return visualBasicInfo.getExternTableHashCrc32(); +} + +/** + * Get visual basic extern table hash as Md5 + * @return Visual basic extern table hash + */ +std::string FileInformation::getVisualBasicExternTableHashMd5() const +{ + return visualBasicInfo.getExternTableHashMd5(); +} + +/** + * Get visual basic extern table hash as Sha256 + * @return Visual basic extern table hash + */ +std::string FileInformation::getVisualBasicExternTableHashSha256() const +{ + return visualBasicInfo.getExternTableHashSha256(); +} + +/** + * Get visual basic object table hash as Crc32 + * @return Visual basic object table hash + */ +std::string FileInformation::getVisualBasicObjectTableHashCrc32() const +{ + return visualBasicInfo.getObjectTableHashCrc32(); +} + +/** + * Get visual basic object table hash as Md5 + * @return Visual basic object table hash + */ +std::string FileInformation::getVisualBasicObjectTableHashMd5() const +{ + return visualBasicInfo.getObjectTableHashMd5(); +} + +/** + * Get visual basic object table hash as Sha256 + * @return Visual basic object table hash + */ +std::string FileInformation::getVisualBasicObjectTableHashSha256() const +{ + return visualBasicInfo.getObjectTableHashSha256(); +} + + + + + + + + /** * Get type of related PDB file * @return Type of related PDB file @@ -3597,6 +3932,24 @@ void FileInformation::setRichHeader(const retdec::fileformat::RichHeader *rHeade richHeader.setHeader(rHeader); } +/** + * Set visual basic information + * @param vbInfo Information about visual basic + */ +void FileInformation::setVisualBasicInfo(const retdec::fileformat::VisualBasicInfo *vbInfo) +{ + visualBasicInfo.setInfo(vbInfo); +} + +/** + * Sets whether visual basic informations are used. + * @param set @c true if used, otherwise @c false. + */ +void FileInformation::setVisualBasicUsed(bool set) +{ + visualBasicInfo.setUsed(set); +} + /** * Set type of related PDB file * @param sType Type of related PDB file diff --git a/src/fileinfo/file_information/file_information.h b/src/fileinfo/file_information/file_information.h index 8fbda47ad..56261e630 100644 --- a/src/fileinfo/file_information/file_information.h +++ b/src/fileinfo/file_information/file_information.h @@ -39,6 +39,7 @@ class FileInformation std::string compactManifest; ///< compact version of XML manifest FileHeader header; ///< file header RichHeader richHeader; ///< rich header + VisualBasicInfo visualBasicInfo; ///< visual basic information PdbInfo pdbInfo; ///< information about related PDB file ImportTable importTable; ///< information about imports ExportTable exportTable; ///< information about exports @@ -152,6 +153,47 @@ class FileInformation bool hasRichHeaderRecords() const; /// @} + /// @name Getters of @a visualBasicInfo + /// @{ + bool isVisualBasicUsed() const; + bool getVisualBasicIsPcode() const; + std::string getVisualBasicLanguageDLL() const; + std::string getVisualBasicBackupLanguageDLL() const; + std::string getVisualBasicProjectExeName() const; + std::string getVisualBasicProjectDescription() const; + std::string getVisualBasicProjectHelpFile() const; + std::string getVisualBasicProjectName() const; + std::string getVisualBasicLanguageDLLPrimaryLCIDStr() const; + std::string getVisualBasicLanguageDLLSecondaryLCIDStr() const; + std::string getVisualBasicProjectPath() const; + std::string getVisualBasicProjectPrimaryLCIDStr() const; + std::string getVisualBasicProjectSecondaryLCIDStr() const; + const retdec::fileformat::VisualBasicObject *getVisualBasicObject(std::size_t position) const; + const retdec::fileformat::VisualBasicExtern *getVisualBasicExtern(std::size_t position) const; + std::size_t getVisualBasicNumberOfObjects() const; + std::size_t getVisualBasicNumberOfExterns() const; + std::string getVisualBasicExternModuleName(std::size_t position) const; + std::string getVisualBasicExternApiName(std::size_t position) const; + std::string getVisualBasicObjectTableGUID() const; + std::string getVisualBasicTypeLibCLSID() const; + std::string getVisualBasicTypeLibMajorVersionStr() const; + std::string getVisualBasicTypeLibMinorVersionStr() const; + std::string getVisualBasicTypeLibLCIDStr() const; + std::string getVisualBasicCOMObjectName() const; + std::string getVisualBasicCOMObjectDescription() const; + std::string getVisualBasicCOMObjectCLSID() const; + std::string getVisualBasicCOMObjectInterfaceCLSID() const; + std::string getVisualBasicCOMObjectEventsCLSID() const; + std::string getVisualBasicCOMObjectType() const; + std::string getVisualBasicExternTableHashCrc32() const; + std::string getVisualBasicExternTableHashMd5() const; + std::string getVisualBasicExternTableHashSha256() const; + std::string getVisualBasicObjectTableHashCrc32() const; + std::string getVisualBasicObjectTableHashMd5() const; + std::string getVisualBasicObjectTableHashSha256() const; + /// @} + + /// @name Getters of @a pdbInfo /// @{ std::string getPdbType() const; @@ -510,6 +552,8 @@ class FileInformation void setOverlayOffset(unsigned long long offset); void setOverlaySize(unsigned long long size); void setRichHeader(const retdec::fileformat::RichHeader *rHeader); + void setVisualBasicInfo(const retdec::fileformat::VisualBasicInfo *vbInfo); + void setVisualBasicUsed(bool set); void setPdbType(const std::string &sType); void setPdbPath(const std::string &sPath); void setPdbGuid(const std::string &sGuid); diff --git a/src/fileinfo/file_information/file_information_types/file_information_types.h b/src/fileinfo/file_information/file_information_types/file_information_types.h index 084fec203..d826e3d97 100644 --- a/src/fileinfo/file_information/file_information_types/file_information_types.h +++ b/src/fileinfo/file_information/file_information_types/file_information_types.h @@ -24,6 +24,7 @@ #include "fileinfo/file_information/file_information_types/relocation_table/relocation_table.h" #include "fileinfo/file_information/file_information_types/resource_table/resource_table.h" #include "fileinfo/file_information/file_information_types/rich_header.h" +#include "fileinfo/file_information/file_information_types/visual_basic_info.h" #include "fileinfo/file_information/file_information_types/strings.h" #include "fileinfo/file_information/file_information_types/symbol_table/symbol_table.h" diff --git a/src/fileinfo/file_information/file_information_types/visual_basic_info.cpp b/src/fileinfo/file_information/file_information_types/visual_basic_info.cpp new file mode 100644 index 000000000..4034e8c18 --- /dev/null +++ b/src/fileinfo/file_information/file_information_types/visual_basic_info.cpp @@ -0,0 +1,416 @@ +/** + * @file src/fileinfo/file_information/file_information_types/visual_basic_info.cpp + * @brief Rich header. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/fileformat/utils/other.h" +#include "fileinfo/file_information/file_information_types/visual_basic_info.h" +#include "fileinfo/file_information/file_information_types/type_conversions.h" + +using namespace retdec::utils; +using namespace retdec::fileformat; + +namespace fileinfo { + +/** + * Constructor + */ +VisualBasicInfo::VisualBasicInfo() : used(false), visualBasicInfo(nullptr) +{ + +} + +/** + * Destructor + */ +VisualBasicInfo::~VisualBasicInfo() +{ + +} + +/** + * Get language DLL + * @return Visual basic language DLL + */ +std::string VisualBasicInfo::getLanguageDLL() const +{ + return visualBasicInfo ? visualBasicInfo->getLanguageDLL() : ""; +} + +/** + * Get backup language DLL + * @return Visual basic backup language DLL + */ +std::string VisualBasicInfo::getBackupLanguageDLL() const +{ + return visualBasicInfo ? visualBasicInfo->getBackupLanguageDLL() : ""; +} + +/** + * Get project exe name + * @return Visual basic project exe name + */ +std::string VisualBasicInfo::getProjectExeName() const +{ + return visualBasicInfo ? visualBasicInfo->getProjectExeName() : ""; +} + +/** + * Get project description + * @return Visual basic project description + */ +std::string VisualBasicInfo::getProjectDescription() const +{ + return visualBasicInfo ? visualBasicInfo->getProjectDescription() : ""; +} + +/** + * Get project help file + * @return Visual basic project help file + */ +std::string VisualBasicInfo::getProjectHelpFile() const +{ + return visualBasicInfo ? visualBasicInfo->getProjectHelpFile() : ""; +} + +/** + * Get project name + * @return Visual basic project name + */ +std::string VisualBasicInfo::getProjectName() const +{ + return visualBasicInfo ? visualBasicInfo->getProjectName() : ""; +} + +/** + * Get language DLL primary LCID + * @return Visual basic language DLL primary LCID as string + */ +std::string VisualBasicInfo::getLanguageDLLPrimaryLCIDStr() const +{ + std::uint32_t lcid; + if (!visualBasicInfo || !visualBasicInfo->getLanguageDLLPrimaryLCID(lcid)) + { + return ""; + } + return lcidToStr(lcid); +} + +/** + * Get language DLL secondary LCID + * @return Visual basic language DLL secondary LCID as string + */ +std::string VisualBasicInfo::getLanguageDLLSecondaryLCIDStr() const +{ + std::uint32_t lcid; + if (!visualBasicInfo || !visualBasicInfo->getLanguageDLLSecondaryLCID(lcid)) + { + return ""; + } + return lcidToStr(lcid); +} + +/** + * Get project path + * @return Visual basic project path + */ +std::string VisualBasicInfo::getProjectPath() const +{ + return visualBasicInfo ? visualBasicInfo->getProjectPath() : ""; +} + +/** + * Get project primary LCID + * @return Visual basic project primary LCID as string + */ +std::string VisualBasicInfo::getProjectPrimaryLCIDStr() const +{ + std::uint32_t lcid; + if (!visualBasicInfo || !visualBasicInfo->getProjectPrimaryLCID(lcid)) + { + return ""; + } + return lcidToStr(lcid); +} + +/** + * Get project secondary LCID + * @return Visual basic project secondary LCID as string + */ +std::string VisualBasicInfo::getProjectSecondaryLCIDStr() const +{ + std::uint32_t lcid; + if (!visualBasicInfo || !visualBasicInfo->getProjectSecondaryLCID(lcid)) + { + return ""; + } + return lcidToStr(lcid); +} + +/** + * Get object + * @param position Index of selected visual basic object (indexed from 0) + * @return Visual basic object + */ +const retdec::fileformat::VisualBasicObject *VisualBasicInfo::getObject(std::size_t position) const +{ + return visualBasicInfo ? visualBasicInfo->getObject(position) : nullptr; +} + +/** + * Get extern + * @param position Index of selected visual basic extern (indexed from 0) + * @return Visual basic extern + */ +const retdec::fileformat::VisualBasicExtern *VisualBasicInfo::getExtern(std::size_t position) const +{ + return visualBasicInfo ? visualBasicInfo->getExtern(position) : nullptr; +} + +/** + * Get number of objects + * @return Visual basic number of objects + */ +std::size_t VisualBasicInfo::getNumberOfObjects() const +{ + return visualBasicInfo ? visualBasicInfo->getNumberOfObjects() : 0; +} + +/** + * Get number of externs + * @return Visual basic number of externs + */ +std::size_t VisualBasicInfo::getNumberOfExterns() const +{ + return visualBasicInfo ? visualBasicInfo->getNumberOfExterns() : 0; +} + +/** + * Get extern module name + * @param position Index of selected visual basic extern (indexed from 0) + * @return Extern module name + */ +std::string VisualBasicInfo::getExternModuleName(std::size_t position) const +{ + auto ext = getExtern(position); + return ext ? ext->getModuleName() : ""; +} + +/** + * Get extern api name + * @param position Index of selected visual basic extern (indexed from 0) + * @return Extern api name + */ +std::string VisualBasicInfo::getExternApiName(std::size_t position) const +{ + auto ext = getExtern(position); + return ext ? ext->getApiName() : ""; +} + +/** + * Get object table GUID + * @return Object table GUID as string + */ +std::string VisualBasicInfo::getObjectTableGUID() const +{ + return visualBasicInfo ? visualBasicInfo->getObjectTableGUID() : ""; +} + +/** + * Get typeLib CLSID + * @return typeLib CLSID as string + */ +std::string VisualBasicInfo::getTypeLibCLSID() const +{ + return visualBasicInfo ? visualBasicInfo->getTypeLibCLSID() : ""; +} + +/** + * Get typeLib major version + * @return TypeLib major version + */ +std::string VisualBasicInfo::getTypeLibMajorVersionStr() const +{ + std::uint16_t majV; + if (!visualBasicInfo || !visualBasicInfo->getTypeLibMajorVersion(majV)) + { + return ""; + } + return getNumberAsString(majV); +} + +/** + * Get typeLib minor version + * @return TypeLib minor version + */ +std::string VisualBasicInfo::getTypeLibMinorVersionStr() const +{ + std::uint16_t minV; + if (!visualBasicInfo || !visualBasicInfo->getTypeLibMinorVersion(minV)) + { + return ""; + } + return getNumberAsString(minV); +} + +/** + * Get typeLib LCID + * @return Visual basic typeLib LCID as string + */ +std::string VisualBasicInfo::getTypeLibLCIDStr() const +{ + std::uint32_t lcid; + if (!visualBasicInfo || !visualBasicInfo->getTypeLibLCID(lcid)) + { + return ""; + } + return lcidToStr(lcid); +} + +/** + * Get COM object name + * @return Visual basic COM object name + */ +std::string VisualBasicInfo::getCOMObjectName() const +{ + return visualBasicInfo ? visualBasicInfo->getCOMObjectName() : ""; +} + +/** + * Get COM object description + * @return Visual basic COM object description + */ +std::string VisualBasicInfo::getCOMObjectDescription() const +{ + return visualBasicInfo ? visualBasicInfo->getCOMObjectDescription() : ""; +} + +/** + * Get COM object CLSID + * @return Visual basic COM object CLSID + */ +std::string VisualBasicInfo::getCOMObjectCLSID() const +{ + return visualBasicInfo ? visualBasicInfo->getCOMObjectCLSID() : ""; +} + +/** + * Get COM object interface CLSID + * @return Visual basic COM object interface CLSID + */ +std::string VisualBasicInfo::getCOMObjectInterfaceCLSID() const +{ + return visualBasicInfo ? visualBasicInfo->getCOMObjectInterfaceCLSID() : ""; +} + +/** + * Get COM object events CLSID + * @return Visual basic COM object events CLSID + */ +std::string VisualBasicInfo::getCOMObjectEventsCLSID() const +{ + return visualBasicInfo ? visualBasicInfo->getCOMObjectEventsCLSID() : ""; +} + +/** + * Get COM object type + * @return Visual basic COM object type + */ +std::string VisualBasicInfo::getCOMObjectType() const +{ + return visualBasicInfo ? visualBasicInfo->getCOMObjectType() : ""; +} + +/** + * Get extern table hash as CRC32 + * @return Extern table hash + */ +std::string VisualBasicInfo::getExternTableHashCrc32() const +{ + return visualBasicInfo ? visualBasicInfo->getExternTableHashCrc32() : ""; +} + +/** + * Get extern table hash as MD5 + * @return Extern table hash + */ +std::string VisualBasicInfo::getExternTableHashMd5() const +{ + return visualBasicInfo ? visualBasicInfo->getExternTableHashMd5() : ""; +} + +/** + * Get extern table hash as SHA256 + * @return Extern table hash + */ +std::string VisualBasicInfo::getExternTableHashSha256() const +{ + return visualBasicInfo ? visualBasicInfo->getExternTableHashSha256() : ""; +} + +/** + * Get object table hash as CRC32 + * @return Object table hash + */ +std::string VisualBasicInfo::getObjectTableHashCrc32() const +{ + return visualBasicInfo ? visualBasicInfo->getObjectTableHashCrc32() : ""; +} + +/** + * Get object table hash as MD5 + * @return Object table hash + */ +std::string VisualBasicInfo::getObjectTableHashMd5() const +{ + return visualBasicInfo ? visualBasicInfo->getObjectTableHashMd5() : ""; +} + +/** + * Get object table hash as SHA256 + * @return Object table hash + */ +std::string VisualBasicInfo::getObjectTableHashSha256() const +{ + return visualBasicInfo ? visualBasicInfo->getObjectTableHashSha256() : ""; +} + +/** + * Set visual basic information + * @param vbInfo Instance of class with original information about visual basic + */ +void VisualBasicInfo::setInfo(const retdec::fileformat::VisualBasicInfo *vbInfo) +{ + visualBasicInfo = vbInfo; +} + +/** + * Set whether visual basic info is used. + * @param set @c true if used, @c false otherwise. + */ +void VisualBasicInfo::setUsed(bool set) +{ + used = set; +} + +/** + * Check whether visual basic informations are used. + * @return @c true if used, otherwise @c false. + */ +bool VisualBasicInfo::isUsed() const +{ + return used; +} + +/** + * Check whether visual basic file is a P-code file. + * @return @c true if is a P-code file, otherwise @c false. + */ +bool VisualBasicInfo::isPcode() const +{ + return visualBasicInfo ? visualBasicInfo->isPcode() : false; +} + + +} // namespace fileinfo diff --git a/src/fileinfo/file_information/file_information_types/visual_basic_info.h b/src/fileinfo/file_information/file_information_types/visual_basic_info.h new file mode 100644 index 000000000..71d678118 --- /dev/null +++ b/src/fileinfo/file_information/file_information_types/visual_basic_info.h @@ -0,0 +1,81 @@ +/** + * @file src/fileinfo/file_information/file_information_types/visual_basic_info.h + * @brief Visual basic information. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef FILEINFO_FILE_INFORMATION_FILE_INFORMATION_TYPES_VISUAL_BASIC_INFO_H +#define FILEINFO_FILE_INFORMATION_FILE_INFORMATION_TYPES_VISUAL_BASIC_INFO_H + +#include "retdec/fileformat/types/visual_basic/visual_basic_info.h" +#include "retdec/fileformat/types/visual_basic/visual_basic_object.h" +#include "retdec/fileformat/types/visual_basic/visual_basic_extern.h" + +namespace fileinfo { + +/** + * Class for rich header + */ +class VisualBasicInfo +{ + private: + bool used; + const retdec::fileformat::VisualBasicInfo *visualBasicInfo; + public: + VisualBasicInfo(); + ~VisualBasicInfo(); + + /// @name Getters + /// @{ + std::string getLanguageDLL() const; + std::string getBackupLanguageDLL() const; + std::string getProjectExeName() const; + std::string getProjectDescription() const; + std::string getProjectHelpFile() const; + std::string getProjectName() const; + std::string getLanguageDLLPrimaryLCIDStr() const; + std::string getLanguageDLLSecondaryLCIDStr() const; + std::string getProjectPath() const; + std::string getProjectPrimaryLCIDStr() const; + std::string getProjectSecondaryLCIDStr() const; + const retdec::fileformat::VisualBasicObject *getObject(std::size_t position) const; + const retdec::fileformat::VisualBasicExtern *getExtern(std::size_t position) const; + std::size_t getNumberOfObjects() const; + std::size_t getNumberOfExterns() const; + std::string getExternModuleName(std::size_t position) const; + std::string getExternApiName(std::size_t position) const; + std::string getObjectTableGUID() const; + std::string getTypeLibCLSID() const; + std::string getTypeLibMajorVersionStr() const; + std::string getTypeLibMinorVersionStr() const; + std::string getTypeLibLCIDStr() const; + std::string getCOMObjectName() const; + std::string getCOMObjectDescription() const; + std::string getCOMObjectCLSID() const; + std::string getCOMObjectInterfaceCLSID() const; + std::string getCOMObjectEventsCLSID() const; + std::string getCOMObjectType() const; + std::string getExternTableHashCrc32() const; + std::string getExternTableHashMd5() const; + std::string getExternTableHashSha256() const; + std::string getObjectTableHashCrc32() const; + std::string getObjectTableHashMd5() const; + std::string getObjectTableHashSha256() const; + /// @} + + /// @name Setters + /// @{ + void setInfo(const retdec::fileformat::VisualBasicInfo *vbInfo); + void setUsed(bool set); + /// @} + + /// @name Other methods + /// @{ + bool isUsed() const; + bool isPcode() const; + /// @} +}; + +} // namespace fileinfo + +#endif diff --git a/src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.cpp b/src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.cpp new file mode 100644 index 000000000..4596a3326 --- /dev/null +++ b/src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.cpp @@ -0,0 +1,100 @@ +/** + * @file src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.h + * @brief Definition of VisualBasicExternTablePlainGetter class. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/utils/conversion.h" +#include "retdec/utils/string.h" +#include "retdec/fileformat/utils/conversions.h" +#include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.h" + +using namespace retdec::utils; +using namespace retdec::fileformat; + +namespace fileinfo { + +namespace +{ + +const std::size_t distributionArray[] = {6, 40, 40}; +const std::string headerArray[] = {"i", "apiName", "moduleName"}; +const std::string headerDesc[] = {"index", "api name of extern", "module name of extern"}; + +} // anonymous namespace + +/** + * Constructor + * @param fileInfo Information about file + */ +VisualBasicExternTablePlainGetter::VisualBasicExternTablePlainGetter(FileInformation &fileInfo) : IterativeDistributionGetter(fileInfo) +{ + numberOfStructures = 1; + numberOfStoredRecords.push_back(fileinfo.getVisualBasicNumberOfExterns()); + numberOfExtraElements.push_back(0); + title = "Visual basic extern table"; + distribution.insert(distribution.begin(), std::begin(distributionArray), std::end(distributionArray)); + commonHeaderElements.insert(commonHeaderElements.begin(), std::begin(headerArray), std::end(headerArray)); + commonHeaderDesc.insert(commonHeaderDesc.begin(), std::begin(headerDesc), std::end(headerDesc)); + loadRecords(); +} + +/** + * Destructor + */ +VisualBasicExternTablePlainGetter::~VisualBasicExternTablePlainGetter() +{ + +} + +std::size_t VisualBasicExternTablePlainGetter::getBasicInfo(std::size_t structIndex, std::vector &desc, std::vector &info) const +{ + if(structIndex >= numberOfStructures || !fileinfo.isVisualBasicUsed() + || !fileinfo.getVisualBasicNumberOfExterns()) + { + return 0; + } + + desc.clear(); + info.clear(); + + desc.push_back("Number of externs: "); + desc.push_back("CRC32 : "); + desc.push_back("MD5 : "); + desc.push_back("SHA256 : "); + info.push_back(numToStr(fileinfo.getVisualBasicNumberOfExterns())); + info.push_back(fileinfo.getVisualBasicExternTableHashCrc32()); + info.push_back(fileinfo.getVisualBasicExternTableHashMd5()); + info.push_back(fileinfo.getVisualBasicExternTableHashSha256()); + + return info.size(); +} + +bool VisualBasicExternTablePlainGetter::loadRecord(std::size_t structIndex, std::size_t recIndex, std::vector &record) +{ + if(structIndex >= numberOfStructures || recIndex >= numberOfStoredRecords[structIndex]) + { + return false; + } + + record.clear(); + record.push_back(numToStr(recIndex)); + record.push_back(replaceNonprintableChars(fileinfo.getVisualBasicExternApiName(recIndex))); + record.push_back(replaceNonprintableChars(fileinfo.getVisualBasicExternModuleName(recIndex))); + return true; +} + +bool VisualBasicExternTablePlainGetter::getFlagDescriptors(std::size_t structIndex, std::vector &desc, std::vector &abbv) const +{ + if(structIndex >= numberOfStructures) + { + return false; + } + + desc.clear(); + abbv.clear(); + + return true; +} + +} // namespace fileinfo diff --git a/src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.h b/src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.h new file mode 100644 index 000000000..24533f90e --- /dev/null +++ b/src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.h @@ -0,0 +1,31 @@ +/** + * @file src/fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.h + * @brief Definition of VisualBasicExternTablePlainGetter class. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef FILEINFO_FILE_PRESENTATION_GETTERS_ITERATIVE_GETTER_ITERATIVE_DISTRIBUTION_GETTER_VISUAL_BASIC_EXTERN_TABLE_PLAIN_GETTER_H +#define FILEINFO_FILE_PRESENTATION_GETTERS_ITERATIVE_GETTER_ITERATIVE_DISTRIBUTION_GETTER_VISUAL_BASIC_EXTERN_TABLE_PLAIN_GETTER_H + +#include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/iterative_distribution_getter.h" + +namespace fileinfo { + +/** + * Getter for visual basic objects + */ +class VisualBasicExternTablePlainGetter : public IterativeDistributionGetter +{ + protected: + virtual bool loadRecord(std::size_t structIndex, std::size_t recIndex, std::vector &record) override; + public: + VisualBasicExternTablePlainGetter(FileInformation &fileInfo); + virtual ~VisualBasicExternTablePlainGetter() override; + + virtual std::size_t getBasicInfo(std::size_t structIndex, std::vector &desc, std::vector &info) const override; + virtual bool getFlagDescriptors(std::size_t structIndex, std::vector &desc, std::vector &abbv) const override; +}; + +} // namespace fileinfo + +#endif diff --git a/src/fileinfo/file_presentation/getters/json_getters.h b/src/fileinfo/file_presentation/getters/json_getters.h index 8737b05e8..1c9af60c8 100644 --- a/src/fileinfo/file_presentation/getters/json_getters.h +++ b/src/fileinfo/file_presentation/getters/json_getters.h @@ -26,5 +26,6 @@ #include "fileinfo/file_presentation/getters/simple_getter/entry_point_json_getter.h" #include "fileinfo/file_presentation/getters/simple_getter/header_json_getter.h" #include "fileinfo/file_presentation/getters/simple_getter/pdb_json_getter.h" +#include "fileinfo/file_presentation/getters/simple_getter/visual_basic_json_getter.h" #endif diff --git a/src/fileinfo/file_presentation/getters/plain_getters.h b/src/fileinfo/file_presentation/getters/plain_getters.h index 25cc964b0..8a01af36d 100644 --- a/src/fileinfo/file_presentation/getters/plain_getters.h +++ b/src/fileinfo/file_presentation/getters/plain_getters.h @@ -25,8 +25,10 @@ #include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/symbol_tables_plain_getter.h" #include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/typeref_table_plain_getter.h" #include "fileinfo/file_presentation/getters/iterative_getter/iterative_simple_getter/certificate_table_plain_getter.h" +#include "fileinfo/file_presentation/getters/iterative_getter/iterative_distribution_getter/visual_basic_extern_table_plain_getter.h" #include "fileinfo/file_presentation/getters/simple_getter/basic_plain_getter.h" #include "fileinfo/file_presentation/getters/simple_getter/dotnet_plain_getter.h" +#include "fileinfo/file_presentation/getters/simple_getter/visual_basic_plain_getter.h" #include "fileinfo/file_presentation/getters/simple_getter/header_plain_getter.h" #include "fileinfo/file_presentation/getters/simple_getter/pdb_plain_getter.h" diff --git a/src/fileinfo/file_presentation/getters/simple_getter/visual_basic_json_getter.cpp b/src/fileinfo/file_presentation/getters/simple_getter/visual_basic_json_getter.cpp new file mode 100644 index 000000000..959883ad1 --- /dev/null +++ b/src/fileinfo/file_presentation/getters/simple_getter/visual_basic_json_getter.cpp @@ -0,0 +1,91 @@ +/** + * @file src/fileinfo/file_presentation/getters/simple_getter/visual_basic_json_getter.cpp + * @brief Methods of VisualBasicJsonGetter class. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/fileformat/utils/conversions.h" +#include "fileinfo/file_presentation/getters/simple_getter/visual_basic_json_getter.h" + +using namespace retdec::utils; +using namespace retdec::fileformat; + +namespace fileinfo { + +/** + * Constructor + * @param fileInfo Information about file + */ +VisualBasicJsonGetter::VisualBasicJsonGetter(FileInformation &fileInfo) : SimpleGetter(fileInfo) +{ + +} + +/** + * Destructor + */ +VisualBasicJsonGetter::~VisualBasicJsonGetter() +{ + +} + +std::size_t VisualBasicJsonGetter::loadInformation(std::vector &desc, std::vector &info) const +{ + desc.clear(); + info.clear(); + + if (!fileinfo.isVisualBasicUsed()) + { + return 0; + } + + desc.push_back("projectName"); + desc.push_back("projectExeName"); + desc.push_back("projectPath"); + desc.push_back("projectDescription"); + desc.push_back("projectHelpFile"); + desc.push_back("languageDLL"); + desc.push_back("backupLanguageDLL"); + desc.push_back("languageDLLPrimaryLCID"); + desc.push_back("languageDLLSecondaryLCID"); + desc.push_back("projectPrimaryLCID"); + desc.push_back("projectSecondaryLCID"); + desc.push_back("typeLibCLSID"); + desc.push_back("typeLibMajorVersion"); + desc.push_back("typeLibMinorVersion"); + desc.push_back("typeLibLCID"); + desc.push_back("comObjectName"); + desc.push_back("comObjectDescription"); + desc.push_back("comObjectCLSID"); + desc.push_back("comObjectInterfaceCLSID"); + desc.push_back("comObjectEventsCLSID"); + desc.push_back("comObjectType"); + desc.push_back("isPCode"); + + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicProjectName())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicProjectExeName())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicProjectPath())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicProjectDescription())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicProjectHelpFile())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicLanguageDLL())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicBackupLanguageDLL())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicLanguageDLLPrimaryLCIDStr())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicLanguageDLLSecondaryLCIDStr())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicProjectPrimaryLCIDStr())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicProjectSecondaryLCIDStr())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicTypeLibCLSID())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicTypeLibMajorVersionStr())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicTypeLibMinorVersionStr())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicTypeLibLCIDStr())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicCOMObjectName())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicCOMObjectDescription())); + info.push_back(fileinfo.getVisualBasicCOMObjectCLSID()); + info.push_back(fileinfo.getVisualBasicCOMObjectInterfaceCLSID()); + info.push_back(fileinfo.getVisualBasicCOMObjectEventsCLSID()); + info.push_back(fileinfo.getVisualBasicCOMObjectType()); + info.push_back((fileinfo.getVisualBasicIsPcode()) ? "yes" : "no"); + + return info.size(); +} + +} // namespace fileinfo diff --git a/src/fileinfo/file_presentation/getters/simple_getter/visual_basic_json_getter.h b/src/fileinfo/file_presentation/getters/simple_getter/visual_basic_json_getter.h new file mode 100644 index 000000000..c82ec2eb7 --- /dev/null +++ b/src/fileinfo/file_presentation/getters/simple_getter/visual_basic_json_getter.h @@ -0,0 +1,28 @@ +/** + * @file src/fileinfo/file_presentation/getters/simple_getter/visual_basic_json_getter.h + * @brief Definition of VisualBasicJsonGetter class. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef FILEINFO_FILE_PRESENTATION_GETTERS_SIMPLE_GETTER_VISUAL_BASIC_JSON_GETTER_H +#define FILEINFO_FILE_PRESENTATION_GETTERS_SIMPLE_GETTER_VISUAL_BASIC_JSON_GETTER_H + +#include "fileinfo/file_presentation/getters/simple_getter/simple_getter.h" + +namespace fileinfo { + +/** + * Getter for information about Visual Basic + */ +class VisualBasicJsonGetter : public SimpleGetter +{ + public: + VisualBasicJsonGetter(FileInformation &fileInfo); + virtual ~VisualBasicJsonGetter() override; + + virtual std::size_t loadInformation(std::vector &desc, std::vector &info) const override; +}; + +} // namespace fileinfo + +#endif diff --git a/src/fileinfo/file_presentation/getters/simple_getter/visual_basic_plain_getter.cpp b/src/fileinfo/file_presentation/getters/simple_getter/visual_basic_plain_getter.cpp new file mode 100644 index 000000000..de59e3101 --- /dev/null +++ b/src/fileinfo/file_presentation/getters/simple_getter/visual_basic_plain_getter.cpp @@ -0,0 +1,91 @@ +/** + * @file src/fileinfo/file_presentation/getters/simple_getter/visual_basic_plain_getter.cpp + * @brief Methods of VisualBasicPlainGetter class. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#include "retdec/fileformat/utils/conversions.h" +#include "fileinfo/file_presentation/getters/simple_getter/visual_basic_plain_getter.h" + +using namespace retdec::utils; +using namespace retdec::fileformat; + +namespace fileinfo { + +/** + * Constructor + * @param fileInfo Information about file + */ +VisualBasicPlainGetter::VisualBasicPlainGetter(FileInformation &fileInfo) : SimpleGetter(fileInfo) +{ + +} + +/** + * Destructor + */ +VisualBasicPlainGetter::~VisualBasicPlainGetter() +{ + +} + +std::size_t VisualBasicPlainGetter::loadInformation(std::vector &desc, std::vector &info) const +{ + desc.clear(); + info.clear(); + + if (!fileinfo.isVisualBasicUsed()) + { + return 0; + } + + desc.push_back("Project name : "); + desc.push_back("Project exe name : "); + desc.push_back("Project path : "); + desc.push_back("Project description : "); + desc.push_back("Project help file : "); + desc.push_back("Language DLL : "); + desc.push_back("Backup Language DLL : "); + desc.push_back("Language DLL primary LCID : "); + desc.push_back("Language DLL secondary LCID : "); + desc.push_back("Project primary LCID : "); + desc.push_back("Project secondary LCID : "); + desc.push_back("TypeLib CLSID : "); + desc.push_back("TypeLib major version : "); + desc.push_back("TypeLib minor version : "); + desc.push_back("TypeLib LCID : "); + desc.push_back("COM object name : "); + desc.push_back("COM object description : "); + desc.push_back("COM object CLSID : "); + desc.push_back("COM object interface CLSID : "); + desc.push_back("COM object events CLSID : "); + desc.push_back("COM object type : "); + desc.push_back("Is P-Code : "); + + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicProjectName())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicProjectExeName())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicProjectPath())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicProjectDescription())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicProjectHelpFile())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicLanguageDLL())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicBackupLanguageDLL())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicLanguageDLLPrimaryLCIDStr())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicLanguageDLLSecondaryLCIDStr())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicProjectPrimaryLCIDStr())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicProjectSecondaryLCIDStr())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicTypeLibCLSID())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicTypeLibMajorVersionStr())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicTypeLibMinorVersionStr())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicTypeLibLCIDStr())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicCOMObjectName())); + info.push_back(replaceNonprintableChars(fileinfo.getVisualBasicCOMObjectDescription())); + info.push_back(fileinfo.getVisualBasicCOMObjectCLSID()); + info.push_back(fileinfo.getVisualBasicCOMObjectInterfaceCLSID()); + info.push_back(fileinfo.getVisualBasicCOMObjectEventsCLSID()); + info.push_back(fileinfo.getVisualBasicCOMObjectType()); + info.push_back((fileinfo.getVisualBasicIsPcode()) ? "Yes" : "No"); + + return info.size(); +} + +} // namespace fileinfo diff --git a/src/fileinfo/file_presentation/getters/simple_getter/visual_basic_plain_getter.h b/src/fileinfo/file_presentation/getters/simple_getter/visual_basic_plain_getter.h new file mode 100644 index 000000000..03afdc4e3 --- /dev/null +++ b/src/fileinfo/file_presentation/getters/simple_getter/visual_basic_plain_getter.h @@ -0,0 +1,28 @@ +/** + * @file src/fileinfo/file_presentation/getters/simple_getter/visual_basic_plain_getter.h + * @brief Definition of VisualBasicPlainGetter class. + * @copyright (c) 2017 Avast Software, licensed under the MIT license + */ + +#ifndef FILEINFO_FILE_PRESENTATION_GETTERS_SIMPLE_GETTER_VISUAL_BASIC_PLAIN_GETTER_H +#define FILEINFO_FILE_PRESENTATION_GETTERS_SIMPLE_GETTER_VISUAL_BASIC_PLAIN_GETTER_H + +#include "fileinfo/file_presentation/getters/simple_getter/simple_getter.h" + +namespace fileinfo { + +/** + * Getter for information about visual basic + */ +class VisualBasicPlainGetter : public SimpleGetter +{ + public: + VisualBasicPlainGetter(FileInformation &fileInfo); + virtual ~VisualBasicPlainGetter() override; + + virtual std::size_t loadInformation(std::vector &desc, std::vector &info) const override; +}; + +} // namespace fileinfo + +#endif diff --git a/src/fileinfo/file_presentation/json_presentation.cpp b/src/fileinfo/file_presentation/json_presentation.cpp index 6b987f7a9..95c204165 100644 --- a/src/fileinfo/file_presentation/json_presentation.cpp +++ b/src/fileinfo/file_presentation/json_presentation.cpp @@ -480,6 +480,78 @@ void JsonPresentation::presentDotnetInfo(Json::Value &root) const root["dotnetInfo"] = jDotnet; } +/** + * Present information about Visual Basic + * @param root Parent node in output document + */ +void JsonPresentation::presentVisualBasicInfo(Json::Value &root) const +{ + Value jVBasic; + if (!presentSimple(VisualBasicJsonGetter(fileinfo), jVBasic)) + { + return; + } + + auto nExterns = fileinfo.getVisualBasicNumberOfExterns(); + if (nExterns) + { + Value jExternTable; + jExternTable["crc32"] = fileinfo.getVisualBasicExternTableHashCrc32(); + jExternTable["md5"] = fileinfo.getVisualBasicExternTableHashMd5(); + jExternTable["sha256"] = fileinfo.getVisualBasicExternTableHashSha256(); + for (std::size_t i = 0; i < nExterns; i++) + { + auto ext = fileinfo.getVisualBasicExtern(i); + if (!ext) + { + continue; + } + Value jExtern; + jExtern["moduleName"] = ext->getModuleName(); + jExtern["apiName"] = ext->getApiName(); + jExternTable["externs"].append(jExtern); + } + jVBasic["externTable"] = jExternTable; + } + + Value jObjectTable; + auto guid = fileinfo.getVisualBasicObjectTableGUID(); + + if (!guid.empty()) + { + jObjectTable["guid"] = guid; + } + + auto nObjects = fileinfo.getVisualBasicNumberOfObjects(); + if (nObjects) + { + jObjectTable["crc32"] = fileinfo.getVisualBasicObjectTableHashCrc32(); + jObjectTable["md5"] = fileinfo.getVisualBasicObjectTableHashMd5(); + jObjectTable["sha256"] = fileinfo.getVisualBasicObjectTableHashSha256(); + for (std::size_t i = 0; i < nObjects; i++) + { + auto obj = fileinfo.getVisualBasicObject(i); + if (!obj) + { + continue; + } + Value jObject; + jObject["name"] = obj->getName(); + for (const auto &method : obj->getMethods()) + { + jObject["methods"].append(method); + } + jObjectTable["objects"].append(jObject); + } + } + + if (!jObjectTable["guid"].empty() || nObjects > 0) + { + jVBasic["objectTable"] = jObjectTable; + } + root["visualBasicInfo"] = jVBasic; +} + /** * Present ELF notes * @param root Parent node in output document @@ -740,6 +812,7 @@ bool JsonPresentation::present() presentPatterns(root); presentCertificateAttributes(root); presentDotnetInfo(root); + presentVisualBasicInfo(root); } else { diff --git a/src/fileinfo/file_presentation/json_presentation.h b/src/fileinfo/file_presentation/json_presentation.h index 4593efe97..e53023019 100644 --- a/src/fileinfo/file_presentation/json_presentation.h +++ b/src/fileinfo/file_presentation/json_presentation.h @@ -33,6 +33,7 @@ class JsonPresentation : public FilePresentation void presentLoaderInfo(Json::Value &root) const; void presentCertificateAttributes(Json::Value &root) const; void presentDotnetInfo(Json::Value &root) const; + void presentVisualBasicInfo(Json::Value &root) const; void presentElfNotes(Json::Value &root) const; void presentFlags(Json::Value &root, const std::string &title, const std::string &flags, const std::vector &desc) const; void presentIterativeSubtitleStructure(Json::Value &root, const IterativeSubtitleGetter &getter, std::size_t structIndex) const; diff --git a/src/fileinfo/file_presentation/plain_presentation.cpp b/src/fileinfo/file_presentation/plain_presentation.cpp index d8ebeb02f..466f2c011 100644 --- a/src/fileinfo/file_presentation/plain_presentation.cpp +++ b/src/fileinfo/file_presentation/plain_presentation.cpp @@ -627,6 +627,46 @@ void PlainPresentation::presentDotnetClasses() const } } +void PlainPresentation::presentVisualBasicObjects() const +{ + auto nObjs = fileinfo.getVisualBasicNumberOfObjects(); + auto guid = fileinfo.getVisualBasicObjectTableGUID(); + if (!fileinfo.isVisualBasicUsed() || (nObjs == 0 && guid.empty())) + { + return; + } + + std::cout << "\n"; + std::cout << "Visual Basic Object table" << "\n"; + std::cout << "-------------------------" << "\n"; + std::cout << "CRC32 : " << fileinfo.getVisualBasicObjectTableHashCrc32() << "\n"; + std::cout << "MD5 : " << fileinfo.getVisualBasicObjectTableHashMd5() << "\n"; + std::cout << "SHA256 : " << fileinfo.getVisualBasicObjectTableHashSha256() << "\n"; + std::cout << "GUID : " << guid << "\n"; + std::cout << "\n"; + + std::size_t cnt = 0; + for (std::size_t i = 0; i < nObjs; i++) + { + auto obj = fileinfo.getVisualBasicObject(i); + if (!obj) + { + continue; + } + auto objName = obj->getName(); + if (objName.empty()) + { + continue; + } + std::cout << cnt << ". " << "object name: " << objName << "\n"; + for (const auto &m : obj->getMethods()) + { + std::cout << " method name: " << m << "\n"; + } + cnt++; + } +} + /** * Present ELF notes */ @@ -704,6 +744,7 @@ bool PlainPresentation::present() presentIterativeDistribution(ImportTablePlainGetter(fileinfo), explanatory); presentIterativeDistribution(ExportTablePlainGetter(fileinfo), explanatory); presentIterativeDistribution(TypeRefTablePlainGetter(fileinfo), explanatory); + presentIterativeDistribution(VisualBasicExternTablePlainGetter(fileinfo), explanatory); presentIterativeDistribution(RelocationTablesPlainGetter(fileinfo), explanatory); presentIterativeDistribution(DynamicSectionsPlainGetter(fileinfo), explanatory); presentIterativeDistribution(ResourcePlainGetter(fileinfo), explanatory); @@ -728,6 +769,8 @@ bool PlainPresentation::present() presentIterativeSimple(CertificateTablePlainGetter(fileinfo)); presentSimple(DotnetPlainGetter(fileinfo), false, ".NET Information"); presentDotnetClasses(); + presentSimple(VisualBasicPlainGetter(fileinfo), false, "Visual Basic Information"); + presentVisualBasicObjects(); if(returnCode != ReturnCode::FILE_NOT_EXIST && returnCode != ReturnCode::UNKNOWN_FORMAT) { diff --git a/src/fileinfo/file_presentation/plain_presentation.h b/src/fileinfo/file_presentation/plain_presentation.h index 76a74e4c0..3196d24db 100644 --- a/src/fileinfo/file_presentation/plain_presentation.h +++ b/src/fileinfo/file_presentation/plain_presentation.h @@ -30,6 +30,7 @@ class PlainPresentation : public FilePresentation void presentSimpleFlags(const std::string &title, const std::string &flags, const std::vector &desc, const std::vector &abbv) const; void presentPatterns(const std::string &title, const std::vector &patterns); void presentDotnetClasses() const; + void presentVisualBasicObjects() const; void presentNotes() const; void presentCore() const; /// @} diff --git a/src/fileinfo/pattern_detector/pattern_detector.cpp b/src/fileinfo/pattern_detector/pattern_detector.cpp index cda890741..9390c4720 100644 --- a/src/fileinfo/pattern_detector/pattern_detector.cpp +++ b/src/fileinfo/pattern_detector/pattern_detector.cpp @@ -10,6 +10,7 @@ #include "retdec/utils/filesystem_path.h" #include "retdec/utils/string.h" #include "fileinfo/pattern_detector/pattern_detector.h" +#include "yaracpp/yara_detector/yara_detector.h" using namespace retdec::utils; using namespace yaracpp; diff --git a/src/fileinfo/pattern_detector/pattern_detector.h b/src/fileinfo/pattern_detector/pattern_detector.h index 6f978d9ca..4812fdfc5 100644 --- a/src/fileinfo/pattern_detector/pattern_detector.h +++ b/src/fileinfo/pattern_detector/pattern_detector.h @@ -11,9 +11,12 @@ #include #include -#include "yaracpp/yara_detector/yara_detector.h" #include "fileinfo/file_information/file_information.h" +namespace yaracpp { +class YaraRule; +} // namespace yaracpp + namespace fileinfo { /** diff --git a/src/stacofin/stacofin.cpp b/src/stacofin/stacofin.cpp index ec630338a..d96c74df6 100644 --- a/src/stacofin/stacofin.cpp +++ b/src/stacofin/stacofin.cpp @@ -108,10 +108,14 @@ std::set selectSignaturePaths( selectSignaturesWithName(allSigs, sigs, "ucrt"); std::string arch; - if (c.architecture.isX86()) + if (c.architecture.isX86_32()) { arch = "x86"; } + else if (c.architecture.isX86_64()) + { + arch = "x64"; + } else if (c.architecture.isArmOrThumb()) { arch = "arm"; @@ -855,7 +859,7 @@ void Finder::solveReferences() utils::Address Finder::getAddressFromRef(utils::Address ref) { - if (_config->architecture.isX86_32()) + if (_config->architecture.isX86()) { return getAddressFromRef_x86(ref); } diff --git a/src/unpacker/CMakeLists.txt b/src/unpacker/CMakeLists.txt index 3bad97af8..972f6816d 100644 --- a/src/unpacker/CMakeLists.txt +++ b/src/unpacker/CMakeLists.txt @@ -5,7 +5,6 @@ set(UNPACKER_SOURCES decompression/nrv/nrv2e_data.cpp decompression/lzmat/lzmat_data.cpp signature.cpp - dynamic_buffer.cpp ) add_library(retdec-unpacker STATIC ${UNPACKER_SOURCES}) diff --git a/src/unpacker/signature.cpp b/src/unpacker/signature.cpp index 17a1e0093..c2a7bd542 100644 --- a/src/unpacker/signature.cpp +++ b/src/unpacker/signature.cpp @@ -8,6 +8,8 @@ #include "retdec/unpacker/signature.h" +using namespace retdec::utils; + namespace retdec { namespace unpacker { diff --git a/src/unpackertool/plugins/mpress/mpress.cpp b/src/unpackertool/plugins/mpress/mpress.cpp index 14aafe821..373d28782 100644 --- a/src/unpackertool/plugins/mpress/mpress.cpp +++ b/src/unpackertool/plugins/mpress/mpress.cpp @@ -8,8 +8,6 @@ #include #include -#include - #include "retdec/loader/loader.h" #include "retdec/unpacker/plugin.h" #include "retdec/unpacker/decompression/lzma/lzma_data.h" @@ -19,6 +17,9 @@ #include "unpackertool/plugins/mpress/mpress.h" #include "unpackertool/plugins/mpress/mpress_exceptions.h" +#include "retdec/fileformat/fileformat.h" + +using namespace retdec::utils; using namespace retdec::unpacker; namespace retdec { diff --git a/src/unpackertool/plugins/mpress/mpress.h b/src/unpackertool/plugins/mpress/mpress.h index 3523de86b..cbbe9767f 100644 --- a/src/unpackertool/plugins/mpress/mpress.h +++ b/src/unpackertool/plugins/mpress/mpress.h @@ -7,8 +7,10 @@ #ifndef UNPACKERTOOL_PLUGINS_MPRESS_MPRESS_H #define UNPACKERTOOL_PLUGINS_MPRESS_MPRESS_H +#include + #include "retdec/loader/loader.h" -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" #include "retdec/unpacker/plugin.h" #define mpress_plugin plugin(retdec::unpackertool::mpress::MpressPlugin) @@ -72,17 +74,19 @@ class MpressPlugin : public Plugin virtual void cleanup() override; private: - bool decompressData(unpacker::DynamicBuffer& compressedContent, unpacker::DynamicBuffer& decompressedContent); - void decodeLzmaProperties(unpacker::DynamicBuffer& compressedContent, std::uint8_t& pb, std::uint8_t& lp, std::uint8_t& lc); + bool decompressData(retdec::utils::DynamicBuffer& compressedContent, + retdec::utils::DynamicBuffer& decompressedContent); + void decodeLzmaProperties(retdec::utils::DynamicBuffer& compressedContent, std::uint8_t& pb, + std::uint8_t& lp, std::uint8_t& lc); std::uint32_t getFixStub(); - void fixJumpsAndCalls(unpacker::DynamicBuffer& buffer); - void fixImportsAndEp(unpacker::DynamicBuffer& buffer); - void offsetAnalysis(const unpacker::DynamicBuffer& buffer); - void trailingBytesAnalysis(const unpacker::DynamicBuffer& buffer); + void fixJumpsAndCalls(retdec::utils::DynamicBuffer& buffer); + void fixImportsAndEp(retdec::utils::DynamicBuffer& buffer); + void offsetAnalysis(const retdec::utils::DynamicBuffer& buffer); + void trailingBytesAnalysis(const retdec::utils::DynamicBuffer& buffer); void fixRelocations(); MpressUnpackerStub detectUnpackerStubVersion(); - MpressFixStub detectFixStubVersion(unpacker::DynamicBuffer& unpackedContent); - void saveFile(const std::string& fileName, unpacker::DynamicBuffer& content); + MpressFixStub detectFixStubVersion(retdec::utils::DynamicBuffer& unpackedContent); + void saveFile(const std::string& fileName, retdec::utils::DynamicBuffer& content); void copySectionFromOriginalFile(std::uint32_t origSectIndex, const std::string& newFileName, std::uint32_t newSectIndex); std::unique_ptr _file; diff --git a/src/unpackertool/plugins/upx/decompressors/decompressor.cpp b/src/unpackertool/plugins/upx/decompressors/decompressor.cpp index 3207a68d9..edcc5cd02 100644 --- a/src/unpackertool/plugins/upx/decompressors/decompressor.cpp +++ b/src/unpackertool/plugins/upx/decompressors/decompressor.cpp @@ -8,6 +8,7 @@ #include "unpackertool/plugins/upx/upx.h" #include "unpackertool/plugins/upx/upx_exceptions.h" +using namespace retdec::utils; using namespace retdec::unpacker; namespace retdec { diff --git a/src/unpackertool/plugins/upx/decompressors/decompressor.h b/src/unpackertool/plugins/upx/decompressors/decompressor.h index 068bbdd5e..dda247f8e 100644 --- a/src/unpackertool/plugins/upx/decompressors/decompressor.h +++ b/src/unpackertool/plugins/upx/decompressors/decompressor.h @@ -14,10 +14,6 @@ namespace retdec { -namespace unpacker { - class DynamicBuffer; -} // namespace unpacker - namespace unpackertool { namespace upx { @@ -35,29 +31,36 @@ class Decompressor virtual ~Decompressor(); virtual void setupPackingMethod(ElfUpxStub<32>* stub, std::uint8_t packingMethod) = 0; - virtual void decompress(ElfUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) = 0; + virtual void decompress(ElfUpxStub<32>* stub, retdec::utils::DynamicBuffer& packedData, + retdec::utils::DynamicBuffer& unpackedData) = 0; virtual void setupPackingMethod(ElfUpxStub<64>* stub, std::uint8_t packingMethod) = 0; - virtual void decompress(ElfUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) = 0; + virtual void decompress(ElfUpxStub<64>* stub, retdec::utils::DynamicBuffer& packedData, + retdec::utils::DynamicBuffer& unpackedData) = 0; virtual void setupPackingMethod(MachOUpxStub<32>* stub, std::uint8_t packingMethod) = 0; - virtual void decompress(MachOUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) = 0; + virtual void decompress(MachOUpxStub<32>* stub, retdec::utils::DynamicBuffer& packedData, + retdec::utils::DynamicBuffer& unpackedData) = 0; virtual void setupPackingMethod(MachOUpxStub<64>* stub, std::uint8_t packingMethod) = 0; - virtual void decompress(MachOUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) = 0; + virtual void decompress(MachOUpxStub<64>* stub, retdec::utils::DynamicBuffer& packedData, + retdec::utils::DynamicBuffer& unpackedData) = 0; virtual void setupPackingMethod(PeUpxStub<32>* stub, std::uint8_t packingMethod) = 0; - virtual void readUnpackingStub(PeUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& unpackingStub) = 0; - virtual void readPackedData(PeUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, bool trustMetadata) = 0; - virtual void decompress(PeUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData, bool trustMetadata) = 0; + virtual void readUnpackingStub(PeUpxStub<32>* stub, retdec::utils::DynamicBuffer& unpackingStub) = 0; + virtual void readPackedData(PeUpxStub<32>* stub, retdec::utils::DynamicBuffer& packedData, bool trustMetadata) = 0; + virtual void decompress(PeUpxStub<32>* stub, retdec::utils::DynamicBuffer& packedData, + retdec::utils::DynamicBuffer& unpackedData, bool trustMetadata) = 0; virtual void setupPackingMethod(PeUpxStub<64>* stub, std::uint8_t packingMethod) = 0; - virtual void readUnpackingStub(PeUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& unpackingStub) = 0; - virtual void readPackedData(PeUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, bool trustMetadata) = 0; - virtual void decompress(PeUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData, bool trustMetadata) = 0; + virtual void readUnpackingStub(PeUpxStub<64>* stub, retdec::utils::DynamicBuffer& unpackingStub) = 0; + virtual void readPackedData(PeUpxStub<64>* stub, retdec::utils::DynamicBuffer& packedData, bool trustMetadata) = 0; + virtual void decompress(PeUpxStub<64>* stub, retdec::utils::DynamicBuffer& packedData, + retdec::utils::DynamicBuffer& unpackedData, bool trustMetadata) = 0; protected: - void performDecompression(const std::weak_ptr& compressedDataWptr, retdec::unpacker::DynamicBuffer& unpackedData); + void performDecompression(const std::weak_ptr& compressedDataWptr, + retdec::utils::DynamicBuffer& unpackedData); }; } // namespace upx diff --git a/src/unpackertool/plugins/upx/decompressors/decompressor_direct_jump.cpp b/src/unpackertool/plugins/upx/decompressors/decompressor_direct_jump.cpp index a4c864ce2..d71cdae97 100644 --- a/src/unpackertool/plugins/upx/decompressors/decompressor_direct_jump.cpp +++ b/src/unpackertool/plugins/upx/decompressors/decompressor_direct_jump.cpp @@ -14,6 +14,7 @@ #include "unpackertool/plugins/upx/upx_stub.h" #include "unpackertool/plugins/upx/upx_stub_signatures.h" +using namespace retdec::utils; using namespace retdec::unpacker; namespace retdec { diff --git a/src/unpackertool/plugins/upx/decompressors/decompressor_direct_jump.h b/src/unpackertool/plugins/upx/decompressors/decompressor_direct_jump.h index b0321c28c..50374160e 100644 --- a/src/unpackertool/plugins/upx/decompressors/decompressor_direct_jump.h +++ b/src/unpackertool/plugins/upx/decompressors/decompressor_direct_jump.h @@ -21,9 +21,9 @@ class DecompressorDirectJump : public DecompressorScrambler DecompressorDirectJump(); virtual ~DecompressorDirectJump(); - virtual void readUnpackingStub(PeUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& unpackingStub) override; + virtual void readUnpackingStub(PeUpxStub<32>* stub, retdec::utils::DynamicBuffer& unpackingStub) override; - virtual void readUnpackingStub(PeUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& unpackingStub) override; + virtual void readUnpackingStub(PeUpxStub<64>* stub, retdec::utils::DynamicBuffer& unpackingStub) override; }; } // namespace upx diff --git a/src/unpackertool/plugins/upx/decompressors/decompressor_lzma.cpp b/src/unpackertool/plugins/upx/decompressors/decompressor_lzma.cpp index 4a95248bb..05dfedf25 100644 --- a/src/unpackertool/plugins/upx/decompressors/decompressor_lzma.cpp +++ b/src/unpackertool/plugins/upx/decompressors/decompressor_lzma.cpp @@ -14,6 +14,7 @@ #include "unpackertool/plugins/upx/upx_stub.h" #include "retdec/unpacker/decompression/lzma/lzma_data.h" +using namespace retdec::utils; using namespace retdec::unpacker; namespace retdec { diff --git a/src/unpackertool/plugins/upx/decompressors/decompressor_lzma.h b/src/unpackertool/plugins/upx/decompressors/decompressor_lzma.h index 05b3eb9c1..38635fe64 100644 --- a/src/unpackertool/plugins/upx/decompressors/decompressor_lzma.h +++ b/src/unpackertool/plugins/upx/decompressors/decompressor_lzma.h @@ -8,6 +8,7 @@ #include "unpackertool/plugins/upx/decompressors/decompressor.h" + namespace retdec { namespace unpackertool { namespace upx { @@ -22,26 +23,32 @@ class DecompressorLzma : public Decompressor virtual ~DecompressorLzma(); virtual void setupPackingMethod(ElfUpxStub<32>* stub, std::uint8_t packingMethod) override; - virtual void decompress(ElfUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) override; + virtual void decompress(ElfUpxStub<32>* stub, retdec::utils::DynamicBuffer& packedData, + retdec::utils::DynamicBuffer& unpackedData) override; virtual void setupPackingMethod(ElfUpxStub<64>* stub, std::uint8_t packingMethod) override; - virtual void decompress(ElfUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) override; + virtual void decompress(ElfUpxStub<64>* stub, retdec::utils::DynamicBuffer& packedData, + retdec::utils::DynamicBuffer& unpackedData) override; virtual void setupPackingMethod(MachOUpxStub<32>* stub, std::uint8_t packingMethod) override; - virtual void decompress(MachOUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) override; + virtual void decompress(MachOUpxStub<32>* stub, retdec::utils::DynamicBuffer& packedData, + retdec::utils::DynamicBuffer& unpackedData) override; virtual void setupPackingMethod(MachOUpxStub<64>* stub, std::uint8_t packingMethod) override; - virtual void decompress(MachOUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) override; + virtual void decompress(MachOUpxStub<64>* stub, retdec::utils::DynamicBuffer& packedData, + retdec::utils::DynamicBuffer& unpackedData) override; virtual void setupPackingMethod(PeUpxStub<32>* stub, std::uint8_t packingMethod) override; - virtual void readUnpackingStub(PeUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& unpackingStub) override; - virtual void readPackedData(PeUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, bool trustMetadata) override; - virtual void decompress(PeUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData, bool trustMetadata) override; + virtual void readUnpackingStub(PeUpxStub<32>* stub, retdec::utils::DynamicBuffer& unpackingStub) override; + virtual void readPackedData(PeUpxStub<32>* stub, retdec::utils::DynamicBuffer& packedData, bool trustMetadata) override; + virtual void decompress(PeUpxStub<32>* stub, retdec::utils::DynamicBuffer& packedData, + retdec::utils::DynamicBuffer& unpackedData, bool trustMetadata) override; virtual void setupPackingMethod(PeUpxStub<64>* stub, std::uint8_t packingMethod) override; - virtual void readUnpackingStub(PeUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& unpackingStub) override; - virtual void readPackedData(PeUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, bool trustMetadata) override; - virtual void decompress(PeUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData, bool trustMetadata) override; + virtual void readUnpackingStub(PeUpxStub<64>* stub, retdec::utils::DynamicBuffer& unpackingStub) override; + virtual void readPackedData(PeUpxStub<64>* stub, retdec::utils::DynamicBuffer& packedData, bool trustMetadata) override; + virtual void decompress(PeUpxStub<64>* stub, retdec::utils::DynamicBuffer& packedData, + retdec::utils::DynamicBuffer& unpackedData, bool trustMetadata) override; }; } // namespace upx diff --git a/src/unpackertool/plugins/upx/decompressors/decompressor_nrv.cpp b/src/unpackertool/plugins/upx/decompressors/decompressor_nrv.cpp index 018c2eded..fd83331de 100644 --- a/src/unpackertool/plugins/upx/decompressors/decompressor_nrv.cpp +++ b/src/unpackertool/plugins/upx/decompressors/decompressor_nrv.cpp @@ -16,6 +16,7 @@ #include "retdec/unpacker/decompression/nrv/nrv2d_data.h" #include "retdec/unpacker/decompression/nrv/nrv2e_data.h" +using namespace retdec::utils; using namespace retdec::unpacker; namespace retdec { @@ -379,7 +380,7 @@ void DecompressorNrv::setupPackingMethod(std::uint8_t packingMethod) } } -void DecompressorNrv::decompress(retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) +void DecompressorNrv::decompress(DynamicBuffer& packedData, DynamicBuffer& unpackedData) { if (_bitParser == nullptr) throw FatalException("Unpacking NRV packed data without bit parser. Report this incident please."); diff --git a/src/unpackertool/plugins/upx/decompressors/decompressor_nrv.h b/src/unpackertool/plugins/upx/decompressors/decompressor_nrv.h index cd0e53f14..5245928a2 100644 --- a/src/unpackertool/plugins/upx/decompressors/decompressor_nrv.h +++ b/src/unpackertool/plugins/upx/decompressors/decompressor_nrv.h @@ -9,6 +9,8 @@ #include "unpackertool/plugins/upx/decompressors/decompressor.h" #include "retdec/unpacker/decompression/nrv/bit_parsers.h" +using namespace retdec::utils; + namespace retdec { namespace unpackertool { namespace upx { @@ -23,30 +25,30 @@ class DecompressorNrv : public Decompressor virtual ~DecompressorNrv(); virtual void setupPackingMethod(ElfUpxStub<32>* stub, std::uint8_t packingMethod) override; - virtual void decompress(ElfUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) override; + virtual void decompress(ElfUpxStub<32>* stub, DynamicBuffer& packedData, DynamicBuffer& unpackedData) override; virtual void setupPackingMethod(ElfUpxStub<64>* stub, std::uint8_t packingMethod) override; - virtual void decompress(ElfUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) override; + virtual void decompress(ElfUpxStub<64>* stub, DynamicBuffer& packedData, DynamicBuffer& unpackedData) override; virtual void setupPackingMethod(MachOUpxStub<32>* stub, std::uint8_t packingMethod) override; - virtual void decompress(MachOUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) override; + virtual void decompress(MachOUpxStub<32>* stub, DynamicBuffer& packedData, DynamicBuffer& unpackedData) override; virtual void setupPackingMethod(MachOUpxStub<64>* stub, std::uint8_t packingMethod) override; - virtual void decompress(MachOUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) override; + virtual void decompress(MachOUpxStub<64>* stub, DynamicBuffer& packedData, DynamicBuffer& unpackedData) override; virtual void setupPackingMethod(PeUpxStub<32>* stub, std::uint8_t packingMethod) override; - virtual void readUnpackingStub(PeUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& unpackingStub) override; - virtual void readPackedData(PeUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, bool trustMetadata) override; - virtual void decompress(PeUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData, bool trustMetadata) override; + virtual void readUnpackingStub(PeUpxStub<32>* stub, DynamicBuffer& unpackingStub) override; + virtual void readPackedData(PeUpxStub<32>* stub, DynamicBuffer& packedData, bool trustMetadata) override; + virtual void decompress(PeUpxStub<32>* stub, DynamicBuffer& packedData, DynamicBuffer& unpackedData, bool trustMetadata) override; virtual void setupPackingMethod(PeUpxStub<64>* stub, std::uint8_t packingMethod) override; - virtual void readUnpackingStub(PeUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& unpackingStub) override; - virtual void readPackedData(PeUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, bool trustMetadata) override; - virtual void decompress(PeUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData, bool trustMetadata) override; + virtual void readUnpackingStub(PeUpxStub<64>* stub, DynamicBuffer& unpackingStub) override; + virtual void readPackedData(PeUpxStub<64>* stub, DynamicBuffer& packedData, bool trustMetadata) override; + virtual void decompress(PeUpxStub<64>* stub, DynamicBuffer& packedData, DynamicBuffer& unpackedData, bool trustMetadata) override; protected: void setupPackingMethod(std::uint8_t packingMethod); - void decompress(retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData); + void decompress(DynamicBuffer& packedData, DynamicBuffer& unpackedData); private: char _nrvVersion; diff --git a/src/unpackertool/plugins/upx/decompressors/decompressor_scrambler.h b/src/unpackertool/plugins/upx/decompressors/decompressor_scrambler.h index 3a8cd6482..47d399093 100644 --- a/src/unpackertool/plugins/upx/decompressors/decompressor_scrambler.h +++ b/src/unpackertool/plugins/upx/decompressors/decompressor_scrambler.h @@ -8,6 +8,8 @@ #include "unpackertool/plugins/upx/decompressors/decompressor.h" +using namespace retdec::utils; + namespace retdec { namespace unpackertool { namespace upx { @@ -24,24 +26,24 @@ class DecompressorScrambler : public Decompressor virtual ~DecompressorScrambler(); virtual void setupPackingMethod(ElfUpxStub<32>* stub, std::uint8_t packingMethod) override; - virtual void decompress(ElfUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) override; + virtual void decompress(ElfUpxStub<32>* stub, DynamicBuffer& packedData, DynamicBuffer& unpackedData) override; virtual void setupPackingMethod(ElfUpxStub<64>* stub, std::uint8_t packingMethod) override; - virtual void decompress(ElfUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) override; + virtual void decompress(ElfUpxStub<64>* stub, DynamicBuffer& packedData, DynamicBuffer& unpackedData) override; virtual void setupPackingMethod(MachOUpxStub<32>* stub, std::uint8_t packingMethod) override; - virtual void decompress(MachOUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) override; + virtual void decompress(MachOUpxStub<32>* stub, DynamicBuffer& packedData, DynamicBuffer& unpackedData) override; virtual void setupPackingMethod(MachOUpxStub<64>* stub, std::uint8_t packingMethod) override; - virtual void decompress(MachOUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) override; + virtual void decompress(MachOUpxStub<64>* stub, DynamicBuffer& packedData, DynamicBuffer& unpackedData) override; virtual void setupPackingMethod(PeUpxStub<32>* stub, std::uint8_t packingMethod) override; - virtual void readPackedData(PeUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, bool trustMetadata) override; - virtual void decompress(PeUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData, bool trustMetadata) override; + virtual void readPackedData(PeUpxStub<32>* stub, DynamicBuffer& packedData, bool trustMetadata) override; + virtual void decompress(PeUpxStub<32>* stub, DynamicBuffer& packedData, DynamicBuffer& unpackedData, bool trustMetadata) override; virtual void setupPackingMethod(PeUpxStub<64>* stub, std::uint8_t packingMethod) override; - virtual void readPackedData(PeUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, bool trustMetadata) override; - virtual void decompress(PeUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData, bool trustMetadata) override; + virtual void readPackedData(PeUpxStub<64>* stub, DynamicBuffer& packedData, bool trustMetadata) override; + virtual void decompress(PeUpxStub<64>* stub, DynamicBuffer& packedData, DynamicBuffer& unpackedData, bool trustMetadata) override; protected: std::shared_ptr _scrambledStub; ///< The unpacking stub packed by this scrambler. diff --git a/src/unpackertool/plugins/upx/decompressors/decompressor_upxshit.h b/src/unpackertool/plugins/upx/decompressors/decompressor_upxshit.h index 2ab324255..29859b8f1 100644 --- a/src/unpackertool/plugins/upx/decompressors/decompressor_upxshit.h +++ b/src/unpackertool/plugins/upx/decompressors/decompressor_upxshit.h @@ -8,6 +8,8 @@ #include "unpackertool/plugins/upx/decompressors/decompressor_scrambler.h" +using namespace retdec::utils; + namespace retdec { namespace unpackertool { namespace upx { @@ -21,9 +23,9 @@ class DecompressorUpxshit : public DecompressorScrambler DecompressorUpxshit(); virtual ~DecompressorUpxshit(); - virtual void readUnpackingStub(PeUpxStub<32>* stub, retdec::unpacker::DynamicBuffer& unpackingStub) override; + virtual void readUnpackingStub(PeUpxStub<32>* stub, DynamicBuffer& unpackingStub) override; - virtual void readUnpackingStub(PeUpxStub<64>* stub, retdec::unpacker::DynamicBuffer& unpackingStub) override; + virtual void readUnpackingStub(PeUpxStub<64>* stub, DynamicBuffer& unpackingStub) override; }; } // namespace upx diff --git a/src/unpackertool/plugins/upx/elf/elf_upx_stub.cpp b/src/unpackertool/plugins/upx/elf/elf_upx_stub.cpp index e887609e7..55a1de714 100644 --- a/src/unpackertool/plugins/upx/elf/elf_upx_stub.cpp +++ b/src/unpackertool/plugins/upx/elf/elf_upx_stub.cpp @@ -18,8 +18,9 @@ #include "unpackertool/plugins/upx/upx.h" #include "unpackertool/plugins/upx/upx_exceptions.h" #include "unpackertool/plugins/upx/upx_stub_signatures.h" -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" +using namespace retdec::utils; using namespace retdec::unpacker; namespace retdec { @@ -256,7 +257,7 @@ template void ElfUpxStub::setupPackingMethod(std::uint8_t packi * @param packedData The packed data. * @param unpackedData Buffer where to unpack the data. */ -template void ElfUpxStub::decompress(retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) +template void ElfUpxStub::decompress(DynamicBuffer& packedData, DynamicBuffer& unpackedData) { _decompressor->decompress(this, packedData, unpackedData); } @@ -370,7 +371,7 @@ template void ElfUpxStub::unpackBlock(DynamicBuffer& unpackedDa } /** - * Unpacks the packed block that is stored in the @ref retdec::unpacker::DynamicBuffer. + * Unpacks the packed block that is stored in the @ref retdec::utils::DynamicBuffer. * * @tparam bits Number of bits of the architecture. * diff --git a/src/unpackertool/plugins/upx/elf/elf_upx_stub.h b/src/unpackertool/plugins/upx/elf/elf_upx_stub.h index dd84fba0b..ecc150672 100644 --- a/src/unpackertool/plugins/upx/elf/elf_upx_stub.h +++ b/src/unpackertool/plugins/upx/elf/elf_upx_stub.h @@ -11,7 +11,9 @@ #include "unpackertool/plugins/upx/upx_stub.h" #include "retdec/unpacker/decompression/nrv/bit_parsers.h" -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" + +using namespace retdec::utils; // Foroward declarations namespace ELFIO { @@ -81,7 +83,7 @@ template class ElfUpxStub : public UpxStub using ElfHeaderType = typename ElfUpxStubTraits::ElfHeaderType; using ProgHeaderType = typename ElfUpxStubTraits::ProgHeaderType; - ElfUpxStub(retdec::loader::Image* inputFile, const UpxStubData* stubData, const retdec::unpacker::DynamicBuffer& stubCapturedData, + ElfUpxStub(retdec::loader::Image* inputFile, const UpxStubData* stubData, const DynamicBuffer& stubCapturedData, std::unique_ptr decompressor, const UpxMetadata& metadata); virtual ~ElfUpxStub() override; @@ -90,15 +92,15 @@ template class ElfUpxStub : public UpxStub virtual void cleanup() override; void setupPackingMethod(std::uint8_t packingMethod); - void decompress(retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData); + void decompress(DynamicBuffer& packedData, DynamicBuffer& unpackedData); private: std::uint32_t getFirstBlockOffset(); - bool validBlock(const retdec::unpacker::DynamicBuffer& block); - void unpackBlock(retdec::unpacker::DynamicBuffer& unpackedData, AddressType fileOffset, AddressType& readFromBuffer, std::uint32_t sizeHint = 0); - void unpackBlock(retdec::unpacker::DynamicBuffer& unpackedData, retdec::unpacker::DynamicBuffer& packedBlock, AddressType& readFromBuffer, std::uint32_t sizeHint = 0); + bool validBlock(const DynamicBuffer& block); + void unpackBlock(DynamicBuffer& unpackedData, AddressType fileOffset, AddressType& readFromBuffer, std::uint32_t sizeHint = 0); + void unpackBlock(DynamicBuffer& unpackedData, DynamicBuffer& packedBlock, AddressType& readFromBuffer, std::uint32_t sizeHint = 0); AddressType nextLoadSegmentGap(const std::vector& phdrs, std::uint32_t currentLoadSegmentIndex); - void unfilterBlock(const retdec::unpacker::DynamicBuffer& packedBlock, retdec::unpacker::DynamicBuffer& unpackedData); + void unfilterBlock(const DynamicBuffer& packedBlock, DynamicBuffer& unpackedData); retdec::unpacker::BitParser* _bitParser; ///< Associated NRV bit parser. }; diff --git a/src/unpackertool/plugins/upx/macho/macho_upx_stub.cpp b/src/unpackertool/plugins/upx/macho/macho_upx_stub.cpp index ad3916fee..c8c3ec329 100644 --- a/src/unpackertool/plugins/upx/macho/macho_upx_stub.cpp +++ b/src/unpackertool/plugins/upx/macho/macho_upx_stub.cpp @@ -14,8 +14,9 @@ #include "unpackertool/plugins/upx/unfilter.h" #include "unpackertool/plugins/upx/upx.h" #include "unpackertool/plugins/upx/upx_exceptions.h" -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" +using namespace retdec::utils; using namespace retdec::unpacker; namespace retdec { @@ -170,7 +171,7 @@ template void MachOUpxStub::setupPackingMethod(std::uint8_t pac _decompressor->setupPackingMethod(this, packingMethod); } -template void MachOUpxStub::decompress(retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData) +template void MachOUpxStub::decompress(DynamicBuffer& packedData, DynamicBuffer& unpackedData) { _decompressor->decompress(this, packedData, unpackedData); } diff --git a/src/unpackertool/plugins/upx/macho/macho_upx_stub.h b/src/unpackertool/plugins/upx/macho/macho_upx_stub.h index 5cdca23cd..64871da21 100644 --- a/src/unpackertool/plugins/upx/macho/macho_upx_stub.h +++ b/src/unpackertool/plugins/upx/macho/macho_upx_stub.h @@ -11,7 +11,9 @@ #include "unpackertool/plugins/upx/upx_stub.h" #include "retdec/unpacker/decompression/nrv/bit_parsers.h" -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" + +using namespace retdec::utils; namespace retdec { namespace unpackertool { @@ -67,7 +69,7 @@ template class MachOUpxStub : public UpxStub using MachOHeaderType = typename MachOUpxStubTraits::MachOHeaderType; using MachOSegmentCommandType = typename MachOUpxStubTraits::MachOSegmentCommandType; - MachOUpxStub(retdec::loader::Image* inputFile, const UpxStubData* stubData, const retdec::unpacker::DynamicBuffer& stubCapturedData, + MachOUpxStub(retdec::loader::Image* inputFile, const UpxStubData* stubData, const DynamicBuffer& stubCapturedData, std::unique_ptr decompressor, const UpxMetadata& metadata); virtual ~MachOUpxStub() override; @@ -76,15 +78,15 @@ template class MachOUpxStub : public UpxStub virtual void cleanup() override; void setupPackingMethod(std::uint8_t packingMethod); - void decompress(retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData); + void decompress(DynamicBuffer& packedData, DynamicBuffer& unpackedData); void unpack(std::ifstream& inputFile, std::ofstream& outputFile, std::uint64_t baseInputOffset, std::uint64_t baseOutputOffset); protected: std::uint32_t getFirstBlockOffset(std::ifstream& inputFile) const; - retdec::unpacker::DynamicBuffer readNextBlock(std::ifstream& inputFile); - retdec::unpacker::DynamicBuffer unpackBlock(retdec::unpacker::DynamicBuffer& packedBlock); - void unfilterBlock(const retdec::unpacker::DynamicBuffer& packedBlock, retdec::unpacker::DynamicBuffer& unpackedData); + DynamicBuffer readNextBlock(std::ifstream& inputFile); + DynamicBuffer unpackBlock(DynamicBuffer& packedBlock); + void unfilterBlock(const DynamicBuffer& packedBlock, DynamicBuffer& unpackedData); private: std::uint64_t _readPos; diff --git a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp index 5f0786c8a..22dd0b7fa 100644 --- a/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp +++ b/src/unpackertool/plugins/upx/pe/pe_upx_stub.cpp @@ -271,7 +271,7 @@ template void PeUpxStub::setupPackingMethod(std::uint8_t packin } /** - * Reads the unpacking stub (from EP up to the end of the EP section) and stores it into @ref retdec::unpacker::DynamicBuffer. + * Reads the unpacking stub (from EP up to the end of the EP section) and stores it into @ref retdec::utils::DynamicBuffer. * * @param unpackingStub Buffer where to store unpacking stub. */ @@ -292,7 +292,7 @@ template void PeUpxStub::readPackedData(DynamicBuffer& packedDa } /** - * Decompresses the packed data and stores result in @ref retdec::unpacker::DynamicBuffer. + * Decompresses the packed data and stores result in @ref retdec::utils::DynamicBuffer. * * @param packedData Data to decompress. * @param unpackedData Buffer where to store the result. @@ -427,7 +427,7 @@ template void PeUpxStub::unpackData(DynamicBuffer& unpackedData } /** - * Reads the ILT (Import Lookup Table) of the packed file and stores it into @ref retdec::unpacker::DynamicBuffer. + * Reads the ILT (Import Lookup Table) of the packed file and stores it into @ref retdec::utils::DynamicBuffer. * * @param ilt Buffer where to store ILT. */ @@ -510,7 +510,7 @@ template void PeUpxStub::fixSizeOfSections(const DynamicBuffer& * * @return @ref UpxExtraData structure. */ -template UpxExtraData PeUpxStub::parseExtraData(retdec::unpacker::DynamicBuffer& unpackedData, retdec::unpacker::DynamicBuffer& originalHeader) +template UpxExtraData PeUpxStub::parseExtraData(DynamicBuffer& unpackedData, DynamicBuffer& originalHeader) { // First we need to find original PE header. If we have metadata, we can easily find it using unpacked data size. // However, if we don't have, we need to use heuristic that looks in the last 1024 bytes (should be more than enough) @@ -828,7 +828,7 @@ template void PeUpxStub::fixOep(const DynamicBuffer& originalHe * * @param originalHeader The original PE header. */ -template void PeUpxStub::fixExports(const retdec::unpacker::DynamicBuffer& originalHeader) +template void PeUpxStub::fixExports(const DynamicBuffer& originalHeader) { // Assumption is that exports are compressed _exportsCompressed = true; @@ -1171,7 +1171,7 @@ template void PeUpxStub::fixCertificates() * @param unpackedData The unpacked data. * @param extraData @ref UpxExtraData structure. */ -template void PeUpxStub::cutHintsData(retdec::unpacker::DynamicBuffer& unpackedData, const UpxExtraData& extraData) +template void PeUpxStub::cutHintsData(DynamicBuffer& unpackedData, const UpxExtraData& extraData) { // We need to find lowest possible address where we can cut the unpacked data and remove hints. // We always know the address of original PE header, we need to check whether import hints or reloc hints are at lower address. diff --git a/src/unpackertool/plugins/upx/pe/pe_upx_stub.h b/src/unpackertool/plugins/upx/pe/pe_upx_stub.h index 4e2885e8e..56cf99f2f 100644 --- a/src/unpackertool/plugins/upx/pe/pe_upx_stub.h +++ b/src/unpackertool/plugins/upx/pe/pe_upx_stub.h @@ -9,10 +9,14 @@ #include +#include + #include "unpackertool/plugins/upx/upx_stub.h" -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" #include "retdec/unpacker/signature.h" +using namespace retdec::utils; + namespace retdec { namespace unpackertool { namespace upx { @@ -109,16 +113,16 @@ template class PeUpxStub : public UpxStub using PeLibFileType = typename PeUpxStubTraits::PeLibFileType; public: - PeUpxStub(retdec::loader::Image* inputFile, const UpxStubData* stubData, const retdec::unpacker::DynamicBuffer& stubCapturedData, + PeUpxStub(retdec::loader::Image* inputFile, const UpxStubData* stubData, const DynamicBuffer& stubCapturedData, std::unique_ptr decompressor, const UpxMetadata& metadata); virtual ~PeUpxStub() override; virtual void unpack(const std::string& ouputFile) override; virtual void setupPackingMethod(std::uint8_t packingMethod); - virtual void readUnpackingStub(retdec::unpacker::DynamicBuffer& unpackingStub); - virtual void readPackedData(retdec::unpacker::DynamicBuffer& packedData, bool trustMetadata); - virtual void decompress(retdec::unpacker::DynamicBuffer& packedData, retdec::unpacker::DynamicBuffer& unpackedData, bool trustMetadata); + virtual void readUnpackingStub(DynamicBuffer& unpackingStub); + virtual void readPackedData(DynamicBuffer& packedData, bool trustMetadata); + virtual void decompress(DynamicBuffer& packedData, DynamicBuffer& unpackedData, bool trustMetadata); virtual void cleanup() override; virtual std::uint32_t getRealEpAddress() const override; @@ -130,28 +134,28 @@ template class PeUpxStub : public UpxStub private: void prepare(); - void detectUnfilter(const retdec::unpacker::DynamicBuffer& unpackingStub); - void unpackData(retdec::unpacker::DynamicBuffer& unpackedData); - void readPackedFileILT(retdec::unpacker::DynamicBuffer& ilt); - void fixSizeOfSections(const retdec::unpacker::DynamicBuffer& unpackedData); - UpxExtraData parseExtraData(retdec::unpacker::DynamicBuffer& unpackedData, retdec::unpacker::DynamicBuffer& originalHeader); - void fixPeHeader(const retdec::unpacker::DynamicBuffer& originalHeader); - void unfilterData(retdec::unpacker::DynamicBuffer& unpackedData); - void fixImports(const retdec::unpacker::DynamicBuffer& unpackedData, const UpxExtraData& extraData, const retdec::unpacker::DynamicBuffer& ilt); - void fixRelocations(retdec::unpacker::DynamicBuffer& unpackedData, const UpxExtraData& extraData); - void fixTls(const retdec::unpacker::DynamicBuffer& originalHeader); - void fixOep(const retdec::unpacker::DynamicBuffer& originalHeader); - void fixExports(const retdec::unpacker::DynamicBuffer& originalHeader); - void fixLoadConfiguration(const retdec::unpacker::DynamicBuffer& originalHeader); - void fixResources(const retdec::unpacker::DynamicBuffer& unpackedData, const retdec::unpacker::DynamicBuffer& originalHeader); - void fixSectionHeaders(const retdec::unpacker::DynamicBuffer& originalHeader); + void detectUnfilter(const DynamicBuffer& unpackingStub); + void unpackData(DynamicBuffer& unpackedData); + void readPackedFileILT(DynamicBuffer& ilt); + void fixSizeOfSections(const DynamicBuffer& unpackedData); + UpxExtraData parseExtraData(DynamicBuffer& unpackedData, DynamicBuffer& originalHeader); + void fixPeHeader(const DynamicBuffer& originalHeader); + void unfilterData(DynamicBuffer& unpackedData); + void fixImports(const DynamicBuffer& unpackedData, const UpxExtraData& extraData, const DynamicBuffer& ilt); + void fixRelocations(DynamicBuffer& unpackedData, const UpxExtraData& extraData); + void fixTls(const DynamicBuffer& originalHeader); + void fixOep(const DynamicBuffer& originalHeader); + void fixExports(const DynamicBuffer& originalHeader); + void fixLoadConfiguration(const DynamicBuffer& originalHeader); + void fixResources(const DynamicBuffer& unpackedData, const DynamicBuffer& originalHeader); + void fixSectionHeaders(const DynamicBuffer& originalHeader); void fixCoffSymbolTable(); void fixCertificates(); - void cutHintsData(retdec::unpacker::DynamicBuffer& unpackedData, const UpxExtraData& extraData); - void saveFile(const std::string& outputFile, retdec::unpacker::DynamicBuffer& unpackedData); + void cutHintsData(DynamicBuffer& unpackedData, const UpxExtraData& extraData); + void saveFile(const std::string& outputFile, DynamicBuffer& unpackedData); void loadResources(PeLib::ResourceNode* rootNode, std::uint32_t offset, std::uint32_t uncompressedRsrcRva, std::uint32_t compressedRsrcRva, - const retdec::unpacker::DynamicBuffer& uncompressedRsrcs, const retdec::unpacker::DynamicBuffer& unpackedData, std::unordered_set& visitedNodes); + const DynamicBuffer& uncompressedRsrcs, const DynamicBuffer& unpackedData, std::unordered_set& visitedNodes); std::uint8_t getPackingMethod(bool trustMetadata) const; PeLibFileType* _newPeFile; ///< Unpacked output file. diff --git a/src/unpackertool/plugins/upx/unfilter.cpp b/src/unpackertool/plugins/upx/unfilter.cpp index c221114e6..15515176d 100644 --- a/src/unpackertool/plugins/upx/unfilter.cpp +++ b/src/unpackertool/plugins/upx/unfilter.cpp @@ -5,10 +5,11 @@ */ #include +#include #include "unpackertool/plugins/upx/unfilter.h" -using namespace retdec::unpacker; +using namespace retdec::utils; namespace retdec { namespace unpackertool { diff --git a/src/unpackertool/plugins/upx/unfilter.h b/src/unpackertool/plugins/upx/unfilter.h index 2da08769f..8c87389ca 100644 --- a/src/unpackertool/plugins/upx/unfilter.h +++ b/src/unpackertool/plugins/upx/unfilter.h @@ -7,7 +7,9 @@ #ifndef UNPACKERTOOL_PLUGINS_UPX_UNFILTER_H #define UNPACKERTOOL_PLUGINS_UPX_UNFILTER_H -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" + +using namespace retdec::utils; namespace retdec { namespace unpackertool { @@ -37,9 +39,9 @@ struct Unfilter { virtual ~Unfilter() {} - virtual void perform(retdec::unpacker::DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) = 0; + virtual void perform(DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) = 0; - static bool run(retdec::unpacker::DynamicBuffer& unpackedData, std::uint32_t filterId, std::uint32_t filterParam, std::uint32_t filterCount = 0, std::uint32_t startOffset = 0, std::uint32_t size = 0); + static bool run(DynamicBuffer& unpackedData, std::uint32_t filterId, std::uint32_t filterParam, std::uint32_t filterCount = 0, std::uint32_t startOffset = 0, std::uint32_t size = 0); }; /** @@ -49,7 +51,7 @@ struct Unfilter11 : public Unfilter { virtual ~Unfilter11() override {} - virtual void perform(retdec::unpacker::DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) override; + virtual void perform(DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) override; }; /** @@ -59,7 +61,7 @@ struct Unfilter16 : public Unfilter { virtual ~Unfilter16() override {} - virtual void perform(retdec::unpacker::DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) override; + virtual void perform(DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) override; }; /** @@ -69,7 +71,7 @@ struct Unfilter24 : public Unfilter { virtual ~Unfilter24() override {} - virtual void perform(retdec::unpacker::DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) override; + virtual void perform(DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) override; }; /** @@ -79,7 +81,7 @@ struct Unfilter26_46 : public Unfilter { virtual ~Unfilter26_46() override {} - virtual void perform(retdec::unpacker::DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) override; + virtual void perform(DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) override; }; /** @@ -89,7 +91,7 @@ struct Unfilter49 : public Unfilter { virtual ~Unfilter49() override {} - virtual void perform(retdec::unpacker::DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) override; + virtual void perform(DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) override; }; /** @@ -99,7 +101,7 @@ struct Unfilter50 : public Unfilter { virtual ~Unfilter50() override {} - virtual void perform(retdec::unpacker::DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) override; + virtual void perform(DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) override; }; /** @@ -109,7 +111,7 @@ struct UnfilterD0 : public Unfilter { virtual ~UnfilterD0() override {} - virtual void perform(retdec::unpacker::DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) override; + virtual void perform(DynamicBuffer& unpackedData, std::uint32_t filterParam, std::uint32_t filterCount, std::uint32_t startOffset, std::uint32_t size) override; }; } // namespace upx diff --git a/src/unpackertool/plugins/upx/upx_stub.cpp b/src/unpackertool/plugins/upx/upx_stub.cpp index cdd50ceac..aabde4fc0 100644 --- a/src/unpackertool/plugins/upx/upx_stub.cpp +++ b/src/unpackertool/plugins/upx/upx_stub.cpp @@ -14,8 +14,9 @@ #include "unpackertool/plugins/upx/upx_stub.h" #include "unpackertool/plugins/upx/upx_stub_signatures.h" #include "retdec/unpacker/decompression/compressed_data.h" -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" +using namespace retdec::utils; using namespace retdec::unpacker; namespace retdec { @@ -72,7 +73,7 @@ UpxMetadata UpxMetadata::read(retdec::loader::Image* file) } inputFile.read(reinterpret_cast(&dataBuffer[0]), 1024); - retdec::unpacker::DynamicBuffer data(dataBuffer, file->getFileFormat()->getEndianness()); + DynamicBuffer data(dataBuffer, file->getFileFormat()->getEndianness()); std::string pattern = "UPX!"; for (size_t i = 0; i < 1024 - pattern.length(); ++i) @@ -81,7 +82,7 @@ UpxMetadata UpxMetadata::read(retdec::loader::Image* file) if (needle == pattern) { std::uint32_t metadataSize = UpxMetadata::getSizeOfVersion(data.read(static_cast(i) + 4)); - retdec::unpacker::DynamicBuffer metadataBuffer(data, static_cast(i), metadataSize); + DynamicBuffer metadataBuffer(data, static_cast(i), metadataSize); // Check whether calculated checksum and checksum in header matches // This is the only way how we can validate the metadata @@ -105,7 +106,7 @@ UpxMetadata UpxMetadata::read(retdec::loader::Image* file) return metadata; } -uint8_t UpxMetadata::calcChecksum(const retdec::unpacker::DynamicBuffer& data) +uint8_t UpxMetadata::calcChecksum(const DynamicBuffer& data) { std::uint32_t sum = 0; for (std::uint32_t i = 4; i < data.getRealDataSize() - 1; ++i) @@ -181,7 +182,7 @@ std::shared_ptr UpxStub::createStub(retdec::loader::Image* file, const return _createStubImpl(file, &stubBytes); } -std::shared_ptr UpxStub::_createStubImpl(retdec::loader::Image* file, const retdec::unpacker::DynamicBuffer* stubBytes) +std::shared_ptr UpxStub::_createStubImpl(retdec::loader::Image* file, const DynamicBuffer* stubBytes) { UpxMetadata metadata = UpxMetadata::read(file); @@ -377,7 +378,7 @@ void UpxStub::setStubData(const UpxStubData* stubData) _stubData = stubData; } -void UpxStub::setStubCapturedData(const retdec::unpacker::DynamicBuffer& stubCapturedData) +void UpxStub::setStubCapturedData(const DynamicBuffer& stubCapturedData) { _stubCapturedData = stubCapturedData; } diff --git a/src/unpackertool/plugins/upx/upx_stub.h b/src/unpackertool/plugins/upx/upx_stub.h index 199d887c4..47a25418e 100644 --- a/src/unpackertool/plugins/upx/upx_stub.h +++ b/src/unpackertool/plugins/upx/upx_stub.h @@ -11,9 +11,11 @@ #include "retdec/loader/loader.h" #include "retdec/unpacker/plugin.h" -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" #include "retdec/unpacker/unpacking_stub.h" +using namespace retdec::utils; + namespace retdec { // Forward declaration @@ -64,7 +66,7 @@ class UpxMetadata UpxMetadata(const UpxMetadata& metadata); static UpxMetadata read(retdec::loader::Image* file); - static std::uint8_t calcChecksum(const retdec::unpacker::DynamicBuffer& data); + static std::uint8_t calcChecksum(const DynamicBuffer& data); static std::uint32_t getSizeOfVersion(std::uint8_t version); UpxStubVersion getStubVersion() const; @@ -108,34 +110,34 @@ class UpxMetadata class UpxStub : public retdec::unpacker::UnpackingStub { public: - UpxStub(retdec::loader::Image* inputFile, const UpxStubData* stubData, const retdec::unpacker::DynamicBuffer& stubCapturedData, + UpxStub(retdec::loader::Image* inputFile, const UpxStubData* stubData, const DynamicBuffer& stubCapturedData, std::unique_ptr decompressor, const UpxMetadata& metadata); virtual ~UpxStub() override; static std::shared_ptr createStub(retdec::loader::Image* file); - static std::shared_ptr createStub(retdec::loader::Image* file, const retdec::unpacker::DynamicBuffer& stubBytes); + static std::shared_ptr createStub(retdec::loader::Image* file, const DynamicBuffer& stubBytes); UpxStubVersion getVersion() const; const UpxStubData* getStubData() const; - const retdec::unpacker::DynamicBuffer* getStubCapturedData() const; + const DynamicBuffer* getStubCapturedData() const; Decompressor* getDecompressor() const; const UpxMetadata* getUpxMetadata() const; virtual std::uint32_t getRealEpAddress() const; void setStubData(const UpxStubData* stubData); - void setStubCapturedData(const retdec::unpacker::DynamicBuffer& stubCapturedData); + void setStubCapturedData(const DynamicBuffer& stubCapturedData); protected: std::unique_ptr decodePackingMethod(std::uint8_t packingMethod) const; const UpxStubData* _stubData; ///< Additional stub information. - retdec::unpacker::DynamicBuffer _stubCapturedData; ///< Data captured while matching signature of this stub. + DynamicBuffer _stubCapturedData; ///< Data captured while matching signature of this stub. std::unique_ptr _decompressor; ///< Decompressor associated with stub. UpxMetadata _metadata; ///< UPX metadata aka packheader. private: - static std::shared_ptr _createStubImpl(retdec::loader::Image* file, const retdec::unpacker::DynamicBuffer* stubBytes); + static std::shared_ptr _createStubImpl(retdec::loader::Image* file, const DynamicBuffer* stubBytes); }; } // namespace upx diff --git a/src/unpackertool/plugins/upx/upx_stub_signatures.cpp b/src/unpackertool/plugins/upx/upx_stub_signatures.cpp index d2699acae..b0889653b 100644 --- a/src/unpackertool/plugins/upx/upx_stub_signatures.cpp +++ b/src/unpackertool/plugins/upx/upx_stub_signatures.cpp @@ -8,6 +8,7 @@ using namespace retdec::fileformat; using namespace retdec::loader; +using namespace retdec::utils; using namespace retdec::unpacker; namespace retdec { diff --git a/src/unpackertool/plugins/upx/upx_stub_signatures.h b/src/unpackertool/plugins/upx/upx_stub_signatures.h index c0a1759f5..a7dc16215 100644 --- a/src/unpackertool/plugins/upx/upx_stub_signatures.h +++ b/src/unpackertool/plugins/upx/upx_stub_signatures.h @@ -12,6 +12,8 @@ #include "unpackertool/plugins/upx/upx_stub.h" #include "retdec/unpacker/signature.h" +using namespace retdec::utils; + namespace retdec { namespace unpackertool { namespace upx { @@ -54,8 +56,8 @@ class UpxStubSignatures UpxStubSignatures(const UpxStubSignatures&) = delete; ~UpxStubSignatures(); - static const UpxStubData* matchSignatures(retdec::loader::Image* file, retdec::unpacker::DynamicBuffer& captureData); - static const UpxStubData* matchSignatures(const retdec::unpacker::DynamicBuffer& data, retdec::unpacker::DynamicBuffer& captureData, + static const UpxStubData* matchSignatures(retdec::loader::Image* file, DynamicBuffer& captureData); + static const UpxStubData* matchSignatures(const DynamicBuffer& data, DynamicBuffer& captureData, retdec::fileformat::Architecture architecture = retdec::fileformat::Architecture::UNKNOWN, retdec::fileformat::Format format = retdec::fileformat::Format::UNKNOWN); private: diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index c76985d81..1fc3a010c 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -4,6 +4,7 @@ set(RETDEC_UTILS_SOURCES byte_value_storage.cpp binary_path.cpp conversion.cpp + dynamic_buffer.cpp file_io.cpp filesystem_path.cpp math.cpp diff --git a/src/unpacker/dynamic_buffer.cpp b/src/utils/dynamic_buffer.cpp similarity index 98% rename from src/unpacker/dynamic_buffer.cpp rename to src/utils/dynamic_buffer.cpp index 1e8c78dc1..550ac4cf1 100644 --- a/src/unpacker/dynamic_buffer.cpp +++ b/src/utils/dynamic_buffer.cpp @@ -1,15 +1,15 @@ /** - * @file src/unpacker/dynamic_buffer.cpp + * @file src/utils/dynamic_buffer.cpp * @brief Implementation of class for buffered data mainpulation. * @copyright (c) 2017 Avast Software, licensed under the MIT license */ -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" using namespace retdec::utils; namespace retdec { -namespace unpacker { +namespace utils { /** * Creates the empty DynamicBuffer object with no capacity and specified endianness. diff --git a/src/utils/string.cpp b/src/utils/string.cpp index cdbba0115..d4278bc7b 100644 --- a/src/utils/string.cpp +++ b/src/utils/string.cpp @@ -49,7 +49,7 @@ bool isNonasciiChar(unsigned char c) { */ std::string replaceChars(const std::string &str, bool (* predicate)(unsigned char)) { std::stringstream result; - const std::size_t maxC = std::pow(2, sizeof(std::string::value_type) * CHAR_BIT) - 1; + const std::size_t maxC = (1 << (sizeof(std::string::value_type) * CHAR_BIT)) - 1; for (const auto &c : str) { if (predicate(c)) { const auto val = numToStr(c & maxC, std::hex); @@ -404,6 +404,100 @@ std::string toWide(const std::string &str, std::string::size_type length) { return result; } +/** +* @brief Converts unicode @a bytes to ASCII string. +* +* @param[in] bytes Bytes for conversion. +* @param[in] nBytes Number of bytes. +* +* @return Converted string in ASCII. +*/ +std::string unicodeToAscii(const std::uint8_t *bytes, std::size_t nBytes) +{ + std::stringstream result; + if (!bytes || !nBytes) + { + return {}; + } + if (nBytes & 1) + { + nBytes--; + } + + for (std::size_t i = 0; i < nBytes; i += 2) + { + if (bytes[i] == 0 && bytes[i + 1] == 0) + { + break; + } + if (bytes[i + 1] == 0 && isPrintableChar(bytes[i])) + { + result << bytes[i]; + } + else + { + const std::size_t maxC = (1 << (sizeof(std::string::value_type) * CHAR_BIT)) - 1; + const auto val1 = numToStr(bytes[i] & maxC, std::hex); + const auto val2 = numToStr(bytes[i + 1] & maxC, std::hex); + result << "\\x" << std::setw(2) << std::setfill('0') << val1; + result << "\\x" << std::setw(2) << std::setfill('0') << val2; + } + } + + return result.str(); +} + +/** +* @brief Read up to @a maxBytes bytes as ASCII string. +* +* @param[in] bytes Bytes to read from. +* @param[in] bytesLen Length of @a bytes +* @param[in] offset Offset in bytes. +* @param[in] maxBytes Maximum of bytes to read. Zero indicates as much as possible. +* @param[in] failOnExceed If string isn't null terminated until @a maxBytes, an empty string is returned +* +* @return Converted string in ASCII. +*/ +std::string readNullTerminatedAscii(const std::uint8_t *bytes, std::size_t bytesLen, std::size_t offset, + std::size_t maxBytes, bool failOnExceed) +{ + std::string result; + if (!bytes) + { + return {}; + } + + if (maxBytes == 0) + { + maxBytes = bytesLen; + } + else if (offset + maxBytes > bytesLen) + { + maxBytes = bytesLen; + } + else + { + maxBytes += offset; + } + + std::size_t i; + for (i = offset; i < maxBytes; i++) + { + if (bytes[i] == '\0') + { + break; + } + result.push_back(bytes[i]); + } + + if (i == maxBytes && failOnExceed) + { + return {}; + } + + return replaceNonprintableChars(result); +} + /** * @brief Trims the given string. * diff --git a/support/yara_patterns/tools/macho/arm/compilers.yara b/support/yara_patterns/tools/macho/arm/compilers.yara index 3c604beab..f381e4427 100644 --- a/support/yara_patterns/tools/macho/arm/compilers.yara +++ b/support/yara_patterns/tools/macho/arm/compilers.yara @@ -16,7 +16,7 @@ rule xcode_ios_sdk_01 strings: $1 = { 00 00 9D E5 04 10 8D E2 01 40 80 E2 04 21 81 E0 07 D0 CD E3 02 30 A0 E1 04 40 93 E4 00 00 54 E3 FC FF FF 1A } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_ARM) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_ARM) } rule xcode_ios_sdk_02 { @@ -29,5 +29,5 @@ rule xcode_ios_sdk_02 { strings: $1 = { 00 00 9D E5 04 10 8D E2 01 40 80 E2 04 21 81 E0 07 D0 CD E3 02 30 A0 E1 04 40 93 E4 00 00 54 E3 FC FF FF 1A 18 C0 9F E5 0C C0 8F E0 00 C0 9C E5 3C FF 2F E1 0C C0 9F E5 0C C0 8F E0 00 C0 9C E5 1C FF 2F E1 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_ARM) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_ARM) } diff --git a/support/yara_patterns/tools/macho/arm/packers.yara b/support/yara_patterns/tools/macho/arm/packers.yara index 8f70bf131..e1b0de5f0 100644 --- a/support/yara_patterns/tools/macho/arm/packers.yara +++ b/support/yara_patterns/tools/macho/arm/packers.yara @@ -15,7 +15,7 @@ rule upx_391_lzma strings: $1 = { 04 D0 4D E2 FF DF 2D E9 B9 02 00 EB 00 C0 DD E5 0E 00 5C E3 79 02 00 1A 0C 48 2D E9 00 B0 D0 E5 06 CC A0 E3 AB B1 A0 E1 1C CB A0 E1 0D B0 A0 E1 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_ARM) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_ARM) } rule upx_391_nrv2b @@ -28,7 +28,7 @@ rule upx_391_nrv2b strings: $1 = { 04 D0 4D E2 FF DF 2D E9 79 00 00 EB 00 10 81 E0 3E 40 2D E9 00 50 E0 E3 02 41 A0 E3 1F 00 00 EA } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_ARM) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_ARM) } rule upx_391_nrv2d @@ -41,7 +41,7 @@ rule upx_391_nrv2d strings: $1 = { 04 D0 4D E2 FF DF 2D E9 88 00 00 EB FC 40 2D E9 00 70 81 E0 00 50 E0 E3 02 41 A0 E3 16 00 00 EA } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_ARM) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_ARM) } rule upx_391_nrv2e @@ -54,5 +54,5 @@ rule upx_391_nrv2e strings: $1 = { 04 D0 4D E2 FF DF 2D E9 8D 00 00 EB FC 40 2D E9 00 70 81 E0 00 50 E0 E3 02 41 A0 E3 16 00 00 EA } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_ARM) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_ARM) } diff --git a/support/yara_patterns/tools/macho/ppc/compilers.yara b/support/yara_patterns/tools/macho/ppc/compilers.yara index 0db73299b..49703544d 100644 --- a/support/yara_patterns/tools/macho/ppc/compilers.yara +++ b/support/yara_patterns/tools/macho/ppc/compilers.yara @@ -15,7 +15,7 @@ rule xcode_osx_sdk_01 { strings: $1 = { 7C 3A 0B 78 38 21 FF FC 54 21 00 34 38 00 00 00 90 01 00 00 94 21 FF C0 80 7A 00 00 38 9A 00 04 3B 63 00 01 57 7B 10 3A 7C A4 DA 14 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) } rule xcode_osx_sdk_02 { @@ -28,7 +28,7 @@ rule xcode_osx_sdk_02 { strings: $1 = { 7C 3A 0B 78 38 21 FF FC 54 21 00 34 38 00 00 00 90 01 00 00 94 21 FF C0 80 7A 00 00 38 9A 00 04 3B 63 00 01 57 7B 10 3A 7C A4 DA 14 ?? ?? ?? ?? 7F E0 00 08 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) } rule xcode_osx_sdk_03 { @@ -41,5 +41,5 @@ rule xcode_osx_sdk_03 { strings: $1 = { 7C 3A 0B 78 38 21 FF FC 54 21 00 34 38 00 00 00 90 01 00 00 94 21 FF C0 80 7A 00 00 38 9A 00 04 3B 63 00 01 57 7B 10 3A 7C A4 DA 14 7C A6 2B 78 80 06 00 00 38 C6 00 04 2C 00 00 00 40 82 FF F4 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) } diff --git a/support/yara_patterns/tools/macho/ppc/packers.yara b/support/yara_patterns/tools/macho/ppc/packers.yara index bb1ff0b8c..af5584188 100644 --- a/support/yara_patterns/tools/macho/ppc/packers.yara +++ b/support/yara_patterns/tools/macho/ppc/packers.yara @@ -15,7 +15,7 @@ rule upx_391_lzma { strings: $1 = { 48 00 0B 59 28 07 00 0E 40 82 0A 44 7C 08 02 A6 7C C9 33 78 81 06 00 00 7C A7 2B 78 38 A4 FF FE 38 83 00 02 90 01 00 08 88 03 00 00 54 0B E8 FE 54 02 07 7E 38 60 FA 00 7C 63 58 30 38 63 F1 7C 7C 26 0B 78 7C 21 1A 14 54 21 00 34 38 00 00 00 7C C3 33 78 90 09 00 00 94 03 FF FC 7C 01 18 40 41 80 FF F8 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) } rule upx_391_nrv2b { @@ -28,7 +28,7 @@ rule upx_391_nrv2b { strings: $1 = { 48 00 02 1D 7C 00 29 EC 7D A8 02 A6 28 07 00 02 40 82 00 E4 90 A6 00 00 7C 84 1A 14 3C 00 80 00 3D 20 80 00 38 63 FF FF 38 A5 FF FF 39 40 FF FF 48 00 00 B4 7C 09 00 40 7D 29 48 14 4C A2 00 20 39 20 00 01 7D 29 1C 2C 38 63 00 04 7C 09 00 40 7D 29 49 14 4E 80 00 20 8D 03 00 01 9D 05 00 01 4B FF FF D5 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) } rule upx_391_nrv2d { @@ -41,7 +41,7 @@ rule upx_391_nrv2d { strings: $1 = { 48 00 02 59 7C 00 29 EC 7D A8 02 A6 28 07 00 05 40 82 01 20 90 A6 00 00 7C 84 1A 14 3C 00 80 00 3D 20 80 00 38 63 FF FF 38 A5 FF FF 39 40 FF FF 48 00 00 F0 39 20 00 01 7D 29 1C 2C 38 63 00 04 7C 09 00 40 7D 29 48 14 61 29 00 01 4E 80 00 20 8D 03 00 01 9D 05 00 01 7C 09 00 40 7D 29 4A 14 41 A2 FF D5 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) } rule upx_391_nrv2e { @@ -54,7 +54,7 @@ rule upx_391_nrv2e { strings: $1 = { 48 00 02 75 7C 00 29 EC 7D A8 02 A6 28 07 00 08 40 82 01 3C 90 A6 00 00 7C 84 1A 14 3C 00 80 00 3D 20 80 00 38 63 FF FF 38 A5 FF FF 39 40 FF FF 48 00 01 0C 39 20 00 01 7D 29 1C 2C 38 63 00 04 7C 09 00 40 7D 29 48 14 61 29 00 01 4E 80 00 20 8D 03 00 01 9D 05 00 01 7C 09 00 40 7D 29 4A 14 41 A2 FF D5 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) } rule upx_392_lzma { @@ -68,7 +68,7 @@ rule upx_392_lzma { strings: $1 = { 83 E3 78 7F C4 F3 78 38 A1 00 38 38 C0 40 00 39 29 FF F8 4B FF FD B9 7C 7D 1B 78 7F 83 E3 78 7F C4 F3 78 4B FF F8 CD 7F A3 EB 78 38 21 40 50 80 01 00 08 7C 08 03 A6 BB 81 FF F0 4E 80 00 20 00 00 00 00 5F 5F 4C 49 4E 4B 45 44 49 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 72 AD C1 77 55 50 58 21 0B CC 0D 83 00 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 00 ?? ?? 00 00 0? ?? 0E 00 00 00 1A 03 00 7F 3B 5B 41 2F 70 78 } condition: - $1 at macho.entry_point + 1929 or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + 1929 + $1 at macho.entry_point + 1929 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) + 1929 } rule upx_392_nrv2b { @@ -82,7 +82,7 @@ rule upx_392_nrv2b { strings: $1 = { 83 E3 78 7F C4 F3 78 38 A1 00 38 38 C0 40 00 39 29 FF F8 4B FF FD B9 7C 7D 1B 78 7F 83 E3 78 7F C4 F3 78 4B FF F8 CD 7F A3 EB 78 38 21 40 50 80 01 00 08 7C 08 03 A6 BB 81 FF F0 4E 80 00 20 00 00 00 00 5F 5F 4C 49 4E 4B 45 44 49 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E4 0A E3 B8 55 50 58 21 02 8C 0D 83 00 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 00 ?? ?? 00 00 0? ?? 02 00 00 00 ?? ?? ?? F9 FE ED FA CE 00 12 0? 0? } condition: - $1 at macho.entry_point + 1929 or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + 1929 + $1 at macho.entry_point + 1929 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) + 1929 } rule upx_392_nrv2d { @@ -96,7 +96,7 @@ rule upx_392_nrv2d { strings: $1 = { 83 E3 78 7F C4 F3 78 38 A1 00 38 38 C0 40 00 39 29 FF F8 4B FF FD B9 7C 7D 1B 78 7F 83 E3 78 7F C4 F3 78 4B FF F8 CD 7F A3 EB 78 38 21 40 50 80 01 00 08 7C 08 03 A6 BB 81 FF F0 4E 80 00 20 00 00 00 00 5F 5F 4C 49 4E 4B 45 44 49 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8C 11 EF E5 55 50 58 21 02 C8 0D 83 00 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 00 ?? ?? 00 00 0? ?? 05 00 00 00 ?? ?? ?? F9 FE ED FA CE 00 12 0? } condition: - $1 at macho.entry_point + 1929 or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + 1929 + $1 at macho.entry_point + 1929 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) + 1929 } rule upx_392_nrv2e { @@ -110,7 +110,7 @@ rule upx_392_nrv2e { strings: $1 = { 83 E3 78 7F C4 F3 78 38 A1 00 38 38 C0 40 00 39 29 FF F8 4B FF FD B9 7C 7D 1B 78 7F 83 E3 78 7F C4 F3 78 4B FF F8 CD 7F A3 EB 78 38 21 40 50 80 01 00 08 7C 08 03 A6 BB 81 FF F0 4E 80 00 20 00 00 00 00 5F 5F 4C 49 4E 4B 45 44 49 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 93 A1 F6 29 55 50 58 21 02 E4 0D 83 00 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 00 ?? ?? 00 00 0? ?? 08 00 00 00 ?? ?? ?? F9 FE ED FA CE 00 12 0? } condition: - $1 at macho.entry_point + 1929 or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + 1929 + $1 at macho.entry_point + 1929 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) + 1929 } rule upx_393_lzma { @@ -124,7 +124,7 @@ rule upx_393_lzma { strings: $1 = { 83 E3 78 7F C4 F3 78 38 A1 00 38 38 C0 40 00 39 29 FF F8 4B FF FD B9 7C 7D 1B 78 7F 83 E3 78 7F C4 F3 78 4B FF F8 CD 7F A3 EB 78 38 21 40 50 80 01 00 08 7C 08 03 A6 BB 81 FF F0 4E 80 00 20 00 00 00 00 5F 5F 4C 49 4E 4B 45 44 49 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 73 C3 C1 79 55 50 58 21 0B CC 0D 83 00 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 00 ?? ?? 00 00 0? ?? 0E 00 00 00 1A 03 00 7F 3B 5B 41 2F 70 78 } condition: - $1 at macho.entry_point + 1929 or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + 1929 + $1 at macho.entry_point + 1929 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) + 1929 } rule upx_393_nrv2b { @@ -138,7 +138,7 @@ rule upx_393_nrv2b { strings: $1 = { 83 E3 78 7F C4 F3 78 38 A1 00 38 38 C0 40 00 39 29 FF F8 4B FF FD B9 7C 7D 1B 78 7F 83 E3 78 7F C4 F3 78 4B FF F8 CD 7F A3 EB 78 38 21 40 50 80 01 00 08 7C 08 03 A6 BB 81 FF F0 4E 80 00 20 00 00 00 00 5F 5F 4C 49 4E 4B 45 44 49 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E5 20 E3 BA 55 50 58 21 02 8C 0D 83 00 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 00 ?? ?? 00 00 0? ?? 02 00 00 00 ?? ?? ?? F9 FE ED FA CE 00 12 0? 0? } condition: - $1 at macho.entry_point + 1929 or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + 1929 + $1 at macho.entry_point + 1929 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) + 1929 } rule upx_393_nrv2d { @@ -152,7 +152,7 @@ rule upx_393_nrv2d { strings: $1 = { 83 E3 78 7F C4 F3 78 38 A1 00 38 38 C0 40 00 39 29 FF F8 4B FF FD B9 7C 7D 1B 78 7F 83 E3 78 7F C4 F3 78 4B FF F8 CD 7F A3 EB 78 38 21 40 50 80 01 00 08 7C 08 03 A6 BB 81 FF F0 4E 80 00 20 00 00 00 00 5F 5F 4C 49 4E 4B 45 44 49 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8D 27 EF E7 55 50 58 21 02 C8 0D 83 00 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 00 ?? ?? 00 00 0? ?? 05 00 00 00 ?? ?? ?? F9 FE ED FA CE 00 12 0? } condition: - $1 at macho.entry_point + 1929 or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + 1929 + $1 at macho.entry_point + 1929 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) + 1929 } rule upx_393_nrv2e { @@ -166,7 +166,7 @@ rule upx_393_nrv2e { strings: $1 = { 83 E3 78 7F C4 F3 78 38 A1 00 38 38 C0 40 00 39 29 FF F8 4B FF FD B9 7C 7D 1B 78 7F 83 E3 78 7F C4 F3 78 4B FF F8 CD 7F A3 EB 78 38 21 40 50 80 01 00 08 7C 08 03 A6 BB 81 FF F0 4E 80 00 20 00 00 00 00 5F 5F 4C 49 4E 4B 45 44 49 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 B7 F6 2B 55 50 58 21 02 E4 0D 83 00 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 00 ?? ?? 00 00 0? ?? 08 00 00 00 ?? ?? ?? F9 FE ED FA CE 00 12 0? } condition: - $1 at macho.entry_point + 1929 or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + 1929 + $1 at macho.entry_point + 1929 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) + 1929 } rule upx_394_lzma { @@ -180,7 +180,7 @@ rule upx_394_lzma { strings: $1 = { 83 E3 78 7F C4 F3 78 38 A1 00 38 38 C0 40 00 39 29 FF F8 4B FF FD B9 7C 7D 1B 78 7F 83 E3 78 7F C4 F3 78 4B FF F8 CD 7F A3 EB 78 38 21 40 50 80 01 00 08 7C 08 03 A6 BB 81 FF F0 4E 80 00 20 00 00 00 00 5F 5F 4C 49 4E 4B 45 44 49 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 74 5F C7 62 55 50 58 21 0B D0 0D 83 00 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 00 ?? ?? 00 00 0? ?? 0E 00 00 00 1A 03 00 7F 3B 5B 41 2F 70 78 } condition: - $1 at macho.entry_point + 1929 or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + 1929 + $1 at macho.entry_point + 1929 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) + 1929 } rule upx_394_nrv2b { @@ -194,7 +194,7 @@ rule upx_394_nrv2b { strings: $1 = { 83 E3 78 7F C4 F3 78 38 A1 00 38 38 C0 40 00 39 29 FF F8 4B FF FD B9 7C 7D 1B 78 7F 83 E3 78 7F C4 F3 78 4B FF F8 CD 7F A3 EB 78 38 21 40 50 80 01 00 08 7C 08 03 A6 BB 81 FF F0 4E 80 00 20 00 00 00 00 5F 5F 4C 49 4E 4B 45 44 49 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 EC E7 E4 17 55 50 58 21 02 8C 0D 83 00 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 00 ?? ?? 00 00 0? ?? 02 00 00 00 ?? ?? ?? F9 FE ED FA CE 00 12 0? 0? } condition: - $1 at macho.entry_point + 1929 or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + 1929 + $1 at macho.entry_point + 1929 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) + 1929 } rule upx_394_nrv2d { @@ -208,7 +208,7 @@ rule upx_394_nrv2d { strings: $1 = { 83 E3 78 7F C4 F3 78 38 A1 00 38 38 C0 40 00 39 29 FF F8 4B FF FD B9 7C 7D 1B 78 7F 83 E3 78 7F C4 F3 78 4B FF F8 CD 7F A3 EB 78 38 21 40 50 80 01 00 08 7C 08 03 A6 BB 81 FF F0 4E 80 00 20 00 00 00 00 5F 5F 4C 49 4E 4B 45 44 49 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 EE F0 44 55 50 58 21 02 C8 0D 83 00 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 00 ?? ?? 00 00 0? ?? 05 00 00 00 ?? ?? ?? F9 FE ED FA CE 00 12 0? } condition: - $1 at macho.entry_point + 1929 or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + 1929 + $1 at macho.entry_point + 1929 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) + 1929 } rule upx_394_nrv2e { @@ -222,5 +222,5 @@ rule upx_394_nrv2e { strings: $1 = { 83 E3 78 7F C4 F3 78 38 A1 00 38 38 C0 40 00 39 29 FF F8 4B FF FD B9 7C 7D 1B 78 7F 83 E3 78 7F C4 F3 78 4B FF F8 CD 7F A3 EB 78 38 21 40 50 80 01 00 08 7C 08 03 A6 BB 81 FF F0 4E 80 00 20 00 00 00 00 5F 5F 4C 49 4E 4B 45 44 49 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 9C 7E F6 88 55 50 58 21 02 E4 0D 83 00 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 00 ?? ?? 00 00 0? ?? 08 00 00 00 ?? ?? ?? F9 FE ED FA CE 00 12 0? } condition: - $1 at macho.entry_point + 1929 or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC) + 1929 + $1 at macho.entry_point + 1929 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC) + 1929 } diff --git a/support/yara_patterns/tools/macho/ppc64/compilers.yara b/support/yara_patterns/tools/macho/ppc64/compilers.yara index 83974540e..a1ec054b5 100644 --- a/support/yara_patterns/tools/macho/ppc64/compilers.yara +++ b/support/yara_patterns/tools/macho/ppc64/compilers.yara @@ -15,7 +15,7 @@ rule xcode_osx_sdk_01 { strings: $1 = { 7C 3A 0B 78 38 21 FF F8 78 21 06 A4 38 00 00 00 F8 01 00 00 F8 21 FF 81 80 7A 00 00 38 9A 00 08 3B 63 00 01 7B 7B 1F 24 7C A4 DA 14 ?? ?? ?? ?? 7F E0 00 08 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC64) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC64) } rule xcode_osx_sdk_02 { @@ -28,5 +28,5 @@ rule xcode_osx_sdk_02 { strings: $1 = { 7C 3A 0B 78 38 21 FF F8 78 21 06 A4 38 00 00 00 F8 01 00 00 F8 21 FF 81 80 7A 00 00 38 9A 00 08 3B 63 00 01 7B 7B 1F 24 7C A4 DA 14 7C A6 2B 78 E8 06 00 00 38 C6 00 08 2C 20 00 00 40 82 FF F4 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_POWERPC64) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_POWERPC64) } diff --git a/support/yara_patterns/tools/macho/x64/compilers.yara b/support/yara_patterns/tools/macho/x64/compilers.yara index d077f872e..51a8d3a86 100644 --- a/support/yara_patterns/tools/macho/x64/compilers.yara +++ b/support/yara_patterns/tools/macho/x64/compilers.yara @@ -15,7 +15,7 @@ rule xcode_osx_sdk_01 { strings: $1 = { 6A 00 48 89 E5 48 83 E4 F0 48 8B 7D 08 48 8D 75 10 89 FA 83 C2 01 C1 E2 03 48 01 F2 E8 ?? ?? ?? ?? F4 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) } rule xcode_osx_sdk_02 { @@ -28,7 +28,7 @@ rule xcode_osx_sdk_02 { strings: $1 = { 6A 00 48 89 E5 48 83 E4 F0 48 8B 7D 08 48 8D 75 10 89 FA 83 C2 01 C1 E2 03 48 01 F2 48 89 D1 EB 04 48 83 C1 08 48 83 39 00 75 F6 48 83 C1 08 E8 ?? ?? ?? ?? 89 C7 E8 ?? ?? ?? ?? F4 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) } rule gc @@ -41,5 +41,5 @@ rule gc strings: $1 = { 48 8D 74 24 08 48 8B 3C 24 48 8D 05 10 00 00 00 FF E0 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 48 8D 05 ?9 C? FF FF FF E0 ?? ?? ?? ?? ?? ?? ?? 8B 7C 24 08 B8 01 00 00 02 0F 05 C7 04 25 F1 00 00 00 F1 00 00 00 C3 ?? ?? ?? ?? ?? ?? ?? ?? ?? 8B 7C 24 08 B8 69 01 00 02 0F 05 C7 04 25 F1 00 00 00 F1 00 00 00 C3 ?? ?? ?? ?? ?? ?? ?? ?? ?? 48 8B 7C 24 08 8B 74 24 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) } diff --git a/support/yara_patterns/tools/macho/x64/packers.yara b/support/yara_patterns/tools/macho/x64/packers.yara index 056768041..649768d5a 100644 --- a/support/yara_patterns/tools/macho/x64/packers.yara +++ b/support/yara_patterns/tools/macho/x64/packers.yara @@ -16,7 +16,7 @@ rule upx_391_lzma strings: $1 = { E8 ?? ?? ?? ?? 55 53 51 52 48 01 FE 56 41 80 F8 0E 0F 85 6C 0A 00 00 55 48 89 E5 44 8B 09 49 89 D0 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) } rule upx_391_nrv2b @@ -31,7 +31,7 @@ rule upx_391_nrv2b strings: $1 = { FC 41 5B 41 80 F8 02 74 0D E9 ?? ?? ?? ?? 48 FF C6 88 17 48 FF C7 8A 16 01 DB 75 0A 8B 1E 48 83 EE FC 11 DB 8A 16 72 E6 8D 41 01 41 FF D3 } condition: - $1 at macho.entry_point + 112 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 112 + $1 at macho.entry_point + 112 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 112 } rule upx_391_nrv2d @@ -46,7 +46,7 @@ rule upx_391_nrv2d strings: $1 = { FC 41 5B 41 80 F8 05 74 0D E9 ?? ?? ?? ?? 48 FF C6 88 17 48 FF C7 8A 16 01 DB 75 0A 8B 1E 48 83 EE FC 11 DB 8A 16 72 E6 8D 41 01 EB 07 FF C8 41 FF D3 } condition: - $1 at macho.entry_point + 112 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 112 + $1 at macho.entry_point + 112 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 112 } rule upx_391_nrv2e @@ -61,7 +61,7 @@ rule upx_391_nrv2e strings: $1 = { FC 41 5B 41 80 F8 08 74 0D E9 ?? ?? ?? ?? 48 FF C6 88 17 48 FF C7 8A 16 01 DB 75 0A 8B 1E 48 83 EE FC 11 DB 8A 16 72 E6 8D 41 01 EB 07 FF C8 41 FF D3 } condition: - $1 at macho.entry_point + 112 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 112 + $1 at macho.entry_point + 112 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 112 } rule upx_392_lzma @@ -77,7 +77,7 @@ rule upx_392_lzma $1 = { FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 FD 08 00 00 34 00 00 00 34 00 00 00 A9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 03 00 18 00 03 00 00 00 00 02 13 06 00 01 5D 06 00 00 00 00 00 00 00 00 00 01 D1 58 05 01 33 C1 0B A6 55 50 58 21 BD 0B 0D 22 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 0E 00 00 00 1A 03 00 67 BE 99 AF DE 39 19 1D 3F 9? ?? ?A } condition: - $1 at macho.entry_point + 354 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 354 + $1 at macho.entry_point + 354 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 354 } rule upx_392_nrv2b @@ -92,7 +92,7 @@ rule upx_392_nrv2b strings: $1 = { FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 FD 08 00 00 34 00 00 00 34 00 00 00 A9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 03 00 18 00 03 00 00 00 00 02 13 06 00 01 5D 06 00 00 00 00 00 00 00 00 00 01 D1 58 05 01 37 F6 FE 4F 55 50 58 21 41 02 0D 22 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 02 00 00 00 ?? ?? B7 FF CF FA ED FE 07 00 00 01 03 03 ?0 02 } condition: - $1 at macho.entry_point + 354 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 354 + $1 at macho.entry_point + 354 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 354 } rule upx_392_nrv2d @@ -107,7 +107,7 @@ rule upx_392_nrv2d strings: $1 = { FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 FD 08 00 00 34 00 00 00 34 00 00 00 A9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 03 00 18 00 03 00 00 00 00 02 13 06 00 01 5D 06 00 00 00 00 00 00 00 00 00 01 D1 58 05 01 E2 02 7C E8 55 50 58 21 51 02 0D 22 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 05 00 00 00 ?? ?? BE FF CF FA ED FE 07 00 00 01 03 07 ?0 02 } condition: - $1 at macho.entry_point + 354 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 354 + $1 at macho.entry_point + 354 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 354 } rule upx_392_nrv2e @@ -122,7 +122,7 @@ rule upx_392_nrv2e strings: $1 = { FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 FD 08 00 00 34 00 00 00 34 00 00 00 A9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 03 00 18 00 03 00 00 00 00 02 13 06 00 01 5D 06 00 00 00 00 00 00 00 00 00 01 D1 58 05 01 ED 0C 65 23 55 50 58 21 69 02 0D 22 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 08 00 00 00 ?? ?? B6 FF CF FA ED FE 07 00 00 01 03 06 ?0 02 } condition: - $1 at macho.entry_point + 354 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 354 + $1 at macho.entry_point + 354 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 354 } rule upx_393_lzma @@ -138,7 +138,7 @@ rule upx_393_lzma $1 = { FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 FD 08 00 00 34 00 00 00 34 00 00 00 A9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 03 00 18 00 03 00 00 00 00 02 13 06 00 01 5D 06 00 00 00 00 00 00 00 00 00 01 D1 58 05 01 35 C1 FB A6 55 50 58 21 BD 0B 0D 22 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 0E 00 00 00 1A 03 00 67 BE 99 AF DE 39 19 1D 3F 9? ?? ?A } condition: - $1 at macho.entry_point + 354 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 354 + $1 at macho.entry_point + 354 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 354 } rule upx_393_nrv2b @@ -153,7 +153,7 @@ rule upx_393_nrv2b strings: $1 = { FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 FD 08 00 00 34 00 00 00 34 00 00 00 A9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 03 00 18 00 03 00 00 00 00 02 13 06 00 01 5D 06 00 00 00 00 00 00 00 00 00 01 D1 58 05 01 39 F6 EA 50 55 50 58 21 41 02 0D 22 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 02 00 00 00 ?? ?? B7 FF CF FA ED FE 07 00 00 01 03 03 ?0 02 } condition: - $1 at macho.entry_point + 354 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 354 + $1 at macho.entry_point + 354 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 354 } rule upx_393_nrv2d @@ -168,7 +168,7 @@ rule upx_393_nrv2d strings: $1 = { FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 FD 08 00 00 34 00 00 00 34 00 00 00 A9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 03 00 18 00 03 00 00 00 00 02 13 06 00 01 5D 06 00 00 00 00 00 00 00 00 00 01 D1 58 05 01 E4 02 6C E9 55 50 58 21 51 02 0D 22 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 05 00 00 00 ?? ?? BE FF CF FA ED FE 07 00 00 01 03 07 ?0 02 } condition: - $1 at macho.entry_point + 354 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 354 + $1 at macho.entry_point + 354 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 354 } rule upx_393_nrv2e @@ -183,7 +183,7 @@ rule upx_393_nrv2e strings: $1 = { FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 FD 08 00 00 34 00 00 00 34 00 00 00 A9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 03 00 18 00 03 00 00 00 00 02 13 06 00 01 5D 06 00 00 00 00 00 00 00 00 00 01 D1 58 05 01 EF 0C 53 24 55 50 58 21 69 02 0D 22 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 08 00 00 00 ?? ?? B6 FF CF FA ED FE 07 00 00 01 03 06 ?0 02 } condition: - $1 at macho.entry_point + 354 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 354 + $1 at macho.entry_point + 354 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 354 } rule upx_394_lzma @@ -199,7 +199,7 @@ rule upx_394_lzma $1 = { FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 FD 08 00 00 34 00 00 00 34 00 00 00 A9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 03 00 18 00 03 00 00 00 00 02 13 06 00 01 5D 06 00 00 00 00 00 00 00 00 00 01 D1 58 05 01 78 BC 96 68 55 50 58 21 B5 0B 0D 22 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 0E 00 00 00 1A 03 00 67 BE 99 AF DE 39 19 1D 3F 9? ?? ?A } condition: - $1 at macho.entry_point + 354 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 354 + $1 at macho.entry_point + 354 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 354 } rule upx_394_nrv2b @@ -214,7 +214,7 @@ rule upx_394_nrv2b strings: $1 = { FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 FD 08 00 00 34 00 00 00 34 00 00 00 A9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 03 00 18 00 03 00 00 00 00 02 13 06 00 01 5D 06 00 00 00 00 00 00 00 00 00 01 D1 58 05 01 BE F3 84 60 55 50 58 21 3D 02 0D 22 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 02 00 00 00 ?? ?? B7 FF CF FA ED FE 07 00 00 01 03 03 ?0 02 } condition: - $1 at macho.entry_point + 354 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 354 + $1 at macho.entry_point + 354 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 354 } rule upx_394_nrv2d @@ -229,7 +229,7 @@ rule upx_394_nrv2d strings: $1 = { FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 FD 08 00 00 34 00 00 00 34 00 00 00 A9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 03 00 18 00 03 00 00 00 00 02 13 06 00 01 5D 06 00 00 00 00 00 00 00 00 00 01 D1 58 05 01 1A FE 28 C5 55 50 58 21 49 02 0D 22 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 05 00 00 00 ?? ?? BE FF CF FA ED FE 07 00 00 01 03 07 ?0 02 } condition: - $1 at macho.entry_point + 354 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 354 + $1 at macho.entry_point + 354 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 354 } rule upx_394_nrv2e @@ -244,5 +244,5 @@ rule upx_394_nrv2e strings: $1 = { FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 FD 08 00 00 34 00 00 00 34 00 00 00 A9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 03 00 18 00 03 00 00 00 00 02 13 06 00 01 5D 06 00 00 00 00 00 00 00 00 00 01 D1 58 05 01 34 08 49 95 55 50 58 21 61 02 0D 22 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 08 00 00 00 ?? ?? B6 FF CF FA ED FE 07 00 00 01 03 06 ?0 02 } condition: - $1 at macho.entry_point + 354 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86_64) + 354 + $1 at macho.entry_point + 354 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86_64) + 354 } diff --git a/support/yara_patterns/tools/macho/x86/compilers.yara b/support/yara_patterns/tools/macho/x86/compilers.yara index 8adcb0c06..249629072 100644 --- a/support/yara_patterns/tools/macho/x86/compilers.yara +++ b/support/yara_patterns/tools/macho/x86/compilers.yara @@ -16,7 +16,7 @@ rule embarcadero_delphi_01 strings: $1 = { 8B D4 83 C4 F1 83 E4 F0 68 00 EF 00 BE 55 8B EC ?? ?? ?? ?3 ?? ?4 ?? ?? ?? ?? F? ?? ?? ?? ?? ?? ?? ?? ?? F? ?? 8? ?? ?? ?? 0? ?? ?? 0? ?? ?? ?? ?? 0? } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) } rule embarcadero_delphi_02 @@ -30,7 +30,7 @@ rule embarcadero_delphi_02 strings: $1 = { 8B D4 83 C4 F1 83 E4 F0 68 00 EF 00 BE 55 8B EC 83 C4 F8 53 83 C4 F4 E8 ?8 ?? F? FF 83 C4 0C 81 C3 A? ?? F? FF 8B 83 ?? ?? 0? 00 C6 00 01 8D 83 ?8 A? 0? 00 83 C4 F4 E8 ?4 ?? F? FF 83 C4 0C 83 C4 F4 8? ?3 ?? 3? 0? 00 8D ?3 ?? ?? 0? 00 E8 ?? ?? FF FF ?? ?0 ?? ?? ?? ?? ?4 0? ?? ?? ?? ?? } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) } rule xcode_osx_sdk_01 { @@ -43,7 +43,7 @@ rule xcode_osx_sdk_01 { strings: $1 = { 6A 00 89 E5 83 E4 F0 83 EC 10 8B 5D 04 89 5C 24 00 8D 4D 08 89 4C 24 04 83 C3 01 C1 E3 02 01 CB 89 5C 24 08 E8 ?? ?? ?? ?? F4 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) } rule xcode_osx_sdk_02 { @@ -56,7 +56,7 @@ rule xcode_osx_sdk_02 { strings: $1 = { 6A 00 89 E5 83 E4 F0 83 EC 10 8B 5D 04 89 5C 24 00 8D 4D 08 89 4C 24 04 83 C3 01 C1 E3 02 01 CB 89 5C 24 08 8B 03 83 C3 04 85 C0 75 F7 89 5C 24 0C E8 ?? ?? ?? ?? 89 44 24 00 E8 ?? ?? ?? ?? F4 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) } rule xcode_osx_sdk_03 { @@ -69,7 +69,7 @@ rule xcode_osx_sdk_03 { strings: $1 = { 6A 00 89 E5 83 E4 F0 83 EC 10 8B 5D 04 89 1C 24 8D 4D 08 89 4C 24 04 83 C3 01 C1 E3 02 01 CB 89 5C 24 08 8B 03 83 C3 04 85 C0 75 F7 89 5C 24 0C E8 ?? ?? ?? ?? 89 04 24 E8 ?? ?? ?? ?? F4 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) } rule gc @@ -82,5 +82,5 @@ rule gc strings: $1 = { 83 EC 08 8B 44 24 08 8D 5C 24 0C 89 04 24 89 5C 24 04 E8 09 00 00 00 CD 03 ?? ?? ?? ?? ?? ?? ?? E9 ?B D? FF FF ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? B8 01 00 00 00 CD 80 C7 05 F1 00 00 00 F1 00 00 00 C3 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? B8 69 01 00 00 CD 80 73 0A C7 05 F1 00 00 00 F1 00 00 00 C3 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? B8 05 00 00 00 CD 80 73 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) } diff --git a/support/yara_patterns/tools/macho/x86/packers.yara b/support/yara_patterns/tools/macho/x86/packers.yara index fd7eff7e2..774ad03e5 100644 --- a/support/yara_patterns/tools/macho/x86/packers.yara +++ b/support/yara_patterns/tools/macho/x86/packers.yara @@ -16,7 +16,7 @@ rule upx_391_lzma_01 strings: $1 = { E8 ?? ?? ?? ?? 60 8B 74 24 24 8B 7C 24 2C 83 CD FF 89 E5 8B 55 28 AC 4A 88 C1 24 07 C0 E9 03 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) } rule upx_391_lzma_02 @@ -30,7 +30,7 @@ rule upx_391_lzma_02 strings: $1 = { E8 ?? ?? ?? ?? EB 0E 5A 58 59 97 60 8A 54 24 20 E9 18 0B 00 00 60 8B 74 24 24 8B 7C 24 2C 83 CD FF 89 E5 8B 55 28 AC 4A 88 C1 24 07 C0 E9 03 BB 00 FD FF FF D3 E3 8D A4 5C 90 F1 FF FF 83 E4 E0 6A 00 6A 00 89 E3 53 83 C3 04 8B 4D 30 FF 31 57 53 83 C3 04 88 43 02 AC 4A 88 C1 24 0F 88 03 C0 E9 04 88 4B } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) } rule upx_391_nrv2b_01 @@ -44,7 +44,7 @@ rule upx_391_nrv2b_01 strings: $1 = { E8 ?? ?? ?? ?? 60 8B 74 24 24 8B 7C 24 2C 83 CD FF EB 0F 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 8A 07 72 EB B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 EF 75 09 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) } rule upx_391_nrv2b_02 @@ -58,7 +58,7 @@ rule upx_391_nrv2b_02 strings: $1 = { E8 ?? ?? ?? ?? EB 0E 5A 58 59 97 60 8A 54 24 20 E9 EE 00 00 00 60 8B 74 24 24 8B 7C 24 2C 83 CD FF EB 0F 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 8A 07 72 EB B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 EF 75 09 8B 1E 83 EE FC 11 DB 73 E4 31 C9 83 E8 03 72 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) } rule upx_391_nrv2d_01 @@ -72,7 +72,7 @@ rule upx_391_nrv2d_01 strings: $1 = { E8 ?? ?? ?? ?? 60 8B 74 24 24 8B 7C 24 2C 83 CD FF EB 0F 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 8A 07 72 EB B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 0B 75 19 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) } rule upx_391_nrv2d_02 @@ -86,7 +86,7 @@ rule upx_391_nrv2d_02 strings: $1 = { E8 ?? ?? ?? ?? EB 0E 5A 58 59 97 60 8A 54 24 20 E9 02 01 00 00 60 8B 74 24 24 8B 7C 24 2C 83 CD FF EB 0F 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 8A 07 72 EB B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 0B 75 19 8B 1E 83 EE FC 11 DB 72 10 48 01 DB 75 07 8B } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) } rule upx_391_nrv2e_01 @@ -100,7 +100,7 @@ rule upx_391_nrv2e_01 strings: $1 = { E8 ?? ?? ?? ?? 60 8B 74 24 24 8B 7C 24 2C 83 CD FF EB 0F 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 8A 07 72 EB B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 0B 75 28 } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) } rule upx_391_nrv2e_02 @@ -114,7 +114,7 @@ rule upx_391_nrv2e_02 strings: $1 = { E8 ?? ?? ?? ?? EB 0E 5A 58 59 97 60 8A 54 24 20 E9 12 01 00 00 60 8B 74 24 24 8B 7C 24 2C 83 CD FF EB 0F 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 8A 07 72 EB B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 0B 75 28 8B 1E 83 EE FC 11 DB 72 1F 48 01 DB 75 07 8B } condition: - $1 at macho.entry_point or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + $1 at macho.entry_point or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) } rule upx_392_lzma @@ -129,7 +129,7 @@ rule upx_392_lzma strings: $1 = { 8D 52 04 77 F2 C3 5A 58 59 51 50 52 57 97 31 C0 F3 AA 5F C3 5A 0F 34 B0 04 EB 02 B0 01 EB 02 B0 4A EB 02 B0 49 EB 02 B0 99 EB 02 B0 06 EB 02 B0 05 EB 02 B0 C5 EB 02 B0 03 0F B6 C0 89 E1 0D 00 00 0C 00 E8 CC FF FF FF 73 03 83 C8 FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 21 09 00 00 34 00 00 00 34 00 00 00 B9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 01 00 10 00 01 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 55 50 58 21 ?? ?? 0D 1D 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 0E 00 00 00 1A 03 00 67 3E 99 AF DE 39 19 5C D6 9F 95 BD } condition: - $1 at macho.entry_point + 363 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + 363 + $1 at macho.entry_point + 363 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) + 363 } rule upx_392_nrv2b @@ -144,7 +144,7 @@ rule upx_392_nrv2b strings: $1 = { 8D 52 04 77 F2 C3 5A 58 59 51 50 52 57 97 31 C0 F3 AA 5F C3 5A 0F 34 B0 04 EB 02 B0 01 EB 02 B0 4A EB 02 B0 49 EB 02 B0 99 EB 02 B0 06 EB 02 B0 05 EB 02 B0 C5 EB 02 B0 03 0F B6 C0 89 E1 0D 00 00 0C 00 E8 CC FF FF FF 73 03 83 C8 FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 21 09 00 00 34 00 00 00 34 00 00 00 B9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 01 00 10 00 01 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 55 50 58 21 ?? 0? 0D 1D 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 02 00 00 00 ?6 ?D B7 FC CE FA ED FE 07 00 03 03 02 } condition: - $1 at macho.entry_point + 363 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + 363 + $1 at macho.entry_point + 363 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) + 363 } rule upx_392_nrv2d @@ -159,7 +159,7 @@ rule upx_392_nrv2d strings: $1 = { 8D 52 04 77 F2 C3 5A 58 59 51 50 52 57 97 31 C0 F3 AA 5F C3 5A 0F 34 B0 04 EB 02 B0 01 EB 02 B0 4A EB 02 B0 49 EB 02 B0 99 EB 02 B0 06 EB 02 B0 05 EB 02 B0 C5 EB 02 B0 03 0F B6 C0 89 E1 0D 00 00 0C 00 E8 CC FF FF FF 73 03 83 C8 FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 21 09 00 00 34 00 00 00 34 00 00 00 B9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 01 00 10 00 01 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 55 50 58 21 ?? 0? 0D 1D 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 05 00 00 00 ?? ?? B6 FC CE FA ED FE 07 00 03 06 02 } condition: - $1 at macho.entry_point + 363 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + 363 + $1 at macho.entry_point + 363 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) + 363 } rule upx_392_nrv2e @@ -174,5 +174,5 @@ rule upx_392_nrv2e strings: $1 = { 8D 52 04 77 F2 C3 5A 58 59 51 50 52 57 97 31 C0 F3 AA 5F C3 5A 0F 34 B0 04 EB 02 B0 01 EB 02 B0 4A EB 02 B0 49 EB 02 B0 99 EB 02 B0 06 EB 02 B0 05 EB 02 B0 C5 EB 02 B0 03 0F B6 C0 89 E1 0D 00 00 0C 00 E8 CC FF FF FF 73 03 83 C8 FF C3 01 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 00 00 00 00 1C 00 00 00 02 00 00 00 21 09 00 00 34 00 00 00 34 00 00 00 B9 0F 00 00 00 00 00 00 34 00 00 00 03 00 00 00 0C 00 01 00 10 00 01 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 55 50 58 21 ?? 0? 0D 1D 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 00 00 ?? 0? 00 00 08 00 00 00 ?? ?? D7 FC CE FA ED FE 07 00 03 06 02 } condition: - $1 at macho.entry_point + 363 or $1 at macho.ep_for_arch(macho.CPU_TYPE_X86) + 363 + $1 at macho.entry_point + 363 or $1 at macho.entry_point_for_arch(macho.CPU_TYPE_X86) + 363 } diff --git a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp index 1baef1ba9..7f78a6e07 100644 --- a/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp +++ b/tests/bin2llvmir/optimizations/param_return/param_return_tests.cpp @@ -4,6 +4,10 @@ * @copyright (c) 2017 Avast Software, licensed under the MIT license */ +#include "retdec/bin2llvmir/providers/abi/arm64.h" +#include "retdec/bin2llvmir/providers/abi/mips64.h" +#include "retdec/bin2llvmir/providers/abi/powerpc64.h" + #include "retdec/bin2llvmir/optimizations/param_return/param_return.h" #include "bin2llvmir/utils/llvmir_tests.h" @@ -23,11 +27,547 @@ class ParamReturnTests: public LlvmIrTests ParamReturn pass; }; -//// -//// x86 -//// // -//TEST_F(ParamReturnTests, x86PtrCallBasicFunctionality) +// x86 +// + +TEST_F(ParamReturnTests, x86PtrCallBasicFunctionality) +{ + parseInput(R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* %stack_-8 + %2 = load i32, i32* %stack_-4 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PtrCallPrevBbIsUsedOnlyIfItIsASinglePredecessor) +{ + parseInput(R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + br label %lab1 + lab1: + store i32 123, i32* %stack_-4 + br label %lab2 + lab2: + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + br label %lab1 + lab1: + store i32 123, i32* %stack_-4 + br label %lab2 + lab2: + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* %stack_-8 + %2 = load i32, i32* %stack_-4 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PtrCallPrevBbIsNotUsedIfItIsNotASinglePredecessor) +{ + parseInput(R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + br label %lab1 + lab1: + store i32 123, i32* %stack_-4 + br label %lab2 + lab2: + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + call void %a() + br label %lab2 + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + br label %lab1 + lab1: + store i32 123, i32* %stack_-4 + br label %lab2 + lab2: + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* %stack_-8 + %2 = bitcast void ()* %a to void (i32)* + call void %2(i32 %1) + br label %lab2 + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PtrCallOnlyStackStoresAreUsed) +{ + parseInput(R"( + @eax = global i32 0 + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %local = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %local + store i32 789, i32* @eax + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_EAX, getGlobalByName("eax")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @eax = global i32 0 + @r = global i32 0 + define i32 @fnc() { + %stack_-4 = alloca i32 + %local = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %local + store i32 789, i32* @eax + %a = bitcast i32* @r to void()* + %1 = load i32, i32* %stack_-4 + %2 = bitcast void ()* %a to void (i32)* + call void %2(i32 %1) + %3 = load i32, i32* @eax + ret i32 %3 + } + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PtrCallStackAreUsedAsArgumentsInCorrectOrder) +{ + parseInput(R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 456, i32* %stack_-8 + store i32 123, i32* %stack_-4 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 456, i32* %stack_-8 + store i32 123, i32* %stack_-4 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* %stack_-8 + %2 = load i32, i32* %stack_-4 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PtrCallOnlyContinuousStackOffsetsAreUsed) +{ + parseInput(R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-16 = alloca i32 + %stack_-20 = alloca i32 + %stack_-24 = alloca i32 + store i32 1, i32* %stack_-16 + store i32 2, i32* %stack_-20 + store i32 3, i32* %stack_-24 + store i32 4, i32* %stack_-4 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-16", + "storage" : { "type" : "stack", "value" : -16 } + }, + { + "name" : "stack_-20", + "storage" : { "type" : "stack", "value" : -20 } + }, + { + "name" : "stack_-24", + "storage" : { "type" : "stack", "value" : -24 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-16 = alloca i32 + %stack_-20 = alloca i32 + %stack_-24 = alloca i32 + store i32 1, i32* %stack_-16 + store i32 2, i32* %stack_-20 + store i32 3, i32* %stack_-24 + store i32 4, i32* %stack_-4 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* %stack_-24 + %2 = load i32, i32* %stack_-20 + %3 = load i32, i32* %stack_-16 + %4 = bitcast void ()* %a to void (i32, i32, i32)* + call void %4(i32 %1, i32 %2, i32 %3) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86ExternalCallBasicFunctionality) +{ + parseInput(R"( + declare void @print() + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + declare void @print(i32, i32) + declare void @0() + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %1 = load i32, i32* %stack_-8 + %2 = load i32, i32* %stack_-4 + call void @print(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86ExternalCallFixOnMultiplePlaces) +{ + parseInput(R"( + declare void @print() + define void @fnc1() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + call void @print() + ret void + } + define void @fnc2() { + %stack_-16 = alloca i32 + %stack_-20 = alloca i32 + %stack_-24 = alloca i32 + store i32 456, i32* %stack_-20 + store i32 123, i32* %stack_-16 + store i32 123, i32* %stack_-24 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc1", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + }, + { + "name" : "fnc2", + "locals" : [ + { + "name" : "stack_-16", + "storage" : { "type" : "stack", "value" : -16 } + }, + { + "name" : "stack_-20", + "storage" : { "type" : "stack", "value" : -20 } + }, + { + "name" : "stack_-24", + "storage" : { "type" : "stack", "value" : -24 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + declare void @print(i32, i32) + declare void @0() + define void @fnc1() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %1 = load i32, i32* %stack_-8 + %2 = load i32, i32* %stack_-4 + call void @print(i32 %1, i32 %2) + ret void + } + define void @fnc2() { + %stack_-16 = alloca i32 + %stack_-20 = alloca i32 + %stack_-24 = alloca i32 + store i32 456, i32* %stack_-20 + store i32 123, i32* %stack_-16 + store i32 123, i32* %stack_-24 + %1 = load i32, i32* %stack_-24 + %2 = load i32, i32* %stack_-20 + call void @print(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +//TEST_F(ParamReturnTests, x86ExternalCallSomeFunctionCallsAreNotModified) //{ // parseInput(R"( // @r = global i32 0 @@ -339,6 +879,939 @@ class ParamReturnTests: public LlvmIrTests // )"; // checkModuleAgainstExpectedIr(exp); //} + +TEST_F(ParamReturnTests, x86_64PtrCallBasicFunctionality) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rdi = global i64 0 + @rsi = global i64 0 + @rax = global i64 0 + define void @fnc() { + store i64 123, i64* @rdi + store i64 456, i64* @rsi + %a = bitcast i64* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RDI, getGlobalByName("rdi")); + abi->addRegister(X86_REG_RSI, getGlobalByName("rsi")); + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rdi = global i64 0 + @rsi = global i64 0 + @rax = global i64 0 + + define i64 @fnc() { + store i64 123, i64* @rdi + store i64 456, i64* @rsi + %a = bitcast i64* @r to void()* + %1 = load i64, i64* @rdi + %2 = load i64, i64* @rsi + %3 = bitcast void ()* %a to void (i64, i64)* + call void %3(i64 %1, i64 %2) + %4 = load i64, i64* @rax + ret i64 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86_64PtrCallPrevBbIsUsedOnlyIfItIsASinglePredecessor) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rdi = global i64 0 + @rsi = global i64 0 + @rax = global i64 0 + + define void @fnc() { + br label %lab1 + lab1: + store i64 123, i64* @rdi + br label %lab2 + lab2: + store i64 456, i64* @rsi + %a = bitcast i64* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + } + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RDI, getGlobalByName("rdi")); + abi->addRegister(X86_REG_RSI, getGlobalByName("rsi")); + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rdi = global i64 0 + @rsi = global i64 0 + @rax = global i64 0 + + define i64 @fnc() { + br label %lab1 + + lab1: + store i64 123, i64* @rdi + br label %lab2 + + lab2: + store i64 456, i64* @rsi + %a = bitcast i64* @r to void ()* + %1 = load i64, i64* @rdi + %2 = load i64, i64* @rsi + %3 = bitcast void ()* %a to void (i64, i64)* + call void %3(i64 %1, i64 %2) + %4 = load i64, i64* @rax + ret i64 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86_64ExternalCallUseStacksIf6RegistersUsed) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rdi = global i64 0 + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @r10 = global i64 0 + @rax = global i64 0 + declare void @print() + define void @fnc() { + store i64 1, i64* @rdi + %stack_-8 = alloca i64 + %stack_-16 = alloca i64 + store i64 1, i64* @r9 + store i64 2, i64* @r10 + store i64 1, i64* @r8 + store i64 1, i64* @rsi + store i64 2, i64* %stack_-8 + store i64 1, i64* @rdx + store i64 2, i64* %stack_-16 + store i64 1, i64* @rcx + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + }, + { + "name" : "stack_-16", + "storage" : { "type" : "stack", "value" : -16 } + } + + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_RDI, getGlobalByName("rdi")); + abi->addRegister(X86_REG_RSI, getGlobalByName("rsi")); + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + abi->addRegister(X86_REG_R8, getGlobalByName("r8")); + abi->addRegister(X86_REG_R9, getGlobalByName("r9")); + abi->addRegister(X86_REG_R10, getGlobalByName("r10")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rdi = global i64 0 + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @r10 = global i64 0 + @rax = global i64 0 + + declare i64 @print(i64, i64, i64, i64, i64, i64, i64, i64) + + declare void @0() + + define i64 @fnc() { + store i64 1, i64* @rdi + %stack_-8 = alloca i64 + %stack_-16 = alloca i64 + store i64 1, i64* @r9 + store i64 2, i64* @r10 + store i64 1, i64* @r8 + store i64 1, i64* @rsi + store i64 2, i64* %stack_-8 + store i64 1, i64* @rdx + store i64 2, i64* %stack_-16 + store i64 1, i64* @rcx + %1 = load i64, i64* @rdi + %2 = load i64, i64* @rsi + %3 = load i64, i64* @rdx + %4 = load i64, i64* @rcx + %5 = load i64, i64* @r8 + %6 = load i64, i64* @r9 + %7 = load i64, i64* %stack_-16 + %8 = load i64, i64* %stack_-8 + %9 = call i64 @print(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64 %7, i64 %8) + store i64 %9, i64* @rax + %10 = load i64, i64* @rax + ret i64 %10 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86_64ExternalCallUsesFPRegistersBasic) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rax = global i64 0 + @xmm0 = global double 0.0 + @xmm1 = global double 0.0 + + declare void @print() + define void @fnc() { + store double 2.0, double* @xmm1 + store double 2.0, double* @xmm0 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + } + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_XMM0, getGlobalByName("xmm0")); + abi->addRegister(X86_REG_XMM1, getGlobalByName("xmm1")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rax = global i64 0 + @xmm0 = global double 0.000000e+00 + @xmm1 = global double 0.000000e+00 + + declare i64 @print(double, double) + + declare void @0() + + define i64 @fnc() { + store double 2.000000e+00, double* @xmm1 + store double 2.000000e+00, double* @xmm0 + %1 = load double, double* @xmm0 + %2 = load double, double* @xmm1 + %3 = call i64 @print(double %1, double %2) + store i64 %3, i64* @rax + %4 = load i64, i64* @rax + ret i64 %4 + } + + declare void @1() + + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86_64ExternalCallUsesFPRegisters) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rdi = global i64 0 + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @r10 = global i64 0 + @rax = global i64 0 + @xmm0 = global double 0.0 + @xmm1 = global double 0.0 + + declare void @print() + define void @fnc() { + store i64 1, i64* @rdi + store i64 1, i64* @r9 + store i64 2, i64* @r10 + store i64 1, i64* @r8 + store i64 1, i64* @rsi + store double 2.0, double* @xmm1 + store i64 1, i64* @rdx + store double 2.0, double* @xmm0 + store i64 1, i64* @rcx + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + } + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_RDI, getGlobalByName("rdi")); + abi->addRegister(X86_REG_RSI, getGlobalByName("rsi")); + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + abi->addRegister(X86_REG_R8, getGlobalByName("r8")); + abi->addRegister(X86_REG_R9, getGlobalByName("r9")); + abi->addRegister(X86_REG_R10, getGlobalByName("r10")); + abi->addRegister(X86_REG_XMM0, getGlobalByName("xmm0")); + abi->addRegister(X86_REG_XMM1, getGlobalByName("xmm1")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rdi = global i64 0 + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @r10 = global i64 0 + @rax = global i64 0 + @xmm0 = global double 0.000000e+00 + @xmm1 = global double 0.000000e+00 + + declare i64 @print(i64, i64, i64, i64, i64, i64, double, double) + + declare void @0() + + define i64 @fnc() { + store i64 1, i64* @rdi + store i64 1, i64* @r9 + store i64 2, i64* @r10 + store i64 1, i64* @r8 + store i64 1, i64* @rsi + store double 2.000000e+00, double* @xmm1 + store i64 1, i64* @rdx + store double 2.000000e+00, double* @xmm0 + store i64 1, i64* @rcx + %1 = load i64, i64* @rdi + %2 = load i64, i64* @rsi + %3 = load i64, i64* @rdx + %4 = load i64, i64* @rcx + %5 = load i64, i64* @r8 + %6 = load i64, i64* @r9 + %7 = load double, double* @xmm0 + %8 = load double, double* @xmm1 + %9 = call i64 @print(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, double %7, double %8) + store i64 %9, i64* @rax + %10 = load i64, i64* @rax + ret i64 %10 + } + + declare void @1() + + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86_64UsesJustContinuousSequenceOfRegisters) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rax = global i64 0 + @rdi = global i64 0 + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + + declare void @print() + define void @fnc() { + store i64 1, i64* @rdi + store i64 1, i64* @rdx + store i64 1, i64* @rcx + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_RDI, getGlobalByName("rdi")); + abi->addRegister(X86_REG_RSI, getGlobalByName("rsi")); + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rax = global i64 0 + @rdi = global i64 0 + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + + declare i64 @print(i64) + + declare void @0() + + define i64 @fnc() { + store i64 1, i64* @rdi + store i64 1, i64* @rdx + store i64 1, i64* @rcx + %1 = load i64, i64* @rdi + %2 = call i64 @print(i64 %1) + store i64 %2, i64* @rax + %3 = load i64, i64* @rax + ret i64 %3 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ms_x64PtrCallBasicFunctionality) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @rax = global i64 0 + define void @fnc() { + store i64 123, i64* @rcx + store i64 456, i64* @rdx + %a = bitcast i64* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + }, + "fileFormat" : "pe64", + "tools" : + [ + {"name" : "gcc"} + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @rax = global i64 0 + + define i64 @fnc() { + store i64 123, i64* @rcx + store i64 456, i64* @rdx + %a = bitcast i64* @r to void()* + %1 = load i64, i64* @rcx + %2 = load i64, i64* @rdx + %3 = bitcast void ()* %a to void (i64, i64)* + call void %3(i64 %1, i64 %2) + %4 = load i64, i64* @rax + ret i64 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ms_x64PtrCallPrevBbIsUsedOnlyIfItIsASinglePredecessor) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @rax = global i64 0 + + define void @fnc() { + br label %lab1 + lab1: + store i64 123, i64* @rcx + br label %lab2 + lab2: + store i64 456, i64* @rdx + %a = bitcast i64* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + }, + "fileFormat" : "pe64", + "tools" : + [ + {"name" : "gcc"} + ] + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @rax = global i64 0 + + define i64 @fnc() { + br label %lab1 + + lab1: + store i64 123, i64* @rcx + br label %lab2 + + lab2: + store i64 456, i64* @rdx + %a = bitcast i64* @r to void ()* + %1 = load i64, i64* @rcx + %2 = load i64, i64* @rdx + %3 = bitcast void ()* %a to void (i64, i64)* + call void %3(i64 %1, i64 %2) + %4 = load i64, i64* @rax + ret i64 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ms_x64ExternalCallUseStacksIf4RegistersUsed) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @rax = global i64 0 + declare void @print() + define void @fnc() { + %stack_-8 = alloca i64 + %stack_-16 = alloca i64 + store i64 1, i64* @r9 + store i64 1, i64* @r8 + store i64 1, i64* @rsi + store i64 2, i64* %stack_-8 + store i64 1, i64* @rdx + store i64 2, i64* %stack_-16 + store i64 1, i64* @rcx + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + }, + { + "name" : "stack_-16", + "storage" : { "type" : "stack", "value" : -16 } + } + + ] + } + ], + "fileFormat" : "pe64", + "tools" : + [ + {"name" : "gcc"} + ] + + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_RSI, getGlobalByName("rsi")); + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + abi->addRegister(X86_REG_R8, getGlobalByName("r8")); + abi->addRegister(X86_REG_R9, getGlobalByName("r9")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rsi = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @rax = global i64 0 + + declare i64 @print(i64, i64, i64, i64, i64, i64) + + declare void @0() + + define i64 @fnc() { + %stack_-8 = alloca i64 + %stack_-16 = alloca i64 + store i64 1, i64* @r9 + store i64 1, i64* @r8 + store i64 1, i64* @rsi + store i64 2, i64* %stack_-8 + store i64 1, i64* @rdx + store i64 2, i64* %stack_-16 + store i64 1, i64* @rcx + %1 = load i64, i64* @rcx + %2 = load i64, i64* @rdx + %3 = load i64, i64* @r8 + %4 = load i64, i64* @r9 + %5 = load i64, i64* %stack_-16 + %6 = load i64, i64* %stack_-8 + %7 = call i64 @print(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6) + store i64 %7, i64* @rax + %8 = load i64, i64* @rax + ret i64 %8 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegisters) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r8 = global i64 0 + @r9 = global i64 0 + @rax = global i64 0 + @xmm0 = global double 0.0 + @xmm1 = global double 0.0 + + declare void @print() + define void @fnc() { + store double 2.0, double* @xmm1 + store double 2.0, double* @xmm0 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + }, + "fileFormat" : "pe64", + "tools" : + [ + {"name" : "gcc"} + ] + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_R8, getGlobalByName("r8")); + abi->addRegister(X86_REG_R9, getGlobalByName("r9")); + abi->addRegister(X86_REG_XMM0, getGlobalByName("xmm0")); + abi->addRegister(X86_REG_XMM1, getGlobalByName("xmm1")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @r8 = global i64 0 + @r9 = global i64 0 + @rax = global i64 0 + @xmm0 = global double 0.000000e+00 + @xmm1 = global double 0.000000e+00 + + declare i64 @print(double, double) + + declare void @0() + + define i64 @fnc() { + store double 2.000000e+00, double* @xmm1 + store double 2.000000e+00, double* @xmm0 + %1 = load double, double* @xmm0 + %2 = load double, double* @xmm1 + %3 = call i64 @print(double %1, double %2) + store i64 %3, i64* @rax + %4 = load i64, i64* @rax + ret i64 %4 + } + + declare void @1() + + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ms_x64UsesJustContinuousSequenceOfRegisters) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rax = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + + declare void @print() + define void @fnc() { + store i64 1, i64* @r9 + store i64 1, i64* @r8 + store i64 1, i64* @rcx + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + }, + "fileFormat" : "pe64", + "tools" : + [ + {"name" : "gcc"} + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_R8, getGlobalByName("r8")); + abi->addRegister(X86_REG_R9, getGlobalByName("r9")); + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rax = global i64 0 + @r8 = global i64 0 + @r9 = global i64 0 + @rcx = global i64 0 + @rdx = global i64 0 + + declare i64 @print(i64) + + declare void @0() + + define i64 @fnc() { + store i64 1, i64* @r9 + store i64 1, i64* @r8 + store i64 1, i64* @rcx + %1 = load i64, i64* @rcx + %2 = call i64 @print(i64 %1) + store i64 %2, i64* @rax + %3 = load i64, i64* @rax + ret i64 %3 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ms_x64ExternalCallUsesFPRegistersAdvanced) +{ + parseInput(R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rcx = global i64 0 + @rdx = global i64 0 + @rax = global i64 0 + @xmm2 = global double 0.0 + @xmm3 = global double 0.0 + + declare void @print() + define void @fnc() { + store i64 1, i64* @rcx + store i64 1, i64* @rdx + store double 2.0, double* @xmm2 + store double 2.0, double* @xmm3 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "x86" + }, + "fileFormat" : "pe64", + "tools" : + [ + {"name" : "gcc"} + ] + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(X86_REG_RAX, getGlobalByName("rax")); + abi->addRegister(X86_REG_RDX, getGlobalByName("rdx")); + abi->addRegister(X86_REG_RCX, getGlobalByName("rcx")); + abi->addRegister(X86_REG_XMM2, getGlobalByName("xmm2")); + abi->addRegister(X86_REG_XMM3, getGlobalByName("xmm3")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + + @rcx = global i64 0 + @rdx = global i64 0 + @rax = global i64 0 + @xmm2 = global double 0.000000e+00 + @xmm3 = global double 0.000000e+00 + + declare i64 @print(i64, i64, double, double) + + declare void @0() + + define i64 @fnc() { + store i64 1, i64* @rcx + store i64 1, i64* @rdx + store double 2.000000e+00, double* @xmm2 + store double 2.000000e+00, double* @xmm3 + %1 = load i64, i64* @rcx + %2 = load i64, i64* @rdx + %3 = load double, double* @xmm2 + %4 = load double, double* @xmm3 + %5 = call i64 @print(i64 %1, i64 %2, double %3, double %4) + store i64 %5, i64* @rax + %6 = load i64, i64* @rax + ret i64 %6 + } + + declare void @1() + + )"; + checkModuleAgainstExpectedIr(exp); +} + // //TEST_F(ParamReturnTests, x86PtrCallOnlyContinuousStackOffsetsAreUsed) //{ @@ -390,1139 +1863,1031 @@ class ParamReturnTests: public LlvmIrTests // })"); // auto abi = AbiProvider::addAbi(module.get(), &config); // -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r = global i32 0 -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-16 = alloca i32 -// %stack_-20 = alloca i32 -// %stack_-24 = alloca i32 -// store i32 1, i32* %stack_-16 -// store i32 2, i32* %stack_-20 -// store i32 3, i32* %stack_-24 -// store i32 4, i32* %stack_-4 -// %a = bitcast i32* @r to void()* -// %1 = load i32, i32* %stack_-24 -// %2 = load i32, i32* %stack_-20 -// %3 = load i32, i32* %stack_-16 -// %4 = bitcast void ()* %a to void (i32, i32, i32)* -// call void %4(i32 %1, i32 %2, i32 %3) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, x86ExternalCallBasicFunctionality) -//{ -// parseInput(R"( -// declare void @print() -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 123, i32* %stack_-4 -// store i32 456, i32* %stack_-8 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "little", -// "name" : "x86" -// }, -// "functions" : [ -// { -// "name" : "fnc", -// "locals" : [ -// { -// "name" : "stack_-4", -// "storage" : { "type" : "stack", "value" : -4 } -// }, -// { -// "name" : "stack_-8", -// "storage" : { "type" : "stack", "value" : -8 } -// } -// ] -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// declare void @print(i32, i32) -// declare void @0() -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 123, i32* %stack_-4 -// store i32 456, i32* %stack_-8 -// %1 = load i32, i32* %stack_-8 -// %2 = load i32, i32* %stack_-4 -// call void @print(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, x86ExternalCallFixOnMultiplePlaces) -//{ -// parseInput(R"( -// declare void @print() -// define void @fnc1() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 123, i32* %stack_-4 -// store i32 456, i32* %stack_-8 -// call void @print() -// ret void -// } -// define void @fnc2() { -// %stack_-16 = alloca i32 -// %stack_-20 = alloca i32 -// %stack_-24 = alloca i32 -// store i32 456, i32* %stack_-20 -// store i32 123, i32* %stack_-16 -// store i32 123, i32* %stack_-24 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "little", -// "name" : "x86" -// }, -// "functions" : [ -// { -// "name" : "fnc1", -// "locals" : [ -// { -// "name" : "stack_-4", -// "storage" : { "type" : "stack", "value" : -4 } -// }, -// { -// "name" : "stack_-8", -// "storage" : { "type" : "stack", "value" : -8 } -// } -// ] -// }, -// { -// "name" : "fnc2", -// "locals" : [ -// { -// "name" : "stack_-16", -// "storage" : { "type" : "stack", "value" : -16 } -// }, -// { -// "name" : "stack_-20", -// "storage" : { "type" : "stack", "value" : -20 } -// }, -// { -// "name" : "stack_-24", -// "storage" : { "type" : "stack", "value" : -24 } -// } -// ] -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// declare void @print(i32, i32) -// declare void @0() -// define void @fnc1() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 123, i32* %stack_-4 -// store i32 456, i32* %stack_-8 -// %1 = load i32, i32* %stack_-8 -// %2 = load i32, i32* %stack_-4 -// call void @print(i32 %1, i32 %2) -// ret void -// } -// define void @fnc2() { -// %stack_-16 = alloca i32 -// %stack_-20 = alloca i32 -// %stack_-24 = alloca i32 -// store i32 456, i32* %stack_-20 -// store i32 123, i32* %stack_-16 -// store i32 123, i32* %stack_-24 -// %1 = load i32, i32* %stack_-24 -// %2 = load i32, i32* %stack_-20 -// call void @print(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -////TEST_F(ParamReturnTests, x86ExternalCallSomeFunctionCallsAreNotModified) -////{ -//// auto module = parseInput(R"( -//// declare void @print1() -//// declare void @print2() -//// declare void @print3(i32) -//// define void @fnc() { -//// %stack_-4 = alloca i32 -//// store i32 123, i32* %stack_-4 -//// call void @print1() -//// store i32 123, i32* %stack_-4 -//// call void @print2() -//// store i32 123, i32* %stack_-4 -//// call void @print3(i32 123) -//// ret void -//// } -//// )"); -//// auto config = Config::fromJsonString(module.get(), R"({ -//// "architecture" : { -//// "bitSize" : 32, -//// "endian" : "little", -//// "name" : "x86" -//// }, -//// "functions" : [ -//// { -//// "name" : "fnc", -//// "locals" : [ -//// { -//// "name" : "stack_-4", -//// "storage" : { "type" : "stack", "value" : -4 } -//// } -//// ] -//// }, -//// { -//// "name" : "print1", -//// "fncType" : "dynamicallyLinked", -//// "declarationStr" : "whatever" -//// }, -//// { -//// "name" : "print2", -//// "fncType" : "dynamicallyLinked", -//// "isFromDebug" : true -//// }, -//// { -//// "name" : "print3", -//// "fncType" : "dynamicallyLinked" -//// } -//// ] -//// })"); -//// -//// pass.runOnModuleCustom(*module, &config, abi); -//// -//// std::string exp = R"( -//// declare void @print1() -//// declare void @print2() -//// declare void @print3(i32) -//// define void @fnc() { -//// %stack_-4 = alloca i32 -//// store i32 123, i32* %stack_-4 -//// call void @print1() -//// store i32 123, i32* %stack_-4 -//// call void @print2() -//// store i32 123, i32* %stack_-4 -//// call void @print3(i32 123) -//// ret void -//// } -//// )"; -//// checkModuleAgainstExpectedIr(exp, module.get()); -////} -// -//// -//// PowerPC -//// -// -//TEST_F(ParamReturnTests, ppcPtrCallBasicFunctionality) -//{ -// parseInput(R"( -// @r = global i32 0 -// @r3 = global i32 0 -// @r4 = global i32 0 -// define void @fnc() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r4 -// %a = bitcast i32* @r to void()* -// call void %a() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// }, -// "registers" : [ -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "gpregs", "registerNumber" : 3 } -// }, -// { -// "name" : "r4", -// "storage" : { "type" : "register", "value" : "r4", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r = global i32 0 -// @r3 = global i32 0 -// @r4 = global i32 0 -// define void @fnc() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r4 -// %a = bitcast i32* @r to void()* -// %1 = load i32, i32* @r3 -// %2 = load i32, i32* @r4 -// %3 = bitcast void ()* %a to void (i32, i32)* -// call void %3(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, ppcExternalCallBasicFunctionality) -//{ -// parseInput(R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// declare void @print() -// define void @fnc() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r4 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// }, -// "registers" : [ -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "gpregs", "registerNumber" : 3 } -// }, -// { -// "name" : "r4", -// "storage" : { "type" : "register", "value" : "r4", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// declare void @print(i32, i32) -// declare void @0() -// define void @fnc() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r4 -// %1 = load i32, i32* @r3 -// %2 = load i32, i32* @r4 -// call void @print(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, ppcExternalCallDoNotUseObjectsIfTheyAreNotRegisters) -//{ -// parseInput(R"( -// @r3 = global i32 0 -// declare void @print() -// define void @fnc() { -// store i32 123, i32* @r3 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// } -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r3 = global i32 0 -// declare void @print() -// define void @fnc() { -// store i32 123, i32* @r3 -// call void @print() -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, ppcExternalCallFilterRegistersOnMultiplePlaces) -//{ -// parseInput(R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// @r5 = global i32 0 -// declare void @print() -// define void @fnc1() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r4 -// call void @print() -// ret void -// } -// define void @fnc2() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r5 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// }, -// "registers" : [ -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "gpregs", "registerNumber" : 3 } -// }, -// { -// "name" : "r4", -// "storage" : { "type" : "register", "value" : "r4", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// }, -// { -// "name" : "r5", -// "storage" : { "type" : "register", "value" : "r5", -// "registerClass" : "gpregs", "registerNumber" : 5 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// @r5 = global i32 0 -// declare void @print(i32) -// declare void @0() -// define void @fnc1() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r4 -// %1 = load i32, i32* @r3 -// call void @print(i32 %1) -// ret void -// } -// define void @fnc2() { -// store i32 123, i32* @r3 -// store i32 456, i32* @r5 -// %1 = load i32, i32* @r3 -// call void @print(i32 %1) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, ppcExternalCallDoNotUseAllRegisters) -//{ -// parseInput(R"( -// @r1 = global i32 0 -// @r2 = global i32 0 -// @r3 = global i32 0 -// declare void @print() -// define void @fnc() { -// store i32 123, i32* @r1 -// store i32 456, i32* @r3 -// store i32 789, i32* @r2 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// }, -// "registers" : [ -// { -// "name" : "r1", -// "storage" : { "type" : "register", "value" : "r1", -// "registerClass" : "gpregs", "registerNumber" : 1 } -// }, -// { -// "name" : "r2", -// "storage" : { "type" : "register", "value" : "r2", -// "registerClass" : "gpregs", "registerNumber" : 2 } -// }, -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "gpregs", "registerNumber" : 3 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r1 = global i32 0 -// @r2 = global i32 0 -// @r3 = global i32 0 -// declare void @print(i32) -// declare void @0() -// define void @fnc() { -// store i32 123, i32* @r1 -// store i32 456, i32* @r3 -// store i32 789, i32* @r2 -// %1 = load i32, i32* @r3 -// call void @print(i32 %1) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, ppcExternalCallSortRegistersIntoCorrectOrder) -//{ -// parseInput(R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// @r5 = global i32 0 -// declare void @print() -// define void @fnc() { -// store i32 123, i32* @r5 -// store i32 456, i32* @r3 -// store i32 789, i32* @r4 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// }, -// "registers" : [ -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "gpregs", "registerNumber" : 3 } -// }, -// { -// "name" : "r4", -// "storage" : { "type" : "register", "value" : "r4", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// }, -// { -// "name" : "r5", -// "storage" : { "type" : "register", "value" : "r5", -// "registerClass" : "gpregs", "registerNumber" : 5 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// @r5 = global i32 0 -// declare void @print(i32, i32, i32) -// declare void @0() -// define void @fnc() { -// store i32 123, i32* @r5 -// store i32 456, i32* @r3 -// store i32 789, i32* @r4 -// %1 = load i32, i32* @r3 -// %2 = load i32, i32* @r4 -// %3 = load i32, i32* @r5 -// call void @print(i32 %1, i32 %2, i32 %3) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, ppcExternalCallDoNotUseStacksIfLessThan7RegistersUsed) -//{ -// parseInput(R"( -// @r3 = global i32 0 -// declare void @print() -// define void @fnc() { -// %stack_-4 = alloca i32 -// store i32 123, i32* @r3 -// store i32 456, i32* %stack_-4 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// }, -// "functions" : [ -// { -// "name" : "fnc", -// "locals" : [ -// { -// "name" : "stack_-4", -// "storage" : { "type" : "stack", "value" : -4 } -// } -// ] -// } -// ], -// "registers" : [ -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "gpregs", "registerNumber" : 3 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r3 = global i32 0 -// declare void @print(i32) -// declare void @0() -// define void @fnc() { -// %stack_-4 = alloca i32 -// store i32 123, i32* @r3 -// store i32 456, i32* %stack_-4 -// %1 = load i32, i32* @r3 -// call void @print(i32 %1) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, ppcExternalCallUseStacksIf7RegistersUsed) -//{ -// parseInput(R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// @r5 = global i32 0 -// @r6 = global i32 0 -// @r7 = global i32 0 -// @r8 = global i32 0 -// @r9 = global i32 0 -// @r10 = global i32 0 -// declare void @print() -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 1, i32* @r3 -// store i32 1, i32* @r4 -// store i32 1, i32* @r5 -// store i32 2, i32* %stack_-4 -// store i32 1, i32* @r6 -// store i32 1, i32* @r7 -// store i32 1, i32* @r8 -// store i32 2, i32* %stack_-8 -// store i32 1, i32* @r9 -// store i32 1, i32* @r10 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "big", -// "name" : "powerpc" -// }, -// "functions" : [ -// { -// "name" : "fnc", -// "locals" : [ -// { -// "name" : "stack_-4", -// "storage" : { "type" : "stack", "value" : -4 } -// }, -// { -// "name" : "stack_-8", -// "storage" : { "type" : "stack", "value" : -8 } -// } -// ] -// } -// ], -// "registers" : [ -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "gpregs", "registerNumber" : 3 } -// }, -// { -// "name" : "r4", -// "storage" : { "type" : "register", "value" : "r4", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// }, -// { -// "name" : "r5", -// "storage" : { "type" : "register", "value" : "r5", -// "registerClass" : "gpregs", "registerNumber" : 5 } -// }, -// { -// "name" : "r6", -// "storage" : { "type" : "register", "value" : "r6", -// "registerClass" : "gpregs", "registerNumber" : 6 } -// }, -// { -// "name" : "r7", -// "storage" : { "type" : "register", "value" : "r7", -// "registerClass" : "gpregs", "registerNumber" : 7 } -// }, -// { -// "name" : "r8", -// "storage" : { "type" : "register", "value" : "r8", -// "registerClass" : "gpregs", "registerNumber" : 8 } -// }, -// { -// "name" : "r9", -// "storage" : { "type" : "register", "value" : "r9", -// "registerClass" : "gpregs", "registerNumber" : 9 } -// }, -// { -// "name" : "r10", -// "storage" : { "type" : "register", "value" : "r10", -// "registerClass" : "gpregs", "registerNumber" : 10 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r3 = global i32 0 -// @r4 = global i32 0 -// @r5 = global i32 0 -// @r6 = global i32 0 -// @r7 = global i32 0 -// @r8 = global i32 0 -// @r9 = global i32 0 -// @r10 = global i32 0 -// declare void @print(i32, i32, i32, i32, i32, i32, i32, i32, i32) -// declare void @0() -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 1, i32* @r3 -// store i32 1, i32* @r4 -// store i32 1, i32* @r5 -// store i32 2, i32* %stack_-4 -// store i32 1, i32* @r6 -// store i32 1, i32* @r7 -// store i32 1, i32* @r8 -// store i32 2, i32* %stack_-8 -// store i32 1, i32* @r9 -// store i32 1, i32* @r10 -// %1 = load i32, i32* @r3 -// %2 = load i32, i32* @r4 -// %3 = load i32, i32* @r5 -// %4 = load i32, i32* @r6 -// %5 = load i32, i32* @r7 -// %6 = load i32, i32* @r8 -// %7 = load i32, i32* @r9 -// %8 = load i32, i32* %stack_-8 -// %9 = load i32, i32* %stack_-4 -// call void @print(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7, i32 %8, i32 %9) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//// -//// ARM (+THUMB) -//// -// -//TEST_F(ParamReturnTests, armPtrCallBasicFunctionality) -//{ -// parseInput(R"( -// @r = global i32 0 -// @r0 = global i32 0 -// @r1 = global i32 0 -// define void @fnc() { -// store i32 123, i32* @r0 -// store i32 456, i32* @r1 -// %a = bitcast i32* @r to void()* -// call void %a() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "little", -// "name" : "arm" -// }, -// "registers" : [ -// { -// "name" : "r0", -// "storage" : { "type" : "register", "value" : "r0", -// "registerClass" : "regs", "registerNumber" : 0 } -// }, -// { -// "name" : "r1", -// "storage" : { "type" : "register", "value" : "r1", -// "registerClass" : "regs", "registerNumber" : 1 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r = global i32 0 -// @r0 = global i32 0 -// @r1 = global i32 0 -// define void @fnc() { -// store i32 123, i32* @r0 -// store i32 456, i32* @r1 -// %a = bitcast i32* @r to void()* -// %1 = load i32, i32* @r0 -// %2 = load i32, i32* @r1 -// %3 = bitcast void ()* %a to void (i32, i32)* -// call void %3(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, armExternalCallBasicFunctionality) -//{ -// parseInput(R"( -// @r0 = global i32 0 -// @r1 = global i32 0 -// declare void @print() -// define void @fnc() { -// store i32 123, i32* @r0 -// store i32 456, i32* @r1 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "little", -// "name" : "arm" -// }, -// "registers" : [ -// { -// "name" : "r0", -// "storage" : { "type" : "register", "value" : "r0", -// "registerClass" : "regs", "registerNumber" : 0 } -// }, -// { -// "name" : "r1", -// "storage" : { "type" : "register", "value" : "r1", -// "registerClass" : "regs", "registerNumber" : 1 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r0 = global i32 0 -// @r1 = global i32 0 -// declare void @print(i32, i32) -// declare void @0() -// define void @fnc() { -// store i32 123, i32* @r0 -// store i32 456, i32* @r1 -// %1 = load i32, i32* @r0 -// %2 = load i32, i32* @r1 -// call void @print(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, armExternalCallUseStacksIf4RegistersUsed) -//{ -// parseInput(R"( -// @r0 = global i32 0 -// @r1 = global i32 0 -// @r2 = global i32 0 -// @r3 = global i32 0 -// @r4 = global i32 0 -// declare void @print() -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 1, i32* @r2 -// store i32 1, i32* @r1 -// store i32 2, i32* %stack_-4 -// store i32 1, i32* @r4 -// store i32 1, i32* @r0 -// store i32 2, i32* %stack_-8 -// store i32 1, i32* @r3 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "little", -// "name" : "arm" -// }, -// "functions" : [ -// { -// "name" : "fnc", -// "locals" : [ -// { -// "name" : "stack_-4", -// "storage" : { "type" : "stack", "value" : -4 } -// }, -// { -// "name" : "stack_-8", -// "storage" : { "type" : "stack", "value" : -8 } -// } -// ] -// } -// ], -// "registers" : [ -// { -// "name" : "r0", -// "storage" : { "type" : "register", "value" : "r0", -// "registerClass" : "regs", "registerNumber" : 0 } -// }, -// { -// "name" : "r1", -// "storage" : { "type" : "register", "value" : "r1", -// "registerClass" : "regs", "registerNumber" : 1 } -// }, -// { -// "name" : "r2", -// "storage" : { "type" : "register", "value" : "r2", -// "registerClass" : "regs", "registerNumber" : 2 } -// }, -// { -// "name" : "r3", -// "storage" : { "type" : "register", "value" : "r3", -// "registerClass" : "regs", "registerNumber" : 3 } -// }, -// { -// "name" : "r4", -// "storage" : { "type" : "register", "value" : "r4", -// "registerClass" : "regs", "registerNumber" : 4 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r0 = global i32 0 -// @r1 = global i32 0 -// @r2 = global i32 0 -// @r3 = global i32 0 -// @r4 = global i32 0 -// declare void @print(i32, i32, i32, i32, i32, i32) -// declare void @0() -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 1, i32* @r2 -// store i32 1, i32* @r1 -// store i32 2, i32* %stack_-4 -// store i32 1, i32* @r4 -// store i32 1, i32* @r0 -// store i32 2, i32* %stack_-8 -// store i32 1, i32* @r3 -// %1 = load i32, i32* @r0 -// %2 = load i32, i32* @r1 -// %3 = load i32, i32* @r2 -// %4 = load i32, i32* @r3 -// %5 = load i32, i32* %stack_-8 -// %6 = load i32, i32* %stack_-4 -// call void @print(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//// -//// MIPS (+Pic32) -//// -// -//TEST_F(ParamReturnTests, mipsPtrCallBasicFunctionality) -//{ -// parseInput(R"( -// @r = global i32 0 -// @a0 = global i32 0 -// @a1 = global i32 0 -// define void @fnc() { -// store i32 123, i32* @a0 -// store i32 456, i32* @a1 -// %a = bitcast i32* @r to void()* -// call void %a() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "little", -// "name" : "mips" -// }, -// "registers" : [ -// { -// "name" : "a0", -// "storage" : { "type" : "register", "value" : "a0", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// }, -// { -// "name" : "a1", -// "storage" : { "type" : "register", "value" : "a1", -// "registerClass" : "gpregs", "registerNumber" : 5 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @r = global i32 0 -// @a0 = global i32 0 -// @a1 = global i32 0 -// define void @fnc() { -// store i32 123, i32* @a0 -// store i32 456, i32* @a1 -// %a = bitcast i32* @r to void()* -// %1 = load i32, i32* @a0 -// %2 = load i32, i32* @a1 -// %3 = bitcast void ()* %a to void (i32, i32)* -// call void %3(i32 %1, i32 %2) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} -// -//TEST_F(ParamReturnTests, mipsExternalCallBasicFunctionality) -//{ -// parseInput(R"( -// @a0 = global i32 0 -// @a1 = global i32 0 -// declare void @print() -// define void @fnc() { -// store i32 123, i32* @a0 -// store i32 456, i32* @a1 -// call void @print() -// ret void -// } -// )"); -// auto config = Config::fromJsonString(module.get(), R"({ -// "architecture" : { -// "bitSize" : 32, -// "endian" : "little", -// "name" : "mips" -// }, -// "registers" : [ -// { -// "name" : "a0", -// "storage" : { "type" : "register", "value" : "a0", -// "registerClass" : "gpregs", "registerNumber" : 4 } -// }, -// { -// "name" : "a1", -// "storage" : { "type" : "register", "value" : "a1", -// "registerClass" : "gpregs", "registerNumber" : 5 } -// } -// ] -// })"); -// auto abi = AbiProvider::addAbi(module.get(), &config); -// -// pass.runOnModuleCustom(*module, &config, abi); + +TEST_F(ParamReturnTests, ppcPtrCallBasicFunctionality) +{ + parseInput(R"( + @r = global i32 0 + @r3 = global i32 0 + @r4 = global i32 0 + define void @fnc() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + abi->addRegister(PPC_REG_R4, getGlobalByName("r4")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + @r3 = global i32 0 + @r4 = global i32 0 + + define i32 @fnc() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + %a = bitcast i32* @r to void ()* + %1 = load i32, i32* @r3 + %2 = load i32, i32* @r4 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i32 %1, i32 %2) + %4 = load i32, i32* @r3 + ret i32 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ppcExternalCallBasicFunctionality) +{ + parseInput(R"( + @r3 = global i32 0 + @r4 = global i32 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + abi->addRegister(PPC_REG_R4, getGlobalByName("r4")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r3 = global i32 0 + @r4 = global i32 0 + + declare i32 @print(i32, i32) + declare void @0() + + define i32 @fnc() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + %1 = load i32, i32* @r3 + %2 = load i32, i32* @r4 + %3 = call i32 @print(i32 %1, i32 %2) + store i32 %3, i32* @r3 + %4 = load i32, i32* @r3 + ret i32 %4 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ppcExternalCallBasicFPFunctionality) +{ + parseInput(R"( + @r3 = global i32 0 + @r4 = global i32 0 + @f1 = global double 0.0 + @f2 = global double 0.0 + declare void @print() + define void @fnc() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + store double 0.0, double* @f1 + store double 0.0, double* @f2 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + abi->addRegister(PPC_REG_R4, getGlobalByName("r4")); + abi->addRegister(PPC_REG_F1, getGlobalByName("f1")); + abi->addRegister(PPC_REG_F2, getGlobalByName("f2")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r3 = global i32 0 + @r4 = global i32 0 + @f1 = global double 0.0 + @f2 = global double 0.0 + + declare i32 @print(i32, i32, double, double) + declare void @0() + + define i32 @fnc() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + store double 0.0, double* @f1 + store double 0.0, double* @f2 + %1 = load i32, i32* @r3 + %2 = load i32, i32* @r4 + %3 = load double, double* @f1 + %4 = load double, double* @f2 + %5 = call i32 @print(i32 %1, i32 %2, double %3, double %4) + store i32 %5, i32* @r3 + %6 = load i32, i32* @r3 + ret i32 %6 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ppcExternalCallDoNotUseObjectsIfTheyAreNotRegisters) +{ + parseInput(R"( + @r3 = global i32 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @r3 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r3 = global i32 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @r3 + call void @print() + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} +/* +TEST_F(ParamReturnTests, ppcExternalCallFilterRegistersOnMultiplePlaces) +{ + parseInput(R"( + @r3 = global i32 0 + @r4 = global i32 0 + @r5 = global i32 0 + declare void @print() + define void @fnc1() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + call void @print() + ret void + } + define void @fnc2() { + store i32 123, i32* @r3 + store i32 456, i32* @r5 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + abi->addRegister(PPC_REG_R4, getGlobalByName("r4")); + abi->addRegister(PPC_REG_R5, getGlobalByName("r5")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r3 = global i32 0 + @r4 = global i32 0 + @r5 = global i32 0 + + declare i32 @print(i32) + + declare void @0() + + define i32 @fnc1() { + store i32 123, i32* @r3 + store i32 456, i32* @r4 + %1 = load i32, i32* @r3 + %2 = call i32 @print(i32 %1) + store i32 %2, i32* @r3 + %3 = load i32, i32* @r3 + ret i32 %3 + } + + declare void @1() + + define i32 @fnc2() { + store i32 123, i32* @r3 + store i32 456, i32* @r5 + %1 = load i32, i32* @r3 + %2 = call i32 @print(i32 %1) + store i32 %2, i32* @r3 + %3 = load i32, i32* @r3 + ret i32 %3 + } + + declare void @2() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ppcExternalCallDoNotUseAllRegisters) +{ + parseInput(R"( + @r1 = global i32 0 + @r2 = global i32 0 + @r3 = global i32 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @r1 + store i32 456, i32* @r3 + store i32 789, i32* @r2 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(PPC_REG_R1, getGlobalByName("r1")); + abi->addRegister(PPC_REG_R2, getGlobalByName("r2")); + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r1 = global i32 0 + @r2 = global i32 0 + @r3 = global i32 0 + + declare i32 @print(i32) + + declare void @0() + + define i32 @fnc() { + store i32 123, i32* @r1 + store i32 456, i32* @r3 + store i32 789, i32* @r2 + %1 = load i32, i32* @r3 + %2 = call i32 @print(i32 %1) + store i32 %2, i32* @r3 + %3 = load i32, i32* @r3 + ret i32 %3 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} +*/ + +TEST_F(ParamReturnTests, ppcExternalCallSortRegistersIntoCorrectOrder) +{ + parseInput(R"( + @r3 = global i32 0 + @r4 = global i32 0 + @r5 = global i32 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @r5 + store i32 456, i32* @r3 + store i32 789, i32* @r4 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + abi->addRegister(PPC_REG_R4, getGlobalByName("r4")); + abi->addRegister(PPC_REG_R5, getGlobalByName("r5")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r3 = global i32 0 + @r4 = global i32 0 + @r5 = global i32 0 + + declare i32 @print(i32, i32, i32) + + declare void @0() + + define i32 @fnc() { + store i32 123, i32* @r5 + store i32 456, i32* @r3 + store i32 789, i32* @r4 + %1 = load i32, i32* @r3 + %2 = load i32, i32* @r4 + %3 = load i32, i32* @r5 + %4 = call i32 @print(i32 %1, i32 %2, i32 %3) + store i32 %4, i32* @r3 + %5 = load i32, i32* @r3 + ret i32 %5 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ppcExternalCallDoNotUseStacksIfLessThan7RegistersUsed) +{ + parseInput(R"( + @r3 = global i32 0 + declare void @print() + define void @fnc() { + %stack_-4 = alloca i32 + store i32 123, i32* @r3 + store i32 456, i32* %stack_-4 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "big", + "name" : "powerpc" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(PPC_REG_R3, getGlobalByName("r3")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r3 = global i32 0 + + declare i32 @print(i32) + + declare void @0() + + define i32 @fnc() { + %stack_-4 = alloca i32 + store i32 123, i32* @r3 + store i32 456, i32* %stack_-4 + %1 = load i32, i32* @r3 + %2 = call i32 @print(i32 %1) + store i32 %2, i32* @r3 + %3 = load i32, i32* @r3 + ret i32 %3 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, ppc64PtrCallBasicFunctionality) +{ + parseInput(R"( + target datalayout = "E-m:e-p:64:64-i64:64-n32" + @r = global i64 0 + @r3 = global i64 0 + @r4 = global i64 0 + define void @fnc() { + store i64 123, i64* @r3 + store i64 456, i64* @r4 + %a = bitcast i64* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "big", + "name" : "powerpc64" + } + })"); + + AbiPowerpc64 abi(module.get(), &config); + + abi.addRegister(PPC_REG_R3, getGlobalByName("r3")); + abi.addRegister(PPC_REG_R4, getGlobalByName("r4")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + target datalayout = "E-m:e-p:64:64-i64:64-n32" + + @r = global i64 0 + @r3 = global i64 0 + @r4 = global i64 0 + + define i64 @fnc() { + store i64 123, i64* @r3 + store i64 456, i64* @r4 + %a = bitcast i64* @r to void ()* + %1 = load i64, i64* @r3 + %2 = load i64, i64* @r4 + %3 = bitcast void ()* %a to void (i64, i64)* + call void %3(i64 %1, i64 %2) + %4 = load i64, i64* @r3 + ret i64 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + // // std::string exp = R"( -// @a0 = global i32 0 -// @a1 = global i32 0 -// declare void @print(i32, i32) -// declare void @0() +// @r = global i32 0 // define void @fnc() { -// store i32 123, i32* @a0 -// store i32 456, i32* @a1 -// %1 = load i32, i32* @a0 -// %2 = load i32, i32* @a1 -// call void @print(i32 %1, i32 %2) +// %stack_-4 = alloca i32 +// %stack_-16 = alloca i32 +// %stack_-20 = alloca i32 +// %stack_-24 = alloca i32 +// store i32 1, i32* %stack_-16 +// store i32 2, i32* %stack_-20 +// store i32 3, i32* %stack_-24 +// store i32 4, i32* %stack_-4 +// %a = bitcast i32* @r to void()* +// %1 = load i32, i32* %stack_-24 +// %2 = load i32, i32* %stack_-20 +// %3 = load i32, i32* %stack_-16 +// %4 = bitcast void ()* %a to void (i32, i32, i32)* +// call void %4(i32 %1, i32 %2, i32 %3) // ret void // } // )"; // checkModuleAgainstExpectedIr(exp); //} // -//TEST_F(ParamReturnTests, mipsExternalCallUseStacksIf4RegistersUsed) + +TEST_F(ParamReturnTests, armPtrCallBasicFunctionality) +{ + parseInput(R"( + @r = global i32 0 + @r0 = global i32 0 + @r1 = global i32 0 + define void @fnc() { + store i32 123, i32* @r0 + store i32 456, i32* @r1 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "arm" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(ARM_REG_R0, getGlobalByName("r0")); + abi->addRegister(ARM_REG_R1, getGlobalByName("r1")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + @r0 = global i32 0 + @r1 = global i32 0 + + define i32 @fnc() { + store i32 123, i32* @r0 + store i32 456, i32* @r1 + %a = bitcast i32* @r to void ()* + %1 = load i32, i32* @r0 + %2 = load i32, i32* @r1 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i32 %1, i32 %2) + %4 = load i32, i32* @r0 + ret i32 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, armExternalCallBasicFunctionality) +{ + parseInput(R"( + @r0 = global i32 0 + @r1 = global i32 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @r0 + store i32 456, i32* @r1 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "arm" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(ARM_REG_R0, getGlobalByName("r0")); + abi->addRegister(ARM_REG_R1, getGlobalByName("r1")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r0 = global i32 0 + @r1 = global i32 0 + + declare i32 @print(i32, i32) + + declare void @0() + + define i32 @fnc() { + store i32 123, i32* @r0 + store i32 456, i32* @r1 + %1 = load i32, i32* @r0 + %2 = load i32, i32* @r1 + %3 = call i32 @print(i32 %1, i32 %2) + store i32 %3, i32* @r0 + %4 = load i32, i32* @r0 + ret i32 %4 + } + + declare void @1() + + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, armExternalCallUseStacksIf4RegistersUsed) +{ + parseInput(R"( + @r0 = global i32 0 + @r1 = global i32 0 + @r2 = global i32 0 + @r3 = global i32 0 + @r4 = global i32 0 + declare void @print() + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @r2 + store i32 1, i32* @r1 + store i32 2, i32* %stack_-4 + store i32 1, i32* @r4 + store i32 1, i32* @r0 + store i32 2, i32* %stack_-8 + store i32 1, i32* @r3 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "arm" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(ARM_REG_R0, getGlobalByName("r0")); + abi->addRegister(ARM_REG_R1, getGlobalByName("r1")); + abi->addRegister(ARM_REG_R2, getGlobalByName("r2")); + abi->addRegister(ARM_REG_R3, getGlobalByName("r3")); + abi->addRegister(ARM_REG_R4, getGlobalByName("r4")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r0 = global i32 0 + @r1 = global i32 0 + @r2 = global i32 0 + @r3 = global i32 0 + @r4 = global i32 0 + + declare i32 @print(i32, i32, i32, i32, i32, i32) + + declare void @0() + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @r2 + store i32 1, i32* @r1 + store i32 2, i32* %stack_-4 + store i32 1, i32* @r4 + store i32 1, i32* @r0 + store i32 2, i32* %stack_-8 + store i32 1, i32* @r3 + %1 = load i32, i32* @r0 + %2 = load i32, i32* @r1 + %3 = load i32, i32* @r2 + %4 = load i32, i32* @r3 + %5 = load i32, i32* %stack_-8 + %6 = load i32, i32* %stack_-4 + %7 = call i32 @print(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6) + store i32 %7, i32* @r0 + %8 = load i32, i32* @r0 + ret i32 %8 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, arm64PtrCallBasicFunctionality) +{ + parseInput(R"( + target datalayout = "E-m:e-p:64:64-i64:64-n32" + + @r = global i64 0 + @x0 = global i64 0 + @x1 = global i64 0 + define void @fnc() { + store i64 123, i64* @x0 + store i64 456, i64* @x1 + %a = bitcast i64* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "arm aarch64" + } + })"); + AbiArm64 abi(module.get(), &config); + + abi.addRegister(ARM64_REG_X0, getGlobalByName("x0")); + abi.addRegister(ARM64_REG_X1, getGlobalByName("x1")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + target datalayout = "E-m:e-p:64:64-i64:64-n32" + + @r = global i64 0 + @x0 = global i64 0 + @x1 = global i64 0 + + define i64 @fnc() { + store i64 123, i64* @x0 + store i64 456, i64* @x1 + %a = bitcast i64* @r to void ()* + %1 = load i64, i64* @x0 + %2 = load i64, i64* @x1 + %3 = bitcast void ()* %a to void (i64, i64)* + call void %3(i64 %1, i64 %2) + %4 = load i64, i64* @x0 + ret i64 %4 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, arm64ExternalCallBasicFunctionality) +{ + parseInput(R"( + @x0 = global i64 0 + @x1 = global i64 0 + declare void @print() + define void @fnc() { + store i64 123, i64* @x0 + store i64 456, i64* @x1 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "arm aarch64" + } + })"); + + AbiArm64 abi(module.get(), &config); + + abi.addRegister(ARM64_REG_X0, getGlobalByName("x0")); + abi.addRegister(ARM64_REG_X1, getGlobalByName("x1")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @x0 = global i64 0 + @x1 = global i64 0 + + declare i64 @print(i64, i64) + + declare void @0() + + define i64 @fnc() { + store i64 123, i64* @x0 + store i64 456, i64* @x1 + %1 = load i64, i64* @x0 + %2 = load i64, i64* @x1 + %3 = call i64 @print(i64 %1, i64 %2) + store i64 %3, i64* @x0 + %4 = load i64, i64* @x0 + ret i64 %4 + } + + declare void @1() + + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, arm64ExternalCallUseStacksIf8RegistersUsed) +{ + parseInput(R"( + @x0 = global i64 0 + @x1 = global i64 0 + @x2 = global i64 0 + @x3 = global i64 0 + @x4 = global i64 0 + @x5 = global i64 0 + @x6 = global i64 0 + @x7 = global i64 0 + @x8 = global i64 0 + declare void @print() + define void @fnc() { + %stack_-4 = alloca i64 + %stack_-12 = alloca i64 + store i64 1, i64* @x2 + store i64 1, i64* @x1 + store i64 1, i64* @x5 + store i64 1, i64* @x6 + store i64 1, i64* @x8 + store i64 1, i64* @x7 + store i64 2, i64* %stack_-4 + store i64 1, i64* @x4 + store i64 1, i64* @x0 + store i64 2, i64* %stack_-12 + store i64 1, i64* @x3 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "arm aarch64" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-12", + "storage" : { "type" : "stack", "value" : -12 } + } + ] + } + ] + })"); + AbiArm64 abi(module.get(), &config); + + abi.addRegister(ARM64_REG_X0, getGlobalByName("x0")); + abi.addRegister(ARM64_REG_X1, getGlobalByName("x1")); + abi.addRegister(ARM64_REG_X2, getGlobalByName("x2")); + abi.addRegister(ARM64_REG_X3, getGlobalByName("x3")); + abi.addRegister(ARM64_REG_X4, getGlobalByName("x4")); + abi.addRegister(ARM64_REG_X5, getGlobalByName("x5")); + abi.addRegister(ARM64_REG_X6, getGlobalByName("x6")); + abi.addRegister(ARM64_REG_X7, getGlobalByName("x7")); + abi.addRegister(ARM64_REG_X8, getGlobalByName("x8")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @x0 = global i64 0 + @x1 = global i64 0 + @x2 = global i64 0 + @x3 = global i64 0 + @x4 = global i64 0 + @x5 = global i64 0 + @x6 = global i64 0 + @x7 = global i64 0 + @x8 = global i64 0 + + declare i64 @print(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64) + + declare void @0() + + define i64 @fnc() { + %stack_-4 = alloca i64 + %stack_-12 = alloca i64 + store i64 1, i64* @x2 + store i64 1, i64* @x1 + store i64 1, i64* @x5 + store i64 1, i64* @x6 + store i64 1, i64* @x8 + store i64 1, i64* @x7 + store i64 2, i64* %stack_-4 + store i64 1, i64* @x4 + store i64 1, i64* @x0 + store i64 2, i64* %stack_-12 + store i64 1, i64* @x3 + + %1 = load i64, i64* @x0 + %2 = load i64, i64* @x1 + %3 = load i64, i64* @x2 + %4 = load i64, i64* @x3 + %5 = load i64, i64* @x4 + %6 = load i64, i64* @x5 + %7 = load i64, i64* @x6 + %8 = load i64, i64* @x7 + %9 = load i64, i64* %stack_-12 + %10 = load i64, i64* %stack_-4 + %11 = call i64 @print(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64 %7, i64 %8, i64 %9, i64 %10) + store i64 %11, i64* @x0 + %12 = load i64, i64* @x0 + ret i64 %12 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, arm64ExternalCallHasDouleParameter) +{ + parseInput(R"( + @x0 = global i64 0 + @x1 = global i64 0 + @x2 = global i64 0 + @x3 = global i64 0 + @x4 = global i64 0 + @v0 = global double 0.0 + declare void @foo() + define void @fnc() { + store double 0.0, double* @v0 + call void @foo() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "arm aarch64" + } + })"); + AbiArm64 abi(module.get(), &config); + + abi.addRegister(ARM64_REG_X0, getGlobalByName("x0")); + abi.addRegister(ARM64_REG_X1, getGlobalByName("x1")); + abi.addRegister(ARM64_REG_X2, getGlobalByName("x2")); + abi.addRegister(ARM64_REG_X3, getGlobalByName("x3")); + abi.addRegister(ARM64_REG_X4, getGlobalByName("x4")); + abi.addRegister(ARM64_REG_V0, getGlobalByName("v0")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + @x0 = global i64 0 + @x1 = global i64 0 + @x2 = global i64 0 + @x3 = global i64 0 + @x4 = global i64 0 + @v0 = global double 0.0 + + declare i64 @foo(double) + + declare void @0() + + define i64 @fnc() { + store double 0.0, double* @v0 + %1 = load double, double* @v0 + %2 = call i64 @foo(double %1) + store i64 %2, i64* @x0 + %3 = load i64, i64* @x0 + ret i64 %3 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +// +//TEST_F(ParamReturnTests, ppcExternalCallUseStacksIf7RegistersUsed) //{ // parseInput(R"( -// @a0 = global i32 0 -// @a1 = global i32 0 -// @a2 = global i32 0 -// @a3 = global i32 0 -// @t0 = global i32 0 +// @r3 = global i32 0 +// @r4 = global i32 0 +// @r5 = global i32 0 +// @r6 = global i32 0 +// @r7 = global i32 0 +// @r8 = global i32 0 +// @r9 = global i32 0 +// @r10 = global i32 0 // declare void @print() // define void @fnc() { // %stack_-4 = alloca i32 // %stack_-8 = alloca i32 -// store i32 1, i32* @a2 -// store i32 1, i32* @a1 +// store i32 1, i32* @r3 +// store i32 1, i32* @r4 +// store i32 1, i32* @r5 // store i32 2, i32* %stack_-4 -// store i32 1, i32* @t0 -// store i32 1, i32* @a0 +// store i32 1, i32* @r6 +// store i32 1, i32* @r7 +// store i32 1, i32* @r8 // store i32 2, i32* %stack_-8 -// store i32 1, i32* @a3 +// store i32 1, i32* @r9 +// store i32 1, i32* @r10 // call void @print() // ret void // } @@ -1530,8 +2895,8 @@ class ParamReturnTests: public LlvmIrTests // auto config = Config::fromJsonString(module.get(), R"({ // "architecture" : { // "bitSize" : 32, -// "endian" : "little", -// "name" : "mips" +// "endian" : "big", +// "name" : "powerpc" // }, // "functions" : [ // { @@ -1550,66 +2915,1036 @@ class ParamReturnTests: public LlvmIrTests // ], // "registers" : [ // { -// "name" : "a0", -// "storage" : { "type" : "register", "value" : "a0", +// "name" : "r3", +// "storage" : { "type" : "register", "value" : "r3", +// "registerClass" : "gpregs", "registerNumber" : 3 } +// }, +// { +// "name" : "r4", +// "storage" : { "type" : "register", "value" : "r4", // "registerClass" : "gpregs", "registerNumber" : 4 } // }, // { -// "name" : "a1", -// "storage" : { "type" : "register", "value" : "a1", +// "name" : "r5", +// "storage" : { "type" : "register", "value" : "r5", // "registerClass" : "gpregs", "registerNumber" : 5 } // }, // { -// "name" : "a2", -// "storage" : { "type" : "register", "value" : "a2", +// "name" : "r6", +// "storage" : { "type" : "register", "value" : "r6", // "registerClass" : "gpregs", "registerNumber" : 6 } // }, // { -// "name" : "a3", -// "storage" : { "type" : "register", "value" : "a3", +// "name" : "r7", +// "storage" : { "type" : "register", "value" : "r7", // "registerClass" : "gpregs", "registerNumber" : 7 } // }, // { -// "name" : "t0", -// "storage" : { "type" : "register", "value" : "t0", +// "name" : "r8", +// "storage" : { "type" : "register", "value" : "r8", // "registerClass" : "gpregs", "registerNumber" : 8 } +// }, +// { +// "name" : "r9", +// "storage" : { "type" : "register", "value" : "r9", +// "registerClass" : "gpregs", "registerNumber" : 9 } +// }, +// { +// "name" : "r10", +// "storage" : { "type" : "register", "value" : "r10", +// "registerClass" : "gpregs", "registerNumber" : 10 } // } // ] // })"); // auto abi = AbiProvider::addAbi(module.get(), &config); // -// pass.runOnModuleCustom(*module, &config, abi); -// -// std::string exp = R"( -// @a0 = global i32 0 -// @a1 = global i32 0 -// @a2 = global i32 0 -// @a3 = global i32 0 -// @t0 = global i32 0 -// declare void @print(i32, i32, i32, i32, i32, i32) -// declare void @0() -// define void @fnc() { -// %stack_-4 = alloca i32 -// %stack_-8 = alloca i32 -// store i32 1, i32* @a2 -// store i32 1, i32* @a1 -// store i32 2, i32* %stack_-4 -// store i32 1, i32* @t0 -// store i32 1, i32* @a0 -// store i32 2, i32* %stack_-8 -// store i32 1, i32* @a3 -// %1 = load i32, i32* @a0 -// %2 = load i32, i32* @a1 -// %3 = load i32, i32* @a2 -// %4 = load i32, i32* @a3 -// %5 = load i32, i32* %stack_-8 -// %6 = load i32, i32* %stack_-4 -// call void @print(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6) -// ret void -// } -// )"; -// checkModuleAgainstExpectedIr(exp); -//} + +TEST_F(ParamReturnTests, mipsPtrCallBasicFunctionality) +{ + parseInput(R"( + @r = global i32 0 + @a0 = global i32 0 + @a1 = global i32 0 + define void @fnc() { + store i32 123, i32* @a0 + store i32 456, i32* @a1 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "mips" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi->addRegister(MIPS_REG_A1, getGlobalByName("a1")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + @a0 = global i32 0 + @a1 = global i32 0 + define void @fnc() { + store i32 123, i32* @a0 + store i32 456, i32* @a1 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* @a0 + %2 = load i32, i32* @a1 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, mipsExternalCallBasicFunctionality) +{ + parseInput(R"( + @a0 = global i32 0 + @a1 = global i32 0 + declare void @print() + define void @fnc() { + store i32 123, i32* @a0 + store i32 456, i32* @a1 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "mips" + } + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi->addRegister(MIPS_REG_A1, getGlobalByName("a1")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @a0 = global i32 0 + @a1 = global i32 0 + declare void @print(i32, i32) + declare void @0() + define void @fnc() { + store i32 123, i32* @a0 + store i32 456, i32* @a1 + %1 = load i32, i32* @a0 + %2 = load i32, i32* @a1 + call void @print(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, mipsExternalCallUseStacksIf4RegistersUsed) +{ + parseInput(R"( + @a0 = global i32 0 + @a1 = global i32 0 + @a2 = global i32 0 + @a3 = global i32 0 + @t0 = global i32 0 + declare void @print() + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @a2 + store i32 1, i32* @a1 + store i32 2, i32* %stack_-4 + store i32 1, i32* @t0 + store i32 1, i32* @a0 + store i32 2, i32* %stack_-8 + store i32 1, i32* @a3 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "mips" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + auto abi = AbiProvider::addAbi(module.get(), &config); + + abi->addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi->addRegister(MIPS_REG_A1, getGlobalByName("a1")); + abi->addRegister(MIPS_REG_A2, getGlobalByName("a2")); + abi->addRegister(MIPS_REG_A3, getGlobalByName("a3")); + abi->addRegister(MIPS_REG_T0, getGlobalByName("t0")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @a0 = global i32 0 + @a1 = global i32 0 + @a2 = global i32 0 + @a3 = global i32 0 + @t0 = global i32 0 + declare void @print(i32, i32, i32, i32, i32, i32) + declare void @0() + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @a2 + store i32 1, i32* @a1 + store i32 2, i32* %stack_-4 + store i32 1, i32* @t0 + store i32 1, i32* @a0 + store i32 2, i32* %stack_-8 + store i32 1, i32* @a3 + %1 = load i32, i32* @a0 + %2 = load i32, i32* @a1 + %3 = load i32, i32* @a2 + %4 = load i32, i32* @a3 + %5 = load i32, i32* %stack_-8 + %6 = load i32, i32* %stack_-4 + call void @print(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, mips64PtrCallBasicFunctionality) +{ + parseInput(R"( + target datalayout = "E-m:e-p:64:64-i64:64-f64:64" + + @r = global i64 0 + @a0 = global i64 0 + @a1 = global i64 0 + define void @fnc() { + store i64 123, i64* @a0 + store i64 456, i64* @a1 + %a = bitcast i64* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "mips64" + } + })"); + + AbiMips64 abi(module.get(), &config); + + abi.addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi.addRegister(MIPS_REG_A1, getGlobalByName("a1")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + target datalayout = "E-m:e-p:64:64-i64:64-f64:64" + + @r = global i64 0 + @a0 = global i64 0 + @a1 = global i64 0 + define void @fnc() { + store i64 123, i64* @a0 + store i64 456, i64* @a1 + %a = bitcast i64* @r to void()* + %1 = load i64, i64* @a0 + %2 = load i64, i64* @a1 + %3 = bitcast void ()* %a to void (i64, i64)* + call void %3(i64 %1, i64 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, mips64ExternalCallBasicFunctionality) +{ + parseInput(R"( + target datalayout = "E-m:e-p:64:64-i64:64-f64:64" + + @a0 = global i64 0 + @a1 = global i64 0 + declare void @print() + define void @fnc() { + store i64 123, i64* @a0 + store i64 456, i64* @a1 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "mips64" + } + })"); + + AbiMips64 abi(module.get(), &config); + + abi.addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi.addRegister(MIPS_REG_A1, getGlobalByName("a1")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + target datalayout = "E-m:e-p:64:64-i64:64-f64:64" + + @a0 = global i64 0 + @a1 = global i64 0 + declare void @print(i64, i64) + declare void @0() + define void @fnc() { + store i64 123, i64* @a0 + store i64 456, i64* @a1 + %1 = load i64, i64* @a0 + %2 = load i64, i64* @a1 + call void @print(i64 %1, i64 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, mips64ExternalCallUseStacksIf8RegistersUsed) +{ + parseInput(R"( + target datalayout = "E-m:e-p:64:64-i64:64-f64:64" + + @a0 = global i64 0 + @a1 = global i64 0 + @a2 = global i64 0 + @a3 = global i64 0 + @a4 = global i64 0 + @a5 = global i64 0 + @a6 = global i64 0 + @a7 = global i64 0 + @t4 = global i64 0 + declare void @print() + define void @fnc() { + %stack_-4 = alloca i64 + %stack_-12 = alloca i64 + store i64 1, i64* @a2 + store i64 1, i64* @a1 + store i64 1, i64* @a7 + store i64 1, i64* @a4 + store i64 2, i64* %stack_-4 + store i64 1, i64* @t4 + store i64 1, i64* @a0 + store i64 2, i64* %stack_-12 + store i64 1, i64* @a6 + store i64 1, i64* @a5 + store i64 1, i64* @a3 + call void @print() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 64, + "endian" : "little", + "name" : "mips64" + }, + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-12", + "storage" : { "type" : "stack", "value" : -12 } + } + ] + } + ] + })"); + + AbiMips64 abi(module.get(), &config); + + abi.addRegister(MIPS_REG_A0, getGlobalByName("a0")); + abi.addRegister(MIPS_REG_A1, getGlobalByName("a1")); + abi.addRegister(MIPS_REG_A2, getGlobalByName("a2")); + abi.addRegister(MIPS_REG_A3, getGlobalByName("a3")); + abi.addRegister(MIPS_REG_T0, getGlobalByName("a4")); + abi.addRegister(MIPS_REG_T1, getGlobalByName("a5")); + abi.addRegister(MIPS_REG_T2, getGlobalByName("a6")); + abi.addRegister(MIPS_REG_T3, getGlobalByName("a7")); + abi.addRegister(MIPS_REG_T4, getGlobalByName("t4")); + + pass.runOnModuleCustom(*module, &config, &abi); + + std::string exp = R"( + target datalayout = "E-m:e-p:64:64-i64:64-f64:64" + + @a0 = global i64 0 + @a1 = global i64 0 + @a2 = global i64 0 + @a3 = global i64 0 + @a4 = global i64 0 + @a5 = global i64 0 + @a6 = global i64 0 + @a7 = global i64 0 + @t4 = global i64 0 + + declare void @print(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64) + declare void @0() + + define void @fnc() { + %stack_-4 = alloca i64 + %stack_-12 = alloca i64 + store i64 1, i64* @a2 + store i64 1, i64* @a1 + store i64 1, i64* @a7 + store i64 1, i64* @a4 + store i64 2, i64* %stack_-4 + store i64 1, i64* @t4 + store i64 1, i64* @a0 + store i64 2, i64* %stack_-12 + store i64 1, i64* @a6 + store i64 1, i64* @a5 + store i64 1, i64* @a3 + + %1 = load i64, i64* @a0 + %2 = load i64, i64* @a1 + %3 = load i64, i64* @a2 + %4 = load i64, i64* @a3 + %5 = load i64, i64* @a4 + %6 = load i64, i64* @a5 + %7 = load i64, i64* @a6 + %8 = load i64, i64* @a7 + %9 = load i64, i64* %stack_-12 + %10 = load i64, i64* %stack_-4 + call void @print(i64 %1, i64 %2, i64 %3, i64 %4, i64 %5, i64 %6, i64 %7, i64 %8, i64 %9, i64 %10) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86FastcallBasic) +{ + parseInput(R"( + @eax = global i32 0 + @edx = global i32 0 + @ecx = global i32 0 + @r = global i32 0 + declare void @a() + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @ecx + store i32 1, i32* @edx + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + call void @a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "tools" : + [ + { "name" : "gcc" } + ], + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + }, + { + "name" : "a", + "callingConvention" : "fastcall" + } + ] + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + abi->addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi->addRegister(X86_REG_ECX, getGlobalByName("ecx")); + abi->addRegister(X86_REG_EDX, getGlobalByName("edx")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @eax = global i32 0 + @edx = global i32 0 + @ecx = global i32 0 + @r = global i32 0 + + declare i32 @a(i32, i32, i32, i32) + + declare void @0() + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @ecx + store i32 1, i32* @edx + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %1 = load i32, i32* @ecx + %2 = load i32, i32* @edx + %3 = load i32, i32* %stack_-8 + %4 = load i32, i32* %stack_-4 + %5 = call i32 @a(i32 %1, i32 %2, i32 %3, i32 %4) + store i32 %5, i32* @eax + %6 = load i32, i32* @eax + ret i32 %6 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + + +TEST_F(ParamReturnTests, x86FastcallLargeTypeCatch) +{ + parseInput(R"( + @r = global i32 0 + @ecx = global i32 0 + @edx = global i32 0 + @eax = global i32 0 + declare void @a() + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* @ecx + store i32 456, i32* %stack_-4 + store i32 789, i32* %stack_-8 + call void @a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "tools" : + [ + { "name" : "gcc" } + ], + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ], + "calingConvention" : "fastcall" + }, + { + "name" : "a", + "callingConvention" : "fastcall" + } + ] + + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + abi->addRegister(X86_REG_ECX, getGlobalByName("ecx")); + abi->addRegister(X86_REG_EAX, getGlobalByName("eax")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + @ecx = global i32 0 + @edx = global i32 0 + @eax = global i32 0 + + declare i32 @a(i32, i32, i32) + + declare void @0() + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* @ecx + store i32 456, i32* %stack_-4 + store i32 789, i32* %stack_-8 + %1 = load i32, i32* @ecx + %2 = load i32, i32* %stack_-8 + %3 = load i32, i32* %stack_-4 + %4 = call i32 @a(i32 %1, i32 %2, i32 %3) + store i32 %4, i32* @eax + %5 = load i32, i32* @eax + ret i32 %5 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PascalBasic) +{ + parseInput(R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "tools" : + [ + { "name" : "borland" } + ], + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* %stack_-4 + %2 = load i32, i32* %stack_-8 + %3 = bitcast void ()* %a to void (i32, i32)* + call void %3(i32 %1, i32 %2) + ret void + } + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PascalFastcallBasic) +{ + parseInput(R"( + @eax = global i32 0 + @edx = global i32 0 + @ecx = global i32 0 + @r = global i32 0 + + declare void @a() + + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 1, i32* @ecx + store i32 1, i32* @edx + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + call void @a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "tools" : + [ + { "name" : "borland" } + ], + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ], + "callingConvention" : "fastcall" + }, + { + "name" : "a", + "callingConvention" : "fastcall" + } + ] + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + abi->addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi->addRegister(X86_REG_EDX, getGlobalByName("edx")); + abi->addRegister(X86_REG_ECX, getGlobalByName("ecx")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @eax = global i32 0 + @edx = global i32 0 + @ecx = global i32 0 + @r = global i32 0 + + declare i32 @a(i32, i32, i32, i32, i32) + + declare void @0() + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 1, i32* @ecx + store i32 1, i32* @edx + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %1 = load i32, i32* @eax + %2 = load i32, i32* @edx + %3 = load i32, i32* @ecx + %4 = load i32, i32* %stack_-4 + %5 = load i32, i32* %stack_-8 + %6 = call i32 @a(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5) + store i32 %6, i32* @eax + %7 = load i32, i32* @eax + ret i32 %7 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86PascalFastcallLargeType) +{ + parseInput(R"( + @eax = global i32 0 + @edx = global i32 0 + @r = global i32 0 + + declare void @a() + + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 456, i32* %stack_-8 + store i32 123, i32* %stack_-4 + store i32 1, i32* @edx + call void @a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "tools" : + [ + { "name" : "borland" } + ], + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ], + "callingConvention" : "fastcall" + }, + { + "name" : "a", + "callingConvention" : "fastcall" + } + ] + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + abi->addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi->addRegister(X86_REG_EDX, getGlobalByName("edx")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @eax = global i32 0 + @edx = global i32 0 + @r = global i32 0 + + declare i32 @a(i32, i32, i32, i32) + + declare void @0() + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 456, i32* %stack_-8 + store i32 123, i32* %stack_-4 + store i32 1, i32* @edx + %1 = load i32, i32* @eax + %2 = load i32, i32* @edx + %3 = load i32, i32* %stack_-4 + %4 = load i32, i32* %stack_-8 + %5 = call i32 @a(i32 %1, i32 %2, i32 %3, i32 %4) + store i32 %5, i32* @eax + %6 = load i32, i32* @eax + ret i32 %6 + } + + declare void @1() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86WatcomBasic) +{ + parseInput(R"( + @eax = global i32 0 + @ebx = global i32 0 + @edx = global i32 0 + @ecx = global i32 0 + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 1, i32* @ebx + store i32 1, i32* @ecx + store i32 1, i32* @edx + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "tools" : + [ + { "name" : "open_watcom" } + ], + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + abi->addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi->addRegister(X86_REG_EBX, getGlobalByName("ebx")); + abi->addRegister(X86_REG_ECX, getGlobalByName("ecx")); + abi->addRegister(X86_REG_EDX, getGlobalByName("edx")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @eax = global i32 0 + @ebx = global i32 0 + @edx = global i32 0 + @ecx = global i32 0 + @r = global i32 0 + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 1, i32* @ebx + store i32 1, i32* @ecx + store i32 1, i32* @edx + store i32 123, i32* %stack_-4 + store i32 456, i32* %stack_-8 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* @eax + %2 = load i32, i32* @edx + %3 = load i32, i32* @ebx + %4 = load i32, i32* @ecx + %5 = load i32, i32* %stack_-8 + %6 = load i32, i32* %stack_-4 + %7 = bitcast void ()* %a to void (i32, i32, i32, i32, i32, i32)* + call void %7(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6) + %8 = load i32, i32* @eax + ret i32 %8 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} + +TEST_F(ParamReturnTests, x86WatcomPassDouble) +{ + parseInput(R"( + @eax = global i32 0 + @edx = global i32 0 + @r = global i32 0 + define void @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 1, i32* @edx + store i32 456, i32* %stack_-8 + store i32 123, i32* %stack_-4 + %a = bitcast i32* @r to void()* + call void %a() + ret void + } + )"); + auto config = Config::fromJsonString(module.get(), R"({ + "architecture" : { + "bitSize" : 32, + "endian" : "little", + "name" : "x86" + }, + "tools" : + [ + { "name" : "open_watcom" } + ], + "functions" : [ + { + "name" : "fnc", + "locals" : [ + { + "name" : "stack_-4", + "storage" : { "type" : "stack", "value" : -4 } + }, + { + "name" : "stack_-8", + "storage" : { "type" : "stack", "value" : -8 } + } + ] + } + ] + })"); + + auto abi = AbiProvider::addAbi(module.get(), &config); + abi->addRegister(X86_REG_EAX, getGlobalByName("eax")); + abi->addRegister(X86_REG_EDX, getGlobalByName("edx")); + + pass.runOnModuleCustom(*module, &config, abi); + + std::string exp = R"( + @eax = global i32 0 + @edx = global i32 0 + @r = global i32 0 + + define i32 @fnc() { + %stack_-4 = alloca i32 + %stack_-8 = alloca i32 + store i32 1, i32* @eax + store i32 1, i32* @edx + store i32 456, i32* %stack_-8 + store i32 123, i32* %stack_-4 + %a = bitcast i32* @r to void()* + %1 = load i32, i32* @eax + %2 = load i32, i32* @edx + %3 = load i32, i32* %stack_-8 + %4 = load i32, i32* %stack_-4 + %5 = bitcast void ()* %a to void (i32, i32, i32, i32)* + call void %5(i32 %1, i32 %2, i32 %3, i32 %4) + %6 = load i32, i32* @eax + ret i32 %6 + } + + declare void @0() + )"; + checkModuleAgainstExpectedIr(exp); +} } // namespace tests } // namespace bin2llvmir diff --git a/tests/bin2llvmir/utils/llvmir_tests.h b/tests/bin2llvmir/utils/llvmir_tests.h index 9f58965bf..00fce3a33 100644 --- a/tests/bin2llvmir/utils/llvmir_tests.h +++ b/tests/bin2llvmir/utils/llvmir_tests.h @@ -53,6 +53,7 @@ class LlvmIrTests : public ::testing::Test */ void clearAllStaticData() { + AbiProvider::clear(); ConfigProvider::clear(); DebugFormatProvider::clear(); DemanglerProvider::clear(); diff --git a/tests/capstone2llvmir/arm_tests.cpp b/tests/capstone2llvmir/arm_tests.cpp index d7676177a..8ab432776 100644 --- a/tests/capstone2llvmir/arm_tests.cpp +++ b/tests/capstone2llvmir/arm_tests.cpp @@ -2908,8 +2908,54 @@ TEST_P(Capstone2LlvmIrTranslatorArmTests, ARM_INS_STRD) EXPECT_NO_REGISTERS_STORED(); EXPECT_NO_MEMORY_LOADED(); EXPECT_JUST_MEMORY_STORED({ -// {0x1000, 0x1234567890abcdef_qw} - {0x1000, 0x12345678_dw} + {0x1000, 0x12345678_dw}, + {0x1004, 0x90abcdef_dw} + }); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArmTests, ARM_INS_STRD_sp_imm) +{ + ALL_MODES; + + setRegisters({ + {ARM_REG_R0, 0x12345678}, + {ARM_REG_R1, 0x90abcdef}, + {ARM_REG_SP, 0x1000}, + }); + + emulate("strd r0, r1, [sp, #0x18]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM_REG_R0, ARM_REG_R1, ARM_REG_SP}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1018, 0x12345678_dw}, + {0x101c, 0x90abcdef_dw} + }); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArmTests, ARM_INS_STRD_sp_post_imm) +{ + ALL_MODES; + + setRegisters({ + {ARM_REG_R0, 0x12345678}, + {ARM_REG_R1, 0x90abcdef}, + {ARM_REG_SP, 0x1000}, + }); + + emulate("strd r0, r1, [sp], #0x18"); + + EXPECT_JUST_REGISTERS_LOADED({ARM_REG_R0, ARM_REG_R1, ARM_REG_SP}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM_REG_SP, ANY}, // Not an exact value because some strange behaviour. + }); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1000, 0x12345678_dw}, + {0x1004, 0x90abcdef_dw} }); EXPECT_NO_VALUE_CALLED(); } diff --git a/tests/config/architecture_tests.cpp b/tests/config/architecture_tests.cpp index e2a2b9f2a..3a2e3a898 100644 --- a/tests/config/architecture_tests.cpp +++ b/tests/config/architecture_tests.cpp @@ -37,6 +37,11 @@ TEST_F(ArchitectureTests, CheckIfArchMethodsWork) EXPECT_TRUE( arch.isKnown() ); EXPECT_EQ( "arm", arch.getName() ); + arch.setIsArm64(); + EXPECT_TRUE( arch.isArm64() ); + EXPECT_TRUE( arch.isKnown() ); + EXPECT_EQ( "aarch64", arch.getName() ); + arch.setIsThumb(); EXPECT_TRUE( arch.isThumb() ); EXPECT_TRUE( arch.isArmOrThumb() ); diff --git a/tests/fileformat/macho_format_tests.cpp b/tests/fileformat/macho_format_tests.cpp index b65f42ff2..36b2f76b5 100644 --- a/tests/fileformat/macho_format_tests.cpp +++ b/tests/fileformat/macho_format_tests.cpp @@ -20,352 +20,352 @@ namespace tests { const std::vector machoBytes = { - 0xcf, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x80, - 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, - 0x85, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0x48, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x50, 0x41, 0x47, 0x45, 0x5a, 0x45, - 0x52, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, - 0xe8, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65, - 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x75, 0x6e, 0x77, 0x69, 0x6e, 0x64, - 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, - 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb0, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xb0, 0x0f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x19, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x4c, 0x49, - 0x4e, 0x4b, 0x45, 0x44, 0x49, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x18, 0x10, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x0b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, - 0x20, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2f, 0x75, 0x73, 0x72, - 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x64, 0x79, 0x6c, 0x64, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0xb7, 0x53, 0x05, 0xf8, 0x2f, 0x5e, 0x3c, 0x7f, 0xa0, 0x03, 0x60, 0x16, - 0x6a, 0x45, 0xf9, 0xf7, 0x24, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x0d, 0x0a, 0x00, 0x00, 0x0d, 0x0a, 0x00, 0x2a, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x00, 0x00, 0x80, 0x18, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x0c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x04, 0x32, 0xe4, 0x04, 0x00, 0x00, 0x01, 0x00, - 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x69, 0x62, - 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x42, 0x2e, 0x64, 0x79, 0x6c, - 0x69, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x29, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x55, 0x48, 0x89, 0xe5, 0x31, 0xc0, 0xc7, 0x45, - 0xfc, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xc3, 0x90, 0x01, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0xa0, 0x0f, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0xb0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x79, 0x6c, 0x64, - 0x5f, 0x73, 0x74, 0x75, 0x62, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x65, 0x72, - 0x00, 0x00, 0x00, 0x00 + 0xcf, 0xfa, 0xed, 0xfe, 0x07, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x80, + 0x02, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xd8, 0x02, 0x00, 0x00, + 0x85, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x50, 0x41, 0x47, 0x45, 0x5a, 0x45, + 0x52, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, + 0xe8, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x74, 0x65, + 0x78, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x5f, 0x54, 0x45, 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x75, 0x6e, 0x77, 0x69, 0x6e, 0x64, + 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x54, 0x45, + 0x58, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb0, 0x0f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb0, 0x0f, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x19, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x5f, 0x5f, 0x4c, 0x49, + 0x4e, 0x4b, 0x45, 0x44, 0x49, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x00, 0x80, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x18, 0x10, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x2f, 0x75, 0x73, 0x72, + 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x64, 0x79, 0x6c, 0x64, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0xb7, 0x53, 0x05, 0xf8, 0x2f, 0x5e, 0x3c, 0x7f, 0xa0, 0x03, 0x60, 0x16, + 0x6a, 0x45, 0xf9, 0xf7, 0x24, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x0d, 0x0a, 0x00, 0x00, 0x0d, 0x0a, 0x00, 0x2a, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x80, 0x18, 0x00, 0x00, 0x00, 0xa0, 0x0f, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x32, 0xe4, 0x04, 0x00, 0x00, 0x01, 0x00, + 0x2f, 0x75, 0x73, 0x72, 0x2f, 0x6c, 0x69, 0x62, 0x2f, 0x6c, 0x69, 0x62, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x42, 0x2e, 0x64, 0x79, 0x6c, + 0x69, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x29, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x55, 0x48, 0x89, 0xe5, 0x31, 0xc0, 0xc7, 0x45, + 0xfc, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xc3, 0x90, 0x01, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0xa0, 0x0f, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0xb0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x10, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x79, 0x6c, 0x64, + 0x5f, 0x73, 0x74, 0x75, 0x62, 0x5f, 0x62, 0x69, 0x6e, 0x64, 0x65, 0x72, + 0x00, 0x00, 0x00, 0x00 }; /** diff --git a/tests/unpacker/dynamic_buffer_tests.cpp b/tests/unpacker/dynamic_buffer_tests.cpp index da57cbc42..1e4bebeae 100644 --- a/tests/unpacker/dynamic_buffer_tests.cpp +++ b/tests/unpacker/dynamic_buffer_tests.cpp @@ -9,7 +9,7 @@ #include #include "retdec/fileformat/fftypes.h" -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" using namespace ::testing; using namespace retdec::utils; diff --git a/tests/unpacker/signature_tests.cpp b/tests/unpacker/signature_tests.cpp index 0a2b7e64e..5d538635b 100644 --- a/tests/unpacker/signature_tests.cpp +++ b/tests/unpacker/signature_tests.cpp @@ -6,10 +6,11 @@ #include -#include "retdec/unpacker/dynamic_buffer.h" +#include "retdec/utils/dynamic_buffer.h" #include "retdec/unpacker/signature.h" using namespace ::testing; +using namespace retdec::utils; namespace retdec { namespace unpacker { From e9b2866580ee82df48df70f90a6a0ea4066fcb5f Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 7 Mar 2019 15:32:31 +0100 Subject: [PATCH 096/107] Architecture: Change arm architectures to account for arm64 -> isArmOrThumb renamed to isArm32OrThumb -> added isArm32 method -> thumb is now set with a flag _thumbFlag --- include/retdec/config/architecture.h | 5 +- .../optimizations/decoder/decoder.cpp | 8 +-- .../optimizations/decoder/decoder_init.cpp | 4 +- .../decoder/ir_modifications.cpp | 2 +- .../optimizations/decoder/jump_targets.cpp | 8 +-- .../idioms_libgcc/idioms_libgcc.cpp | 2 +- .../main_detection/main_detection.cpp | 2 +- .../optimizations/syscalls/syscalls.cpp | 2 +- src/bin2llvmir/providers/abi/abi.cpp | 4 +- src/bin2llvmir/providers/fileimage.cpp | 2 +- src/bin2llvmir/providers/lti.cpp | 2 +- src/bin2llvmir/providers/names.cpp | 4 +- src/bin2llvmir/utils/capstone.cpp | 2 +- src/bin2llvmir/utils/ir_modifier.cpp | 2 +- src/capstone2llvmir/arm64/arm64.cpp | 2 +- src/config/architecture.cpp | 60 +++++++++---------- src/fileinfo/file_detector/file_detector.cpp | 2 +- src/stacofin/stacofin.cpp | 6 +- tests/config/architecture_tests.cpp | 29 ++++++--- 19 files changed, 83 insertions(+), 65 deletions(-) diff --git a/include/retdec/config/architecture.h b/include/retdec/config/architecture.h index f3ed217d2..01eeb00d1 100644 --- a/include/retdec/config/architecture.h +++ b/include/retdec/config/architecture.h @@ -29,9 +29,10 @@ class Architecture bool isPic32() const; bool isMipsOrPic32() const; bool isArm() const; + bool isArm32() const; bool isArm64() const; bool isThumb() const; - bool isArmOrThumb() const; + bool isArm32OrThumb() const; bool isX86() const; bool isX86_16() const; bool isX86_32() const; @@ -51,6 +52,7 @@ class Architecture void setIsPic32(); void setIsArm(); void setIsThumb(); + void setIsArm32(); void setIsArm64(); void setIsX86(); void setIsPpc(); @@ -99,6 +101,7 @@ class Architecture private: std::string _name; unsigned _bitSize = 32; + bool _thumbFlag = false; eEndian _endian = E_UNKNOWN; eArch _arch = eArch::UNKNOWN; }; diff --git a/src/bin2llvmir/optimizations/decoder/decoder.cpp b/src/bin2llvmir/optimizations/decoder/decoder.cpp index c70f1a9e4..8871b7ed2 100644 --- a/src/bin2llvmir/optimizations/decoder/decoder.cpp +++ b/src/bin2llvmir/optimizations/decoder/decoder.cpp @@ -380,7 +380,7 @@ std::size_t Decoder::decodeJumpTargetDryRun( { return decodeJumpTargetDryRun_x86(jt, bytes, strict); } - else if (_config->getConfig().architecture.isArmOrThumb()) + else if (_config->getConfig().architecture.isArm32OrThumb()) { return decodeJumpTargetDryRun_arm(jt, bytes, strict); } @@ -408,7 +408,7 @@ std::size_t Decoder::decodeJumpTargetDryRun( cs_mode Decoder::determineMode(cs_insn* insn, utils::Address& target) { - if (_config->getConfig().architecture.isArmOrThumb()) + if (_config->getConfig().architecture.isArm32OrThumb()) { return determineMode_arm(insn, target); } @@ -480,7 +480,7 @@ bool Decoder::getJumpTargetsFromInstruction( CallInst*& pCall = tr.branchCall; auto nextAddr = addr + tr.size; - if (_config->getConfig().architecture.isArmOrThumb()) + if (_config->getConfig().architecture.isArm32OrThumb()) { AsmInstruction ai(tr.llvmInsn); patternsPseudoCall_arm(pCall, ai); @@ -1562,7 +1562,7 @@ void Decoder::finalizePseudoCalls() // TODO: what about other possible LR stores? e.g. see // patternsPseudoCall_arm(). // - if (_config->getConfig().architecture.isArmOrThumb() + if (_config->getConfig().architecture.isArm32OrThumb() && icf) if (auto* st = dyn_cast(i)) { diff --git a/src/bin2llvmir/optimizations/decoder/decoder_init.cpp b/src/bin2llvmir/optimizations/decoder/decoder_init.cpp index 409e3a3db..c1c714233 100644 --- a/src/bin2llvmir/optimizations/decoder/decoder_init.cpp +++ b/src/bin2llvmir/optimizations/decoder/decoder_init.cpp @@ -61,7 +61,7 @@ void Decoder::initTranslator() case 32: basicMode = CS_MODE_32; break; } } - else if (a.isArmOrThumb() + else if (a.isArm32OrThumb() && a.getBitSize() == 32) { arch = CS_ARCH_ARM; @@ -193,7 +193,7 @@ void Decoder::initRanges() auto& arch = _config->getConfig().architecture; unsigned a = 0; - a = arch.isArmOrThumb() ? 2 : a; + a = arch.isArm32OrThumb() ? 2 : a; a = arch.isArm64() ? 4 : a; a = arch.isMipsOrPic32() ? 4 : a; a = arch.isPpc() ? 4 : a; diff --git a/src/bin2llvmir/optimizations/decoder/ir_modifications.cpp b/src/bin2llvmir/optimizations/decoder/ir_modifications.cpp index 3c7326982..40118c3e5 100644 --- a/src/bin2llvmir/optimizations/decoder/ir_modifications.cpp +++ b/src/bin2llvmir/optimizations/decoder/ir_modifications.cpp @@ -165,7 +165,7 @@ llvm::GlobalVariable* Decoder::getCallReturnObject() { return _abi->getRegister(PPC_REG_R3); } - else if (_config->getConfig().architecture.isArmOrThumb()) + else if (_config->getConfig().architecture.isArm32OrThumb()) { return _abi->getRegister(ARM_REG_R0); } diff --git a/src/bin2llvmir/optimizations/decoder/jump_targets.cpp b/src/bin2llvmir/optimizations/decoder/jump_targets.cpp index 9394b1a3d..8aa29284d 100644 --- a/src/bin2llvmir/optimizations/decoder/jump_targets.cpp +++ b/src/bin2llvmir/optimizations/decoder/jump_targets.cpp @@ -38,7 +38,7 @@ JumpTarget::JumpTarget( _fromAddress(f), _mode(m) { - if (config->getConfig().architecture.isArmOrThumb() && _address % 2) + if (config->getConfig().architecture.isArm32OrThumb() && _address % 2) { _mode = CS_MODE_THUMB; _address -= 1; @@ -191,14 +191,14 @@ const JumpTarget* JumpTargets::push( if (a.isDefined()) { - if (arch.isArmOrThumb() && a % 2) + if (arch.isArm32OrThumb() && a % 2) { m = CS_MODE_THUMB; a -= 1; } - if ((arch.isArmOrThumb() && m == CS_MODE_ARM && a % 4) - || (arch.isArmOrThumb() && m == CS_MODE_THUMB && a % 2) + if ((arch.isArm32OrThumb() && m == CS_MODE_ARM && a % 4) + || (arch.isArm32OrThumb() && m == CS_MODE_THUMB && a % 2) || (arch.isArm64() && a % 4) || (arch.isMipsOrPic32() && a % 4) || (arch.isPpc() && a % 4)) diff --git a/src/bin2llvmir/optimizations/idioms_libgcc/idioms_libgcc.cpp b/src/bin2llvmir/optimizations/idioms_libgcc/idioms_libgcc.cpp index 66364e12f..14e5b6978 100644 --- a/src/bin2llvmir/optimizations/idioms_libgcc/idioms_libgcc.cpp +++ b/src/bin2llvmir/optimizations/idioms_libgcc/idioms_libgcc.cpp @@ -211,7 +211,7 @@ bool IdiomsLibgccImpl::testArchAndInitialize( config::Architecture& arch, Abi* abi) { - if (arch.isArmOrThumb()) + if (arch.isArm32OrThumb()) { op0Single = abi->getRegister(ARM_REG_R0); op0Double = abi->getRegister(ARM_REG_R0); // + r1 diff --git a/src/bin2llvmir/optimizations/main_detection/main_detection.cpp b/src/bin2llvmir/optimizations/main_detection/main_detection.cpp index 29c5c54eb..4010abfae 100644 --- a/src/bin2llvmir/optimizations/main_detection/main_detection.cpp +++ b/src/bin2llvmir/optimizations/main_detection/main_detection.cpp @@ -369,7 +369,7 @@ retdec::utils::Address MainDetection::getFromContext() } } } - else if (_config->getConfig().architecture.isArmOrThumb()) + else if (_config->getConfig().architecture.isArm32OrThumb()) { if (ci.isGcc() && major == 4 && minor == 1) { diff --git a/src/bin2llvmir/optimizations/syscalls/syscalls.cpp b/src/bin2llvmir/optimizations/syscalls/syscalls.cpp index da804afc0..69e9a00ce 100644 --- a/src/bin2llvmir/optimizations/syscalls/syscalls.cpp +++ b/src/bin2llvmir/optimizations/syscalls/syscalls.cpp @@ -64,7 +64,7 @@ bool SyscallFixer::run() { return runMips(); } - else if (_config->getConfig().architecture.isArmOrThumb()) + else if (_config->getConfig().architecture.isArm32OrThumb()) { return runArm(); } diff --git a/src/bin2llvmir/providers/abi/abi.cpp b/src/bin2llvmir/providers/abi/abi.cpp index 360f589fa..ed3c4e1dd 100644 --- a/src/bin2llvmir/providers/abi/abi.cpp +++ b/src/bin2llvmir/providers/abi/abi.cpp @@ -231,7 +231,7 @@ bool Abi::isMips64() const bool Abi::isArm() const { - return _config->getConfig().architecture.isArmOrThumb(); + return _config->getConfig().architecture.isArm32OrThumb(); } bool Abi::isArm64() const @@ -303,7 +303,7 @@ Abi* AbiProvider::addAbi( return nullptr; } - if (c->getConfig().architecture.isArmOrThumb()) + if (c->getConfig().architecture.isArm32OrThumb()) { auto p = _module2abi.emplace(m, std::make_unique(m, c)); return p.first->second.get(); diff --git a/src/bin2llvmir/providers/fileimage.cpp b/src/bin2llvmir/providers/fileimage.cpp index 77233580b..7d404e62d 100644 --- a/src/bin2llvmir/providers/fileimage.cpp +++ b/src/bin2llvmir/providers/fileimage.cpp @@ -73,7 +73,7 @@ FileImage::FileImage( auto arch = retdec::fileformat::Architecture::UNKNOWN; if (ca.isX86()) arch = retdec::fileformat::Architecture::X86; if (ca.isX86_64()) arch = retdec::fileformat::Architecture::X86_64; - if (ca.isArmOrThumb()) arch = retdec::fileformat::Architecture::ARM; + if (ca.isArm32OrThumb()) arch = retdec::fileformat::Architecture::ARM; if (ca.isPpc()) arch = retdec::fileformat::Architecture::POWERPC; if (ca.isMipsOrPic32()) arch = retdec::fileformat::Architecture::MIPS; diff --git a/src/bin2llvmir/providers/lti.cpp b/src/bin2llvmir/providers/lti.cpp index 7284d999a..c58e646fa 100644 --- a/src/bin2llvmir/providers/lti.cpp +++ b/src/bin2llvmir/providers/lti.cpp @@ -277,7 +277,7 @@ Lti::Lti( loadLtiFile(l); } else if (retdec::utils::startsWith(fileName, "arm") && - _config->getConfig().architecture.isArmOrThumb()) + _config->getConfig().architecture.isArm32OrThumb()) { loadLtiFile(l); } diff --git a/src/bin2llvmir/providers/names.cpp b/src/bin2llvmir/providers/names.cpp index d15dd3971..3814d747b 100644 --- a/src/bin2llvmir/providers/names.cpp +++ b/src/bin2llvmir/providers/names.cpp @@ -441,7 +441,7 @@ void NameContainer::initFromImage() break; } - if (_config->getConfig().architecture.isArmOrThumb() && a % 2) + if (_config->getConfig().architecture.isArm32OrThumb() && a % 2) { a -= 1; } @@ -455,7 +455,7 @@ void NameContainer::initFromImage() unsigned long long ep = 0; if (_image->getFileFormat()->getEpAddress(ep)) { - if (_config->getConfig().architecture.isArmOrThumb() && ep % 2) + if (_config->getConfig().architecture.isArm32OrThumb() && ep % 2) { ep -= 1; } diff --git a/src/bin2llvmir/utils/capstone.cpp b/src/bin2llvmir/utils/capstone.cpp index 5d44a2e27..fd781abac 100644 --- a/src/bin2llvmir/utils/capstone.cpp +++ b/src/bin2llvmir/utils/capstone.cpp @@ -38,7 +38,7 @@ std::string mode2string(const config::Architecture& arch, cs_mode m) ret += m & CS_MODE_V8 ? ", CS_MODE_V8" : ", CS_MODE_ARM"; ret += m & CS_MODE_MCLASS ? ", CS_MODE_MCLASS" : ""; } - else if (arch.isArmOrThumb()) + else if (arch.isArm32OrThumb()) { ret += m & CS_MODE_THUMB ? ", CS_MODE_THUMB" : ", CS_MODE_ARM"; ret += m & CS_MODE_MCLASS ? ", CS_MODE_MCLASS" : ""; diff --git a/src/bin2llvmir/utils/ir_modifier.cpp b/src/bin2llvmir/utils/ir_modifier.cpp index 9b75d4590..2ff192e25 100644 --- a/src/bin2llvmir/utils/ir_modifier.cpp +++ b/src/bin2llvmir/utils/ir_modifier.cpp @@ -463,7 +463,7 @@ bool globalVariableCanBeCreated( } // ARM has data after functions, Pic32 does not bother to mark data (e.g. rodata) as data. - if ((config->getConfig().architecture.isArmOrThumb() + if ((config->getConfig().architecture.isArm32OrThumb() || config->getConfig().architecture.isPic32()) && !strict) { diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 17f4f8d48..1af5e1a35 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -306,7 +306,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( cs_detail* d = i->detail; cs_arm64* ai = &d->arm64; - //std::cout << i->mnemonic << " " << i->op_str << std::endl; + std::cout << i->mnemonic << " " << i->op_str << std::endl; auto fIt = _i2fm.find(i->id); if (fIt != _i2fm.end() && fIt->second != nullptr) diff --git a/src/config/architecture.cpp b/src/config/architecture.cpp index 904690bfb..5f89799bf 100644 --- a/src/config/architecture.cpp +++ b/src/config/architecture.cpp @@ -34,22 +34,23 @@ const std::string JSON_val_big = "big"; namespace retdec { namespace config { -bool Architecture::isArmOrThumb() const { return isArm() || isThumb(); } -bool Architecture::isPic32() const { return isArch(eArch::PIC32); } -bool Architecture::isArm() const { return isArch(eArch::ARM); } -bool Architecture::isArm64() const { return isArch(eArch::ARM64); } -bool Architecture::isThumb() const { return isArch(eArch::THUMB); } -bool Architecture::isX86() const { return isArch(eArch::X86); } -bool Architecture::isX86_16() const { return isX86() && getBitSize() == 16; } -bool Architecture::isX86_32() const { return isX86() && getBitSize() == 32; } -bool Architecture::isX86_64() const { return isX86() && getBitSize() == 64; } -bool Architecture::isPpc() const { return isArch(eArch::PPC); } -bool Architecture::isPpc64() const { return isPpc() && getBitSize() == 64; } -bool Architecture::isKnown() const { return !isUnknown(); } -bool Architecture::isUnknown() const { return isArch(eArch::UNKNOWN); } -bool Architecture::isMips() const { return isArch(eArch::MIPS); } -bool Architecture::isMips64() const { return isMips() && getBitSize() == 64; } -bool Architecture::isMipsOrPic32() const{ return isMips() || isPic32(); } +bool Architecture::isArm32OrThumb() const { return isArm32() || isThumb(); } +bool Architecture::isPic32() const { return isArch(eArch::PIC32); } +bool Architecture::isArm() const { return isArch(eArch::ARM); } +bool Architecture::isArm32() const { return isArm() && getBitSize() == 32 && !_thumbFlag; } +bool Architecture::isArm64() const { return isArm() && getBitSize() == 64; } +bool Architecture::isThumb() const { return isArm() && _thumbFlag; } +bool Architecture::isX86() const { return isArch(eArch::X86); } +bool Architecture::isX86_16() const { return isX86() && getBitSize() == 16; } +bool Architecture::isX86_32() const { return isX86() && getBitSize() == 32; } +bool Architecture::isX86_64() const { return isX86() && getBitSize() == 64; } +bool Architecture::isPpc() const { return isArch(eArch::PPC); } +bool Architecture::isPpc64() const { return isPpc() && getBitSize() == 64; } +bool Architecture::isKnown() const { return !isUnknown(); } +bool Architecture::isUnknown() const { return isArch(eArch::UNKNOWN); } +bool Architecture::isMips() const { return isArch(eArch::MIPS); } +bool Architecture::isMips64() const { return isMips() && getBitSize() == 64; } +bool Architecture::isMipsOrPic32() const { return isMips() || isPic32(); } /** * Checks if this architecture instance matches with the provided architecture name. @@ -72,14 +73,15 @@ bool Architecture::isEndianBig() const { return _endian == E_BIG; } bool Architecture::isEndianUnknown() const { return _endian == E_UNKNOWN; } bool Architecture::isEndianKnown() const { return !isEndianUnknown(); } -void Architecture::setIsUnknown() { setName(ARCH_UNKNOWN); } -void Architecture::setIsMips() { setName(ARCH_MIPS); } -void Architecture::setIsPic32() { setName(ARCH_PIC32); } -void Architecture::setIsArm() { setName(ARCH_ARM); } -void Architecture::setIsThumb() { setName(ARCH_THUMB); } -void Architecture::setIsArm64() { setName(ARCH_ARM64); } -void Architecture::setIsX86() { setName(ARCH_x86); } -void Architecture::setIsPpc() { setName(ARCH_PPC); } +void Architecture::setIsUnknown() { setName(ARCH_UNKNOWN); } +void Architecture::setIsMips() { setName(ARCH_MIPS); } +void Architecture::setIsPic32() { setName(ARCH_PIC32); } +void Architecture::setIsArm() { setName(ARCH_ARM); } +void Architecture::setIsThumb() { setName(ARCH_THUMB); _thumbFlag = true; } +void Architecture::setIsArm32() { setName(ARCH_ARM); setBitSize(32); } +void Architecture::setIsArm64() { setName(ARCH_ARM64); setBitSize(64); } +void Architecture::setIsX86() { setName(ARCH_x86); } +void Architecture::setIsPpc() { setName(ARCH_PPC); } void Architecture::setIsEndianLittle() { _endian = E_LITTLE; } void Architecture::setIsEndianBig() { _endian = E_BIG; } @@ -121,17 +123,15 @@ void Architecture::setArch() { _arch = eArch::PIC32; } - else if (retdec::utils::containsCaseInsensitive(_name, ARCH_ARM64)) + else if (retdec::utils::containsCaseInsensitive(_name, ARCH_THUMB)) { - _arch = eArch::ARM64; + _arch = eArch::ARM; + _thumbFlag = true; } else if (retdec::utils::containsCaseInsensitive(_name, ARCH_ARM)) { _arch = eArch::ARM; - } - else if (retdec::utils::containsCaseInsensitive(_name, ARCH_THUMB)) - { - _arch = eArch::THUMB; + _thumbFlag = false; } else if (retdec::utils::containsCaseInsensitive(_name, ARCH_x86)) { diff --git a/src/fileinfo/file_detector/file_detector.cpp b/src/fileinfo/file_detector/file_detector.cpp index e5e7eeb9e..704a05add 100644 --- a/src/fileinfo/file_detector/file_detector.cpp +++ b/src/fileinfo/file_detector/file_detector.cpp @@ -287,7 +287,7 @@ void FileDetector::setConfigFile(retdec::config::Config &config) auto arch = retdec::fileformat::Architecture::UNKNOWN; if (ca.isX86()) arch = retdec::fileformat::Architecture::X86; if (ca.isX86_64()) arch = retdec::fileformat::Architecture::X86_64; - if (ca.isArmOrThumb()) arch = retdec::fileformat::Architecture::ARM; + if (ca.isArm32OrThumb()) arch = retdec::fileformat::Architecture::ARM; if (ca.isPpc()) arch = retdec::fileformat::Architecture::POWERPC; if (ca.isMipsOrPic32()) arch = retdec::fileformat::Architecture::MIPS; diff --git a/src/stacofin/stacofin.cpp b/src/stacofin/stacofin.cpp index d96c74df6..3051adf8a 100644 --- a/src/stacofin/stacofin.cpp +++ b/src/stacofin/stacofin.cpp @@ -116,7 +116,7 @@ std::set selectSignaturePaths( { arch = "x64"; } - else if (c.architecture.isArmOrThumb()) + else if (c.architecture.isArm32OrThumb()) { arch = "arm"; } @@ -795,7 +795,7 @@ bool Finder::initDisassembler() arch = CS_ARCH_MIPS; _ceMode = CS_MODE_MIPS32; } - else if (_config->architecture.isArmOrThumb()) + else if (_config->architecture.isArm32OrThumb()) { arch = CS_ARCH_ARM; _ceMode = CS_MODE_ARM; @@ -829,7 +829,7 @@ void Finder::solveReferences() { bool modeSwitch = false; std::string& sigPath = p.second.signaturePath; - if (_config->architecture.isArmOrThumb() + if (_config->architecture.isArm32OrThumb() && utils::containsCaseInsensitive(sigPath, "thumb")) { if (cs_option(_ce, CS_OPT_MODE, CS_MODE_THUMB) != CS_ERR_OK) diff --git a/tests/config/architecture_tests.cpp b/tests/config/architecture_tests.cpp index 3a2e3a898..47d18ef3b 100644 --- a/tests/config/architecture_tests.cpp +++ b/tests/config/architecture_tests.cpp @@ -33,21 +33,36 @@ TEST_F(ArchitectureTests, CheckIfArchMethodsWork) arch.setIsArm(); EXPECT_TRUE( arch.isArm() ); - EXPECT_TRUE( arch.isArmOrThumb() ); EXPECT_TRUE( arch.isKnown() ); EXPECT_EQ( "arm", arch.getName() ); - arch.setIsArm64(); - EXPECT_TRUE( arch.isArm64() ); - EXPECT_TRUE( arch.isKnown() ); - EXPECT_EQ( "aarch64", arch.getName() ); - arch.setIsThumb(); + EXPECT_TRUE( arch.isArm() ); EXPECT_TRUE( arch.isThumb() ); - EXPECT_TRUE( arch.isArmOrThumb() ); + EXPECT_TRUE( arch.isArm32OrThumb() ); + EXPECT_FALSE( arch.isArm64() ); + EXPECT_FALSE( arch.isArm32() ); EXPECT_TRUE( arch.isKnown() ); EXPECT_EQ( "thumb", arch.getName() ); + arch.setIsArm32(); + EXPECT_TRUE( arch.isArm() ); + EXPECT_TRUE( arch.isArm32() ); + EXPECT_TRUE( arch.isArm32OrThumb() ); + EXPECT_FALSE( arch.isThumb() ); + EXPECT_FALSE( arch.isArm64() ); + EXPECT_TRUE( arch.isKnown() ); + EXPECT_EQ( "arm", arch.getName() ); + + arch.setIsArm64(); + EXPECT_TRUE( arch.isArm() ); + EXPECT_FALSE( arch.isArm32() ); + EXPECT_FALSE( arch.isArm32OrThumb() ); + EXPECT_FALSE( arch.isThumb() ); + EXPECT_TRUE( arch.isArm64() ); + EXPECT_TRUE( arch.isKnown() ); + EXPECT_EQ( "aarch64", arch.getName() ); + arch.setIsX86(); EXPECT_TRUE( arch.isX86() ); EXPECT_TRUE( arch.isKnown() ); From c5f421f07fa9e3fc7e6524775e523e5084dbac82 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 7 Mar 2019 18:38:13 +0100 Subject: [PATCH 097/107] Architecture: Removed the wrong architecture types Now the enum eArch represents only general architecture and all subtypes of architecture are checked to getBitSize() or _thumbFlag. The function isArm() return true for every type of subarchitecture e.g. {arm32, arm64 or thumb} --- include/retdec/config/architecture.h | 2 -- src/capstone2llvmir/arm64/arm64.cpp | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/retdec/config/architecture.h b/include/retdec/config/architecture.h index 01eeb00d1..65ef2688b 100644 --- a/include/retdec/config/architecture.h +++ b/include/retdec/config/architecture.h @@ -87,8 +87,6 @@ class Architecture MIPS, PIC32, ARM, - THUMB, - ARM64, X86, PPC, }; diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 1af5e1a35..17f4f8d48 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -306,7 +306,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( cs_detail* d = i->detail; cs_arm64* ai = &d->arm64; - std::cout << i->mnemonic << " " << i->op_str << std::endl; + //std::cout << i->mnemonic << " " << i->op_str << std::endl; auto fIt = _i2fm.find(i->id); if (fIt != _i2fm.end() && fIt->second != nullptr) From dbbb13793ac33df9853492a733464c3d12df257d Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 9 Mar 2019 16:16:04 +0100 Subject: [PATCH 098/107] Arm64: XZR loads zero and discards result when written - Added some instruction IDs to branch types --- src/capstone2llvmir/arm64/arm64.cpp | 23 ++++++++++++++++------- src/capstone2llvmir/arm64/arm64_init.cpp | 10 ++++++++-- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 17f4f8d48..54cbbc741 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -275,11 +275,11 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() // Stack pointer. createRegister(ARM64_REG_SP, _regLt); - createRegister(ARM64_REG_WSP, _regLt); + //createRegister(ARM64_REG_WSP, _regLt); // Zero. - createRegister(ARM64_REG_XZR, _regLt); - createRegister(ARM64_REG_WZR, _regLt); + //createRegister(ARM64_REG_XZR, _regLt); + //createRegister(ARM64_REG_WZR, _regLt); // Flags. createRegister(ARM64_REG_CPSR_N, _regLt); @@ -595,9 +595,6 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateGetOperandMemAddr( cs_arm64_op& op, llvm::IRBuilder<>& irb) { - // TODO: Check the operand types - // TODO: If the type is IMM return load of that value, or variable - // TODO: name, maybe generateGetOperandValue? auto* baseR = loadRegister(op.mem.base, irb); auto* t = baseR ? baseR->getType() : getDefaultType(); llvm::Value* disp = op.mem.disp @@ -659,6 +656,12 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadRegister( } auto* rt = getRegisterType(r); + if (r == ARM64_REG_XZR || r == ARM64_REG_WZR) + { + // Loads from XZR registers generate zero + return llvm::ConstantInt::get(rt, 0); + } + auto pr = getParentRegister(r); auto* llvmReg = getRegister(pr); if (llvmReg == nullptr) @@ -716,7 +719,7 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadOp( case ARM64_OP_FP: { auto* val = llvm::ConstantFP::get(irb.getDoubleTy(), op.fp); - return val; //generateOperandShift(irb, op, val); + return val; } case ARM64_OP_INVALID: case ARM64_OP_CIMM: @@ -750,6 +753,12 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeRegister( // TODO: Check? } + if (r == ARM64_REG_XZR || r == ARM64_REG_WZR) + { + // When written the register discards the result + return nullptr; + } + //auto* rt = getRegisterType(r); auto pr = getParentRegister(r); auto* llvmReg = getRegister(pr); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 918adf5ea..6932bc892 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -318,21 +318,27 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializePseudoCallInstructionIDs() _callInsnIds = { ARM64_INS_BL, + ARM64_INS_BLR, + ARM64_INS_BR, }; _returnInsnIds = { ARM64_INS_RET, + ARM64_INS_ERET, }; _branchInsnIds = { - + ARM64_INS_B, }; _condBranchInsnIds = { - + ARM64_INS_CBNZ, + ARM64_INS_CBZ, + ARM64_INS_TBNZ, + ARM64_INS_TBZ, }; _controlFlowInsnIds = From 2a5e865ef37400f6b37820de09b450d5b6e07395 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 9 Mar 2019 21:37:38 +0100 Subject: [PATCH 099/107] Arm64: STR and LDR instructions now determine correct register size - For example 'str w0, [sp]' should store only 4bytes to stack pointer --- src/capstone2llvmir/arm64/arm64.cpp | 78 +++++++++++++++++++++++--- src/capstone2llvmir/arm64/arm64_impl.h | 3 + 2 files changed, 73 insertions(+), 8 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 54cbbc741..cfbbdaa4b 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -937,8 +937,49 @@ uint8_t Capstone2LlvmIrTranslatorArm64_impl::getOperandAccess(cs_arm64_op& op) return op.access; } -bool Capstone2LlvmIrTranslatorArm64_impl::isCondIns(cs_arm64 * i) { - return (i->cc == ARM64_CC_AL || i->cc == ARM64_CC_INVALID) ? false : true; +bool Capstone2LlvmIrTranslatorArm64_impl::isCondIns(cs_arm64 * i) +{ + return (i->cc == ARM64_CC_AL || i->cc == ARM64_CC_INVALID) ? false : true; +} + +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateIntBitCastToFP(llvm::IRBuilder<>& irb, llvm::Value* val) +{ + if (auto* it = llvm::dyn_cast(val->getType())) + { + switch(it->getBitWidth()) + { + case 32: + return irb.CreateBitCast(val, irb.getFloatTy()); + case 64: + return irb.CreateBitCast(val, irb.getDoubleTy()); + default: + throw GenericError("Arm64::generateIntBitCastToFP: unhandled Integer type"); + } + } + // Return unchanged value if its not FP type + return val; +} + +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateFPBitCastToIntegerType(llvm::IRBuilder<>& irb, llvm::Value* val) +{ + auto* ty = val->getType(); + if (ty->isFloatingPointTy()) + { + if (ty->isDoubleTy()) + { + return irb.CreateBitCast(val, irb.getInt64Ty()); + } + else if (ty->isFloatTy()) + { + return irb.CreateBitCast(val, irb.getInt32Ty()); + } + else + { + throw GenericError("Arm64::generateFPBitCastToIntegerType: unhandled FP type"); + } + } + // Return unchanged value if its not FP type + return val; } // @@ -1186,7 +1227,15 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, case ARM64_INS_STTR: //case ARM64_INS_STXR: { - ty = getDefaultType(); + ty = getRegisterType(ai->operands[0].reg); + if (ty->isFloatTy()) + { + ty = irb.getInt32Ty(); + } + else if (ty->isDoubleTy()) + { + ty = irb.getInt64Ty(); + } break; } case ARM64_INS_STRB: @@ -1212,6 +1261,12 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, } op0 = loadOp(ai->operands[0], irb); + + // If its floating point operand bit cast it to integer type + // since the ZExt or Trunc doesn't work fp numbers + op0 = generateFPBitCastToIntegerType(irb, op0); + //op0 = irb.CreateBitCast(op0, irb.getInt32Ty()); + op0 = irb.CreateZExtOrTrunc(op0, ty); auto* dest = generateGetOperandMemAddr(ai->operands[1], irb); @@ -1317,7 +1372,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, case ARM64_INS_LDAXR: case ARM64_INS_LDAR: { - ty = irb.getInt32Ty(); + ty = getRegisterType(ai->operands[0].reg); sext = false; break; } @@ -1379,12 +1434,16 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateLdr(cs_insn* i, cs_arm64* ai, auto* pt = llvm::PointerType::get(ty, 0); auto* addr = irb.CreateIntToPtr(dest, pt); - auto* loaded_value = irb.CreateLoad(addr); - auto* ext_value = sext + llvm::Value* loaded_value = irb.CreateLoad(addr); + // If the result should be floating point, bit cast it + if (!regType->isFloatingPointTy()) + { + loaded_value = sext ? irb.CreateSExtOrTrunc(loaded_value, regType) : irb.CreateZExtOrTrunc(loaded_value, regType); + } - storeRegister(ai->operands[0].reg, ext_value, irb); + storeRegister(ai->operands[0].reg, loaded_value, irb); uint32_t baseR = ARM64_REG_INVALID; if (ai->op_count == 2) @@ -2591,7 +2650,10 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateFMov(cs_insn* i, cs_arm64* ai EXPECT_IS_BINARY(i, ai, irb); op1 = loadOp(ai->operands[1], irb); - op1 = irb.CreateBitCast(op1, getRegisterType(ai->operands[0].reg)); + if (!op1->getType()->isFloatingPointTy()) + { + op1 = irb.CreateBitCast(op1, getRegisterType(ai->operands[0].reg)); + } storeOp(ai->operands[0], op1, irb); } diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 0d350da31..3988f68fb 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -140,6 +140,9 @@ class Capstone2LlvmIrTranslatorArm64_impl : llvm::IRBuilder<>& irb, eOpConv ct = eOpConv::ZEXT_TRUNC) override; bool isCondIns(cs_arm64 * i); + + llvm::Value* generateFPBitCastToIntegerType(llvm::IRBuilder<>& irb, llvm::Value* val); + llvm::Value* generateIntBitCastToFP(llvm::IRBuilder<>& irb, llvm::Value* val); // //============================================================================== // Helper methods. From 275d44e98146b1b1ac8e3eb9d1264c9fde63fb4d Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Wed, 13 Mar 2019 17:03:00 +0100 Subject: [PATCH 100/107] Arm64: Syscall optimalization and detection Replace svc #0 with corresponding syscall decoded from previous assignments. --- .../optimizations/syscalls/syscalls.h | 4 + src/bin2llvmir/CMakeLists.txt | 1 + .../optimizations/syscalls/arm64.cpp | 386 ++++++++++++++++++ .../optimizations/syscalls/syscalls.cpp | 4 + src/bin2llvmir/providers/abi/arm64.cpp | 2 +- 5 files changed, 396 insertions(+), 1 deletion(-) create mode 100644 src/bin2llvmir/optimizations/syscalls/arm64.cpp diff --git a/include/retdec/bin2llvmir/optimizations/syscalls/syscalls.h b/include/retdec/bin2llvmir/optimizations/syscalls/syscalls.h index 70fa55a5c..8775f81e4 100644 --- a/include/retdec/bin2llvmir/optimizations/syscalls/syscalls.h +++ b/include/retdec/bin2llvmir/optimizations/syscalls/syscalls.h @@ -46,6 +46,10 @@ class SyscallFixer : public llvm::ModulePass bool runArm_linux_32(); bool runArm_linux_32(AsmInstruction ai); + bool runArm64(); + bool runArm64_linux_64(); + bool runArm64_linux_64(AsmInstruction ai); + bool runMips(); bool runMips_linux(); bool runMips_linux(AsmInstruction ai); diff --git a/src/bin2llvmir/CMakeLists.txt b/src/bin2llvmir/CMakeLists.txt index 4992e0867..5532c9636 100644 --- a/src/bin2llvmir/CMakeLists.txt +++ b/src/bin2llvmir/CMakeLists.txt @@ -66,6 +66,7 @@ set(BIN2LLVMIR_SOURCES optimizations/stack_pointer_ops/stack_pointer_ops.cpp optimizations/value_protect/value_protect.cpp optimizations/syscalls/arm.cpp + optimizations/syscalls/arm64.cpp optimizations/syscalls/mips.cpp optimizations/syscalls/syscalls.cpp optimizations/syscalls/x86.cpp diff --git a/src/bin2llvmir/optimizations/syscalls/arm64.cpp b/src/bin2llvmir/optimizations/syscalls/arm64.cpp new file mode 100644 index 000000000..7b48bedf0 --- /dev/null +++ b/src/bin2llvmir/optimizations/syscalls/arm64.cpp @@ -0,0 +1,386 @@ +/** + * @file src/bin2llvmir/optimizations/syscalls/arm64.cpp + * @brief Implement ARM64 syscall identification and fixing pass @c SyscallFixer. + * @copyright (c) 2019 Avast Software, licensed under the MIT license + */ + +#include + +#include "retdec/bin2llvmir/optimizations/syscalls/syscalls.h" +#include "retdec/bin2llvmir/providers/asm_instruction.h" + +using namespace llvm; + +//https://thog.github.io/syscalls-table-aarch64/latest.html +//https://github.com/hugsy/cemu/blob/master/cemu/syscalls/aarch64.csv +std::map syscalls_arm64_linux_64 = +{ + {0x80, "restart_syscall"}, //0 + {0x5D, "exit"}, //1 + {0x3F, "read"}, //3 + {0x40, "write"}, //4 + {0x400, "open"}, //5 + {0x39, "close"}, //6 + {0x428, "creat"}, //8 + {0x401, "link"}, //9 + {0x402, "unlink"}, //10 + {0xDD, "execve"}, //11 + {0x31, "chdir"}, //12 + {0x403, "mknod"}, //14 + {0x404, "chmod"}, //15 + {0x421, "lseek"}, //19 + {0xAC, "getpid"}, //20 + {0x28, "mount"}, //21 + {0x434, "umount"}, //22 + {0x75, "ptrace"}, //26 + {0x409, "access"}, //33 + {0x51, "sync"}, //36 + {0x81, "kill"}, //37 + {0x40A, "rename"}, //38 + {0x406, "mkdir"}, //39 + {0x407, "rmdir"}, //40 + {0x17, "dup"}, //41 + {0x410, "pipe"}, //42 + {0x99, "times"}, //43 + {0xD6, "brk"}, //45 + {0x59, "acct"}, //51 + {0x27, "umount2"}, //52 + {0x1D, "ioctl"}, //54 + {0x41C, "fcntl"}, //55 + {0x9A, "setpgid"}, //57 + {0xA6, "umask"}, //60 + {0x33, "chroot"}, //61 + {0x42E, "ustat"}, //62 + {0x411, "dup2"}, //63 + {0xAD, "getppid"}, //64 + {0x9D, "setsid"}, //66 + {0xA1, "sethostname"}, //74 + {0xA4, "setrlimit"}, //75 + {0xA5, "getrusage"}, //77 + {0xA9, "gettimeofday"}, //78 + {0xAA, "settimeofday"}, //79 + {0x40C, "symlink"}, //83 + {0x40B, "readlink"}, //85 + {0x435, "uselib"}, //86 + {0xE0, "swapon"}, //87 + {0x8E, "reboot"}, //88 + {0xD7, "munmap"}, //91 + {0x418, "truncate"}, //92 + {0x417, "ftruncate"}, //93 + {0x34, "fchmod"}, //94 + {0x8D, "getpriority"}, //96 + {0x8C, "setpriority"}, //97 + {0x420, "statfs"}, //99 + {0x41F, "fstatfs"}, //100 + {0x74, "syslog"}, //103 + {0x67, "setitimer"}, //104 + {0x66, "getitimer"}, //105 + {0x419, "stat"}, //106 + {0x41A, "lstat"}, //107 + {0x41B, "fstat"}, //108 + {0x3A, "vhangup"}, //111 + {0x104, "wait4"}, //114 + {0xE1, "swapoff"}, //115 + {0xB3, "sysinfo"}, //116 + {0x52, "fsync"}, //118 + {0xDC, "clone"}, //120 + {0xA2, "setdomainname"}, //121 + {0xA0, "uname"}, //122 + {0xAB, "adjtimex"}, //124 + {0xE2, "mprotect"}, //125 + {0x69, "init_module"}, //128 + {0x6A, "delete_module"}, //129 + {0x3C, "quotactl"}, //131 + {0x9B, "getpgid"}, //132 + {0x32, "fchdir"}, //133 + {0x433, "bdflush"}, //134 + {0x5C, "personality"}, //136 + {0x3E, "_llseek"}, //140 + {0x20, "flock"}, //143 + {0xE3, "msync"}, //144 + {0x41, "readv"}, //145 + {0x42, "writev"}, //146 + {0x9C, "getsid"}, //147 + {0x53, "fdatasync"}, //148 + {0x436, "_sysctl"}, //149 + {0xE4, "mlock"}, //150 + {0xE5, "munlock"}, //151 + {0xE6, "mlockall"}, //152 + {0xE7, "munlockall"}, //153 + {0x76, "sched_setparam"}, //154 + {0x79, "sched_getparam"}, //155 + {0x77, "sched_setscheduler"}, //156 + {0x78, "sched_getscheduler"}, //157 + {0x7C, "sched_yield"}, //158 + {0x7D, "sched_get_priority_max"}, //159 + {0x7E, "sched_get_priority_min"}, //160 + {0x65, "nanosleep"}, //162 + {0xD8, "mremap"}, //163 + {0x42C, "poll"}, //168 + {0xA7, "prctl"}, //172 + {0x86, "rt_sigaction"}, //174 + {0x87, "rt_sigprocmask"}, //175 + {0x88, "rt_sigpending"}, //176 + {0x85, "rt_sigsuspend"}, //179 + {0x43, "pread64"}, //180 + {0x44, "pwrite64"}, //181 + {0x11, "getcwd"}, //183 + {0x5A, "capget"}, //184 + {0x5B, "capset"}, //185 + {0x84, "sigaltstack"}, //186 + {0x416, "sendfile"}, //187 + {0x42F, "vfork"}, //190 + {0xA3, "ugetrlimit"}, //191 + {0x40E, "stat64"}, //195 + {0x40F, "lstat64"}, //196 + {0x50, "fstat64"}, //197 + {0x408, "lchown32"}, //198 + {0xAE, "getuid32"}, //199 + {0xB0, "getgid32"}, //200 + {0xAF, "geteuid32"}, //201 + {0xB1, "getegid32"}, //202 + {0x91, "setreuid32"}, //203 + {0x8F, "setregid32"}, //204 + {0x9E, "getgroups32"}, //205 + {0x9F, "setgroups32"}, //206 + {0x37, "fchown32"}, //207 + {0x93, "setresuid32"}, //208 + {0x94, "getresuid32"}, //209 + {0x95, "setresgid32"}, //210 + {0x96, "getresgid32"}, //211 + {0x405, "chown32"}, //212 + {0x92, "setuid32"}, //213 + {0x90, "setgid32"}, //214 + {0x97, "setfsuid32"}, //215 + {0x98, "setfsgid32"}, //216 + {0x3D, "getdents64"}, //217 + {0x29, "pivot_root"}, //218 + {0xE8, "mincore"}, //219 + {0xE9, "madvise"}, //220 + {0xB2, "gettid"}, //224 + {0xD5, "readahead"}, //225 + {0x5, "setxattr"}, //226 + {0x6, "lsetxattr"}, //227 + {0x7, "fsetxattr"}, //228 + {0x8, "getxattr"}, //229 + {0x9, "lgetxattr"}, //230 + {0xA, "fgetxattr"}, //231 + {0xB, "listxattr"}, //232 + {0xC, "llistxattr"}, //233 + {0xD, "flistxattr"}, //234 + {0xE, "removexattr"}, //235 + {0xF, "lremovexattr"}, //236 + {0x10, "fremovexattr"}, //237 + {0x82, "tkill"}, //238 + {0x47, "sendfile64"}, //239 + {0x62, "futex"}, //240 + {0x0, "io_setup"}, //243 + {0x1, "io_destroy"}, //244 + {0x4, "io_getevents"}, //245 + {0x2, "io_submit"}, //246 + {0x3, "io_cancel"}, //247 + {0x5E, "exit_group"}, //248 + {0x12, "lookup_dcookie"}, //249 + {0x412, "epoll_create"}, //250 + {0x15, "epoll_ctl"}, //251 + {0x42D, "epoll_wait"}, //252 + {0xEA, "remap_file_pages"}, //253 + {0x60, "set_tid_address"}, //256 + {0x6B, "timer_create"}, //257 + {0x6E, "timer_settime"}, //258 + {0x6C, "timer_gettime"}, //259 + {0x6D, "timer_getoverrun"}, //260 + {0x6F, "timer_delete"}, //261 + {0x70, "clock_settime"}, //262 + {0x71, "clock_gettime"}, //263 + {0x72, "clock_getres"}, //264 + {0x83, "tgkill"}, //268 + {0x40D, "utimes"}, //269 + {0xB4, "mq_open"}, //274 + {0xB5, "mq_unlink"}, //275 + {0xB6, "mq_timedsend"}, //276 + {0xB8, "mq_notify"}, //278 + {0xB9, "mq_getsetattr"}, //279 + {0x5F, "waitid"}, //280 + {0xC6, "socket"}, //281 + {0xC8, "bind"}, //282 + {0xCB, "connect"}, //283 + {0xC9, "listen"}, //284 + {0xCA, "accept"}, //285 + {0xCC, "getsockname"}, //286 + {0xCD, "getpeername"}, //287 + {0xC7, "socketpair"}, //288 + {0x432, "send"}, //289 + {0xCE, "sendto"}, //290 + {0x431, "recv"}, //291 + {0xCF, "recvfrom"}, //292 + {0xD2, "shutdown"}, //293 + {0xD0, "setsockopt"}, //294 + {0xD1, "getsockopt"}, //295 + {0xD3, "sendmsg"}, //296 + {0xD4, "recvmsg"}, //297 + {0xC1, "semop"}, //298 + {0xBE, "semget"}, //299 + {0xBF, "semctl"}, //300 + {0xBD, "msgsnd"}, //301 + {0xBC, "msgrcv"}, //302 + {0xBA, "msgget"}, //303 + {0xBB, "msgctl"}, //304 + {0xC4, "shmat"}, //305 + {0xC5, "shmdt"}, //306 + {0xC2, "shmget"}, //307 + {0xC3, "shmctl"}, //308 + {0xD9, "add_key"}, //309 + {0xDA, "request_key"}, //310 + {0xDB, "keyctl"}, //311 + {0xC0, "semtimedop"}, //312 + {0x1E, "ioprio_set"}, //314 + {0x1F, "ioprio_get"}, //315 + {0x413, "inotify_init"}, //316 + {0x1B, "inotify_add_watch"}, //317 + {0x1C, "inotify_rm_watch"}, //318 + {0xEB, "mbind"}, //319 + {0xEC, "get_mempolicy"}, //320 + {0xED, "set_mempolicy"}, //321 + {0x38, "openat"}, //322 + {0x22, "mkdirat"}, //323 + {0x21, "mknodat"}, //324 + {0x36, "fchownat"}, //325 + {0x42A, "futimesat"}, //326 + {0x4F, "fstatat64"}, //327 + {0x23, "unlinkat"}, //328 + {0x26, "renameat"}, //329 + {0x25, "linkat"}, //330 + {0x24, "symlinkat"}, //331 + {0x4E, "readlinkat"}, //332 + {0x35, "fchmodat"}, //333 + {0x30, "faccessat"}, //334 + {0x48, "pselect6"}, //335 + {0x49, "ppoll"}, //336 + {0x61, "unshare"}, //337 + {0x4C, "splice"}, //340 + {0x4D, "tee"}, //342 + {0x4B, "vmsplice"}, //343 + {0xEF, "move_pages"}, //344 + {0xA8, "getcpu"}, //345 + {0x16, "epoll_pwait"}, //346 + {0x68, "kexec_load"}, //347 + {0x58, "utimensat"}, //348 + {0x415, "signalfd"}, //349 + {0x55, "timerfd_create"}, //350 + {0x414, "eventfd"}, //351 + {0x2F, "fallocate"}, //352 + {0x4A, "signalfd4"}, //355 + {0x13, "eventfd2"}, //356 + {0x14, "epoll_create1"}, //357 + {0x18, "dup3"}, //358 + {0x3B, "pipe2"}, //359 + {0x1A, "inotify_init1"}, //360 + {0x45, "preadv"}, //361 + {0x46, "pwritev"}, //362 + {0xF1, "perf_event_open"}, //364 + {0xF3, "recvmmsg"}, //365 + {0xF2, "accept4"}, //366 + {0x106, "fanotify_init"}, //367 + {0x107, "fanotify_mark"}, //368 + {0x105, "prlimit64"}, //369 + {0x108, "name_to_handle_at"}, //370 + {0x10A, "clock_adjtime"}, //372 + {0x10B, "syncfs"}, //373 + {0x10D, "sendmmsg"}, //374 + {0x10C, "setns"}, //375 + {0x110, "kcmp"}, //378 + {0x111, "finit_module"}, //379 + {0x112, "sched_setattr"}, //380 + {0x113, "sched_getattr"}, //381 + {0x114, "renameat2"}, //382 + {0x115, "seccomp"}, //383 + {0x116, "getrandom"}, //384 + {0x117, "memfd_create"}, //385 + {0x118, "bpf"}, //386 + {0x119, "execveat"}, //387 + {0x11A, "userfaultfd"}, //388 + {0x11B, "membarrier"}, //389 + {0x11C, "mlock2"}, //390 + {0x11D, "copy_file_range"}, //391 + {0x11E, "preadv2"}, //392 + {0x11F, "pwritev2"}, //393 + {0x120, "pkey_mprotect"}, //394 + {0x121, "pkey_alloc"}, //395 + {0x122, "pkey_free"}, //396 + {0x123, "statx"}, //397 +}; + +namespace retdec { +namespace bin2llvmir { + +bool SyscallFixer::runArm64() +{ + if (_config->getConfig().fileFormat.isElf64()) + { + return runArm64_linux_64(); + } + + return false; +} + +bool SyscallFixer::runArm64_linux_64() +{ + bool changed = false; + for (Function& F : *_module) + { + for (auto ai = AsmInstruction(&F); ai.isValid(); ai = ai.getNext()) + { + changed |= runArm64_linux_64(ai); + } + } + return changed; +} + +/** +| 0x00400180 200080d2 movz x0, 0x1 ; [02] -r-x section size 56 named .text +| 0x00400184 61010058 ldr x1, loc._d_2 ; "Hello, world!\n" +| 0x00400188 820280d2 movz x2, 0xe +| 0x0040018c 080880d2 movz x8, 0x40 ; '@' +| ;-- syscall.io_setup: +| 0x00400190 010000d4 svc 0 +\*/ +bool SyscallFixer::runArm64_linux_64(AsmInstruction ai) +{ + auto* arm64Asm = ai.getCapstoneInsn(); + if (arm64Asm == nullptr || arm64Asm->id != ARM64_INS_SVC) + { + return false; + } + LOG << "ARM64 syscall @ " << ai.getAddress() << std::endl; + + // Find syscall ID. + // + auto* syscallIdReg = _abi->getSyscallIdRegister(); + StoreInst* store = nullptr; + Instruction* it = ai.getLlvmToAsmInstruction()->getPrevNode(); + for (; it != nullptr; it = it->getPrevNode()) + { + if (auto* s = dyn_cast(it)) + { + if (s->getPointerOperand() == syscallIdReg) + { + store = s; + break; + } + } + } + if (store == nullptr || !isa(store->getValueOperand())) + { + LOG << "\tsyscall code not found" << std::endl; + return false; + } + uint64_t code = cast(store->getValueOperand())->getZExtValue(); + LOG << "\tcode instruction: " << llvmObjToString(store) << std::endl; + LOG << "\tcode : " << std::dec << code << std::endl; + + return transform(ai, code, syscalls_arm64_linux_64); +} + +} // namespace bin2llvmir +} // namespace retdec diff --git a/src/bin2llvmir/optimizations/syscalls/syscalls.cpp b/src/bin2llvmir/optimizations/syscalls/syscalls.cpp index 69e9a00ce..2977a8691 100644 --- a/src/bin2llvmir/optimizations/syscalls/syscalls.cpp +++ b/src/bin2llvmir/optimizations/syscalls/syscalls.cpp @@ -68,6 +68,10 @@ bool SyscallFixer::run() { return runArm(); } + else if (_config->getConfig().architecture.isArm64()) + { + return runArm64(); + } else if (_config->getConfig().architecture.isX86_32()) { return runX86(); diff --git a/src/bin2llvmir/providers/abi/arm64.cpp b/src/bin2llvmir/providers/abi/arm64.cpp index d9be3ba84..71d438675 100644 --- a/src/bin2llvmir/providers/abi/arm64.cpp +++ b/src/bin2llvmir/providers/abi/arm64.cpp @@ -19,7 +19,7 @@ AbiArm64::AbiArm64(llvm::Module* m, Config* c) : _regStackPointerId = ARM64_REG_SP; // system calls - _regSyscallId = ARM64_REG_X7; + _regSyscallId = ARM64_REG_X8; _regSyscallReturn = ARM64_REG_X0; _syscallRegs = { ARM64_REG_X0, From f64fba46a50ae1c00f2c6b9f89cc9414547e2dfd Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 16 Mar 2019 12:26:21 +0100 Subject: [PATCH 101/107] Arm64: MOVI instructions + tests, Vector and half register Generate Vector registers so in case the pseudo instructions with them as operands is generated we don't crash. For the similar purpose I changed the f16 in ARM64_REG_H* to i16 since half type in not supported and we wan't to be able to at least generate pseudo instructions. --- src/capstone2llvmir/arm64/arm64.cpp | 135 ++++++++++++++++++----- src/capstone2llvmir/arm64/arm64_impl.h | 22 +++- src/capstone2llvmir/arm64/arm64_init.cpp | 111 ++++++++++++------- tests/capstone2llvmir/arm64_tests.cpp | 31 ++++++ 4 files changed, 231 insertions(+), 68 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index cfbbdaa4b..9533de4a4 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -68,6 +68,39 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateDataLayout() void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() { // FP&SIMD registers + createRegister(ARM64_REG_V0, _regLt); + createRegister(ARM64_REG_V1, _regLt); + createRegister(ARM64_REG_V2, _regLt); + createRegister(ARM64_REG_V3, _regLt); + createRegister(ARM64_REG_V4, _regLt); + createRegister(ARM64_REG_V5, _regLt); + createRegister(ARM64_REG_V6, _regLt); + createRegister(ARM64_REG_V7, _regLt); + createRegister(ARM64_REG_V8, _regLt); + createRegister(ARM64_REG_V9, _regLt); + createRegister(ARM64_REG_V10, _regLt); + createRegister(ARM64_REG_V11, _regLt); + createRegister(ARM64_REG_V12, _regLt); + createRegister(ARM64_REG_V13, _regLt); + createRegister(ARM64_REG_V14, _regLt); + createRegister(ARM64_REG_V15, _regLt); + createRegister(ARM64_REG_V16, _regLt); + createRegister(ARM64_REG_V17, _regLt); + createRegister(ARM64_REG_V18, _regLt); + createRegister(ARM64_REG_V19, _regLt); + createRegister(ARM64_REG_V20, _regLt); + createRegister(ARM64_REG_V21, _regLt); + createRegister(ARM64_REG_V22, _regLt); + createRegister(ARM64_REG_V23, _regLt); + createRegister(ARM64_REG_V24, _regLt); + createRegister(ARM64_REG_V25, _regLt); + createRegister(ARM64_REG_V26, _regLt); + createRegister(ARM64_REG_V27, _regLt); + createRegister(ARM64_REG_V28, _regLt); + createRegister(ARM64_REG_V29, _regLt); + createRegister(ARM64_REG_V30, _regLt); + createRegister(ARM64_REG_V31, _regLt); + createRegister(ARM64_REG_Q0, _regLt); createRegister(ARM64_REG_Q1, _regLt); createRegister(ARM64_REG_Q2, _regLt); @@ -167,7 +200,6 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() createRegister(ARM64_REG_S30, _regLt); createRegister(ARM64_REG_S31, _regLt); - /* createRegister(ARM64_REG_H0, _regLt); createRegister(ARM64_REG_H1, _regLt); createRegister(ARM64_REG_H2, _regLt); @@ -200,7 +232,6 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() createRegister(ARM64_REG_H29, _regLt); createRegister(ARM64_REG_H30, _regLt); createRegister(ARM64_REG_H31, _regLt); - */ createRegister(ARM64_REG_B0, _regLt); createRegister(ARM64_REG_B1, _regLt); @@ -317,23 +348,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateInstruction( } else { - throwUnhandledInstructions(i); - - if (ai->cc == ARM64_CC_AL - || ai->cc == ARM64_CC_INVALID) - { - _inCondition = false; - translatePseudoAsmGeneric(i, ai, irb); - } - else - { - _inCondition = true; - - auto* cond = generateInsnConditionCode(irb, ai); - auto bodyIrb = generateIfThen(cond, irb); - - translatePseudoAsmGeneric(i, ai, bodyIrb); - } + generatePseudoInstruction(i, ai, irb); } } @@ -926,23 +941,49 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateInsnConditionCode( } } - bool Capstone2LlvmIrTranslatorArm64_impl::isOperandRegister(cs_arm64_op& op) { return op.type == ARM64_OP_REG; } +bool Capstone2LlvmIrTranslatorArm64_impl::isFPRegister(cs_arm64_op& op, bool onlySupported) const +{ + if (op.type != ARM64_OP_REG) + { + return false; + } + bool is_q_reg = (op.reg >= ARM64_REG_Q0 && op.reg <= ARM64_REG_Q31); + bool is_d_reg = (op.reg >= ARM64_REG_D0 && op.reg <= ARM64_REG_D31); + bool is_h_reg = (op.reg >= ARM64_REG_H0 && op.reg <= ARM64_REG_H31); + bool is_s_reg = (op.reg >= ARM64_REG_S0 && op.reg <= ARM64_REG_S31); + if (onlySupported) + { + return is_d_reg || is_h_reg; + } + else + { + // This is the overall correct behavior but since the support for 16bit floats + // or 128 bit floats is not implemented, we want to check only D and H registers + return is_q_reg || is_d_reg || is_h_reg || is_s_reg; + } +} + +bool Capstone2LlvmIrTranslatorArm64_impl::isVectorRegister(cs_arm64_op& op) const +{ + return op.type == ARM64_OP_REG && op.reg >= ARM64_REG_V0 && op.reg <= ARM64_REG_V31; +} + uint8_t Capstone2LlvmIrTranslatorArm64_impl::getOperandAccess(cs_arm64_op& op) { return op.access; } -bool Capstone2LlvmIrTranslatorArm64_impl::isCondIns(cs_arm64 * i) +bool Capstone2LlvmIrTranslatorArm64_impl::isCondIns(cs_arm64 * i) const { return (i->cc == ARM64_CC_AL || i->cc == ARM64_CC_INVALID) ? false : true; } -llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateIntBitCastToFP(llvm::IRBuilder<>& irb, llvm::Value* val) +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateIntBitCastToFP(llvm::IRBuilder<>& irb, llvm::Value* val) const { if (auto* it = llvm::dyn_cast(val->getType())) { @@ -960,7 +1001,7 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateIntBitCastToFP(llvm::I return val; } -llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateFPBitCastToIntegerType(llvm::IRBuilder<>& irb, llvm::Value* val) +llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateFPBitCastToIntegerType(llvm::IRBuilder<>& irb, llvm::Value* val) const { auto* ty = val->getType(); if (ty->isFloatingPointTy()) @@ -982,6 +1023,26 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateFPBitCastToIntegerType return val; } +void Capstone2LlvmIrTranslatorArm64_impl::generatePseudoInstruction(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + throwUnhandledInstructions(i); + + if (!isCondIns(ai)) + { + _inCondition = false; + translatePseudoAsmGeneric(i, ai, irb); + } + else + { + _inCondition = true; + + auto* cond = generateInsnConditionCode(irb, ai); + auto bodyIrb = generateIfThen(cond, irb); + + translatePseudoAsmGeneric(i, ai, bodyIrb); + } +} + // //============================================================================== // ARM64 instruction translation methods. @@ -1264,10 +1325,12 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, // If its floating point operand bit cast it to integer type // since the ZExt or Trunc doesn't work fp numbers - op0 = generateFPBitCastToIntegerType(irb, op0); + //op0 = generateFPBitCastToIntegerType(irb, op0); //op0 = irb.CreateBitCast(op0, irb.getInt32Ty()); - - op0 = irb.CreateZExtOrTrunc(op0, ty); + if (!op0->getType()->isFloatingPointTy()) + { + op0 = irb.CreateZExtOrTrunc(op0, ty); + } auto* dest = generateGetOperandMemAddr(ai->operands[1], irb); auto* pt = llvm::PointerType::get(op0->getType(), 0); @@ -2650,14 +2713,30 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateFMov(cs_insn* i, cs_arm64* ai EXPECT_IS_BINARY(i, ai, irb); op1 = loadOp(ai->operands[1], irb); - if (!op1->getType()->isFloatingPointTy()) + op1 = irb.CreateBitCast(op1, getRegisterType(ai->operands[0].reg)); + + storeOp(ai->operands[0], op1, irb); +} + +/** + * ARM64_INS_MOVI + */ +void Capstone2LlvmIrTranslatorArm64_impl::translateMovi(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) +{ + EXPECT_IS_BINARY(i, ai, irb); + + if (!isFPRegister(ai->operands[0])) { - op1 = irb.CreateBitCast(op1, getRegisterType(ai->operands[0].reg)); + // We want this behavior in cases when move destination is vector register + generatePseudoInstruction(i, ai, irb); + return; } + op1 = loadOp(ai->operands[1], irb); storeOp(ai->operands[0], op1, irb); } + /** * ARM64_INS_FMUL, ARM64_INS_FNMUL */ diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 3988f68fb..1334e834e 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -139,16 +139,31 @@ class Capstone2LlvmIrTranslatorArm64_impl : llvm::Value* val, llvm::IRBuilder<>& irb, eOpConv ct = eOpConv::ZEXT_TRUNC) override; - bool isCondIns(cs_arm64 * i); - llvm::Value* generateFPBitCastToIntegerType(llvm::IRBuilder<>& irb, llvm::Value* val); - llvm::Value* generateIntBitCastToFP(llvm::IRBuilder<>& irb, llvm::Value* val); + /** + * @brief This functions will generate psuedo asm translation. + * Instructions that are not implemented fall back to this method which will + * check there is need to generate conditional code and then generate given pseudo. + */ + void generatePseudoInstruction(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + llvm::Value* generateFPBitCastToIntegerType(llvm::IRBuilder<>& irb, llvm::Value* val) const; + llvm::Value* generateIntBitCastToFP(llvm::IRBuilder<>& irb, llvm::Value* val) const; // //============================================================================== // Helper methods. //============================================================================== // protected: + + bool isCondIns(cs_arm64 * i) const; + + /** + * @brief Return if register is FP type. + * @param onlySupported Account only for supported registers in retdec. + */ + bool isFPRegister(cs_arm64_op& op, bool onlySupported = true) const; + bool isVectorRegister(cs_arm64_op& op) const; + virtual bool isOperandRegister(cs_arm64_op& op) override; virtual uint8_t getOperandAccess(cs_arm64_op& op) override; // @@ -225,6 +240,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : void translateFMinMaxNum(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFMsub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFMov(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); + void translateMovi(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFMul(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFSub(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); void translateFUnaryOp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb); diff --git a/src/capstone2llvmir/arm64/arm64_init.cpp b/src/capstone2llvmir/arm64/arm64_init.cpp index 6932bc892..2e5eb0726 100644 --- a/src/capstone2llvmir/arm64/arm64_init.cpp +++ b/src/capstone2llvmir/arm64/arm64_init.cpp @@ -38,12 +38,12 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializeRegTypeMap() { auto* i1 = llvm::IntegerType::getInt1Ty(_module->getContext()); auto* i8 = llvm::IntegerType::getInt8Ty(_module->getContext()); - //auto* i16 = llvm::IntegerType::getInt16Ty(_module->getContext()); + auto* i16 = llvm::IntegerType::getInt16Ty(_module->getContext()); auto* i32 = llvm::IntegerType::getInt32Ty(_module->getContext()); auto* i64 = llvm::IntegerType::getInt64Ty(_module->getContext()); - //auto* i128 = llvm::IntegerType::getInt128Ty(_module->getContext()); + auto* i128 = llvm::IntegerType::getInt128Ty(_module->getContext()); - auto* f16 = llvm::Type::getHalfTy(_module->getContext()); + //auto* f16 = llvm::Type::getHalfTy(_module->getContext()); auto* f32 = llvm::Type::getFloatTy(_module->getContext()); auto* f64 = llvm::Type::getDoubleTy(_module->getContext()); auto* f128 = llvm::Type::getFP128Ty(_module->getContext()); @@ -118,7 +118,41 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializeRegTypeMap() {ARM64_REG_W30, i32}, // FP&SIMD Regs - // + // Vector + {ARM64_REG_V0, i128}, + {ARM64_REG_V1, i128}, + {ARM64_REG_V2, i128}, + {ARM64_REG_V3, i128}, + {ARM64_REG_V4, i128}, + {ARM64_REG_V5, i128}, + {ARM64_REG_V6, i128}, + {ARM64_REG_V7, i128}, + {ARM64_REG_V8, i128}, + {ARM64_REG_V9, i128}, + {ARM64_REG_V10, i128}, + {ARM64_REG_V11, i128}, + {ARM64_REG_V12, i128}, + {ARM64_REG_V13, i128}, + {ARM64_REG_V14, i128}, + {ARM64_REG_V15, i128}, + {ARM64_REG_V16, i128}, + {ARM64_REG_V17, i128}, + {ARM64_REG_V18, i128}, + {ARM64_REG_V19, i128}, + {ARM64_REG_V20, i128}, + {ARM64_REG_V21, i128}, + {ARM64_REG_V22, i128}, + {ARM64_REG_V23, i128}, + {ARM64_REG_V24, i128}, + {ARM64_REG_V25, i128}, + {ARM64_REG_V26, i128}, + {ARM64_REG_V27, i128}, + {ARM64_REG_V28, i128}, + {ARM64_REG_V29, i128}, + {ARM64_REG_V30, i128}, + {ARM64_REG_V31, i128}, + + // FP {ARM64_REG_Q0, f128}, {ARM64_REG_Q1, f128}, {ARM64_REG_Q2, f128}, @@ -218,38 +252,41 @@ void Capstone2LlvmIrTranslatorArm64_impl::initializeRegTypeMap() {ARM64_REG_S30, f32}, {ARM64_REG_S31, f32}, - {ARM64_REG_H0, f16}, - {ARM64_REG_H1, f16}, - {ARM64_REG_H2, f16}, - {ARM64_REG_H3, f16}, - {ARM64_REG_H4, f16}, - {ARM64_REG_H5, f16}, - {ARM64_REG_H6, f16}, - {ARM64_REG_H7, f16}, - {ARM64_REG_H8, f16}, - {ARM64_REG_H9, f16}, - {ARM64_REG_H10, f16}, - {ARM64_REG_H11, f16}, - {ARM64_REG_H12, f16}, - {ARM64_REG_H13, f16}, - {ARM64_REG_H14, f16}, - {ARM64_REG_H15, f16}, - {ARM64_REG_H16, f16}, - {ARM64_REG_H17, f16}, - {ARM64_REG_H18, f16}, - {ARM64_REG_H19, f16}, - {ARM64_REG_H20, f16}, - {ARM64_REG_H21, f16}, - {ARM64_REG_H22, f16}, - {ARM64_REG_H23, f16}, - {ARM64_REG_H24, f16}, - {ARM64_REG_H25, f16}, - {ARM64_REG_H26, f16}, - {ARM64_REG_H27, f16}, - {ARM64_REG_H28, f16}, - {ARM64_REG_H29, f16}, - {ARM64_REG_H30, f16}, - {ARM64_REG_H31, f16}, + // Instead of 16bit floats which are not supported in llvm + // we use 16bit integers, so we can generate meaningfull + // pseudo instructions instead of crashing. + {ARM64_REG_H0, i16}, + {ARM64_REG_H1, i16}, + {ARM64_REG_H2, i16}, + {ARM64_REG_H3, i16}, + {ARM64_REG_H4, i16}, + {ARM64_REG_H5, i16}, + {ARM64_REG_H6, i16}, + {ARM64_REG_H7, i16}, + {ARM64_REG_H8, i16}, + {ARM64_REG_H9, i16}, + {ARM64_REG_H10, i16}, + {ARM64_REG_H11, i16}, + {ARM64_REG_H12, i16}, + {ARM64_REG_H13, i16}, + {ARM64_REG_H14, i16}, + {ARM64_REG_H15, i16}, + {ARM64_REG_H16, i16}, + {ARM64_REG_H17, i16}, + {ARM64_REG_H18, i16}, + {ARM64_REG_H19, i16}, + {ARM64_REG_H20, i16}, + {ARM64_REG_H21, i16}, + {ARM64_REG_H22, i16}, + {ARM64_REG_H23, i16}, + {ARM64_REG_H24, i16}, + {ARM64_REG_H25, i16}, + {ARM64_REG_H26, i16}, + {ARM64_REG_H27, i16}, + {ARM64_REG_H28, i16}, + {ARM64_REG_H29, i16}, + {ARM64_REG_H30, i16}, + {ARM64_REG_H31, i16}, {ARM64_REG_B0, i8}, {ARM64_REG_B1, i8}, @@ -612,7 +649,7 @@ Capstone2LlvmIrTranslatorArm64_impl::_i2fm = {ARM64_INS_MADD, &Capstone2LlvmIrTranslatorArm64_impl::translateMul}, {ARM64_INS_MLA, nullptr}, {ARM64_INS_MLS, nullptr}, - {ARM64_INS_MOVI, nullptr}, + {ARM64_INS_MOVI, &Capstone2LlvmIrTranslatorArm64_impl::translateMovi}, {ARM64_INS_MOVK, &Capstone2LlvmIrTranslatorArm64_impl::translateMovk}, {ARM64_INS_MOVN, &Capstone2LlvmIrTranslatorArm64_impl::translateMov}, {ARM64_INS_MOVZ, &Capstone2LlvmIrTranslatorArm64_impl::translateMov}, diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 989dab8d7..4218cfd4b 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -7713,6 +7713,37 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMOV_d_x) EXPECT_NO_VALUE_CALLED(); } +// +// ARM64_INS_MOVI +// + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVI_d_i) +{ + emulate("movi d0, #0"); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 0._f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_MOVI_v_i) +{ + // Generate pseudo instruction in this case + emulate("movi v15.4h, #0xcf"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_V15}); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_V15, ANY}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_module.getFunction("__asm_movi"), {0, 207}}, + }); +} + // // ARM64_INS_FMUL // From 501258521a231de1adcceccf8ff571a7260a9fb8 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Sat, 16 Mar 2019 13:14:51 +0100 Subject: [PATCH 102/107] Arm64: STR and LDR tests Those tests target loading and storing floating point values. --- tests/capstone2llvmir/arm64_tests.cpp | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 4218cfd4b..ad6634ff3 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -2758,6 +2758,42 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STR32_r_r) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STR_d_r) +{ + setRegisters({ + {ARM64_REG_D0, 123.45678910_f64}, + {ARM64_REG_SP, 0x1234}, + }); + + emulate("str d0, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D0, ARM64_REG_SP}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1234, 123.45678910_f64} + }); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_STR_s_r) +{ + setRegisters({ + {ARM64_REG_S0, 24.122019_f32}, + {ARM64_REG_SP, 0x1234}, + }); + + emulate("str s0, [sp]"); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_S0, ARM64_REG_SP}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED(); + EXPECT_JUST_MEMORY_STORED({ + {0x1234, 24.122019_f32} + }); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_STRB // From 891db78687ee6f43740953ca2043c7ed33f0d7d3 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Thu, 21 Mar 2019 09:50:59 +0100 Subject: [PATCH 103/107] Arm64: Removed zero division semantics from llvmir - Zero division is NOW undefined behaviour - This caused problems in modulo idiom detection - Also removed coresponding tests --- src/capstone2llvmir/arm64/arm64.cpp | 22 +++++++++++++------- tests/capstone2llvmir/arm64_tests.cpp | 30 --------------------------- 2 files changed, 15 insertions(+), 37 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 9533de4a4..40c57b1ed 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -306,11 +306,6 @@ void Capstone2LlvmIrTranslatorArm64_impl::generateRegisters() // Stack pointer. createRegister(ARM64_REG_SP, _regLt); - //createRegister(ARM64_REG_WSP, _regLt); - - // Zero. - //createRegister(ARM64_REG_XZR, _regLt); - //createRegister(ARM64_REG_WZR, _regLt); // Flags. createRegister(ARM64_REG_CPSR_N, _regLt); @@ -460,9 +455,9 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::generateOperandShift( if (n == nullptr) { - assert(false && "should not be possible"); - return val; + throw GenericError("generateOperandShift(): nullptr shift value"); } + n = irb.CreateZExtOrTrunc(n, val->getType()); switch (op.shift.type) @@ -2114,7 +2109,19 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateDiv(cs_insn* i, cs_arm64* ai, EXPECT_IS_TERNARY(i, ai, irb); std::tie(op1, op2) = loadOpBinaryOrTernaryOp1Op2(ai, irb); + llvm::Value *val = nullptr; + if (i->id == ARM64_INS_UDIV) + { + val = irb.CreateUDiv(op1, op2); + } + else if (i->id == ARM64_INS_SDIV) + { + val = irb.CreateSDiv(op1, op2); + } + storeOp(ai->operands[0], val, irb); + + /* // Zero division yelds zero as result in this case we // don't want undefined behaviour so we // check for zero division and manualy set the result, for now. @@ -2139,6 +2146,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateDiv(cs_insn* i, cs_arm64* ai, storeOp(ai->operands[0], val, bodyElse); //ENDIF + */ } /** diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index ad6634ff3..8f11aee7c 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -6242,21 +6242,6 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SDIV32_r_r_r) EXPECT_NO_VALUE_CALLED(); } -TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_SDIV_r_r_r_zero_div) -{ - setRegisters({ - {ARM64_REG_X1, 0x1230}, - {ARM64_REG_X2, 0x0}, - }); - - emulate("sdiv x0, x1, x2"); - - EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); - EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x0},}); - EXPECT_NO_MEMORY_LOADED_STORED(); - EXPECT_NO_VALUE_CALLED(); -} - TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UDIV_r_r_r) { setRegisters({ @@ -6358,21 +6343,6 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UDIV32_r_r_r) EXPECT_NO_VALUE_CALLED(); } -TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_UDIV_r_r_r_zero_div) -{ - setRegisters({ - {ARM64_REG_X1, 0x1230}, - {ARM64_REG_X2, 0x0}, - }); - - emulate("udiv x0, x1, x2"); - - EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_X1, ARM64_REG_X2}); - EXPECT_JUST_REGISTERS_STORED({{ARM64_REG_X0, 0x0},}); - EXPECT_NO_MEMORY_LOADED_STORED(); - EXPECT_NO_VALUE_CALLED(); -} - // // ARM64_INS_TST // From 2ee7c9142280b381aa9757a6b37d9f75faad0f1b Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 22 Mar 2019 12:25:17 +0100 Subject: [PATCH 104/107] Arm64: FMOV instruction with immediate values - Correctly handle imm values as operands of this instruction --- src/capstone2llvmir/arm64/arm64.cpp | 9 ++++++++- tests/capstone2llvmir/arm64_tests.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 40c57b1ed..a0702ab3b 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -2721,7 +2721,14 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateFMov(cs_insn* i, cs_arm64* ai EXPECT_IS_BINARY(i, ai, irb); op1 = loadOp(ai->operands[1], irb); - op1 = irb.CreateBitCast(op1, getRegisterType(ai->operands[0].reg)); + if (ai->operands[1].type == ARM64_OP_FP) + { + op1 = generateTypeConversion(irb, op1, getRegisterType(ai->operands[0].reg), eOpConv::FP_CAST); + } + else + { + op1 = irb.CreateBitCast(op1, getRegisterType(ai->operands[0].reg)); + } storeOp(ai->operands[0], op1, irb); } diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 8f11aee7c..83fbf7c70 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -7719,6 +7719,30 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMOV_d_x) EXPECT_NO_VALUE_CALLED(); } +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMOV_d_i) +{ + emulate("fmov d0, #1."); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_D0, 1._f64}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FMOV_s_i) +{ + emulate("fmov s0, #1."); + + EXPECT_NO_REGISTERS_LOADED(); + EXPECT_JUST_REGISTERS_STORED({ + {ARM64_REG_S0, 1._f32}, + }); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_NO_VALUE_CALLED(); +} + // // ARM64_INS_MOVI // From 3c6b0d36cf03bd754a8438094f1c73955dd30833 Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Fri, 22 Mar 2019 15:35:21 +0100 Subject: [PATCH 105/107] Revert "Arm64, bin2llvmir: Decoder should not analyse stack." This reverts commit 7b884752806408dd37ade5881a57e670fecc63b2. This change caused other tests to fail. --- include/retdec/bin2llvmir/analyses/symbolic_tree.h | 2 -- src/bin2llvmir/analyses/symbolic_tree.cpp | 10 +--------- src/bin2llvmir/optimizations/decoder/decoder.cpp | 4 ---- 3 files changed, 1 insertion(+), 15 deletions(-) diff --git a/include/retdec/bin2llvmir/analyses/symbolic_tree.h b/include/retdec/bin2llvmir/analyses/symbolic_tree.h index aaa48df69..06f6cf590 100644 --- a/include/retdec/bin2llvmir/analyses/symbolic_tree.h +++ b/include/retdec/bin2llvmir/analyses/symbolic_tree.h @@ -109,7 +109,6 @@ class SymbolicTree static void setToDefaultConfiguration(); static void setTrackThroughAllocaLoads(bool b); static void setTrackThroughGeneralRegisterLoads(bool b); - static void setTrackThroughStackPointerRegister(bool b); static void setTrackOnlyFlagRegisters(bool b); static void setSimplifyAtCreation(bool b); static void setNaryLimit(unsigned n); @@ -120,7 +119,6 @@ class SymbolicTree static bool _val2valUsed; static bool _trackThroughAllocaLoads; static bool _trackThroughGeneralRegisterLoads; - static bool _trackThroughStackPointerRegister; static bool _trackOnlyFlagRegisters; static bool _simplifyAtCreation; static unsigned _naryLimit; diff --git a/src/bin2llvmir/analyses/symbolic_tree.cpp b/src/bin2llvmir/analyses/symbolic_tree.cpp index 48a710488..f7b4fa84b 100644 --- a/src/bin2llvmir/analyses/symbolic_tree.cpp +++ b/src/bin2llvmir/analyses/symbolic_tree.cpp @@ -301,8 +301,7 @@ void SymbolicTree::expandNode( || isa(value) || (_abi && _abi->isRegister(value) - && (!_trackThroughStackPointerRegister - || !_abi->isStackPointerRegister(value)) + && !_abi->isStackPointerRegister(value) && !_abi->isZeroRegister(value) && value != _abi->getRegister(MIPS_REG_GP, _abi->isMips()))) { @@ -703,7 +702,6 @@ Config* SymbolicTree::_config = nullptr; bool SymbolicTree::_val2valUsed = false; bool SymbolicTree::_trackThroughAllocaLoads = true; bool SymbolicTree::_trackThroughGeneralRegisterLoads = true; -bool SymbolicTree::_trackThroughStackPointerRegister = true; bool SymbolicTree::_trackOnlyFlagRegisters = false; bool SymbolicTree::_simplifyAtCreation = true; unsigned SymbolicTree::_naryLimit = 3; @@ -712,7 +710,6 @@ void SymbolicTree::setToDefaultConfiguration() { _trackThroughAllocaLoads = true; _trackThroughGeneralRegisterLoads = true; - _trackThroughStackPointerRegister = true; _trackOnlyFlagRegisters = false; _simplifyAtCreation = true; _naryLimit = 3; @@ -743,11 +740,6 @@ void SymbolicTree::setTrackThroughGeneralRegisterLoads(bool b) _trackThroughGeneralRegisterLoads = b; } -void SymbolicTree::setTrackThroughStackPointerRegister(bool b) -{ - _trackThroughStackPointerRegister = b; -} - void SymbolicTree::setTrackOnlyFlagRegisters(bool b) { _trackOnlyFlagRegisters = b; diff --git a/src/bin2llvmir/optimizations/decoder/decoder.cpp b/src/bin2llvmir/optimizations/decoder/decoder.cpp index 8871b7ed2..2ac2b5222 100644 --- a/src/bin2llvmir/optimizations/decoder/decoder.cpp +++ b/src/bin2llvmir/optimizations/decoder/decoder.cpp @@ -104,8 +104,6 @@ bool Decoder::run() return false; } - SymbolicTree::setTrackThroughStackPointerRegister(false); - initTranslator(); initDryRunCsInstruction(); initEnvironment(); @@ -141,8 +139,6 @@ bool Decoder::run() initializeGpReg_mips(); - SymbolicTree::setToDefaultConfiguration(); - return false; } From e92523d9b76b7f8c57f9514fc30daa319d71f89c Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Wed, 27 Mar 2019 12:58:16 +0100 Subject: [PATCH 106/107] Arm64: Simplified and documented some code - Removed unused code from decoder/arm64.cpp - Fixed insnWrittesPcArm64 to work better - Fixed Cond branch tests --- .../optimizations/decoder/arm64.cpp | 155 +++--------------- src/capstone2llvmir/arm64/arm64.cpp | 16 +- tests/capstone2llvmir/arm64_tests.cpp | 62 ++++--- 3 files changed, 55 insertions(+), 178 deletions(-) diff --git a/src/bin2llvmir/optimizations/decoder/arm64.cpp b/src/bin2llvmir/optimizations/decoder/arm64.cpp index 850cf5aa4..968c066da 100644 --- a/src/bin2llvmir/optimizations/decoder/arm64.cpp +++ b/src/bin2llvmir/optimizations/decoder/arm64.cpp @@ -17,36 +17,25 @@ namespace bin2llvmir { bool insnWrittesPcArm64(csh& ce, cs_insn* insn) { - //auto& arm64 = insn->detail->arm64; - - return insn->id == ARM64_INS_BL; - - // TODO: Arm64 doesn't allow PC to be an explicit operand - // Create list of instructions that modify PC? - - /* - // Implicit write. - // - if (cs_reg_write(ce, insn, ARM64_REG_PC)) - { - return true; - } - - // Explicit write. - // - for (std::size_t i = 0; i < arm64.op_count; ++i) - { - auto& op = arm64.operands[i]; - if (op.type == ARM64_OP_REG - && op.reg == ARM64_REG_PC - && op.access == CS_AC_WRITE) - { - return true; - } - } - - return false; - */ + // Aarch64 reference manual states: + // Software cannot write directly to the PC. It can only + // be updated on a branch, exception entry or exception return. + + // Set of instructions that can modify PC + const std::set branch_instructions = { + ARM64_INS_B, + ARM64_INS_CBNZ, + ARM64_INS_CBZ, + ARM64_INS_TBNZ, + ARM64_INS_TBZ, + ARM64_INS_BL, + ARM64_INS_BLR, + ARM64_INS_BR, + ARM64_INS_RET, + ARM64_INS_ERET, + }; + + return (branch_instructions.count(insn->id) != 0); } bool looksLikeArm64FunctionStart(cs_insn* insn) @@ -55,59 +44,6 @@ bool looksLikeArm64FunctionStart(cs_insn* insn) return insn->id == ARM64_INS_STP; } - /* -std::size_t Decoder::decodeJumpTargetDryRun_arm64( - const JumpTarget& jt, - ByteData bytes, - bool strict) -{ - std::size_t decodedSzArm64 = 0; - auto skipArm64 = decodeJumpTargetDryRun_arm64( - jt, - bytes, - CS_MODE_ARM, - decodedSzArm64, - strict); - - std::size_t decodedSzThumb = 0; - auto skipThumb = decodeJumpTargetDryRun_arm64( - jt, - bytes, - CS_MODE_THUMB, - decodedSzThumb, - strict); - - // ARM64 ok. - // - if (skipArm64 == 0 && skipThumb) - { - jt.setMode(CS_MODE_ARM); - return skipArm64; - } - // THUMB ok. - // - else if (skipArm64 && skipThumb == 0) - { - jt.setMode(CS_MODE_THUMB); - return skipThumb; - } - // Both OK. - // - else if (skipArm64 == 0 && skipThumb == 0) - { - // Prefer ARM64. - jt.setMode(CS_MODE_ARM); - return 0; - } - // Both bad. - // - else - { - return skipArm64 < skipThumb ? skipArm64 : skipThumb; - } -} - */ - std::size_t Decoder::decodeJumpTargetDryRun_arm64( const JumpTarget& jt, ByteData bytes, @@ -119,9 +55,6 @@ std::size_t Decoder::decodeJumpTargetDryRun_arm64( return true; } - //auto basicMode = _c2l->getBasicMode(); - //if (mode != basicMode) _c2l->modifyBasicMode(mode); - static csh ce = _c2l->getCapstoneEngine(); uint64_t addr = jt.getAddress(); @@ -174,55 +107,5 @@ std::size_t Decoder::decodeJumpTargetDryRun_arm64( return true; } -/** - * Recognize some ARM64-specific patterns. - */ -void Decoder::patternsPseudoCall_arm64(llvm::CallInst*& call, AsmInstruction& ai) -{ - // TODO: We could detect this using architecture-agnostic approach by using - // ABI info on LR reg. - // - // 113A0 0F E0 A0 E1 MOV LR, PC // PC = current insn + 2*insn_size - // 113A4 03 F0 A0 E1 MOV PC, R3 // branch -> call - // 113A8 00 20 94 E5 LDR R2, [R4] // next insn = return point - // - // Check that both instructions have the same cond code: - // 112E8 0F E0 A0 11 MOVNE LR, PC - // 112EC 03 F0 A0 11 MOVNE PC, R3 - // - /* - if (_c2l->isBranchFunctionCall(call)) - { - AsmInstruction prev = ai.getPrev(); - if (prev.isInvalid()) - { - return; - } - auto* insn = ai.getCapstoneInsn(); - auto& arm64 = insn->detail->arm64; - auto* pInsn = prev.getCapstoneInsn(); - auto& pArm64 = pInsn->detail->arm64; - - if (pInsn->id == ARM64_INS_MOV - && arm64.cc == pArm64.cc - && pArm64.op_count == 2 - && pArm64.operands[0].type == ARM64_OP_REG - && pArm64.operands[0].reg == ARM64_REG_LR - && pArm64.operands[1].type == ARM64_OP_REG - && pArm64.operands[1].reg == ARM64_REG_PC) - { - // Replace pseudo branch with pseudo call. - auto* nc = CallInst::Create( - _c2l->getCallFunction(), - {call->getArgOperand(0)}, - "", - call); - call->eraseFromParent(); - call = nc; - } - } - */ -} - } // namespace bin2llvmir } // namespace retdec diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index a0702ab3b..651fbe9c9 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -659,10 +659,11 @@ llvm::Value* Capstone2LlvmIrTranslatorArm64_impl::loadRegister( return nullptr; } + // There is no such instruction that can access PC, but in case + // it happens somewhere in LLVM, we should be able to handle it. if (r == ARM64_REG_PC) { return getCurrentPc(_insn); - // TODO: Check } auto* rt = getRegisterType(r); @@ -757,10 +758,11 @@ llvm::Instruction* Capstone2LlvmIrTranslatorArm64_impl::storeRegister( return nullptr; } + // Direct writes to PC are not supported, the intended way to alter control flow is to + // use a branching instruction or exception, those will call pseudo llvm pseudo functions if (r == ARM64_REG_PC) { return nullptr; - // TODO: Check? } if (r == ARM64_REG_XZR || r == ARM64_REG_WZR) @@ -1269,7 +1271,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateMovk(cs_insn* i, cs_arm64* ai * ARM64_INS_STR, ARM64_INS_STRB, ARM64_INS_STRH * ARM64_INS_STUR, ARM64_INS_STURB, ARM64_INS_STURH * ARM64_INS_STTR, ARM64_INS_STTRB, ARM64_INS_STTRH - * TODO: Prob pseudo! ARM64_INS_STXR, ARM64_INS_STXRB, ARM64_INS_STXRH + * ARM64_INS_STXR, ARM64_INS_STXRB, ARM64_INS_STXRH -- Maybe those should be pseudo */ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1358,7 +1360,7 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateStr(cs_insn* i, cs_arm64* ai, /** * ARM64_INS_STP, ARM64_INS_STNP - * TODO: prob Pseudo! ARM64_INS_STXP + * ARM64_INS_STXP -- Maybe should be pseudo */ void Capstone2LlvmIrTranslatorArm64_impl::translateStp(cs_insn* i, cs_arm64* ai, llvm::IRBuilder<>& irb) { @@ -1891,9 +1893,6 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateCondOp(cs_insn* i, cs_arm64* case ARM64_INS_CNEG: val = generateValueNegate(bodyElse, op1); val = bodyElse.CreateAdd(val, llvm::ConstantInt::get(val->getType(), 1)); - //TODO: Express this as: (zero - op1) ? - //llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); - //val = irb.CreateSub(zero, val); break; default: throw GenericError("translateCondOp: Instruction id error"); @@ -1933,9 +1932,6 @@ void Capstone2LlvmIrTranslatorArm64_impl::translateCondSelOp(cs_insn* i, cs_arm6 case ARM64_INS_CSNEG: val = generateValueNegate(bodyElse, op2); val = bodyElse.CreateAdd(val, llvm::ConstantInt::get(val->getType(), 1)); - //TODO: Express this as: (zero - op2) ? - //llvm::Value* zero = llvm::ConstantInt::get(val->getType(), 0); - //val = irb.CreateSub(zero, val); break; default: throw GenericError("translateCondSelOp: Instruction id error"); diff --git a/tests/capstone2llvmir/arm64_tests.cpp b/tests/capstone2llvmir/arm64_tests.cpp index 83fbf7c70..b1aacd628 100644 --- a/tests/capstone2llvmir/arm64_tests.cpp +++ b/tests/capstone2llvmir/arm64_tests.cpp @@ -4294,17 +4294,37 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_B) }); } -TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_B_cond) +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_B_cond_true) { + setRegisters({ + {ARM64_REG_CPSR_Z, false}, + }); + emulate("b.ne #0x110d8", 0x1107C); EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_Z}); EXPECT_NO_REGISTERS_STORED(); EXPECT_NO_MEMORY_LOADED_STORED(); - // TODO: How to test this? - //EXPECT_JUST_VALUES_CALLED({ - // {_translator->getCondBranchFunction(), {0x110d8}}, - //}); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {true, 0x110d8}}, + }); +} + +TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_B_cond_false) +{ + setRegisters({ + {ARM64_REG_CPSR_N, true}, + {ARM64_REG_CPSR_V, false}, + }); + + emulate("b.ge #0x110d8", 0x1107C); + + EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_CPSR_N, ARM64_REG_CPSR_V}); + EXPECT_NO_REGISTERS_STORED(); + EXPECT_NO_MEMORY_LOADED_STORED(); + EXPECT_JUST_VALUES_CALLED({ + {_translator->getCondBranchFunction(), {false, 0x110d8}}, + }); } // @@ -6758,28 +6778,6 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCMP_d_d_lt) EXPECT_NO_VALUE_CALLED(); } -/* TODO: Check Ordered vs Unordered -TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FCMP_d_d_NAN) -{ - setRegisters({ - {ARM64_REG_D1, NAN}, - {ARM64_REG_D2, NAN}, - }); - - emulate("fcmp d1, d2"); - - EXPECT_JUST_REGISTERS_LOADED({ARM64_REG_D1, ARM64_REG_D2}); - EXPECT_JUST_REGISTERS_STORED({ - {ARM64_REG_CPSR_N, false}, - {ARM64_REG_CPSR_Z, false}, - {ARM64_REG_CPSR_C, true}, - {ARM64_REG_CPSR_V, true}, - }); - EXPECT_NO_MEMORY_LOADED_STORED(); - EXPECT_NO_VALUE_CALLED(); -} -*/ - // // ARM64_INS_FCCMP // @@ -8106,7 +8104,7 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FSUB_d_d_d_neg) EXPECT_NO_VALUE_CALLED(); } -/* TODO: Check why those tests are failing +/* // // ARM64_INS_FSQRT // @@ -8143,10 +8141,10 @@ TEST_P(Capstone2LlvmIrTranslatorArm64Tests, ARM64_INS_FSQRT_d_d) {ARM64_REG_D0, ANY}, }); EXPECT_NO_MEMORY_LOADED_STORED(); - EXPECT_NO_VALUE_CALLED(); - //EXPECT_VALUES_CALLED({ - // {_module.getFunction("llvm.fsqrt.f64"), {32.40_f64}}, - //}); + //EXPECT_NO_VALUE_CALLED(); + EXPECT_VALUES_CALLED({ + {_module.getFunction("llvm.fsqrt.f64"), {32.40_f64}}, + }); } */ From aa97f928a0b3ef6d45638c902fd4bbd51fe810cc Mon Sep 17 00:00:00 2001 From: Matej Kastak Date: Wed, 27 Mar 2019 22:40:46 +0100 Subject: [PATCH 107/107] Arm64: Fixed documentation build --- src/capstone2llvmir/arm64/arm64.cpp | 2 +- src/capstone2llvmir/arm64/arm64_impl.h | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/capstone2llvmir/arm64/arm64.cpp b/src/capstone2llvmir/arm64/arm64.cpp index 651fbe9c9..ab8997b74 100644 --- a/src/capstone2llvmir/arm64/arm64.cpp +++ b/src/capstone2llvmir/arm64/arm64.cpp @@ -967,7 +967,7 @@ bool Capstone2LlvmIrTranslatorArm64_impl::isFPRegister(cs_arm64_op& op, bool onl bool Capstone2LlvmIrTranslatorArm64_impl::isVectorRegister(cs_arm64_op& op) const { - return op.type == ARM64_OP_REG && op.reg >= ARM64_REG_V0 && op.reg <= ARM64_REG_V31; + return op.type == ARM64_OP_REG && op.reg >= ARM64_REG_V0 && op.reg <= ARM64_REG_V31; } uint8_t Capstone2LlvmIrTranslatorArm64_impl::getOperandAccess(cs_arm64_op& op) diff --git a/src/capstone2llvmir/arm64/arm64_impl.h b/src/capstone2llvmir/arm64/arm64_impl.h index 1334e834e..8bebcf1d8 100644 --- a/src/capstone2llvmir/arm64/arm64_impl.h +++ b/src/capstone2llvmir/arm64/arm64_impl.h @@ -158,10 +158,17 @@ class Capstone2LlvmIrTranslatorArm64_impl : bool isCondIns(cs_arm64 * i) const; /** - * @brief Return if register is FP type. + * @brief Check if register is FP type. + * @param op Capstone operand type to check. * @param onlySupported Account only for supported registers in retdec. */ bool isFPRegister(cs_arm64_op& op, bool onlySupported = true) const; + + /** + * @brief Check if register is Vector type. + * This is true for all ARM64_REG_V* registers. + * @param op Capstone operand type to check. + */ bool isVectorRegister(cs_arm64_op& op) const; virtual bool isOperandRegister(cs_arm64_op& op) override; @@ -173,6 +180,7 @@ class Capstone2LlvmIrTranslatorArm64_impl : // protected: + /// Mapping from register to its parent register std::map _reg2parentMap; static std::map<