1 """
2 Vtrace Debugger Framework
3
4 Vtrace is a *mostly* native python debugging framework which
5 can be used to quickly write programatic debuggers and research
6 tools.
7
8 I'm not known for writting great docs... but the code should
9 be pretty straight forward...
10
11 This has been in use for many years privately, but is nowhere
12 *near* free of bugs... idiosyncracies abound.
13
14 ==== Werd =====================================================
15
16 Blah blah blah... many more docs to come.
17
18 Brought to you by kenshoto. e-mail invisigoth.
19
20 Greetz:
21 h1kari - eeeeeooorrrmmm CHKCHKCHKCHKCHKCHKCHK
22 Ghetto - wizoo... to the tizoot.
23 atlas - *whew* finally... no more teasing...
24 beatle/dnm - come out and play yo!
25 The Kenshoto Gophers.
26 Blackhats Everywhere.
27
28 """
29
30 import os
31 import re
32 import sys
33 import code
34 import copy
35 import time
36 import types
37 import struct
38 import getopt
39 import signal
40 import inspect
41 import platform
42 import traceback
43
44 import cPickle as pickle
45
46 import envi
47 import envi.bits as e_bits
48 import envi.memory as e_mem
49 import envi.registers as e_reg
50 import envi.expression as e_expr
51 import envi.resolver as e_resolv
52
53 import cobra
54 import vstruct
55
56 remote = None
57 cobra_daemon = None
58 port = 0x5656
59 verbose = False
60
61
62
63
64 NOTIFY_ALL = 0
65 NOTIFY_SIGNAL = 1
66 NOTIFY_BREAK = 2
67 NOTIFY_STEP = 3
68 NOTIFY_SYSCALL = 4
69 NOTIFY_CONTINUE = 5
70 NOTIFY_EXIT = 6
71 NOTIFY_ATTACH = 7
72 NOTIFY_DETACH = 8
73
74
75 NOTIFY_LOAD_LIBRARY = 9
76 NOTIFY_UNLOAD_LIBRARY = 10
77 NOTIFY_CREATE_THREAD = 11
78 NOTIFY_EXIT_THREAD = 12
79 NOTIFY_DEBUG_PRINT = 13
80 NOTIFY_MAX = 20
81
82
83 FD_UNKNOWN = 0
84 FD_FILE = 1
85 FD_SOCKET = 2
86 FD_PIPE = 3
87 FD_LOCK = 4
88 FD_EVENT = 5
89 FD_THREAD = 6
90 FD_REGKEY = 7
91
92
93 SYM_MISC = -1
94 SYM_GLOBAL = 0
95 SYM_LOCAL = 1
96 SYM_FUNCTION = 2
97 SYM_SECTION = 3
98 SYM_META = 4
99
100
101 VSYM_NAME = 0
102 VSYM_ADDR = 1
103 VSYM_SIZE = 2
104 VSYM_TYPE = 3
105 VSYM_FILE = 4
106
107 from vtrace.rmi import *
108 from vtrace.notifiers import *
109 from vtrace.breakpoints import *
110 from vtrace.watchpoints import *
111 import vtrace.util as v_util
112
122
124 """
125 An exception which is raised on bad-touch to memory
126 """
128 self.va = va
129 self.perm = perm
130 Exception.__init__(self, "AccessViolation at 0x%.8x (%d)" % (va, perm))
131
132 -class Trace(e_mem.IMemory, e_reg.RegisterContext, e_resolv.SymbolResolver, object):
133 """
134 The main tracer object. A trace instance is dynamically generated using
135 this and *many* potential mixin classes. However, API users should *not*
136 worry about the methods that come from the mixins... Everything that is
137 *meant* to be used from the API is contained and documented here.
138 """
140
141
142 self.requires_thread = {}
143 self.proxymeth = None
144 self._released = False
145
146
147
148 self.modes = {}
149 self.modedocs = {}
150 self.notifiers = {}
151
152
153
154 self.metadata = {}
155
156 self.initMode("RunForever", False, "Run until RunForever = False")
157 self.initMode("NonBlocking", False, "A call to wait() fires a thread to wait *for* you")
158 self.initMode("ThreadProxy", True, "Proxy necissary requests through a single thread (can deadlock...)")
159 self.initMode("SingleStep", False, "All calls to run() actually just step. This allows RunForever + SingleStep to step forever ;)")
160 self.initMode("FastStep", False, "All stepi() will NOT generate a step event")
161
162 self.regcache = None
163 self.regcachedirty = False
164 self.sus_threads = {}
165
166
167 self.proxy = None
168
169
170
171 if archname == None:
172 archname = envi.getCurrentArch()
173 self.setMeta('Architecture', archname)
174 self.arch = envi.getArchModule(name=archname)
175
176 e_resolv.SymbolResolver.__init__(self, width=self.arch.getPointerSize())
177 e_mem.IMemory.__init__(self, archmod=self.arch)
178 e_reg.RegisterContext.__init__(self)
179
180
181 self.auto_continue = [NOTIFY_LOAD_LIBRARY, NOTIFY_CREATE_THREAD, NOTIFY_UNLOAD_LIBRARY, NOTIFY_EXIT_THREAD, NOTIFY_DEBUG_PRINT]
182
184 """
185 Start a new process and debug it
186 """
187 if self.isAttached():
188 raise Exception("ERROR - Tracer must first be detached before you can execute()")
189
190 pid = self.platformExec(cmdline)
191 self._justAttached(pid)
192 self.setMeta('ExecCommand', cmdline)
193 self.wait()
194
196 '''
197 Retrieve the current signal/exception posted to the process.
198 If there are no pending signals/exceptions the API will return
199 None. For POSIX systems, this will be a traditional POSIX signal.
200 For Windows systems it will be a current exception code (if any).
201
202 Example: sig = trace.getCurrentSignal()
203 '''
204 return self.platformGetSignal()
205
207 '''
208 Set the currently pending signal for delivery to the target process on
209 continue. This is intended for use by programs wishing the mask or change
210 the delivery of exceptions on a NOTIFY_SIGNAL event.
211
212 Example: trace.setCurrentSignal(None)
213 '''
214 return self.platformSetSignal(sig)
215
217 """
218 By adding an IgnoreSignal you tell the tracer object to
219 supress the notification of a particular type of signal.
220 In POSIX, these are regular signals, in Win32, these
221 are exception codes. This is mostly useful in RunForever
222 mode because you still need the process to begin running again.
223 (these may be viewed/modified by the metadata key "IgnoredSignals")
224 FIXME: make address do something.
225 """
226 self.getMeta("IgnoredSignals").append(code)
227
229 """
230 See addIgnoreSignal for a description of signal ignoring.
231 This removes an ignored signal and re-enables it's delivery.
232 """
233 self.getMeta("IgnoredSignals").remove(code)
234
248
250 """
251 Single step the target process ONE instruction (and do
252 NOT activate breakpoints for the one step). Also, we
253 don't deliver pending signals for the single step...
254 Use the mode FastStep to allow/supress notifier callbacks on step
255 """
256 self.requireNotRunning()
257
258
259
260 self.curbp = None
261
262 self._syncRegs()
263 self.platformStepi()
264 event = self.platformWait()
265 self.platformProcessEvent(event)
266
267 - def run(self, until=None):
268 """
269 Allow the traced target to continue execution. (Depending on the mode
270 "Blocking" this will either block until an event, or return immediately)
271 Additionally, the argument until may be used to cause execution to continue
272 until the specified address is reached (internally uses and removes a breakpoint).
273 """
274 self.requireNotRunning()
275 if self.getMode("SingleStep", False):
276 self.steploop()
277
278 else:
279 if until != None:
280 self.setMode("RunForever", True)
281 self.addBreakpoint(StopAndRemoveBreak(until))
282
283 self._doRun()
284 self.wait()
285
287 """
288 The runAgain() method may be used from inside a notifier
289 (Notifier, Breakpoint, Watchpoint, etc...) to inform the trace
290 that once event processing is complete, it should continue
291 running the trace.
292 """
293 self.runagain = val
294
312
324
326 '''
327 Release resources for this tracer. This API should be called
328 once you are done with the trace.
329 '''
330 if not self._released:
331 self._released = True
332 if self.attached:
333 self.detach()
334 self._cleanupResources()
335 self.platformRelease()
336
338 """
339 Return the pid for this Trace
340 """
341 return self.pid
342
344 """
345 Symbols are stored internally based off of
346 "normalized" library names. This method returns
347 the list of normalized names for the loaded libraries.
348
349 (probably only useful for writting symbol browsers...)
350 """
351 return self.getMeta("LibraryBases").keys()
352
363
365 """
366 Return an envi Symbol object for an address.
367 Use exact=False to get the nearest previous match.
368 """
369
370
371
372 r = e_resolv.SymbolResolver.getSymByAddr(self, addr, exact=exact)
373 if r != None:
374 return r
375
376
377 map = self.getMemoryMap(addr)
378 if map == None:
379 return None
380
381 va,size,perms,fname = map
382
383 if not self._loadBinary(fname):
384 return None
385
386
387 return e_resolv.SymbolResolver.getSymByAddr(self, addr, exact=exact)
388
395
397 '''
398 Search for symbols which match the given regular expression. Specify libname
399 as the "normalized" library name to only search the specified lib.
400
401 Example: for sym in trace.searchSymbols('.*CreateFile.*', 'kernel32'):
402 '''
403 reobj = re.compile(regex)
404 if libname != None:
405 libs = [libname, ]
406 else:
407 libs = self.getNormalizedLibNames()
408
409 ret = []
410 for lname in libs:
411 for sym in self.getSymsForFile(lname):
412 symstr = str(sym)
413 if reobj.match(symstr):
414 ret.append(sym)
415 return ret
416
417
418 - def getRegisterContext(self, threadid=None):
419 """
420 Retrieve the envi.registers.RegisterContext object for the
421 specified thread. Use this API to iterate over threads
422 register values without setting the global tracer thread context.
423 """
424 if threadid == None:
425 threadid = self.getMeta("ThreadId")
426 return self._cacheRegs(threadid)
427
428
429
430
431
432
433
434
435
439
443
444
445
447 """
448 Allocate a chunk of memory inside the target process' address
449 space. Memory wil be mapped rwx unless otherwise specified with
450 perms=envi.memory.MM_FOO values. Optionally you may *suggest* an address
451 to the allocator, but there is no guarentee. Returns the mapped
452 memory address.
453 """
454 self.requireNotRunning()
455 self.mapcache = None
456 return self.platformAllocateMemory(size, perms=perms, suggestaddr=suggestaddr)
457
459 """
460 Change the page protections on the specified region of memory.
461 See envi.memory for perms values.
462 """
463 self.requireNotRunning()
464 self.mapcache = None
465 return self.platformProtectMemory(va, size, perms)
466
468 """
469 Read memory from address. Areas that are NOT valid memory will be read
470 back as \x00s (this probably goes in a mixin soon)
471 """
472 self.requireNotRunning()
473 return self.platformReadMemory(long(address), long(size))
474
481
483 """
484 Search all of process memory for a sequence of bytes.
485 """
486 ret = e_mem.IMemory.searchMemory(self, needle, regex=regex)
487 self.setMeta('search', ret)
488 self.setVariable('search', ret)
489 return ret
490
492 """
493 Search a memory range for the specified sequence of bytes
494 """
495 ret = e_mem.IMemory.searchMemoryRange(self, needle, address, size, regex=regex)
496 self.setMeta('search', ret)
497 self.setVariable('search', ret)
498 return ret
499
516
531
539
540 - def getMode(self, name, default=False):
541 """
542 Get the value for a mode setting allowing
543 for a clean default...
544 """
545 return self.modes.get(name, default)
546
548 """
549 Set a mode setting... This is ONLY valid
550 if that mode has been iniitialized with
551 initMode(name, value). Otherwise, it's an
552 unsupported mode for this platform ;) cute huh?
553 This way, platform sections can cleanly setmodes
554 and such.
555 """
556 if not self.modes.has_key(name):
557 raise Exception("Mode %s not supported on this platform" % name)
558 self.modes[name] = bool(value)
559
561 """
562 Inject a shared object into the target of the trace. So, on windows
563 this is easy with InjectDll and on *nix... it's.. fugly...
564
565 NOTE: This method will likely cause the trace to run. Do not call from
566 within a notifier!
567 """
568 self.requireNotRunning()
569 self.platformInjectSo(filename)
570
572 """
573 Return a list of proccesses which are currently running on the
574 system.
575 (pid, name)
576 """
577 return self.platformPs()
578
580 '''
581 Add a breakpoint by resolving an expression. This will create
582 the Breakpoint object for you and add it to the trace. It
583 returns the newly created breakpoint id.
584
585 Optionally, set fastbreak=True to have the breakpoint behave in
586 "fast break" mode which automatically continues execution and does
587 not fire notifiers for the breakpoint.
588
589 Example: trace.addBreakByExpr('kernel32.CreateFileA + ecx')
590 '''
591 bp = Breakpoint(None, expression=symname)
592 bp.fastbreak = fastbreak
593 return self.addBreakpoint(bp)
594
596 '''
597 Add a breakpoint by address. This will create the Breakpoint
598 object for you and add it to the trace. It returns the newly
599 created breakpoint id.
600
601 Optionally, set fastbreak=True to have the breakpoint behave in
602 "fast break" mode which automatically continues execution and does
603 not fire notifiers for the breakpoint.
604
605 Example: trace.addBreakByAddr(0x7c770308)
606 '''
607 bp = Breakpoint(va)
608 bp.fastbreak = fastbreak
609 return self.addBreakpoint(bp)
610
612 """
613 Add a breakpoint/watchpoint to the trace. The "breakpoint" argument
614 is a vtrace Breakpoint/Watchpoint object or something that extends it.
615
616 To add a basic breakpoint use trace.addBreakpoint(vtrace.Breakpoint(address))
617 NOTE: expression breakpoints do *not* get evaluated in fastbreak mode
618
619 This will return the internal ID given to the new breakpoint
620 """
621 breakpoint.inittrace(self)
622
623 breakpoint.id = self.nextBpId()
624 addr = breakpoint.resolveAddress(self)
625
626
627 if addr == None:
628 self.bpbyid[breakpoint.id] = breakpoint
629 self.deferred.append(breakpoint)
630 return breakpoint.id
631
632 if self.breakpoints.has_key(addr):
633 raise Exception("ERROR: Duplicate break for address 0x%.8x" % addr)
634
635 self.bpbyid[breakpoint.id] = breakpoint
636 self.breakpoints[addr] = breakpoint
637
638
639 if breakpoint.fastbreak:
640 self._activateBreak(breakpoint)
641
642 return breakpoint.id
643
645 """
646 Remove the breakpoint with the specified ID
647 """
648 self.requireAttached()
649 bp = self.bpbyid.pop(id, None)
650 if bp != None:
651 bp.deactivate(self)
652 if bp in self.deferred:
653 self.deferred.remove(bp)
654 else:
655 self.breakpoints.pop(bp.address, None)
656
657
658 if self.curbp == bp:
659 self.curbp = None
660
661
662 Breakpoint.bpcodeobj.pop(id, None)
663
665 """
666 Return the current breakpoint otherwise None
667 """
668 return self.curbp
669
671 """
672 Return a reference to the breakpoint with the requested ID.
673
674 NOTE: NEVER set locals or use things like setBreakpointCode()
675 method on return'd breakpoint objects as they may be remote
676 and would then be *coppies* of the bp objects. (use the trace's
677 setBreakpointCode() instead).
678 """
679 return self.bpbyid.get(id)
680
682 '''
683 Return the breakpoint object (or None) for a given virtual address.
684 '''
685 return self.breakpoints.get(va)
686
688 """
689 Return a list of the current breakpoints.
690 """
691 return self.bpbyid.values()
692
694 """
695 An accessor method for returning if a breakpoint is
696 currently enabled.
697 NOTE: code which wants to be remote-safe should use this
698 """
699 bp = self.getBreakpoint(bpid)
700 if bp == None:
701 raise Exception("Breakpoint %d Not Found" % bpid)
702 return bp.isEnabled()
703
705 """
706 An accessor method for setting a breakpoint enabled/disabled.
707
708 NOTE: code which wants to be remote-safe should use this
709 """
710 bp = self.getBreakpoint(bpid)
711 if bp == None:
712 raise Exception("Breakpoint %d Not Found" % bpid)
713 if not enabled:
714 bp.deactivate(self)
715 return bp.setEnabled(enabled)
716
718 """
719 Because breakpoints are potentially on the remote debugger
720 and code is not pickleable in python, special access methods
721 which takes strings of python code are necissary for the
722 vdb interface to quick script breakpoint code. Use this method
723 to set the python code for this breakpoint.
724 """
725 bp = self.getBreakpoint(bpid)
726 if bp == None:
727 raise Exception("Breakpoint %d Not Found" % bpid)
728 bp.setBreakpointCode(pystr)
729
731 """
732 Return the python string of user specified code that will run
733 when this breakpoint is hit.
734 """
735 bp = self.getBreakpoint(bpid)
736 if bp != None:
737 return bp.getBreakpointCode()
738 return None
739
740 - def call(self, address, args, convention=None):
741 """
742 Setup the "stack" and call the target address with the following
743 arguments. If the argument is a string or a buffer, copy that into
744 memory and hand in the argument.
745
746 The current state of ALL registers are returned as a dictionary at the
747 end of the call...
748
749 Additionally, a "convention" string may be specified that the underlying
750 platform may be able to interpret...
751 """
752 self.requireNotRunning()
753 return self.platformCall(address, args, convention)
754
756 """
757 Register a notifier who will be called for various
758 events. See NOTIFY_* constants for handler hooks.
759 """
760 nlist = self.notifiers.get(event,None)
761 if nlist:
762 nlist.append(notifier)
763 else:
764 nlist = []
765 nlist.append(notifier)
766 self.notifiers[event] = nlist
767
769 nlist = self.notifiers.get(event, [])
770 if notifier in nlist:
771 nlist.remove(notifier)
772
775
777 if self.exited:
778 raise Exception("ERROR - Request invalid for trace which exited")
779
781 """
782 Just a quick method to throw an error if the
783 tracer is already running...
784 """
785 self.requireAttached()
786 if self.isRunning():
787 raise Exception("ERROR - Request invalid for running trace")
788
790 """
791 A utility method for other methods to use in order
792 to require being attached
793 """
794 if not self.attached:
795 raise Exception("ERROR - Must be attached to a process")
796
798 """
799 Get a list of (fd,type,bestname) pairs. This is MOSTLY useful
800 for HUMON consumtion... or giving HUMONs consumption...
801 """
802 self.requireNotRunning()
803 if not self.fds:
804 self.fds = self.platformGetFds()
805 return self.fds
806
808 """
809 Return a list of the currently mapped memory for the target
810 process. This is acomplished by calling the platform's
811 platformGetMaps() mixin method. This will also cache the
812 results until CONTINUE. The format is (addr,len,perms,file).
813 """
814 self.requireNotRunning()
815 if not self.mapcache:
816 self.mapcache = self.platformGetMaps()
817 return self.mapcache
818
820 '''
821 If the most receent event is a memory access error, this API will
822 return a tuple of (<addr>,<perm>) on supported platforms. Otherwise,
823 a (None, None) will result.
824
825 Example:
826 import envi.memory as e_mem
827 vaddr,vperm = trace.getMemoryFault()
828 if vaddr != None:
829 print 'Memory Fault At: 0x%.8x (perm: %d)' % (vaddr, vperm)
830 '''
831 return self.platformGetMemFault()
832
834 """
835 Return boolean true/false for weather or not this trace is
836 currently attached to a process.
837 """
838 return self.attached
839
841 """
842 Return true or false if this trace's target process is "running".
843 """
844 return self.running
845
847 '''
848 Returns True if the trace is a CobraProxy object to a trace on another system
849 '''
850 return False
851
853 """
854 Put the tracer object in to AutoContinue mode
855 for the specified event. To make all events
856 continue running see RunForever mode in setMode().
857 """
858 if event not in self.auto_continue:
859 self.auto_continue.append(event)
860
862 """
863 Disable Auto Continue for the specified
864 event.
865 """
866 if event in self.auto_continue:
867 self.auto_continue.remove(event)
868
870 """
871 Retrieve the list of vtrace notification events
872 that will be auto-continued.
873 """
874 return list(self.auto_continue)
875
877 """
878 Parse a python expression with many useful helpers mapped
879 into the execution namespace.
880
881 Example: trace.parseExpression("ispoi(ecx+ntdll.RtlAllocateHeap)")
882 """
883 locs = VtraceExpressionLocals(self)
884 return long(e_expr.evaluate(expression, locs))
885
887 """
888 Send an asynchronous break signal to the target process.
889 This is only valid if the target is actually running...
890 """
891 self.requireAttached()
892 self.setMode("RunForever", False)
893 self.setMeta("ShouldBreak", True)
894 self.platformSendBreak()
895 time.sleep(0.01)
896
897 if self.getMode("NonBlocking", True):
898 while self.isRunning():
899 time.sleep(0.01)
900
902 """
903 Returns a list of (instruction pointer, stack frame) tuples.
904 If stack tracing results in an error, the error entry will
905 be (-1,-1). Otherwise most platforms end up with 0,0 as
906 the top stack frame
907 """
908
909 return self.archGetStackTrace()
910
912 """
913 Get a dictionary of <threadid>:<tinfo> pairs where
914 tinfo is platform dependant, but is tyically either
915 the top of the stack for that thread, or the TEB on
916 win32
917 """
918 if not self.threadcache:
919 self.threadcache = self.platformGetThreads()
920 return self.threadcache
921
923 '''
924 Return the thread id of the currently selected thread.
925 '''
926 return self.getMeta('ThreadId')
927
929 """
930 Set the "current thread" context to the given thread id.
931 (For example stack traces and register values will depend
932 on the current thread context). By default the thread
933 responsible for an "interesting event" is selected.
934 """
935 if threadid not in self.getThreads():
936 raise Exception("ERROR: Invalid threadid chosen: %d" % threadid)
937 self.requireNotRunning()
938 self.platformSelectThread(threadid)
939 self.setMeta("ThreadId", threadid)
940
942 """
943 Used to determine if a thread is suspended.
944 """
945 return self.sus_threads.get(threadid, False)
946
948 """
949 Suspend a thread by ID. This will mean that on continuing
950 the trace, the suspended thread will not be scheduled.
951 """
952 self.requireNotRunning()
953 if self.sus_threads.get(threadid):
954 raise Exception("The specified thread is already suspended")
955 if threadid not in self.getThreads().keys():
956 raise Exception("There is no thread %d!" % threadid)
957 self.platformSuspendThread(threadid)
958 self.sus_threads[threadid] = True
959
961 """
962 Resume a suspended thread.
963 """
964 self.requireNotRunning()
965 if not self.sus_threads.get(threadid):
966 raise Exception("The specified thread is not suspended")
967 self.platformResumeThread(threadid)
968 self.sus_threads.pop(threadid)
969
971 """
972 Create a new thread inside the target process. This thread
973 will begin execution on the next process run().
974 """
975 self.requireNotRunning()
976
977 pass
978
980 '''
981 Run the trace in a loop until the specified thread exits.
982 '''
983 self.setMode('RunForever', True)
984 self._join_thread = threadid
985
986 nb = self.getMode('NonBlocking')
987 self.setMode('NonBlocking', False)
988 self.run()
989 self.setMode('NonBlocking', nb)
990
992 '''
993 This method returns either the structure names, or
994 the structure namespaces that the target tracer is aware
995 of. If "namespace" is specified, it is structures within
996 that namespace, otherwise it is "known namespaces"
997
998 Example: namespaces = trace.getStructNames()
999 ntdll_structs = trace.getStructNames(namespace='ntdll')
1000 '''
1001 if namespace:
1002 return self.vsbuilder.getVStructNames(namespace=namespace)
1003 return self.vsbuilder.getVStructNamespaceNames()
1004
1006 """
1007 Retrieve a vstruct structure populated with memory from
1008 the specified address. Returns a standard vstruct object.
1009 """
1010
1011 libbase = sname.split('.')[0]
1012 self._loadBinaryNorm(libbase)
1013
1014 if self.vsbuilder.hasVStructNamespace(libbase):
1015 vs = self.vsbuilder.buildVStruct(sname)
1016
1017
1018 else:
1019 vs = vstruct.getStructure(sname)
1020 bytes = self.readMemory(address, len(vs))
1021 vs.vsParse(bytes)
1022 return vs
1023
1025 """
1026 Set a named variable in the trace which may be used in
1027 subsequent VtraceExpressions.
1028
1029 Example:
1030 trace.setVariable("whereiam", trace.getProgramCounter())
1031 """
1032 self.localvars[name] = value
1033
1035 """
1036 Get the value of a previously set variable name.
1037 (or None on not found)
1038 """
1039 return self.localvars.get(name)
1040
1042 """
1043 Get the dictionary of named variables.
1044 """
1045 return dict(self.localvars)
1046
1047 - def hex(self, value):
1048 """
1049 Much like the python hex routine, except this will automatically
1050 pad the value's string length out to pointer width.
1051 """
1052 w = self.arch.getPointerSize()
1053 return e_bits.hex(value, width)
1054
1056 '''
1057 Build a new/clean trace "like" this one. For platforms where a
1058 special trace was handed in, this allows initialization of a new one.
1059 For most implementations, this is very simple....
1060
1061 Example:
1062 if need_another_trace:
1063 newt = trace.buildNewTrace()
1064 '''
1065 return self.__class__()
1066
1068 """
1069 Encapsulate several traces, run them, and continue to
1070 handle their event notifications.
1071 """
1082
1093
1098
1100 """
1101 Detach from ALL the currently targetd processes
1102 """
1103 for trace in self.traces.values():
1104 try:
1105 if trace.isRunning():
1106 trace.sendBreak()
1107 trace.detach()
1108 except:
1109 pass
1110
1112 """
1113 Our run method is a little different than a traditional
1114 trace. It will *never* block.
1115 """
1116 if len(self.traces.keys()) == 0:
1117 raise Exception("ERROR - can't run() with no traces!")
1118
1119 for trace in self.traces.values():
1120
1121 if trace.exited:
1122 self.traces.pop(trace.pid)
1123 trace.detach()
1124 continue
1125
1126 if not trace.isRunning():
1127 trace.run()
1128
1135
1137 """
1138 Add a new tracer to this group the "proc" argument
1139 may be either an long() for a pid (which we will attach
1140 to) or an already attached (and broken) tracer object.
1141 """
1142
1143 if (type(proc) == types.IntType or
1144 type(proc) == types.LongType):
1145 trace = getTrace()
1146 self._initTrace(trace)
1147 self.traces[proc] = trace
1148 try:
1149 trace.attach(proc)
1150 except:
1151 self.delTrace(proc)
1152 raise
1153
1154 else:
1155 trace = proc
1156 self._initTrace(trace)
1157 self.traces[trace.getPid()] = trace
1158
1159 return trace
1160
1162 '''
1163 Similar to vtrace.getTrace(), but also init's
1164 the trace for being managed by a TraceGroup.
1165
1166 Example:
1167 tg = TraceGroup()
1168 t = tg.getTrace()
1169 t....
1170 '''
1171 t = getTrace()
1172 self.addTrace(t)
1173 return t
1174
1176 """
1177 - INTERNAL -
1178 Setup a tracer object to be ready for being in this
1179 trace group (setup modes and notifiers). Only addTrace()
1180 and execTrace() probably need to be aware of this.
1181 """
1182 self.manageTrace(trace)
1183
1185 """
1186 Remove a trace from the current TraceGroup
1187 """
1188 trace = self.traces.pop(pid, None)
1189 self.unManageTrace(trace)
1190
1192 """
1193 Return a list of the current traces
1194 """
1195 return self.traces.values()
1196
1198 """
1199 Return the the trace for process PID if we're
1200 already attached. Return None if not.
1201 """
1202 return self.traces.get(pid, None)
1203
1204 - def notify(self, event, trace):
1209
1211 """
1212 A class which serves as the namespace dictionary during the
1213 evaluation of an expression on a tracer.
1214 """
1229
1246
1248 '''
1249 A shortcut for trace.runAgain() which may be used in
1250 breakpoint code (or similar even processors) to begin
1251 execution again after event processing...
1252 '''
1253 self.trace.runAgain();
1254
1255 - def frame(self, index):
1256 """
1257 Return the address of the saved base pointer for
1258 the specified frame.
1259
1260 Usage: frame(<index>)
1261 """
1262 stack = self.trace.getStackTrace()
1263 return stack[index][1]
1264
1265 - def teb(self, threadnum=None):
1266 """
1267 The expression teb(threadid) will return whatever the
1268 platform stores as the int for threadid. In the case
1269 of windows, this is the TEB, others may be the thread
1270 stack base or whatever. If threadid is left out, it
1271 uses the threadid of the current thread context.
1272 """
1273 if threadnum == None:
1274
1275 threadnum = self.trace.getMeta("ThreadId")
1276
1277 teb = self.trace.getThreads().get(threadnum, None)
1278 if teb == None:
1279 raise Exception("ERROR - Unknown Thread Id %d" % threadnum)
1280
1281 return teb
1282
1283 - def bp(self, bpid):
1284 """
1285 The expression bp(0) returns the resolved address of the given
1286 breakpoint
1287 """
1288 bp = self.trace.getBreakpoint(bpid)
1289 if bp == None:
1290 raise Exception("Unknown Breakpoint ID: %d" % bpid)
1291 return bp.resolveAddress(self.trace)
1292
1301
1303 """
1304 Return a tracer object appropriate for this platform.
1305 This is the function you will use to get a tracer object
1306 with the appropriate ancestry for your host.
1307 ex. mytrace = vtrace.getTrace()
1308
1309
1310 NOTE: Use the release() method on the tracer once debugging
1311 is complete. This releases the tracer thread and allows
1312 garbage collection to function correctly.
1313
1314 Some specialized tracers may be constructed by specifying the "plat"
1315 name from one of the following list. Additionally, each "specialized"
1316 tracer may require additional kwargs (which are listed).
1317
1318 android - Debug android apps through adb (adb must be in your path)
1319 avd=<name> (None will let adb decide)
1320
1321 vmware32 - Debug a 32bit VMWare target.
1322 host=<host> - Where is the gdb server listening? (default 127.0.0.1)
1323 port=<port> - What port (default: 8832)
1324 os=<osname> - On of "Windows", "Linux" (that's all we support now...)
1325
1326 vmware64 - Debug a 64bit VMWare target.
1327 host=<host> - Where is the gdb server listening? (default 127.0.0.1)
1328 port=<port> - What port (default: 8864)
1329 os=<osname> - On of "Windows", "Linux" (that's all we support now...)
1330
1331 Examples:
1332 t = vtrace.getTrace() # A tracer for *this* os
1333
1334 t = vtrace.getTrace(plat='android') # The default ADB device
1335
1336 t = vtrace.getTrace(plat='vmware32', host='localhost', port=31337)
1337 """
1338
1339 if plat == 'android':
1340 import vtrace.platforms.android as v_android
1341 return v_android.getTrace(**kwargs)
1342
1343 if remote:
1344 return getRemoteTrace()
1345
1346
1347
1348 os_name = platform.system()
1349 arch = envi.getCurrentArch()
1350
1351 if os_name == "Linux":
1352 import vtrace.platforms.linux as v_linux
1353 if arch == "amd64":
1354 return v_linux.LinuxAmd64Trace()
1355
1356 elif arch == "i386":
1357 return v_linux.Linuxi386Trace()
1358
1359 else:
1360 raise Exception("Sorry, no linux support for %s" % arch)
1361
1362 elif os_name == "FreeBSD":
1363
1364 import vtrace.platforms.freebsd as v_freebsd
1365
1366 if arch == "i386":
1367 return v_freebsd.FreeBSDi386Trace()
1368
1369 elif arch == "amd64":
1370 return v_freebsd.FreeBSDAmd64Trace()
1371
1372 else:
1373 raise Exception("Sorry, no FreeBSD support for %s" % arch)
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387 elif os_name == "sunos5":
1388 raise Exception("Solaris needs porting!")
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398 elif os_name == "Darwin":
1399
1400
1401
1402
1403
1404
1405 if os.getuid() != 0:
1406 print 'For NOW you *must* be root. There are some crazy MACH perms...'
1407 raise Exception('You must be root for now (on OSX)....')
1408
1409 print 'Also... the darwin port is not even REMOTELY working yet. Solid progress though...'
1410
1411
1412
1413 import vtrace.platforms.darwin as v_darwin
1414 if arch == 'i386':
1415 return v_darwin.Darwini386Trace()
1416 elif arch == 'amd64':
1417 return v_darwin.DarwinAmd64Trace()
1418 else:
1419 raise Exception('Darwin not supported on %s (only i386...)' % arch)
1420
1421 elif os_name in ['Microsoft', 'Windows']:
1422
1423 import vtrace.platforms.win32 as v_win32
1424
1425 if arch == "i386":
1426 return v_win32.Windowsi386Trace()
1427
1428 elif arch == "amd64":
1429 return v_win32.WindowsAmd64Trace()
1430
1431 else:
1432 raise Exception("Windows with arch %s is not supported!" % arch)
1433
1434 else:
1435
1436 raise Exception("ERROR - OS %s not supported yet" % os_name)
1437
1438 -def interact(pid=0,server=None,trace=None):
1439
1440 """
1441 Just a cute and dirty way to get a tracer attached to a pid
1442 and get a python interpreter instance out of it.
1443 """
1444
1445 global remote
1446 remote = server
1447
1448 if trace == None:
1449 trace = getTrace()
1450 if pid:
1451 trace.attach(pid)
1452
1453 mylocals = {}
1454 mylocals["trace"] = trace
1455
1456 code.interact(local=mylocals)
1457