view src/disasm.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 util;
import dbgprocess;
import dbgthread;
public import udis86;
import util;

import std.string;

import win32.winnt;

class DisAsm
{
    /**********************************************************************************************
        Calculates the absolute destination address of a jxx or call instruction.
        Params: is_imm = if true, only JIMM destinations will be considered. Out value is whether destination was JIMM
    **********************************************************************************************/
	static int calcJumpDestination(DbgProcess process, DbgThread thread, ud_t* ud_obj, inout bool is_imm)
	{
		if ( !isConditionalJump(ud_obj.mnemonic)
			&& ud_obj.mnemonic != ud_mnemonic_code.UD_Icall
			&& ud_obj.mnemonic != ud_mnemonic_code.UD_Ijmp )
			return 0;

		uint address, destination;
		if ( ud_obj.operand[0].type == ud_type.UD_OP_MEM || ud_obj.operand[0].type == ud_type.UD_OP_REG )
		{
			if ( is_imm ) {
				is_imm = false;
				return 0;
			}
			is_imm = false;
			CONTEXT ctx;
			thread.getContext(ctx, CONTEXT_FULL);
			switch ( ud_obj.operand[0].base )
			{
			    case ud_type.UD_NONE:   break;
				case ud_type.UD_R_EAX:	address = ctx.Eax;	break;
				case ud_type.UD_R_EBX:	address = ctx.Ebx;	break;
				case ud_type.UD_R_ECX:	address = ctx.Ecx;	break;
				case ud_type.UD_R_EDX:	address = ctx.Edx;	break;
				case ud_type.UD_R_ESI:	address = ctx.Esi;	break;
				case ud_type.UD_R_EDI:	address = ctx.Edi;	break;
				default:
					DbgIO.println("WARNING: yet unsupported register 0x%x used in jmp/call destination", ud_obj.operand[0].base);
					break;
			}
			if ( ud_obj.operand[0].type == ud_type.UD_OP_MEM )
			{
                switch ( ud_obj.operand[0].offset )
                {
                    case 8:		address += ud_obj.operand[0].lval._ubyte;	break;
                    case 16:	address += ud_obj.operand[0].lval.uword;	break;
                    case 32:	address += ud_obj.operand[0].lval.udword;	break;
                    default:
                        DbgIO.println("WARNING: yet unsupported offset size used in jmp/call destination");
                        break;
                }
                process.readProcessMemory(address, &destination, uint.sizeof);
			}
			else
                destination = address;
		}
		else if ( ud_obj.operand[0].type == ud_type.UD_OP_JIMM )
		{
			is_imm = true;
			address		= cast(uint)ud_insn_off(ud_obj);
			destination	= address+ud_insn_len(ud_obj);
			switch ( ud_obj.operand[0].size )
			{
				case 8:
					destination += ud_obj.operand[0].lval.sbyte;
					break;
				case 16:
					destination += ud_obj.operand[0].lval.sword;
					break;
				case 32:
					destination += ud_obj.operand[0].lval.sdword;
					break;
				case 48:
					DbgIO.println("WARNING: 48bit immediate jump destinations not implemented, yet");
					break;
				case 64:
					DbgIO.println("WARNING: 64bit immediate jump destinations not implemented, yet");
					break;
                default:
                    assert(0);
			}
		}
		else
			DbgIO.println("yet unsupported jmp/call destination");
		return destination;
	}

    /**********************************************************************************************
        Test if given mnemonic a a conditional jump (i.e. jxx, not jmp).
    **********************************************************************************************/
	static bool isConditionalJump(ud_mnemonic_code opcode)
	{
		if ( ud_mnemonic_code.UD_Ijmp == opcode )
			return false;
		if ( ud_mnemonic_code.UD_Ijcxz <= opcode && ud_mnemonic_code.UD_Ijnle >= opcode )
			return true;
		if ( ud_mnemonic_code.UD_Ija <= opcode && ud_mnemonic_code.UD_Ijnc >= opcode )
			return true;
		if ( ud_mnemonic_code.UD_Iloop <= opcode && ud_mnemonic_code.UD_Iloopz >= opcode )
			return true;
		return false;
	}

    /**********************************************************************************************
        Wrapper function for disassembly. Calls the delegate callback for each instruction.
    **********************************************************************************************/
	static void disasm(DbgProcess process, uint start, uint stop, bool delegate(ud_t*) callback)
	{
		ubyte[]	code;

		bool disasm(uint length, bool abort_at_ret)
		{
			ud_t	ud_obj;
			ud_init(&ud_obj);
			ud_set_pc(&ud_obj, start);
			ud_set_input_buffer(&ud_obj, code.ptr, length);
			ud_set_mode(&ud_obj, 32);
			ud_set_syntax(&ud_obj, &ud_translate_intel);

			// init callback
			callback(cast(ud_t*)null);

			while ( ud_disassemble(&ud_obj) )
			{
				if ( !callback(&ud_obj) )
					return false;
				if ( abort_at_ret && (ud_obj.mnemonic == ud_mnemonic_code.UD_Iret || ud_obj.mnemonic == ud_mnemonic_code.UD_Iretf) )
					return false;
			}
			return true;
		}

		if ( stop > 0 && stop <= start ) {
			DbgIO.println("ERROR: invalid address range: Eip=0x%x >= 0x%x", start, stop);
			return;
		}

		code.length = stop>0?stop-start:512;
		bool more;
		uint read;
		do
		{
			read = process.readProcessMemory(start, code.ptr, code.length);
			if ( read == 0 )
				DbgIO.println("ERROR: Couldn't read from process' memory for disassembly: %s", lastError);
			if ( read > 0 )
				more = disasm(read, stop==0);
			start += code.length;
		} while ( stop == 0 && more && read > 0 );
	}
}