Source code for vtrace.snapshot
"""
All the code related to vtrace process snapshots
and TraceSnapshot classes.
"""
import sys
import copy
import cPickle as pickle
import envi
import envi.memory as e_mem
import envi.resolver as e_resolv
import vtrace
import vtrace.platforms.base as v_base
[docs]class TraceSnapshot(
vtrace.Trace,
v_base.TracerBase,
):
"""
A tracer snapshot is similar to a traditional "core file" except that
you may also have memory only snapshots that are never written to disk.
TraceSnapshots allow you to take a picture of a process from a given point
in it's execution and manipulate/test from there or save it to disk for later
analysis...
"""
def __init__(self, snapdict):
self.s_snapcache = {}
self.s_snapdict = snapdict
# a seperate parser for each version...
if snapdict['version'] == 1:
self.s_version = snapdict['version']
self.s_threads = snapdict['threads']
self.s_regs = snapdict['regs']
self.s_maps = snapdict['maps']
self.s_mem = snapdict['mem']
self.metadata = snapdict['meta']
self.s_stacktrace = snapdict['stacktrace']
self.s_exe = snapdict['exe']
self.s_fds = snapdict['fds']
self.localvars = snapdict.get('vars', {})
else:
raise Exception("ERROR: Unknown snapshot version!")
# In the ghetto!
archname = self.metadata.get('Architecture')
envi.stealArchMethods(self, archname)
vtrace.Trace.__init__(self)
v_base.TracerBase.__init__(self)
# This will re-init meta... *sigh* set it back...
self.metadata = snapdict['meta']
# Steal the reg defs of the first thread
rinfo = self.s_regs.items()[0][1]
self.setRegisterInfo(rinfo)
#FIXME hard-coded page size!
self.s_map_lookup = {}
for map in self.s_maps:
for i in range(map[0],map[0] + map[1], 4096):
self.s_map_lookup[i] = map
# Lets get some symbol resolvers created for our libraries
#for fname in self.getNormalizedLibNames():
#subres = e_resolv.FileSymbol(fname,
self.running = False
self.attached = True
# So that we pickle
self.bplock = None
self.thread = None
[docs] def saveToFd(self, fd):
'''
Save this snapshot to the given file like object
for later reloading...
'''
pickle.dump(self.s_snapdict, fd)
[docs] def saveToFile(self, filename):
"""
Save a snapshot to file for later reading in...
"""
f = file(filename, "wb")
self.saveToFd(f)
f.close()
[docs] def getMemoryMap(self, addr):
base = addr & 0xfffff000
return self.s_map_lookup.get(base, None)
[docs] def getExe(self):
return self.s_exe
[docs] def getStackTrace(self):
tid = self.getMeta("ThreadId")
tr = self.s_stacktrace.get(tid, None)
if tr == None:
raise Exception("ERROR: Invalid thread id specified")
return tr
[docs] def cacheRegs(self, threadid):
pass
# FIXME regs in snapshots are broke...
[docs] def syncRegs(self):
pass
[docs]def loadSnapshot(filename):
'''
Load a vtrace process snapshot from a file
'''
sfile = file(filename, "rb")
snapdict = pickle.load(sfile)
return TraceSnapshot(snapdict)
[docs]def takeSnapshot(trace):
"""
Take a snapshot of the process from the current state and return
a reference to a tracer which wraps a "snapshot" or "core file".
"""
sd = dict()
orig_thread = trace.getMeta("ThreadId")
regs = dict()
stacktrace = dict()
for thrid,tdata in trace.getThreads().items():
ctx = trace.getRegisterContext(thrid)
reginfo = ctx.getRegisterInfo()
regs[thrid] = reginfo
try:
stacktrace[thrid] = trace.getStackTrace()
except Exception, msg:
print >> sys.stderr, "WARNING: Failed to get stack trace for thread 0x%.8x" % thrid
mem = dict()
maps = []
for base,size,perms,fname in trace.getMemoryMaps():
try:
mem[base] = trace.readMemory(base, size)
maps.append((base,size,perms,fname))
except Exception, msg:
print >> sys.stderr, "WARNING: Can't snapshot memmap at 0x%.8x (%s)" % (base,msg)
# If the contents here change, change the version...
sd['version'] = 1
sd['threads'] = trace.getThreads()
sd['regs'] = regs
sd['maps'] = maps
sd['mem'] = mem
sd['meta'] = copy.deepcopy(trace.metadata)
sd['stacktrace'] = stacktrace
sd['exe'] = trace.getExe()
sd['fds'] = trace.getFds()
sd['vars'] = trace.localvars
return TraceSnapshot(snapdict=sd)