#include "emulateinsn.h" #include "insndecoder.h" #include "bitutils.h" #include "appexceptions.h" #include "bkptmanager.h" #include "codesnipmanager.h" #include "stringutils.h" #define NREGS 16 #define REG_PC 15 class handle_branchbpt : public breakpoint_action { uint32_t _codeofs; uint32_t _bpaddr; uint32_t _branch; public: handle_branchbpt(breakpoint_manager& bpm, ThreadContext& td, uint32_t codeofs, uint32_t bpaddr, uint32_t branch) : breakpoint_action(bpm, td), _codeofs(codeofs), _bpaddr(bpaddr), _branch(branch) { } virtual void action() const { // todo: how do i handle breakpoints in shared memory ( set in 1 proc, raised in 2nd proc ) printf("branch bpt action d=%d\n", _bpaddr-_codeofs); _bpm.removecode(VirtualAddress(_td.proc(), _codeofs)); // remove companion breakpoint _bpm.del_bpt(VirtualAddress(_td.proc(), _codeofs+ 12-(_bpaddr-_codeofs))); _td.setreg(REG_PC, _branch); } virtual int type() const { return BPT_BRANCH; } virtual std::string description() const { return stringformat("BRANCH: code=%08lx bp=%08lx branch=%08lx\n", _codeofs, _bpaddr, _branch); } }; void InstructionEmulator::emulate_branch(ThreadContext& td, instruction& insn) { printf("emu branch\n"); // codeofs+0 B +0 == codeofs+8 // codeofs+4 BKPT // codeofs+8 BKPT instruction branch(insn); branch.set_relative(0); uint32_t codeofs= _bpm.codeforinsn(td.proc(), branch.opcode()); _bpm.reg_bpt(VirtualAddress(td.proc(), codeofs+4), new handle_branchbpt(_bpm, td, codeofs, codeofs+4, td.getreg(15)+4)); _bpm.reg_bpt(VirtualAddress(td.proc(), codeofs+8), new handle_branchbpt(_bpm, td, codeofs, codeofs+8, insn.branchofs()*4+td.getreg(REG_PC)+td.pc_offset())); td.setreg(REG_PC, codeofs); } class handle_emupcbpt : public breakpoint_action { uint32_t _codeofs; int _pcreg; uint32_t _savedpc; uint32_t _flowpc; uint32_t _origval; public: handle_emupcbpt(breakpoint_manager& bpm, ThreadContext& td, uint32_t codeofs, int pcreg, uint32_t savedpc, uint32_t flowpc, uint32_t origval) : breakpoint_action(bpm, td), _codeofs(codeofs), _pcreg(pcreg), _savedpc(savedpc), _flowpc(flowpc), _origval(origval) { } virtual void action() const { printf("emupc action\n"); _bpm.removecode(VirtualAddress(_td.proc(), _codeofs)); uint32_t newpc= _td.getreg(_pcreg); if (newpc != _savedpc) _td.setreg(REG_PC, newpc); else _td.setreg(REG_PC, _flowpc); _td.setreg(_pcreg, _origval); } virtual int type() const { return BPT_EMULATEPC; } virtual std::string description() const { return stringformat("EMUPC: code=%08lx pc=R%d(%08lx) flow=%08lx savedpc=%08lx\n", _codeofs, _pcreg, _origval, _flowpc, _savedpc); } }; void InstructionEmulator::emulate_pc_insn(ThreadContext& td, instruction& insn) { // todo: translate LDRD R14, Rn in 2 instructions: // -> LDR R14, Rn // LDR Rx, Rn+4 // BKPT instruction pcinsn(insn); uint32_t unusedregs= ~(insn.used()|insn.defined()); int firstunusedreg= find_first_one(unusedregs); if (firstunusedreg<0) { // problem: no register to replace // likely this is LDM or STM throw app_error("need one free reg\n"); } pcinsn.replace_reg(REG_PC, firstunusedreg); uint32_t savedreg= td.getreg(firstunusedreg); uint32_t savedpc= td.getreg(15)+td.pc_offset(); td.setreg(firstunusedreg, savedpc); uint32_t codeofs= _bpm.codeforinsn(td.proc(), pcinsn.opcode()); printf("emu pc: newreg=%d\n", firstunusedreg); _bpm.reg_bpt(VirtualAddress(td.proc(), codeofs+4), new handle_emupcbpt(_bpm, td, codeofs, firstunusedreg, savedpc, td.getreg(15)+4, savedreg)); td.setreg(REG_PC, codeofs); } class handle_emubpt : public breakpoint_action { uint32_t _codeofs; uint32_t _flowpc; public: handle_emubpt(breakpoint_manager& bpm, ThreadContext& td, uint32_t codeofs, uint32_t flowpc) : breakpoint_action(bpm, td), _codeofs(codeofs), _flowpc(flowpc) { } virtual void action() const { printf("emu other bpt action\n"); _bpm.removecode(VirtualAddress(_td.proc(), _codeofs)); _td.setreg(REG_PC, _flowpc); } virtual int type() const { return BPT_EMULATE; } virtual std::string description() const { return stringformat("OTHER: code=%08lx flow=%08lx\n", _codeofs, _flowpc); } }; void InstructionEmulator::emulate_other(ThreadContext& td, instruction& insn) { printf("emu other\n"); uint32_t codeofs= _bpm.codeforinsn(td.proc(), insn.opcode()); _bpm.reg_bpt(VirtualAddress(td.proc(), codeofs+4), new handle_emubpt(_bpm, td, codeofs, td.getreg(15)+4)); td.setreg(REG_PC, codeofs); } void InstructionEmulator::emulate_insn(ThreadContext& td, instruction& insn) { if (insn.isbranch()) { emulate_branch(td, insn); } else if ((insn.used(REG_PC)) || (insn.defined(REG_PC))) { emulate_pc_insn(td, insn); } else { emulate_other(td, insn); } }