summaryrefslogtreecommitdiffstats
path: root/arch/arm-singlestep.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm-singlestep.c')
-rw-r--r--arch/arm-singlestep.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/arch/arm-singlestep.c b/arch/arm-singlestep.c
new file mode 100644
index 0000000..e98feb3
--- /dev/null
+++ b/arch/arm-singlestep.c
@@ -0,0 +1,154 @@
+#include "arm-singlestep.h"
+
+#ifdef ARCH_AARCH64
+
+static void break_imm(unsigned long address, struct thread *th) {
+ struct breakpoint *b = add_breakpoint(th->proc, address, 1);
+ b->user = 0;
+ b->tid = th->id;
+ b->enabled = -1;
+}
+
+static void break_reg(int reg, struct thread *th) {
+ unsigned long address = 0;
+ unsigned int *regs = th->state->regs.arm32.regs;
+
+ switch (reg) {
+ case ARM_REG_R0: address = regs[0]; break;
+ case ARM_REG_R1: address = regs[1]; break;
+ case ARM_REG_R2: address = regs[2]; break;
+ case ARM_REG_R3: address = regs[3]; break;
+ case ARM_REG_R4: address = regs[4]; break;
+ case ARM_REG_R5: address = regs[5]; break;
+ case ARM_REG_R6: address = regs[6]; break;
+ case ARM_REG_R7: address = regs[7]; break;
+ case ARM_REG_R8: address = regs[8]; break;
+ case ARM_REG_R9: address = regs[9]; break;
+ case ARM_REG_R10: address = regs[10]; break;
+ case ARM_REG_R11: address = regs[11]; break;
+ case ARM_REG_R12: address = regs[12]; break;
+ case ARM_REG_R13: address = regs[13]; break;
+ case ARM_REG_R14: address = regs[14]; break;
+ case ARM_REG_R15: address = regs[15]; break;
+ default: /* todo thread error */ break;
+ }
+
+ break_imm(address, th);
+}
+
+static int is_pc(csh handle, cs_insn *insn) {
+ cs_regs read, write;
+ uint8_t read_size, write_size;
+ cs_regs_access(handle, insn, read, &read_size, write, &write_size);
+
+ for (uint8_t i = 0; i < write_size; i++) {
+ if (write[i] == ARM_REG_PC) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static uint8_t pc_op(cs_arm_op *ops, uint8_t ops_size) {
+ uint8_t i;
+ for (i = 0; i < ops_size; i++) {
+ if (ops[i].type == ARM_OP_REG && ops[i].reg == ARM_REG_PC) {
+ break;
+ }
+ }
+ return i;
+}
+
+int arm_singlestep(struct thread *th) {
+ struct archinfo archinfo;
+ struct iovec regs = { &th->state->regs, th->state->regsize };
+ architecture_info(&archinfo, &regs);
+
+ int ret = 0;
+ csh handle;
+
+ if (cs_open(archinfo.cs_arch, archinfo.cs_mode, &handle) != CS_ERR_OK) {
+ /* todo thread error */
+ return -1;
+ }
+
+ cs_option(handle, CS_OPT_DETAIL, CS_OPT_ON);
+
+ uint64_t address = archinfo.progmctr;
+ size_t codez = 128;
+ const uint8_t *code = deref(th, address, codez);
+ cs_insn *insn = cs_malloc(handle);
+
+ if (cs_disasm_iter(handle, &code, &codez, &address, insn)) {
+ if (is_pc(handle, insn)) {
+ cs_arm_op *ops = insn->detail->arm.operands;
+ uint8_t ops_size = insn->detail->arm.op_count;
+ uint8_t pci;
+
+ switch (insn->id) {
+ case ARM_INS_B:
+ case ARM_INS_BL:
+ case ARM_INS_BX:
+ case ARM_INS_BLX:
+ if (ops_size == 1) {
+ switch (ops[0].type) {
+ case ARM_OP_REG: break_reg(ops[0].reg, th); break;
+ case ARM_OP_IMM: break_imm(ops[0].imm, th); break;
+ default: ret = -1; /* todo thread error */ break;
+ }
+ } else {
+ ret = -1;
+ /* todo thread error */
+ }
+ break;
+
+ case ARM_INS_POP:
+ if ((pci = pc_op(ops, ops_size)) < ops_size) {
+ unsigned long saddr = archinfo.stackptr + (pci * archinfo.wordsize);
+ unsigned long *sval = deref(th, saddr, archinfo.wordsize);
+ break_imm(*sval, th);
+ } else {
+ ret = -1;
+ /* todo thread error */
+ }
+ break;
+
+ case ARM_INS_MOV:
+ if (pc_op(ops, ops_size) == 0) {
+ if (ops_size == 2) {
+ switch (ops[1].type) {
+ case ARM_OP_REG: break_reg(ops[1].reg, th); break;
+ case ARM_OP_IMM: break_imm(ops[1].imm, th); break;
+ default: ret = -1; /* todo thread error */ break;
+ }
+ } else {
+ ret = -1;
+ /* tr */
+ }
+ } else {
+ ret = -1;
+ /* tr */
+ }
+ break;
+
+ default:
+ ret = -1;
+ /* todo thread error */
+ break;
+ }
+ }
+
+ /* default case - next sequential instruction */
+ break_imm(address, th);
+ } else {
+ ret = -1;
+ /* todo thread error */
+ }
+
+ cs_free(insn, 1);
+ cs_close(&handle);
+ return ret;
+}
+
+#endif