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

Armv7 support #178

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_*
19 changes: 19 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ include(cmake/variables.cmake)
add_library(maat_maat
src/arch/arch_EVM.cpp
src/arch/arch_X86.cpp
src/arch/arch_ARM32.cpp
src/arch/lifter.cpp
src/arch/register_aliases.cpp
src/engine/callother.cpp
Expand Down Expand Up @@ -180,15 +181,33 @@ 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_files(ARM ARM32 ARM7_le ARMt)
maat_sleigh_compile_files(ARM THUMB32 ARM7_le ARMtTHUMB)

# 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_ARM32
maat_sleigh_spec_THUMB32
)

# 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, "ARM32", PyLong_FromLong((int)Arch::Type::ARM32));

PyObject* arch_class = create_class(PyUnicode_FromString("ARCH"), PyTuple_New(0), arch_enum);
PyModule_AddObject(module, "ARCH", arch_class);
Expand Down
118 changes: 118 additions & 0 deletions src/arch/arch_ARM32.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
/*
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 ARM32
{
ArchARM32::ArchARM32(): Arch(Arch::Type::ARM32, 32, ARM32::NB_REGS)
{
available_modes = {CPUMode::A32,CPUMode::T32};
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},
{"fp", FP},
{"ip", IP},
{"sp", SP},
{"lr", LR},
{"pc", PC},
{"cpsr", CPSR},
{"nf", NF},
{"zf", ZF},
{"cf", CF},
{"vf", VF},
{"qf", QF},
{"jf", JF},
{"ge1", GE1},
{"ge2", GE2},
{"ge3", GE3},
{"ge4", GE4},
{"tf", TF},
{"sc", SC},
{"ISAModeSwitch", ISAModeSwitch}
};
}

size_t ArchARM32::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 CPSR:
case mult_addr:
return 32;
case mult_dat8:
return 64;
case mult_dat16:
return 128;
case NF:
case ZF:
case CF:
case VF:
case QF:
case JF:
case GE1:
case GE2:
case GE3:
case GE4:
case TF:
case SC:
case ISAModeSwitch:
return 8;
default:
throw runtime_exception("ArchARM32::reg_size(): got unsupported reg num");
}
}

reg_t ArchARM32::sp() const
{
return ARM32::SP;
}

reg_t ArchARM32::pc() const
{
return ARM32::PC;
}

reg_t ArchARM32::tsc() const
{
throw runtime_exception("ArchARM32::tsc(): method not available");
}
} // namespace ARM32
} // namespace maat
12 changes: 12 additions & 0 deletions src/arch/lifter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ Lifter::Lifter(CPUMode m): mode(m)
pspecfile = config.find_sleigh_file("EVM.pspec");
arch = Arch::Type::EVM;
}
else if (mode == CPUMode::A32)
{
slafile = config.find_sleigh_file("ARM7_le.sla");
pspecfile = config.find_sleigh_file("ARMt.pspec");
arch = Arch::Type::ARM32;
}
else if (mode == CPUMode::T32)
{
slafile = config.find_sleigh_file("ARM7_le.sla");
pspecfile = config.find_sleigh_file("ARMtTHUMB.pspec");
arch = Arch::Type::ARM32;
}
else
{
throw lifter_exception("Lifter: this CPU mode is not supported");
Expand Down
57 changes: 56 additions & 1 deletion src/arch/register_aliases.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,55 @@ Value x64_alias_getter(CPUContext& ctx, ir::reg_t reg)

std::set x64_aliases{X64::RFLAGS};

void arm32_alias_setter(CPUContext& ctx, ir::reg_t reg, const Value& val)
{
if (reg == ARM32::CPSR)
{
_set_flag_from_bit(ctx, ARM32::TF, val, 5);
_set_flag_from_bit(ctx, ARM32::GE1, val, 16);
_set_flag_from_bit(ctx, ARM32::GE2, val, 17);
_set_flag_from_bit(ctx, ARM32::GE3, val, 18);
_set_flag_from_bit(ctx, ARM32::GE4, val, 19);
_set_flag_from_bit(ctx, ARM32::JF, val, 24);
_set_flag_from_bit(ctx, ARM32::QF, val, 27);
_set_flag_from_bit(ctx, ARM32::VF, val, 28);
_set_flag_from_bit(ctx, ARM32::CF, val, 29);
_set_flag_from_bit(ctx, ARM32::ZF, val, 30);
_set_flag_from_bit(ctx, ARM32::NF, val, 31);
}
else
throw runtime_exception("arm32_alias_setter: got unsupported register");
}

Value arm32_alias_getter(CPUContext& ctx, ir::reg_t reg)
{
Value res;
if (reg == ARM32::CPSR)
{

res = Value(5,0);
res.set_concat(extract(ctx.get(ARM32::TF),0,0), res);
res.set_concat(Value(10,0), res);
res.set_concat(extract(ctx.get(ARM32::GE1),0,0), res);
res.set_concat(extract(ctx.get(ARM32::GE2),0,0), res);
res.set_concat(extract(ctx.get(ARM32::GE3),0,0), res);
res.set_concat(extract(ctx.get(ARM32::GE4),0,0), res);
res.set_concat(Value(4,0), res);
res.set_concat(extract(ctx.get(ARM32::JF),0,0), res);
res.set_concat(Value(2,0), res);
res.set_concat(extract(ctx.get(ARM32::QF),0,0), res);
res.set_concat(extract(ctx.get(ARM32::VF),0,0), res);
res.set_concat(extract(ctx.get(ARM32::CF),0,0), res);
res.set_concat(extract(ctx.get(ARM32::ZF),0,0), res);
res.set_concat(extract(ctx.get(ARM32::NF),0,0), res);
}
else
throw runtime_exception("arm32_alias_getter: got unsupported register");
return res;
}

std::set arm32_aliases{ARM32::CPSR};

void CPUContext::init_alias_getset(Arch::Type arch)
{
if (arch == Arch::Type::X86)
Expand All @@ -150,7 +199,13 @@ void CPUContext::init_alias_getset(Arch::Type arch)
alias_getter = x64_alias_getter;
aliased_regs = x64_aliases;
}
else if (arch == Arch::Type::ARM32)
{
alias_setter = arm32_alias_setter;
alias_getter = arm32_alias_getter;
aliased_regs = arm32_aliases;
}
}

} // namespace ir
} // namespace maat
} // namespace maat
43 changes: 43 additions & 0 deletions src/engine/callother.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ 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::ARM32:
if (mnemonic == "swi") return Id::ARM32_SC;
default:
break;
}
Expand Down Expand Up @@ -1041,6 +1043,45 @@ void EVM_LOG_handler(MaatEngine& engine, const ir::Inst& inst, ir::ProcessedInst
}
}

/*
System call for ARM32.
The syscalls are untested and don't work
*/
void ARM32_SC_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(ARM32::R7);
if (sys_num.is_symbolic(*engine.vars))
{
throw callother_exception("SWI 0x0: 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::ARM32_SYSCALL::instance()))
{
case env::Action::CONTINUE:
break;
case env::Action::ERROR:
throw callother_exception(
"SWI 0x0: Emulation callback signaled an error, SWI is untested and might not work!!"
);
}
}
catch(const env_exception& e)
{
throw callother_exception(
Fmt() << "SWI 0x0: " << e.what() >> Fmt::to_str
);
}
}

/// Return the default handler map for CALLOTHER occurences
HandlerMap default_handler_map()
{
Expand Down Expand Up @@ -1083,6 +1124,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::ARM32_SC, ARM32_SC_handler);

return h;
}

Expand Down
39 changes: 39 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::ARM32:
arch = std::make_shared<ARM32::ArchARM32>();
lifters[CPUMode::A32] = std::make_shared<Lifter>(CPUMode::A32);
_current_cpu_mode = CPUMode::A32;
break;
case Arch::Type::NONE:
arch = std::make_shared<ArchNone>();
_current_cpu_mode = CPUMode::NONE;
Expand Down Expand Up @@ -74,6 +79,24 @@ MaatEngine::MaatEngine(Arch::Type _arch, env::OS os): env(nullptr), _uid(++_uid_
#endif
}

void MaatEngine::change_mode(CPUMode _arch)
{
// switch current_CPU_Mode
switch (_arch)
{
case CPUMode::A32:
lifters[CPUMode::A32] = std::make_shared<Lifter>(CPUMode::A32);
_current_cpu_mode = CPUMode::A32;
break;
case CPUMode::T32:
lifters[CPUMode::T32] = std::make_shared<Lifter>(CPUMode::T32);
_current_cpu_mode = CPUMode::T32;
break;
default:
throw runtime_exception("MaatEngine(): Can't swap modes for this architecture");
}
}

MaatEngine::MaatEngine(
const MaatEngine& other,
std::set<std::string>& duplicate,
Expand Down Expand Up @@ -282,6 +305,22 @@ info::Stop MaatEngine::run(int max_inst)
}
_previous_halt_before_exec = -1;

// If Arch == ARM32 then check if mode needs to change
if (arch->type == Arch::Type::ARM32)
{
// Change CPU mode if TF bit is set
switch (cpu.ctx().get(ARM32::TF).as_uint())
{
case 0:
if (_current_cpu_mode != CPUMode::A32)
change_mode(CPUMode::A32);
break;
case 1:
if (_current_cpu_mode != CPUMode::T32)
change_mode(CPUMode::T32);
break;
}
}
// TODO: periodically increment tsc() ?

// Get the PCODE IR
Expand Down
Loading
Loading