view src/expression/datahandler.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 source

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

import std.string;
import std.utf;

import codeview.codeview;
import codeview.decl;
import dbgprocess;
import util;
import minidump;
import expression.evaluationcontext;

import internal.aaA;

T min(T)(T a, T b)
{
    return a<b?a:b;
}

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

**************************************************************************************************/
class SymbolValue
{
    string          name,
                    value;
    SymbolValue[]   children;

    this() {}

    this(string v)
    {
        value = v;
    }

    this(string n, string v)
    {
        name = n;
        value = v;
    }
}


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

**************************************************************************************************/
class DataHandler
{
	static DataHandler[string] s_dataHandlerRegistry;
	static uint max_elem_count = 32;

	static this()
	{
		s_dataHandlerRegistry["b"] = new DataHandler_bool;
		s_dataHandlerRegistry["a"] = new DataHandler_num;
		s_dataHandlerRegistry["w"] = new DataHandler_num;
		s_dataHandlerRegistry["u"] = new DataHandler_num;
		s_dataHandlerRegistry["g"] = new DataHandler_num;
		s_dataHandlerRegistry["h"] = new DataHandler_num;
		s_dataHandlerRegistry["i"] = new DataHandler_num;
		s_dataHandlerRegistry["l"] = new DataHandler_num;
		s_dataHandlerRegistry["k"] = new DataHandler_num;
		s_dataHandlerRegistry["m"] = new DataHandler_num;
		s_dataHandlerRegistry["s"] = new DataHandler_num;
		s_dataHandlerRegistry["t"] = new DataHandler_num;
		s_dataHandlerRegistry["v"] = new DataHandler_num;
		s_dataHandlerRegistry["f"] = new DataHandler_num;
		s_dataHandlerRegistry["d"] = new DataHandler_num;
		s_dataHandlerRegistry["e"] = new DataHandler_num;
		s_dataHandlerRegistry["x"] = new DataHandler_num;
		s_dataHandlerRegistry["Aa"] = new DataHandler_string;
		s_dataHandlerRegistry["Au"] = new DataHandler_string;
		s_dataHandlerRegistry["Aw"] = new DataHandler_string;
		s_dataHandlerRegistry["P*"] = new DataHandler_num;
		s_dataHandlerRegistry["A*"] = new DataHandler_A;
		s_dataHandlerRegistry["G*"] = new DataHandler_G;
		s_dataHandlerRegistry["S*"] = new DataHandler_SCU;
		s_dataHandlerRegistry["C*"] = new DataHandler_SCU;
		s_dataHandlerRegistry["PC*"] = new DataHandler_SCU;
		s_dataHandlerRegistry["E*"] = new DataHandler_E;
		s_dataHandlerRegistry["H*"] = new DataHandler_H;
	}

    static SymbolValue handle(EvaluationContext ctx, string type, ubyte[] data, int depth)
    {
		if ( type.length <= 0 )
			return null;

		DataHandler* handler = type in s_dataHandlerRegistry;
		if ( type.length > 1 && handler is null )
			handler = type[0..2]~"*" in s_dataHandlerRegistry;
		if ( handler is null )
			handler = type[0]~"*" in s_dataHandlerRegistry;

        SymbolValue val;
		if ( handler !is null ) {
			debug(datahandler) DbgIO.println("%s is handling data", handler.classinfo.name);
			val = handler.toString(ctx, type, data, depth);
		}
		return val;
	}

	abstract SymbolValue toString(EvaluationContext ctx, string mangled_type, ubyte[] data, int depth);
}

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

**************************************************************************************************/
class DataHandler_H : DataHandler
{
	SymbolValue toString(EvaluationContext ctx, string mangled_type, ubyte[] data, int depth)
	{
	    SymbolValue val = new SymbolValue;

		size_t ptr = (cast(size_t[])data)[0];
		if ( ptr == 0 ) {
			val.value = "null";
	        return val;
		}

	    if ( depth == 0 ) {
	        val.value = "...";
	        return val;
	    }

		int i;
		pragma(msg, TODO(__FILE__,__LINE__,"allow named types (C,S,D,F, etc.)"));
		for ( i = 1; i < mangled_type.length && find(lowercase, mangled_type[i]) < 0; ++i ) {}

		string		key_type	= mangled_type[1..i+1],
					val_type	= mangled_type[i+1..$];
        size_t      val_tsize   = ctx.codeView.sizeofMangled(val_type),
                    key_tsize	= ctx.codeView.sizeofMangled(key_type);

        if ( key_type.length == 0 ) {
            val.value = "invalid key type "~key_type;
            return val;
        }
        if ( val_type.length == 0 ) {
            val.value = "invalid val type "~val_type;
            return val;
        }

		bool evalaaA(void* ptr)
		{
			if ( ptr is null )
				return true;
			ubyte[] data;
			size_t len = aaA.sizeof+key_tsize+val_tsize;
			data = ctx.readMemory(cast(size_t)ptr, len);
			if ( data is null )
                return false;

			uint i=aaA.sizeof;
			SymbolValue k = handle(ctx, key_type, data[i..i+key_tsize], depth>0?depth-1:depth);
			i += key_tsize;
			SymbolValue v = handle(ctx, val_type, data[i..i+val_tsize], depth>0?depth-1:depth);
			v.name = k.value;
			val.children ~= v;
			return true;
		}

		bool evalBB(uint ptr)
		{
			ubyte[] data = ctx.readMemory(cast(size_t)ptr, BB.sizeof);
			if ( data is null )
                return false;

			BB* bb = cast(BB*)data.ptr;
            size_t blen = bb.b.length*size_t.sizeof;
			debug DbgIO.println("%d nodes, bb.b.length=%d", bb.nodes, bb.b.length);

			data = ctx.readMemory(cast(size_t)bb.b.ptr, blen);
			if ( data is null )
                return false;
			bb.b = cast(aaA*[])data;

			foreach ( a; bb.b )
			{
			    if ( !evalaaA(a) )
                    return false;
			}
			return true;
		}

		if ( !evalBB(ptr) )
            val.value = format("invalid AA pointer 0x%x", ptr);

		return val;
	}
}

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

**************************************************************************************************/
class DataHandler_E : DataHandler
{
	SymbolValue toString(EvaluationContext ctx, string mangled_type, ubyte[] data, int depth)
	{
	    SymbolValue val = new SymbolValue;
		string	mangled = mangled_type[1..$].dup,
				name;
 		name = demangleNameSkip(mangled);
		if ( (name in ctx.codeView.UDTsByName) !is null )
		{
			LeafEnum lf = cast(LeafEnum)ctx.codeView.UDTsByName[name];
			if ( lf is null ) {
				val.value = "invalid codeview information for enum type "~name;
				return val;
			}
			uint index = lf.field-0x1000;
			if ( index >= ctx.codeView.type_strings.length ) {
				val.value = "invalid codeview information for enum type "~name;
				return val;
			}
			LeafFieldList fields = cast(LeafFieldList)ctx.codeView.type_strings[lf.field-0x1000][0];
			if ( fields is null ) {
				val.value = "invalid codeview information for enum type "~name;
				return val;
			}
			assert(data.length >= 4);
			uint value = (cast(uint[])data)[0];
			foreach ( f; fields.fields )
			{
				LeafEnumNameValue ef = cast(LeafEnumNameValue)f;
				assert(ef !is null);
				if ( ef.value.getUint == value ) {
					val.value = ef.name;
					return val;
				}
			}
			val.value = "invalid enum value";
		}
		else
			val.value = "unknown enum type "~name;
        return val;
	}
}

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

**************************************************************************************************/
class DataHandler_SCU : DataHandler
{
	SymbolValue toString(EvaluationContext ctx, string mangled_type, ubyte[] data, int depth)
	{
	    SymbolValue val = new SymbolValue;

		string	scu_name_mangled,
				scu_name;
		if ( mangled_type[0] == 'P' )
		{
		    assert(data.length==size_t.sizeof);
            if ( *cast(size_t*)data.ptr == 0 ) {
                val.value = "null";
                return val;
            }
			scu_name_mangled = mangled_type[2..$].dup;
		}
		else
			scu_name_mangled = mangled_type[1..$].dup;
 		scu_name = demangleNameSkip(scu_name_mangled);

	    if ( depth == 0 ) {
	        val.value = "...";
	        return val;
	    }

		if ( (scu_name in ctx.codeView.UDTsByName) is null ) {
            val.value = format("unknown type %s", scu_name);
            return val;
		}

		LeafClassStruc  lcs;
		LeafUnion       lu;

		LeafFieldList   lfl;
		uint            type_length;

        lcs = cast(LeafClassStruc)ctx.codeView.UDTsByName[scu_name];
        debug DbgIO.println("%s %x", scu_name, lcs.field);
        if ( lcs !is null && lcs.field-0x1000 < ctx.codeView.type_strings.length ) {
            lfl = cast(LeafFieldList)ctx.codeView.type_strings[lcs.field-0x1000][0];
            type_length = lcs.length.getUint();
        }
        else
        {
            lu = cast(LeafUnion)ctx.codeView.UDTsByName[scu_name];
            if ( lu !is null && lu.field-0x1000 < ctx.codeView.type_strings.length ) {
                lfl = cast(LeafFieldList)ctx.codeView.type_strings[lu.field-0x1000][0];
                type_length = lu.length.getUint();
            }
        }

		if ( lfl is null ) {
			val.value = "{no debug symbols available}";
			return val;
		}

		ubyte[] tmpdata;
		if ( mangled_type[0] == 'P' || mangled_type[0] == 'C' )
		{
			assert(data.length==size_t.sizeof);
			debug(datahandler) DbgIO.println("dereferencing class/struct reference at 0x%x", *cast(size_t*)data.ptr);
			tmpdata = ctx.readMemory(*cast(size_t*)data.ptr, type_length);
			if ( tmpdata is null ) {
				val.value = format("invalid class pointer 0x%08x", *cast(size_t*)data.ptr);
				return val;
			}
		}
		else
			tmpdata = data;

		void listMembers(LeafFieldList lfl, SymbolValue root)
		{
			foreach ( l; lfl.fields )
			{
				if ( l.leaf_index == LF_BCLASS_16t )
				{
					LeafBaseClass lbc = cast(LeafBaseClass)l;
					assert ( lbc !is null );
					if ( lbc.type-0x1000 >= ctx.codeView.type_strings.length ) {
						root.children ~= new SymbolValue("unknown base class "~format("0x%04x", lbc.type));
						continue;
					}
					LeafClassStruc lcs = cast(LeafClassStruc)ctx.codeView.type_strings[lbc.type-0x1000][0];
					assert ( lcs !is null );
					if ( lcs.field == 0 )
						continue;
					if ( lcs.field-0x1000 >= ctx.codeView.type_strings.length ) {
						root.children ~= new SymbolValue("unknown field list "~format("0x%04x", lcs.field));
						continue;
					}
					Leaf[] fields = ctx.codeView.type_strings[lcs.field-0x1000];
					debug(datahandler) DbgIO.println("processing base class ", lcs.name);

                    SymbolValue v = new SymbolValue;
                    v.name = lcs.name;
                    listMembers(cast(LeafFieldList)fields[0], v);
					root.children ~= v;
				}
				else if ( l.leaf_index == LF_MEMBER_16t )
				{
					LeafMember lm = cast(LeafMember)l;
					assert ( lm !is null );
					uint	size	= ctx.codeView.sizeofCV(lm.type),
							offset	= lm.offset.getUint;

                    LeafPointer lp;
                    bool seen_type;
                    if ( lm.type >= 0x1000 && lm.type-0x1000 < ctx.codeView.type_strings.length )
                        lp = cast(LeafPointer)ctx.codeView.type_strings[lm.type-0x1000][0];
                    if ( depth > 0 )
                    {
                        debug(datahandler) DbgIO.println("processing member %s cvtype 0x%x mangled %s", lm.name, lm.type, ctx.codeView.mangleCVtype(lm.type));
                        if ( offset+size > tmpdata.length )
                            root.children ~= new SymbolValue(lm.name, format("invalid: offset=0x%x size=%d", offset, size));
                        else
                        {
                            SymbolValue v = handle(ctx, ctx.codeView.mangleCVtype(lm.type), tmpdata[offset..offset+size], depth>0?depth-1:depth);
                            if ( v !is null ) {
                                v.name = lm.name;
                                root.children ~= v;
                            }
                            else
                                root.children ~= new SymbolValue(lm.name, "null");
                        }
                    }
				}
			}
		}

        listMembers(lfl, val);
		return val;
	}
}

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

**************************************************************************************************/
class DataHandler_A : DataHandler
{
	SymbolValue toString(EvaluationContext ctx, string mangled_type, ubyte[] data, int depth)
	{
	    SymbolValue val = new SymbolValue;
		size_t[] idata  = cast(size_t[])data;

		if ( idata[1] == 0 ) {
			val.value = "null";
			return val;
		}

	    if ( depth == 0 ) {
	        val.value = "...";
	        return val;
	    }

		mangled_type = mangled_type[1..$];
		uint    elm_size    = ctx.codeView.sizeofMangled(mangled_type);
		size_t  alen        = min(idata[0],max_elem_count)*elm_size;

		ubyte[]	tmpdata = ctx.readMemory(idata[1], alen);
		if ( tmpdata is null )
			val.value = format("invalid array: ptr=0x%08x $=%d", idata[1], idata[0]);
        else
        {
            uint off_end = tmpdata.length;
            for ( uint i = 0, off=0; off < off_end; ++i, off+=elm_size ) {
                SymbolValue v = handle(ctx, mangled_type, tmpdata[off..off+elm_size], depth>0?depth-1:depth);
                if ( v is null )
                    val.children ~= new SymbolValue("["~.toString(i)~"]", "null");
                else {
                    v.name = "["~.toString(i)~"]";
                    val.children ~= v;
                }
            }
            if ( idata[0] > max_elem_count )
                val.children ~= new SymbolValue("... $", format("%d", idata[0]));
        }
		return val;
	}
}

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

**************************************************************************************************/
class DataHandler_G : DataHandler
{
	SymbolValue toString(EvaluationContext ctx, string mangled_type, ubyte[] data, int depth)
	{
        SymbolValue val = new SymbolValue;

	    if ( depth == 0 ) {
	        val.value = "...";
	        return val;
	    }

        mangled_type = mangled_type[1..$];
        uint	count       = parseNumber(mangled_type),
                elm_size    = ctx.codeView.sizeofMangled(mangled_type),
                off_end     = min(count,max_elem_count)*elm_size;
        if ( count*elm_size != data.length )
            throw new EvaluationException("unexpected data length: have "~.toString(data.length)~" should be "~.toString(count*elm_size));
        for ( uint i = 0, off=0; off < off_end; ++i, off+=elm_size ) {
            SymbolValue v = handle(ctx, mangled_type, data[off..off+elm_size], depth>0?depth-1:depth);
            if ( v is null )
                val.children ~= new SymbolValue("["~.toString(i)~"]", "null");
            else {
                v.name = "["~.toString(i)~"]";
                val.children ~= v;
            }
        }
        if ( count > max_elem_count )
            val.children ~= new SymbolValue("... $", format("%d", count));
		return val;
	}
}

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

**************************************************************************************************/
class DataHandler_string : DataHandler
{
	SymbolValue toString(EvaluationContext ctx, string mangled_type, ubyte[] data, int depth)
	{
	    SymbolValue val = new SymbolValue;

        string str;
		uint[] idata = cast(uint[])data;
		if ( idata[1] == 0 ) {
		    val.value = "null";
		    return val;
		}

        assert(mangled_type[0] == 'A');

        switch ( mangled_type[1] )
        {
            case 'a':
                str = cast(string)ctx.readMemory(idata[1], idata[0]);
                if ( str is null ) {
                    val.value = format("invalid string: ptr=0x%08x $=%d", idata[1], idata[0]);
                    return val;
                }
                break;
            case 'u':
                wstring wstr;
                size_t len = idata[0]*wchar.sizeof;

                wstr = cast(wstring)ctx.readMemory(idata[1], len);
                if ( wstr is null ) {
                    val.value = format("invalid string: ptr=0x%08x $=%d", idata[1], idata[0]);
                    return val;
                }
                str = toUTF8(wstr);
                break;
            case 'w':
                dstring dstr;
                size_t len = idata[0]*dchar.sizeof;

                dstr = cast(dstring)ctx.readMemory(idata[1], len);
                if ( dstr is null ) {
                    val.value = format("invalid string: ptr=0x%08x $=%d", idata[1], idata[0]);
                    return val;
                }
                str = toUTF8(dstr);
                break;
            default:
                assert(0);
        }
        val.value = "\""~replace(replace(str, "\\", "\\\\"), "\"", "\\\"")~"\"";
		return val;
	}
}

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

**************************************************************************************************/
class DataHandler_num : DataHandler
{
	SymbolValue toString(EvaluationContext ctx, string mangled_type, ubyte[] data, int depth)
	{
	    SymbolValue val = new SymbolValue;
		switch ( mangled_type[0] )
		{
			case 'a':
				val.value = (cast(char[])data)[0..1];
				break;
			//~ case 'u':
                //~ val.value = toUTF8((cast(wchar[])data)[0..1]);
				//~ break;
			case 'w':
                val.value = toUTF8((cast(dchar[])data)[0..1]);
				break;
			case 'g':
				val.value = format("%d", (cast(byte[])data)[0]);
				break;
			case 'h':
				val.value = format("%d", (cast(ubyte[])data)[0]);
				break;
			case 's':
				val.value = format("%d", (cast(short[])data)[0]);
				break;
			case 't':
			case 'u':
				val.value = format("%d", (cast(ushort[])data)[0]);
				break;
			case 'i':
				val.value = format("%d", (cast(int[])data)[0]);
				break;
			case 'P':
			case 'v':
			case 'k':
				val.value = format("0x%08x", (cast(uint[])data)[0]);
				break;
			case 'l':
				val.value = format("%d", (cast(long[])data)[0]);
				break;
			case 'm':
				val.value = format("%d", (cast(ulong[])data)[0]);
				break;
			case 'f':
				val.value = format("% .6g", (cast(float[])data)[0]);
				break;
			case 'd':
				val.value = format("% .12g", (cast(double[])data)[0]);
				break;
			case 'e':
				val.value = format("% .16g", (cast(real[])data)[0]);
				break;
			case 'x':
			case 'b':
				val.value = format("%s", (cast(bool[])data)[0]?"true":"false");
				break;
			default:
				assert(0, mangled_type);
		}
		return val;
	}
}


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

**************************************************************************************************/
class DataHandler_bool : DataHandler
{
	SymbolValue toString(EvaluationContext ctx, string mangled_type, ubyte[] data, int depth)
	{
	    SymbolValue val = new SymbolValue;
		assert(mangled_type[0]=='b');
		val.value = format("%s", (cast(bool[])data)[0]);
		return val;
	}
}