Package vdb :: Package stalker
[hide private]
[frames] | no frames]

Source Code for Package vdb.stalker

  1  '''
 
  2  The stalker subsystem is a breakpoint based coverage tool
 
  3  ''' 
  4  
 
  5  import vtrace 
  6  
 
  7  import envi 
  8  import envi.memory as e_mem 
  9  import envi.codeflow as e_codeflow 
 10  
 
11 -class StalkerCodeFlow(e_codeflow.CodeFlowContext):
12
13 - def __init__(self, trace):
14 e_codeflow.CodeFlowContext.__init__(self, trace) 15 self.trace = trace 16 self.setupBreakLists(None)
17
18 - def setupBreakLists(self, mmap):
19 self.mmap = mmap 20 self.bplist = [] # Block Breaks 21 self.sbreaks = [] # Stalker Breaks 22 self.scbreaks = [] # Callbreaks
23
24 - def _cb_opcode(self, va, op, branches):
25 26 ret = [] 27 28 for br,bflags in branches: 29 30 if bflags & envi.BR_DEREF and br != None: 31 bflags &= ~envi.BR_DEREF # Mask it back out... 32 if not self.trace.probeMemory(br, 1, e_mem.MM_READ): 33 continue 34 35 br = self.trace.readMemoryFormat(br, '<P')[0] 36 37 # Skip branches to other maps... 38 if br != None and self.trace.getMemoryMap(br) != self.mmap: 39 continue 40 41 ret.append( (br, bflags) ) 42 43 # Procedural branches to regs etc must be marked 44 # Otherwise, add another breakpoint like us 45 if bflags & envi.BR_PROC: 46 if br == None: 47 self.scbreaks.append(op.va) 48 else: 49 self.sbreaks.append(br) 50 continue 51 52 if br == None: 53 #print 'Skipping a branch from 0x%.8x: %s' % (op.va, repr(op)) 54 self.scbreaks.append(op.va) 55 continue 56 57 # Conditional branches always create new blocks... 58 if bflags & envi.BR_COND: 59 self.bplist.append(br) 60 continue 61 62 # Even non-conditional jmp's will create new blocks for now... 63 if br != op.va + len(op): 64 self.bplist.append(br) 65 continue 66 67 return ret
68
69 -class StalkerBreak(vtrace.Breakpoint):
70 71 ''' 72 Stalker breakpoints are added to function entry points 73 to trigger code-flow analysis and subsequent block breakpoint 74 addition. 75 ''' 76
77 - def __init__(self, address, expression=None):
78 vtrace.Breakpoint.__init__(self, address, expression=expression) 79 self.fastbreak = True 80 self.mymap = None
81
82 - def resolvedaddr(self, trace, address):
83 vtrace.Breakpoint.resolvedaddr(self, trace, address) 84 self.mymap = trace.getMemoryMap(address)
85
86 - def notify(self, event, trace):
87 self.trace = trace 88 89 # Get out of the way 90 self.enabled = False 91 self.deactivate(trace) 92 93 breaks = trace.getMeta('StalkerBreaks') 94 h = trace.getMeta('StalkerHits') 95 h.append(self.address) 96 97 cf = trace.getMeta('StalkerCodeFlow') 98 if cf == None: 99 cf = StalkerCodeFlow(trace) 100 trace.setMeta('StalkerCodeFlow', cf) 101 102 cf.setupBreakLists(self.mymap) 103 cf.addCodeFlow(self.address, persist=True) 104 105 for va in cf.bplist: 106 if breaks.get(va): 107 continue 108 breaks[va] = True 109 #print 'block: 0x%.8x' % va 110 b = StalkerBlockBreak(va) 111 bid = trace.addBreakpoint(b) 112 113 for va in cf.sbreaks: 114 if breaks.get(va): 115 continue 116 breaks[va] = True 117 #print 'func: 0x%.8x' % va 118 b = StalkerBreak(va) 119 bid = trace.addBreakpoint(b) 120 121 for va in cf.scbreaks: 122 if breaks.get(va): 123 continue 124 breaks[va] = True 125 #print 'call: 0x%.8x' % va 126 b = StalkerDynBreak(va) 127 bid = trace.addBreakpoint(b)
128
129 -class StalkerBlockBreak(vtrace.Breakpoint):
130 ''' 131 A breakpoint object which is put on codeblock boundaries 132 to track hits. 133 ''' 134
135 - def __init__(self, address, expression=None):
136 vtrace.Breakpoint.__init__(self, address, expression=expression) 137 self.fastbreak = True
138
139 - def notify(self, event, trace):
140 h = trace.getMeta('StalkerHits') 141 h.append(self.address) 142 self.enabled = False 143 self.deactivate(trace) 144 trace.runAgain()
145
146 -class StalkerDynBreak(vtrace.Breakpoint):
147 148 ''' 149 A breakpoint which is placed on dynamic branches to track 150 code flow across them. 151 ''' 152
153 - def __init__(self, address, expression=None):
154 vtrace.Breakpoint.__init__(self, address, expression=expression) 155 self.fastbreak = True 156 self.mymap = None 157 self.lasthit = None 158 self.lastcnt = 0
159
160 - def resolvedaddr(self, trace, address):
161 vtrace.Breakpoint.resolvedaddr(self, trace, address) 162 self.mymap = trace.getMemoryMap(address)
163
164 - def notify(self, event, trace):
165 166 trace.runAgain() 167 168 self.deactivate(trace) 169 op = trace.parseOpcode(self.address) 170 # Where is the call going? 171 dva = op.getOperValue(0, emu=trace) 172 173 if self.lasthit == dva: 174 self.lastcnt += 1 175 else: 176 self.lasthit = dva 177 self.lastcnt = 0 178 179 #print 'Dynamic: 0x%.8x: %s -> 0x%.8x' % (self.address, repr(op), dva) 180 if trace.getMemoryMap(dva) == self.mymap: 181 addStalkerEntry(trace, dva) 182 183 if self.lastcnt > 10: # FIXME what should this be??!?! 184 self.lasthit = None 185 self.lastcnt = 0 186 self.enabled = False 187 else: 188 self.activate(trace)
189
190 -def initStalker(trace):
191 if trace.getMeta('StalkerBreaks') == None: 192 trace.setMeta('StalkerBreaks', {}) 193 trace.setMeta('StalkerHits', [])
194
195 -def clearStalkerHits(trace):
196 ''' 197 Clear the stalker hit list for the given trace 198 ''' 199 initStalker(trace) 200 trace.setMeta('StalkerHits', [])
201
202 -def getStalkerHits(trace):
203 ''' 204 Retrieve the list of blocks hit in the current stalker 205 ''' 206 initStalker(trace) 207 return trace.getMeta('StalkerHits', [])
208
209 -def clearStalkerBreaks(trace):
210 ''' 211 Cleanup all stalker breaks and metadata 212 ''' 213 initStalker(trace) 214 breaks = trace.getMeta('StalkerBreaks', {}) 215 trace.setMeta('StalkerCodeFlow', None) 216 bpaddrs = list(breaks.keys()) 217 for va in bpaddrs: 218 bp = trace.getBreakpointByAddr(va) 219 if bp != None: 220 trace.removeBreakpoint(bp.id) 221 breaks.pop(va, None)
222
223 -def resetStalkerBreaks(trace):
224 ''' 225 Re-enable all previously hit stalker breakpoints. 226 ''' 227 initStalker(trace) 228 breaks = trace.getMeta('StalkerBreaks', {}) 229 bpaddrs = list(breaks.keys()) 230 trace.fb_bp_done = False # FIXME HACK 231 for va in bpaddrs: 232 bp = trace.getBreakpointByAddr(va) 233 if bp != None: 234 trace.setBreakpointEnabled(bp.id, enabled=True)
235
236 -def addStalkerEntry(trace, va):
237 ''' 238 Add stalker coverage beginning with the specified entry point 239 ''' 240 initStalker(trace) 241 b = trace.getMeta('StalkerBreaks') 242 if b.get(va): 243 return 244 bp = StalkerBreak(va) 245 trace.addBreakpoint(bp) 246 b[va] = True
247