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

Source Code for Module winappdbg.event

   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
129 - def __init__(self, debug, raw):
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
151 - def get_event_name(self):
152 """ 153 @rtype: str 154 @return: User-friendly name of the event. 155 """ 156 return self.eventName
157
158 - def get_event_description(self):
159 """ 160 @rtype: str 161 @return: User-friendly description of the event. 162 """ 163 return self.eventDescription
164
165 - def get_event_code(self):
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
185 - def get_pid(self):
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
194 - def get_tid(self):
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
203 - def get_process(self):
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
223 - def get_thread(self):
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
255 - def __init__(self, debug, raw = None):
256 Event.__init__(self, debug, raw)
257
258 - def __len__(self):
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
266 - def get_event_code(self):
267 return -1
268
269 - def get_pid(self):
270 return -1
271
272 - def get_tid(self):
273 return -1
274
275 - def get_process(self):
276 return Process(self.get_pid())
277
278 - def get_thread(self):
279 return Thread(self.get_tid())
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
404 - def eventMethod(self):
405 return self.__exceptionMethod.get( 406 self.get_exception_code(), 'unknown_exception')
407
408 - def get_exception_name(self):
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
417 - def get_exception_description(self):
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
426 - def is_first_chance(self):
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
433 - def is_last_chance(self):
434 """ 435 @rtype: bool 436 @return: The opposite of L{is_first_chance}. 437 """ 438 return not self.is_first_chance()
439
440 - def is_noncontinuable(self):
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
453 - def is_continuable(self):
454 """ 455 @rtype: bool 456 @return: The opposite of L{is_noncontinuable}. 457 """ 458 return not self.is_noncontinuable()
459
460 - def get_exception_code(self):
461 """ 462 @rtype: int 463 @return: Exception code as defined by the Win32 API. 464 """ 465 return self.raw.u.Exception.ExceptionRecord.ExceptionCode
466
467 - def get_exception_address(self):
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
477 - def get_exception_information(self, index):
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
507 - def get_fault_type(self):
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
528 - def get_fault_address(self):
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
544 - def get_ntstatus_code(self):
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
560 - def is_nested(self):
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
597 - def get_nested_exceptions(self):
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
649 - def get_thread_handle(self):
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
664 - def get_teb(self):
665 """ 666 @rtype: int 667 @return: Pointer to the TEB. 668 """ 669 return self.raw.u.CreateThread.lpThreadLocalBase
670
671 - def get_start_address(self):
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
694 - def get_file_handle(self):
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
714 - def get_process_handle(self):
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
729 - def get_thread_handle(self):
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
744 - def get_start_address(self):
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
755 - def get_image_base(self):
756 """ 757 @rtype: int 758 @return: Base address of the main module. 759 """ 760 return self.raw.u.CreateProcessInfo.lpBaseOfImage
761
762 - def get_teb(self):
763 """ 764 @rtype: int 765 @return: Pointer to the TEB. 766 """ 767 return self.raw.u.CreateProcessInfo.lpThreadLocalBase
768
769 - def get_debug_info(self):
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
782 - def get_filename(self):
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
818 - def get_module_base(self):
819 """ 820 @rtype: int 821 @return: Base address of the main module. 822 """ 823 return self.get_image_base()
824
825 - def get_module(self):
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
843 - def get_exit_code(self):
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
861 - def get_exit_code(self):
862 """ 863 @rtype: int 864 @return: Exit code of the process. 865 """ 866 return self.raw.u.ExitProcess.dwExitCode
867
868 - def get_filename(self):
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
876 - def get_image_base(self):
877 """ 878 @rtype: int 879 @return: Base address of the main module. 880 """ 881 return self.get_module_base()
882
883 - def get_module_base(self):
884 """ 885 @rtype: int 886 @return: Base address of the main module. 887 """ 888 return self.get_module().get_base()
889
890 - def get_module(self):
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
908 - def get_module_base(self):
909 """ 910 @rtype: int 911 @return: Base address for the newly loaded DLL. 912 """ 913 return self.raw.u.LoadDll.lpBaseOfDll
914
915 - def get_module(self):
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
934 - def get_file_handle(self):
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
954 - def get_filename(self):
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
995 - def get_module_base(self):
996 """ 997 @rtype: int 998 @return: Base address for the recently unloaded DLL. 999 """ 1000 return self.raw.u.UnloadDll.lpBaseOfDll
1001
1002 - def get_module(self):
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
1016 - def get_file_handle(self):
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
1027 - def get_filename(self):
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
1046 - def get_debug_string(self):
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
1069 - def get_rip_error(self):
1070 """ 1071 @rtype: int 1072 @return: RIP error code as defined by the Win32 API. 1073 """ 1074 return self.raw.u.RipInfo.dwError
1075
1076 - def get_rip_type(self):
1077 """ 1078 @rtype: int 1079 @return: RIP type code as defined by the Win32 API. 1080 """ 1081 return self.raw.u.RipInfo.dwType
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
1113 - def get(cls, debug, raw):
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
1128 - def __new__(typ, *args, **kwargs):
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
1310 - def __init__(self):
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
1323 - def __setApiHooksForDll(self, event):
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
1340 - def __call__(self, event):
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
1359 - def event(self, event):
1360 """ 1361 Handler for events not handled by any other defined method. 1362 1363 @type event: L{Event} 1364 @param event: Event object. 1365 """ 1366 pass
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
1411 - def __init__(self, eventHandler = None):
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
1436 - def dispatch(self, event):
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