Skip to content

Commit

Permalink
Merge branch 'arm64'
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterMatula committed May 29, 2019
2 parents 1bda328 + fd3ee25 commit 3905f47
Show file tree
Hide file tree
Showing 41 changed files with 14,354 additions and 77 deletions.
3 changes: 2 additions & 1 deletion deps/capstone/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ else()
-DCAPSTONE_MIPS_SUPPORT=ON
-DCAPSTONE_PPC_SUPPORT=ON
-DCAPSTONE_X86_SUPPORT=ON
-DCAPSTONE_ARM64_SUPPORT=ON
# Disabled architectures.
-DCAPSTONE_ARM64_SUPPORT=OFF
-DCAPSTONE_M68K_SUPPORT=OFF
-DCAPSTONE_SPARC_SUPPORT=OFF
-DCAPSTONE_SYSZ_SUPPORT=OFF
Expand Down Expand Up @@ -102,5 +102,6 @@ ExternalProject_Get_Property(capstone-project binary_dir)
add_library(capstone INTERFACE)
add_dependencies(capstone capstone-project)
target_include_directories(capstone SYSTEM INTERFACE ${source_dir}/include)
target_include_directories(capstone SYSTEM INTERFACE ${source_dir}/arch)
target_link_libraries(capstone INTERFACE debug ${binary_dir}/${DEBUG_DIR}${CMAKE_STATIC_LIBRARY_PREFIX}capstone${CMAKE_STATIC_LIBRARY_SUFFIX})
target_link_libraries(capstone INTERFACE optimized ${binary_dir}/${RELEASE_DIR}${CMAKE_STATIC_LIBRARY_PREFIX}capstone${CMAKE_STATIC_LIBRARY_SUFFIX})
9 changes: 9 additions & 0 deletions include/retdec/bin2llvmir/optimizations/decoder/decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,15 @@ 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);
void patternsPseudoCall_arm64(llvm::CallInst*& call, AsmInstruction& pAi);

// MIPS specific.
//
private:
Expand Down
4 changes: 4 additions & 0 deletions include/retdec/bin2llvmir/optimizations/syscalls/syscalls.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
35 changes: 35 additions & 0 deletions include/retdec/capstone2llvmir/arm64/arm64.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @file include/retdec/capstone2llvmir/arm64/arm64.h
* @brief ARM64 specialization of translator's abstract public interface.
* @copyright (c) 2018 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() {};

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
} // namespace retdec

#endif /* RETDEC_CAPSTONE2LLVMIR_ARM64_ARM64_H */
21 changes: 21 additions & 0 deletions include/retdec/capstone2llvmir/arm64/arm64_defs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @file include/retdec/capstone2llvmir/arm64/arm64_defs.h
* @brief Additional (on top of Capstone) definitions for ARM64 translator.
* @copyright (c) 2018 Avast Software, licensed under the MIT license
*/

#ifndef RETDEC_CAPSTONE2LLVMIR_ARM64_ARM64_DEFS_H
#define RETDEC_CAPSTONE2LLVMIR_ARM64_ARM64_DEFS_H

#include <capstone/arm64.h>

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 */
1 change: 1 addition & 0 deletions include/retdec/capstone2llvmir/capstone2llvmir.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
7 changes: 5 additions & 2 deletions include/retdec/config/architecture.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -51,6 +52,8 @@ class Architecture
void setIsPic32();
void setIsArm();
void setIsThumb();
void setIsArm32();
void setIsArm64();
void setIsX86();
void setIsPpc();
void setIsEndianLittle();
Expand Down Expand Up @@ -84,7 +87,6 @@ class Architecture
MIPS,
PIC32,
ARM,
THUMB,
X86,
PPC,
};
Expand All @@ -97,6 +99,7 @@ class Architecture
private:
std::string _name;
unsigned _bitSize = 32;
bool _thumbFlag = false;
eEndian _endian = E_UNKNOWN;
eArch _arch = eArch::UNKNOWN;
};
Expand Down
15 changes: 9 additions & 6 deletions scripts/retdec-decompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ def parse_args(args):
parser.add_argument('-a', '--arch',
dest='arch',
metavar='ARCH',
choices=['mips', 'pic32', 'arm', 'thumb', 'powerpc', 'x86', 'x86-64'],
help='Specify target architecture [mips|pic32|arm|thumb|powerpc|x86|x86-64].'
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',
Expand Down Expand Up @@ -894,7 +894,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)
Expand All @@ -917,7 +920,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', 'x86-64']:
ords_dir = config.X86_ORDS_DIR
Expand All @@ -929,7 +932,7 @@ def decompile(self):

self._cleanup()
utils.print_error('Unsupported target architecture \'%s\'. Supported architectures: '
'Intel x86, Intel x86-64, ARM, ARM + Thumb, 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.
Expand All @@ -947,7 +950,7 @@ def decompile(self):
return 1

# TODO this should be somehow connected somewhere else
if fileclass == '64' and self.arch in ['arm', 'mips', 'pic32', 'powerpc', 'x86']:
if fileclass == '64' and self.arch in ['mips', 'pic32', 'powerpc']:
if self.args.generate_log:
self.generate_log()

Expand Down
2 changes: 2 additions & 0 deletions src/bin2llvmir/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,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
Expand Down Expand Up @@ -65,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
Expand Down
2 changes: 1 addition & 1 deletion src/bin2llvmir/optimizations/constants/constants.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ void ConstantsAnalysis::checkForGlobalInInstruction(
auto* maxC = max ? dyn_cast_or_null<ConstantInt>(max->value) : nullptr;
Instruction* userI = max ? dyn_cast_or_null<Instruction>(max->user) : nullptr;

if (max && maxC && maxC->getZExtValue() != 0)
if (max && maxC && maxC->getValue().getActiveBits() <= 64 && maxC->getZExtValue() != 0)
if (userI || max == &root)
if (_image->getImage()->hasDataOnAddress(maxC->getZExtValue()))
{
Expand Down
111 changes: 111 additions & 0 deletions src/bin2llvmir/optimizations/decoder/arm64.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* @file src/bin2llvmir/optimizations/decoder/arm64.cpp
* @brief Decoding methods specific to ARM64 architecture.
* @copyright (c) 2018 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)
{
// 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<unsigned int> 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)
{
// 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,
bool strict)
{

if (strict)
{
return true;
}

static csh ce = _c2l->getCapstoneEngine();

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

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)
{
return nops;
}

if (_c2l->isControlFlowInstruction(*_dryCsInsn)
|| insnWrittesPcArm64(ce, _dryCsInsn))
{
return false;
}

first = false;
}

if (nops > 0)
{
return nops;
}

// There is a BB right after, that is not a function start.
//
if (getBasicBlockAtAddress(addr) && getFunctionAtAddress(addr) == nullptr)
{
return false;
}

return true;
}

} // namespace bin2llvmir
} // namespace retdec
12 changes: 8 additions & 4 deletions src/bin2llvmir/optimizations/decoder/decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,10 +376,14 @@ 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);
}
else if (_config->getConfig().architecture.isArm64())
{
return decodeJumpTargetDryRun_arm64(jt, bytes, strict);
}
else if (_config->getConfig().architecture.isMipsOrPic32())
{
return decodeJumpTargetDryRun_mips(jt, bytes, strict);
Expand All @@ -400,7 +404,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);
}
Expand Down Expand Up @@ -472,7 +476,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);
Expand Down Expand Up @@ -1554,7 +1558,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<StoreInst>(i))
{
Expand Down
Loading

0 comments on commit 3905f47

Please sign in to comment.