Source code for envi.archs.arm.emu

"""
The initial arm module.
"""

import struct

import envi
from envi.archs.arm import ArmModule
from envi.archs.arm.regs import *
from envi.archs.arm.thumbdisasm import *    #this gets both arm and thumb



# CPU state (memory, regs inc SPSRs and banked registers)
# CPU mode  (User, FIQ, IRQ, supervisor, Abort, Undefined, System)
# 
# instruction code
# exception handler code
# FIXME: SPSR handling is not certain.  

# calling conventions
class ArmArchitectureProcedureCall(envi.CallingConvention):
[docs] """ Implement calling conventions for your arch. """ def setReturnValue(self, emu, value, ccinfo=None):
[docs] esp = emu.getRegister(REG_ESP) eip = struct.unpack("<L", emu.readMemory(esp, 4))[0] esp += 4 # For the saved eip esp += (4 * argc) # Cleanup saved args emu.setRegister(REG_ESP, esp) emu.setRegister(REG_EAX, value) emu.setProgramCounter(eip) def getCallArgs(self, emu, count):
[docs] return emu.getRegisters(0xf) # r0-r3 are used to hand in parameters. additional parms are stored and pointed to by r0 aapcs = ArmArchitectureProcedureCall()
class CoProcEmulator: # useful for prototyping, but should be subclassed
[docs] def __init__(self): pass def stc(self, parms):
[docs] print >>sys.stderr,"CoProcEmu: stc(%s)"%repr(parms) def ldc(self, parms):
[docs] print >>sys.stderr,"CoProcEmu: ldc(%s)"%repr(parms) def cdp(self, parms):
[docs] print >>sys.stderr,"CoProcEmu: cdp(%s)"%repr(parms) def mcr(self, parms):
[docs] print >>sys.stderr,"CoProcEmu: mcr(%s)"%repr(parms) def mcrr(self, parms):
[docs] print >>sys.stderr,"CoProcEmu: mcrr(%s)"%repr(parms) def mrc(self, parms):
[docs] print >>sys.stderr,"CoProcEmu: mrc(%s)"%repr(parms) def mrrc(self, parms):
[docs] print >>sys.stderr,"CoProcEmu: mrrc(%s)"%repr(parms) class ArmEmulator(ArmModule, ArmRegisterContext, envi.Emulator):
[docs] def __init__(self): ArmModule.__init__(self) self.coprocs = [CoProcEmulator() for x in xrange(16)] # FIXME: this should be None's, and added in for each real coproc... but this will work for now. seglist = [ (0,0xffffffff) for x in xrange(6) ] envi.Emulator.__init__(self, segs=seglist) ArmRegisterContext.__init__(self) self.addCallingConvention("Arm Arch Procedure Call", aapcs) def undefFlags(self):
[docs] """ Used in PDE. A flag setting operation has resulted in un-defined value. Set the flags to un-defined as well. """ self.setRegister(REG_EFLAGS, None) def setFlag(self, which, state, mode=PM_usr): # FIXME: CPSR?
[docs] flags = self.getSPSR(mode) if state: flags |= which else: flags &= ~which self.setSPSR(mode, flags) def getFlag(self, which, mode=PM_usr): # FIXME: CPSR?
[docs] #if (flags_reg == None): # flags_reg = proc_modes[self.getProcMode()][5] #flags = self.getRegister(flags_reg) flags = self.getSPSR(mode) if flags == None: raise envi.PDEUndefinedFlag(self) return bool(flags & which) def readMemValue(self, addr, size):
[docs] bytes = self.readMemory(addr, size) if bytes == None: return None #FIXME change this (and all uses of it) to passing in format... #FIXME: Remove byte check and possibly half-word check. (possibly all but word?) if len(bytes) != size: raise Exception("Read Gave Wrong Length At 0x%.8x (va: 0x%.8x wanted %d got %d)" % (self.getProgramCounter(),addr, size, len(bytes))) if size == 1: return struct.unpack("B", bytes)[0] elif size == 2: return struct.unpack("<H", bytes)[0] elif size == 4: return struct.unpack("<L", bytes)[0] elif size == 8: return struct.unpack("<Q", bytes)[0] def writeMemValue(self, addr, value, size):
[docs] #FIXME change this (and all uses of it) to passing in format... #FIXME: Remove byte check and possibly half-word check. (possibly all but word?) if size == 1: bytes = struct.pack("B",value & 0xff) elif size == 2: bytes = struct.pack("<H",value & 0xffff) elif size == 4: bytes = struct.pack("<L", value & 0xffffffff) elif size == 8: bytes = struct.pack("<Q", value & 0xffffffffffffffff) self.writeMemory(addr, bytes) def readMemSignedValue(self, addr, size):
[docs] #FIXME: Remove byte check and possibly half-word check. (possibly all but word?) bytes = self.readMemory(addr, size) if bytes == None: return None if size == 1: return struct.unpack("b", bytes)[0] elif size == 2: return struct.unpack("<h", bytes)[0] elif size == 4: return struct.unpack("<l", bytes)[0] def executeOpcode(self, op):
[docs] # NOTE: If an opcode method returns # other than None, that is the new eip x = None if op.prefixes >= 0xe or op.prefixes == (self.getRegister(REG_FLAGS)>>28): #nearly every opcode is optional meth = self.op_methods.get(op.mnem, None) if meth == None: raise envi.UnsupportedInstruction(self, op) x = meth(op) print >>sys.stderr,"executed instruction, returned: %s"%x if x == None: pc = self.getProgramCounter() x = pc+op.size self.setProgramCounter(x) def doPush(self, val):
[docs] esp = self.getRegister(REG_ESP) esp -= 4 self.writeMemValue(esp, val, 4) self.setRegister(REG_ESP, esp) def doPop(self):
[docs] esp = self.getRegister(REG_ESP) val = self.readMemValue(esp, 4) self.setRegister(REG_ESP, esp+4) return val def getProcMode(self):
[docs] return self._rctx_vals[REG_CPSR] & 0x1f # obfuscated for speed. could call getCPSR but it's not as fast def getCPSR(self):
[docs] return self._rctx_vals[REG_CPSR] def setCPSR(self, psr):
[docs] self._rctx_vals[REG_CPSR] = psr def getSPSR(self, mode):
[docs] return self._rctx_vals[((mode&0xf)*17)+16] def setSPSR(self, mode, psr):
[docs] self._rctx_vals[((mode&0xf)*17)+16] = psr def setProcMode(self, mode):
[docs] # write current psr to the saved psr register for current mode curSPSRidx = proc_modes[self.getProcMode()][5] self._rctx_vals[curSPSRidx] = self._rctx_vals[REG_CPSR] # do we restore saved spsr? cpsr = self._rctx_vals[REG_CPSR] & 0xffffffe0 self._rctx_vals[REG_CPSR] = cpsr | mode def getRegister(self, index, mode=None):
[docs] """ Return the current value of the specified register index. """ if mode == None: mode = self.getProcMode() & 0xf else: mode &= 0xf idx = (index & 0xffff) ridx = idx + (mode*17) # account for different banks of registers ridx = reg_table[ridx][2] # magic pointers allowing overlapping banks of registers if idx == index: return self._rctx_vals[ridx] offset = (index >> 24) & 0xff width = (index >> 16) & 0xff mask = (2**width)-1 return (self._rctx_vals[ridx] >> offset) & mask def setRegister(self, index, value, mode=None):
[docs] """ Set a register value by index. """ if mode == None: mode = self.getProcMode() & 0xf else: mode &= 0xf self._rctx_dirty = True idx = (index & 0xffff) ridx = idx + (mode*17) # account for different banks of registers ridx = reg_table[ridx][2] # magic pointers allowing overlapping banks of registers if idx == index: self._rctx_vals[ridx] = (value & self._rctx_masks[ridx]) # FIXME: hack. should look up index in proc_modes dict? return # If we get here, it's a meta register index. # NOTE: offset/width are in bits... offset = (index >> 24) & 0xff width = (index >> 16) & 0xff #FIXME is it faster to generate or look thses up? mask = (2**width)-1 mask = mask << offset # NOTE: basewidth is in *bits* basewidth = self._rctx_widths[ridx] basemask = (2**basewidth)-1 # cut a whole in basemask at the size/offset of mask finalmask = basemask ^ mask curval = self._rctx_vals[ridx] self._rctx_vals[ridx] = (curval & finalmask) | (value << offset) def integerSubtraction(self, op):
[docs] """ Do the core of integer subtraction but only *return* the resulting value rather than assigning it. (allows cmp and sub to use the same code) """ # Src op gets sign extended to dst #FIXME account for same operand with zero result for PDE src1 = self.getOperValue(op, 1) src2 = self.getOperValue(op, 2) Sflag = op.iflags & IF_PSR_S if src1 == None or src2 == None: self.undefFlags() return None return self.intSubBase(src1, src2, Sflag) def intSubBase(self, src1, src2, Sflag=0, rd=0):
[docs] # So we can either do a BUNCH of crazyness with xor and shifting to # get the necissary flags here, *or* we can just do both a signed and # unsigned sub and use the results. usrc = e_bits.unsigned(src1, 4) udst = e_bits.unsigned(src2, 4) ssrc = e_bits.signed(src1, 4) sdst = e_bits.signed(src2, 4) ures = udst - usrc sres = sdst - ssrc if Sflag: curmode = self.getProcMode() if rd == 15: if(curmode != PM_sys and curmode != PM_usr): self.setCPSR(self.getSPSR(curmode)) else: raise Exception("Messed up opcode... adding to r15 from PM_usr or PM_sys") self.setFlag(PSR_C, e_bits.is_unsigned_carry(ures, 4)) self.setFlag(PSR_Z, not ures) self.setFlag(PSR_N, e_bits.is_signed(ures, 4)) self.setFlag(PSR_V, e_bits.is_signed_overflow(sres, 4)) #print "s2size/s1size: %d %d" % (s2size, s1size) #print "unsigned: %d %d %d" % (usrc, udst, ures) #print "signed: %d %d %d" % (ssrc, sdst, sres) #if Sflag: # self.setFlag(PSR_N, sres>>32) # self.setFlag(PSR_Z, sres==0) # self.setFlag(PSR_C, e_bits.is_unsigned_carry(ures, s2size)) # self.setFlag(PSR_V, e_bits.is_signed_overflow(sres, s2size)) return ures def logicalAnd(self, op):
[docs] src1 = self.getOperValue(op, 1) src2 = self.getOperValue(op, 2) # PDE if src1 == None or src2 == None: self.undefFlags() self.setOperValue(op, 0, None) return res = src1 & src2 self.setFlag(PSR_N, 0) self.setFlag(PSR_V, 0) self.setFlag(PSR_C, 0) self.setFlag(PSR_Z, not res) return res def i_and(self, op):
[docs] res = self.logicalAnd(op) self.setOperValue(op, 0, res) def i_stm(self, op):
[docs] srcreg = self.getOperValue(op,0) regmask = self.getOperValue(op,1) pc = self.getRegister(REG_PC) # store for later check start_address = self.getRegister(srcreg) addr = start_address for reg in xrange(16): if reg in regmask: val = self.getRegister(reg) if op.iflags & IF_DAIB_B: if op.iflags & IF_DAIB_I: addr += 4 else: addr -= 4 self.writeMemValue(addr, val, 4) else: self.writeMemValue(addr, val, 4) if op.iflags & IF_DAIB_I: addr += 4 else: addr -= 4 if op.opers[0].oflags & OF_W: self.setRegister(srcreg,addr) #FIXME: add "shared memory" functionality? prolly just in strex which will be handled in i_strex # is the following necessary? newpc = self.getRegister(REG_PC) # check whether pc has changed if pc != newpc: return newpc i_stmia = i_stm
def i_ldm(self, op):
[docs] srcreg = self.getOperValue(op,0) regmask = self.getOperValue(op,1) pc = self.getRegister(REG_PC) # store for later check start_address = self.getRegister(srcreg) addr = start_address for reg in xrange(16): if reg in regmask: if op.iflags & IF_DAIB_B: if op.iflags & IF_DAIB_I: addr += 4 else: addr -= 4 regval = self.readMemValue(addr, 4) self.setRegister(reg, regval) else: regval = self.readMemValue(addr, 4) self.setRegister(reg, regval) if op.iflags & IF_DAIB_I: addr += 4 else: addr -= 4 if op.opers[0].oflags & OF_W: self.setRegister(srcreg,addr) #FIXME: add "shared memory" functionality? prolly just in ldrex which will be handled in i_ldrex # is the following necessary? newpc = self.getRegister(REG_PC) # check whether pc has changed if pc != newpc: return newpc i_ldmia = i_ldm
def i_ldr(self, op):
[docs] # hint: covers ldr, ldrb, ldrbt, ldrd, ldrh, ldrsh, ldrsb, ldrt (any instr where the syntax is ldr{condition}stuff) val = self.getOperValue(op, 1) self.setOperValue(op, 0, val) if op.opers[0].reg == REG_PC: return val def i_add(self, op):
[docs] src1 = self.getOperValue(op, 1) src2 = self.getOperValue(op, 2) #FIXME PDE and flags if src1 == None or src2 == None: self.undefFlags() self.setOperValue(op, 0, None) return dsize = op.opers[0].tsize ssize = op.opers[1].tsize s2size = op.opers[2].tsize usrc1 = e_bits.unsigned(src1, 4) usrc2 = e_bits.unsigned(src2, 4) ssrc1 = e_bits.signed(src1, 4) ssrc2 = e_bits.signed(src2, 4) ures = usrc1 + usrc2 sres = ssrc1 + ssrc2 self.setOperValue(op, 0, ures) curmode = self.getProcMode() if op.flags & IF_S: if op.opers[0].reg == 15 and (curmode != PM_sys and curmode != PM_usr): self.setCPSR(self.getSPSR(curmode)) else: raise Exception("Messed up opcode... adding to r15 from PM_usr or PM_sys") self.setFlag(PSR_C, e_bits.is_unsigned_carry(ures, dsize)) self.setFlag(PSR_Z, not ures) self.setFlag(PSR_N, e_bits.is_signed(ures, dsize)) self.setFlag(PSR_V, e_bits.is_signed_overflow(sres, dsize)) def i_b(self, op):
[docs] return self.getOperValue(op, 0) def i_bl(self, op):
[docs] self.setRegister(REG_LR, self.getRegister(REG_PC)) return self.getOperValue(op, 0) def i_tst(self, op):
[docs] src1 = self.getOperValue(op, 0) src2 = self.getOperValue(op, 1) dsize = op.opers[0].tsize ures = src1 & src2 self.setFlag(PSR_N, e_bits.is_signed(ures, dsize)) self.setFlag(PSR_Z, (0,1)[ures==0]) self.setFlag(PSR_C, e_bits.is_unsigned_carry(ures, dsize)) #self.setFlag(PSR_V, e_bits.is_signed_overflow(sres, dsize)) def i_rsb(self, op):
src1 = self.getOperValue(op, 1) src2 = self.getOperValue(op, 2) #FIXME PDE and flags if src1 == None or src2 == None: self.undefFlags() self.setOperValue(op, 0, None) return dsize = op.opers[0].tsize ssize = op.opers[1].tsize s2size = op.opers[2].tsize usrc1 = e_bits.unsigned(src1, 4) usrc2 = e_bits.unsigned(src2, 4) ssrc1 = e_bits.signed(src1, 4) ssrc2 = e_bits.signed(src2, 4) ures = usrc2 - usrc1 sres = ssrc2 - ssrc1 self.setOperValue(op, 0, ures) curmode = self.getProcMode() if op.flags & IF_S: if op.opers[0].reg == 15: if (curmode != PM_sys and curmode != PM_usr): self.setCPSR(self.getSPSR(curmode)) else: raise Exception("Messed up opcode... adding to r15 from PM_usr or PM_sys") self.setFlag(PSR_C, e_bits.is_unsigned_carry(ures, dsize)) self.setFlag(PSR_Z, not ures) self.setFlag(PSR_N, e_bits.is_signed(ures, dsize)) self.setFlag(PSR_V, e_bits.is_signed_overflow(sres, dsize)) def i_rsb(self, op):
[docs] # Src op gets sign extended to dst #FIXME account for same operand with zero result for PDE src1 = self.getOperValue(op, 1) src2 = self.getOperValue(op, 2) Sflag = op.iflags & IF_PSR_S if src1 == None or src2 == None: self.undefFlags() return None res = self.intSubBase(src2, src1, Sflag, op.opers[0].reg) self.setOperValue(op, 0, res) def i_sub(self, op):
[docs] # Src op gets sign extended to dst #FIXME account for same operand with zero result for PDE src1 = self.getOperValue(op, 1) src2 = self.getOperValue(op, 2) Sflag = op.iflags & IF_PSR_S if src1 == None or src2 == None: self.undefFlags() return None res = self.intSubBase(src1, src2, Sflag, op.opers[0].reg) self.setOperValue(op, 0, res) def i_eor(self, op):
[docs] src1 = self.getOperValue(op, 1) src2 = self.getOperValue(op, 2) #FIXME PDE and flags if src1 == None or src2 == None: self.undefFlags() self.setOperValue(op, 0, None) return usrc1 = e_bits.unsigned(src1, 4) usrc2 = e_bits.unsigned(src2, 4) ures = usrc1 ^ usrc2 self.setOperValue(op, 0, ures) curmode = self.getProcMode() if op.iflags & IF_S: if op.opers[0].reg == 15: if (curmode != PM_sys and curmode != PM_usr): self.setCPSR(self.getSPSR(curmode)) else: raise Exception("Messed up opcode... adding to r15 from PM_usr or PM_sys") self.setFlag(PSR_C, e_bits.is_unsigned_carry(ures, 4)) self.setFlag(PSR_Z, not ures) self.setFlag(PSR_N, e_bits.is_signed(ures, 4)) self.setFlag(PSR_V, e_bits.is_signed_overflow(sres, 4)) # Coprocessor Instructions def i_stc(self, op):
[docs] cpnum = op.opers[0] coproc = self._getCoProc(cpnum) coproc.stc(op.opers) def i_ldc(self, op):
[docs] cpnum = op.opers[0] coproc = self._getCoProc(cpnum) coproc.ldc(op.opers) def i_cdp(self, op):
[docs] cpnum = op.opers[0] coproc = self._getCoProc(cpnum) coproc.cdp(op.opers) def i_mrc(self, op):
[docs] cpnum = op.opers[0] coproc = self._getCoProc(cpnum) coproc.mrc(op.opers) def i_mrrc(self, op):
[docs] cpnum = op.opers[0] coproc = self._getCoProc(cpnum) coproc.mrrc(op.opers) def i_mcr(self, op):
[docs] cpnum = op.opers[0] coproc = self._getCoProc(cpnum) coproc.mrrc(op.opers) def i_mcrr(self, op):
[docs] cpnum = op.opers[0] coproc = self._getCoProc(cpnum) coproc.mcrr(op.opers) opcode_dist = \
[('and', 4083),# ('stm', 1120),# ('ldr', 1064),# ('add', 917),# ('stc', 859),# ('str', 770),# ('bl', 725),# ('ldm', 641),# ('b', 472),# ('ldc', 469),# ('tst', 419),# ('rsb', 196),# ('eor', 180),# ('mul', 159), ('swi', 128), ('sub', 110),# ('adc', 96), ('cdp', 74),# ('orr', 66), ('cmn', 59), ('mcr', 55),# ('stc2', 54), ('ldc2', 52), ('mrc', 49),# ('mvn', 47), ('rsc', 46), ('teq', 45), ('cmp', 41), ('sbc', 40), ('mov', 35), ('bic', 34), ('mcr2', 29),# ('mrc2', 28),# ('swp', 28), ('mcrr', 21),# ('mrrc', 20),# ('usada8', 20), ('qadd', 13), ('mrrc2', 10),# ('add16', 9), ('mla', 9), ('mcrr2', 7),# ('uqsub16', 6), ('uqadd16', 5), ('sub16', 5), ('umull', 4), ('uq', 3), ('smlsdx', 3), ('uhsub16', 3), ('uqsubaddx', 3), ('qdsub', 2), ('subaddx', 2), ('uqadd8', 2), ('ssat', 2), ('uqaddsubx', 2), ('smull', 2), ('blx', 2), ('smlal', 2), ('shsub16', 1), ('', 1), ('smlsd', 1), ('pkhbt', 1), ('revsh', 1), ('qadd16', 1), ('uqsub8', 1), ('ssub16', 1), ('usad8', 1), ('uadd16', 1), ('smladx', 1), ('swpb', 1), ('smlaldx', 1), ('usat', 1), ('umlal', 1), ('rev16', 1), ('sadd16', 1), ('sel', 1), ('sub8', 1), ('pkhtb', 1), ('umaal', 1), ('addsubx', 1), ('add8', 1), ('smlad', 1), ('sxtb', 1), ('sadd8', 1)]