view src/dbgprocess.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 dbgprocess;

import win32.winbase;
import win32.windef;

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

import util;
import breakpoint;
import dbgthread;
import callstack;
import codeview.coff;

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

**************************************************************************************************/
class DbgProcess
{
public:
	HANDLE		process_handle;
	uint        processId,
                mainThreadId;
	DLL[]		loaded_dlls;

	DbgThread[uint]	    threads;

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

    **********************************************************************************************/
	DLL loadDLL(LOAD_DLL_DEBUG_INFO* lddi)
	{
		DLL dll					= new DLL;
		dll.filehandle		    = lddi.hFile;
		dll.base				= cast(uint)lddi.lpBaseOfDll;
		dll.debug_info_offset	= lddi.dwDebugInfoFileOffset;
		dll.debug_info_size	= lddi.nDebugInfoSize;
		loaded_dlls ~= dll;

		size_t filesize = GetFileSize(lddi.hFile, null);
		if ( filesize == 0 )
		{
			debug DbgIO.println("Couldn't get DLL %s image size: %s", dll.image.name, lastError);
			return dll;
		}

		ubyte[] buf;
		buf.length = filesize;
		if ( !ReadFile(lddi.hFile, cast(void*)buf.ptr, buf.length, &filesize, null) || filesize != buf.length )
		{
			debug DbgIO.println("Couldn't read DLL image for %s: %s", dll.image.name, lastError);
			return dll;
		}
		dll.image = new COFFImage;
		dll.image.load(buf);

		return dll;
	}

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

    **********************************************************************************************/
	DLL findDLL(size_t vaddress)
	{
		foreach ( dll; loaded_dlls )
		{
			if ( vaddress < dll.base )
				continue;
			assert( dll !is null );
			assert( dll.image !is null );
			uint size_image = dll.image.imageSize;
			if ( vaddress-dll.base > size_image )
				continue;
			return dll;
		}
		return null;
	}

    /**********************************************************************************************
        Loads the given thread's stack and the index of the current frame pointer (ebp).
        Returns: Arrays of uints.
    **********************************************************************************************/
	CallStack loadStack(DbgThread thread)
	{
		CONTEXT ctx;
		if ( !thread.getContext(ctx, CONTEXT_CONTROL) )
            throw new Exception("Couldn't get thread's context");

		CallStack stack = new CallStack(thread.stack_base, ctx.Esp, ctx.Ebp);
		uint read = readProcessMemory(ctx.Esp, stack.data.ptr, stack.data.length);
		if ( read == 0 )
            throw new Exception("Couldn't read thread's stack memory");
		else if ( read < stack.data.length )
			stack.data.length = read;
		return stack;
	}

    /**********************************************************************************************
        Read from debuggee's memory.
        Returns: #bytes read
    **********************************************************************************************/
	size_t readProcessMemory(size_t address, void* data, size_t size, bool changeProtect=false)
	{
		uint oldprot;
		if( changeProtect && !VirtualProtectEx(process_handle, cast(void*)address, size, PAGE_READONLY, &oldprot) ) {
			debug DbgIO.println("readProcessMemory(): Failed to obtain read access to page at 0x%08x: %s", address, lastError);
			return false;
		}

		size_t numbytes;
		if( !ReadProcessMemory(process_handle, cast(void*)address, data, size, &numbytes) ) {
			debug DbgIO.println("ReadProcessMemory() returned false reading address 0x%08x: %s", address, lastError);
            return 0;
		}
		if ( numbytes != size ) {
			debug DbgIO.println("readProcessMemory(): Failed to read at address 0x%08x: %s", address, lastError);
		}

		if( changeProtect && !VirtualProtectEx(process_handle, cast(void*)address, size, oldprot, &oldprot) ) {
			DbgIO.println("writeProcessMemory(): Failed to restore access to page at 0x%08x: %s", address, lastError);
			return 0;
		}

		return numbytes;
	}

    /**********************************************************************************************
        Write to debuggee's memory.
        Returns success.
    **********************************************************************************************/
	size_t writeProcessMemory(size_t address, void* data, size_t size)
	{
		uint oldprot;

		if( !VirtualProtectEx(process_handle, cast(void*)address, size, PAGE_EXECUTE_READWRITE, &oldprot) )
		{
			DbgIO.println("writeProcessMemory(): Failed to obtain write access to page at 0x%08x: %s", address, lastError);
			return false;
		}

		size_t numbytes;
		if( !WriteProcessMemory(process_handle, cast(void*)address, data, size, &numbytes) )
			DbgIO.println("writeProcessMemory(): Failed to write byte at 0x%08x: %s", address, lastError);

		if( !VirtualProtectEx(process_handle, cast(void*)address, size, oldprot, &oldprot) )
		{
			DbgIO.println("writeProcessMemory(): Failed to restore access to page at 0x%08x: %s", address, lastError);
			return false;
		}

		if ( !FlushInstructionCache(process_handle, cast(void*)address, numbytes) )
		{
			DbgIO.println("writeProcessMemory(): FlushInstructionCache failed for 0x%08x: %s", address, lastError());
			return false;
		}

		return numbytes;
	}

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

    **********************************************************************************************/
	ClassInfo getClassInfo(size_t obj_ptr)
	{
		uint	vtbl,
				ci_ptr;
		readProcessMemory(obj_ptr, &vtbl, size_t.sizeof);
		readProcessMemory(vtbl, &ci_ptr, size_t.sizeof);
		ubyte[] data;
		data.length = ClassInfo.classinfo.init.length;
		readProcessMemory(ci_ptr, data.ptr, data.length);
		return cast(ClassInfo)data.ptr;
	}

    /**********************************************************************************************
        simple check for invalidity of a memory block
    **********************************************************************************************/
    const size_t MEMCHECK_MIN = 0x1000;
    bool isInvalidMem(size_t ptr, size_t len)
    {
        uint tmp;
        if ( uint.sizeof != readProcessMemory(ptr, &tmp, uint.sizeof)
            || uint.sizeof != readProcessMemory(ptr+len-uint.sizeof, &tmp, uint.sizeof) )
            return true;
        return false;
    }

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

    **********************************************************************************************/
    MEMORY_BASIC_INFORMATION[] walkMemory()
    {
        SYSTEM_INFO                 si;
        MEMORY_BASIC_INFORMATION[]  mbis;
        GetSystemInfo(&si);
        for ( void* ptr = si.lpMinimumApplicationAddress; ptr < si.lpMaximumApplicationAddress; )
        {
            mbis.length = mbis.length + 1;
            VirtualQueryEx(process_handle, ptr, &mbis[$-1], MEMORY_BASIC_INFORMATION.sizeof);
            ptr = mbis[$-1].BaseAddress + mbis[$-1].RegionSize;
        }
        return mbis;
    }
}

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

**************************************************************************************************/
class DLL
{
public:
	HANDLE	filehandle;
	uint	base,
			debug_info_offset,
			debug_info_size;
	COFFImage	image;
}