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

Source Code for Module winappdbg.interactive

   1  #!~/.wine/drive_c/Python25/python.exe 
   2  # -*- coding: utf-8 -*- 
   3   
   4  # Acknowledgements: 
   5  #  Nicolas Economou, for his command line debugger on which this is inspired. 
   6  #  http://tinyurl.com/nicolaseconomou 
   7   
   8  # Copyright (c) 2009-2014, Mario Vilas 
   9  # All rights reserved. 
  10  # 
  11  # Redistribution and use in source and binary forms, with or without 
  12  # modification, are permitted provided that the following conditions are met: 
  13  # 
  14  #     * Redistributions of source code must retain the above copyright notice, 
  15  #       this list of conditions and the following disclaimer. 
  16  #     * Redistributions in binary form must reproduce the above copyright 
  17  #       notice,this list of conditions and the following disclaimer in the 
  18  #       documentation and/or other materials provided with the distribution. 
  19  #     * Neither the name of the copyright holder nor the names of its 
  20  #       contributors may be used to endorse or promote products derived from 
  21  #       this software without specific prior written permission. 
  22  # 
  23  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  24  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  25  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  26  # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
  27  # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  28  # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  29  # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  30  # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  31  # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  32  # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  33  # POSSIBILITY OF SUCH DAMAGE. 
  34   
  35  """ 
  36  Interactive debugging console. 
  37   
  38  @group Debugging: 
  39      ConsoleDebugger 
  40   
  41  @group Exceptions: 
  42      CmdError 
  43  """ 
  44   
  45  from __future__ import with_statement 
  46   
  47  __revision__ = "$Id: interactive.py 1303 2013-12-20 12:14:40Z qvasimodo $" 
  48   
  49  __all__ = [ 'ConsoleDebugger', 'CmdError' ] 
  50   
  51  # TODO document this module with docstrings. 
  52  # TODO command to set a last error breakpoint. 
  53  # TODO command to show available plugins. 
  54   
  55  import win32 
  56  from system import System 
  57  from util import PathOperations 
  58  from event import EventHandler, NoEvent 
  59  from textio import HexInput, HexOutput, HexDump, CrashDump, DebugLog 
  60   
  61  import os 
  62  import sys 
  63  import code 
  64  import time 
  65  import warnings 
  66  import traceback 
  67   
  68  # too many variables named "cmd" to have a module by the same name :P 
  69  from cmd import Cmd 
  70   
  71  # lazy imports 
  72  readline = None 
73 74 #============================================================================== 75 76 -class DummyEvent (NoEvent):
77 "Dummy event object used internally by L{ConsoleDebugger}." 78
79 - def get_pid(self):
80 return self._pid
81
82 - def get_tid(self):
83 return self._tid
84
85 - def get_process(self):
86 return self._process
87
88 - def get_thread(self):
89 return self._thread
90
91 #============================================================================== 92 93 -class CmdError (Exception):
94 """ 95 Exception raised when a command parsing error occurs. 96 Used internally by L{ConsoleDebugger}. 97 """
98
99 #============================================================================== 100 101 -class ConsoleDebugger (Cmd, EventHandler):
102 """ 103 Interactive console debugger. 104 105 @see: L{Debug.interactive} 106 """ 107 108 #------------------------------------------------------------------------------ 109 # Class variables 110 111 # Exception to raise when an error occurs executing a command. 112 command_error_exception = CmdError 113 114 # Milliseconds to wait for debug events in the main loop. 115 dwMilliseconds = 100 116 117 # History file name. 118 history_file = '.winappdbg_history' 119 120 # Confirm before quitting? 121 confirm_quit = True 122 123 # Valid plugin name characters. 124 valid_plugin_name_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXY' \ 125 'abcdefghijklmnopqrstuvwxy' \ 126 '012345678' \ 127 '_' 128 129 # Names of the registers. 130 segment_names = ( 'cs', 'ds', 'es', 'fs', 'gs' ) 131 132 register_alias_64_to_32 = { 133 'eax':'Rax', 'ebx':'Rbx', 'ecx':'Rcx', 'edx':'Rdx', 134 'eip':'Rip', 'ebp':'Rbp', 'esp':'Rsp', 'esi':'Rsi', 'edi':'Rdi' 135 } 136 register_alias_64_to_16 = { 'ax':'Rax', 'bx':'Rbx', 'cx':'Rcx', 'dx':'Rdx' } 137 register_alias_64_to_8_low = { 'al':'Rax', 'bl':'Rbx', 'cl':'Rcx', 'dl':'Rdx' } 138 register_alias_64_to_8_high = { 'ah':'Rax', 'bh':'Rbx', 'ch':'Rcx', 'dh':'Rdx' } 139 register_alias_32_to_16 = { 'ax':'Eax', 'bx':'Ebx', 'cx':'Ecx', 'dx':'Edx' } 140 register_alias_32_to_8_low = { 'al':'Eax', 'bl':'Ebx', 'cl':'Ecx', 'dl':'Edx' } 141 register_alias_32_to_8_high = { 'ah':'Eax', 'bh':'Ebx', 'ch':'Ecx', 'dh':'Edx' } 142 143 register_aliases_full_32 = list(segment_names) 144 register_aliases_full_32.extend(register_alias_32_to_16.iterkeys()) 145 register_aliases_full_32.extend(register_alias_32_to_8_low.iterkeys()) 146 register_aliases_full_32.extend(register_alias_32_to_8_high.iterkeys()) 147 register_aliases_full_32 = tuple(register_aliases_full_32) 148 149 register_aliases_full_64 = list(segment_names) 150 register_aliases_full_64.extend(register_alias_64_to_32.iterkeys()) 151 register_aliases_full_64.extend(register_alias_64_to_16.iterkeys()) 152 register_aliases_full_64.extend(register_alias_64_to_8_low.iterkeys()) 153 register_aliases_full_64.extend(register_alias_64_to_8_high.iterkeys()) 154 register_aliases_full_64 = tuple(register_aliases_full_64) 155 156 # Names of the control flow instructions. 157 jump_instructions = ( 158 'jmp', 'jecxz', 'jcxz', 159 'ja', 'jnbe', 'jae', 'jnb', 'jb', 'jnae', 'jbe', 'jna', 'jc', 'je', 160 'jz', 'jnc', 'jne', 'jnz', 'jnp', 'jpo', 'jp', 'jpe', 'jg', 'jnle', 161 'jge', 'jnl', 'jl', 'jnge', 'jle', 'jng', 'jno', 'jns', 'jo', 'js' 162 ) 163 call_instructions = ( 'call', 'ret', 'retn' ) 164 loop_instructions = ( 'loop', 'loopz', 'loopnz', 'loope', 'loopne' ) 165 control_flow_instructions = call_instructions + loop_instructions + \ 166 jump_instructions 167 168 #------------------------------------------------------------------------------ 169 # Instance variables 170
171 - def __init__(self):
172 """ 173 Interactive console debugger. 174 175 @see: L{Debug.interactive} 176 """ 177 Cmd.__init__(self) 178 EventHandler.__init__(self) 179 180 # Quit the debugger when True. 181 self.debuggerExit = False 182 183 # Full path to the history file. 184 self.history_file_full_path = None 185 186 # Last executed command. 187 self.__lastcmd = ""
188 189 #------------------------------------------------------------------------------ 190 # Debugger 191 192 # Use this Debug object.
193 - def start_using_debugger(self, debug):
194 195 # Clear the previous Debug object. 196 self.stop_using_debugger() 197 198 # Keep the Debug object. 199 self.debug = debug 200 201 # Set ourselves as the event handler for the debugger. 202 self.prevHandler = debug.set_event_handler(self)
203 204 # Stop using the Debug object given by start_using_debugger(). 205 # Circular references must be removed, or the destructors never get called.
206 - def stop_using_debugger(self):
207 if hasattr(self, 'debug'): 208 debug = self.debug 209 debug.set_event_handler(self.prevHandler) 210 del self.prevHandler 211 del self.debug 212 return debug 213 return None
214 215 # Destroy the Debug object.
216 - def destroy_debugger(self, autodetach = True):
217 debug = self.stop_using_debugger() 218 if debug is not None: 219 if not autodetach: 220 debug.kill_all(bIgnoreExceptions=True) 221 debug.lastEvent = None 222 debug.stop() 223 del debug
224 225 @property
226 - def lastEvent(self):
227 return self.debug.lastEvent
228
229 - def set_fake_last_event(self, process):
230 if self.lastEvent is None: 231 self.debug.lastEvent = DummyEvent(self.debug) 232 self.debug.lastEvent._process = process 233 self.debug.lastEvent._thread = process.get_thread( 234 process.get_thread_ids()[0]) 235 self.debug.lastEvent._pid = process.get_pid() 236 self.debug.lastEvent._tid = self.lastEvent._thread.get_tid()
237 238 #------------------------------------------------------------------------------ 239 # Input 240 241 # TODO 242 # * try to guess breakpoints when insufficient data is given 243 # * child Cmd instances will have to be used for other prompts, for example 244 # when assembling or editing memory - it may also be a good idea to think 245 # if it's possible to make the main Cmd instance also a child, instead of 246 # the debugger itself - probably the same goes for the EventHandler, maybe 247 # it can be used as a contained object rather than a parent class. 248 249 # Join a token list into an argument string.
250 - def join_tokens(self, token_list):
251 return self.debug.system.argv_to_cmdline(token_list)
252 253 # Split an argument string into a token list.
254 - def split_tokens(self, arg, min_count = 0, max_count = None):
255 token_list = self.debug.system.cmdline_to_argv(arg) 256 if len(token_list) < min_count: 257 raise CmdError("missing parameters.") 258 if max_count and len(token_list) > max_count: 259 raise CmdError("too many parameters.") 260 return token_list
261 262 # Token is a thread ID or name.
263 - def input_thread(self, token):
264 targets = self.input_thread_list( [token] ) 265 if len(targets) == 0: 266 raise CmdError("missing thread name or ID") 267 if len(targets) > 1: 268 msg = "more than one thread with that name:\n" 269 for tid in targets: 270 msg += "\t%d\n" % tid 271 msg = msg[:-len("\n")] 272 raise CmdError(msg) 273 return targets[0]
274 275 # Token list is a list of thread IDs or names.
276 - def input_thread_list(self, token_list):
277 targets = set() 278 system = self.debug.system 279 for token in token_list: 280 try: 281 tid = self.input_integer(token) 282 if not system.has_thread(tid): 283 raise CmdError("thread not found (%d)" % tid) 284 targets.add(tid) 285 except ValueError: 286 found = set() 287 for process in system.iter_processes(): 288 found.update( system.find_threads_by_name(token) ) 289 if not found: 290 raise CmdError("thread not found (%s)" % token) 291 for thread in found: 292 targets.add( thread.get_tid() ) 293 targets = list(targets) 294 targets.sort() 295 return targets
296 297 # Token is a process ID or name.
298 - def input_process(self, token):
299 targets = self.input_process_list( [token] ) 300 if len(targets) == 0: 301 raise CmdError("missing process name or ID") 302 if len(targets) > 1: 303 msg = "more than one process with that name:\n" 304 for pid in targets: 305 msg += "\t%d\n" % pid 306 msg = msg[:-len("\n")] 307 raise CmdError(msg) 308 return targets[0]
309 310 # Token list is a list of process IDs or names.
311 - def input_process_list(self, token_list):
312 targets = set() 313 system = self.debug.system 314 for token in token_list: 315 try: 316 pid = self.input_integer(token) 317 if not system.has_process(pid): 318 raise CmdError("process not found (%d)" % pid) 319 targets.add(pid) 320 except ValueError: 321 found = system.find_processes_by_filename(token) 322 if not found: 323 raise CmdError("process not found (%s)" % token) 324 for (process, _) in found: 325 targets.add( process.get_pid() ) 326 targets = list(targets) 327 targets.sort() 328 return targets
329 330 # Token is a command line to execute.
331 - def input_command_line(self, command_line):
332 argv = self.debug.system.cmdline_to_argv(command_line) 333 if not argv: 334 raise CmdError("missing command line to execute") 335 fname = argv[0] 336 if not os.path.exists(fname): 337 try: 338 fname, _ = win32.SearchPath(None, fname, '.exe') 339 except WindowsError: 340 raise CmdError("file not found: %s" % fname) 341 argv[0] = fname 342 command_line = self.debug.system.argv_to_cmdline(argv) 343 return command_line
344 345 # Token is an integer. 346 # Only hexadecimal format is supported.
347 - def input_hexadecimal_integer(self, token):
348 return int(token, 0x10)
349 350 # Token is an integer. 351 # It can be in any supported format.
352 - def input_integer(self, token):
353 return HexInput.integer(token)
354 ## input_integer = input_hexadecimal_integer 355 356 # Token is an address. 357 # The address can be a integer, a label or a register.
358 - def input_address(self, token, pid = None, tid = None):
359 address = None 360 if self.is_register(token): 361 if tid is None: 362 if self.lastEvent is None or pid != self.lastEvent.get_pid(): 363 msg = "can't resolve register (%s) for unknown thread" 364 raise CmdError(msg % token) 365 tid = self.lastEvent.get_tid() 366 address = self.input_register(token, tid) 367 if address is None: 368 try: 369 address = self.input_hexadecimal_integer(token) 370 except ValueError: 371 if pid is None: 372 if self.lastEvent is None: 373 raise CmdError("no current process set") 374 process = self.lastEvent.get_process() 375 elif self.lastEvent is not None and pid == self.lastEvent.get_pid(): 376 process = self.lastEvent.get_process() 377 else: 378 try: 379 process = self.debug.system.get_process(pid) 380 except KeyError: 381 raise CmdError("process not found (%d)" % pid) 382 try: 383 address = process.resolve_label(token) 384 except Exception, e: 385 raise CmdError("unknown address (%s)" % token) 386 return address
387 388 # Token is an address range, or a single address. 389 # The addresses can be integers, labels or registers.
390 - def input_address_range(self, token_list, pid = None, tid = None):
391 if len(token_list) == 2: 392 token_1, token_2 = token_list 393 address = self.input_address(token_1, pid, tid) 394 try: 395 size = self.input_integer(token_2) 396 except ValueError: 397 raise CmdError("bad address range: %s %s" % (token_1, token_2)) 398 elif len(token_list) == 1: 399 token = token_list[0] 400 if '-' in token: 401 try: 402 token_1, token_2 = token.split('-') 403 except Exception: 404 raise CmdError("bad address range: %s" % token) 405 address = self.input_address(token_1, pid, tid) 406 size = self.input_address(token_2, pid, tid) - address 407 else: 408 address = self.input_address(token, pid, tid) 409 size = None 410 return address, size
411 412 # XXX TODO 413 # Support non-integer registers here.
414 - def is_register(self, token):
415 if win32.arch == 'i386': 416 if token in self.register_aliases_full_32: 417 return True 418 token = token.title() 419 for (name, typ) in win32.CONTEXT._fields_: 420 if name == token: 421 return win32.sizeof(typ) == win32.sizeof(win32.DWORD) 422 elif win32.arch == 'amd64': 423 if token in self.register_aliases_full_64: 424 return True 425 token = token.title() 426 for (name, typ) in win32.CONTEXT._fields_: 427 if name == token: 428 return win32.sizeof(typ) == win32.sizeof(win32.DWORD64) 429 return False
430 431 # The token is a register name. 432 # Returns None if no register name is matched.
433 - def input_register(self, token, tid = None):
434 if tid is None: 435 if self.lastEvent is None: 436 raise CmdError("no current process set") 437 thread = self.lastEvent.get_thread() 438 else: 439 thread = self.debug.system.get_thread(tid) 440 ctx = thread.get_context() 441 442 token = token.lower() 443 title = token.title() 444 445 if title in ctx: 446 return ctx.get(title) # eax -> Eax 447 448 if ctx.arch == 'i386': 449 450 if token in self.segment_names: 451 return ctx.get( 'Seg%s' % title ) # cs -> SegCs 452 453 if token in self.register_alias_32_to_16.keys(): 454 return ctx.get( self.register_alias_32_to_16[token] ) & 0xFFFF 455 456 if token in self.register_alias_32_to_8_low.keys(): 457 return ctx.get( self.register_alias_32_to_8_low[token] ) & 0xFF 458 459 if token in self.register_alias_32_to_8_high.keys(): 460 return (ctx.get( self.register_alias_32_to_8_high[token] ) & 0xFF00) >> 8 461 462 elif ctx.arch == 'amd64': 463 464 if token in self.segment_names: 465 return ctx.get( 'Seg%s' % title ) # cs -> SegCs 466 467 if token in self.register_alias_64_to_32.keys(): 468 return ctx.get( self.register_alias_64_to_32[token] ) & 0xFFFFFFFF 469 470 if token in self.register_alias_64_to_16.keys(): 471 return ctx.get( self.register_alias_64_to_16[token] ) & 0xFFFF 472 473 if token in self.register_alias_64_to_8_low.keys(): 474 return ctx.get( self.register_alias_64_to_8_low[token] ) & 0xFF 475 476 if token in self.register_alias_64_to_8_high.keys(): 477 return (ctx.get( self.register_alias_64_to_8_high[token] ) & 0xFF00) >> 8 478 479 return None
480 481 # Token list contains an address or address range. 482 # The prefix is also parsed looking for process and thread IDs.
483 - def input_full_address_range(self, token_list):
484 pid, tid = self.get_process_and_thread_ids_from_prefix() 485 address, size = self.input_address_range(token_list, pid, tid) 486 return pid, tid, address, size
487 488 # Token list contains a breakpoint.
489 - def input_breakpoint(self, token_list):
490 pid, tid, address, size = self.input_full_address_range(token_list) 491 if not self.debug.is_debugee(pid): 492 raise CmdError("target process is not being debugged") 493 return pid, tid, address, size
494 495 # Token list contains a memory address, and optional size and process. 496 # Sets the results as the default for the next display command.
497 - def input_display(self, token_list, default_size = 64):
498 pid, tid, address, size = self.input_full_address_range(token_list) 499 if not size: 500 size = default_size 501 next_address = HexOutput.integer(address + size) 502 self.default_display_target = next_address 503 return pid, tid, address, size
504 505 #------------------------------------------------------------------------------ 506 # Output 507 508 # Tell the user a module was loaded.
509 - def print_module_load(self, event):
510 mod = event.get_module() 511 base = mod.get_base() 512 name = mod.get_filename() 513 if not name: 514 name = '' 515 msg = "Loaded module (%s) %s" 516 msg = msg % (HexDump.address(base), name) 517 print msg
518 519 # Tell the user a module was unloaded.
520 - def print_module_unload(self, event):
521 mod = event.get_module() 522 base = mod.get_base() 523 name = mod.get_filename() 524 if not name: 525 name = '' 526 msg = "Unloaded module (%s) %s" 527 msg = msg % (HexDump.address(base), name) 528 print msg
529 530 # Tell the user a process was started.
531 - def print_process_start(self, event):
532 pid = event.get_pid() 533 start = event.get_start_address() 534 if start: 535 start = HexOutput.address(start) 536 print "Started process %d at %s" % (pid, start) 537 else: 538 print "Attached to process %d" % pid
539 540 # Tell the user a thread was started.
541 - def print_thread_start(self, event):
542 tid = event.get_tid() 543 start = event.get_start_address() 544 if start: 545 with warnings.catch_warnings(): 546 warnings.simplefilter("ignore") 547 start = event.get_process().get_label_at_address(start) 548 print "Started thread %d at %s" % (tid, start) 549 else: 550 print "Attached to thread %d" % tid
551 552 # Tell the user a process has finished.
553 - def print_process_end(self, event):
554 pid = event.get_pid() 555 code = event.get_exit_code() 556 print "Process %d terminated, exit code %d" % (pid, code)
557 558 # Tell the user a thread has finished.
559 - def print_thread_end(self, event):
560 tid = event.get_tid() 561 code = event.get_exit_code() 562 print "Thread %d terminated, exit code %d" % (tid, code)
563 564 # Print debug strings.
565 - def print_debug_string(self, event):
566 tid = event.get_tid() 567 string = event.get_debug_string() 568 print "Thread %d says: %r" % (tid, string)
569 570 # Inform the user of any other debugging event.
571 - def print_event(self, event):
572 code = HexDump.integer( event.get_event_code() ) 573 name = event.get_event_name() 574 desc = event.get_event_description() 575 if code in desc: 576 print 577 print "%s: %s" % (name, desc) 578 else: 579 print 580 print "%s (%s): %s" % (name, code, desc) 581 self.print_event_location(event)
582 583 # Stop on exceptions and prompt for commands.
584 - def print_exception(self, event):
585 address = HexDump.address( event.get_exception_address() ) 586 code = HexDump.integer( event.get_exception_code() ) 587 desc = event.get_exception_description() 588 if event.is_first_chance(): 589 chance = 'first' 590 else: 591 chance = 'second' 592 if code in desc: 593 msg = "%s at address %s (%s chance)" % (desc, address, chance) 594 else: 595 msg = "%s (%s) at address %s (%s chance)" % (desc, code, address, chance) 596 print 597 print msg 598 self.print_event_location(event)
599 600 # Show the current location in the code.
601 - def print_event_location(self, event):
605 606 # Show the current location in the code.
607 - def print_breakpoint_location(self, event):
612 613 # Show the current location in any process and thread.
614 - def print_current_location(self, process = None, thread = None, pc = None):
615 if not process: 616 if self.lastEvent is None: 617 raise CmdError("no current process set") 618 process = self.lastEvent.get_process() 619 if not thread: 620 if self.lastEvent is None: 621 raise CmdError("no current process set") 622 thread = self.lastEvent.get_thread() 623 thread.suspend() 624 try: 625 if pc is None: 626 pc = thread.get_pc() 627 ctx = thread.get_context() 628 finally: 629 thread.resume() 630 label = process.get_label_at_address(pc) 631 try: 632 disasm = process.disassemble(pc, 15) 633 except WindowsError: 634 disasm = None 635 except NotImplementedError: 636 disasm = None 637 print 638 print CrashDump.dump_registers(ctx), 639 print "%s:" % label 640 if disasm: 641 print CrashDump.dump_code_line(disasm[0], pc, bShowDump = True) 642 else: 643 try: 644 data = process.peek(pc, 15) 645 except Exception: 646 data = None 647 if data: 648 print '%s: %s' % (HexDump.address(pc), HexDump.hexblock_byte(data)) 649 else: 650 print '%s: ???' % HexDump.address(pc)
651 652 # Display memory contents using a given method.
653 - def print_memory_display(self, arg, method):
654 if not arg: 655 arg = self.default_display_target 656 token_list = self.split_tokens(arg, 1, 2) 657 pid, tid, address, size = self.input_display(token_list) 658 label = self.get_process(pid).get_label_at_address(address) 659 data = self.read_memory(address, size, pid) 660 if data: 661 print "%s:" % label 662 print method(data, address),
663 664 #------------------------------------------------------------------------------ 665 # Debugging 666 667 # Get the process ID from the prefix or the last event.
668 - def get_process_id_from_prefix(self):
669 if self.cmdprefix: 670 pid = self.input_process(self.cmdprefix) 671 else: 672 if self.lastEvent is None: 673 raise CmdError("no current process set") 674 pid = self.lastEvent.get_pid() 675 return pid
676 677 # Get the thread ID from the prefix or the last event.
678 - def get_thread_id_from_prefix(self):
679 if self.cmdprefix: 680 tid = self.input_thread(self.cmdprefix) 681 else: 682 if self.lastEvent is None: 683 raise CmdError("no current process set") 684 tid = self.lastEvent.get_tid() 685 return tid
686 687 # Get the process from the prefix or the last event.
688 - def get_process_from_prefix(self):
689 pid = self.get_process_id_from_prefix() 690 return self.get_process(pid)
691 692 # Get the thread from the prefix or the last event.
693 - def get_thread_from_prefix(self):
694 tid = self.get_thread_id_from_prefix() 695 return self.get_thread(tid)
696 697 # Get the process and thread IDs from the prefix or the last event.
699 if self.cmdprefix: 700 try: 701 pid = self.input_process(self.cmdprefix) 702 tid = None 703 except CmdError: 704 try: 705 tid = self.input_thread(self.cmdprefix) 706 pid = self.debug.system.get_thread(tid).get_pid() 707 except CmdError: 708 msg = "unknown process or thread (%s)" % self.cmdprefix 709 raise CmdError(msg) 710 else: 711 if self.lastEvent is None: 712 raise CmdError("no current process set") 713 pid = self.lastEvent.get_pid() 714 tid = self.lastEvent.get_tid() 715 return pid, tid
716 717 # Get the process and thread from the prefix or the last event. 723 724 # Get the process object.
725 - def get_process(self, pid = None):
726 if pid is None: 727 if self.lastEvent is None: 728 raise CmdError("no current process set") 729 process = self.lastEvent.get_process() 730 elif self.lastEvent is not None and pid == self.lastEvent.get_pid(): 731 process = self.lastEvent.get_process() 732 else: 733 try: 734 process = self.debug.system.get_process(pid) 735 except KeyError: 736 raise CmdError("process not found (%d)" % pid) 737 return process
738 739 # Get the thread object.
740 - def get_thread(self, tid = None):
741 if tid is None: 742 if self.lastEvent is None: 743 raise CmdError("no current process set") 744 thread = self.lastEvent.get_thread() 745 elif self.lastEvent is not None and tid == self.lastEvent.get_tid(): 746 thread = self.lastEvent.get_thread() 747 else: 748 try: 749 thread = self.debug.system.get_thread(tid) 750 except KeyError: 751 raise CmdError("thread not found (%d)" % tid) 752 return thread
753 754 # Read the process memory.
755 - def read_memory(self, address, size, pid = None):
756 process = self.get_process(pid) 757 try: 758 data = process.peek(address, size) 759 except WindowsError, e: 760 orig_address = HexOutput.integer(address) 761 next_address = HexOutput.integer(address + size) 762 msg = "error reading process %d, from %s to %s (%d bytes)" 763 msg = msg % (pid, orig_address, next_address, size) 764 raise CmdError(msg) 765 return data
766 767 # Write the process memory.
768 - def write_memory(self, address, data, pid = None):
769 process = self.get_process(pid) 770 try: 771 process.write(address, data) 772 except WindowsError, e: 773 size = len(data) 774 orig_address = HexOutput.integer(address) 775 next_address = HexOutput.integer(address + size) 776 msg = "error reading process %d, from %s to %s (%d bytes)" 777 msg = msg % (pid, orig_address, next_address, size) 778 raise CmdError(msg)
779 780 # Change a register value.
781 - def change_register(self, register, value, tid = None):
782 783 # Get the thread. 784 if tid is None: 785 if self.lastEvent is None: 786 raise CmdError("no current process set") 787 thread = self.lastEvent.get_thread() 788 else: 789 try: 790 thread = self.debug.system.get_thread(tid) 791 except KeyError: 792 raise CmdError("thread not found (%d)" % tid) 793 794 # Convert the value to integer type. 795 try: 796 value = self.input_integer(value) 797 except ValueError: 798 pid = thread.get_pid() 799 value = self.input_address(value, pid, tid) 800 801 # Suspend the thread. 802 # The finally clause ensures the thread is resumed before returning. 803 thread.suspend() 804 try: 805 806 # Get the current context. 807 ctx = thread.get_context() 808 809 # Register name matching is case insensitive. 810 register = register.lower() 811 812 # Integer 32 bits registers. 813 if register in self.register_names: 814 register = register.title() # eax -> Eax 815 816 # Segment (16 bit) registers. 817 if register in self.segment_names: 818 register = 'Seg%s' % register.title() # cs -> SegCs 819 value = value & 0x0000FFFF 820 821 # Integer 16 bits registers. 822 if register in self.register_alias_16.keys(): 823 register = self.register_alias_16[register] 824 previous = ctx.get(register) & 0xFFFF0000 825 value = (value & 0x0000FFFF) | previous 826 827 # Integer 8 bits registers (low part). 828 if register in self.register_alias_8_low.keys(): 829 register = self.register_alias_8_low[register] 830 previous = ctx.get(register) % 0xFFFFFF00 831 value = (value & 0x000000FF) | previous 832 833 # Integer 8 bits registers (high part). 834 if register in self.register_alias_8_high.keys(): 835 register = self.register_alias_8_high[register] 836 previous = ctx.get(register) % 0xFFFF00FF 837 value = ((value & 0x000000FF) << 8) | previous 838 839 # Set the new context. 840 ctx.__setitem__(register, value) 841 thread.set_context(ctx) 842 843 # Resume the thread. 844 finally: 845 thread.resume()
846 847 # Very crude way to find data within the process memory. 848 # TODO: Perhaps pfind.py can be integrated here instead.
849 - def find_in_memory(self, query, process):
850 for mbi in process.get_memory_map(): 851 if mbi.State != win32.MEM_COMMIT or mbi.Protect & win32.PAGE_GUARD: 852 continue 853 address = mbi.BaseAddress 854 size = mbi.RegionSize 855 try: 856 data = process.read(address, size) 857 except WindowsError: 858 msg = "*** Warning: read error at address %s" 859 msg = msg % HexDump.address(address) 860 print msg 861 width = min(len(query), 16) 862 p = data.find(query) 863 while p >= 0: 864 q = p + len(query) 865 d = data[ p : min(q, p + width) ] 866 h = HexDump.hexline(d, width = width) 867 a = HexDump.address(address + p) 868 print "%s: %s" % (a, h) 869 p = data.find(query, q)
870 871 # Kill a process.
872 - def kill_process(self, pid):
873 process = self.debug.system.get_process(pid) 874 try: 875 process.kill() 876 if self.debug.is_debugee(pid): 877 self.debug.detach(pid) 878 print "Killed process (%d)" % pid 879 except Exception, e: 880 print "Error trying to kill process (%d)" % pid
881 882 # Kill a thread.
883 - def kill_thread(self, tid):
884 thread = self.debug.system.get_thread(tid) 885 try: 886 thread.kill() 887 process = thread.get_process() 888 pid = process.get_pid() 889 if self.debug.is_debugee(pid) and not process.is_alive(): 890 self.debug.detach(pid) 891 print "Killed thread (%d)" % tid 892 except Exception, e: 893 print "Error trying to kill thread (%d)" % tid
894 895 #------------------------------------------------------------------------------ 896 # Command prompt input 897 898 # Prompt the user for commands.
899 - def prompt_user(self):
900 while not self.debuggerExit: 901 try: 902 self.cmdloop() 903 break 904 except CmdError, e: 905 print "*** Error: %s" % str(e) 906 except Exception, e: 907 traceback.print_exc(e)
908 ## self.debuggerExit = True 909 910 # Prompt the user for a YES/NO kind of question.
911 - def ask_user(self, msg, prompt = "Are you sure? (y/N): "):
912 print msg 913 answer = raw_input(prompt) 914 answer = answer.strip()[:1].lower() 915 return answer == 'y'
916 917 # Autocomplete the given command when not ambiguous. 918 # Convert it to lowercase (so commands are seen as case insensitive).
919 - def autocomplete(self, cmd):
920 cmd = cmd.lower() 921 completed = self.completenames(cmd) 922 if len(completed) == 1: 923 cmd = completed[0] 924 return cmd
925 926 # Get the help text for the given list of command methods. 927 # Note it's NOT a list of commands, but a list of actual method names. 928 # Each line of text is stripped and all lines are sorted. 929 # Repeated text lines are removed. 930 # Returns a single, possibly multiline, string.
931 - def get_help(self, commands):
932 msg = set() 933 for name in commands: 934 if name != 'do_help': 935 try: 936 doc = getattr(self, name).__doc__.split('\n') 937 except Exception: 938 return ( "No help available when Python" 939 " is run with the -OO switch." ) 940 for x in doc: 941 x = x.strip() 942 if x: 943 msg.add(' %s' % x) 944 msg = list(msg) 945 msg.sort() 946 msg = '\n'.join(msg) 947 return msg
948 949 # Parse the prefix and remove it from the command line.
950 - def split_prefix(self, line):
951 prefix = None 952 if line.startswith('~'): 953 pos = line.find(' ') 954 if pos == 1: 955 pos = line.find(' ', pos + 1) 956 if not pos < 0: 957 prefix = line[ 1 : pos ].strip() 958 line = line[ pos : ].strip() 959 return prefix, line
960 961 #------------------------------------------------------------------------------ 962 # Cmd() hacks 963 964 # Header for help page. 965 doc_header = 'Available commands (type help * or help <command>)' 966 967 ## # Read and write directly to stdin and stdout. 968 ## # This prevents the use of raw_input and print. 969 ## use_rawinput = False 970 971 @property
972 - def prompt(self):
973 if self.lastEvent: 974 pid = self.lastEvent.get_pid() 975 tid = self.lastEvent.get_tid() 976 if self.debug.is_debugee(pid): 977 ## return '~%d(%d)> ' % (tid, pid) 978 return '%d:%d> ' % (pid, tid) 979 return '> '
980 981 # Return a sorted list of method names. 982 # Only returns the methods that implement commands.
983 - def get_names(self):
984 names = Cmd.get_names(self) 985 names = [ x for x in set(names) if x.startswith('do_') ] 986 names.sort() 987 return names
988 989 # Automatically autocomplete commands, even if Tab wasn't pressed. 990 # The prefix is removed from the line and stored in self.cmdprefix. 991 # Also implement the commands that consist of a symbol character.
992 - def parseline(self, line):
993 self.cmdprefix, line = self.split_prefix(line) 994 line = line.strip() 995 if line: 996 if line[0] == '.': 997 line = 'plugin ' + line[1:] 998 elif line[0] == '#': 999 line = 'python ' + line[1:] 1000 cmd, arg, line = Cmd.parseline(self, line) 1001 if cmd: 1002 cmd = self.autocomplete(cmd) 1003 return cmd, arg, line
1004 1005 ## # Don't repeat the last executed command. 1006 ## def emptyline(self): 1007 ## pass 1008 1009 # Reset the defaults for some commands.
1010 - def preloop(self):
1011 self.default_disasm_target = 'eip' 1012 self.default_display_target = 'eip' 1013 self.last_display_command = self.do_db
1014 1015 # Put the prefix back in the command line.
1016 - def get_lastcmd(self):
1017 return self.__lastcmd
1018 - def set_lastcmd(self, lastcmd):
1019 if self.cmdprefix: 1020 lastcmd = '~%s %s' % (self.cmdprefix, lastcmd) 1021 self.__lastcmd = lastcmd
1022 lastcmd = property(get_lastcmd, set_lastcmd) 1023 1024 # Quit the command prompt if the debuggerExit flag is on.
1025 - def postcmd(self, stop, line):
1026 return stop or self.debuggerExit
1027 1028 #------------------------------------------------------------------------------ 1029 # Commands 1030 1031 # Each command contains a docstring with it's help text. 1032 # The help text consist of independent text lines, 1033 # where each line shows a command and it's parameters. 1034 # Each command method has the help message for itself and all it's aliases. 1035 # Only the docstring for the "help" command is shown as-is. 1036 1037 # NOTE: Command methods MUST be all lowercase! 1038 1039 # Extended help command.
1040 - def do_help(self, arg):
1041 """ 1042 ? - show the list of available commands 1043 ? * - show help for all commands 1044 ? <command> [command...] - show help for the given command(s) 1045 help - show the list of available commands 1046 help * - show help for all commands 1047 help <command> [command...] - show help for the given command(s) 1048 """ 1049 if not arg: 1050 Cmd.do_help(self, arg) 1051 elif arg in ('?', 'help'): 1052 # An easter egg :) 1053 print " Help! I need somebody..." 1054 print " Help! Not just anybody..." 1055 print " Help! You know, I need someone..." 1056 print " Heeelp!" 1057 else: 1058 if arg == '*': 1059 commands = self.get_names() 1060 commands = [ x for x in commands if x.startswith('do_') ] 1061 else: 1062 commands = set() 1063 for x in arg.split(' '): 1064 x = x.strip() 1065 if x: 1066 for n in self.completenames(x): 1067 commands.add( 'do_%s' % n ) 1068 commands = list(commands) 1069 commands.sort() 1070 print self.get_help(commands)
1071
1072 - def do_shell(self, arg):
1073 """ 1074 ! - spawn a system shell 1075 shell - spawn a system shell 1076 ! <command> [arguments...] - execute a single shell command 1077 shell <command> [arguments...] - execute a single shell command 1078 """ 1079 if self.cmdprefix: 1080 raise CmdError("prefix not allowed") 1081 1082 # Try to use the environment to locate cmd.exe. 1083 # If not found, it's usually OK to just use the filename, 1084 # since cmd.exe is one of those "magic" programs that 1085 # can be automatically found by CreateProcess. 1086 shell = os.getenv('ComSpec', 'cmd.exe') 1087 1088 # When given a command, run it and return. 1089 # When no command is given, spawn a shell. 1090 if arg: 1091 arg = '%s /c %s' % (shell, arg) 1092 else: 1093 arg = shell 1094 process = self.debug.system.start_process(arg, bConsole = True) 1095 process.wait()
1096 1097 # This hack fixes a bug in Python, the interpreter console is closing the 1098 # stdin pipe when calling the exit() function (Ctrl+Z seems to work fine).
1099 - class _PythonExit(object):
1100 - def __repr__(self):
1101 return "Use exit() or Ctrl-Z plus Return to exit"
1102 - def __call__(self):
1103 raise SystemExit()
1104 _python_exit = _PythonExit() 1105 1106 # Spawns a Python shell with some handy local variables and the winappdbg 1107 # module already imported. Also the console banner is improved.
1108 - def _spawn_python_shell(self, arg):
1109 import winappdbg 1110 banner = ('Python %s on %s\nType "help", "copyright", ' 1111 '"credits" or "license" for more information.\n') 1112 platform = winappdbg.version.lower() 1113 platform = 'WinAppDbg %s' % platform 1114 banner = banner % (sys.version, platform) 1115 local = {} 1116 local.update(__builtins__) 1117 local.update({ 1118 '__name__' : '__console__', 1119 '__doc__' : None, 1120 'exit' : self._python_exit, 1121 'self' : self, 1122 'arg' : arg, 1123 'winappdbg' : winappdbg, 1124 }) 1125 try: 1126 code.interact(banner=banner, local=local) 1127 except SystemExit: 1128 # We need to catch it so it doesn't kill our program. 1129 pass
1130
1131 - def do_python(self, arg):
1132 """ 1133 # - spawn a python interpreter 1134 python - spawn a python interpreter 1135 # <statement> - execute a single python statement 1136 python <statement> - execute a single python statement 1137 """ 1138 if self.cmdprefix: 1139 raise CmdError("prefix not allowed") 1140 1141 # When given a Python statement, execute it directly. 1142 if arg: 1143 try: 1144 exec arg in globals(), locals() 1145 except Exception, e: 1146 traceback.print_exc(e) 1147 1148 # When no statement is given, spawn a Python interpreter. 1149 else: 1150 try: 1151 self._spawn_python_shell(arg) 1152 except Exception, e: 1153 raise CmdError( 1154 "unhandled exception when running Python console: %s" % e)
1155 1156 # The plugins interface is quite simple. 1157 # 1158 # Just place a .py file with the plugin name in the "plugins" folder, 1159 # for example "do_example.py" would implement the "example" command. 1160 # 1161 # The plugin must have a function named "do", which implements the 1162 # command functionality exactly like the do_* methods of Cmd instances. 1163 # 1164 # The docstring for the "do" function will be parsed exactly like 1165 # one of the debugger's commands - that is, each line is treated 1166 # independently. 1167 #
1168 - def do_plugin(self, arg):
1169 """ 1170 [~prefix] .<name> [arguments] - run a plugin command 1171 [~prefix] plugin <name> [arguments] - run a plugin command 1172 """ 1173 pos = arg.find(' ') 1174 if pos < 0: 1175 name = arg 1176 arg = '' 1177 else: 1178 name = arg[:pos] 1179 arg = arg[pos:].strip() 1180 if not name: 1181 raise CmdError("missing plugin name") 1182 for c in name: 1183 if c not in self.valid_plugin_name_chars: 1184 raise CmdError("invalid plugin name: %r" % name) 1185 name = 'winappdbg.plugins.do_%s' % name 1186 try: 1187 plugin = __import__(name) 1188 components = name.split('.') 1189 for comp in components[1:]: 1190 plugin = getattr(plugin, comp) 1191 reload(plugin) 1192 except ImportError: 1193 raise CmdError("plugin not found: %s" % name) 1194 try: 1195 return plugin.do(self, arg) 1196 except CmdError: 1197 raise 1198 except Exception, e: 1199 ## traceback.print_exc(e) # XXX DEBUG 1200 raise CmdError("unhandled exception in plugin: %s" % e)
1201
1202 - def do_quit(self, arg):
1203 """ 1204 quit - close the debugging session 1205 q - close the debugging session 1206 """ 1207 if self.cmdprefix: 1208 raise CmdError("prefix not allowed") 1209 if arg: 1210 raise CmdError("too many arguments") 1211 if self.confirm_quit: 1212 count = self.debug.get_debugee_count() 1213 if count > 0: 1214 if count == 1: 1215 msg = "There's a program still running." 1216 else: 1217 msg = "There are %s programs still running." % count 1218 if not self.ask_user(msg): 1219 return False 1220 self.debuggerExit = True 1221 return True
1222 1223 do_q = do_quit 1224
1225 - def do_attach(self, arg):
1226 """ 1227 attach <target> [target...] - attach to the given process(es) 1228 """ 1229 if self.cmdprefix: 1230 raise CmdError("prefix not allowed") 1231 targets = self.input_process_list( self.split_tokens(arg, 1) ) 1232 if not targets: 1233 print "Error: missing parameters" 1234 else: 1235 debug = self.debug 1236 for pid in targets: 1237 try: 1238 debug.attach(pid) 1239 print "Attached to process (%d)" % pid 1240 except Exception, e: 1241 print "Error: can't attach to process (%d)" % pid
1242
1243 - def do_detach(self, arg):
1244 """ 1245 [~process] detach - detach from the current process 1246 detach - detach from the current process 1247 detach <target> [target...] - detach from the given process(es) 1248 """ 1249 debug = self.debug 1250 token_list = self.split_tokens(arg) 1251 if self.cmdprefix: 1252 token_list.insert(0, self.cmdprefix) 1253 targets = self.input_process_list(token_list) 1254 if not targets: 1255 if self.lastEvent is None: 1256 raise CmdError("no current process set") 1257 targets = [ self.lastEvent.get_pid() ] 1258 for pid in targets: 1259 try: 1260 debug.detach(pid) 1261 print "Detached from process (%d)" % pid 1262 except Exception, e: 1263 print "Error: can't detach from process (%d)" % pid
1264
1265 - def do_windowed(self, arg):
1266 """ 1267 windowed <target> [arguments...] - run a windowed program for debugging 1268 """ 1269 if self.cmdprefix: 1270 raise CmdError("prefix not allowed") 1271 cmdline = self.input_command_line(arg) 1272 try: 1273 process = self.debug.execl(arg, 1274 bConsole = False, 1275 bFollow = self.options.follow) 1276 print "Spawned process (%d)" % process.get_pid() 1277 except Exception, e: 1278 raise CmdError("can't execute") 1279 self.set_fake_last_event(process)
1280
1281 - def do_console(self, arg):
1282 """ 1283 console <target> [arguments...] - run a console program for debugging 1284 """ 1285 if self.cmdprefix: 1286 raise CmdError("prefix not allowed") 1287 cmdline = self.input_command_line(arg) 1288 try: 1289 process = self.debug.execl(arg, 1290 bConsole = True, 1291 bFollow = self.options.follow) 1292 print "Spawned process (%d)" % process.get_pid() 1293 except Exception, e: 1294 raise CmdError("can't execute") 1295 self.set_fake_last_event(process)
1296
1297 - def do_continue(self, arg):
1298 """ 1299 continue - continue execution 1300 g - continue execution 1301 go - continue execution 1302 """ 1303 if self.cmdprefix: 1304 raise CmdError("prefix not allowed") 1305 if arg: 1306 raise CmdError("too many arguments") 1307 if self.debug.get_debugee_count() > 0: 1308 return True
1309 1310 do_g = do_continue 1311 do_go = do_continue 1312
1313 - def do_gh(self, arg):
1314 """ 1315 gh - go with exception handled 1316 """ 1317 if self.cmdprefix: 1318 raise CmdError("prefix not allowed") 1319 if arg: 1320 raise CmdError("too many arguments") 1321 if self.lastEvent: 1322 self.lastEvent.continueStatus = win32.DBG_EXCEPTION_HANDLED 1323 return self.do_go(arg)
1324
1325 - def do_gn(self, arg):
1326 """ 1327 gn - go with exception not handled 1328 """ 1329 if self.cmdprefix: 1330 raise CmdError("prefix not allowed") 1331 if arg: 1332 raise CmdError("too many arguments") 1333 if self.lastEvent: 1334 self.lastEvent.continueStatus = win32.DBG_EXCEPTION_NOT_HANDLED 1335 return self.do_go(arg)
1336
1337 - def do_refresh(self, arg):
1338 """ 1339 refresh - refresh the list of running processes and threads 1340 [~process] refresh - refresh the list of running threads 1341 """ 1342 if arg: 1343 raise CmdError("too many arguments") 1344 if self.cmdprefix: 1345 process = self.get_process_from_prefix() 1346 process.scan() 1347 else: 1348 self.debug.system.scan()
1349
1350 - def do_processlist(self, arg):
1351 """ 1352 pl - show the processes being debugged 1353 processlist - show the processes being debugged 1354 """ 1355 if self.cmdprefix: 1356 raise CmdError("prefix not allowed") 1357 if arg: 1358 raise CmdError("too many arguments") 1359 system = self.debug.system 1360 pid_list = self.debug.get_debugee_pids() 1361 if pid_list: 1362 print "Process ID File name" 1363 for pid in pid_list: 1364 if pid == 0: 1365 filename = "System Idle Process" 1366 elif pid == 4: 1367 filename = "System" 1368 else: 1369 filename = system.get_process(pid).get_filename() 1370 filename = PathOperations.pathname_to_filename(filename) 1371 print "%-12d %s" % (pid, filename)
1372 1373 do_pl = do_processlist 1374
1375 - def do_threadlist(self, arg):
1376 """ 1377 tl - show the threads being debugged 1378 threadlist - show the threads being debugged 1379 """ 1380 if arg: 1381 raise CmdError("too many arguments") 1382 if self.cmdprefix: 1383 process = self.get_process_from_prefix() 1384 for thread in process.iter_threads(): 1385 tid = thread.get_tid() 1386 name = thread.get_name() 1387 print "%-12d %s" % (tid, name) 1388 else: 1389 system = self.debug.system 1390 pid_list = self.debug.get_debugee_pids() 1391 if pid_list: 1392 print "Thread ID Thread name" 1393 for pid in pid_list: 1394 process = system.get_process(pid) 1395 for thread in process.iter_threads(): 1396 tid = thread.get_tid() 1397 name = thread.get_name() 1398 print "%-12d %s" % (tid, name)
1399 1400 do_tl = do_threadlist 1401
1402 - def do_kill(self, arg):
1403 """ 1404 [~process] kill - kill a process 1405 [~thread] kill - kill a thread 1406 kill - kill the current process 1407 kill * - kill all debugged processes 1408 kill <processes and/or threads...> - kill the given processes and threads 1409 """ 1410 if arg: 1411 if arg == '*': 1412 target_pids = self.debug.get_debugee_pids() 1413 target_tids = list() 1414 else: 1415 target_pids = set() 1416 target_tids = set() 1417 if self.cmdprefix: 1418 pid, tid = self.get_process_and_thread_ids_from_prefix() 1419 if tid is None: 1420 target_tids.add(tid) 1421 else: 1422 target_pids.add(pid) 1423 for token in self.split_tokens(arg): 1424 try: 1425 pid = self.input_process(token) 1426 target_pids.add(pid) 1427 except CmdError: 1428 try: 1429 tid = self.input_process(token) 1430 target_pids.add(pid) 1431 except CmdError: 1432 msg = "unknown process or thread (%s)" % token 1433 raise CmdError(msg) 1434 target_pids = list(target_pids) 1435 target_tids = list(target_tids) 1436 target_pids.sort() 1437 target_tids.sort() 1438 msg = "You are about to kill %d processes and %d threads." 1439 msg = msg % ( len(target_pids), len(target_tids) ) 1440 if self.ask_user(msg): 1441 for pid in target_pids: 1442 self.kill_process(pid) 1443 for tid in target_tids: 1444 self.kill_thread(tid) 1445 else: 1446 if self.cmdprefix: 1447 pid, tid = self.get_process_and_thread_ids_from_prefix() 1448 if tid is None: 1449 if self.lastEvent is not None and pid == self.lastEvent.get_pid(): 1450 msg = "You are about to kill the current process." 1451 else: 1452 msg = "You are about to kill process %d." % pid 1453 if self.ask_user(msg): 1454 self.kill_process(pid) 1455 else: 1456 if self.lastEvent is not None and tid == self.lastEvent.get_tid(): 1457 msg = "You are about to kill the current thread." 1458 else: 1459 msg = "You are about to kill thread %d." % tid 1460 if self.ask_user(msg): 1461 self.kill_thread(tid) 1462 else: 1463 if self.lastEvent is None: 1464 raise CmdError("no current process set") 1465 pid = self.lastEvent.get_pid() 1466 if self.ask_user("You are about to kill the current process."): 1467 self.kill_process(pid)
1468 1469 # TODO: create hidden threads using undocumented API calls.
1470 - def do_modload(self, arg):
1471 """ 1472 [~process] modload <filename.dll> - load a DLL module 1473 """ 1474 filename = self.split_tokens(arg, 1, 1)[0] 1475 process = self.get_process_from_prefix() 1476 try: 1477 process.inject_dll(filename, bWait=False) 1478 except RuntimeError: 1479 print "Can't inject module: %r" % filename
1480 1481 # TODO: modunload 1482
1483 - def do_stack(self, arg):
1484 """ 1485 [~thread] k - show the stack trace 1486 [~thread] stack - show the stack trace 1487 """ 1488 if arg: # XXX TODO add depth parameter 1489 raise CmdError("too many arguments") 1490 pid, tid = self.get_process_and_thread_ids_from_prefix() 1491 process = self.get_process(pid) 1492 thread = process.get_thread(tid) 1493 try: 1494 stack_trace = thread.get_stack_trace_with_labels() 1495 if stack_trace: 1496 print CrashDump.dump_stack_trace_with_labels(stack_trace), 1497 else: 1498 print "No stack trace available for thread (%d)" % tid 1499 except WindowsError, e: 1500 print "Can't get stack trace for thread (%d)" % tid
1501 1502 do_k = do_stack 1503
1504 - def do_break(self, arg):
1505 """ 1506 break - force a debug break in all debugees 1507 break <process> [process...] - force a debug break 1508 """ 1509 debug = self.debug 1510 system = debug.system 1511 targets = self.input_process_list( self.split_tokens(arg) ) 1512 if not targets: 1513 targets = debug.get_debugee_pids() 1514 targets.sort() 1515 if self.lastEvent: 1516 current = self.lastEvent.get_pid() 1517 else: 1518 current = None 1519 for pid in targets: 1520 if pid != current and debug.is_debugee(pid): 1521 process = system.get_process(pid) 1522 try: 1523 process.debug_break() 1524 except WindowsError, e: 1525 print "Can't force a debug break on process (%d)"
1526
1527 - def do_step(self, arg):
1528 """ 1529 p - step on the current assembly instruction 1530 next - step on the current assembly instruction 1531 step - step on the current assembly instruction 1532 """ 1533 if self.cmdprefix: 1534 raise CmdError("prefix not allowed") 1535 if self.lastEvent is None: 1536 raise CmdError("no current process set") 1537 if arg: # XXX this check is to be removed 1538 raise CmdError("too many arguments") 1539 pid = self.lastEvent.get_pid() 1540 thread = self.lastEvent.get_thread() 1541 pc = thread.get_pc() 1542 code = thread.disassemble(pc, 16)[0] 1543 size = code[1] 1544 opcode = code[2].lower() 1545 if ' ' in opcode: 1546 opcode = opcode[ : opcode.find(' ') ] 1547 if opcode in self.jump_instructions or opcode in ('int', 'ret', 'retn'): 1548 return self.do_trace(arg) 1549 address = pc + size 1550 ## print hex(pc), hex(address), size # XXX DEBUG 1551 self.debug.stalk_at(pid, address) 1552 return True
1553 1554 do_p = do_step 1555 do_next = do_step 1556
1557 - def do_trace(self, arg):
1558 """ 1559 t - trace at the current assembly instruction 1560 trace - trace at the current assembly instruction 1561 """ 1562 if arg: # XXX this check is to be removed 1563 raise CmdError("too many arguments") 1564 if self.lastEvent is None: 1565 raise CmdError("no current thread set") 1566 self.lastEvent.get_thread().set_tf() 1567 return True
1568 1569 do_t = do_trace 1570
1571 - def do_bp(self, arg):
1572 """ 1573 [~process] bp <address> - set a code breakpoint 1574 """ 1575 pid = self.get_process_id_from_prefix() 1576 if not self.debug.is_debugee(pid): 1577 raise CmdError("target process is not being debugged") 1578 process = self.get_process(pid) 1579 token_list = self.split_tokens(arg, 1, 1) 1580 try: 1581 address = self.input_address(token_list[0], pid) 1582 deferred = False 1583 except Exception: 1584 address = token_list[0] 1585 deferred = True 1586 if not address: 1587 address = token_list[0] 1588 deferred = True 1589 self.debug.break_at(pid, address) 1590 if deferred: 1591 print "Deferred breakpoint set at %s" % address 1592 else: 1593 print "Breakpoint set at %s" % address
1594
1595 - def do_ba(self, arg):
1596 """ 1597 [~thread] ba <a|w|e> <1|2|4|8> <address> - set hardware breakpoint 1598 """ 1599 debug = self.debug 1600 thread = self.get_thread_from_prefix() 1601 pid = thread.get_pid() 1602 tid = thread.get_tid() 1603 if not debug.is_debugee(pid): 1604 raise CmdError("target thread is not being debugged") 1605 token_list = self.split_tokens(arg, 3, 3) 1606 access = token_list[0].lower() 1607 size = token_list[1] 1608 address = token_list[2] 1609 if access == 'a': 1610 access = debug.BP_BREAK_ON_ACCESS 1611 elif access == 'w': 1612 access = debug.BP_BREAK_ON_WRITE 1613 elif access == 'e': 1614 access = debug.BP_BREAK_ON_EXECUTION 1615 else: 1616 raise CmdError("bad access type: %s" % token_list[0]) 1617 if size == '1': 1618 size = debug.BP_WATCH_BYTE 1619 elif size == '2': 1620 size = debug.BP_WATCH_WORD 1621 elif size == '4': 1622 size = debug.BP_WATCH_DWORD 1623 elif size == '8': 1624 size = debug.BP_WATCH_QWORD 1625 else: 1626 raise CmdError("bad breakpoint size: %s" % size) 1627 thread = self.get_thread_from_prefix() 1628 tid = thread.get_tid() 1629 pid = thread.get_pid() 1630 if not debug.is_debugee(pid): 1631 raise CmdError("target process is not being debugged") 1632 address = self.input_address(address, pid) 1633 if debug.has_hardware_breakpoint(tid, address): 1634 debug.erase_hardware_breakpoint(tid, address) 1635 debug.define_hardware_breakpoint(tid, address, access, size) 1636 debug.enable_hardware_breakpoint(tid, address)
1637
1638 - def do_bm(self, arg):
1639 """ 1640 [~process] bm <address-address> - set memory breakpoint 1641 """ 1642 pid = self.get_process_id_from_prefix() 1643 if not self.debug.is_debugee(pid): 1644 raise CmdError("target process is not being debugged") 1645 process = self.get_process(pid) 1646 token_list = self.split_tokens(arg, 1, 2) 1647 address, size = self.input_address_range(token_list[0], pid) 1648 self.debug.watch_buffer(pid, address, size)
1649
1650 - def do_bl(self, arg):
1651 """ 1652 bl - list the breakpoints for the current process 1653 bl * - list the breakpoints for all processes 1654 [~process] bl - list the breakpoints for the given process 1655 bl <process> [process...] - list the breakpoints for each given process 1656 """ 1657 debug = self.debug 1658 if arg == '*': 1659 if self.cmdprefix: 1660 raise CmdError("prefix not supported") 1661 breakpoints = debug.get_debugee_pids() 1662 else: 1663 targets = self.input_process_list( self.split_tokens(arg) ) 1664 if self.cmdprefix: 1665 targets.insert(0, self.input_process(self.cmdprefix)) 1666 if not targets: 1667 if self.lastEvent is None: 1668 raise CmdError("no current process is set") 1669 targets = [ self.lastEvent.get_pid() ] 1670 for pid in targets: 1671 bplist = debug.get_process_code_breakpoints(pid) 1672 printed_process_banner = False 1673 if bplist: 1674 if not printed_process_banner: 1675 print "Process %d:" % pid 1676 printed_process_banner = True 1677 for bp in bplist: 1678 address = repr(bp)[1:-1].replace('remote address ','') 1679 print " %s" % address 1680 dbplist = debug.get_process_deferred_code_breakpoints(pid) 1681 if dbplist: 1682 if not printed_process_banner: 1683 print "Process %d:" % pid 1684 printed_process_banner = True 1685 for (label, action, oneshot) in dbplist: 1686 if oneshot: 1687 address = " Deferred unconditional one-shot" \ 1688 " code breakpoint at %s" 1689 else: 1690 address = " Deferred unconditional" \ 1691 " code breakpoint at %s" 1692 address = address % label 1693 print " %s" % address 1694 bplist = debug.get_process_page_breakpoints(pid) 1695 if bplist: 1696 if not printed_process_banner: 1697 print "Process %d:" % pid 1698 printed_process_banner = True 1699 for bp in bplist: 1700 address = repr(bp)[1:-1].replace('remote address ','') 1701 print " %s" % address 1702 for tid in debug.system.get_process(pid).iter_thread_ids(): 1703 bplist = debug.get_thread_hardware_breakpoints(tid) 1704 if bplist: 1705 print "Thread %d:" % tid 1706 for bp in bplist: 1707 address = repr(bp)[1:-1].replace('remote address ','') 1708 print " %s" % address
1709
1710 - def do_bo(self, arg):
1711 """ 1712 [~process] bo <address> - make a code breakpoint one-shot 1713 [~thread] bo <address> - make a hardware breakpoint one-shot 1714 [~process] bo <address-address> - make a memory breakpoint one-shot 1715 [~process] bo <address> <size> - make a memory breakpoint one-shot 1716 """ 1717 token_list = self.split_tokens(arg, 1, 2) 1718 pid, tid, address, size = self.input_breakpoint(token_list) 1719 debug = self.debug 1720 found = False 1721 if size is None: 1722 if tid is not None: 1723 if debug.has_hardware_breakpoint(tid, address): 1724 debug.enable_one_shot_hardware_breakpoint(tid, address) 1725 found = True 1726 if pid is not None: 1727 if debug.has_code_breakpoint(pid, address): 1728 debug.enable_one_shot_code_breakpoint(pid, address) 1729 found = True 1730 else: 1731 if debug.has_page_breakpoint(pid, address): 1732 debug.enable_one_shot_page_breakpoint(pid, address) 1733 found = True 1734 if not found: 1735 print "Error: breakpoint not found."
1736
1737 - def do_be(self, arg):
1738 """ 1739 [~process] be <address> - enable a code breakpoint 1740 [~thread] be <address> - enable a hardware breakpoint 1741 [~process] be <address-address> - enable a memory breakpoint 1742 [~process] be <address> <size> - enable a memory breakpoint 1743 """ 1744 token_list = self.split_tokens(arg, 1, 2) 1745 pid, tid, address, size = self.input_breakpoint(token_list) 1746 debug = self.debug 1747 found = False 1748 if size is None: 1749 if tid is not None: 1750 if debug.has_hardware_breakpoint(tid, address): 1751 debug.enable_hardware_breakpoint(tid, address) 1752 found = True 1753 if pid is not None: 1754 if debug.has_code_breakpoint(pid, address): 1755 debug.enable_code_breakpoint(pid, address) 1756 found = True 1757 else: 1758 if debug.has_page_breakpoint(pid, address): 1759 debug.enable_page_breakpoint(pid, address) 1760 found = True 1761 if not found: 1762 print "Error: breakpoint not found."
1763
1764 - def do_bd(self, arg):
1765 """ 1766 [~process] bd <address> - disable a code breakpoint 1767 [~thread] bd <address> - disable a hardware breakpoint 1768 [~process] bd <address-address> - disable a memory breakpoint 1769 [~process] bd <address> <size> - disable a memory breakpoint 1770 """ 1771 token_list = self.split_tokens(arg, 1, 2) 1772 pid, tid, address, size = self.input_breakpoint(token_list) 1773 debug = self.debug 1774 found = False 1775 if size is None: 1776 if tid is not None: 1777 if debug.has_hardware_breakpoint(tid, address): 1778 debug.disable_hardware_breakpoint(tid, address) 1779 found = True 1780 if pid is not None: 1781 if debug.has_code_breakpoint(pid, address): 1782 debug.disable_code_breakpoint(pid, address) 1783 found = True 1784 else: 1785 if debug.has_page_breakpoint(pid, address): 1786 debug.disable_page_breakpoint(pid, address) 1787 found = True 1788 if not found: 1789 print "Error: breakpoint not found."
1790
1791 - def do_bc(self, arg):
1792 """ 1793 [~process] bc <address> - clear a code breakpoint 1794 [~thread] bc <address> - clear a hardware breakpoint 1795 [~process] bc <address-address> - clear a memory breakpoint 1796 [~process] bc <address> <size> - clear a memory breakpoint 1797 """ 1798 token_list = self.split_tokens(arg, 1, 2) 1799 pid, tid, address, size = self.input_breakpoint(token_list) 1800 debug = self.debug 1801 found = False 1802 if size is None: 1803 if tid is not None: 1804 if debug.has_hardware_breakpoint(tid, address): 1805 debug.dont_watch_variable(tid, address) 1806 found = True 1807 if pid is not None: 1808 if debug.has_code_breakpoint(pid, address): 1809 debug.dont_break_at(pid, address) 1810 found = True 1811 else: 1812 if debug.has_page_breakpoint(pid, address): 1813 debug.dont_watch_buffer(pid, address, size) 1814 found = True 1815 if not found: 1816 print "Error: breakpoint not found."
1817
1818 - def do_disassemble(self, arg):
1819 """ 1820 [~thread] u [register] - show code disassembly 1821 [~process] u [address] - show code disassembly 1822 [~thread] disassemble [register] - show code disassembly 1823 [~process] disassemble [address] - show code disassembly 1824 """ 1825 if not arg: 1826 arg = self.default_disasm_target 1827 token_list = self.split_tokens(arg, 1, 1) 1828 pid, tid = self.get_process_and_thread_ids_from_prefix() 1829 process = self.get_process(pid) 1830 address = self.input_address(token_list[0], pid, tid) 1831 try: 1832 code = process.disassemble(address, 15*8)[:8] 1833 except Exception, e: 1834 msg = "can't disassemble address %s" 1835 msg = msg % HexDump.address(address) 1836 raise CmdError(msg) 1837 if code: 1838 label = process.get_label_at_address(address) 1839 last_code = code[-1] 1840 next_address = last_code[0] + last_code[1] 1841 next_address = HexOutput.integer(next_address) 1842 self.default_disasm_target = next_address 1843 print "%s:" % label 1844 ## print CrashDump.dump_code(code) 1845 for line in code: 1846 print CrashDump.dump_code_line(line, bShowDump = False)
1847 1848 do_u = do_disassemble 1849
1850 - def do_search(self, arg):
1851 """ 1852 [~process] s [address-address] <search string> 1853 [~process] search [address-address] <search string> 1854 """ 1855 token_list = self.split_tokens(arg, 1, 3) 1856 pid, tid = self.get_process_and_thread_ids_from_prefix() 1857 process = self.get_process(pid) 1858 if len(token_list) == 1: 1859 pattern = token_list[0] 1860 minAddr = None 1861 maxAddr = None 1862 else: 1863 pattern = token_list[-1] 1864 addr, size = self.input_address_range(token_list[:-1], pid, tid) 1865 minAddr = addr 1866 maxAddr = addr + size 1867 iter = process.search_bytes(pattern) 1868 if process.get_bits() == 32: 1869 addr_width = 8 1870 else: 1871 addr_width = 16 1872 # TODO: need a prettier output here! 1873 for addr in iter: 1874 print HexDump.address(addr, addr_width)
1875 1876 do_s = do_search 1877
1878 - def do_searchhex(self, arg):
1879 """ 1880 [~process] sh [address-address] <hexadecimal pattern> 1881 [~process] searchhex [address-address] <hexadecimal pattern> 1882 """ 1883 token_list = self.split_tokens(arg, 1, 3) 1884 pid, tid = self.get_process_and_thread_ids_from_prefix() 1885 process = self.get_process(pid) 1886 if len(token_list) == 1: 1887 pattern = token_list[0] 1888 minAddr = None 1889 maxAddr = None 1890 else: 1891 pattern = token_list[-1] 1892 addr, size = self.input_address_range(token_list[:-1], pid, tid) 1893 minAddr = addr 1894 maxAddr = addr + size 1895 iter = process.search_hexa(pattern) 1896 if process.get_bits() == 32: 1897 addr_width = 8 1898 else: 1899 addr_width = 16 1900 for addr, bytes in iter: 1901 print HexDump.hexblock(bytes, addr, addr_width),
1902 1903 do_sh = do_searchhex 1904 1905 ## def do_strings(self, arg): 1906 ## """ 1907 ## [~process] strings - extract ASCII strings from memory 1908 ## """ 1909 ## if arg: 1910 ## raise CmdError("too many arguments") 1911 ## pid, tid = self.get_process_and_thread_ids_from_prefix() 1912 ## process = self.get_process(pid) 1913 ## for addr, size, data in process.strings(): 1914 ## print "%s: %r" % (HexDump.address(addr), data) 1915
1916 - def do_d(self, arg):
1917 """ 1918 [~thread] d <register> - show memory contents 1919 [~thread] d <register-register> - show memory contents 1920 [~thread] d <register> <size> - show memory contents 1921 [~process] d <address> - show memory contents 1922 [~process] d <address-address> - show memory contents 1923 [~process] d <address> <size> - show memory contents 1924 """ 1925 return self.last_display_command(arg)
1926
1927 - def do_db(self, arg):
1928 """ 1929 [~thread] db <register> - show memory contents as bytes 1930 [~thread] db <register-register> - show memory contents as bytes 1931 [~thread] db <register> <size> - show memory contents as bytes 1932 [~process] db <address> - show memory contents as bytes 1933 [~process] db <address-address> - show memory contents as bytes 1934 [~process] db <address> <size> - show memory contents as bytes 1935 """ 1936 self.print_memory_display(arg, HexDump.hexblock) 1937 self.last_display_command = self.do_db
1938
1939 - def do_dw(self, arg):
1940 """ 1941 [~thread] dw <register> - show memory contents as words 1942 [~thread] dw <register-register> - show memory contents as words 1943 [~thread] dw <register> <size> - show memory contents as words 1944 [~process] dw <address> - show memory contents as words 1945 [~process] dw <address-address> - show memory contents as words 1946 [~process] dw <address> <size> - show memory contents as words 1947 """ 1948 self.print_memory_display(arg, HexDump.hexblock_word) 1949 self.last_display_command = self.do_dw
1950
1951 - def do_dd(self, arg):
1952 """ 1953 [~thread] dd <register> - show memory contents as dwords 1954 [~thread] dd <register-register> - show memory contents as dwords 1955 [~thread] dd <register> <size> - show memory contents as dwords 1956 [~process] dd <address> - show memory contents as dwords 1957 [~process] dd <address-address> - show memory contents as dwords 1958 [~process] dd <address> <size> - show memory contents as dwords 1959 """ 1960 self.print_memory_display(arg, HexDump.hexblock_dword) 1961 self.last_display_command = self.do_dd
1962
1963 - def do_dq(self, arg):
1964 """ 1965 [~thread] dq <register> - show memory contents as qwords 1966 [~thread] dq <register-register> - show memory contents as qwords 1967 [~thread] dq <register> <size> - show memory contents as qwords 1968 [~process] dq <address> - show memory contents as qwords 1969 [~process] dq <address-address> - show memory contents as qwords 1970 [~process] dq <address> <size> - show memory contents as qwords 1971 """ 1972 self.print_memory_display(arg, HexDump.hexblock_qword) 1973 self.last_display_command = self.do_dq
1974 1975 # XXX TODO 1976 # Change the way the default is used with ds and du 1977
1978 - def do_ds(self, arg):
1979 """ 1980 [~thread] ds <register> - show memory contents as ANSI string 1981 [~process] ds <address> - show memory contents as ANSI string 1982 """ 1983 if not arg: 1984 arg = self.default_display_target 1985 token_list = self.split_tokens(arg, 1, 1) 1986 pid, tid, address, size = self.input_display(token_list, 256) 1987 process = self.get_process(pid) 1988 data = process.peek_string(address, False, size) 1989 if data: 1990 print repr(data) 1991 self.last_display_command = self.do_ds
1992
1993 - def do_du(self, arg):
1994 """ 1995 [~thread] du <register> - show memory contents as Unicode string 1996 [~process] du <address> - show memory contents as Unicode string 1997 """ 1998 if not arg: 1999 arg = self.default_display_target 2000 token_list = self.split_tokens(arg, 1, 2) 2001 pid, tid, address, size = self.input_display(token_list, 256) 2002 process = self.get_process(pid) 2003 data = process.peek_string(address, True, size) 2004 if data: 2005 print repr(data) 2006 self.last_display_command = self.do_du
2007
2008 - def do_register(self, arg):
2009 """ 2010 [~thread] r - print the value of all registers 2011 [~thread] r <register> - print the value of a register 2012 [~thread] r <register>=<value> - change the value of a register 2013 [~thread] register - print the value of all registers 2014 [~thread] register <register> - print the value of a register 2015 [~thread] register <register>=<value> - change the value of a register 2016 """ 2017 arg = arg.strip() 2018 if not arg: 2019 self.print_current_location() 2020 else: 2021 equ = arg.find('=') 2022 if equ >= 0: 2023 register = arg[:equ].strip() 2024 value = arg[equ+1:].strip() 2025 if not value: 2026 value = '0' 2027 self.change_register(register, value) 2028 else: 2029 value = self.input_register(arg) 2030 if value is None: 2031 raise CmdError("unknown register: %s" % arg) 2032 try: 2033 label = None 2034 thread = self.get_thread_from_prefix() 2035 process = thread.get_process() 2036 module = process.get_module_at_address(value) 2037 if module: 2038 label = module.get_label_at_address(value) 2039 except RuntimeError: 2040 label = None 2041 reg = arg.upper() 2042 val = HexDump.address(value) 2043 if label: 2044 print "%s: %s (%s)" % (reg, val, label) 2045 else: 2046 print "%s: %s" % (reg, val)
2047 2048 do_r = do_register 2049
2050 - def do_eb(self, arg):
2051 """ 2052 [~process] eb <address> <data> - write the data to the specified address 2053 """ 2054 # TODO 2055 # data parameter should be optional, use a child Cmd here 2056 pid = self.get_process_id_from_prefix() 2057 token_list = self.split_tokens(arg, 2) 2058 address = self.input_address(token_list[0], pid) 2059 data = HexInput.hexadecimal(' '.join(token_list[1:])) 2060 self.write_memory(address, data, pid)
2061 2062 # XXX TODO 2063 # add ew, ed and eq here 2064
2065 - def do_find(self, arg):
2066 """ 2067 [~process] f <string> - find the string in the process memory 2068 [~process] find <string> - find the string in the process memory 2069 """ 2070 if not arg: 2071 raise CmdError("missing parameter: string") 2072 process = self.get_process_from_prefix() 2073 self.find_in_memory(arg, process)
2074 2075 do_f = do_find 2076
2077 - def do_memory(self, arg):
2078 """ 2079 [~process] m - show the process memory map 2080 [~process] memory - show the process memory map 2081 """ 2082 if arg: # TODO: take min and max addresses 2083 raise CmdError("too many arguments") 2084 process = self.get_process_from_prefix() 2085 try: 2086 memoryMap = process.get_memory_map() 2087 mappedFilenames = process.get_mapped_filenames() 2088 print 2089 print CrashDump.dump_memory_map(memoryMap, mappedFilenames) 2090 except WindowsError, e: 2091 msg = "can't get memory information for process (%d)" 2092 raise CmdError(msg % process.get_pid())
2093 2094 do_m = do_memory 2095 2096 #------------------------------------------------------------------------------ 2097 # Event handling 2098 2099 # TODO 2100 # * add configurable stop/don't stop behavior on events and exceptions 2101 2102 # Stop for all events, unless stated otherwise.
2103 - def event(self, event):
2104 self.print_event(event) 2105 self.prompt_user()
2106 2107 # Stop for all exceptions, unless stated otherwise.
2108 - def exception(self, event):
2109 self.print_exception(event) 2110 self.prompt_user()
2111 2112 # Stop for breakpoint exceptions.
2113 - def breakpoint(self, event):
2114 if hasattr(event, 'breakpoint') and event.breakpoint: 2115 self.print_breakpoint_location(event) 2116 else: 2117 self.print_exception(event) 2118 self.prompt_user()
2119 2120 # Stop for WOW64 breakpoint exceptions.
2121 - def wow64_breakpoint(self, event):
2122 self.print_exception(event) 2123 self.prompt_user()
2124 2125 # Stop for single step exceptions.
2126 - def single_step(self, event):
2127 if event.debug.is_tracing(event.get_tid()): 2128 self.print_breakpoint_location(event) 2129 else: 2130 self.print_exception(event) 2131 self.prompt_user()
2132 2133 # Don't stop for C++ exceptions.
2134 - def ms_vc_exception(self, event):
2135 self.print_exception(event) 2136 event.continueStatus = win32.DBG_CONTINUE
2137 2138 # Don't stop for process start.
2139 - def create_process(self, event):
2143 2144 # Don't stop for process exit.
2145 - def exit_process(self, event):
2147 2148 # Don't stop for thread creation.
2149 - def create_thread(self, event):
2151 2152 # Don't stop for thread exit.
2153 - def exit_thread(self, event):
2155 2156 # Don't stop for DLL load.
2157 - def load_dll(self, event):
2159 2160 # Don't stop for DLL unload.
2161 - def unload_dll(self, event):
2163 2164 # Don't stop for debug strings.
2165 - def output_string(self, event):
2167 2168 #------------------------------------------------------------------------------ 2169 # History file 2170
2171 - def load_history(self):
2172 global readline 2173 if readline is None: 2174 try: 2175 import readline 2176 except ImportError: 2177 return 2178 if self.history_file_full_path is None: 2179 folder = os.environ.get('USERPROFILE', '') 2180 if not folder: 2181 folder = os.environ.get('HOME', '') 2182 if not folder: 2183 folder = os.path.split(sys.argv[0])[1] 2184 if not folder: 2185 folder = os.path.curdir 2186 self.history_file_full_path = os.path.join(folder, 2187 self.history_file) 2188 try: 2189 if os.path.exists(self.history_file_full_path): 2190 readline.read_history_file(self.history_file_full_path) 2191 except IOError, e: 2192 warnings.warn("Cannot load history file, reason: %s" % str(e))
2193
2194 - def save_history(self):
2195 if self.history_file_full_path is not None: 2196 global readline 2197 if readline is None: 2198 try: 2199 import readline 2200 except ImportError: 2201 return 2202 try: 2203 readline.write_history_file(self.history_file_full_path) 2204 except IOError, e: 2205 warnings.warn("Cannot save history file, reason: %s" % str(e))
2206 2207 #------------------------------------------------------------------------------ 2208 # Main loop 2209 2210 # Debugging loop.
2211 - def loop(self):
2212 self.debuggerExit = False 2213 debug = self.debug 2214 2215 # Stop on the initial event, if any. 2216 if self.lastEvent is not None: 2217 self.cmdqueue.append('r') 2218 self.prompt_user() 2219 2220 # Loop until the debugger is told to quit. 2221 while not self.debuggerExit: 2222 2223 try: 2224 2225 # If for some reason the last event wasn't continued, 2226 # continue it here. This won't be done more than once 2227 # for a given Event instance, though. 2228 try: 2229 debug.cont() 2230 # On error, show the command prompt. 2231 except Exception: 2232 traceback.print_exc() 2233 self.prompt_user() 2234 2235 # While debugees are attached, handle debug events. 2236 # Some debug events may cause the command prompt to be shown. 2237 if self.debug.get_debugee_count() > 0: 2238 try: 2239 2240 # Get the next debug event. 2241 debug.wait() 2242 2243 # Dispatch the debug event. 2244 try: 2245 debug.dispatch() 2246 2247 # Continue the debug event. 2248 finally: 2249 debug.cont() 2250 2251 # On error, show the command prompt. 2252 except Exception: 2253 traceback.print_exc() 2254 self.prompt_user() 2255 2256 # While no debugees are attached, show the command prompt. 2257 else: 2258 self.prompt_user() 2259 2260 # When the user presses Ctrl-C send a debug break to all debugees. 2261 except KeyboardInterrupt: 2262 success = False 2263 try: 2264 print "*** User requested debug break" 2265 system = debug.system 2266 for pid in debug.get_debugee_pids(): 2267 try: 2268 system.get_process(pid).debug_break() 2269 success = True 2270 except: 2271 traceback.print_exc() 2272 except: 2273 traceback.print_exc() 2274 if not success: 2275 raise # This should never happen!
2276