Package vtrace :: Package archs :: Module i386
[hide private]
[frames] | no frames]

Source Code for Module vtrace.archs.i386

  1  """ 
  2  x86 Support Module 
  3  """ 
  4  # Copyright (C) 2007 Invisigoth - See LICENSE file for details 
  5  import vtrace 
  6  import struct 
  7  import traceback 
  8  import types 
  9  import vtrace.breakpoints as breakpoints 
 10   
 11  import envi.archs.i386 as e_i386 
 12   
 13  # Pre-populating these saves a little processing 
 14  # time (important in tight watchpoint loops) 
 15  drnames = ["debug%d" % d for d in range(8)] 
 16   
 17  dbg_status = "debug6" 
 18  dbg_ctrl = "debug7" 
 19   
 20  dbg_execute    = 0 
 21  dbg_write      = 1 
 22  dbg_read_write = 3 
 23   
 24  dbg_types = { 
 25      "x":dbg_execute, 
 26      "w":dbg_write, 
 27      "rw":dbg_read_write, 
 28  } 
 29   
30 -class i386WatchMixin:
31 - def __init__(self):
32 # Which ones are in use / enabled. 33 self.hwdebug = [0, 0, 0, 0]
34 # FIXME change this to storing debug0 index and using setRegister() 35
36 - def archAddWatchpoint(self, address, size=4, perms="rw"):
37 38 idx = None 39 for i in range(4): 40 if not self.hwdebug[i]: 41 idx = i 42 break 43 44 if idx == None: 45 raise Exception("ERROR: there... are... 4... debug registers!") 46 47 pbits = dbg_types.get(perms) 48 if pbits == None: 49 raise Exception("Unsupported watchpoint perms %s (x86 supports x,w,rw)" % perms) 50 51 if pbits == dbg_execute and size != 1: 52 raise Exception("Watchpoint for execute *must* be 1 byte long!") 53 54 if size not in [1,2,4]: 55 raise Exception("Unsupported watchpoint size %d (x86 supports 1,2,4)" % size) 56 57 ctrl = 0 58 59 self.hwdebug[idx] = address 60 61 ctrl |= 1 << (2*idx) # Enabled 62 mask = ((size-1) << 2) + pbits # perms and size 63 ctrl |= (mask << (16+(4*idx))) 64 #ctrl |= 0x100 # Local exact (ignored by p6+ for read) 65 66 for tid in self.getThreads().keys(): 67 ctx = self.getRegisterContext(tid) 68 ctrl_orig = ctx.getRegister(e_i386.REG_DEBUG7) 69 #print "debug%d: %.8x debug7: %.8x" % (idx,address,ctrl|ctrl_orig) 70 ctx.setRegister(e_i386.REG_DEBUG7, ctrl_orig | ctrl) 71 ctx.setRegister(e_i386.REG_DEBUG0 + idx, address) 72 return
73
74 - def archRemWatchpoint(self, address):
75 idx = None 76 for i in range(4): 77 if self.hwdebug[i] == address: 78 idx = i 79 break 80 81 if idx == None: 82 raise Exception("Watchpoint not found at 0x%.8x" % address) 83 84 self.hwdebug[idx] = 0 85 86 ctrl_disable = ~(1 << (2*idx)) # we are not enabled 87 ctrl_disperm = ~(0xf << (16+(4*idx))) # mask off the rwx stuff 88 ctrl_mask = ctrl_disable & ctrl_disperm 89 90 for tid in self.getThreads().keys(): 91 ctx = self.getRegisterContext(tid) 92 ctrl = ctx.getRegister(e_i386.REG_DEBUG7) 93 ctrl &= ctrl_mask 94 #print "debug%d: %.8x debug7: %.8x" % (idx,address,ctrl|ctrl_orig) 95 ctx.setRegister(e_i386.REG_DEBUG7, ctrl) 96 ctx.setRegister(e_i386.REG_DEBUG0 + idx, 0) 97 return
98
99 - def archCheckWatchpoints(self):
100 regs = self.getRegisters() 101 status = regs.get(dbg_status) 102 #print "STATUS %.8x" % status 103 if status == None: 104 return None 105 x = status & 0x0f 106 if not x: 107 return None 108 109 for i in range(4): 110 if (x >> i) & 1: 111 return self.hwdebug[i] 112 return None
113 114
115 -class i386Mixin(e_i386.i386Module, e_i386.i386RegisterContext, i386WatchMixin):
116
117 - def __init__(self):
118 # Mixin our i386 envi architecture module and register context 119 e_i386.i386Module.__init__(self) 120 # FIXME tracer base should inherit from RegisterContext and we should 121 # just have to load a register definition! 122 e_i386.i386RegisterContext.__init__(self) 123 i386WatchMixin.__init__(self) 124 125 self.setMeta('Architecture', 'i386')
126
127 - def archGetStackTrace(self):
128 self.requireAttached() 129 current = 0 130 sanity = 1000 131 frames = [] 132 133 #FIXME make these by register index 134 #FIXME make these GPREG stuff! (then both are the same) 135 ebp = self.getRegisterByName("ebp") 136 eip = self.getRegisterByName("eip") 137 frames.append((eip,ebp)) 138 139 while ebp != 0 and current < sanity: 140 try: 141 buf = self.readMemory(ebp, 8) 142 ebp,eip = struct.unpack("<LL",buf) 143 frames.append((eip,ebp)) 144 current += 1 145 except: 146 break 147 148 return frames
149
150 - def platformCall(self, address, args, convention=None):
151 buf = "" 152 finalargs = [] 153 saved_regs = self.getRegisters() 154 sp = self.getStackCounter() 155 pc = self.getProgramCounter() 156 157 for arg in args: 158 if type(arg) == types.StringType: # Nicly map strings into mem 159 buf = arg+"\x00\x00"+buf # Pad with a null for convenience 160 finalargs.append(sp - len(buf)) 161 else: 162 finalargs.append(arg) 163 164 m = len(buf) % 4 165 if m: 166 buf = ("\x00" * (4-m)) + buf 167 168 # Args are 169 #finalargs.reverse() 170 buf = struct.pack("<%dI" % len(finalargs), *finalargs) + buf 171 172 # Saved EIP is target addr so when we hit the break... 173 buf = struct.pack("<I", address) + buf 174 # Calc the new stack pointer 175 newsp = sp-len(buf) 176 # Write the stack buffer in 177 self.writeMemory(newsp, buf) 178 # Setup the stack pointer 179 self.setStackCounter(newsp) 180 # Setup the instruction pointer 181 self.setProgramCounter(address) 182 # Add the magical call-break 183 callbreak = breakpoints.CallBreak(address, saved_regs) 184 self.addBreakpoint(callbreak) 185 # Continue until the CallBreak has been hit 186 while not callbreak.endregs: 187 self.run() 188 return callbreak.endregs
189