view src/util.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.
 */

import std.ctype;
import std.stdio;
import std.string;
import std.c.string;
import std.c.stdio;
import std.format;
import std.date : getUTCtime, d_time, TicksPerSecond;
import std.demangle;

import win32.winbase;
import win32.windef;

import std.typeinfo.ti_AC;
import std.typeinfo.ti_Acdouble;
import std.typeinfo.ti_Acfloat;
import std.typeinfo.ti_Acreal;
import std.typeinfo.ti_Adouble;
import std.typeinfo.ti_Afloat;
import std.typeinfo.ti_Ag;
import std.typeinfo.ti_Aint;
import std.typeinfo.ti_Along;
import std.typeinfo.ti_Areal;
import std.typeinfo.ti_Ashort;
import std.typeinfo.ti_byte;
import std.typeinfo.ti_C;
import std.typeinfo.ti_cdouble;
import std.typeinfo.ti_cfloat;
import std.typeinfo.ti_char;
import std.typeinfo.ti_creal;
import std.typeinfo.ti_dchar;
import std.typeinfo.ti_delegate;
import std.typeinfo.ti_double;
import std.typeinfo.ti_float;
import std.typeinfo.ti_idouble;
import std.typeinfo.ti_ifloat;
import std.typeinfo.ti_int;
import std.typeinfo.ti_ireal;
import std.typeinfo.ti_long;
import std.typeinfo.ti_ptr;
import std.typeinfo.ti_real;
import std.typeinfo.ti_short;
import std.typeinfo.ti_ubyte;
import std.typeinfo.ti_uint;
import std.typeinfo.ti_ulong;
import std.typeinfo.ti_ushort;
import std.typeinfo.ti_void;
import std.typeinfo.ti_wchar;

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

**************************************************************************************************/
T dmax(T)(T a, T b)
{
	return a<b?b:a;
}

T dmin(T)(T a, T b)
{
	return a>b?b:a;
}

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

**************************************************************************************************/
uint intFromStr(string str)
{
	uint i;
	foreach_reverse ( c; str )
		i = i<<8 | c;
	return i;
}

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

**************************************************************************************************/
string itoa(uint i)
{
    if ( i == 0 )
        return "0";
    string str;
    for ( ; i > 0; i /= 10 )
        str = "0123456789"[i%10] ~ str;
    return str;
}

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

**************************************************************************************************/
string TODO(string file, uint line, string msg)
{
	return "TODO - "~file~"("~itoa(line)~"): "~msg~"";
}

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

**************************************************************************************************/
string formatTicks(ulong ticks)
{
    SYSTEMTIME stime;
    if ( !FileTimeToSystemTime(cast(FILETIME*)&ticks, &stime) )
        return "invalid";
    string str = format("%02d:%02d:%02d.%03d", stime.wHour, stime.wMinute, stime.wSecond, stime.wMilliseconds);
    return str;
}

/**************************************************************************************************
    Name lookup for win32 DebugEventCodes.
**************************************************************************************************/
string getEventName(uint event)
{
	switch ( event )
	{
		case EXCEPTION_DEBUG_EVENT	: return "EXCEPTION_DEBUG_EVENT";
		case CREATE_THREAD_DEBUG_EVENT	: return "CREATE_THREAD_DEBUG_EVENT";
		case CREATE_PROCESS_DEBUG_EVENT	: return "CREATE_PROCESS_DEBUG_EVENT";
		case EXIT_THREAD_DEBUG_EVENT	: return "EXIT_THREAD_DEBUG_EVENT";
		case EXIT_PROCESS_DEBUG_EVENT	: return "EXIT_PROCESS_DEBUG_EVENT";
		case LOAD_DLL_DEBUG_EVENT	: return "LOAD_DLL_DEBUG_EVENT";
		case UNLOAD_DLL_DEBUG_EVENT	: return "UNLOAD_DLL_DEBUG_EVENT";
		case OUTPUT_DEBUG_STRING_EVENT	: return "OUTPUT_DEBUG_STRING_EVENT";
		case RIP_EVENT: return "RIP_EVENT";
		default : break;
	}
	return "";
}

/**************************************************************************************************
    Name lookup for win32 ExceptionCodes.
**************************************************************************************************/
string getExceptionName(uint excpt)
{
	switch ( excpt )
	{
		case EXCEPTION_ACCESS_VIOLATION	: return "EXCEPTION_ACCESS_VIOLATION";
		case EXCEPTION_ARRAY_BOUNDS_EXCEEDED	: return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
		case EXCEPTION_BREAKPOINT	: return "EXCEPTION_BREAKPOINT";
		case EXCEPTION_DATATYPE_MISALIGNMENT	: return "EXCEPTION_DATATYPE_MISALIGNMENT";
		case EXCEPTION_FLT_DENORMAL_OPERAND	: return "EXCEPTION_FLT_DENORMAL_OPERAND";
		case EXCEPTION_FLT_DIVIDE_BY_ZERO	: return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
		case EXCEPTION_FLT_INEXACT_RESULT	: return "EXCEPTION_FLT_INEXACT_RESULT";
		case EXCEPTION_FLT_INVALID_OPERATION	: return "EXCEPTION_FLT_INVALID_OPERATION";
		case EXCEPTION_FLT_OVERFLOW	: return "EXCEPTION_FLT_OVERFLOW";
		case EXCEPTION_FLT_STACK_CHECK	: return "EXCEPTION_FLT_STACK_CHECK";
		case EXCEPTION_FLT_UNDERFLOW	: return "EXCEPTION_FLT_UNDERFLOW";
		case EXCEPTION_ILLEGAL_INSTRUCTION	: return "EXCEPTION_ILLEGAL_INSTRUCTION";
		case EXCEPTION_IN_PAGE_ERROR	: return "EXCEPTION_IN_PAGE_ERROR";
		case EXCEPTION_INT_DIVIDE_BY_ZERO	: return "EXCEPTION_INT_DIVIDE_BY_ZERO";
		case EXCEPTION_INT_OVERFLOW	: return "EXCEPTION_INT_OVERFLOW";
		case EXCEPTION_INVALID_DISPOSITION	: return "EXCEPTION_INVALID_DISPOSITION";
		case EXCEPTION_NONCONTINUABLE_EXCEPTION	: return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
		case EXCEPTION_PRIV_INSTRUCTION	: return "EXCEPTION_PRIV_INSTRUCTION";
		case EXCEPTION_SINGLE_STEP	: return "EXCEPTION_SINGLE_STEP";
		case EXCEPTION_STACK_OVERFLOW	: return "EXCEPTION_STACK_OVERFLOW";
		default : break;
	}
	return "";
}

/**************************************************************************************************
    Wrapper for Win32 GetLastError.
**************************************************************************************************/
string lastError()
{
	char[4096] msg;
	FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, null, GetLastError(), 0, msg.ptr, msg.length, null);
	return msg[0..strlen(msg.ptr)];
}

/**************************************************************************************************
    Simplified number parser for prefixes.
    Returns: number represented by the prefix of name, 0 else
**************************************************************************************************/
uint parseNumber(inout string name)
{
	uint res;
	int i;
	while ( name.length > 0 )
	{
		if ( !isdigit(name[0]) )
			break;
		res = res*10+(name[0]-'0');
		name = name[1..$];
	}
	return res;
}

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

**************************************************************************************************/
string typeFromMangled(string mangled)
{
	if ( mangled is null || mangled.length < 4 || mangled[0..2] != "_D" || !isdigit(mangled[2]) )
		return null;
	string type = mangled[1..$];
	// skip symbol name
	while ( type.length > 1 && type[0] == 'D' && isdigit(type[1]) ) {
		type = type[1..$];
		uint len = parseNumber(type);
		type = type[len..$];
	}
	return type;
}

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

**************************************************************************************************/
string mangleName(string name)
{
	string		mangled;
	string[]	idents	= split(name, ".");
	foreach ( string id; idents )
		mangled ~= .toString(id.length)~id;
	return mangled;
}

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

**************************************************************************************************/
string demangleType(string mangled)
{
	return demangle("_D0"~mangled);
}

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

**************************************************************************************************/
string demangleNameSkip(inout string mangled)
{
	string name;
	do {
		uint len = parseNumber(mangled);
		if ( len <= 0 || len > mangled.length )
			return null;
		if ( name.length > 0 )
			name ~= ".";
		name ~= mangled[0..len];
		mangled = mangled[len..$];
	} while ( mangled.length > 0 );
	return name;
}

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

**************************************************************************************************/
string demangleName(string mangled)
{
	string name;
	if ( mangled.length > 2 && mangled[0..2] == "_D" && isNumeric(mangled[2]) )
        mangled = mangled[2..$];
    else
        return mangled;
	do {
		uint len = parseNumber(mangled);
        while ( len <= 0 && mangled.length > 0 ) {
            mangled = mangled[1..$];
            len = parseNumber(mangled);
        }
		if ( len <= 0 || len > mangled.length )
			return name;
		if ( name.length > 0 )
			name ~= ".";
		name ~= mangled[0..len];
		mangled = mangled[len..$];
	} while ( mangled.length > 0 );
	return name;
}

/**************************************************************************************************
    Wraps win32 stdio functions. Respects io redirection into pipes.
**************************************************************************************************/
class DbgIO
{
	static HANDLE ddb_read, ddb_write;
	static string buffer;

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

    **********************************************************************************************/
	static this()
	{
		ddb_read = GetStdHandle(STD_INPUT_HANDLE);
		ddb_write = GetStdHandle(STD_OUTPUT_HANDLE);
	}

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

    **********************************************************************************************/
	static string readln()
	{
		char[128] buf;
		uint read;

		int nl_index;
		do
		{
			ReadFile(ddb_read, buf.ptr, buf.length, &read, null);
			buffer ~= buf[0..read];
			nl_index = find(buffer, '\n');
		} while ( nl_index < 0 );
		string ret = buffer[0..nl_index];
		buffer = buffer[nl_index+1..$];
		return ret;
	}

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

    **********************************************************************************************/
	static void print(...)
	{
		string str;

		void putc(dchar c)
		{
			str ~= c;
		}

		doFormat(&putc, _arguments, _argptr);
		uint written;
		WriteFile(ddb_write, str.ptr, str.length, &written, null);
	}

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

    **********************************************************************************************/
	static void println(...)
	{
		string str;

		void putc(dchar c)
		{
			str ~= c;
		}

		doFormat(&putc, _arguments, _argptr);
		uint written;
		str ~= '\n';
		WriteFile(ddb_write, str.ptr, str.length, &written, null);
	}

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

    **********************************************************************************************/
	static void write(string str)
	{
		uint written;
		WriteFile(ddb_write, str.ptr, str.length, &written, null);
	}

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

    **********************************************************************************************/
	static void writeln(string str)
	{
		uint written;
		str ~= "\n";
		WriteFile(ddb_write, str.ptr, str.length, &written, null);
	}
}

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

**************************************************************************************************/
TypeInfo TypeInfoFromMangled(string mangled)
{
	TypeInfo	res;
	TypeInfo*	ti = &res;

    for ( uint i=0; ti !is null && i < mangled.length; ++i )
    {
        switch ( mangled[i] )
        {
            case 'C':
                debug DbgIO.println("TypeInfoFromMangled: classinfos not supported, yet");
                return null;
            case 'P':
                TypeInfo_Pointer tip = new TypeInfo_Pointer;
                *ti = tip;
                ti = &tip.m_next;
                break;
            case 'G':
                TypeInfo_StaticArray tia = new TypeInfo_StaticArray;
                *ti = tia;
                ti = &tia.value;
                break;
            case 'A':
                switch ( mangled[i+1] )
                {
                    case 'v':	*ti = new TypeInfo_Av;	ti = null;	break;
                    case 'x':
                    case 'b':	*ti = new TypeInfo_Ab;	ti = null;	break;
                    case 'g':	*ti = new TypeInfo_Ag;	ti = null;	break;
                    case 'h':	*ti = new TypeInfo_Ah;	ti = null;	break;
                    case 's':	*ti = new TypeInfo_As;	ti = null;	break;
                    case 't':	*ti = new TypeInfo_At;	ti = null;	break;
                    case 'i':	*ti = new TypeInfo_Ai;	ti = null;	break;
                    case 'k':	*ti = new TypeInfo_Ak;	ti = null;	break;
                    case 'l':	*ti = new TypeInfo_Al;	ti = null;	break;
                    case 'm':	*ti = new TypeInfo_Am;	ti = null;	break;
                    case 'f':	*ti = new TypeInfo_Af;	ti = null;	break;
                    case 'd':	*ti = new TypeInfo_Ad;	ti = null;	break;
                    case 'e':	*ti = new TypeInfo_Ae;	ti = null;	break;
                    case 'o':	*ti = new TypeInfo_Ao;	ti = null;	break;
                    case 'p':	*ti = new TypeInfo_Ap;	ti = null;	break;
                    case 'j':	*ti = new TypeInfo_Aj;	ti = null;	break;
                    case 'q':	*ti = new TypeInfo_Aq;	ti = null;	break;
                    case 'r':	*ti = new TypeInfo_Ar;	ti = null;	break;
                    case 'c':	*ti = new TypeInfo_Ac;	ti = null;	break;
                    case 'a':	*ti = new TypeInfo_Aa;	ti = null;	break;
                    case 'u':	*ti = new TypeInfo_Au;	ti = null;	break;
                    case 'w':	*ti = new TypeInfo_Aw;	ti = null;	break;
                    default:
                        TypeInfo_Array tia = new TypeInfo_Array;
                        *ti = tia;
                        ti = &tia.value;
                }
                break;
            case 'v':	*ti = new TypeInfo_v;	ti = null;	break;
            case 'x':
            case 'b':	*ti = new TypeInfo_b;	ti = null;	break;
            case 'g':	*ti = new TypeInfo_g;	ti = null;	break;
            case 'h':	*ti = new TypeInfo_h;	ti = null;	break;
            case 's':	*ti = new TypeInfo_s;	ti = null;	break;
            case 't':	*ti = new TypeInfo_t;	ti = null;	break;
            case 'i':	*ti = new TypeInfo_i;	ti = null;	break;
            case 'k':	*ti = new TypeInfo_k;	ti = null;	break;
            case 'l':	*ti = new TypeInfo_l;	ti = null;	break;
            case 'm':	*ti = new TypeInfo_m;	ti = null;	break;
            case 'f':	*ti = new TypeInfo_f;	ti = null;	break;
            case 'd':	*ti = new TypeInfo_d;	ti = null;	break;
            case 'e':	*ti = new TypeInfo_e;	ti = null;	break;
            case 'o':	*ti = new TypeInfo_o;	ti = null;	break;
            case 'p':	*ti = new TypeInfo_p;	ti = null;	break;
            case 'j':	*ti = new TypeInfo_j;	ti = null;	break;
            case 'q':	*ti = new TypeInfo_q;	ti = null;	break;
            case 'r':	*ti = new TypeInfo_r;	ti = null;	break;
            case 'c':	*ti = new TypeInfo_c;	ti = null;	break;
            case 'a':	*ti = new TypeInfo_a;	ti = null;	break;
            case 'u':	*ti = new TypeInfo_u;	ti = null;	break;
            case 'w':	*ti = new TypeInfo_w;	ti = null;	break;
            default:
                debug DbgIO.println("unknown mangled type "~mangled[i]);
                assert(0);
        }
    }

	return res;
}

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

**************************************************************************************************/
class DataReader
{
	ubyte[] data;
	uint	cursor;

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

    **********************************************************************************************/
	this(ubyte[] d)
	{
		data = d;
	}

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

    **********************************************************************************************/
	void alignCursor(ubyte num)
	{
		cursor += (num + cursor) % num;
		assert(cursor<=data.length);
	}

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

    **********************************************************************************************/
	bool available()
	{
		return cursor<data.length;
	}

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

    **********************************************************************************************/
	void seek(uint offset)
	{
		cursor=offset;
		if ( cursor > data.length )
            throw new Exception("DataReader.seek beyond end of data offset="~.toString(cursor)~", $="~.toString(data.length));
	}

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

    **********************************************************************************************/
	void relseek(int offset)
	{
		cursor+=offset;
		if ( cursor > data.length )
            throw new Exception("DataReader.seek beyond end of data offset="~.toString(cursor)~", $="~.toString(data.length));
	}

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

    **********************************************************************************************/
	void peek(out ubyte val)
	{
		assert(cursor<data.length);
		val = data[cursor];
	}

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

    **********************************************************************************************/
	void read(out ubyte val)
	{
		assert(cursor<data.length);
		val = data[cursor];
		++cursor;
	}
	void read(out char val) { read(*cast(ubyte*)&val); }

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

    **********************************************************************************************/
	void read(out ushort val)
	{
		assert(cursor+1<data.length);
		val = (cast(ushort[])(data[cursor..cursor+2]))[0];
		cursor+=2;
	}
	void read(out short val) { read(*cast(ushort*)&val); }

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

    **********************************************************************************************/
	void read(out uint val)
	{
		assert(cursor+3<data.length);
		val = (cast(uint[])(data[cursor..cursor+4]))[0];
		cursor+=4;
	}
	void read(out int val) { read(*cast(uint*)&val); }
	void read(out float val) { read(*cast(uint*)&val); }

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

    **********************************************************************************************/
	void read(out ulong val)
	{
		assert(cursor+7<data.length);
		val = (cast(ulong[])(data[cursor..cursor+8]))[0];
		cursor+=8;
	}
	void read(out long val) { read(*cast(ulong*)&val); }
	void read(out double val) { read(*cast(ulong*)&val); }
	void read(out cfloat val) { read(*cast(ulong*)&val); }

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

    **********************************************************************************************/
	void read(out real val)
	{
		assert(cursor+9<data.length);
		val = (cast(real[])(data[cursor..cursor+10]))[0];
		cursor+=10;
	}

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

    **********************************************************************************************/
	void read(out string str)
	{
		assert(cursor<data.length);
		ushort len = data[cursor++];
		if ( len >= 0xff && data[cursor] == 0 ) {
		    ++cursor;
			read(len);
		}

		assert(cursor+len<=data.length, "dr cursor="~.toString(cursor)~" len="~.toString(len));
		str = (cast(string)data)[cursor..cursor+len];
		cursor+=len;
	}

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

    **********************************************************************************************/
	void readA(T)(out T[] array, uint length)
	{
		uint size = length*T.sizeof;
		assert(cursor<=data.length-size);
		array = cast(T[])(data[cursor..cursor+size]);
		cursor+=size;
	}
}

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

**************************************************************************************************/
string getFullPath(string filename)
{
	char[]	fullpath;
	char*	filepart;
	fullpath.length = 4096;
	int len = GetFullPathName(
		toStringz(filename),
		fullpath.length,
		fullpath.ptr,
		&filepart
	);
	if ( len <= 0 )
		return null;
	fullpath.length = len;

	char[]	longfullpath;
	longfullpath.length = 4096;
	len = GetLongPathName(
	  toStringz(fullpath),
	  longfullpath.ptr,
	  longfullpath.length
	);
	longfullpath.length = len;
	return longfullpath;
}

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

**************************************************************************************************/
struct DbgTimer
{
    d_time time;

    void start()
    {
        time = getUTCtime;
    }

    string finish()
    {
        time = getUTCtime - time;
        return format("%d'%03d", time / TicksPerSecond, time % TicksPerSecond);
    }
}