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