| Home | Trees | Indices | Help |
|
|---|
|
|
1 # Copyright (c) 2009-2010, Mario Vilas
2 # All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are met:
6 #
7 # * Redistributions of source code must retain the above copyright notice,
8 # this list of conditions and the following disclaimer.
9 # * Redistributions in binary form must reproduce the above copyright
10 # notice,this list of conditions and the following disclaimer in the
11 # documentation and/or other materials provided with the distribution.
12 # * Neither the name of the copyright holder nor the names of its
13 # contributors may be used to endorse or promote products derived from
14 # this software without specific prior written permission.
15 #
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 # POSSIBILITY OF SUCH DAMAGE.
27
28 """
29 Event handling module.
30
31 @see: U{http://apps.sourceforge.net/trac/winappdbg/wiki/Debugging}
32
33 @group Debugging:
34 EventHandler
35
36 @group Debug events:
37 EventFactory,
38 EventDispatcher,
39 Event,
40 NoEvent,
41 CreateProcessEvent,
42 CreateThreadEvent,
43 ExitProcessEvent,
44 ExitThreadEvent,
45 LoadDLLEvent,
46 UnloadDLLEvent,
47 OutputDebugStringEvent,
48 RIPEvent,
49 ExceptionEvent
50 """
51
52 __revision__ = "$Id: event.py 689 2010-06-20 13:56:12Z qvasimodo $"
53
54 __all__ = [
55 # Factory of Event objects and all of it's subclasses.
56 # Users should not need to instance Event objects directly.
57 'EventFactory',
58
59 # Event dispatcher used internally by the Debug class.
60 'EventDispatcher',
61
62 # Base class for user-defined event handlers.
63 'EventHandler',
64
65 # Dummy event object that can be used as a placeholder.
66 # It's never returned by the EventFactory.
67 'NoEvent',
68
69 # Base class for event objects.
70 'Event',
71
72 # Event objects.
73 'CreateProcessEvent',
74 'CreateThreadEvent',
75 'ExitProcessEvent',
76 'ExitThreadEvent',
77 'LoadDLLEvent',
78 'UnloadDLLEvent',
79 'OutputDebugStringEvent',
80 'RIPEvent',
81 'ExceptionEvent'
82 ]
83
84 import win32
85 from win32 import FileHandle, ProcessHandle, ThreadHandle
86 from breakpoint import ApiHook
87 from system import Module, Thread, Process, PathOperations
88 from textio import HexDump
89
90 import ctypes
91 ##import weakref
92
93 #==============================================================================
94
95 -class Event (object):
96 """
97 Event object.
98
99 @type eventMethod: str
100 @cvar eventMethod:
101 Method name to call when using L{EventHandler} subclasses.
102 Used internally.
103
104 @type eventName: str
105 @cvar eventName:
106 User-friendly name of the event.
107
108 @type eventDescription: str
109 @cvar eventDescription:
110 User-friendly description of the event.
111
112 @type debug: L{Debug}
113 @ivar debug:
114 Debug object that received the event.
115
116 @type raw: L{DEBUG_EVENT}
117 @ivar raw:
118 Raw DEBUG_EVENT structure as used by the Win32 API.
119
120 @type continueStatus: int
121 @ivar continueStatus:
122 Continue status to pass to L{win32.ContinueDebugEvent}.
123 """
124
125 eventMethod = 'unknown_event'
126 eventName = 'Unknown event'
127 eventDescription = 'A debug event of an unknown type has occured.'
128
130 """
131 @type debug: L{Debug}
132 @param debug: Debug object that received the event.
133
134 @type raw: L{DEBUG_EVENT}
135 @param raw: Raw DEBUG_EVENT structure as used by the Win32 API.
136 """
137 ## self.__debug = weakref.ref(debug)
138 self.debug = debug
139 self.raw = raw
140 self.continueStatus = win32.DBG_EXCEPTION_NOT_HANDLED
141
142 ## @property
143 ## def debug(self):
144 ## """
145 ## @rtype debug: L{Debug}
146 ## @return debug:
147 ## Debug object that received the event.
148 ## """
149 ## return self.__debug()
150
152 """
153 @rtype: str
154 @return: User-friendly name of the event.
155 """
156 return self.eventName
157
159 """
160 @rtype: str
161 @return: User-friendly description of the event.
162 """
163 return self.eventDescription
164
166 """
167 @rtype: int
168 @return: Debug event code as defined in the Win32 API.
169 """
170 return self.raw.dwDebugEventCode
171
172 ## # Compatibility with version 1.0
173 ## # XXX to be removed in version 1.4
174 ## def get_code(self):
175 ## """
176 ## Alias of L{get_event_code} for backwards compatibility
177 ## with WinAppDbg version 1.0.
178 ## Will be phased out in the next version.
179 ##
180 ## @rtype: int
181 ## @return: Debug event code as defined in the Win32 API.
182 ## """
183 ## return self.get_event_code()
184
186 """
187 @see: L{get_process}
188
189 @rtype: int
190 @return: Process global ID where the event occured.
191 """
192 return self.raw.dwProcessId
193
195 """
196 @see: L{get_thread}
197
198 @rtype: int
199 @return: Thread global ID where the event occured.
200 """
201 return self.raw.dwThreadId
202
204 """
205 @see: L{get_pid}
206
207 @rtype: L{Process}
208 @return: Process where the event occured.
209 """
210 pid = self.get_pid()
211 system = self.debug.system
212 if system.has_process(pid):
213 process = system.get_process(pid)
214 else:
215 # XXX HACK
216 # The process object was missing for some reason, so make a new one.
217 process = Process(pid)
218 system._ProcessContainer__add_process(process)
219 ## process.scan_threads() # not needed
220 process.scan_modules()
221 return process
222
224 """
225 @see: L{get_tid}
226
227 @rtype: L{Thread}
228 @return: Thread where the event occured.
229 """
230 tid = self.get_tid()
231 process = self.get_process()
232 if process.has_thread(tid):
233 thread = process.get_thread(tid)
234 else:
235 # XXX HACK
236 # The thread object was missing for some reason, so make a new one.
237 thread = Thread(tid)
238 process._ThreadContainer__add_thread(thread)
239 return thread
240
241 #==============================================================================
242
243 -class NoEvent (Event):
244 """
245 No event.
246
247 Dummy L{Event} object that can be used as a placeholder when no debug
248 event has occured yet. It's never returned by the L{EventFactory}.
249 """
250
251 eventMethod = 'no_event'
252 eventName = 'No event'
253 eventDescription = 'No debug event has occured.'
254
257
259 """
260 Always returns C{0}, so when evaluating the object as a boolean it's
261 always C{False}. This prevents L{Debug.cont} from trying to continue
262 a dummy event.
263 """
264 return 0
265
268
271
274
277
280
281 #==============================================================================
282
283 -class ExceptionEvent (Event):
284 """
285 Exception event.
286
287 @type exceptionName: dict( int S{->} str )
288 @cvar exceptionName:
289 Mapping of exception constants to their names.
290
291 @type exceptionDescription: dict( int S{->} str )
292 @cvar exceptionDescription:
293 Mapping of exception constants to user-friendly strings.
294
295 @type breakpoint: L{Breakpoint}
296 @ivar breakpoint:
297 If the exception was caused by one of our breakpoints, this member
298 contains a reference to the breakpoint object. Otherwise it's not
299 defined. It should only be used from the condition or action callback
300 routines, instead of the event handler.
301
302 @type hook: L{Hook}
303 @ivar hook:
304 If the exception was caused by a function hook, this member contains a
305 reference to the hook object. Otherwise it's not defined. It should
306 only be used from the hook callback routines, instead of the event
307 handler.
308 """
309
310 eventName = 'Exception event'
311 eventDescription = 'An exception was raised by the debugee.'
312
313 __exceptionMethod = {
314 win32.EXCEPTION_ACCESS_VIOLATION : 'access_violation',
315 win32.EXCEPTION_ARRAY_BOUNDS_EXCEEDED : 'array_bounds_exceeded',
316 win32.EXCEPTION_BREAKPOINT : 'breakpoint',
317 win32.EXCEPTION_DATATYPE_MISALIGNMENT : 'datatype_misalignment',
318 win32.EXCEPTION_FLT_DENORMAL_OPERAND : 'float_denormal_operand',
319 win32.EXCEPTION_FLT_DIVIDE_BY_ZERO : 'float_divide_by_zero',
320 win32.EXCEPTION_FLT_INEXACT_RESULT : 'float_inexact_result',
321 win32.EXCEPTION_FLT_INVALID_OPERATION : 'float_invalid_operation',
322 win32.EXCEPTION_FLT_OVERFLOW : 'float_overflow',
323 win32.EXCEPTION_FLT_STACK_CHECK : 'float_stack_check',
324 win32.EXCEPTION_FLT_UNDERFLOW : 'float_underflow',
325 win32.EXCEPTION_ILLEGAL_INSTRUCTION : 'illegal_instruction',
326 win32.EXCEPTION_IN_PAGE_ERROR : 'in_page_error',
327 win32.EXCEPTION_INT_DIVIDE_BY_ZERO : 'integer_divide_by_zero',
328 win32.EXCEPTION_INT_OVERFLOW : 'integer_overflow',
329 win32.EXCEPTION_INVALID_DISPOSITION : 'invalid_disposition',
330 win32.EXCEPTION_NONCONTINUABLE_EXCEPTION : 'noncontinuable_exception',
331 win32.EXCEPTION_PRIV_INSTRUCTION : 'privileged_instruction',
332 win32.EXCEPTION_SINGLE_STEP : 'single_step',
333 win32.EXCEPTION_STACK_OVERFLOW : 'stack_overflow',
334 win32.EXCEPTION_GUARD_PAGE : 'guard_page',
335 win32.EXCEPTION_INVALID_HANDLE : 'invalid_handle',
336 win32.EXCEPTION_POSSIBLE_DEADLOCK : 'possible_deadlock',
337 win32.EXCEPTION_WX86_BREAKPOINT : 'wow64_breakpoint',
338 win32.CONTROL_C_EXIT : 'control_c_exit',
339 win32.DBG_CONTROL_C : 'debug_control_c',
340 win32.MS_VC_EXCEPTION : 'ms_vc_exception',
341 }
342
343 __exceptionName = {
344 win32.EXCEPTION_ACCESS_VIOLATION : 'EXCEPTION_ACCESS_VIOLATION',
345 win32.EXCEPTION_ARRAY_BOUNDS_EXCEEDED : 'EXCEPTION_ARRAY_BOUNDS_EXCEEDED',
346 win32.EXCEPTION_BREAKPOINT : 'EXCEPTION_BREAKPOINT',
347 win32.EXCEPTION_DATATYPE_MISALIGNMENT : 'EXCEPTION_DATATYPE_MISALIGNMENT',
348 win32.EXCEPTION_FLT_DENORMAL_OPERAND : 'EXCEPTION_FLT_DENORMAL_OPERAND',
349 win32.EXCEPTION_FLT_DIVIDE_BY_ZERO : 'EXCEPTION_FLT_DIVIDE_BY_ZERO',
350 win32.EXCEPTION_FLT_INEXACT_RESULT : 'EXCEPTION_FLT_INEXACT_RESULT',
351 win32.EXCEPTION_FLT_INVALID_OPERATION : 'EXCEPTION_FLT_INVALID_OPERATION',
352 win32.EXCEPTION_FLT_OVERFLOW : 'EXCEPTION_FLT_OVERFLOW',
353 win32.EXCEPTION_FLT_STACK_CHECK : 'EXCEPTION_FLT_STACK_CHECK',
354 win32.EXCEPTION_FLT_UNDERFLOW : 'EXCEPTION_FLT_UNDERFLOW',
355 win32.EXCEPTION_ILLEGAL_INSTRUCTION : 'EXCEPTION_ILLEGAL_INSTRUCTION',
356 win32.EXCEPTION_IN_PAGE_ERROR : 'EXCEPTION_IN_PAGE_ERROR',
357 win32.EXCEPTION_INT_DIVIDE_BY_ZERO : 'EXCEPTION_INT_DIVIDE_BY_ZERO',
358 win32.EXCEPTION_INT_OVERFLOW : 'EXCEPTION_INT_OVERFLOW',
359 win32.EXCEPTION_INVALID_DISPOSITION : 'EXCEPTION_INVALID_DISPOSITION',
360 win32.EXCEPTION_NONCONTINUABLE_EXCEPTION : 'EXCEPTION_NONCONTINUABLE_EXCEPTION',
361 win32.EXCEPTION_PRIV_INSTRUCTION : 'EXCEPTION_PRIV_INSTRUCTION',
362 win32.EXCEPTION_SINGLE_STEP : 'EXCEPTION_SINGLE_STEP',
363 win32.EXCEPTION_STACK_OVERFLOW : 'EXCEPTION_STACK_OVERFLOW',
364 win32.EXCEPTION_GUARD_PAGE : 'EXCEPTION_GUARD_PAGE',
365 win32.EXCEPTION_INVALID_HANDLE : 'EXCEPTION_INVALID_HANDLE',
366 win32.EXCEPTION_POSSIBLE_DEADLOCK : 'EXCEPTION_POSSIBLE_DEADLOCK',
367 win32.EXCEPTION_WX86_BREAKPOINT : 'EXCEPTION_WX86_BREAKPOINT',
368 win32.CONTROL_C_EXIT : 'CONTROL_C_EXIT',
369 win32.DBG_CONTROL_C : 'DBG_CONTROL_C',
370 win32.MS_VC_EXCEPTION : 'MS_VC_EXCEPTION',
371 }
372
373 __exceptionDescription = {
374 win32.EXCEPTION_ACCESS_VIOLATION : 'Access violation',
375 win32.EXCEPTION_ARRAY_BOUNDS_EXCEEDED : 'Array bounds exceeded',
376 win32.EXCEPTION_BREAKPOINT : 'Breakpoint',
377 win32.EXCEPTION_DATATYPE_MISALIGNMENT : 'Datatype misalignment',
378 win32.EXCEPTION_FLT_DENORMAL_OPERAND : 'Float denormal operand',
379 win32.EXCEPTION_FLT_DIVIDE_BY_ZERO : 'Float divide by zero',
380 win32.EXCEPTION_FLT_INEXACT_RESULT : 'Float inexact result',
381 win32.EXCEPTION_FLT_INVALID_OPERATION : 'Float invalid operation',
382 win32.EXCEPTION_FLT_OVERFLOW : 'Float overflow',
383 win32.EXCEPTION_FLT_STACK_CHECK : 'Float stack check',
384 win32.EXCEPTION_FLT_UNDERFLOW : 'Float underflow',
385 win32.EXCEPTION_ILLEGAL_INSTRUCTION : 'Illegal instruction',
386 win32.EXCEPTION_IN_PAGE_ERROR : 'In-page error',
387 win32.EXCEPTION_INT_DIVIDE_BY_ZERO : 'Integer divide by zero',
388 win32.EXCEPTION_INT_OVERFLOW : 'Integer overflow',
389 win32.EXCEPTION_INVALID_DISPOSITION : 'Invalid disposition',
390 win32.EXCEPTION_NONCONTINUABLE_EXCEPTION : 'Noncontinuable exception',
391 win32.EXCEPTION_PRIV_INSTRUCTION : 'Privileged instruction',
392 win32.EXCEPTION_SINGLE_STEP : 'Single step event',
393 win32.EXCEPTION_STACK_OVERFLOW : 'Stack limits overflow',
394 win32.EXCEPTION_GUARD_PAGE : 'Guard page hit',
395 win32.EXCEPTION_INVALID_HANDLE : 'Invalid handle',
396 win32.EXCEPTION_POSSIBLE_DEADLOCK : 'Possible deadlock',
397 win32.EXCEPTION_WX86_BREAKPOINT : 'WOW64 breakpoint',
398 win32.CONTROL_C_EXIT : 'Control-C exit',
399 win32.DBG_CONTROL_C : 'Debug Control-C',
400 win32.MS_VC_EXCEPTION : 'Microsoft Visual C exception',
401 }
402
403 @property
407
409 """
410 @rtype: str
411 @return: Name of the exception as defined by the Win32 API.
412 """
413 code = self.get_exception_code()
414 unk = HexDump.integer(code)
415 return self.__exceptionName.get(code, unk)
416
418 """
419 @rtype: str
420 @return: User-friendly name of the exception.
421 """
422 code = self.get_exception_code()
423 unk = 'C++ exception %s' % HexDump.integer(code)
424 return self.__exceptionDescription.get(code, unk)
425
427 """
428 @rtype: bool
429 @return: True for first chance exceptions, False for last chance.
430 """
431 return self.raw.u.Exception.dwFirstChance != win32.FALSE
432
434 """
435 @rtype: bool
436 @return: The opposite of L{is_first_chance}.
437 """
438 return not self.is_first_chance()
439
441 """
442 @see: U{http://msdn.microsoft.com/en-us/library/aa363082(VS.85).aspx}
443
444 @rtype: bool
445 @return: True if the exception is noncontinuable.
446
447 Attempting to continue a noncontinuable exception results in an
448 EXCEPTION_NONCONTINUABLE_EXCEPTION exception to be raised.
449 """
450 return bool( self.raw.u.Exception.ExceptionRecord.ExceptionFlags & \
451 win32.EXCEPTION_NONCONTINUABLE )
452
454 """
455 @rtype: bool
456 @return: The opposite of L{is_noncontinuable}.
457 """
458 return not self.is_noncontinuable()
459
461 """
462 @rtype: int
463 @return: Exception code as defined by the Win32 API.
464 """
465 return self.raw.u.Exception.ExceptionRecord.ExceptionCode
466
468 """
469 @rtype: int
470 @return: Memory address where the exception occured.
471 """
472 address = self.raw.u.Exception.ExceptionRecord.ExceptionAddress
473 if address is None:
474 address = 0
475 return address
476
478 """
479 @type index: int
480 @param index: Index into the exception information block.
481
482 @rtype: int
483 @return: Exception information DWORD.
484 """
485 if index < 0 or index > win32.EXCEPTION_MAXIMUM_PARAMETERS:
486 raise IndexError, "Array index out of range: %s" % repr(index)
487 info = self.raw.u.Exception.ExceptionRecord.ExceptionInformation
488 value = info[index]
489 if value is None:
490 value = 0
491 return value
492
494 """
495 @rtype: list( int )
496 @return: Exception information block.
497 """
498 info = self.raw.u.Exception.ExceptionRecord.ExceptionInformation
499 data = list()
500 for index in xrange(0, win32.EXCEPTION_MAXIMUM_PARAMETERS):
501 value = info[index]
502 if value is None:
503 value = 0
504 data.append(value)
505 return data
506
508 """
509 @rtype: int
510 @return: Access violation type.
511 Should be one of the following constants:
512
513 - L{win32.EXCEPTION_READ_FAULT}
514 - L{win32.EXCEPTION_WRITE_FAULT}
515 - L{win32.EXCEPTION_EXECUTE_FAULT}
516
517 @note: This method is only meaningful for access violation exceptions,
518 in-page memory error exceptions and guard page exceptions.
519
520 @raise NotImplementedError: Wrong kind of exception.
521 """
522 if self.get_exception_code() not in (win32.EXCEPTION_ACCESS_VIOLATION,
523 win32.EXCEPTION_IN_PAGE_ERROR, win32.EXCEPTION_GUARD_PAGE):
524 msg = "This method is not meaningful for %s."
525 raise NotImplementedError, msg % self.get_exception_name()
526 return self.get_exception_information(0)
527
529 """
530 @rtype: int
531 @return: Access violation memory address.
532
533 @note: This method is only meaningful for access violation exceptions,
534 in-page memory error exceptions and guard page exceptions.
535
536 @raise NotImplementedError: Wrong kind of exception.
537 """
538 if self.get_exception_code() not in (win32.EXCEPTION_ACCESS_VIOLATION,
539 win32.EXCEPTION_IN_PAGE_ERROR, win32.EXCEPTION_GUARD_PAGE):
540 msg = "This method is not meaningful for %s."
541 raise NotImplementedError, msg % self.get_exception_name()
542 return self.get_exception_information(1)
543
545 """
546 @rtype: int
547 @return: NTSTATUS status code that caused the exception.
548
549 @note: This method is only meaningful for in-page memory error
550 exceptions.
551
552 @raise NotImplementedError: Not an in-page memory error.
553 """
554 if self.get_exception_code() != win32.EXCEPTION_IN_PAGE_ERROR:
555 msg = "This method is only meaningful "\
556 "for in-page memory error exceptions."
557 raise NotImplementedError, msg
558 return self.get_exception_information(2)
559
561 """
562 @rtype: bool
563 @return: Returns C{True} if there are additional exception records
564 associated with this exception. This would mean the exception
565 is nested, that is, it was triggered while trying to handle
566 at least one previous exception.
567 """
568 return bool(self.raw.u.Exception.ExceptionRecord.ExceptionRecord)
569
571 """
572 Traverses the exception record linked list and builds a Python list.
573
574 Nested exception records are received for nested exceptions. This
575 happens when an exception is raised in the debugee while trying to
576 handle a previous exception.
577
578 @rtype: list( L{win32.EXCEPTION_RECORD} )
579 @return:
580 List of raw exception record structures as used by the Win32 API.
581
582 There is always at least one exception record, so the list is
583 never empty. All other methods of this class read from the first
584 exception record only, that is, the most recent exception.
585 """
586 # The first EXCEPTION_RECORD is contained in EXCEPTION_DEBUG_INFO.
587 # The remaining EXCEPTION_RECORD structures are linked by pointers.
588 nested = list()
589 record = self.raw.u.Exception
590 while True:
591 record = record.ExceptionRecord
592 if not record:
593 break
594 nested.append(record)
595 return nested
596
598 """
599 Traverses the exception record linked list and builds a Python list.
600
601 Nested exception records are received for nested exceptions. This
602 happens when an exception is raised in the debugee while trying to
603 handle a previous exception.
604
605 @rtype: list( L{ExceptionEvent} )
606 @return:
607 List of ExceptionEvent objects representing each exception record
608 found in this event.
609
610 There is always at least one exception record, so the list is
611 never empty. All other methods of this class read from the first
612 exception record only, that is, the most recent exception.
613 """
614 # The list always begins with ourselves.
615 # Just put a reference to "self" as the first element,
616 # and start looping from the second exception record.
617 nested = [ self ]
618 raw = self.raw
619 dwDebugEventCode = raw.dwDebugEventCode
620 dwProcessId = raw.dwProcessId
621 dwThreadId = raw.dwThreadId
622 dwFirstChance = raw.u.Exception.dwFirstChance
623 record = raw.u.Exception.ExceptionRecord
624 while True:
625 record = record.ExceptionRecord
626 if not record:
627 break
628 raw = win32.DEBUG_EVENT()
629 raw.dwDebugEventCode = dwDebugEventCode
630 raw.dwProcessId = dwProcessId
631 raw.dwThreadId = dwThreadId
632 raw.u.Exception.ExceptionRecord = record
633 raw.u.Exception.dwFirstChance = dwFirstChance
634 event = EventFactory.get(self.debug, raw)
635 nested.append(event)
636 return nested
637
638 #==============================================================================
639
640 -class CreateThreadEvent (Event):
641 """
642 Thread creation event.
643 """
644
645 eventMethod = 'create_thread'
646 eventName = 'Thread creation event'
647 eventDescription = 'A new thread has started.'
648
650 """
651 @rtype: L{ThreadHandle}
652 @return: Thread handle received from the system.
653 Returns C{None} if the handle is not available.
654 """
655 # The handle doesn't need to be closed.
656 # See http://msdn.microsoft.com/en-us/library/ms681423(VS.85).aspx
657 hThread = self.raw.u.CreateThread.hThread
658 if hThread in (0, win32.NULL, win32.INVALID_HANDLE_VALUE):
659 hThread = None
660 else:
661 hThread = ThreadHandle(hThread, False)
662 return hThread
663
665 """
666 @rtype: int
667 @return: Pointer to the TEB.
668 """
669 return self.raw.u.CreateThread.lpThreadLocalBase
670
672 """
673 @rtype: int
674 @return: Pointer to the first instruction to execute in this thread.
675
676 Returns C{NULL} when the debugger attached to a process
677 and the thread already existed.
678
679 See U{http://msdn.microsoft.com/en-us/library/ms679295(VS.85).aspx}
680 """
681 return self.raw.u.CreateThread.lpStartAddress
682
683 #==============================================================================
684
685 -class CreateProcessEvent (Event):
686 """
687 Process creation event.
688 """
689
690 eventMethod = 'create_process'
691 eventName = 'Process creation event'
692 eventDescription = 'A new process has started.'
693
695 """
696 @rtype: L{FileHandle} or None
697 @return: File handle to the main module, received from the system.
698 Returns C{None} if the handle is not available.
699 """
700 # This handle DOES need to be closed.
701 # Therefore we must cache it so it doesn't
702 # get closed after the first call.
703 try:
704 hFile = self.__hFile
705 except AttributeError:
706 hFile = self.raw.u.CreateProcessInfo.hFile
707 if hFile in (0, win32.NULL, win32.INVALID_HANDLE_VALUE):
708 hFile = None
709 else:
710 hFile = FileHandle(hFile, True)
711 self.__hFile = hFile
712 return hFile
713
715 """
716 @rtype: L{ProcessHandle}
717 @return: Process handle received from the system.
718 Returns C{None} if the handle is not available.
719 """
720 # The handle doesn't need to be closed.
721 # See http://msdn.microsoft.com/en-us/library/ms681423(VS.85).aspx
722 hProcess = self.raw.u.CreateProcessInfo.hProcess
723 if hProcess in (0, win32.NULL, win32.INVALID_HANDLE_VALUE):
724 hProcess = None
725 else:
726 hProcess = ProcessHandle(hProcess, False)
727 return hProcess
728
730 """
731 @rtype: L{ThreadHandle}
732 @return: Thread handle received from the system.
733 Returns C{None} if the handle is not available.
734 """
735 # The handle doesn't need to be closed.
736 # See http://msdn.microsoft.com/en-us/library/ms681423(VS.85).aspx
737 hThread = self.raw.u.CreateProcessInfo.hThread
738 if hThread in (0, win32.NULL, win32.INVALID_HANDLE_VALUE):
739 hThread = None
740 else:
741 hThread = ThreadHandle(hThread, False)
742 return hThread
743
745 """
746 @rtype: int
747 @return: Pointer to the first instruction to execute in this process.
748
749 Returns C{NULL} when the debugger attaches to a process.
750
751 See U{http://msdn.microsoft.com/en-us/library/ms679295(VS.85).aspx}
752 """
753 return self.raw.u.CreateProcessInfo.lpStartAddress
754
756 """
757 @rtype: int
758 @return: Base address of the main module.
759 """
760 return self.raw.u.CreateProcessInfo.lpBaseOfImage
761
763 """
764 @rtype: int
765 @return: Pointer to the TEB.
766 """
767 return self.raw.u.CreateProcessInfo.lpThreadLocalBase
768
770 """
771 @rtype: str
772 @return: Debugging information.
773 """
774 raw = self.raw.u.CreateProcessInfo
775 ptr = raw.lpBaseOfImage + raw.dwDebugInfoFileOffset
776 size = raw.nDebugInfoSize
777 data = self.get_process().peek(ptr, size)
778 if len(data) == size:
779 return data
780 return None
781
783 """
784 @rtype: str, None
785 @return: This method does it's best to retrieve the filename to
786 the main module of the process. However, sometimes that's not
787 possible, and C{None} is returned instead.
788 """
789
790 # Try to get the filename from the file handle.
791 szFilename = None
792 hFile = self.get_file_handle()
793 if hFile:
794 szFilename = hFile.get_filename()
795 if not szFilename:
796
797 # Try to get it from CREATE_PROCESS_DEBUG_INFO.lpImageName
798 # It's NULL or *NULL most of the times, see MSDN:
799 # http://msdn.microsoft.com/en-us/library/ms679286(VS.85).aspx
800 aProcess = self.get_process()
801 lpRemoteFilenamePtr = self.raw.u.CreateProcessInfo.lpImageName
802 if lpRemoteFilenamePtr:
803 lpFilename = aProcess.peek_uint(lpRemoteFilenamePtr)
804 fUnicode = bool( self.raw.u.CreateProcessInfo.fUnicode )
805 szFilename = aProcess.peek_string(lpFilename, fUnicode)
806
807 # XXX TODO
808 # Sometimes the filename is relative (ntdll.dll, kernel32.dll).
809 # It could be converted to an absolute pathname (SearchPath).
810
811 # Try to get it from Process.get_image_name().
812 if not szFilename:
813 szFilename = aProcess.get_image_name()
814
815 # Return the filename, or None on error.
816 return szFilename
817
819 """
820 @rtype: int
821 @return: Base address of the main module.
822 """
823 return self.get_image_base()
824
826 """
827 @rtype: L{Module}
828 @return: Main module of the process.
829 """
830 return self.get_process().get_module( self.get_module_base() )
831
832 #==============================================================================
833
834 -class ExitThreadEvent (Event):
835 """
836 Thread termination event.
837 """
838
839 eventMethod = 'exit_thread'
840 eventName = 'Thread termination event'
841 eventDescription = 'A thread has finished executing.'
842
844 """
845 @rtype: int
846 @return: Exit code of the thread.
847 """
848 return self.raw.u.ExitThread.dwExitCode
849
850 #==============================================================================
851
852 -class ExitProcessEvent (Event):
853 """
854 Process termination event.
855 """
856
857 eventMethod = 'exit_process'
858 eventName = 'Process termination event'
859 eventDescription = 'A process has finished executing.'
860
862 """
863 @rtype: int
864 @return: Exit code of the process.
865 """
866 return self.raw.u.ExitProcess.dwExitCode
867
869 """
870 @rtype: None or str
871 @return: Filename of the main module.
872 C{None} if the filename is unknown.
873 """
874 return self.get_module().get_filename()
875
877 """
878 @rtype: int
879 @return: Base address of the main module.
880 """
881 return self.get_module_base()
882
884 """
885 @rtype: int
886 @return: Base address of the main module.
887 """
888 return self.get_module().get_base()
889
891 """
892 @rtype: L{Module}
893 @return: Main module of the process.
894 """
895 return self.get_process().get_main_module()
896
897 #==============================================================================
898
899 -class LoadDLLEvent (Event):
900 """
901 Module load event.
902 """
903
904 eventMethod = 'load_dll'
905 eventName = 'Module load event'
906 eventDescription = 'A new DLL library was loaded by the debugee.'
907
909 """
910 @rtype: int
911 @return: Base address for the newly loaded DLL.
912 """
913 return self.raw.u.LoadDll.lpBaseOfDll
914
916 """
917 @rtype: L{Module}
918 @return: Module object for the newly loaded DLL.
919 """
920 lpBaseOfDll = self.get_module_base()
921 aProcess = self.get_process()
922 if aProcess.has_module(lpBaseOfDll):
923 aModule = aProcess.get_module(lpBaseOfDll)
924 else:
925 # XXX HACK
926 # For some reason the module object is missing, so make a new one.
927 aModule = Module(lpBaseOfDll,
928 hFile = self.get_file_handle(),
929 fileName = get_filename(),
930 process = aProcess)
931 aProcess.__ModuleContainer_add_module(aModule)
932 return aModule
933
935 """
936 @rtype: L{FileHandle} or None
937 @return: File handle to the newly loaded DLL received from the system.
938 Returns C{None} if the handle is not available.
939 """
940 # This handle DOES need to be closed.
941 # Therefore we must cache it so it doesn't
942 # get closed after the first call.
943 try:
944 hFile = self.__hFile
945 except AttributeError:
946 hFile = self.raw.u.LoadDll.hFile
947 if hFile in (0, win32.NULL, win32.INVALID_HANDLE_VALUE):
948 hFile = None
949 else:
950 hFile = FileHandle(hFile, True)
951 self.__hFile = hFile
952 return hFile
953
955 """
956 @rtype: str, None
957 @return: This method does it's best to retrieve the filename to
958 the newly loaded module. However, sometimes that's not
959 possible, and C{None} is returned instead.
960 """
961 szFilename = None
962
963 # Try to get it from LOAD_DLL_DEBUG_INFO.lpImageName
964 # It's NULL or *NULL most of the times, see MSDN:
965 # http://msdn.microsoft.com/en-us/library/ms679286(VS.85).aspx
966 aProcess = self.get_process()
967 lpRemoteFilenamePtr = self.raw.u.LoadDll.lpImageName
968 if lpRemoteFilenamePtr:
969 lpFilename = aProcess.peek_uint(lpRemoteFilenamePtr)
970 fUnicode = bool( self.raw.u.LoadDll.fUnicode )
971 szFilename = aProcess.peek_string(lpFilename, fUnicode)
972 if not szFilename:
973 szFilename = None
974
975 # Try to get the filename from the file handle.
976 if not szFilename:
977 hFile = self.get_file_handle()
978 if hFile:
979 szFilename = hFile.get_filename()
980
981 # Return the filename, or None on error.
982 return szFilename
983
984 #==============================================================================
985
986 -class UnloadDLLEvent (Event):
987 """
988 Module unload event.
989 """
990
991 eventMethod = 'unload_dll'
992 eventName = 'Module unload event'
993 eventDescription = 'A DLL library was unloaded by the debugee.'
994
996 """
997 @rtype: int
998 @return: Base address for the recently unloaded DLL.
999 """
1000 return self.raw.u.UnloadDll.lpBaseOfDll
1001
1003 """
1004 @rtype: L{Module}
1005 @return: Module object for the recently unloaded DLL.
1006 """
1007 lpBaseOfDll = self.get_module_base()
1008 aProcess = self.get_process()
1009 if aProcess.has_module(lpBaseOfDll):
1010 aModule = aProcess.get_module(lpBaseOfDll)
1011 else:
1012 aModule = Module(lpBaseOfDll, process = aProcess)
1013 aProcess._ModuleContainer__add_module(aModule)
1014 return aModule
1015
1017 """
1018 @rtype: None or L{FileHandle}
1019 @return: File handle to the recently unloaded DLL.
1020 Returns C{None} if the handle is not available.
1021 """
1022 hFile = self.get_module().hFile
1023 if hFile in (0, win32.NULL, win32.INVALID_HANDLE_VALUE):
1024 hFile = None
1025 return hFile
1026
1028 """
1029 @rtype: None or str
1030 @return: Filename of the recently unloaded DLL.
1031 C{None} if the filename is unknown.
1032 """
1033 return self.get_module().get_filename()
1034
1035 #==============================================================================
1036
1037 -class OutputDebugStringEvent (Event):
1038 """
1039 Debug string output event.
1040 """
1041
1042 eventMethod = 'output_string'
1043 eventName = 'Debug string output event'
1044 eventDescription = 'The debugee sent a message to the debugger.'
1045
1047 """
1048 @rtype: str, unicode
1049 @return: String sent by the debugee.
1050 It may be ANSI or Unicode and may end with a null character.
1051 """
1052 return self.get_process().peek_string(
1053 self.raw.u.DebugString.lpDebugStringData,
1054 bool( self.raw.u.DebugString.fUnicode ),
1055 self.raw.u.DebugString.nDebugStringLength)
1056
1057 #==============================================================================
1058
1059 -class RIPEvent (Event):
1060 """
1061 RIP event.
1062 """
1063
1064 eventMethod = 'rip'
1065 eventName = 'RIP event'
1066 eventDescription = 'An error has occured and the process ' \
1067 'can no longer be debugged.'
1068
1070 """
1071 @rtype: int
1072 @return: RIP error code as defined by the Win32 API.
1073 """
1074 return self.raw.u.RipInfo.dwError
1075
1082
1083 #==============================================================================
1084
1085 -class EventFactory (object):
1086 """
1087 Factory of L{Event} objects.
1088
1089 @type baseEvent: L{Event}
1090 @cvar baseEvent:
1091 Base class for Event objects.
1092 It's used for unknown event codes.
1093
1094 @type eventClasses: dict( int S{->} L{Event} )
1095 @cvar eventClasses:
1096 Dictionary that maps event codes to L{Event} subclasses.
1097 """
1098
1099 baseEvent = Event
1100 eventClasses = {
1101 win32.EXCEPTION_DEBUG_EVENT : ExceptionEvent, # 1
1102 win32.CREATE_THREAD_DEBUG_EVENT : CreateThreadEvent, # 2
1103 win32.CREATE_PROCESS_DEBUG_EVENT : CreateProcessEvent, # 3
1104 win32.EXIT_THREAD_DEBUG_EVENT : ExitThreadEvent, # 4
1105 win32.EXIT_PROCESS_DEBUG_EVENT : ExitProcessEvent, # 5
1106 win32.LOAD_DLL_DEBUG_EVENT : LoadDLLEvent, # 6
1107 win32.UNLOAD_DLL_DEBUG_EVENT : UnloadDLLEvent, # 7
1108 win32.OUTPUT_DEBUG_STRING_EVENT : OutputDebugStringEvent, # 8
1109 win32.RIP_EVENT : RIPEvent, # 9
1110 }
1111
1112 @classmethod
1114 """
1115 @type debug: L{Debug}
1116 @param debug: Debug object that received the event.
1117
1118 @type raw: L{DEBUG_EVENT}
1119 @param raw: Raw DEBUG_EVENT structure as used by the Win32 API.
1120
1121 @rtype: L{Event}
1122 @returns: An Event object or one of it's subclasses,
1123 depending on the event type.
1124 """
1125 eventClass = cls.eventClasses.get(raw.dwDebugEventCode, cls.baseEvent)
1126 return eventClass(debug, raw)
1127
1129 """
1130 C{EventFactory} is a singleton, you can't really have multiple
1131 instances of it. To create this effect, the C{__new__} operator
1132 was overriden to return always the I{class} object instead
1133 of new I{instances}.
1134
1135 @rtype: L{EventFactory}
1136 @return: C{EventFactory} class (NOT an instance)
1137 """
1138 return EventFactory
1139
1140 #==============================================================================
1141
1142 -class EventHandler (object):
1143 """
1144 Base class for debug event handlers.
1145
1146 Your program should subclass it to implement it's own event handling.
1147
1148 The signature for event handlers is the following::
1149
1150 def event_handler(self, event):
1151
1152 Where B{event} is an L{Event} object.
1153
1154 Each event handler is named after the event they handle.
1155 This is the list of all valid event handler names:
1156
1157 - I{event}
1158
1159 Receives an L{Event} object or an object of any of it's subclasses,
1160 and handles any event for which no handler was defined.
1161
1162 - I{unknown_event}
1163
1164 Receives an L{Event} object or an object of any of it's subclasses,
1165 and handles any event unknown to the debugging engine. (This is not
1166 likely to happen unless the Win32 debugging API is changed in future
1167 versions of Windows).
1168
1169 - I{exception}
1170
1171 Receives an L{ExceptionEvent} object and handles any exception for
1172 which no handler was defined. See above for exception handlers.
1173
1174 - I{unknown_exception}
1175
1176 Receives an L{ExceptionEvent} object and handles any exception unknown
1177 to the debugging engine. This usually happens for C++ exceptions, which
1178 are not standardized and may change from one compiler to the next.
1179
1180 Currently we have partial support for C++ exceptions thrown by Microsoft
1181 compilers.
1182
1183 Also see: U{RaiseException()
1184 <http://msdn.microsoft.com/en-us/library/ms680552(VS.85).aspx>}
1185
1186 - I{create_thread}
1187
1188 Receives a L{CreateThreadEvent} object.
1189
1190 - I{create_process}
1191
1192 Receives a L{CreateProcessEvent} object.
1193
1194 - I{exit_thread}
1195
1196 Receives a L{ExitThreadEvent} object.
1197
1198 - I{exit_process}
1199
1200 Receives a L{ExitProcessEvent} object.
1201
1202 - I{load_dll}
1203
1204 Receives a L{LoadDLLEvent} object.
1205
1206 - I{unload_dll}
1207
1208 Receives an L{UnloadDLLEvent} object.
1209
1210 - I{output_string}
1211
1212 Receives an L{OutputDebugStringEvent} object.
1213
1214 - I{rip}
1215
1216 Receives a L{RIPEvent} object.
1217
1218 This is the list of all valid exception handler names
1219 (they all receive an L{ExceptionEvent} object):
1220
1221 - I{access_violation}
1222 - I{array_bounds_exceeded}
1223 - I{breakpoint}
1224 - I{control_c_exit}
1225 - I{datatype_misalignment}
1226 - I{debug_control_c}
1227 - I{float_denormal_operand}
1228 - I{float_divide_by_zero}
1229 - I{float_inexact_result}
1230 - I{float_invalid_operation}
1231 - I{float_overflow}
1232 - I{float_stack_check}
1233 - I{float_underflow}
1234 - I{guard_page}
1235 - I{illegal_instruction}
1236 - I{in_page_error}
1237 - I{integer_divide_by_zero}
1238 - I{integer_overflow}
1239 - I{invalid_disposition}
1240 - I{invalid_handle}
1241 - I{ms_vc_exception}
1242 - I{noncontinuable_exception}
1243 - I{possible_deadlock}
1244 - I{privileged_instruction}
1245 - I{single_step}
1246 - I{stack_overflow}
1247 - I{wow64_breakpoint}
1248
1249
1250
1251 @type apiHooks: dict( str S{->} tuple( str, int ) )
1252 @cvar apiHooks:
1253 Dictionary that maps module names to
1254 tuples of ( procedure name, parameter count ).
1255
1256 All procedures listed here will be hooked for calls from the debugee.
1257 When this happens, the corresponding event handler is notified both
1258 when the procedure is entered and when it's left by the debugee.
1259
1260 For example, if the procedure name is "LoadLibraryEx" the event handler
1261 routines must be defined as "pre_LoadLibraryEx" and "post_LoadLibraryEx"
1262 in your class.
1263
1264 The signature for the routines can be something like this::
1265
1266 def pre_LoadLibraryEx(event, *params):
1267 ra = params[0] # return address
1268 argv = params[1:] # function parameters
1269
1270 # (...)
1271
1272 def post_LoadLibrary(event, return_value):
1273
1274 # (...)
1275
1276 But since you can also specify the number of arguments, this signature
1277 works too (four arguments in this case)::
1278
1279 def pre_LoadLibraryEx(event, ra, lpFilename, hFile, dwFlags):
1280 szFilename = event.get_process().peek_string(lpFilename)
1281
1282 # (...)
1283
1284 Note that the number of parameters to pull from the stack includes the
1285 return address. The apiHooks dictionary for the example above would
1286 look like this::
1287
1288 apiHook = {
1289
1290 "kernel32.dll" : (
1291
1292 # Procedure name Parameter count
1293 ( "LoadLibraryEx", 4 ),
1294
1295 # (more procedures can go here...)
1296 ),
1297
1298 # (more libraries can go here...)
1299 }
1300
1301 For a more complete support of API hooking, you can also check out
1302 Universal Hooker at U{http://oss.coresecurity.com/projects/uhooker.htm}
1303 """
1304
1305 #------------------------------------------------------------------------------
1306
1307 # Default (empty) API hooks dictionary.
1308 apiHooks = {}
1309
1311 # XXX HACK
1312 # This will be removed when hooks are supported in AMD64.
1313 if self.apiHooks and win32.CONTEXT.arch != 'i386':
1314 raise NotImplementedError, "Hooks are not yet implemented in 64 bits"
1315
1316 # Convert the tuples into instances of the ApiHook class.
1317 # A new dictionary must be instanced, otherwise we could also be
1318 # affecting all other instances of the EventHandler.
1319 self.__apiHooks = dict()
1320 for lib, hooks in self.apiHooks.iteritems():
1321 self.__apiHooks[lib] = [ ApiHook(self, *h) for h in hooks ]
1322
1324 """
1325 Hook the requested API calls (in self.apiHooks).
1326
1327 This method is called automatically whenever a DLL is loaded.
1328 """
1329 if self.__apiHooks:
1330 fileName = event.get_module().get_filename()
1331 if fileName:
1332 lib_name = PathOperations.pathname_to_filename(fileName).lower()
1333 debug = event.debug
1334 pid = event.get_pid()
1335 for hook_lib, hook_api_list in self.__apiHooks.iteritems():
1336 if hook_lib == lib_name:
1337 for hook_api_stub in hook_api_list:
1338 hook_api_stub.hook(debug, pid, lib_name)
1339
1341 """
1342 Dispatch debug events.
1343
1344 @type event: L{Event}
1345 @param event: Event object.
1346 """
1347 eventCode = event.get_event_code()
1348 if eventCode == win32.EXCEPTION_DEBUG_EVENT:
1349 method = getattr(self, 'exception', self.event)
1350 method = getattr(self, event.eventMethod, method)
1351 else:
1352 method = getattr(self, event.eventMethod, self.event)
1353 try:
1354 if eventCode == win32.LOAD_DLL_DEBUG_EVENT:
1355 self.__setApiHooksForDll(event)
1356 finally:
1357 return method(event)
1358
1367
1368 #==============================================================================
1369
1370 -class EventDispatcher (object):
1371 """
1372 Implements debug event dispatching capabilities.
1373 """
1374
1375 # Maps event code constants to the names of the pre-notify routines.
1376 # These routines are called BEFORE the user-defined handlers.
1377 # Unknown codes are ignored.
1378 __preEventNotifyCallbackName = {
1379 win32.CREATE_THREAD_DEBUG_EVENT : 'notify_create_thread',
1380 win32.CREATE_PROCESS_DEBUG_EVENT : 'notify_create_process',
1381 win32.LOAD_DLL_DEBUG_EVENT : 'notify_load_dll',
1382 }
1383
1384 # Maps event code constants to the names of the post-notify routines.
1385 # These routines are called AFTER the user-defined handlers.
1386 # Unknown codes are ignored.
1387 __postEventNotifyCallbackName = {
1388 win32.EXIT_THREAD_DEBUG_EVENT : 'notify_exit_thread',
1389 win32.EXIT_PROCESS_DEBUG_EVENT : 'notify_exit_process',
1390 win32.UNLOAD_DLL_DEBUG_EVENT : 'notify_unload_dll',
1391 win32.RIP_EVENT : 'notify_rip',
1392 }
1393
1394 # Maps exception code constants to the names of the pre-notify routines.
1395 # These routines are called BEFORE the user-defined handlers.
1396 # Unknown codes are ignored.
1397 __preExceptionNotifyCallbackName = {
1398 win32.EXCEPTION_BREAKPOINT : 'notify_breakpoint',
1399 win32.EXCEPTION_SINGLE_STEP : 'notify_single_step',
1400 win32.EXCEPTION_GUARD_PAGE : 'notify_guard_page',
1401 win32.DBG_CONTROL_C : 'notify_debug_control_c',
1402 win32.MS_VC_EXCEPTION : 'notify_ms_vc_exception',
1403 }
1404
1405 # Maps exception code constants to the names of the post-notify routines.
1406 # These routines are called AFTER the user-defined handlers.
1407 # Unknown codes are ignored.
1408 __postExceptionNotifyCallbackName = {
1409 }
1410
1412 """
1413 Event dispatcher.
1414
1415 @type eventHandler: L{EventHandler}
1416 @param eventHandler: (Optional) Event handler object.
1417
1418 @note: The L{eventHandler} parameter may be any callable Python object
1419 (for example a function, or an instance method).
1420 However you'll probably find it more convenient to use an instance
1421 of a subclass of L{EventHandler} here.
1422 """
1423 if eventHandler is not None and not callable(eventHandler):
1424 raise TypeError, "Event handler must be a callable object"
1425 try:
1426 if issubclass(eventHandler):
1427 classname = str(eventHandler)
1428 msg = "Event handler must be an instance of class %s"
1429 msg += "rather than the %s class itself. Missing brackets?"
1430 msg = msg % (classname, classname)
1431 raise TypeError, msg
1432 except TypeError:
1433 pass
1434 self.__eventHandler = eventHandler
1435
1437 """
1438 Sends event notifications to the L{Debug} object and
1439 the L{EventHandler} object provided by the user.
1440
1441 The L{Debug} object will forward the notifications to it's contained
1442 snapshot objects (L{System}, L{Process}, L{Thread} and L{Module}) when
1443 appropriate.
1444
1445 @warning: This method is called automatically from L{Debug.dispatch}.
1446
1447 @see: L{Debug.cont}, L{Debug.loop}, L{Debug.wait}
1448
1449 @type event: L{Event}
1450 @param event: Event object passed to L{Debug.dispatch}.
1451
1452 @raise WindowsError: Raises an exception on error.
1453 """
1454 returnValue = None
1455 bCallHandler = True
1456 pre_handler = None
1457 post_handler = None
1458 eventCode = event.get_event_code()
1459
1460 # Get the pre and post notification methods for exceptions.
1461 # If not found, the following steps take care of that.
1462 if eventCode == win32.EXCEPTION_DEBUG_EVENT:
1463 exceptionCode = event.get_exception_code()
1464 pre_name = self.__preExceptionNotifyCallbackName.get(
1465 exceptionCode, None)
1466 post_name = self.__postExceptionNotifyCallbackName.get(
1467 exceptionCode, None)
1468 if pre_name is not None:
1469 pre_handler = getattr(self, pre_name, None)
1470 if post_name is not None:
1471 post_handler = getattr(self, post_name, None)
1472
1473 # Get the pre notification method for all other events.
1474 # This includes the exception event if no notify method was found
1475 # for this exception code.
1476 if pre_handler is None:
1477 pre_name = self.__preEventNotifyCallbackName.get(eventCode, None)
1478 if pre_name is not None:
1479 pre_handler = getattr(self, pre_name, pre_handler)
1480
1481 # Get the post notification method for all other events.
1482 # This includes the exception event if no notify method was found
1483 # for this exception code.
1484 if post_handler is None:
1485 post_name = self.__postEventNotifyCallbackName.get(eventCode, None)
1486 if post_name is not None:
1487 post_handler = getattr(self, post_name, post_handler)
1488
1489 # Call the pre-notify method only if it was defined.
1490 # If an exception is raised don't call the other methods.
1491 if pre_handler is not None:
1492 bCallHandler = pre_handler(event)
1493
1494 # Call the user-defined event handler only if the pre-notify
1495 # method was not defined, or was and it returned True.
1496 try:
1497 if bCallHandler and self.__eventHandler is not None:
1498 returnValue = self.__eventHandler(event)
1499
1500 # Call the post-notify method if defined, even if an exception is
1501 # raised by the user-defined event handler.
1502 finally:
1503 if post_handler is not None:
1504 post_handler(event)
1505
1506 # Return the value from the call to the user-defined event handler.
1507 # If not defined return None.
1508 return returnValue
1509
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Tue Jul 20 14:32:27 2010 | http://epydoc.sourceforge.net |