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

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

import dbgthread;
import codeview.codeview;
import dbgprocess;
import util;

import win32.windef;

enum StepMode {
    e_in, e_over, e_out
}

/**************************************************************************************************
    Represents a software breakpoint.
**************************************************************************************************/
class Breakpoint
{
    //---------------------------------------------------------------------------------------------
    // constants
    const ubyte BREAKPOINT_OPCODE = 0xccu;

    //---------------------------------------------------------------------------------------------
    // variables
    byte            old_opcode;
    bool            active,
                    temporary,
                    deactivate_d_exception_handler,
                    propagate,				/// when hit on a jmp/call/ret instruction, shall be reactivated on it's destination
                    hardware;
    Breakpoint      foreach_end;
    Location		location;
    size_t          frame_ptr,
                    threadId,
                    old_dr_value;
    ubyte           dr_index;

    //---------------------------------------------------------------------------------------------
    // properties
    string file()				{ return location is null?null:location.file; }
    uint line()					{ return location is null?0:location.line; }
    uint address()				{ return location is null?0:location.address; }


    //---------------------------------------------------------------------------------------------
    // construction
    this(Location loc, bool temp, uint _threadId, bool _hardware=false)
    {
        hardware = _hardware;
        threadId = _threadId;
        temporary = temp;
        location = loc;
    }


    //---------------------------------------------------------------------------------------------
    // methods

    /**
     *
     */
    string toString()
    {
        string tmp;
        tmp.length = 100;
        tmp.length = 0;
        if ( location.path.length > 0 )
            tmp ~= format("%s ", location.path);
        if ( file.length > 0 )
            tmp ~= format("%s:%d ", file, line);
        if ( location.address > 0 )
            tmp ~= format("0x%x ", location.address);
        if ( hardware )
            tmp ~= "hw ";
        if ( threadId > 0 )
            tmp ~= format("thread %s", threadId);
        else
            tmp ~= format("all threads");
        return tmp;
    }

    /**********************************************************************************************
        Restores the opcode that has been overwritten for the given breakpoint.
        Returns success.
    **********************************************************************************************/
    bool deactivate(DbgProcess proc)
    {
        if ( !active )
            return true;
        if ( proc is null )
            return false;

        if ( hardware )
        {
            if ( threadId == 0 )
            {
                foreach ( thread; proc.threads.values )
                    clearHWBP(thread, 0);
            }
            else
                clearHWBP(proc.threads[threadId], 0);
        }
        else if( !proc.writeProcessMemory(location.address, &old_opcode, ubyte.sizeof))
        {
            DbgIO.println("restoreBreakpoint(): Failed to write original opcode at 0x%x", location.address);
            return false;
        }

        active = false;
        return true;
    }

    /**********************************************************************************************
        Writes an int 3 opcode at the address of this breakpoint, saving the overwritten code.
        Returns success.
    **********************************************************************************************/
    bool activate(DbgProcess proc)
    {
        if( active )
            return true;
        if( location.address == 0 || proc is null )
            return false;

        debug DbgIO.println("activating bp at 0x%x", location.address);

        if ( hardware )
        {
            if ( threadId == 0 )
            {
                foreach ( thread; proc.threads.values )
                    setHWBP(thread, location.address, 0);
            }
            else
                setHWBP(proc.threads[threadId], location.address, 0);
        }
        else
        {
            uint	oldprot, oldprot2;
            ubyte	ccByte = cast(ubyte)0xcc;

            if( ubyte.sizeof > proc.readProcessMemory(location.address, &old_opcode, ubyte.sizeof) ) {
                DbgIO.println( "readProcessMemory(): failed to read breakpoint opcode at 0x%08x", location.address );
                return false;
            }

            ubyte opcode = BREAKPOINT_OPCODE;
            if( ubyte.sizeof > proc.writeProcessMemory(location.address, &opcode, ubyte.sizeof) ) {
                DbgIO.println("writeProcessMemory(): Failed to write breakpoint at 0x%08x", location.address );
                return false;
            }
        }

        active = true;
        return true;
    }

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

    **********************************************************************************************/
    void setHWBP(DbgThread thread, size_t address, ubyte index)
    {
        assert(index < 4);

        CONTEXT ctx;
        thread.getContext(ctx, CONTEXT_DEBUG_REGISTERS);
        DbgIO.println("Dr0 = %x\nDr1 = %x\nDr2 = %x\nDr3 = %x\nDr7 = %x\n", ctx.Dr0, ctx.Dr1, ctx.Dr2, ctx.Dr3, ctx.Dr7);

        old_dr_value = *(&ctx.Dr0 + index);
        *(&ctx.Dr0 + index) = address+thread.getDsBase;
        dr_index = index;

        ctx.Dr7 |= 1<<10 | (1 << index) | (15 << (16+index*4));
        DbgIO.println("Dr0 = %x\nDr1 = %x\nDr2 = %x\nDr3 = %x\nDr7 = %x\n", ctx.Dr0, ctx.Dr1, ctx.Dr2, ctx.Dr3, ctx.Dr7);
        thread.setContext(ctx);
    }

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

    **********************************************************************************************/
    void clearHWBP(DbgThread thread, ubyte index)
    {
        assert(index < 4);

        CONTEXT ctx;
        thread.getContext(ctx, CONTEXT_DEBUG_REGISTERS);
        DbgIO.println("Dr0 = %x\nDr1 = %x\nDr2 = %x\nDr3 = %x\nDr7 = %x\n", ctx.Dr0, ctx.Dr1, ctx.Dr2, ctx.Dr3, ctx.Dr7);

        ctx.Dr7 &= ~((1 << index) | (15 << (16+index*4)));
        DbgIO.println("Dr0 = %x\nDr1 = %x\nDr2 = %x\nDr3 = %x\nDr7 = %x\n", ctx.Dr0, ctx.Dr1, ctx.Dr2, ctx.Dr3, ctx.Dr7);
        thread.setContext(ctx);
    }
}