Skip to content

Commit

Permalink
Implemented AARCH64 disassembler functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexandro Sanchez Bach authored and AlexAltea committed May 15, 2017
1 parent 7e3a303 commit 6743049
Show file tree
Hide file tree
Showing 6 changed files with 339 additions and 13 deletions.
300 changes: 300 additions & 0 deletions disasm-aarch64.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
#include <capstone/capstone.h>

#include "disasm-aarch64.h"
#include "log.h"


static int
is_cs_nop_ins(cs_insn *ins)
{
switch(ins->id) {
case ARM64_INS_NOP:
return 1;
default:
return 0;
}
}


static int
is_cs_trap_ins(cs_insn *ins)
{
switch(ins->id) {
/* XXX: todo */
default:
return 0;
}
}


static int
is_cs_cflow_group(uint8_t g)
{
return (g == CS_GRP_JUMP) || (g == CS_GRP_CALL) || (g == CS_GRP_RET) || (g == CS_GRP_IRET);
}


static int
is_cs_cflow_ins(cs_insn *ins)
{
size_t i;

for(i = 0; i < ins->detail->groups_count; i++) {
if(is_cs_cflow_group(ins->detail->groups[i])) {
return 1;
}
}

return 0;
}

static int
is_cs_call_ins(cs_insn *ins)
{
switch(ins->id) {
case ARM64_INS_BL:
case ARM64_INS_BLR:
return 1;
default:
return 0;
}
}


static int
is_cs_ret_ins(cs_insn *ins)
{
/* ret */
if(ins->id == ARM64_INS_RET) {
return 1;
}

return 0;
}


static int
is_cs_unconditional_jmp_ins(cs_insn *ins)
{
switch(ins->id) {
case ARM64_INS_B:
if (ins->detail->arm64.cc == ARM64_CC_AL) {
return 1;
}
return 0;
default:
return 0;
}
}


static int
is_cs_conditional_cflow_ins(cs_insn *ins)
{
switch(ins->id) {
case ARM64_INS_B:
if (ins->detail->arm64.cc != ARM64_CC_AL) {
return 1;
}
return 0;
case ARM64_INS_CBNZ:
case ARM64_INS_CBZ:
case ARM64_INS_TBNZ:
case ARM64_INS_TBZ:
return 1;
default:
return 0;
}
}


static int
is_cs_privileged_ins(cs_insn *ins)
{
switch(ins->id) {
/* XXX: todo */
default:
return 0;
}
}


static uint8_t
cs_to_nucleus_op_type(arm64_op_type op)
{
switch(op) {
case ARM64_OP_REG:
return Operand::OP_TYPE_REG;
case ARM64_OP_IMM:
return Operand::OP_TYPE_IMM;
case ARM64_OP_MEM:
return Operand::OP_TYPE_MEM;
case ARM64_OP_FP:
return Operand::OP_TYPE_FP;
case ARM64_OP_INVALID:
default:
return Operand::OP_TYPE_NONE;
}
}


int
nucleus_disasm_bb_aarch64(Binary *bin, DisasmSection *dis, BB *bb)
{
int init, ret, jmp, cflow, cond, call, nop, only_nop, priv, trap, ndisassembled;
csh cs_dis;
cs_mode cs_mode_flags;
cs_insn *cs_ins;
cs_arm64_op *cs_op;
const uint8_t *pc;
uint64_t pc_addr, offset;
size_t i, j, n;
Instruction *ins;
Operand *op;

init = 0;
cs_ins = NULL;

switch(bin->bits) {
case 64:
cs_mode_flags = (cs_mode)(CS_MODE_ARM);
break;
default:
print_err("unsupported bit width %u for architecture %s", bin->bits, bin->arch_str.c_str());
goto fail;
}

if(cs_open(CS_ARCH_ARM64, cs_mode_flags, &cs_dis) != CS_ERR_OK) {
print_err("failed to initialize libcapstone");
goto fail;
}
init = 1;
cs_option(cs_dis, CS_OPT_DETAIL, CS_OPT_ON);

cs_ins = cs_malloc(cs_dis);
if(!cs_ins) {
print_err("out of memory");
goto fail;
}

offset = bb->start - dis->section->vma;
if((bb->start < dis->section->vma) || (offset >= dis->section->size)) {
print_err("basic block address points outside of section '%s'", dis->section->name.c_str());
goto fail;
}

pc = dis->section->bytes + offset;
n = dis->section->size - offset;
pc_addr = bb->start;
bb->end = bb->start;
bb->section = dis->section;
ndisassembled = 0;
only_nop = 0;
while(cs_disasm_iter(cs_dis, &pc, &n, &pc_addr, cs_ins)) {
if(cs_ins->id == ARM64_INS_INVALID) {
bb->invalid = 1;
bb->end += 1;
break;
}
if(!cs_ins->size) {
break;
}

trap = is_cs_trap_ins(cs_ins);
nop = is_cs_nop_ins(cs_ins);
ret = is_cs_ret_ins(cs_ins);
jmp = is_cs_unconditional_jmp_ins(cs_ins) || is_cs_conditional_cflow_ins(cs_ins);
cond = is_cs_conditional_cflow_ins(cs_ins);
cflow = is_cs_cflow_ins(cs_ins);
call = is_cs_call_ins(cs_ins);
priv = is_cs_privileged_ins(cs_ins);

if(!ndisassembled && nop) only_nop = 1; /* group nop instructions together */
if(!only_nop && nop) break;
if(only_nop && !nop) break;

ndisassembled++;

bb->end += cs_ins->size;
bb->insns.push_back(Instruction());
if(priv) {
bb->privileged = true;
}
if(nop) {
bb->padding = true;
}
if(trap) {
bb->trap = true;
}

ins = &bb->insns.back();
ins->start = cs_ins->address;
ins->size = cs_ins->size;
ins->mnem = std::string(cs_ins->mnemonic);
ins->op_str = std::string(cs_ins->op_str);
ins->privileged = priv;
ins->trap = trap;
if(nop) ins->flags |= Instruction::INS_FLAG_NOP;
if(ret) ins->flags |= Instruction::INS_FLAG_RET;
if(jmp) ins->flags |= Instruction::INS_FLAG_JMP;
if(cond) ins->flags |= Instruction::INS_FLAG_COND;
if(cflow) ins->flags |= Instruction::INS_FLAG_CFLOW;
if(call) ins->flags |= Instruction::INS_FLAG_CALL;

for(i = 0; i < cs_ins->detail->arm64.op_count; i++) {
cs_op = &cs_ins->detail->arm64.operands[i];
ins->operands.push_back(Operand());
op = &ins->operands.back();
op->type = cs_to_nucleus_op_type(cs_op->type);
if(op->type == Operand::OP_TYPE_IMM) {
op->aarch64_value.imm = cs_op->imm;
} else if(op->type == Operand::OP_TYPE_REG) {
op->aarch64_value.reg = (arm64_reg)cs_op->reg;
if(cflow) ins->flags |= Instruction::INS_FLAG_INDIRECT;
} else if(op->type == Operand::OP_TYPE_FP) {
op->aarch64_value.fp = cs_op->fp;
} else if(op->type == Operand::OP_TYPE_MEM) {
op->aarch64_value.mem.base = cs_op->mem.base;
op->aarch64_value.mem.index = cs_op->mem.index;
op->aarch64_value.mem.disp = cs_op->mem.disp;
if(cflow) ins->flags |= Instruction::INS_FLAG_INDIRECT;
}
}

for(i = 0; i < cs_ins->detail->groups_count; i++) {
if(is_cs_cflow_group(cs_ins->detail->groups[i])) {
for(j = 0; j < cs_ins->detail->arm64.op_count; j++) {
cs_op = &cs_ins->detail->arm64.operands[j];
if(cs_op->type == ARM64_OP_IMM) {
ins->target = cs_op->imm;
}
}
}
}

if(cflow) {
/* end of basic block */
break;
}
}

if(!ndisassembled) {
bb->invalid = 1;
bb->end += 1; /* ensure forward progress */
}

ret = ndisassembled;
goto cleanup;

fail:
ret = -1;

cleanup:
if(cs_ins) {
cs_free(cs_ins, 1);
}
if(init) {
cs_close(&cs_dis);
}
return ret;
}
8 changes: 8 additions & 0 deletions disasm-aarch64.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef NUCLEUS_DISASM_AARCH64_H
#define NUCLEUS_DISASM_AARCH64_H

#include "disasm.h"

int nucleus_disasm_bb_aarch64(Binary *bin, DisasmSection *dis, BB *bb);

#endif /* NUCLEUS_DISASM_AARCH64_H */
3 changes: 3 additions & 0 deletions disasm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "options.h"
#include "log.h"

#include "disasm-aarch64.h"
#include "disasm-arm.h"
#include "disasm-mips.h"
#include "disasm-ppc.h"
Expand Down Expand Up @@ -189,6 +190,8 @@ static int
nucleus_disasm_bb(Binary *bin, DisasmSection *dis, BB *bb)
{
switch(bin->arch) {
case Binary::ARCH_AARCH64:
return nucleus_disasm_bb_aarch64(bin, dis, bb);
case Binary::ARCH_ARM:
return nucleus_disasm_bb_arm(bin, dis, bb);
case Binary::ARCH_MIPS:
Expand Down
14 changes: 13 additions & 1 deletion insn.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,19 @@ class Operand {
OP_TYPE_FP = 4
};

union AArch64Value {
AArch64Value() { mem.base = 0; mem.index = 0; mem.disp = 0; }
AArch64Value(const AArch64Value &v) { mem.base = v.mem.base;
mem.index = v.mem.index; mem.disp = v.mem.disp; }

arm64_reg reg;
int32_t imm;
double fp;
arm64_op_mem mem;
};

union ARMValue {
ARMValue() { mem.base = 0; mem.disp = 0; }
ARMValue() { mem.base = 0; mem.index = 0; mem.scale = 0; mem.disp = 0; }
ARMValue(const ARMValue &v) { mem.base = v.mem.base; mem.index = v.mem.index;
mem.scale = v.mem.scale; mem.disp = v.mem.disp; }

Expand Down Expand Up @@ -60,6 +71,7 @@ class Operand {
uint8_t size;

union {
AArch64Value aarch64_value; /* Only set if the arch is aarch64 */
ARMValue arm_value; /* Only set if the arch is arm */
PPCValue ppc_value; /* Only set if the arch is ppc */
X86Value x86_value; /* Only set if the arch is x86 */
Expand Down
16 changes: 9 additions & 7 deletions loader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ const char *binary_types_descr[][2] = {
};

const char *binary_arch_descr[][2] = {
{"auto" , "Try to automatically determine architecture (default)"},
{"arm" , "arm"},
{"mips" , "mips"},
{"ppc" , "ppc"},
{"x86" , "x86: Specify x86-16, x86-32 or x86-64 (default x86-64)"},
{NULL , NULL}
{"auto" , "Try to automatically determine architecture (default)"},
{"aarch64" , "aarch64"},
{"arm" , "arm"},
{"mips" , "mips"},
{"ppc" , "ppc"},
{"x86" , "x86: Specify x86-16, x86-32 or x86-64 (default x86-64)"},
{NULL , NULL}
};


Expand Down Expand Up @@ -282,7 +283,8 @@ load_binary_bfd(std::string &fname, Binary *bin, Binary::BinaryType type)
case bfd_arch_aarch64:
switch(bfd_info->mach) {
case bfd_mach_aarch64:
bin->arch = Binary::ARCH_ARM;
case bfd_mach_aarch64_ilp32:
bin->arch = Binary::ARCH_AARCH64;
bin->bits = 64;
break;
default:
Expand Down
Loading

0 comments on commit 6743049

Please sign in to comment.