Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Aarch64 support #179

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ cmake-build-*/
prefix/
CMakeLists.txt.user
CMakeUserPresets.json
maat_state_*
maat_state_*
17 changes: 17 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ include(cmake/variables.cmake)
# ---- Declare library ----

add_library(maat_maat
src/arch/arch_ARM64.cpp
src/arch/arch_EVM.cpp
src/arch/arch_X86.cpp
src/arch/lifter.cpp
Expand Down Expand Up @@ -180,15 +181,31 @@ macro(maat_sleigh_compile ARCH_DIR ARCH)
configure_file("${spec_dir}/${ARCH_DIR}/data/languages/${ARCH}.pspec" "${spec_out_dir}/${ARCH}.pspec")
endmacro()

macro(maat_sleigh_compile_files ARCH_DIR ARCH SLASPEC PSPEC)
# ARCH_DIR is the directory that appears in Ghidra's source code hierarchy
# ARCH appears in the name of the '.slaspec' and '.pspec' file (they should be the same)
# Creates a target maat_sleigh_spec_${ARCH}
sleigh_compile(
TARGET maat_sleigh_spec_${ARCH}
COMPILER "${maat_SLEIGH_COMPILER}"
SLASPEC "${spec_dir}/${ARCH_DIR}/data/languages/${SLASPEC}.slaspec"
LOG_FILE "${PROJECT_BINARY_DIR}/sleigh-log/${ARCH}.log"
OUT_FILE "${spec_out_dir}/${SLASPEC}.sla"
)
configure_file("${spec_dir}/${ARCH_DIR}/data/languages/${PSPEC}.pspec" "${spec_out_dir}/${PSPEC}.pspec")
endmacro()

maat_sleigh_compile(x86 x86-64)
maat_sleigh_compile(x86 x86)
maat_sleigh_compile(EVM EVM)
maat_sleigh_compile(AARCH64 AARCH64)

# All of the sla spec targets are combined into this one
add_custom_target(maat_all_sla_specs DEPENDS
maat_sleigh_spec_x86-64
maat_sleigh_spec_x86
maat_sleigh_spec_EVM
maat_sleigh_spec_AARCH64
)

# Add sla specs as dependencies to our targets
Expand Down
1 change: 1 addition & 0 deletions bindings/python/py_arch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ void init_arch(PyObject* module)
PyDict_SetItemString(arch_enum, "X86", PyLong_FromLong((int)Arch::Type::X86));
PyDict_SetItemString(arch_enum, "X64", PyLong_FromLong((int)Arch::Type::X64));
PyDict_SetItemString(arch_enum, "EVM", PyLong_FromLong((int)Arch::Type::EVM));
PyDict_SetItemString(arch_enum, "ARM64", PyLong_FromLong((int)Arch::Type::ARM64));

PyObject* arch_class = create_class(PyUnicode_FromString("ARCH"), PyTuple_New(0), arch_enum);
PyModule_AddObject(module, "ARCH", arch_class);
Expand Down
197 changes: 197 additions & 0 deletions src/arch/arch_ARM64.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
/*
Commonwealth of Australia represented by the Department of Defence

Produced by Nathan Do, Student Intern at DSTG (Defence Science and Technology Group)
*/

#include "maat/arch.hpp"
#include "maat/exception.hpp"
#include "maat/cpu.hpp"

namespace maat
{
namespace ARM64
{
ArchARM64::ArchARM64(): Arch(Arch::Type::ARM64, 64, ARM64::NB_REGS)
{
available_modes = {CPUMode::A64};
reg_map =
{
{"r0", R0},
{"r1", R1},
{"r2", R2},
{"r3", R3},
{"r4", R4},
{"r5", R5},
{"r6", R6},
{"r7", R7},
{"r8", R8},
{"r9", R9},
{"r10", R10},
{"r11", R11},
{"r12", R12},
{"r13", R13},
{"r14", R14},
{"r15", R15},
{"r16", R16},
{"r17", R17},
{"r18", R18},
{"r19", R19},
{"r20", R20},
{"r21", R21},
{"r22", R22},
{"r23", R23},
{"r24", R24},
{"r25", R25},
{"r26", R26},
{"r27", R27},
{"r28", R28},
{"r29", R29},
{"r30", R30},
{"lr", LR},
{"v0", V0},
{"v1", V1},
{"v2", V2},
{"v3", V3},
{"v4", V4},
{"v5", V5},
{"v6", V6},
{"v7", V7},
{"v8", V8},
{"v9", V9},
{"v10", V10},
{"v11", V11},
{"v12", V12},
{"v13", V13},
{"v14", V14},
{"v15", V15},
{"v16", V16},
{"v17", V17},
{"v18", V18},
{"v19", V19},
{"v20", V20},
{"v21", V21},
{"v22", V22},
{"v23", V23},
{"v24", V24},
{"v25", V25},
{"v26", V26},
{"v27", V27},
{"v28", V28},
{"v29", V29},
{"v30", V30},
{"v31", V31},
{"zr", ZR},
{"pc", PC},
{"sp", SP},
{"pstate",PSTATE},
{"zf", ZF},
{"nf", NF},
{"cf", CF},
{"vf", VF},
{"cntpct_el0", CNTPCT_EL0}
};
}

size_t ArchARM64::reg_size(reg_t reg_num) const
{
switch (reg_num) {
case R0:
case R1:
case R2:
case R3:
case R4:
case R5:
case R6:
case R7:
case R8:
case R9:
case R10:
case R11:
case R12:
case R13:
case R14:
case R15:
case R16:
case R17:
case R18:
case R19:
case R20:
case R21:
case R22:
case R23:
case R24:
case R25:
case R26:
case R27:
case R28:
case R29:
case R30:
case ZR:
case PC:
case SP:
case PSTATE:
case SPSR:
case ELR:
case CNTPCT_EL0:
return 64;
case V0:
case V1:
case V2:
case V3:
case V4:
case V5:
case V6:
case V7:
case V8:
case V9:
case V10:
case V11:
case V12:
case V13:
case V14:
case V15:
case V16:
case V17:
case V18:
case V19:
case V20:
case V21:
case V22:
case V23:
case V24:
case V25:
case V26:
case V27:
case V28:
case V29:
case V30:
case V31:
return 128;
case ZF:
case NF:
case CF:
case VF:
return 8;
default:
throw runtime_exception("ArchARM64::reg_size(): got unsupported reg num");
}
}

reg_t ArchARM64::sp() const
{
return ARM64::SP;
}

reg_t ArchARM64::pc() const
{
return ARM64::PC;
}

reg_t ArchARM64::tsc() const
{
throw runtime_exception("ArchARM64::tsc(): method not available");
}
} // namespace ARM64

} // namespace maat
6 changes: 6 additions & 0 deletions src/arch/lifter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ Lifter::Lifter(CPUMode m): mode(m)
pspecfile = config.find_sleigh_file("EVM.pspec");
arch = Arch::Type::EVM;
}
else if (mode == CPUMode::A64)
{
slafile = config.find_sleigh_file("AARCH64.sla");
pspecfile = config.find_sleigh_file("AARCH64.pspec");
arch = Arch::Type::ARM64;
}
else
{
throw lifter_exception("Lifter: this CPU mode is not supported");
Expand Down
62 changes: 62 additions & 0 deletions src/engine/callother.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ Id mnemonic_to_id(const std::string& mnemonic, Arch::Type arch)
if (mnemonic == "STACK_PUSH") return Id::EVM_STACK_PUSH;
if (mnemonic == "STACK_POP") return Id::EVM_STACK_POP;
break;
case Arch::Type::ARM64:
if (mnemonic == "udf") return Id::AARCH64_UDF;
if (mnemonic == "svc") return Id::AARCH64_SVC;
break;
default:
break;
}
Expand Down Expand Up @@ -1041,6 +1045,62 @@ void EVM_LOG_handler(MaatEngine& engine, const ir::Inst& inst, ir::ProcessedInst
}
}

/*
System call for AARCH.
The syscalls are untested and don't work
*/
void AARCH64_SVC_handler(MaatEngine& engine, const ir::Inst& inst, ir::ProcessedInst& pinst)
{
engine.log.warning("System Call is untested and might not work!!");
// Get syscall number
const Value& sys_num = engine.cpu.ctx().get(ARM64::R8);
if (sys_num.is_symbolic(*engine.vars))
{
throw callother_exception("SVC #0: syscall number is symbolic!");
}
// Get function to emulate syscall`
try
{
const env::Function& func = engine.env->get_syscall_func_by_num(
sys_num.as_uint(*engine.vars)
);

// Execute function callback
switch (func.callback().execute(engine, env::abi::AARCH64_SVC::instance()))
{
case env::Action::CONTINUE:
break;
case env::Action::ERROR:
throw callother_exception(
"SVC #0: Emulation callback signaled an error, SVC is untested and might not work!!"
);
}
}
catch(const env_exception& e)
{
throw callother_exception(
Fmt() << "SVC #0: " << e.what() >> Fmt::to_str
);
}
}
/*
Permanently Undefined generates an Undefined Instruction exception.
The encodings for UDF used in this section are defined as permanently undefined in the ARMv8-A architecture.
x86 has a similar instruction UD2 for undefined instructions. This indicates that the processor encountered an invalid instruction
*/
void AARCH64_UDF_handler(MaatEngine& engine, const ir::Inst& inst, ir::ProcessedInst& pinst)
{
// UDF Does nothing
engine.log.warning(
Fmt() << "LOG"
<< ": UDF instruction called, UDF does nothing. UDF stands for (Undefined)"
>> Fmt::to_str
);
throw callother_exception(
"UDF instruction: Emulation callback signaled an error"
);
}

/// Return the default handler map for CALLOTHER occurences
HandlerMap default_handler_map()
{
Expand Down Expand Up @@ -1083,6 +1143,8 @@ HandlerMap default_handler_map()
h.set_handler(Id::EVM_SELFDESTRUCT, EVM_SELFDESTRUCT_handler);
h.set_handler(Id::EVM_LOG, EVM_LOG_handler);

h.set_handler(Id::AARCH64_UDF, AARCH64_UDF_handler);
h.set_handler(Id::AARCH64_SVC, AARCH64_SVC_handler);
return h;
}

Expand Down
5 changes: 5 additions & 0 deletions src/engine/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ MaatEngine::MaatEngine(Arch::Type _arch, env::OS os): env(nullptr), _uid(++_uid_
env = std::make_shared<env::EVM::EthereumEmulator>();
endianness = Endian::BIG;
break;
case Arch::Type::ARM64:
arch = std::make_shared<ARM64::ArchARM64>();
lifters[CPUMode::A64] = std::make_shared<Lifter>(CPUMode::A64);
_current_cpu_mode = CPUMode::A64;
break;
case Arch::Type::NONE:
arch = std::make_shared<ArchNone>();
_current_cpu_mode = CPUMode::NONE;
Expand Down
Loading