#ifndef _ARM32INSNDECODER_H_ #define _ARM32INSNDECODER_H_ #include #include #include #include "bitutils.h" typedef std::vector ByteVector; union shifter { struct { unsigned imm8:8; unsigned rot:4; } imm; // bit 25 (I) == 1 struct { unsigned Rm:4; unsigned eq0:1; unsigned type:2; unsigned shift:5; } shift; struct { unsigned Rm:4; unsigned eq1:1; unsigned type:2; unsigned eq0:1; unsigned Rs:4; } regshift; }; struct scaledreg{ unsigned Rm:4; unsigned eq0:1; unsigned type:2; unsigned shift:5; }; union arm32bits { struct { unsigned shifter:12; unsigned Rd:4; unsigned Rn:4; unsigned s:1; unsigned opc:4; unsigned i:1; unsigned eq0:2; unsigned cc:4; } dp; struct { unsigned regindex:12; unsigned Rd:4; unsigned Rn:4; unsigned l:1; unsigned w:1; unsigned b:1; unsigned u:1; unsigned p:1; unsigned i:1; unsigned eq1:2; unsigned cc:4; } ldst; struct { int ofs:24; unsigned l:1; unsigned eq5:3; unsigned cc:4; } branch; struct { unsigned imml:4; unsigned eq7:4; unsigned immh:12; unsigned eqE12:12; } bkpt; struct { int ofs:24; unsigned h:1; unsigned eq7D:7; } blximm; struct { unsigned Rm:4; unsigned eq4BFFC:22; unsigned type:2; // 0:? 1:bx, 2:bxj 3:blx unsigned cc:4; } blxreg; // ldc ? struct { unsigned list:16; unsigned Rn:4; unsigned l:1; unsigned w:1; unsigned special:1; unsigned u:1; unsigned p:1; unsigned eq4:3; unsigned cc:4; } ldmstm; struct { unsigned amodel:4; // or Rm unsigned eq1a:1; unsigned h:1; unsigned s:1; unsigned eq1b:1; unsigned amodeh:4; unsigned Rd:4; unsigned Rn:4; unsigned l:1; unsigned w:1; unsigned i:1; unsigned u:1; unsigned p:1; unsigned eq0:3; unsigned cc:4; } ldrx; }; enum dp_opcodes { DPOPC_AND, DPOPC_EOR, DPOPC_SUB, DPOPC_RSB, DPOPC_ADD, DPOPC_ADC, DPOPC_SBC, DPOPC_RSC, DPOPC_TST, DPOPC_TEQ, DPOPC_CMP, DPOPC_CMN, DPOPC_ORR, DPOPC_MOV, DPOPC_BIC, DPOPC_MVN }; class instruction { public: class regcallback { public: virtual unsigned use(unsigned nr) const=0; virtual unsigned def(unsigned nr) const=0; }; class usedefcallback : public regcallback { instruction& _decoder; public: usedefcallback(instruction& decoder) : _decoder(decoder) { } virtual unsigned use(unsigned nr) const { _decoder.use(nr); return nr; } virtual unsigned def(unsigned nr) const { _decoder.def(nr); return nr; } }; class replacecallback : public regcallback { unsigned _oldnr; unsigned _newnr; public: replacecallback(unsigned oldnr, unsigned newnr) : _oldnr(oldnr), _newnr(newnr) { } virtual unsigned use(unsigned nr) const { if (nr==_oldnr) return _newnr; return nr; } virtual unsigned def(unsigned nr) const { if (nr==_oldnr) return _newnr; return nr; } }; instruction(uint8_t *code, int size) : _insn(*(arm32bits*)code), _branch(false), _used(0), _defined(0) { printf("decoding b=%d %08lx\n", sizeof(arm32bits), opcode()); process_usedef(usedefcallback(*this)); } void process_usedef(const regcallback& cb) { //printf("ldrx: %d %d %d\n", _insn.ldrx.eq0==0, _insn.ldrx.eq1a==1, _insn.ldrx.eq1b==1); //printf("dp: %d\n", _insn.dp.eq0==0); //printf("ldst: %d\n", _insn.ldst.eq1==1); //printf("branch: %d\n", _insn.branch.eq5==5); //printf("bkpt: %d %d\n", _insn.bkpt.eq7==7, _insn.bkpt.eqE12==0xE12); //printf("blximm: %d\n", _insn.blximm.eq7D==0x7D ) ; //printf("blxreg: %d %d\n", _insn.blxreg.eq4BFFC==0x4BFFC, _insn.blxreg.type!=0); //printf("ldmstm: %d\n", _insn.ldmstm.eq4==4); // note: this gives warning 'conditional expr is constant' due to the '0' if (0 || (_insn.ldrx.eq0==0 && _insn.ldrx.eq1a==1 && _insn.ldrx.eq1b==1 && handle_miscsldr(cb)) || (_insn.dp.eq0==0 && handle_dataprocessing(cb)) || (_insn.ldst.eq1==1 && handle_loadstore(cb)) || (_insn.branch.eq5==5 && handle_branch(cb)) || (_insn.bkpt.eq7==7 && _insn.bkpt.eqE12==0xE12 && handle_breakpoint(cb)) || (_insn.blximm.eq7D==0x7D && handle_blximm(cb)) || (_insn.blxreg.eq4BFFC==0x4BFFC && _insn.blxreg.type!=0 && handle_blxreg(cb)) || (_insn.ldmstm.eq4==4 && handle_ldmstm(cb)) ) { printf("instruction decoded: b=%d use=%04x, def=%04x\n", _branch, _used, _defined); } else { printf("unknown instruction\n"); } } private: arm32bits _insn; bool _branch; uint32_t _used; uint32_t _defined; bool handle_dataprocessing(const regcallback& cb) { printf("handle_dataprocessing\n"); // ADD Rd, Rm, Rn // SUB Rd, Rm, Rn // MOV Rd, Rm if (_insn.dp.opc(ribits); if (ri.eq0) return false; ri.Rm= cb.use(ri.Rm); ribits= bf2int(ri); return true; } void use_shifter(const regcallback& cb, unsigned& shbits) { shifter sh= int2bf(shbits); if (sh.regshift.eq0==0 && sh.regshift.eq1==1) { sh.regshift.Rs= cb.use(sh.regshift.Rs); sh.regshift.Rm= cb.use(sh.regshift.Rm); shbits= bf2int(sh); } else if (sh.shift.eq0==0) { sh.regshift.Rm= cb.use(sh.regshift.Rm); shbits= bf2int(sh); } else throw "decoder error"; } void handle_reglist(const regcallback& cb, unsigned& list, bool def) { int orglist= list; for (int r=0 ; r<16 ; r++) { if (orglist&1) { int tmpr= def ? cb.def(r) : cb.use(r); if (tmpr!=r) { list &= ~(1<>=1; } } public: bool isbranch() { return _branch; } void set_relative(int ofs) { _insn.branch.ofs= ofs; } int branchofs() { return _insn.branch.ofs; } uint32_t opcode() { return bf2int(_insn); } void replace_reg(int origr, int newr) { process_usedef(replacecallback(origr, newr)); } void use(int regnr) { _used |= (1<>nr)&1; } bool defined(int nr) { return (_defined>>nr)&1; } }; #endif