view src/cli/userinterface.d @ 5:496dfd8f7342 default tip

added: -repeat option for "in", "ov" -run until a line option -run until a function option -break on a function start -n is an alias for ov
author marton@basel.hu
date Sun, 17 Apr 2011 11:05:31 +0200
parents 4a9dcbd9e54f
children
line wrap: on
line source

/*  Ddbg - Win32 Debugger for the D programming language
 *  Copyright (c) 2007 Jascha Wetzel
 *  All rights reserved. See LICENSE.TXT for details.
 */
module cli.userinterface;

import breakpoint;
import dbgprocess;
import dbgthread;
import debugger;
import expression.datahandler;
import codeview.codeview;
import util;
import disasm;
import codeview.coff;

import win32.winnt;

import std.string;
import std.c.string;
import std.utf;

interface UserInterface
{
	void    init(string[] args);
	int     start();

	bool    readCommand();
	bool    parseCommand(string cmd);
	void    runCommands(string cmdstr);

	void    debugString(string str);
	bool    breakpoint(int index, Breakpoint bp, DbgThread thread);
	void    userInterrupt();
	void    exception(uint threadId, string class_name, string msg, size_t obj_ptr);
	void    win32exception(uint threadId, EXCEPTION_RECORD* exrec);
	void    loadedDLL(DLL dll);
	void    exitProcess();
	void    singleStep();
}

struct StackTraceEntry
{
    uint        index;
    Location    loc;
    uint        frame_level;
    CodeBlock   last_known_cb;

    void describe(UserInterfaceBase ui)
    {
        DbgIO.print("#%d ", index);
        if ( loc is null ) {
            DbgIO.println("<no debug symbols available>");
            return;
        }
        if ( index > 0 )
            DbgIO.print("0x%08x in ", loc.address);
        if ( loc.scope_sym !is null )
        {
            ProcedureSymbol psym = cast(ProcedureSymbol)loc.scope_sym;

            string argstr;
            bool first = true;
            foreach_reverse ( argsym; psym.arguments.stack_symbols )
            {
                string name = argsym.name_notype;
                if ( !first )
                    argstr ~= ", ";
                else
                    first = false;
                argstr ~= argsym.name_notype;
                try {
                    SymbolValue symval = ui.dbg.handleData(ui.dbg.evaluateExpression(name, frame_level), false);
                    argstr ~= " = "~ui.symbolValueToString(symval);
                }
                catch ( Exception e ) {
                }
            }
            int end = find(psym.name_type, '('),
                start = find(psym.name_type, ' ');
            if ( end < 0 )
                end = psym.name_type.length;
            if ( start < 0 )
                start = 0;
            if ( end-start < 2 )
                start = 0;
            DbgIO.print("%s (", psym.name_type[start..end]);
            DbgIO.write(argstr~") ");
        }
        else if ( loc.data_sym !is null )
            DbgIO.print(loc.data_sym.name_type, " () ");
        else
            DbgIO.print("?? () ");
        if ( loc.codeblock !is null )
            DbgIO.print("at %s:%d", loc.file, loc.line);
        else
        {
            if ( last_known_cb !is null && last_known_cb.segment !is null )
                DbgIO.print("at %s:%d ", last_known_cb.segment.file.name, last_known_cb.line);
            if ( loc.mod !is null )
                DbgIO.print("from %s", loc.mod.name);
            else if ( ui.dbg.process !is null )
            {
                DLL dll = ui.dbg.process.findDLL(loc.address);
                if ( dll !is null )
                    DbgIO.print("from %s", dll.image.name);
            }
        }
        DbgIO.println("");
    }
}

abstract class UserInterfaceBase : UserInterface
{
	CodeBlock	last_codeblock;
	Module		last_module;
	DLL			last_dll;

	Debugger dbg;

    string[]    cmdQueue;

    void printAsmLine(uint address, string bytes, string asmsource, string symbol, string location, string source);
	string symbolValueToString(SymbolValue val);

    /**********************************************************************************************

    **********************************************************************************************/
	void unwindStack()
	{
        StackTraceEntry[] entries;

		uint	index,
				counter,
				frame_level;
        debug DbgIO.println("Stack: base 0x%x top 0x%x frame 0x%x", dbg.stack.base_ptr, dbg.stack.top_ptr, dbg.stack.frame_ptr);
		Location loc = dbg.images.findLocation(dbg.current_address);
        if ( loc is null )
            loc = new Location(dbg.current_address, null);
		entries ~= StackTraceEntry(counter++, loc, frame_level);

		dbg.stack.firstFrame(index);
		ubyte[] frame = dbg.stack.prevFrame(index, index);
        size_t next_frame=1;
		while ( frame !is null )
		{
			uint ret_adr = (cast(uint[])frame)[1];
			loc = dbg.images.findLocation(ret_adr);
            if ( loc is null )
                loc = new Location(ret_adr, null);
			frame = dbg.stack.prevFrame(index, index);
			++frame_level;
            if ( next_frame >= entries.length )
                entries.length = entries.length*2+1;
			entries[next_frame++] = StackTraceEntry(counter++, loc, frame_level);
		}
        entries.length = next_frame;
        
        CodeBlock last_known_cb;
        foreach_reverse ( ref ste; entries )
        {
            if ( ste.loc !is null && ste.loc.codeblock !is null )
                last_known_cb = ste.loc.codeblock;
            else
                ste.last_known_cb = last_known_cb;
        }
        
        foreach ( ste; entries )
            ste.describe(this);
	}

    /**********************************************************************************************
        Prints an instruction with looked up symbols if existant.
    **********************************************************************************************/
	bool printDisassembly(ud_t* ud_obj)
	{
		// first call
		if ( ud_obj is null ) {
			last_codeblock = null;
			return true;
		}

		uint    address = cast(uint)ud_insn_off(ud_obj);
		string  source, location;

		// check whether we have symbols here
		Location loc = dbg.images.findLocation(address);
		if ( loc.codeblock !is null )
		{
			if ( last_codeblock !is loc.codeblock )
			{
				last_codeblock = loc.codeblock;
				string[] source_file = dbg.getSourceFile(loc.file);
                location = format("%s:%d", loc.file, loc.line);
				if ( source_file !is null && loc.line <= source_file.length )
					source = source_file[loc.line-1];
			}
		}
		else
		{
            CodeView cv;
			CodeBlock cb = dbg.images.findCodeBlockRel(address, cv);
			if ( cb !is null )
			{
				if ( last_codeblock !is cb )
					last_codeblock = cb;
			}
			else
			{
				uint seg;
				Module mod = dbg.images.findModule(address, seg);
				if ( mod !is null && last_module !is mod ) {
					last_module = mod;
					location = mod.name;
				}
				else
				{
					DLL dll = dbg.process.findDLL(address);
					if ( dll !is null && last_dll !is dll ) {
						last_dll = dll;
						location = dll.image.name;
					}
				}
			}
		}

		string symbol;
		bool is_imm=true;
		uint jmp_dest = DisAsm.calcJumpDestination(dbg.process, dbg.process.threads[dbg.thread_id], ud_obj, is_imm);
		if ( is_imm && jmp_dest>0 )
			symbol = "\t"~describeLocation(jmp_dest, false);

		char* hex = ud_insn_hex(ud_obj);
		uint hexlen = strlen(hex);
		char* ins = ud_insn_asm(ud_obj);

		printAsmLine(address, hex[0..hexlen], ins[0..strlen(ins)], symbol, location, source);
		return true;
	}

     /**********************************************************************************************
      prints information about symbol (not recursive)
    **********************************************************************************************/

        void printSymbol( NamedSymbol ns, uint indent=0)
	{
		
		{
			

			char[] indent_str;
			indent_str.length = indent*2;
			indent_str[0..indent*2] = ' ';
			ClassInfo cs = ns.classinfo;
			if ( cs == ProcedureSymbol.classinfo )
			{
			    ProcedureSymbol ps = cast(ProcedureSymbol)ns;
			   
				DbgIO.println("%s%s %d arguments",
                    indent_str, ps.name_type, ps.arguments.symbols.length
                );
			}
			else if ( cs == StackSymbol.classinfo ) {
				StackSymbol ss = cast(StackSymbol)ns;
				DbgIO.println("%s%s stack (%s) %x ebp%s%d", indent_str, ns.name_type, ns.mangled_name, ss.cvtype, ss.offset>=0?"+":"", ss.offset);
			}
			else if ( cs == DataSymbol.classinfo )
            {
				DataSymbol ds = cast(DataSymbol)ns;
				DbgIO.println("%s%s (%s) data offset: 0x%x size: 0x%x segment: 0x%x type: 0x%x (%s)", indent_str, ds.name_type, ds.name_notype,
					ds.offset, ds.size, ds.cvdata.segment, ds.cvdata.type, dbg.images.mangleCVtype(ds.cvdata.type)
				);
			}
			else
				DbgIO.println("%s%s %s", indent_str, ns.name_type, cs.name);
			ScopeSymbol scs = cast(ScopeSymbol)ns;
			//if ( scs !is null )
			//	printSymbols(cv, scs.symbols.named_symbols, indent+1);
		}
	}

    /**********************************************************************************************
      prints symbols that contain substring with indentation indent
    **********************************************************************************************/
	void printSymbols(CodeView cv, NamedSymbol[] syms, string substring=null, uint indent=0)
	{
		foreach ( ns; syms )
		{
			if ( substring.length > 0 && find(ns.name_notype, substring)<0 )
				continue;

			char[] indent_str;
			indent_str.length = indent*2;
			indent_str[0..indent*2] = ' ';
			ClassInfo cs = ns.classinfo;
			if ( cs == ProcedureSymbol.classinfo )
			{
			    ProcedureSymbol ps = cast(ProcedureSymbol)ns;
			    size_t start = ps.cvdata.offset+cv.getCodeBase;
				DbgIO.println("%s%s %d arguments, entry 0x%x, debug start 0x%x, debug end 0x%x",
                    indent_str, ps.name_type, ps.arguments.symbols.length, start,
                    start+ps.cvdata.debug_start, start+ps.cvdata.debug_end
                );
			}
			else if ( cs == StackSymbol.classinfo ) {
				StackSymbol ss = cast(StackSymbol)ns;
				DbgIO.println("%s%s stack (%s) %x ebp%s%d", indent_str, ns.name_type, ns.mangled_name, ss.cvtype, ss.offset>=0?"+":"", ss.offset);
			}
			else if ( cs == DataSymbol.classinfo )
            {
				DataSymbol ds = cast(DataSymbol)ns;
				DbgIO.println("%s%s (%s) data offset: 0x%x size: 0x%x segment: 0x%x type: 0x%x (%s)", indent_str, ds.name_type, ds.name_notype,
					ds.offset, ds.size, ds.cvdata.segment, ds.cvdata.type, dbg.images.mangleCVtype(ds.cvdata.type)
				);
			}
			else
				DbgIO.println("%s%s %s", indent_str, ns.name_type, cs.name);
			ScopeSymbol scs = cast(ScopeSymbol)ns;
			if ( scs !is null )
				printSymbols(cv, scs.symbols.named_symbols, substring, indent+1);
		}
	}

    /**********************************************************************************************

    **********************************************************************************************/
	string describeLocation(uint vaddress, bool with_address=true)
	{
		Location loc = dbg.images.findLocation(vaddress);
		return describeLocation(loc, with_address);
	}

    /**********************************************************************************************

    **********************************************************************************************/
	string describeLocation(Location loc, bool with_address=true)
	{
		string desc;

		if ( loc is null )
			return "unknown";

		if ( loc.codeblock !is null )
			desc = format("%s:%d", loc.file, loc.line);
		if ( with_address )
			desc ~= (desc.length>0?" ":"")~format("(0x%08x)", loc.address);

		if ( loc.scope_sym !is null )
			return loc.scope_sym.name_notype~" "~desc;
		if ( loc.data_sym !is null )
			return loc.data_sym.name_notype~" "~desc;
		if ( loc.mod !is null )
			return loc.mod.name~" "~desc;
        if ( dbg.process !is null )
        {
            DLL dll = dbg.process.findDLL(loc.address);
            if ( dll !is null )
                return dll.image.name~" "~desc;
        }

		return desc;
	}

    /**********************************************************************************************

    **********************************************************************************************/
	void runCommands(string cmd_string)
	{
        cmd_string = replace(cmd_string, "\\\"", "\"");
        auto r = std.regexp.RegExp("(([^;\" \\t]+)|(\"[^\"]+\"))+|;");
        string cmd;
        string[] cmds;
        foreach ( m; r.search(cmd_string) )
        {
            if ( m.match(0) == ";" ) {
                cmdQueue ~= cmd~";";
                cmd = null;
            }
            else
                cmd ~= " "~m.match(0);
        }
        if ( cmd !is null )
            cmdQueue ~= cmd~";";
	}
}