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

Source Code for Package vdb

   1  import os 
   2  import re 
   3  import sys 
   4  import pprint 
   5  import signal 
   6  import string 
   7  import traceback 
   8   
   9  from ConfigParser import * 
  10   
  11  from cmd import * 
  12  from struct import * 
  13  from getopt import getopt 
  14  from UserDict import * 
  15  from threading import * 
  16   
  17  import vtrace 
  18  import vtrace.util as v_util 
  19  import vtrace.snapshot as vs_snap 
  20  import vtrace.notifiers as v_notif 
  21   
  22  import vdb 
  23  import vdb.stalker as v_stalker 
  24  import vdb.extensions as v_ext 
  25   
  26  import envi 
  27  import envi.cli as e_cli 
  28  import envi.bits as e_bits 
  29  import envi.memory as e_mem 
  30  import envi.config as e_config 
  31  import envi.resolver as e_resolv 
  32  import envi.memcanvas as e_canvas 
  33   
  34  import vstruct 
  35  import vstruct.primitives as vs_prims 
  36   
  37  vdb.basepath = vdb.__path__[0] + "/" 
  38   
39 -class VdbLookup(UserDict):
40 - def __init__(self, initdict={}):
41 UserDict.__init__(self) 42 for key,val in initdict.items(): 43 self.__setitem__(self, key, value)
44
45 - def __setitem__(self, key, item):
46 UserDict.__setitem__(self, key, item) 47 UserDict.__setitem__(self, item, key)
48
49 -class ScriptThread(Thread):
50 - def __init__(self, cobj, locals):
51 Thread.__init__(self) 52 self.setDaemon(True) 53 self.cobj = cobj 54 self.locals = locals
55
56 - def run(self):
57 try: 58 exec(self.cobj, self.locals) 59 except Exception, e: 60 traceback.print_exc() 61 print "Script Error: ",e
62
63 -class VdbTrace:
64 """ 65 Used to hand thing that need a persistant reference to a trace 66 when using vdb to manage tracers. 67 """
68 - def __init__(self, db):
69 self.db = db
70
71 - def attach(self, pid):
72 # Create a new tracer for the debugger and attach. 73 trace = self.db.newTrace() 74 trace.attach(pid)
75 76 # Take over all notifier registration
77 - def registerNotifier(self, event, notif):
78 self.db.registerNotifier(event, notif)
79
80 - def deregisterNotifier(self, event, notif):
81 self.db.deregisterNotifier(event, notif)
82 83 #FIXME should we add modes to this? 84
85 - def selectThread(self, threadid):
86 #FIXME perhaps a thread selected LOCAL event? 87 trace = self.db.getTrace() 88 trace.selectThread(threadid) 89 self.db.fireLocalNotifiers(vtrace.NOTIFY_BREAK, trace)
90
91 - def __getattr__(self, name):
92 return getattr(self.db.getTrace(), name)
93 94 defconfig = """ 95 [Vdb] 96 97 [RegisterView] 98 i386=eax,ebx,ecx,edx,esi,edi,eip,esp,ebp,eflags,ds,es,cs,fs,gs,ss 99 x64=rax,rbx,rcx,rdx,rsi,rdi,rip,rsp,rbp,r8,r9,r10,r11,r12,r13,r14,r15 100 101 [Aliases] 102 <f1>=stepi 103 <f2>=go -I 1 104 <f5>=go 105 """ 106
107 -class Vdb(e_cli.EnviMutableCli, v_notif.Notifier, v_util.TraceManager):
108 109 """ 110 A VDB object is a debugger object which may be used to embed full 111 debugger like functionality into a python application. The 112 Vdb object contains a CLI impelementation which extends envi.cli> 113 """ 114
115 - def __init__(self, trace=None):
116 v_notif.Notifier.__init__(self) 117 v_util.TraceManager.__init__(self) 118 119 if trace == None: 120 trace = vtrace.getTrace() 121 122 arch = trace.getMeta("Architecture") 123 self.arch = envi.getArchModule(arch) 124 self.difftracks = {} 125 self.waitlib = None 126 self.bpcmds = {} 127 128 self.server = None 129 130 self.runagain = False # A one-time thing for the cli 131 self.windows_jit_event = None 132 133 # We hangn on to an opcode renderer instance 134 self.opcoderend = None 135 136 # If a VdbGui instance is present it will set this. 137 self.gui = None 138 139 self.setMode("NonBlocking", True) 140 141 self.manageTrace(trace) 142 self.registerNotifier(vtrace.NOTIFY_ALL, self) 143 144 # FIXME if config verbose 145 #self.registerNotifier(vtrace.NOTIFY_ALL, vtrace.VerboseNotifier()) 146 147 self.vdbhome = e_config.gethomedir(".vdb") 148 149 self.loadConfig() 150 151 self.setupSignalLookups() 152 153 # Ok... from here down we're handing everybody the crazy 154 # on-demand-resolved trace object. 155 trace = vdb.VdbTrace(self) 156 e_cli.EnviMutableCli.__init__(self, trace, self.config, symobj=trace) 157 158 self.prompt = "vdb > " 159 self.banner = "Welcome To VDB!\n" 160 161 self.loadDefaultRenderers(trace) 162 self.loadExtensions(trace)
163
164 - def loadConfig(self):
165 cfgfile = None 166 if self.vdbhome != None: 167 if not os.path.exists(self.vdbhome): 168 os.mkdir(self.vdbhome) 169 cfgfile = os.path.join(self.vdbhome, "vdb.conf") 170 171 self.config = e_config.EnviConfig(filename=cfgfile, defaults=defconfig)
172
173 - def loadDefaultRenderers(self, trace):
174 import envi.memcanvas.renderers as e_render 175 import vdb.renderers as v_rend 176 # FIXME check endianness 177 self.canvas.addRenderer("bytes", e_render.ByteRend()) 178 self.canvas.addRenderer("u_int_16", e_render.ShortRend()) 179 self.canvas.addRenderer("u_int_32", e_render.LongRend()) 180 self.canvas.addRenderer("u_int_64", e_render.QuadRend()) 181 self.opcoderend = v_rend.OpcodeRenderer(self.trace) 182 self.canvas.addRenderer("disasm", self.opcoderend) 183 drend = v_rend.DerefRenderer(self.trace) 184 self.canvas.addRenderer("Deref View", drend) 185 srend = v_rend.SymbolRenderer(self.trace) 186 self.canvas.addRenderer('Symbols View', srend)
187
188 - def verror(self, msg, addnl=True):
189 if addnl: 190 msg += "\n" 191 sys.stderr.write(msg)
192
193 - def loadExtensions(self, trace):
194 """ 195 Load up any extensions which are relevant for the current tracer's 196 platform/arch/etc... 197 """ 198 v_ext.loadExtensions(self, trace)
199
200 - def getTrace(self):
201 return self.trace
202
203 - def newTrace(self):
204 """ 205 Generate a new trace for this vdb instance. This fixes many of 206 the new attach/exec data munging issues because tracer re-use is 207 *very* sketchy... 208 """ 209 oldtrace = self.getTrace() 210 if oldtrace.isRunning(): 211 oldtrace.sendBreak() 212 if oldtrace.isAttached(): 213 oldtrace.detach() 214 215 self.trace = oldtrace.buildNewTrace() 216 oldtrace.release() 217 218 self.bpcmds = {} 219 self.manageTrace(self.trace) 220 return self.trace
221
222 - def setupSignalLookups(self):
223 self.siglookup = VdbLookup() 224 225 self.siglookup[0] = "None" 226 227 for name in dir(signal): 228 if name[:3] == "SIG" and "_" not in name: 229 self.siglookup[name] = getattr(signal, name)
230
231 - def getSignal(self, sig):
232 """ 233 If given an int, return the name, for a name, return the int ;) 234 """ 235 return self.siglookup.get(sig,None)
236
237 - def parseExpression(self, exprstr):
238 return self.trace.parseExpression(exprstr)
239
240 - def getExpressionLocals(self):
241 r = vtrace.VtraceExpressionLocals(self.trace) 242 r['db'] = self 243 r['vprint'] = self.vprint 244 return r
245
246 - def reprPointer(self, address):
247 """ 248 Return a string representing the best known name for 249 the given address 250 """ 251 if not address: 252 return "NULL" 253 254 # Do we have a symbol? 255 sym = self.trace.getSymByAddr(address, exact=False) 256 if sym != None: 257 return "%s + %d" % (repr(sym),address-long(sym)) 258 259 # Check if it's a thread's stack 260 for tid,tinfo in self.trace.getThreads().items(): 261 ctx = self.trace.getRegisterContext(tid) 262 sp = ctx.getStackCounter() 263 stack,size,perms,fname = self.trace.getMemoryMap(sp) 264 if address >= stack and address < (stack+size): 265 off = address - sp 266 op = "+" 267 if off < 0: 268 op = "-" 269 off = abs(off) 270 return "tid:%d sp%s%s (stack)" % (tid,op,off) 271 272 map = self.trace.getMemoryMap(address) 273 if map: 274 return map[3] 275 276 return "Who knows?!?!!?"
277
278 - def script(self, filename, args=[]):
279 """ 280 Execute a vdb script. 281 """ 282 text = file(filename).read() 283 self.scriptstring(text, filename, args)
284
285 - def scriptstring(self, script, filename, args=[]):
286 """ 287 Do the actual compile and execute for the script data 288 contained in script which was read from filename. 289 """ 290 local = self.getExpressionLocals() 291 cobj = compile(script, filename, "exec") 292 sthr = ScriptThread(cobj, local) 293 sthr.start()
294
295 - def notify(self, event, trace):
296 297 pid = trace.getPid() 298 tid = trace.getCurrentThread() 299 300 if event == vtrace.NOTIFY_ATTACH: 301 self.vprint("Attached to : %d" % pid) 302 self.waitlib = None 303 self.difftracks = {} 304 305 if self.windows_jit_event: 306 trace._winJitEvent(self.windows_jit_event) 307 self.windows_jit_event = None 308 309 elif event == vtrace.NOTIFY_CONTINUE: 310 pass 311 312 elif event == vtrace.NOTIFY_DETACH: 313 self.difftracks = {} 314 self.vprint("Detached from %d" % pid) 315 316 elif event == vtrace.NOTIFY_SIGNAL: 317 318 # FIXME move all this code into a bolt on notifier! 319 thr = trace.getCurrentThread() 320 signo = trace.getCurrentSignal() 321 322 self.vprint("Process Recieved Signal %d (0x%.8x) (Thread: %d (0x%.8x))" % (signo, signo, thr, thr)) 323 324 faddr,fperm = trace.getMemoryFault() 325 if faddr != None: 326 accstr = e_mem.getPermName(fperm) 327 self.vprint('Memory Fault: addr: 0x%.8x perm: %s' % (faddr, accstr)) 328 329 elif event == vtrace.NOTIFY_BREAK: 330 331 trace.setMeta('PendingBreak', False) 332 bp = trace.getCurrentBreakpoint() 333 if bp: 334 self.vprint("Thread: %d Hit Break: %s" % (tid, repr(bp))) 335 cmdstr = self.bpcmds.get(bp.id, None) 336 if cmdstr != None: 337 self.onecmd(cmdstr) 338 339 else: 340 self.vprint("Thread: %d NOTIFY_BREAK" % tid) 341 if self.runagain: # One-time run-again behavior (for cli option) 342 trace.runAgain() 343 self.runagain = False 344 345 elif event == vtrace.NOTIFY_EXIT: 346 ecode = trace.getMeta('ExitCode') 347 self.vprint("PID %d exited: %d (0x%.8x)" % (pid,ecode,ecode)) 348 349 elif event == vtrace.NOTIFY_LOAD_LIBRARY: 350 self.vprint("Loading Binary: %s" % trace.getMeta("LatestLibrary",None)) 351 if self.waitlib != None: 352 normname = trace.getMeta('LatestLibraryNorm', None) 353 if self.waitlib == normname: 354 self.waitlib = None 355 trace.runAgain(False) 356 357 elif event == vtrace.NOTIFY_UNLOAD_LIBRARY: 358 self.vprint("Unloading Binary: %s" % trace.getMeta("LatestLibrary",None)) 359 360 elif event == vtrace.NOTIFY_CREATE_THREAD: 361 self.vprint("New Thread: %d" % tid) 362 363 elif event == vtrace.NOTIFY_EXIT_THREAD: 364 ecode = trace.getMeta("ExitCode", 0) 365 self.vprint("Exit Thread: %d (ecode: 0x%.8x (%d))" % (tid,ecode,ecode)) 366 367 elif event == vtrace.NOTIFY_DEBUG_PRINT: 368 s = "<unknown>" 369 win32 = trace.getMeta("Win32Event", None) 370 if win32: 371 s = win32.get("DebugString", "<unknown>") 372 self.vprint("DEBUG PRINT: %s" % s)
373 374 ################################################################### 375 # 376 # All CLI extension commands start here 377 # 378
379 - def do_vstruct(self, line):
380 """ 381 List the available structure modules and optionally 382 structure definitions from a particular module in the 383 current vstruct. 384 385 Usage: vstruct [modname] 386 """ 387 if len(line) == 0: 388 self.vprint("\nVStruct Namespaces:") 389 plist = self.trace.getStructNames() 390 else: 391 self.vprint("\nKnown Structures (from %s):" % line) 392 plist = self.trace.getStructNames(namespace=line) 393 394 for n in plist: 395 self.vprint(str(n)) 396 self.vprint("\n")
397
398 - def do_dis(self, line):
399 """ 400 Print out the opcodes for a given address expression 401 402 Usage: dis <address expression> [<size expression>] 403 """ 404 405 argv = e_cli.splitargs(line) 406 407 size = 20 408 argc = len(argv) 409 if argc == 0: 410 addr = self.trace.getProgramCounter() 411 else: 412 addr = self.parseExpression(argv[0]) 413 414 if argc > 1: 415 size = self.parseExpression(argv[1]) 416 417 self.vprint("Dissassembly:") 418 self.canvas.renderMemory(addr, size, rend=self.opcoderend)
419
420 - def do_var(self, line):
421 """ 422 Set a variable in the expression parsing context. This allows 423 for scratchspace names (python compatable names) to be used in 424 expressions. 425 426 Usage: var <name> <addr_expression> 427 428 NOTE: The address expression *must* resolve at the time you set it. 429 """ 430 t = self.trace 431 432 if len(line): 433 argv = e_cli.splitargs(line) 434 if len(argv) == 1: 435 return self.do_help("var") 436 name = argv[0] 437 expr = " ".join(argv[1:]) 438 addr = t.parseExpression(expr) 439 t.setVariable(name, addr) 440 441 vars = t.getVariables() 442 self.vprint("Current Variables:") 443 if not vars: 444 self.vprint("None.") 445 else: 446 vnames = vars.keys() 447 vnames.sort() 448 for n in vnames: 449 val = vars.get(n) 450 if type(val) in (int, long): 451 self.vprint("%20s = 0x%.8x" % (n,val)) 452 else: 453 rstr = repr(val) 454 if len(rstr) > 30: 455 rstr = rstr[:30] + '...' 456 self.vprint("%20s = %s" % (n,rstr))
457
458 - def do_alloc(self, args):
459 #""" 460 #Allocate a chunk of memory in the target process. You may 461 #optionally specify permissions and a suggested base address. 462 463 #Usage: alloc [-p rwx] [-s <base>] <size> 464 #""" 465 """ 466 Allocate a chunk of memory in the target process. It will be 467 allocated with rwx permissions. 468 469 Usage: alloc <size expr> 470 """ 471 if len(args) == 0: 472 return self.do_help("alloc") 473 t = self.trace 474 #argv = e_cli.splitargs(args) 475 try: 476 size = t.parseExpression(args) 477 base = t.allocateMemory(size) 478 self.vprint("Allocated %d bytes at: 0x%.8x" % (size, base)) 479 except Exception, e: 480 traceback.print_exc() 481 self.vprint("Allocation Error: %s" % e)
482
483 - def do_memload(self, line):
484 ''' 485 Load a file into memory. (straight mapping, no parsing) 486 487 Usage: memload <filename> 488 ''' 489 argv = e_cli.splitargs(line) 490 if len(argv) != 1: 491 return self.do_help('memload') 492 493 fname = argv[0] 494 if not os.path.isfile(fname): 495 self.vprint('Invalid File: %s' % fname) 496 return 497 498 fbytes = file(fname, 'rb').read() 499 memva = self.trace.allocateMemory(len(fbytes)) 500 self.trace.writeMemory(memva, fbytes) 501 502 self.vprint('Loaded At: 0x%.8x (%d bytes)' % (memva, len(fbytes)))
503
504 - def do_struct(self, args):
505 """ 506 Break out a strcuture from memory. You may use the command 507 "vstruct" to show the known structures in vstruct. 508 509 Usage: struct <StructName> <vtrace expression> 510 """ 511 try: 512 clsname, vexpr = e_cli.splitargs(args) 513 except: 514 return self.do_help("struct") 515 516 t = self.trace 517 518 addr = t.parseExpression(vexpr) 519 s = t.getStruct(clsname, addr) 520 self.vprint(s.tree(va=addr))
521
522 - def do_signal(self, args):
523 """ 524 Show the current pending signal/exception code. 525 526 Usage: signal 527 """ 528 # FIXME -i do NOT pass the signal on to the target process. 529 t = self.trace 530 t.requireAttached() 531 cursig = t.getCurrentSignal() 532 if cursig == None: 533 self.vprint('No Pending Signals/Exceptions!') 534 else: 535 self.vprint("Current signal: %d (0x%.8x)" % (cursig, cursig))
536
537 - def do_snapshot(self, line):
538 """ 539 Take a process snapshot of the current (stopped) trace and 540 save it to the specified file. 541 542 Usage: snapshot <filename> 543 """ 544 if len(line) == 0: 545 return self.do_help("snapshot") 546 alist = e_cli.splitargs(line) 547 if len(alist) != 1: 548 return self.do_help("snapshot") 549 550 t = self.trace 551 t.requireAttached() 552 self.vprint("Taking Snapshot...") 553 snap = vs_snap.takeSnapshot(t) 554 self.vprint("Saving To File") 555 snap.saveToFile(alist[0]) 556 self.vprint("Done") 557 snap.release()
558
559 - def do_ignore(self, args):
560 """ 561 Add the specified signal id (exception id for windows) to the ignored 562 signals list for the current trace. This will make the smallest possible 563 performance impact for that particular signal but will also not alert 564 you that it has occured. 565 566 Usage: ignore [options] [-c | <sigcode>...] 567 -d - Remove the specified signal codes. 568 -c - Include the *current* signal in the sigcode list 569 -C - Clear the list of ignored signals 570 571 Example: ignore -c # Ignore the currently posted signal 572 ignore -d 0x80000001 # Remove 0x80000001 from the ignores 573 """ 574 argv = e_cli.splitargs(args) 575 try: 576 opts,args = getopt(argv, 'Ccd') 577 except Exception, e: 578 return self.do_help('ignore') 579 580 remove = False 581 sigs = [] 582 583 for opt,optarg in opts: 584 if opt == '-c': 585 sig = self.trace.getCurrentSignal() 586 if sig == None: 587 self.vprint('No current signal to ignore!') 588 return 589 sigs.append(sig) 590 elif opt == '-C': 591 self.vprint('Clearing ignore list...') 592 self.trace.setMeta('IgnoredSignals', []) 593 elif opt == '-d': 594 remove = True 595 596 for arg in args: 597 sigs.append(self.trace.parseExpression(arg)) 598 599 for sig in sigs: 600 if remove: 601 self.vprint('Removing: 0x%.8x' % sig) 602 self.trace.delIgnoreSignal(sig) 603 else: 604 self.vprint('Adding: 0x%.8x' % sig) 605 self.trace.addIgnoreSignal(sig) 606 607 ilist = self.trace.getMeta("IgnoredSignals") 608 self.vprint("Currently Ignored Signals/Exceptions:") 609 for x in ilist: 610 self.vprint("0x%.8x (%d)" % (x, x))
611
612 - def do_exec(self, cmd):
613 """ 614 Execute a program with the given command line and 615 attach to it. 616 Usage: exec </some/where and some args> 617 """ 618 t = self.newTrace() 619 t.execute(cmd)
620
621 - def do_threads(self, line):
622 """ 623 List the current threads in the target process or select 624 the current thread context for the target tracer. 625 Usage: threads [thread id] 626 """ 627 self.trace.requireNotRunning() 628 if self.trace.isRunning(): 629 self.vprint("Can't list threads while running!") 630 return 631 632 if len(line) > 0: 633 thrid = int(line, 0) 634 self.trace.selectThread(thrid) 635 if self.gui != None: 636 self.gui.setTraceWindowsActive(True) 637 638 self.vprint("Current Threads:") 639 self.vprint("[thrid] [thrinfo] [pc]") 640 641 curtid = self.trace.getMeta("ThreadId") 642 for tid,tinfo in self.trace.getThreads().items(): 643 a = " " 644 if tid == curtid: 645 a = "*" 646 647 sus = "" 648 if self.trace.isThreadSuspended(tid): 649 sus = "(suspended)" 650 ctx = self.trace.getRegisterContext(tid) 651 pc = ctx.getProgramCounter() 652 self.vprint("%s%6d 0x%.8x 0x%.8x %s" % (a, tid, tinfo, pc, sus))
653
654 - def do_suspend(self, line):
655 """ 656 Suspend a thread. 657 658 Usage: suspend <-A | <tid>[ <tid>...]> 659 """ 660 argv = e_cli.splitargs(line) 661 try: 662 opts,args = getopt(argv, "A") 663 except Exception, e: 664 return self.do_help("suspend") 665 666 for opt,optarg in opts: 667 if opt == "-A": 668 # hehe... 669 args = [str(tid) for tid in self.trace.getThreads().keys()] 670 671 if not len(args): 672 return self.do_help("suspend") 673 674 for arg in args: 675 tid = int(arg) 676 self.trace.suspendThread(tid) 677 self.vprint("Suspended Thread: %d" % tid)
678
679 - def do_restart(self, line):
680 ''' 681 Restart the current process. 682 683 Usage: restart 684 685 NOTE: This only works if the process was exec'd to begin 686 with! 687 688 TODO: Plumb options for persisting bp's etc... 689 ''' 690 t = self.trace 691 cmdline = t.getMeta('ExecCommand') 692 if cmdline == None: 693 self.vprint('This trace was not fired with exec! (cannot restart)') 694 return 695 696 if t.isRunning(): 697 t.setMode("RunForever", False) 698 t.sendBreak() 699 700 if t.isAttached(): 701 t.detach() 702 703 t = self.newTrace() 704 t.execute(cmdline)
705
706 - def do_resume(self, line):
707 """ 708 Resume a thread. 709 710 Usage: resume <-A | <tid>[ <tid>...]> 711 """ 712 argv = e_cli.splitargs(line) 713 try: 714 opts,args = getopt(argv, "A") 715 except Exception, e: 716 return self.do_help("suspend") 717 718 for opt,optarg in opts: 719 if opt == "-A": 720 # hehe... 721 args = [str(tid) for tid in self.trace.getThreads().keys()] 722 723 if not len(args): 724 return self.do_help("resume") 725 726 for arg in args: 727 tid = int(arg) 728 self.trace.resumeThread(tid) 729 self.vprint("Resumed Thread: %d" % tid)
730 731 #def do_inject(self, line): 732
733 - def do_mode(self, args):
734 """ 735 Set modes in the tracers... 736 mode Foo=True/False 737 """ 738 if args: 739 mode,val = args.split("=") 740 newmode = eval(val) 741 self.setMode(mode, newmode) 742 else: 743 for key,val in self.trace.modes.items(): 744 self.vprint("%s -> %d" % (key,val))
745
746 - def do_reg(self, args):
747 """ 748 Show the current register values. Additionally, you may specify 749 name=<expression> to set a register 750 751 Usage: reg [regname=vtrace_expression] 752 """ 753 if len(args): 754 if args.find("=") == -1: 755 return self.do_help("reg") 756 regname,expr = args.split("=", 1) 757 val = self.trace.parseExpression(expr) 758 self.trace.setRegisterByName(regname, val) 759 self.vprint("%s = 0x%.8x" % (regname, val)) 760 return 761 762 regs = self.trace.getRegisters() 763 rnames = regs.keys() 764 rnames.sort() 765 final = [] 766 for r in rnames: 767 # Capitol names are used for reg vals that we don't want to see 768 # (by default) 769 if r.lower() != r: 770 continue 771 val = regs.get(r) 772 vstr = e_bits.hex(val, 4) 773 final.append(("%12s:0x%.8x (%d)" % (r,val,val))) 774 self.columnize(final)
775
776 - def do_stepi(self, line):
777 """ 778 Single step the target tracer. 779 Usage: stepi [ options ] 780 781 -A <addr> - Step to <addr> 782 -B - Step past the next branch instruction 783 -C <count> - Step <count> instructions 784 -R - Step to return from this function 785 -V - Show operand values during single step (verbose!) 786 787 """ 788 t = self.trace 789 argv = e_cli.splitargs(line) 790 try: 791 opts,args = getopt(argv, "A:BC:RV") 792 except Exception, e: 793 return self.do_help("stepi") 794 795 count = None 796 taddr = None 797 toret = False 798 tobrn = False 799 showop = False 800 801 for opt, optarg in opts: 802 if opt == '-A': 803 taddr = t.parseExpression(optarg) 804 805 elif opt == '-B': 806 tobrn = True 807 808 elif opt == '-C': 809 count = t.parseExpression(optarg) 810 811 elif opt == '-R': 812 toret = True 813 814 elif opt == '-V': 815 showop = True 816 817 if ( count == None 818 and taddr == None 819 and toret == False 820 and tobrn == False): 821 count = 1 822 823 oldmode = self.getMode('FastStep') 824 self.setMode('FastStep', True) 825 826 hits = 0 827 depth = 0 828 try: 829 while True: 830 831 pc = t.getProgramCounter() 832 833 if pc == taddr: 834 break 835 836 op = t.parseOpcode(pc) 837 838 sym = t.getSymByAddr(pc) 839 840 if sym != None: 841 self.canvas.addVaText(repr(sym), pc) 842 self.canvas.addText(':\n') 843 844 self.canvas.addText(' ' * max(depth,0)) 845 self.canvas.addVaText('0x%.8x' % pc, pc) 846 self.canvas.addText(': ') 847 op.render(self.canvas) 848 if showop: 849 self.canvas.addText(' ; ') 850 for oper in op.opers: 851 try: 852 val = oper.getOperValue(op, emu=t) 853 self.canvas.addText('0x%.8x ' % val) 854 except Exception, e: 855 self.canvas.addText(str(e)) 856 self.canvas.addText('\n') 857 858 if op.iflags & envi.IF_CALL: 859 depth += 1 860 861 elif op.iflags & envi.IF_RET: 862 depth -= 1 863 864 tid = t.getCurrentThread() 865 866 t.stepi() 867 868 # If we get an event from a different thread, get out! 869 if t.getCurrentThread() != tid: 870 break 871 872 # Break out if we have returned from the current function 873 if toret and depth < 0: 874 break 875 876 if depth < 0: 877 depth = 0 878 879 hits += 1 880 881 # If we have passed a conditional branch... 882 if tobrn == True and hits != 0: 883 884 if op.iflags & envi.IF_CALL: 885 break 886 887 if op.iflags & envi.IF_RET: 888 break 889 890 getout = False 891 for bva, bflags in op.getBranches(): 892 if bflags & envi.BR_COND: 893 getout = True 894 break 895 if getout: 896 break 897 898 899 if count != None and hits >= count: 900 break 901 902 if t.getCurrentSignal() != None: 903 break 904 905 if t.getMeta('PendingSignal'): 906 break 907 908 finally: 909 self.setMode('FastStep', oldmode) 910 # We ate all the events, tell things we have updated... 911 t.fireNotifiers(vtrace.NOTIFY_STEP)
912
913 - def do_go(self, line):
914 """ 915 Continue the target tracer. 916 -I go icount linear instructions forward (step over style) 917 -U go *out* of fcount frames (step out style) 918 <until addr> go until explicit address 919 920 Usage: go [-U <fcount> | -I <icount> | <until addr expression>] 921 """ 922 until = None 923 icount = None 924 fcount = None 925 926 argv = e_cli.splitargs(line) 927 try: 928 opts,args = getopt(argv, "U:I:") 929 except: 930 return self.do_help("go") 931 932 for opt,optarg in opts: 933 if opt == "-U": 934 if len(optarg) == 0: return self.do_help("go") 935 fcount = self.trace.parseExpression(optarg) 936 elif opt == "-I": 937 if len(optarg) == 0: return self.do_help("go") 938 icount = self.trace.parseExpression(optarg) 939 940 if icount != None: 941 addr = self.trace.getProgramCounter() 942 for i in xrange(icount): 943 addr += len(self.arch.makeOpcode(self.trace.readMemory(addr, 16))) 944 until = addr 945 946 elif fcount != None: 947 until = self.trace.getStackTrace()[fcount][0] 948 949 elif len(args): 950 until = self.trace.parseExpression(" ".join(args)) 951 952 if not until: 953 self.vprint("Running Tracer (use 'break' to stop it)") 954 955 self.trace.run(until=until)
956
957 - def do_gui(self, line):
958 ''' 959 Attempt to spawn the VDB gui. Assuming GTK etc are all installed. 960 ''' 961 if self.gui != None: 962 self.vprint('Gui already running!') 963 return 964 import vdb.gui 965 vdb.gui.main(self)
966
967 - def do_waitlib(self, line):
968 ''' 969 Run the target process until the specified library 970 (by normalized name such as 'kernel32' or 'libc') 971 is loaded. Disable waiting with -D. 972 973 Usage: waitlib [ -D | <libname> ] 974 ''' 975 t = self.trace 976 pid = t.getPid() 977 978 t.requireAttached() 979 980 argv = e_cli.splitargs(line) 981 try: 982 opts,args = getopt(argv, "D") 983 except: 984 return self.do_help("waitlib") 985 986 for opt, optarg in opts: 987 if opt == '-D': 988 self.vprint('Disabling Wait On: %s' % self.waitlib) 989 self.waitlib = None 990 return 991 992 if len(args) != 1: 993 return self.do_help('waitlib') 994 995 libname = args[0] 996 997 if t.getMeta('LibraryBases').get(libname) != None: 998 self.vprint('Library Already Loaded: %s' % libname) 999 return 1000 1001 self.vprint('Setting Waitlib: %s' % libname) 1002 self.waitlib = libname
1003
1004 - def do_server(self, port):
1005 """ 1006 Start a vtrace server on the local box. If the server 1007 is already running, show which processes are being remotely 1008 debugged. 1009 1010 Usage: server 1011 """ 1012 if port: 1013 vtrace.port = int(port) 1014 1015 if self.server == None: 1016 self.vprint('Starting vtrace server!') 1017 self.server = vtrace.startVtraceServer() 1018 return 1019 1020 self.vprint('Displaying remotely debugged traces:') 1021 shared = [ t for (n,t) in self.server.getSharedObjects() if isinstance(t, vtrace.Trace) ] 1022 if not shared: 1023 self.vprint('None.') 1024 return 1025 1026 for t in shared: 1027 1028 if not t.isAttached(): 1029 continue 1030 1031 runmsg = 'stopped' 1032 if t.isRunning(): 1033 runmsg = 'running' 1034 1035 pid = t.getPid() 1036 name = t.getMeta('ExeName', 'Unknown') 1037 self.vprint('%6d %.8s - %s' % (pid, runmsg, name))
1038
1039 - def do_syms(self, line):
1040 """ 1041 List symbols and by file. 1042 1043 Usage: syms [-s <pattern>] [filename] 1044 1045 With no arguments, syms will self.vprint(the possible 1046 libraries with symbol resolvers. Specify a library 1047 to see all the symbols for it. 1048 """ 1049 1050 argv = e_cli.splitargs(line) 1051 try: 1052 opts,args = getopt(argv, "s:") 1053 except: 1054 return self.do_help("syms") 1055 1056 pattern = None 1057 for opt,optarg in opts: 1058 if opt == "-s": 1059 pattern = optarg.lower() 1060 1061 libs = self.trace.getNormalizedLibNames() 1062 libs.sort() 1063 if len(args) == 0: 1064 self.vprint("Current Library Symbol Resolvers:") 1065 1066 if pattern == None: 1067 for libname in libs: 1068 self.vprint(" %s" % libname) 1069 else: 1070 for libname in libs: 1071 for sym in self.trace.getSymsForFile(libname): 1072 r = repr(sym) 1073 if pattern != None: 1074 if r.lower().find(pattern) == -1: 1075 continue 1076 self.vprint("0x%.8x %s" % (sym.value, r)) 1077 1078 else: 1079 libname = args[0] 1080 if libname not in libs: 1081 self.vprint("Unknown libname: %s" % libname) 1082 return 1083 if pattern: 1084 self.vprint("Matching Symbols From %s:" % libname) 1085 else: 1086 self.vprint("Symbols From %s:" % libname) 1087 1088 for sym in self.trace.getSymsForFile(libname): 1089 r = repr(sym) 1090 if pattern != None: 1091 if r.lower().find(pattern) == -1: 1092 continue 1093 self.vprint("0x%.8x %s" % (sym.value, r))
1094
1095 - def do_call(self, string):
1096 """ 1097 Allows a C-like syntax for calling functions inside 1098 the target process (from his context). 1099 Example: call printf("yermom %d", 10) 1100 """ 1101 self.trace.requireAttached() 1102 ind = string.index("(") 1103 if ind == -1: 1104 raise Exception('ERROR - call wants c-style syntax: ie call printf("yermom")') 1105 funcaddr = self.trace.parseExpression(string[:ind]) 1106 1107 try: 1108 args = eval(string[ind:]) 1109 except: 1110 raise Exception('ERROR - call wants c-style syntax: ie call printf("yermom")') 1111 1112 self.vprint("calling %s -> 0x%.8x" % (string[:ind], funcaddr)) 1113 self.trace.call(funcaddr, args)
1114
1115 - def do_bestname(self, args):
1116 """ 1117 Return the "best name" string for an address. 1118 1119 Usage: bestname <vtrace expression> 1120 """ 1121 if len(args) == 0: 1122 return self.do_help("bestname") 1123 addr = self.trace.parseExpression(args) 1124 self.vprint(self.reprPointer(addr))
1125
1126 - def do_EOF(self, string):
1127 self.vprint("No.. this is NOT a python interpreter... use quit ;)")
1128
1129 - def do_quit(self,args):
1130 """ 1131 Quit VDB 1132 1133 use "quit force" to hard-force a quit regardless of everything. 1134 """ 1135 1136 if args == 'force': 1137 print 'Quitting by force!' 1138 os._exit(0) 1139 1140 try: 1141 if self.trace.isRunning(): 1142 self.trace.setMode("RunForever", False) 1143 self.trace.sendBreak() 1144 1145 if self.trace.isAttached(): 1146 self.vprint("Detaching...") 1147 self.trace.detach() 1148 1149 self.vprint("Exiting...") 1150 e_cli.EnviMutableCli.do_quit(self, args) 1151 1152 self.trace.release() 1153 1154 except Exception, e: 1155 self.vprint('Exception during quit (may need: quite force): %s' % e)
1156
1157 - def do_detach(self, args):
1158 """ 1159 Detach from the current tracer 1160 """ 1161 self.trace.requireAttached() 1162 if self.trace.isRunning(): 1163 self.trace.setMode("RunForever", False) 1164 self.trace.sendBreak() 1165 self.trace.detach()
1166
1167 - def do_attach(self, args):
1168 """ 1169 Attach to a process by PID or by process name. In 1170 the event of more than one process by a given name, 1171 attach to the last (most recently created) one in 1172 the list. 1173 1174 Usage: attach [<pid>,<name>] 1175 1176 NOTE: This is *not* a regular expression. The given 1177 string must be found as a substring of the process 1178 name... 1179 """ 1180 pid = None 1181 try: 1182 pid = int(args) 1183 except ValueError, e: 1184 1185 for mypid, pname in self.trace.ps(): 1186 if pname.find(args) != -1: 1187 pid = mypid 1188 1189 if pid == None: 1190 return self.do_help('attach') 1191 1192 self.vprint("Attaching to %d" % pid) 1193 self.newTrace().attach(pid)
1194
1195 - def do_autocont(self, line):
1196 """ 1197 Manipulate the auto-continue behavior for the trace. This 1198 will cause particular event types to automagically continue 1199 execution. 1200 1201 Usage: autocont [event name] 1202 """ 1203 argv = e_cli.splitargs(line) 1204 acnames = ["attach", 1205 "signal", 1206 "break", 1207 "loadlib", 1208 "unloadlib", 1209 "createthread", 1210 "exitthread", 1211 "dbgprint"] 1212 1213 acvals = [ vtrace.NOTIFY_ATTACH, 1214 vtrace.NOTIFY_SIGNAL, 1215 vtrace.NOTIFY_BREAK, 1216 vtrace.NOTIFY_LOAD_LIBRARY, 1217 vtrace.NOTIFY_UNLOAD_LIBRARY, 1218 vtrace.NOTIFY_CREATE_THREAD, 1219 vtrace.NOTIFY_EXIT_THREAD, 1220 vtrace.NOTIFY_DEBUG_PRINT] 1221 1222 c = self.trace.getAutoContinueList() 1223 1224 if len(line): 1225 try: 1226 index = acnames.index(line) 1227 except ValueError, e: 1228 self.vprint("Unknown event name: %s" % line) 1229 return 1230 sig = acvals[index] 1231 if sig in c: 1232 self.trace.disableAutoContinue(sig) 1233 c.remove(sig) 1234 else: 1235 self.trace.enableAutoContinue(sig) 1236 c.append(sig) 1237 1238 self.vprint("Auto Continue Status:") 1239 for i in range(len(acnames)): 1240 name = acnames[i] 1241 sig = acvals[i] 1242 acont = False 1243 if sig in c: 1244 acont = True 1245 self.vprint("%s %s" % (name.rjust(14),repr(acont)))
1246
1247 - def emptyline(self):
1248 self.do_help("")
1249
1250 - def do_bt(self, line):
1251 """ 1252 Show a stack backtrace for the currently selected thread. 1253 1254 Usage: bt 1255 """ 1256 self.vprint(" [ PC ] [ Frame ] [ Location ]") 1257 idx = 0 1258 for pc,frame in self.trace.getStackTrace(): 1259 self.vprint("[%3d] 0x%.8x 0x%.8x %s" % (idx,pc,frame,self.reprPointer(pc))) 1260 idx += 1
1261
1262 - def do_lm(self, args):
1263 """ 1264 Show the loaded libraries and their base addresses. 1265 1266 Usage: lm [libname] 1267 """ 1268 bases = self.trace.getMeta("LibraryBases") 1269 paths = self.trace.getMeta("LibraryPaths") 1270 if len(args): 1271 base = bases.get(args) 1272 path = paths.get(base, "unknown") 1273 if base == None: 1274 self.vprint("Library %s is not found!" % args) 1275 else: 1276 self.vprint("0x%.8x - %s %s" % (base, args, path)) 1277 else: 1278 self.vprint("Loaded Libraries:") 1279 names = self.trace.getNormalizedLibNames() 1280 names.sort() 1281 names = e_cli.columnstr(names) 1282 for libname in names: 1283 base = bases.get(libname.strip(), -1) 1284 path = paths.get(base, "unknown") 1285 self.vprint("0x%.8x - %.30s %s" % (base, libname, path))
1286
1287 - def do_guid(self, line):
1288 """ 1289 Parse and display a Global Unique Identifier (GUID) from memory 1290 (eventually, use GUID db to lookup the name/meaning of the GUID). 1291 1292 Usage: guid <addr_exp> 1293 """ 1294 self.trace.requireNotRunning() 1295 if not line: 1296 return self.do_help("guid") 1297 1298 addr = self.parseExpression(line) 1299 guid = vs_prims.GUID() 1300 bytes = self.trace.readMemory(addr, len(guid)) 1301 guid.vsSetValue(bytes) 1302 self.vprint("GUID 0x%.8x %s" % (addr, repr(guid)))
1303
1304 - def do_bpfile(self, line):
1305 """ 1306 Set the python code for a breakpoint from the contents 1307 of a file. 1308 1309 Usage: bpfile <bpid> <filename> 1310 """ 1311 argv = e_cli.splitargs(line) 1312 if len(argv) != 2: 1313 return self.do_help("bpfile") 1314 1315 bpid = int(argv[0]) 1316 pycode = file(argv[1], "rU").read() 1317 1318 self.trace.setBreakpointCode(bpid, pycode)
1319
1320 - def do_bpedit(self, line):
1321 """ 1322 Manipulcate the python code that will be run for a given 1323 breakpoint by ID. (Also the way to view the code). 1324 1325 Usage: bpedit <id> ["optionally new code"] 1326 1327 NOTE: Your code must be surrounded by "s and may not 1328 contain any "s 1329 """ 1330 argv = e_cli.splitargs(line) 1331 if len(argv) == 0: 1332 return self.do_help("bpedit") 1333 bpid = int(argv[0]) 1334 1335 if len(argv) == 2: 1336 self.trace.setBreakpointCode(bpid, argv[1]) 1337 1338 pystr = self.trace.getBreakpointCode(bpid) 1339 self.vprint("[%d] Breakpoint code: %s" % (bpid,pystr))
1340
1341 - def do_bp(self, line):
1342 """ 1343 Show, add, and enable/disable breakpoints 1344 USAGE: bp [-d <addr>] [-a <addr>] [-o <addr>] [[-c pycode] <address> [vdb cmds]] 1345 -C - Clear All Breakpoints 1346 -c "py code" - Set the breakpoint code to the given python string 1347 -d <id> - Disable Breakpoint 1348 -e <id> - Enable Breakpoint 1349 -r <id> - Remove Breakpoint 1350 -o <addr> - Create a OneTimeBreak 1351 -L <libname> - Add bp's to all functions in <libname> 1352 -F <filename> - Load bpcode from file 1353 -W perms:size - Set a hardware Watchpoint with perms/size (ie -W rw:4) 1354 -f - Make added breakpoints from this command into "fastbreaks" 1355 -S <libname>:<regex> - Add bp's to all matching funcs in <libname> 1356 1357 <address>... - Create Breakpoint 1358 1359 [vdb cmds].. - (optional) vdb cli comand to run on BP hit (seperate 1360 multiple commands with ;; ) 1361 1362 NOTE: -c adds python code to the breakpoint. The python code will 1363 be run with the following objects mapped into it's namespace 1364 automagically: 1365 vtrace - the vtrace package 1366 trace - the tracer 1367 bp - the breakpoint object 1368 """ 1369 self.trace.requireNotRunning() 1370 1371 argv = e_cli.splitargs(line) 1372 try: 1373 opts,args = getopt(argv, "fF:e:d:o:r:L:Cc:S:W:") 1374 except Exception, e: 1375 return self.do_help('bp') 1376 1377 pycode = None 1378 wpargs = None 1379 fastbreak = False 1380 libsearch = None 1381 1382 for opt,optarg in opts: 1383 if opt == "-e": 1384 self.trace.setBreakpointEnabled(eval(optarg), True) 1385 1386 elif opt == "-c": 1387 pycode = optarg 1388 test = compile(pycode, "test","exec") 1389 1390 elif opt == "-F": 1391 pycode = file(optarg, "rU").read() 1392 1393 elif opt == '-f': 1394 fastbreak = True 1395 1396 elif opt == "-r": 1397 self.bpcmds.pop(eval(optarg), None) 1398 self.trace.removeBreakpoint(eval(optarg)) 1399 1400 elif opt == "-C": 1401 for bp in self.trace.getBreakpoints(): 1402 self.bpcmds.pop(bp.id, None) 1403 self.trace.removeBreakpoint(bp.id) 1404 1405 elif opt == "-d": 1406 self.trace.setBreakpointEnabled(eval(optarg), False) 1407 1408 elif opt == "-o": 1409 self.trace.addBreakpoint(vtrace.OneTimeBreak(None, expression=optarg)) 1410 1411 elif opt == "-L": 1412 for sym in self.trace.getSymsForFile(optarg): 1413 if not isinstance(sym, e_resolv.FunctionSymbol): 1414 continue 1415 try: 1416 bp = vtrace.Breakpoint(None, expression=str(sym)) 1417 bp.setBreakpointCode(pycode) 1418 self.trace.addBreakpoint(bp) 1419 self.vprint("Added: %s" % str(sym)) 1420 except Exception, msg: 1421 self.vprint("WARNING: %s" % str(msg)) 1422 1423 elif opt == "-W": 1424 wpargs = optarg.split(":") 1425 1426 elif opt == '-S': 1427 libname, regex = optarg.split(':') 1428 1429 try: 1430 for sym in self.trace.searchSymbols(regex, libname=libname): 1431 1432 symstr = str(sym) 1433 symval = long(sym) 1434 if self.trace.getBreakpointByAddr(symval) != None: 1435 self.vprint('Duplicate (0x%.8x) %s' % (symval, symstr)) 1436 continue 1437 bp = vtrace.Breakpoint(None, expression=symstr) 1438 self.trace.addBreakpoint(bp) 1439 self.vprint('Added: %s' % symstr) 1440 1441 except re.error, e: 1442 self.vprint('Invalid Regular Expression: %s' % regex) 1443 return 1444 1445 cmdstr = None 1446 if len(args) > 1: 1447 cmdstr = ' '.join(args[1:]) 1448 1449 if len(args) >= 1: 1450 arg = args[0] 1451 1452 if wpargs != None: 1453 size = int(wpargs[1]) 1454 bp = vtrace.Watchpoint(None, expression=arg, size=size, perms=wpargs[0]) 1455 else: 1456 bp = vtrace.Breakpoint(None, expression=arg) 1457 1458 bp.setBreakpointCode(pycode) 1459 bp.fastbreak = fastbreak 1460 bpid = self.trace.addBreakpoint(bp) 1461 if cmdstr: 1462 self.bpcmds[bpid] = cmdstr.replace(';;', '&&') 1463 1464 self.vprint(" [ Breakpoints ]") 1465 for bp in self.trace.getBreakpoints(): 1466 cmdstr = self.bpcmds.get(bp.id, '') 1467 self.vprint("%s enabled: %s fast: %s %s" % (bp, bp.isEnabled(), bp.fastbreak, cmdstr))
1468
1469 - def do_fds(self, args):
1470 """ 1471 Show all the open Handles/FileDescriptors for the target process. 1472 The "typecode" shown in []'s is the vtrace typecode for that kind of 1473 fd/handle. 1474 1475 Usage: fds 1476 """ 1477 self.trace.requireAttached() 1478 for id,fdtype,fname in self.trace.getFds(): 1479 self.vprint("0x%.8x [%d] %s" % (id,fdtype,fname))
1480
1481 - def do_ps(self, args):
1482 """ 1483 Show the current process list. 1484 1485 Usage: ps 1486 """ 1487 self.vprint("[Pid]\t[ Name ]") 1488 for ps in self.trace.ps(): 1489 self.vprint("%s\t%s" % (ps[0],ps[1]))
1490
1491 - def do_break(self, args):
1492 """ 1493 Send the break signal to the target tracer to stop 1494 it's execution. 1495 1496 Usage: break 1497 """ 1498 if self.trace.getMeta('PendingBreak'): 1499 self.vprint('Break already sent...') 1500 return 1501 self.trace.setMeta('PendingBreak', True) 1502 self.trace.setMode("RunForever", False) 1503 self.trace.sendBreak()
1504
1505 - def do_meta(self, line):
1506 """ 1507 Show the metadata for the current trace. 1508 1509 Usage: meta 1510 """ 1511 argv = e_cli.splitargs(line) 1512 if argv: 1513 for name in argv: 1514 mval = self.trace.getMeta(name) 1515 self.vprint('%s: %r' % (name, mval)) 1516 else: 1517 meta = self.trace.metadata 1518 x = pprint.pformat(meta) 1519 self.vprint(x)
1520
1521 - def do_memdiff(self, line):
1522 """ 1523 Save and compare snapshots of memory to enumerate changes. 1524 1525 Usage: memdiff [options] 1526 -C Clear all current memory diff snapshots. 1527 -A <va:size> Add the given virtual address to the list. 1528 -M <va> Add the entire memory map which contains VA to the list. 1529 -D Compare currently tracked memory with the target process 1530 and show any differences. 1531 """ 1532 argv = e_cli.splitargs(line) 1533 opts,args = getopt(argv, "A:CDM:") 1534 1535 if len(opts) == 0: 1536 return self.do_help('memdiff') 1537 1538 self.trace.requireNotRunning() 1539 1540 for opt,optarg in opts: 1541 1542 if opt == "-A": 1543 if optarg.find(':') == -1: 1544 return self.do_help('memdiff') 1545 1546 vastr,sizestr = optarg.split(':') 1547 va = self.parseExpression(vastr) 1548 size = self.parseExpression(sizestr) 1549 bytes = self.trace.readMemory(va,size) 1550 self.difftracks[va] = bytes 1551 1552 elif opt == '-C': 1553 self.difftracks = {} 1554 1555 elif opt == '-D': 1556 difs = self._getDiffs() 1557 if len(difs) == 0: 1558 self.vprint('No Differences!') 1559 else: 1560 for va,thenbytes,nowbytes in difs: 1561 self.vprint('0x%.8x: %s %s' % 1562 (va, 1563 thenbytes.encode('hex'), 1564 nowbytes.encode('hex'))) 1565 1566 elif opt == '-M': 1567 va = self.parseExpression(optarg) 1568 map = self.trace.getMemoryMap(va) 1569 if map == None: 1570 self.vprint('No Memory Map At: 0x%.8x' % va) 1571 return 1572 mva,msize,mperm,mfile = map 1573 bytes = self.trace.readMemory(mva, msize) 1574 self.difftracks[mva] = bytes
1575 1576
1577 - def _getDiffs(self):
1578 1579 ret = [] 1580 for va, bytes in self.difftracks.items(): 1581 nowbytes = self.trace.readMemory(va, len(bytes)) 1582 1583 i = 0 1584 while i < len(bytes): 1585 thendiff = "" 1586 nowdiff = "" 1587 iva = va+i 1588 while (i < len(bytes) and 1589 bytes[i] != nowbytes[i]): 1590 thendiff += bytes[i] 1591 nowdiff += nowbytes[i] 1592 i += 1 1593 1594 if thendiff: 1595 ret.append((iva, thendiff, nowdiff)) 1596 continue 1597 1598 i += 1 1599 1600 return ret
1601
1602 - def do_dope(self, line):
1603 ''' 1604 Cli interface to the "stack doping" api inside recon. *BETA* 1605 1606 (Basically, set all un-initialized stack memory to V's to tease 1607 out uninitialized stack bugs) 1608 1609 Usage: dope [ options ] 1610 -E Enable automagic thread stack doping on all continue events 1611 -D Disable automagic thread stack doping on all continue events 1612 -A Dope all current thread stacks 1613 ''' 1614 import vdb.recon.dopestack as vr_dopestack 1615 1616 argv = e_cli.splitargs(line) 1617 1618 if len(argv) == 0: 1619 return self.do_help('dope') 1620 1621 opts,args = getopt(argv, 'ADE') 1622 1623 if len(opts) == 0: 1624 return self.do_help('dope') 1625 1626 for opt, optarg in opts: 1627 1628 if opt == '-A': 1629 self.vprint('Doping all thread stacks...') 1630 vr_dopestack.dopeAllThreadStacks(self.trace) 1631 self.vprint('...complete!') 1632 1633 elif opt == '-D': 1634 self.vprint('Disabling thread doping...') 1635 vr_dopestack.disableEventDoping(self.trace) 1636 self.vprint('...complete!') 1637 1638 elif opt == '-E': 1639 self.vprint('Enabling thread doping on CONTINUE events...') 1640 vr_dopestack.enableEventDoping(self.trace) 1641 self.vprint('...complete!')
1642 1643
1644 - def do_recon(self, line):
1645 ''' 1646 Cli front end to the vdb recon subsystem which allows runtime 1647 analysis of known API calls. 1648 1649 Usage: recon [options] 1650 -A <sym_expr>:<recon_fmt> - Add a recon breakpoint with the given format 1651 -C - Clear the current list of recon breakpoint hits. 1652 -H - Print the current list of recon breakpoint hits. 1653 -Q - Toggle "quiet" mode which prints nothing on bp hits. 1654 -S <sym_expr>:<argidx> - Add a sniper break for arg index 1655 1656 NOTE: A "recon format" is a special format sequence which tells the 1657 recon subsystem how to present the argument data for a given 1658 breakpoint hit. 1659 1660 Recon Format: 1661 C - A character 1662 I - A decimal integer 1663 P - A pointer (display symbol if possible) 1664 S - An ascii string (up to 260 chars) 1665 U - A unicode string (up to 260 chars) 1666 X - A hex number 1667 1668 ''' 1669 import vdb.recon as v_recon 1670 import vdb.recon.sniper as v_sniper 1671 argv = e_cli.splitargs(line) 1672 1673 if len(argv) == 0: 1674 return self.do_help('recon') 1675 1676 if self.trace.getMeta('Architecture') != 'i386': 1677 self.vprint('FIXME: recon only works on i386 right now...') 1678 return 1679 1680 opts,args = getopt(argv, 'A:CHQS:') 1681 for opt, optarg in opts: 1682 if opt == '-A': 1683 symname, reconfmt = optarg.split(':', 1) 1684 v_recon.addReconBreak(self.trace, symname, reconfmt) 1685 1686 elif opt == '-C': 1687 v_recon.clearReconHits(self.trace) 1688 1689 elif opt == '-H': 1690 self.vprint('Recon Hits:') 1691 hits = v_recon.getReconHits(self.trace) 1692 for hit in hits: 1693 thrid, savedeip, symname, args, argrep = hit 1694 argstr = '(%s)' % ', '.join(argrep) 1695 self.vprint('[%6d] 0x%.8x %s%s' % (thrid, savedeip, symname, argstr)) 1696 self.vprint('%d total hits' % len(hits)) 1697 1698 elif opt == '-Q': 1699 newval = not self.trace.getMeta('recon_quiet', False) 1700 self.trace.setMeta('recon_quiet', newval) 1701 self.vprint('Recon Quiet: %s' % newval) 1702 1703 elif opt == '-S': 1704 symname, idxstr = optarg.split(':') 1705 argidx = self.trace.parseExpression(idxstr) 1706 v_sniper.snipeDynArg(self.trace, symname, argidx)
1707
1708 - def do_stalker(self, line):
1709 ''' 1710 Cli front end to the VDB code coverage subsystem. FIXME MORE DOCS! 1711 1712 Usage: stalker [options] 1713 -C - Cleanup stalker breaks and hit info 1714 -c - Clear the current hits (so you can make more ;) 1715 -E <addr_expr> - Add the specified entry point for tracking 1716 -H - Show the current hits 1717 -L <lib>:<regex> - Add stalker breaks to all matching library symbols 1718 -R - Reset all breakpoints to enabled and clear hit info 1719 ''' 1720 1721 argv = e_cli.splitargs(line) 1722 1723 if len(argv) == 0: 1724 return self.do_help('stalker') 1725 1726 try: 1727 opts,args = getopt(argv, 'cCE:HIL:R') 1728 except Exception ,e: 1729 return self.do_help('stalker') 1730 1731 trace = self.trace 1732 for opt, optarg in opts: 1733 if opt == '-c': 1734 v_stalker.clearStalkerHits(trace) 1735 self.vprint('Clearing Stalker Hits...') 1736 1737 elif opt == '-C': 1738 v_stalker.clearStalkerBreaks(trace) 1739 v_stalker.clearStalkerHits(trace) 1740 self.vprint('Cleaning up stalker breaks and hits') 1741 1742 1743 elif opt == '-E': 1744 addr = trace.parseExpression(optarg) 1745 v_stalker.addStalkerEntry(trace, addr) 1746 self.vprint('Added 0x%.8x' % addr) 1747 1748 elif opt == '-H': 1749 self.vprint('Current Stalker Hits:') 1750 for hitva in v_stalker.getStalkerHits(trace): 1751 self.vprint('0x%.8x' % hitva) 1752 1753 elif opt == '-L': 1754 libname, regex = optarg.split(':', 1) 1755 for sym in trace.searchSymbols(regex, libname=libname): 1756 v_stalker.addStalkerEntry(trace, long(sym)) 1757 self.vprint('Stalking %s' % str(sym)) 1758 1759 elif opt == '-R': 1760 self.vprint('Resetting all breaks and hit info') 1761 v_stalker.clearStalkerHits(trace) 1762 v_stalker.resetStalkerBreaks(trace)
1763
1764 - def do_status(self, line):
1765 ''' 1766 Print out the status of the debugger / trace... 1767 ''' 1768 t = self.getTrace() 1769 if not t.isAttached(): 1770 self.vprint('Trace Not Attached...') 1771 1772 running = t.isRunning() 1773 runmsg = 'stopped' 1774 if running: 1775 runmsg = 'running' 1776 pid = t.getPid() 1777 self.vprint('Attached to pid: %d (%s)' % (pid, runmsg))
1778
1779 - def FIXME_do_remote(self, line):
1780 """ 1781 Act as a remote debugging client to the server running on 1782 the specified host/ip. 1783 1784 Usage: remote <host> 1785 """ 1786 vtrace.remote = line
1787 # FIXME how do we re-init the debugger? 1788