Package winappdbg :: Module event
[hide private]
[frames] | no frames]

Source Code for Module winappdbg.event

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