diff src/cli/gdbcli.d @ 1:4a9dcbd9e54f

-files of 0.13 beta -fixes so that it now compiles with the current dmd version
author marton@basel.hu
date Tue, 05 Apr 2011 20:44:01 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cli/gdbcli.d	Tue Apr 05 20:44:01 2011 +0200
@@ -0,0 +1,832 @@
+/*  Ddbg - Win32 Debugger for the D programming language
+ *  Copyright (c) 2007 Jascha Wetzel
+ *  All rights reserved. See LICENSE.TXT for details.
+ */
+module cli.gdbcli;
+
+import std.string;
+static import std.regexp;
+import std.c.stdio : sscanf;
+import std.c.string;
+import std.demangle;
+
+import util;
+import codeview.codeview;
+import breakpoint;
+import debugger;
+import disasm;
+import callstack;
+import dbgprocess;
+import dbgthread;
+import expression.expression_apd;
+import expression.datahandler : SymbolValue;
+import expression.evaluationcontext;
+import cli.userinterface;
+
+import win32.winbase;
+import win32.winuser;
+import win32.winnt;
+
+/**************************************************************************************************
+
+**************************************************************************************************/
+class GDBCLI : UserInterfaceBase
+{
+	string[]    lastcmd;
+
+    uint        current_frame_level;
+
+	string			prompt,
+					command_line,
+					debuggee;
+	bool			fullname = false,
+					quit;
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	this()
+	{
+		prompt = "(gdb) ";
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void init(string[] args)
+	{
+		DbgIO.println(WELCOME_STRING);
+		if ( args.length < 2 )
+			throw new DebuggerException("Usage: ddbg -cli=gdb [-cmd=<commands>] [-fullname] -args <exe file> [arguments]");
+
+		bool	read_args = false;
+		Lfe: foreach ( int i, a; args )
+		{
+			switch ( a )
+			{
+				case "-fullname":
+				case "--fullname":
+                    fullname = true;
+                    break;
+				case "-args":
+				case "--args":
+					read_args=true;
+					break;
+				default:
+                    debuggee = a;
+					if ( read_args )
+					{
+                        if ( find(a, ' ') >= 0 )
+                            command_line = "\""~a~"\"";
+                        else
+                            command_line = a;
+						if ( args.length > i+1 )
+                            command_line ~= " "~join(args[i+1..$], " ");
+						break Lfe;
+					}
+			}
+		}
+
+		dbg = new Debugger(debuggee, this);
+		dbg.create_new_console = true;
+	}
+
+	int start()
+	{
+		while ( !quit )
+		{
+            try readCommand();
+            catch ( Exception e )
+                DbgIO.println(e.msg);
+		}
+		return 0;
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void singleStep()
+	{
+		DbgIO.println(describeLocation(dbg.current_address));
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void exitProcess()
+	{
+		DbgIO.println("Program exited");
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void loadedDLL(DLL dll)
+	{
+		if( dll !is null && dll.image.name.length )
+			DbgIO.writeln(dll.image.name~" loaded");
+		else
+			DbgIO.writeln("unknown DLL loaded");
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void win32exception(uint threadId, EXCEPTION_RECORD* exrec)
+	{
+		DbgIO.println(
+			"Program received signal SIG Unhandled Exception: %s(0x%x) at 0x%x",
+			getExceptionName(exrec.ExceptionCode), exrec.ExceptionCode, exrec.ExceptionAddress //describeLocation(dbg.current_address)
+		);
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void exception(uint threadId, string class_name, string msg, size_t obj_ptr)
+	{
+		DbgIO.println(
+			"Program received signal SIG Unhandled D Exception (%s%s) at %s",
+			class_name, msg.length>0?" \""~msg~"\"":"", describeLocation(dbg.current_address)
+		);
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void userInterrupt()
+	{
+		DbgIO.println("User interrupt at %s", describeLocation(dbg.current_address));
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	bool breakpoint(int index, Breakpoint bp, DbgThread thread)
+	{
+		if ( bp.file is null || bp.line == 0 )
+			DbgIO.println("Unknown breakpoint hit at %s", describeLocation(bp.address));
+		else
+			DbgIO.println("\032\032%s:%d:0:begmidl:0x%08x", fullname?dbg.getFullSourcePath(bp.file):bp.file, bp.line, bp.address);
+		return true;
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void debugString(string str)
+	{
+		printf("Error OUTPUT DEBUG STRING:\n%s\n", toStringz(str));
+	}
+
+    /**********************************************************************************************
+        Command line parser. Gets called when debuggee is suspended.
+    **********************************************************************************************/
+	bool parseCommand(string input)
+	{
+		if ( strip(input).length > 0 )
+		{
+			auto r = std.regexp.RegExp("(([^\" \\t]+)|(\"[^\"]+\"))+");
+			lastcmd.length = 0;
+			foreach ( m; r.search(strip(input)) )
+				lastcmd ~= r.match(0);
+		}
+		if ( lastcmd.length <= 0 )
+			return false;
+
+		int slash_pos = find(lastcmd[0], '/');
+		if ( slash_pos >= 0 ) {
+			lastcmd ~= lastcmd[0];
+			lastcmd[0] = lastcmd[0][0..slash_pos];
+		}
+
+		switch ( lastcmd[0] )
+		{
+			case "help":
+				DbgIO.println("GDB emulation mode - no help available, yet");
+				break;
+			case "delete":
+				if ( lastcmd.length < 2 )
+					DbgIO.println("Warning: too few arguments for set");
+				else switch ( lastcmd[1] )
+				{
+					case "breakpoints":
+						if ( lastcmd.length < 3 )
+						{
+							foreach ( uint i; dbg.breakpoints.keys )
+								dbg.removeBreakpoint(i);
+						}
+						else if ( !isNumeric(lastcmd[2]) )
+							DbgIO.println("Warning: invalid breakpoint index '%s'", lastcmd[2]);
+						else
+							dbg.removeBreakpoint(cast(uint)atoi(lastcmd[2]));
+						break;
+					default:
+						DbgIO.println("Warning: unknown argument %s", lastcmd[1]);
+				}
+				break;
+			case "set":
+				if ( lastcmd.length < 2 )
+					DbgIO.println("Warning: too few arguments for set");
+				else switch ( lastcmd[1] )
+				{
+					case "prompt":
+						if ( lastcmd.length < 3 )
+							DbgIO.println("Warning: too few arguments for set prompt");
+						else
+							prompt = lastcmd[2];
+						break;
+					case "args":
+						if ( dbg.process_loaded )
+							DbgIO.println("Warning: process already started");
+						command_line = debuggee~" "~join(lastcmd[2..$], " ");
+						break;
+					default:
+						DbgIO.println("Warning: unknown variable %s", lastcmd[1]);
+				}
+				break;
+			case "info":
+				if ( lastcmd.length < 2 )
+					DbgIO.println("Warning: too few arguments for info");
+				else
+				{
+					switch ( lastcmd[1] )
+					{
+						case "locals":
+                            if ( dbg.process_loaded )
+                            {
+                                uint scope_address = dbg.getScopeAddress(current_frame_level);
+                                ScopeSymbol scope_sym = dbg.images.findProcedureSymbol(scope_address);
+                                for ( ; scope_sym !is null; scope_sym = scope_sym.parent_scope )
+                                {
+                                    if ( scope_sym is null )
+                                        DbgIO.println("No valid scope active");
+                                    else
+                                        evalStackSymbols(scope_sym.symbols.stack_symbols);
+                                }
+                            }
+							break;
+						case "args":
+                            if ( dbg.process_loaded )
+                            {
+                                uint scope_address = dbg.getScopeAddress(current_frame_level);
+                                ScopeSymbol scope_sym = dbg.images.findProcedureSymbol(scope_address);
+                                for ( ; scope_sym !is null; scope_sym = scope_sym.parent_scope )
+                                {
+                                    if ( scope_sym is null )
+                                        DbgIO.println("No valid scope active");
+                                    else
+                                    {
+                                        auto psym = cast(ProcedureSymbol)scope_sym;
+                                        if ( psym !is null )
+                                            evalStackSymbols(psym.arguments.stack_symbols);
+                                    }
+                                }
+                            }
+							break;
+						case "registers":
+							printRegisterDump(dbg.process.threads[dbg.thread_id]);
+							break;
+						case "frame":
+                            uint scope_address = dbg.getScopeAddress(current_frame_level);
+                            ubyte[] frame = dbg.stack.getFrame(current_frame_level);
+							Location loc = dbg.images.findLocation(scope_address);
+							DbgIO.print("Stack level %d, frame at ", current_frame_level);
+							if ( loc.scope_sym !is null ) {
+								ProcedureSymbol psym = cast(ProcedureSymbol)loc.scope_sym;
+								DbgIO.println("0x%x:", loc.getCodeBase + psym.cvdata.offset + psym.cvdata.debug_start);
+							}
+							else
+								DbgIO.println("0x%x:", dbg.current_address);
+
+							DbgIO.print(" eip = 0x%x in %s (",
+								loc.address, loc.scope_sym is null?"??":loc.scope_sym.name_notype
+							);
+
+							if ( loc.codeblock !is null )
+								DbgIO.print("%s:%d", loc.file, loc.line);
+							else if ( loc.mod !is null )
+								DbgIO.write(loc.mod.name);
+							else
+							{
+								DLL dll = dbg.process.findDLL(loc.address);
+								if ( dll !is null )
+									DbgIO.write(dll.image.name);
+							}
+
+							DbgIO.println("); saved eip 0x%x", (cast(uint[])frame)[1]);
+							break;
+						default:
+							DbgIO.println("Warning: unknown argument %s", lastcmd[1]);
+					}
+				}
+				break;
+            // select frame
+            case "select-frame":
+                if ( lastcmd.length > 1 )
+                    current_frame_level = cast(uint)atoi(lastcmd[1]);
+                DbgIO.println("Current frame level is %d", current_frame_level);
+                break;
+			// add breakpoint
+			case "tbreak":
+			case "clear":
+			case "break":
+				int index;
+				if ( lastcmd.length < 2 ) {
+					DbgIO.println("invalid syntax - see help for details");
+					break;
+				}
+                Location loc = new Location(lastcmd[1]);
+                loc.bind(dbg.images, dbg.source_search_paths);
+                if ( loc is null )
+                    break;
+				if ( lastcmd.length > 2 )
+					index = cast(int)atoi(lastcmd[2]);
+
+				if ( lastcmd[0] == "clear" )
+				{
+					Breakpoint bp = dbg.getBreakpoint(loc, index);
+					dbg.removeBreakpoint(index);
+				}
+				else
+				{
+                    Breakpoint bp;
+				    if ( lastcmd[0] == "tbreak" )
+                        index = -1;
+                    else if ( index <= 0 && dbg.breakpoints.length > 0 )
+                        index = dbg.breakpoints.keys.dup.sort[$-1]+1;
+                    bp = dbg.setBreakpoint(loc, index, 0);
+					DbgIO.println("Breakpoint %d at 0x%08x", index, bp.address);
+				}
+				break;
+			// add source search path
+			case "directory":
+				if ( lastcmd.length > 1 )
+				{
+					string sp = lastcmd[1].dup;
+					if ( find(sp, '/') >= 0 )
+						sp = replace(sp, "/", "\\");
+					if ( sp[$-1] != '\\' )
+						sp ~= '\\';
+					dbg.source_search_paths ~= sp;
+				}
+				else
+					DbgIO.println("usage: ssp <search_path>");
+				break;
+			// quit
+			case "quit":
+			case "q":
+				dbg.abort = true;
+				quit = true;
+				return true;
+			// run/continue
+			case "cont":
+			case "run":
+			case "start":
+				if ( dbg.process_loaded ) {
+					dbg.single_step = false;
+					dbg.paused = false;
+					return true;
+				}
+				else {
+					dbg.start(command_line);
+					return true;
+				}
+			// single-step
+			case "nexti":
+				dbg.single_step = true;
+				dbg.activateSingleStep(true);
+				return true;
+			// step over
+			case "next":
+				if ( dbg.step(StepMode.e_over) )
+					return true;
+				break;
+			// step into
+			case "step":
+				if ( dbg.step(StepMode.e_in) )
+					return true;
+				break;
+			// step out
+			case "finish":
+				if ( dbg.step(StepMode.e_out) )
+					return true;
+				break;
+			// unwind stack
+			case "bt":
+				unwindStack();
+				break;
+			case "print":
+			case "output":
+				if ( dbg.process_loaded && lastcmd.length > 1 )
+				{
+					string expr;
+					if ( lastcmd[1][0] == '/' )
+						expr = lastcmd[2];
+					else
+						expr = lastcmd[1];
+					try DbgIO.println(symbolValueToString(dbg.handleData(dbg.evaluateExpression(expr), false)));
+					catch ( EvaluationException e ) {
+						DbgIO.writeln(e.toString);
+					}
+				}
+				break;
+			case "disassemble":
+                if ( !dbg.process_loaded )
+                    break;
+
+                uint start_address = dbg.current_address;
+				if ( lastcmd.length > 1 )
+					sscanf(toStringz(lastcmd[1]), "%x", &start_address);
+				else
+				{
+					Location loc = dbg.images.findLocation(dbg.current_address);
+					if ( loc.scope_sym !is null ) {
+						ProcedureSymbol psym = cast(ProcedureSymbol)loc.scope_sym;
+						start_address = loc.getCodeBase + psym.cvdata.offset;
+						DisAsm.disasm(dbg.process, start_address, start_address+psym.cvdata.proc_length, &printDisassembly);
+						break;
+					}
+				}
+				DisAsm.disasm(dbg.process, start_address, 0, &printDisassembly);
+				break;
+			case "x":
+				uint start_address;
+				if ( lastcmd.length > 2 )
+				{
+					if ( lastcmd[1].length > 2 && lastcmd[1][0..2] == "0x" )
+						lastcmd[1] = lastcmd[1][2..$];
+					sscanf(toStringz(lastcmd[1]), "%x", &start_address);
+					string count_str = lastcmd[$-1][2..$-2];
+					uint count = cast(uint)atoi(count_str);
+
+					dumpMemory(start_address, count);
+				}
+				else
+					DbgIO.println("Warning: too few arguments for x");
+				break;
+            case "whatis":
+				if ( dbg.process_loaded && lastcmd.length > 1 )
+				{
+				    SymbolData sd = dbg.evaluateExpression(lastcmd[1], current_frame_level);
+				    string type = demangle("_D0"~sd.type);
+					try DbgIO.println("type = %s", type);
+					catch ( EvaluationException e ) {
+						DbgIO.writeln(e.toString);
+					}
+				}
+                break;
+
+
+			// list source search paths
+			case "lsp":
+				foreach ( s; dbg.source_search_paths )
+					DbgIO.writeln(s);
+				break;
+			// list breakpoints
+			case "lbp":
+				if ( dbg.breakpoints.length <= 0 )
+					DbgIO.println("no breakpoints set");
+				foreach ( uint i, bp; dbg.breakpoints )
+					DbgIO.println("%d %s", i, bp.toString);
+				break;
+			// list temporary breakpoints
+			case "ltbp":
+				if ( dbg.temp_breakpoints.empty )
+					DbgIO.println("no temporary breakpoints set");
+				foreach ( bp; dbg.temp_breakpoints )
+					DbgIO.writeln(bp.value.toString);
+				break;
+			// list debug modules
+			case "lm":
+				string[]	modules_noinfo;
+                foreach ( img; dbg.images.images )
+                {
+                    if ( img.codeView is null )
+                        continue;
+                    foreach ( m; img.codeView.modulesByIndex )
+                    {
+                        string name = m.name;
+
+                        if ( m.header.iLib > 0 )
+                            name ~= " from "~img.codeView.libraries[m.header.iLib];
+
+                        if ( lastcmd.length > 1 && find(name, lastcmd[1]) < 0 )
+                            continue;
+
+                        bool has_info = false;
+                        with ( m.symbols ) if ( proc_symbols.length+stack_symbols.length+data_symbols.length > 0 )
+                        {
+                            DbgIO.println(
+                                "%s\n\tSymbols: %d proc %d stack %d data",
+                                name, proc_symbols.length, stack_symbols.length, data_symbols.length
+                            );
+                            has_info = true;
+                        }
+                        if ( m.source_module !is null )
+                        {
+                            DbgIO.println("\tSource files:");
+                            has_info = true;
+                            foreach ( sf; m.source_module.files )
+                                DbgIO.println("\t\t%s", sf.name);
+                        }
+                        if ( !has_info )
+                            modules_noinfo ~= name;
+                    }
+                }
+				if ( modules_noinfo.length > 0 )
+				{
+					DbgIO.println("Modules without debug information:");
+					foreach ( m; modules_noinfo )
+						DbgIO.println("%s ", m);
+				}
+				break;
+			// list source modules
+			case "lsm":
+                foreach ( img; dbg.images.images )
+                {
+                    if ( img.codeView is null )
+                        continue;
+                    foreach ( m; img.codeView.modulesByIndex )
+                    {
+                        if ( m.source_module !is null )
+                        {
+                            foreach ( sf; m.source_module.files )
+                            {
+                                if ( lastcmd.length > 1 && find(sf.name, lastcmd[1]) < 0 )
+                                    continue;
+                                DbgIO.writeln(sf.name);
+                            }
+                        }
+                    }
+                }
+				break;
+			// list all symbols
+			case "ls":
+                foreach ( img; dbg.images.images )
+                {
+                    if ( img.codeView is null )
+                        continue;
+                    printSymbols(img.codeView, img.codeView.global_pub.named_symbols, lastcmd.length>1?lastcmd[1]:null);
+                    printSymbols(img.codeView, img.codeView.global_sym.named_symbols, lastcmd.length>1?lastcmd[1]:null);
+                    printSymbols(img.codeView, img.codeView.static_sym.named_symbols, lastcmd.length>1?lastcmd[1]:null);
+                    foreach ( m; img.codeView.modulesByIndex )
+                        printSymbols(img.codeView, m.symbols.named_symbols, lastcmd.length>1?lastcmd[1]:null);
+                }
+				break;
+			// list function symbols
+			case "lf":
+                foreach ( img; dbg.images.images )
+                {
+                    if ( img.codeView is null )
+                        continue;
+                    printSymbols(img.codeView, img.codeView.global_pub.proc_symbols, lastcmd.length>1?lastcmd[1]:null);
+                    printSymbols(img.codeView, img.codeView.global_sym.proc_symbols, lastcmd.length>1?lastcmd[1]:null);
+                    printSymbols(img.codeView, img.codeView.static_sym.proc_symbols, lastcmd.length>1?lastcmd[1]:null);
+                    foreach ( m; img.codeView.modulesByIndex )
+                        printSymbols(img.codeView, m.symbols.proc_symbols, lastcmd.length>1?lastcmd[1]:null);
+                }
+				break;
+			// list data symbols
+			case "ld":
+                foreach ( img; dbg.images.images )
+                {
+                    if ( img.codeView is null )
+                        continue;
+                    printSymbols(img.codeView, img.codeView.global_pub.data_symbols, lastcmd.length>1?lastcmd[1]:null);
+                    printSymbols(img.codeView, img.codeView.global_sym.data_symbols, lastcmd.length>1?lastcmd[1]:null);
+                    printSymbols(img.codeView, img.codeView.static_sym.data_symbols, lastcmd.length>1?lastcmd[1]:null);
+                    foreach ( m; img.codeView.modulesByIndex )
+                        printSymbols(img.codeView, m.symbols.data_symbols, lastcmd.length>1?lastcmd[1]:null);
+                }
+				break;
+			// list global symbols
+			case "lg":
+                foreach ( img; dbg.images.images )
+                {
+                    if ( img.codeView is null )
+                        continue;
+                    printSymbols(img.codeView, img.codeView.global_pub.named_symbols, lastcmd.length>1?lastcmd[1]:null);
+                    printSymbols(img.codeView, img.codeView.global_sym.named_symbols, lastcmd.length>1?lastcmd[1]:null);
+                }
+				break;
+			// list global publics
+			case "lp":
+                foreach ( img; dbg.images.images )
+                {
+                    if ( img.codeView is null )
+                        continue;
+                    printSymbols(img.codeView, img.codeView.global_pub.named_symbols, lastcmd.length>1?lastcmd[1]:null);
+                }
+				break;
+			// delete breakpoint
+			case "dbp":
+				if ( lastcmd.length > 1 )
+				{
+					if ( lastcmd[1] == "*" )
+					{
+						foreach ( uint i, bp; dbg.breakpoints )
+						{
+							bp.deactivate(dbg.process);
+							dbg.breakpoints.remove(i);
+						}
+					}
+					else if ( isNumeric(lastcmd[1]) )
+					{
+						if ( !dbg.removeBreakpoint(cast(uint)atoi(lastcmd[1])) )
+							DbgIO.println("invalid breakpoint index: %s",lastcmd[1]);
+					}
+					else
+					{
+                        Location loc = new Location(lastcmd[1]);
+                        loc.bind(dbg.images, dbg.source_search_paths);
+						if ( loc !is null )
+						{
+							int bp_index;
+							dbg.getBreakpoint(loc, bp_index);
+							if ( bp_index >= 0 && !dbg.removeBreakpoint(bp_index) )
+								DbgIO.println("No breakpoint set at "~lastcmd[1]);
+						}
+						else
+							DbgIO.println("Usage: dbp [<bp index>|<file:line>]");
+					}
+				}
+				else
+					DbgIO.println("Usage: bp <sourc file>:<line>");
+				break;
+			// dump stack
+			case "ds":
+				int dump_length;
+				if ( lastcmd.length > 1 )
+					dump_length = cast(int)atoi(lastcmd[1])*4;
+				else
+				{
+					CONTEXT ctx;
+					if ( dbg.process.threads[dbg.thread_id].getContext(ctx, CONTEXT_CONTROL) )
+						dump_length = ctx.Ebp-ctx.Esp+8;
+					if ( dump_length <= 0 )
+						dump_length = 16*4;
+				}
+				int top = dbg.stack.data.length>dump_length?dump_length:dbg.stack.data.length;
+				dumpMemory(dbg.stack.top_ptr, top, dbg.stack.data);
+				break;
+			case "dm":
+				if ( lastcmd.length < 3 ) {
+					DbgIO.println("usage: dm <start> <length>");
+					break;
+				}
+				uint start;
+				sscanf(toStringz(lastcmd[1]), "%x", &start);
+				dumpMemory(start, cast(uint)atoi(lastcmd[2]));
+				break;
+
+			// unknown command
+			default:
+				DbgIO.println("Warning: Unknown command '%s' ignored!", lastcmd[0]);
+				break;
+		}
+
+		return false;
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void dumpMemory(uint start, uint length, ubyte[] _data=null)
+	{
+		ubyte[]	data;
+		if ( _data is null )
+		{
+			data.length = length;
+			if ( !dbg.process.readProcessMemory(start, data.ptr, data.length) )
+				return;
+		}
+		else
+			data = _data;
+		for ( uint i = 0; i < length; ++i )
+		{
+			if ( i % (8*4) == 0 )
+			{
+				if ( i > 0 )
+					DbgIO.println("");
+				DbgIO.print("0x%08x:", start+i);
+			}
+			DbgIO.print(" 0x%02x", data[i]);
+		}
+		DbgIO.println("");
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	void evalStackSymbols(StackSymbol[] symbols)
+	{
+		foreach ( sym; symbols )
+		{
+            string name = sym.mangled_name;
+            DbgIO.print("%s = ", name);
+            try DbgIO.writeln(symbolValueToString(dbg.handleData(dbg.evaluateExpression(name, current_frame_level, sym), true)));
+            catch ( EvaluationException e ) {
+                DbgIO.println(e.msg);
+            }
+		}
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+    void printAsmLine(uint address, string bytes, string asmsource, string symbol, string location, string source)
+	{
+	    bool nl = false;
+        if ( location !is null ) {
+            DbgIO.print("0x%08x <??>: // ", address);
+            DbgIO.write(location);
+            nl = true;
+        }
+        if ( source !is null )
+        {
+            if ( !nl )
+				DbgIO.print("0x%08x <??>: // ", address);
+            DbgIO.write(source);
+            nl = true;
+        }
+        if ( nl )
+            DbgIO.println;
+
+		assert(asmsource !is null);
+		DbgIO.print("0x%08x <??>: ", address, asmsource);
+
+		if ( symbol !is null )
+			DbgIO.write(symbol);
+		DbgIO.println;
+	}
+
+    /**********************************************************************************************
+        Prints the register contents of the given thread's context.
+    **********************************************************************************************/
+	void printRegisterDump(DbgThread thread)
+	{
+		CONTEXT ctx;
+		if ( thread.getContext(ctx) )
+		{
+			DbgIO.println("eax\t0x%x -\nebx\t0x%x -\necx\t0x%x -\nedx\t0x%x -", ctx.Eax, ctx.Ebx, ctx.Ecx, ctx.Edx);
+			DbgIO.println("cs\t0x%x -\nds\t0x%x -\nes\t0x%x -\nfs\t0x%x -", ctx.SegCs, ctx.SegDs, ctx.SegEs, ctx.SegFs);
+			DbgIO.println("gs\t0x%x -\nss\t0x%x -\nedi\t0x%x -\nesi\t0x%x -", ctx.SegGs, ctx.SegSs, ctx.Edi, ctx.Esi);
+			DbgIO.println("ebp\t0x%x -\nesp\t0x%x -\neip\t0x%x -\neflags\t0x%x -", ctx.Ebp, ctx.Esp, ctx.Eip, ctx.EFlags);
+		}
+		else
+			DbgIO.println("Warning: Couldn't get main thread's context");
+	}
+
+    /**********************************************************************************************
+
+    **********************************************************************************************/
+	string symbolValueToString(SymbolValue val)
+	{
+	    string str;
+	    if ( val.name !is null )
+            str = val.name~" = ";
+        if ( val.value !is null )
+            str ~= val.value;
+        else
+        {
+            if ( val.children.length > 0 )
+            {
+                str ~= "{";
+                bool first = true;
+                foreach ( c; val.children )
+                {
+                    if ( first )
+                        first = false;
+                    else
+                        str ~= ",";
+                    str ~= symbolValueToString(c);
+                }
+                str ~= "}";
+            }
+            else
+                str ~= "{}";
+        }
+        return str;
+	}
+
+    /**********************************************************************************************
+        Read command and call CLI supplied parser function.
+        Gets called when debuggee is suspended.
+    **********************************************************************************************/
+	bool readCommand()
+	{
+	    if ( cmdQueue.length > 0 )
+	    {
+	        string cmd = strip(cmdQueue[0]);
+	        cmdQueue = cmdQueue[1..$];
+            DbgIO.writeln(prompt~cmd);
+	        return parseCommand(cmd);
+	    }
+	    else {
+            DbgIO.write(prompt);
+            string input = DbgIO.readln();
+            return parseCommand(input);
+	    }
+	}
+}