Source code for vtrace.archs.i386
"""
x86 Support Module
"""
# Copyright (C) 2007 Invisigoth - See LICENSE file for details
import vtrace
import struct
import traceback
import types
import vtrace.breakpoints as breakpoints
import envi.archs.i386 as e_i386
# Pre-populating these saves a little processing
# time (important in tight watchpoint loops)
drnames = ["debug%d" % d for d in range(8)]
dbg_status = "debug6"
dbg_ctrl = "debug7"
dbg_execute = 0
dbg_write = 1
dbg_read_write = 3
dbg_types = {
"x":dbg_execute,
"w":dbg_write,
"rw":dbg_read_write,
}
[docs]class i386WatchMixin:
def __init__(self):
# Which ones are in use / enabled.
self.hwdebug = [0, 0, 0, 0]
# FIXME change this to storing debug0 index and using setRegister()
[docs] def archAddWatchpoint(self, address, size=4, perms="rw"):
idx = None
for i in range(4):
if not self.hwdebug[i]:
idx = i
break
if idx == None:
raise Exception("ERROR: there... are... 4... debug registers!")
pbits = dbg_types.get(perms)
if pbits == None:
raise Exception("Unsupported watchpoint perms %s (x86 supports x,w,rw)" % perms)
if pbits == dbg_execute and size != 1:
raise Exception("Watchpoint for execute *must* be 1 byte long!")
if size not in [1,2,4]:
raise Exception("Unsupported watchpoint size %d (x86 supports 1,2,4)" % size)
ctrl = 0
self.hwdebug[idx] = address
ctrl |= 1 << (2*idx) # Enabled
mask = ((size-1) << 2) + pbits # perms and size
ctrl |= (mask << (16+(4*idx)))
#ctrl |= 0x100 # Local exact (ignored by p6+ for read)
for tid in self.getThreads().keys():
ctx = self.getRegisterContext(tid)
ctrl_orig = ctx.getRegister(e_i386.REG_DEBUG7)
#print "debug%d: %.8x debug7: %.8x" % (idx,address,ctrl|ctrl_orig)
ctx.setRegister(e_i386.REG_DEBUG7, ctrl_orig | ctrl)
ctx.setRegister(e_i386.REG_DEBUG0 + idx, address)
return
[docs] def archRemWatchpoint(self, address):
idx = None
for i in range(4):
if self.hwdebug[i] == address:
idx = i
break
if idx == None:
raise Exception("Watchpoint not found at 0x%.8x" % address)
self.hwdebug[idx] = 0
ctrl_disable = ~(1 << (2*idx)) # we are not enabled
ctrl_disperm = ~(0xf << (16+(4*idx))) # mask off the rwx stuff
ctrl_mask = ctrl_disable & ctrl_disperm
for tid in self.getThreads().keys():
ctx = self.getRegisterContext(tid)
ctrl = ctx.getRegister(e_i386.REG_DEBUG7)
ctrl &= ctrl_mask
#print "debug%d: %.8x debug7: %.8x" % (idx,address,ctrl|ctrl_orig)
ctx.setRegister(e_i386.REG_DEBUG7, ctrl)
ctx.setRegister(e_i386.REG_DEBUG0 + idx, 0)
return
[docs] def archCheckWatchpoints(self):
regs = self.getRegisters()
status = regs.get(dbg_status)
#print "STATUS %.8x" % status
if status == None:
return None
x = status & 0x0f
if not x:
return None
for i in range(4):
if (x >> i) & 1:
return self.hwdebug[i]
return None
[docs]class i386Mixin(e_i386.i386Module, e_i386.i386RegisterContext, i386WatchMixin):
def __init__(self):
# Mixin our i386 envi architecture module and register context
e_i386.i386Module.__init__(self)
# FIXME tracer base should inherit from RegisterContext and we should
# just have to load a register definition!
e_i386.i386RegisterContext.__init__(self)
i386WatchMixin.__init__(self)
self.setMeta('Architecture', 'i386')
[docs] def archGetStackTrace(self):
self.requireAttached()
current = 0
sanity = 1000
frames = []
#FIXME make these by register index
#FIXME make these GPREG stuff! (then both are the same)
ebp = self.getRegisterByName("ebp")
eip = self.getRegisterByName("eip")
frames.append((eip,ebp))
while ebp != 0 and current < sanity:
try:
buf = self.readMemory(ebp, 8)
ebp,eip = struct.unpack("<LL",buf)
frames.append((eip,ebp))
current += 1
except:
break
return frames