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)