/* 
CCIDE
Copyright 2001-2011 David Lindauer.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

You may contact the author at:
	mailto::camille@bluegrass.net
 */
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include <richedit.h>

#define TF_BIT 0x100

#include "header.h"

extern HWND hwndSourceTab;
extern HWND hwndFrame, hwndASM, hwndRegister, hwndWatch, hwndThread;
extern HWND hwndToolDebug, hwndStack, hwndDump;
extern HANDLE children[MAX_CHILDREN];
extern int numberofdrawwindows;
extern HWND hwndASMBlank;

enum DebugState uState = notDebugging;
PROCESS DebugProcess;
HANDLE StartupSem, BreakpointSem;
THREAD *StoppedThread;

PROJLIST *debugProject;
static DWORD debugThreadID;
static int Semaphores;
static int SingleStepping;
static int LastSkipAddr;
static int stopWinMain;
void StartDebug(char *cmd);

int RunProgramThread(PROJLIST *plist)
{
	char cmd[256];
	
	BOOL bContinue = TRUE;
	DWORD dwContinueStatus;
	BOOL bShownExitCode = FALSE;
    DEBUG_EVENT stDE;
	DWORD threads = 0;
	BOOL bRet;
    STARTUPINFO stStartInfo;
    PROCESS_INFORMATION stProcessInfo;
	BOOL bSeenInitialBP = FALSE;
    char wd[512],*pwd = wd, *pc = cmd;
	if (!plist)
	{
        ExtendedMessageBox("Run without debugger", MB_SETFOREGROUND | MB_SYSTEMMODAL, 
            "There is no project to run");
		return 0;
	}
    sprintf(cmd, "\"%s\" %s", plist->name, plist->cmdline);

    // relies on the file name being quoted, which it will be from the thread
    // that started this one
    pc++ ;
    while (*pc && *pc != '"')
        *pwd++ = *pc++ ;
    *pwd = 0;
    pwd = strrchr(wd,'\\') ;
    if (pwd-1 != '\\')
        *pwd = 0 ;
    memset(&stStartInfo, 0, sizeof(STARTUPINFO));
    memset(&stProcessInfo, 0, sizeof(PROCESS_INFORMATION));

    stStartInfo.cb = sizeof(STARTUPINFO);
    bRet = CreateProcess(NULL, cmd, NULL, NULL, TRUE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS |
						 (plist->buildType == BT_CONSOLE ? CREATE_NEW_CONSOLE : 0), 
						NULL, wd, &stStartInfo, &stProcessInfo);
    if (!bRet)
    {
        ReleaseSemaphore(StartupSem, 1, 0);
        ExtendedMessageBox("Debugger", MB_SETFOREGROUND | MB_SYSTEMMODAL, 
            "Could not execute %s.", cmd);
        return 0;
    }
	if (plist->buildType == BT_CONSOLE)
	{
		ProcessToTop(stProcessInfo.dwProcessId);
	}
    while (TRUE == bContinue)
    {
        // Pause until a debug event notification happens.
        bContinue = WaitForDebugEvent(&stDE, 500);
        if (bContinue)
        {
            switch (stDE.dwDebugEventCode)
            {
                case CREATE_THREAD_DEBUG_EVENT:
                case CREATE_PROCESS_DEBUG_EVENT:
                case LOAD_DLL_DEBUG_EVENT:
                case UNLOAD_DLL_DEBUG_EVENT:
                case OUTPUT_DEBUG_STRING_EVENT:
                case RIP_EVENT:
                    {
                        dwContinueStatus = DBG_CONTINUE;
                    }
                    break;
				case EXIT_THREAD_DEBUG_EVENT:
                    {
						if (stDE.u.ExitThread.dwExitCode == STATUS_CONTROL_C_EXIT)
						{
							if (plist->buildFlags & BF_SHOWRETURNCODE)
							{
								if (plist->buildType == BT_CONSOLE)
								{
									ProcessToTop(stProcessInfo.dwProcessId);
								}
								ExtendedMessageBox("Run", MB_SETFOREGROUND | MB_SYSTEMMODAL, "Process complete. Exit code: %d", stDE.u.ExitProcess.dwExitCode);							
								bShownExitCode = TRUE;
							}
						}
                        dwContinueStatus = DBG_CONTINUE;
                    }
					break;
                case EXIT_PROCESS_DEBUG_EVENT:
                    {
						
						if (!bShownExitCode && plist->buildFlags & BF_SHOWRETURNCODE)
						{
							if (plist->buildType == BT_CONSOLE)
							{
								ProcessToTop(stProcessInfo.dwProcessId);
							}
							ExtendedMessageBox("Run", MB_SETFOREGROUND | MB_SYSTEMMODAL, "Process complete. Exit code: %d", stDE.u.ExitProcess.dwExitCode);							
						}
                        dwContinueStatus = DBG_CONTINUE;
						bContinue = FALSE;
                    }
                    break;

                case EXCEPTION_DEBUG_EVENT:
                    {
                        switch (stDE.u.Exception.ExceptionRecord.ExceptionCode)
                        {
							default:
		                        dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
								break;
	                        case EXCEPTION_BREAKPOINT:
								if (!bSeenInitialBP)
								{
                                    bSeenInitialBP = TRUE;									
                                    dwContinueStatus = DBG_CONTINUE;
                                }
								else
								{
			                        dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
								}
								break;
						}
                    }
                    break;

                    // For any other events, just continue on.
                default:
                    {
                        dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
                    }
                    break;
            }
        }
        else
        {
            dwContinueStatus = DBG_CONTINUE;
            bContinue = TRUE;
		}
        // Pass on to the operating system.
        ContinueDebugEvent(stDE.dwProcessId, stDE.dwThreadId, dwContinueStatus);

    }
	CloseHandle(stProcessInfo.hProcess);
	CloseHandle(stProcessInfo.hThread);
	return 0;
}
void RunProgram(PROJLIST *plist)
{
	DWORD threadhand;
    CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)RunProgramThread, 
        (LPVOID)plist, 0, &threadhand));
}
int initiateDebug(PROJLIST *plist, int stopimmediately)
{
    static char cmd[512];
    if (uState == notDebugging)
    {
        int val = IsPEFile(plist->name);
		debugProject = plist;
        stopWinMain = !!stopimmediately;
        if (val <= 0)
        {
            if (val == 0)
                ExtendedMessageBox("File Error", MB_SYSTEMMODAL |
                    MB_SETFOREGROUND, "File %s was not found", cmd);
            else
                ExtendedMessageBox("File Error", MB_SYSTEMMODAL |
                    MB_SETFOREGROUND, 
                    "File %s must be a win32 executable to debug.", cmd);
            return uState;
        } Semaphores = TRUE;
        StartupSem = CreateSemaphore(0, 0, 1, 0);
        BreakpointSem = CreateSemaphore(0, 0, 1, 0);
        sprintf(cmd, "\"%s\" %s", plist->name, plist->cmdline);
        CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)StartDebug, 
            (LPVOID)cmd, 0, &debugThreadID));


        WaitForSingleObject(StartupSem, INFINITE);
        PostMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
    }
    return uState;
}

//-------------------------------------------------------------------------

HANDLE GetThreadHandle(DWORD procid, DWORD threadid)
{
    THREAD *thread = DebugProcess.threads;
    while (thread)
    {
        if (thread->idThread == threadid)
            return thread->hThread;
        thread = thread->next;
    }
    return DebugProcess.threads->hThread;
}

//-------------------------------------------------------------------------

BOOL CALLBACK topenumfunc(HWND wnd, LPARAM value)
{
    DWORD id;
    GetWindowThreadProcessId(wnd, &id);
    if (id == value)
    {
        SetForegroundWindow(wnd);
        if (IsIconic(wnd))
            ShowWindow(wnd, SW_RESTORE);
        return FALSE;
    }
    return TRUE;
}

/* if we don't do this, the debugger locks up sometimes */
void ProcessToTop(DWORD processid)
{
    HWND top;
    //   return ;
    top = GetTopWindow(0);
    EnumWindows((WNDENUMPROC)topenumfunc, processid);
    //   while (GetTopWindow(0) != top) 
    //      Sleep(1);
}

//-------------------------------------------------------------------------

static int HandleBreakpoint(DEBUG_EVENT *info)
{
    if (uState != Aborting)
        uState = atBreakpoint;
    PostMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
    PostMessage(hwndFrame, WM_BREAKPOINT, 0, (LPARAM)info);
    if (hwndRegister)
        PostMessage(hwndRegister, WM_COMMAND, ID_SETADDRESS, (LPARAM)
            GetThreadHandle(info->dwProcessId, info->dwThreadId));
    PostMessage(hwndWatch, WM_COMMAND, ID_SETADDRESS, 0);
    if (hwndStack)
        PostMessage(hwndStack, WM_RESTACK, (WPARAM)1, 0);
    if (hwndThread)
        PostMessage(hwndThread, WM_RESTACK, (WPARAM)1, 0);
    if (hwndDump)
        PostMessage(hwndDump, WM_RESTACK, 0, 0);
    if (uState != Aborting && uState != notDebugging)
    {
        WaitForSingleObject(BreakpointSem, INFINITE);
    }
    //   PostMessage(hwndRegister,WM_COMMAND,ID_SETCONTEXT,0) ;
    if (hwndStack)
        PostMessage(hwndStack, WM_RESTACK, (WPARAM)0, 0);
    if (hwndThread)
        PostMessage(hwndThread, WM_RESTACK, (WPARAM)0, 0);
    ApplyBreakAddress(0, 0); // get rid of the break line
    if (uState == notDebugging || uState == Aborting)
    {
        PostMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
        return DBG_TERMINATE_PROCESS;
    }
    else
    {
        if (uState != SteppingOut && uState != SteppingOver && uState !=
            SteppingIn && uState != StepInOut)
            uState = Running;
        PostMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
        return DBG_CONTINUE;
    }
}

//-------------------------------------------------------------------------

static int HandleException(DEBUG_EVENT *info)
{
    if (uState == notDebugging || uState == Aborting)
        return DBG_EXCEPTION_NOT_HANDLED;
    if (info->u.Exception.ExceptionRecord.ExceptionCode != DBG_CONTROL_C &&
    	info->u.Exception.ExceptionRecord.ExceptionCode != DBG_CONTROL_BREAK &&
		!(debugProject->buildFlags &BF_DEBUGEXCEPTION))
        if (info->u.Exception.dwFirstChance)
            return DBG_EXCEPTION_NOT_HANDLED;
    uState = atException;
    PostMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
    PostMessage(hwndFrame, WM_EXCEPTION, 0, (LPARAM)info);
    PostMessage(hwndWatch, WM_COMMAND, ID_SETADDRESS, 0);
    if (hwndStack)
        PostMessage(hwndStack, WM_RESTACK, (WPARAM)1, 0);
    if (hwndThread)
        PostMessage(hwndThread, WM_RESTACK, (WPARAM)1, 0);
    if (hwndRegister)
        PostMessage(hwndRegister, WM_COMMAND, ID_SETADDRESS, (LPARAM)
            GetThreadHandle(info->dwProcessId, info->dwThreadId));
    if (hwndDump)
        PostMessage(hwndDump, WM_RESTACK, 0, 0);
    WaitForSingleObject(BreakpointSem, INFINITE);
    //   PostMessage(hwndRegister,WM_COMMAND,ID_SETCONTEXT,0) ;
    if (hwndStack)
        PostMessage(hwndStack, WM_RESTACK, (WPARAM)0, 0);
    if (hwndThread)
        PostMessage(hwndThread, WM_RESTACK, (WPARAM)0, 0);
    if (uState == notDebugging || uState == Aborting)
    {
        PostMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
        return DBG_TERMINATE_PROCESS;
    }
    if (uState != SteppingOut && uState != SteppingOver && uState != SteppingIn
        && uState != StepInOut)
        uState = Running;
    PostMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
    return DBG_CONTINUE;
}

//-------------------------------------------------------------------------

void SingleStep(DWORD procID, DWORD threadID)
{
    StoppedThread->regs.EFlags |= TF_BIT;
    SingleStepping = TRUE;
}

//-------------------------------------------------------------------------

void ClearTraceFlag(DWORD procID, DWORD threadID)
{
    SingleStepping = FALSE;
}

//-------------------------------------------------------------------------

void BlastExitProcFunc(HANDLE hProcess, DWORD procID, DWORD threadID, DWORD
    address)
{
    int buf = 0; // exit code
    StoppedThread->regs.Eip = address;
    StoppedThread->regs.Esp -= 4;
    WriteProcessMemory(hProcess, (LPVOID)StoppedThread->regs.Esp, (LPVOID) &buf,
        4, 0);
    StoppedThread->regs.Esp -= 4;
}

//-------------------------------------------------------------------------

void GetRegs(DWORD procID, DWORD threadID)
{
    THREAD *thread = DebugProcess.threads;
    StoppedThread = thread;
    while (thread)
    {
        if (thread->idThread == threadID)
            StoppedThread = thread;
        thread->regs.ContextFlags = CONTEXT_FULL | CONTEXT_FLOATING_POINT |
            CONTEXT_DEBUG_REGISTERS;
        GetThreadContext(thread->hThread, &thread->regs);
        thread = thread->next;
    }
}

//-------------------------------------------------------------------------

void SetRegs(DWORD procID, DWORD threadID)
{
    THREAD *thread = DebugProcess.threads;
    while (thread)
    {
        SetThreadContext(thread->hThread, &thread->regs);
        thread = thread->next;
    }
}

//-------------------------------------------------------------------------

void SetTempBreakPoint(int procid, int threadid, int address)
{
    DebugProcess.breakpoints.address = address;
    DebugProcess.idTempBpThread = threadid;
}

//-------------------------------------------------------------------------

void ClearTempBreakPoint(int procid)
{
    DebugProcess.breakpoints.address = 0;
}

//-------------------------------------------------------------------------

int SittingOnBreakPoint(DEBUG_EVENT *dbe)
{
    return isBreakPoint((int)dbe->u.Exception.ExceptionRecord.ExceptionAddress);
}

//-------------------------------------------------------------------------

void WriteBreakPoint(HANDLE hProcess, int address, int value)
{
    int bf = value;
    MEMORY_BASIC_INFORMATION mbi;
    DWORD dwOldProtect;

    //	if (!IsNT() && address >= 0x80000000)
    //		return ;
    if (!VirtualQueryEx(hProcess, (LPVOID)address, &mbi, sizeof(mbi)))
        ExtendedMessageBox("Debugger", MB_SYSTEMMODAL, "Could not query pages %d",
            GetLastError());
	// the following fails on win98
    /*if*/ (!VirtualProtectEx(hProcess, mbi.BaseAddress, mbi.RegionSize,
        PAGE_EXECUTE_WRITECOPY, &mbi.Protect));
//        ExtendedMessageBox("Debugger", MB_SYSTEMMODAL, 
//            "Could not protect pages %d", GetLastError());

    if (!WriteProcessMemory(hProcess, (LPVOID)address, (LPVOID) &bf, 1, 0))
        ExtendedMessageBox("Debugger", MB_SYSTEMMODAL, 
            "Could not write breakpoint address %x %d", address, GetLastError())
            ;

    VirtualProtectEx(hProcess, mbi.BaseAddress, mbi.RegionSize, mbi.Protect,
        &dwOldProtect);
    FlushInstructionCache(hProcess, (LPVOID)address, 1);
}

//-------------------------------------------------------------------------

void allocBreakPoint(HANDLE hProcess, BREAKPOINT *pt)
{
    unsigned char bf;
    if (!pt->active && pt->address)
    {
        DWORD len;
        if (ReadProcessMemory(hProcess, (LPVOID)pt->address, (LPVOID) &bf, 1,
            &len))
        {
            if (!len)
                return ;
            if (bf == 0xcc)
                return ;
            WriteBreakPoint(hProcess, pt->address, 0xcc);
            pt->active = TRUE;
            pt->tempVal = bf;

        }
    }
}

//-------------------------------------------------------------------------

void freeBreakPoint(HANDLE hProcess, BREAKPOINT *pt)
{
    if (pt->active)
    {
        WriteBreakPoint(hProcess, pt->address, pt->tempVal);
        pt->active = FALSE;
    }
}

//-------------------------------------------------------------------------

void SetBreakPoints(int procid, int running)
{
    BREAKPOINT *p = &DebugProcess.breakpoints;
    #ifdef HBREAK
        if (running)
            hbpSetBP();
    #endif 
    while (p)
    {
        if (p->address)
            allocBreakPoint(DebugProcess.hProcess, p);
        p = p->next;
    }

}

//-------------------------------------------------------------------------

void ClearBreakPoints(int procid)
{
    BREAKPOINT *p = &DebugProcess.breakpoints;
    THREAD *th = DebugProcess.threads;
    #ifdef HBREAK
        hbpResetBP();
    #endif 
    while (p)
    {
        freeBreakPoint(DebugProcess.hProcess, p);
        p = p->next;
    }
    while (th)
    {
        freeBreakPoint(DebugProcess.hProcess, &th->breakpoint);
        th = th->next;
    }

}

//-------------------------------------------------------------------------

int isBreakPoint(int addr)
{
    BREAKPOINT *p = DebugProcess.breakpoints.next;
    THREAD *th = DebugProcess.threads;
    while (p)
    {
        if (addr == p->address)
            return TRUE;
        p = p->next;
    }
    return FALSE;
}

//-------------------------------------------------------------------------

int isLocalBreakPoint(int addr)
{
    THREAD *th = DebugProcess.threads;
    while (th)
    {
        if (addr == th->breakpoint.address)
            return TRUE;
        th = th->next;
    }
    return isBreakPoint(addr);
}

//-------------------------------------------------------------------------

#ifdef XXXXX
    int IsBreakpointLine(char *module, int line)
    {
        BREAKPOINT *p = DebugProcess.breakpoints.next;
        while (p)
        {
            if (p->linenum)
                if (p->linenum == line && !xstricmp(module, p->module))
                    return TRUE;
            p = p->next;
        }
        return FALSE;
    }
#endif 
int StepOverIncrement(DEBUG_EVENT *dbe)
{
    unsigned char buf[16];
    int word = 0;
    int address;
    int skiplen = 0;
    ReadProcessMemory(DebugProcess.hProcess, (LPVOID)(address = dbe
        ->u.Exception.ExceptionRecord.ExceptionAddress), (LPVOID)buf, 16, 0);
    switch (buf[0])
    {
        case 0xCE:
            skiplen = 1;
            break;
        case 0xCD:
            skiplen = 2;
            break;
        case 0xE8:
            skiplen = 5;
            break;
        default:
            word = (*(short*)buf) &0x38ff;
            if (word == 0x10ff || word == 0x18ff)
            {
                skiplen = 2;
                if ((word = (buf[1] &0xc7)) < 0xc0)
                {
                    // not indirect through reg
                    if (word == 6)
                    // Offset
                        skiplen += 4;
                    else
                    {
                        if (word >= 8)
                            if (word >= 0x80)
                                skiplen += 4;
                            else
                                skiplen += 1;
                        word &= 7;
                        if (word == 4)
                        {
                            skiplen++; /* has a SIB */
                            if (*(buf + 1) < 0xc0)
                            {
                                word = *(buf + 2);
                                if ((word &7) == 5)
                                {
                                     /* EBP special cases */
                                    if (*(buf + 1) &0x40)
                                        skiplen += 4;
                                    else
                                        skiplen += 1;
                                }
                            }
                        }
                    }
                }
            }
            break;
    }
    if (skiplen)
        return address + skiplen;
    return 0;
}

//-------------------------------------------------------------------------

int DoStepOver(DEBUG_EVENT *dbe)
{
    int skipaddr = StepOverIncrement(dbe);
    if (skipaddr)
    {
        SetTempBreakPoint(dbe->dwProcessId, dbe->dwThreadId, skipaddr);
    }
    else
    {
        SingleStep(dbe->dwProcessId, dbe->dwThreadId);
    }
}

//-------------------------------------------------------------------------

int DoStepIn(DEBUG_EVENT *dbe)
{
    LastSkipAddr = StepOverIncrement(dbe);
    SingleStep(dbe->dwProcessId, dbe->dwThreadId);
}

//-------------------------------------------------------------------------

int IsStepping(DEBUG_EVENT *dbe)
{
    char module[256];
    int line;
    if (uState == SteppingOver)
    {
        int v;
        if ((v = GetBreakpointLine((int)dbe
            ->u.Exception.ExceptionRecord.ExceptionAddress, module, &line)) !=
            dbe->u.Exception.ExceptionRecord.ExceptionAddress)
        {
            DoStepOver(dbe);
            return TRUE;
        }
        else
        {
            uState = Running;
            return FALSE;
        }
    }
    else if (uState == SteppingIn)
    {
        int addr = GetBreakpointLine((int)dbe
            ->u.Exception.ExceptionRecord.ExceptionAddress, module, &line);
        if (addr == dbe->u.Exception.ExceptionRecord.ExceptionAddress)
        {
            uState = Running;
            return FALSE;
        }
        else if (LastSkipAddr)
        {
            if (dbe->u.Exception.ExceptionRecord.ExceptionAddress !=
                LastSkipAddr)
            {
                if (addr)
                {
                    uState = SteppingOver;
                    DoStepOver(dbe);
                    return TRUE;
                }
                else
                {
                    SetTempBreakPoint(dbe->dwProcessId, dbe->dwThreadId,
                        LastSkipAddr);
                    uState = StepInOut;
                    return TRUE;
                }
            }
            else
            {
                DoStepIn(dbe);
                return TRUE;
            }
        }
        else
        {
            DoStepIn(dbe);
            return TRUE;
        }
    }
    else if (uState == StepInOut)
    {
        int addr = GetBreakpointLine((int)dbe
            ->u.Exception.ExceptionRecord.ExceptionAddress, module, &line);
        if (addr == dbe->u.Exception.ExceptionRecord.ExceptionAddress)
        {
            uState = Running;
            return FALSE;
        }
        else
        {
            uState = SteppingIn;
            DoStepIn(dbe);
            return TRUE;
        }
    }
    else if (uState == FinishStepOut)
    {
        int addr = GetBreakpointLine((int)dbe
            ->u.Exception.ExceptionRecord.ExceptionAddress, module, &line);
        if (!addr || addr == dbe->u.Exception.ExceptionRecord.ExceptionAddress)
        {
            uState = Running;
            return FALSE;
        }
        else
        {
            uState = SteppingIn;
            DoStepIn(dbe);
            return TRUE;
        }
    }
    return FALSE;
}

//-------------------------------------------------------------------------

void StepOver(DEBUG_EVENT *dbe)
{
    if (dmgrGetHiddenState(DID_ASMWND))
	{
        uState = SteppingOver;
	}
	else
		SetStatusMessage("Disassembly window open - stepping via assembly", FALSE);
    SaveRegisterContext();
    DoStepOver(dbe);
    ReleaseSemaphore(BreakpointSem, 1, 0);
}

//-------------------------------------------------------------------------

void StepOut(DEBUG_EVENT *dbe)
{
    uState = SteppingOut;
    SaveRegisterContext();
    ReleaseSemaphore(BreakpointSem, 1, 0);
}

//-------------------------------------------------------------------------

void StepIn(DEBUG_EVENT *dbe)
{
    if (dmgrGetHiddenState(DID_ASMWND))
	{
        uState = SteppingIn;
	}
	else
		SetStatusMessage("Disassembly window open - stepping via assembly", FALSE);
    SaveRegisterContext();
    DoStepIn(dbe);
    ReleaseSemaphore(BreakpointSem, 1, 0);
}

//-------------------------------------------------------------------------

int RunTo(DEBUG_EVENT *dbe)
{
    int addr;
    HWND wnd = GetFocus();
    if (wnd == hwndASMBlank)
    {
        if (!(addr = SendMessage(hwndASM, WM_GETCURSORADDRESS, 0, 0)))
            return FALSE;
        SetTempBreakPoint(dbe->dwProcessId, dbe->dwThreadId, addr);
        SaveRegisterContext();
        ReleaseSemaphore(BreakpointSem, 1, 0);
    }
    else
    {
        wnd = GetParent(wnd);
        if (!IsSpecialWindow(wnd))
        {
            DWINFO *ptr = (DWINFO*)GetWindowLong(wnd, 0);
            int linenum;
            SendMessage(ptr->dwHandle, EM_GETSEL, (WPARAM) &linenum, 0);
            linenum = SendMessage(ptr->dwHandle, EM_EXLINEFROMCHAR, 0, linenum)
                + 1;
            linenum = TagOldLine(ptr->dwName, linenum);
            addr = GetBreakpointAddress(ptr->dwName, &linenum, FALSE);
            if (addr)
            {
                SetTempBreakPoint(dbe->dwProcessId, dbe->dwThreadId, addr);
                SaveRegisterContext();
                ReleaseSemaphore(BreakpointSem, 1, 0);
            }
            else
                return FALSE;
        }
        else
            return FALSE;
    }
    return TRUE;
}

//-------------------------------------------------------------------------

int dbgSetBreakPoint(char *name, int linenum, char *extra)
{
    BREAKPOINT **p = &DebugProcess.breakpoints.next;
    if (uState == notDebugging)
        return 1;
    // will be checked when entering debugger
    if (!name)
    {
        // it was from the assembly window
        int addr = linenum;
        while (*p)
        {
            if ((*p)->address == addr)
                return 1 ;
            p = &(*p)->next;
        }
        *p = calloc(1,sizeof(BREAKPOINT));
        if (*p)
        {
            memset(*p, 0, sizeof(BREAKPOINT));
            (*p)->address = addr;
            (*p)->extra = extra;
            GetBreakpointLine(addr, &(*p)->module, &(*p)->linenum);
            if (hwndASM)
                InvalidateRect(hwndASM, 0, 0);
            if (uState == Running)
                allocBreakPoint(DebugProcess.hProcess,  *p);
        }
        return 1;
    }
    else
    {
        // it was from a source module
        int addr = GetBreakpointAddress(name, &linenum, FALSE);
        if (addr)
        {
            while (*p)
            {
                if ((*p)->address == addr)
                    return 1 ;
                p = &(*p)->next;
            }
            *p = calloc(1,sizeof(BREAKPOINT));
            if (*p)
            {
                memset(*p, 0, sizeof(BREAKPOINT));
                (*p)->address = addr;
                (*p)->extra = extra;
                strcpy((*p)->module, name);
                (*p)->linenum = linenum;
                InvalidateRect(hwndASM, 0, 0);
                if (uState == Running)
                    allocBreakPoint(DebugProcess.hProcess,  *p);
            }
            return 1;
        }
        else
            return 0;
        // couldn't locate line, invalid line...
    }
}

//-------------------------------------------------------------------------

void dbgClearBreakPoint(char *name, int linenum)
{
    BREAKPOINT **p = &DebugProcess.breakpoints.next;
    if (uState == notDebugging)
        return ;
    if (!name)
    {
        // from ASM window
        int addr = linenum;
        while (*p)
        {

            if ((*p)->address == addr)
            {
                BREAKPOINT *q =  *p;

                *p = (*p)->next;
                if (uState == Running)
                    freeBreakPoint(DebugProcess.hProcess, q);
                free(q->extra);
                free(q);
                InvalidateRect(hwndASM, 0, 0);
                return ;
            }
            p = &(*p)->next;
        }
    }
    else
    {
        int addr = GetBreakpointAddress(name, &linenum, FALSE);
        if (addr)
        {
            while (*p)
            {
                if ((*p)->address == addr)
                {
                    BREAKPOINT *q =  *p;
                    *p = (*p)->next;
                    if (uState == Running)
                        freeBreakPoint(DebugProcess.hProcess, q);
                    free(q->extra);
                    free(q);
                    if (hwndASM)
                        InvalidateRect(hwndASM, 0, 0);
                    return ;
                }
                p = &(*p)->next;
            }
        }
    }
}

//-------------------------------------------------------------------------

void SetBP(DEBUG_EVENT *dbe)
{
    BREAKPOINT **p = &DebugProcess.breakpoints.next;
    if (hwndASM && GetFocus() == hwndASMBlank)
    {
        int addr = SendMessage(hwndASM, WM_GETCURSORADDRESS, 0, 0);
        Tag(TAG_BP, 0, addr, 0, 0, 0, 0);
        if (uState == Running)
            allocBreakPoint(DebugProcess.hProcess,  *p);
    }
    else
    {
        HWND hWnd = GetFocus();
        int i;
        for (i = 0; i < numberofdrawwindows; i++)
        {
            DWINFO *ptr = (DWINFO*)GetWindowLong(children[i], 0);
            if (ptr->dwHandle == hWnd)
            {
                int addr, linenum;
                SendMessage(ptr->dwHandle, EM_GETSEL, (WPARAM) &linenum, 0);
                linenum = SendMessage(ptr->dwHandle, EM_EXLINEFROMCHAR, 0,
                    linenum) + 1;
                Tag(TAG_BP, ptr->dwName, linenum, 0, 0, 0, 0);
                break;
            }
        }
    }
    InvalidateRect(hwndASM, 0, 0);
}

//-------------------------------------------------------------------------

int isSteppingOut(DEBUG_EVENT *dbe)
{
    if (uState == SteppingOut)
    {
        unsigned char bf = 0;
        ReadProcessMemory(DebugProcess.hProcess, (LPVOID)StoppedThread
            ->regs.Eip, (LPVOID) &bf, 1, 0);
        if (bf == 0xc2 || bf == 0xc3)
        {
            SingleStep(dbe->dwProcessId, dbe->dwThreadId);
            uState = FinishStepOut;
        }
        else
            DoStepOver(dbe);
        return TRUE;
    }
    return FALSE;
}

//-------------------------------------------------------------------------

void StopRunning(int newState)
{
    THREAD *th = DebugProcess.threads;
    if (uState == Running || uState == SteppingOut || uState == StepInOut)
    {
        HANDLE hThisThread = GetCurrentThread();
        int iOldPriority = GetThreadPriority(hThisThread);
        int oldaddr;
        ProcessToTop(GetCurrentProcessId());
        SetThreadPriority(hThisThread, REALTIME_PRIORITY_CLASS +
            THREAD_PRIORITY_BELOW_NORMAL);
        while (th)
        {
            SuspendThread(th->hThread);
            th = th->next;
        }
        GetRegs(0, 0);
        th = DebugProcess.threads;
        th->oldaddr = th->regs.Eip;
        th->regs.Eip = th->breakpoint.address = DebugProcess.dbg_info->base;
        th->breakpoint.active = FALSE;
        allocBreakPoint(DebugProcess.hProcess, &th->breakpoint);
        PostThreadMessage(th->idThread, WM_NULL, 0, 0);
        SetRegs(0, 0);
        th->suspcount = ResumeThread(th->hThread) - 1;
        if ((int)th->suspcount < 0)
            th->suspcount = 0;
        if (th->suspcount)
            while (ResumeThread(th->hThread) > 1)
                ;
        th = th->next;
        while (th)
        {
            ResumeThread(th->hThread);
            th = th->next;
        }
        if (newState != nullState)
            uState = newState;

        /* At this point it still may not stop if there is a deadlock
         * condition, requires further work
         */
        SetThreadPriority(hThisThread, iOldPriority);
        ProcessToTop(DebugProcess.idProcess);
    }
}

//-------------------------------------------------------------------------

void abortDebugThread(void)
{
    int i = 0;
    if (uState != notDebugging)
    {
        if (uState == atBreakpoint || uState == atException)
        {
            uState = Aborting;
            SaveRegisterContext();
            ReleaseSemaphore(BreakpointSem, 1, 0);
        }
        else
        {
            StopRunning(Aborting);
            uState = Aborting;
            SaveRegisterContext();
            ReleaseSemaphore(BreakpointSem, 1, 0);
        }
        while (uState != notDebugging)
        {
            if (++i >= 100)
            {
                ExtendedMessageBox("Debugger", MB_SETFOREGROUND |
                    MB_SYSTEMMODAL, "Internal error - debugger is not aborting")
                    ;
                return ;
            }
            Sleep(100);
        }
    }
    i = SendMessage(hwndToolDebug, TB_GETSTATE, IDM_STARTSTOP, 0);
    SendMessage(hwndToolDebug, TB_SETSTATE, IDM_STARTSTOP, MAKELONG
        (~TBSTATE_CHECKED &i, 0));
}

//-------------------------------------------------------------------------

void abortDebug(void)
{
    DWORD threadhand;
    CloseHandle(CreateThread(0, 0, (LPTHREAD_START_ROUTINE)abortDebugThread, 
        (LPVOID)0, 0, &threadhand));
}

void TranslateFilename(char * szFilename)
{
	char szWin32Name[MAX_PATH];
// sanity checks
   char * pszInfo;
   if (szFilename == NULL || szFilename[0] == 0)
   {
   		return;
   }

// check for "strange" filenames
   pszInfo = strstr(szFilename, "\\SystemRoot\\");
   if (pszInfo == szFilename)
   {
   //       \SystemRoot\System32\smss.exe
   // -->   c:\winnt\System32\smss.exe  using GetWindowsDirectory()
      UINT Len = GetWindowsDirectory(szWin32Name, MAX_PATH);
      if (Len != 0)
      {
         strcat(szWin32Name, "\\");
         strcat(szWin32Name, &szFilename[strlen("\\SystemRoot\\")]);
		strcpy(szFilename, szWin32Name);
         return;
      }
   }
   else
   {
   //       \??\C:\WINNT\system32\winlogon.exe
   // -->   C:\WINNT\system32\winlogon.exe  
      pszInfo = strstr(szFilename, "\\??\\");
      if (pszInfo == szFilename)
      {
         strcpy(szWin32Name, &szFilename[strlen("\\??\\")]);
		  strcpy(szFilename, szWin32Name);
      }
   }
}
BOOL GetFileNameOfDLL(HMODULE hpsapiLib, HANDLE hProcess, DWORD base, char *name)
{
	if (hpsapiLib)
	{
		FARPROC func = GetProcAddress(hpsapiLib, "GetModuleFileNameExA");
		if (func)
		{
			(*func)(hProcess, base, name, 260);
			TranslateFilename(name);
			return TRUE;
		}
	}
	return FALSE;
}
//-------------------------------------------------------------------------

void StartDebug(char *cmd)
{
	BOOL bShownExitCode = FALSE;
    STARTUPINFO stStartInfo;
    PROCESS_INFORMATION stProcessInfo;
	DEBUG_EVENT stDE;
    BOOL bSeenInitialBP = FALSE;
    BOOL bContinue = TRUE;
    BOOL bSeenMain = FALSE, bSetMainBP = FALSE;
    DWORD dwContinueStatus;
    BOOL bRet;
    BOOL ContinueStep = FALSE;
    BREAKPOINT **bp;
	HMODULE hpsapiLib;
    THREAD **th;
    int val, i, hbp;
    BOOL terminating = FALSE, isTerminating = FALSE;
    int base = 0;
    char buf[512],wd[512],*pwd = wd, *pc = cmd;

    // relies on the file name being quoted, which it will be from the thread
    // that started this one
    pc++ ;
    while (*pc && *pc != '"')
        *pwd++ = *pc++ ;
    *pwd = 0;
    pwd = strrchr(wd,'\\') ;
    if (pwd-1 != '\\')
        *pwd = 0 ;
    memset(&stStartInfo, 0, sizeof(STARTUPINFO));
    memset(&stProcessInfo, 0, sizeof(PROCESS_INFORMATION));

    stStartInfo.cb = sizeof(STARTUPINFO);

    bRet = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP |
  		   (debugProject->buildType == BT_CONSOLE ? CREATE_NEW_CONSOLE : 0) |
			DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, NULL, 
			wd,  &stStartInfo, &stProcessInfo);
    if (!bRet)
    {
        ReleaseSemaphore(StartupSem, 1, 0);
        ExtendedMessageBox("Debugger", MB_SETFOREGROUND | MB_SYSTEMMODAL, 
            "Could not execute %s.", cmd);
        return ;
    }
    Sleep(500); /* Needed to make things happy */
    uState = Running;
    InvalidateRect(hwndRegister, 0, TRUE);

    ReleaseSemaphore(StartupSem, 1, 0);

	// this is used to retrieve the names of DLLs as they load...	
	hpsapiLib = LoadLibrary("PSAPI.DLL");

    if (debugProject->dbgview &(1 << DID_ASMWND))
        PostMessage(hwndFrame, WM_COMMAND, IDM_VIEWASM, 0);
    if (debugProject->dbgview &(1 << DID_WATCHWND))
        PostMessage(hwndFrame, WM_COMMAND, IDM_VIEWWATCH, 0);
    if (debugProject->dbgview &(1 << DID_MEMWND))
        PostMessage(hwndFrame, WM_COMMAND, IDM_VIEWDUMP, 0);
    if (debugProject->dbgview &(1 << DID_STACKWND))
        PostMessage(hwndFrame, WM_COMMAND, IDM_VIEWSTACK, 0);
    if (debugProject->dbgview &(1 << DID_THREADWND))
        PostMessage(hwndFrame, WM_COMMAND, IDM_VIEWTHREAD, 0);
    if (debugProject->dbgview &(1 << DID_REGWND))
        PostMessage(hwndFrame, WM_COMMAND, IDM_VIEWREGISTER, 0);

	SelectErrorWindow(ERR_DEBUG_WINDOW);
    // Loop until told to stop.
    SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
    while (TRUE == bContinue)
    {
        // Pause until a debug event notification happens.
        bContinue = WaitForDebugEvent(&stDE, 500);
        if (bContinue)
        {
            switch (stDE.dwDebugEventCode)
            {
                case CREATE_PROCESS_DEBUG_EVENT:
                    {
                        THREAD *newThread = calloc(1,sizeof(THREAD));
						if (debugProject->buildType == BT_CONSOLE)
							SetConsoleCtrlHandler(NULL, TRUE);
                        SetThreadPriority(GetCurrentThread(),
                            THREAD_PRIORITY_NORMAL);
                        // Save the handle information needed for later.
                        DebugProcess.hProcess =
                            stDE.u.CreateProcessInfo.hProcess;
                        DebugProcess.idProcess = stDE.dwProcessId;
                        memset(newThread, 0, sizeof(*newThread));
                        newThread->hThread = stDE.u.CreateProcessInfo.hThread;
                        newThread->idThread = stDE.dwThreadId;
                        strcpy(newThread->name, "main thread");
                        DebugProcess.threads = newThread;
                        dwContinueStatus = DBG_CONTINUE;
                        DebugProcess.dbg_info = GetDebugInfo
                            (stDE.u.CreateProcessInfo.lpBaseOfImage, cmd, FALSE)
                            ;
                        base = stDE.u.CreateProcessInfo.lpBaseOfImage;
                        /* next line has to be deferred to the init bp */
                        TagRegenBreakPoints();
                        GetRegs(stDE.dwProcessId, stDE.dwThreadId);
                        newThread->regs.Dr7 = 0;
                        SetBreakPoints(DebugProcess.idProcess, FALSE);
                        SetRegs(stDE.dwProcessId, stDE.dwThreadId);
                        CloseHandle(stDE.u.CreateProcessInfo.hFile);
                        SetThreadPriority(GetCurrentThread(),
                            THREAD_PRIORITY_LOWEST);
                        dwContinueStatus = DBG_CONTINUE;
                    }
                    break;

                case EXIT_PROCESS_DEBUG_EVENT:
                    if (uState != Aborting && !bShownExitCode)
						if (debugProject->buildFlags & BF_SHOWRETURNCODE)
						{
							DWORD exitCode;
							if (debugProject->buildType == BT_CONSOLE)
							{
								ProcessToTop(stDE.dwProcessId);
							}
							ExtendedMessageBox("Debugger", MB_SETFOREGROUND | MB_SYSTEMMODAL, "Process complete. Exit code: %d", stDE.u.ExitProcess.dwExitCode);
						}
                    {
                        DLL_INFO *dllInfo = DebugProcess.dll_info;
                        #ifdef HBREAK
                            hbpEnd();
                        #endif 
                        DebugProcess.dll_info = 0;

                        FreeDebugInfo(DebugProcess.dbg_info);
                        DebugProcess.dbg_info = 0;
                        CloseHandle(DebugProcess.hProcess);

                        // Created threads may not exit gracefully
                        // in fact one at least will always be left
                        while (DebugProcess.threads)
                        {
                            THREAD *v = DebugProcess.threads;
                            DebugProcess.threads = v->next;
                            CloseHandle(v->hThread);
                            free(v);
                        }
                        PostMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);

                        // System dlls don't get an unload message
                        while (dllInfo)
                        {
                            DLL_INFO *x = dllInfo->next;
                            FreeDebugInfo(dllInfo->dbg_info);
                            free(dllInfo);
                            dllInfo = x;
                        }
                        bp = &DebugProcess.breakpoints.next;
                        while (*bp)
                        {
                            BREAKPOINT *q =  *bp;
                            *bp = (*bp)->next;
                            free(q);
                        }
                        memset(&DebugProcess, 0, sizeof(PROCESS));
                        bContinue = FALSE;
                        dwContinueStatus = DBG_CONTINUE;
                    }
                    break;

                case LOAD_DLL_DEBUG_EVENT:
                    {
                        LPVOID pos;
                        int len;
                        DLL_INFO *dllInfo = (DLL_INFO*)calloc(sizeof(DLL_INFO),
                            1);
                        if (dllInfo)
                        {
                            DLL_INFO **info = &DebugProcess.dll_info;
							dllInfo->name[0] = 0;
                            dllInfo->dbg_info = 0;
                            dllInfo->base = stDE.u.LoadDll.lpBaseOfDll;
                            pos = stDE.u.LoadDll.lpImageName;
                            dllInfo->fUnicode = stDE.u.LoadDll.fUnicode;
                            dllInfo->hFile = stDE.u.LoadDll.hFile;
                            CloseHandle(dllInfo->hFile);
                            SetThreadPriority(GetCurrentThread(),
                                THREAD_PRIORITY_NORMAL);
                            if (pos)
                            {
                                char *ava = "";
                                ReadProcessMemory(DebugProcess.hProcess, pos, 
                                    (LPVOID) &pos, 4, &len);
                                if (pos)
                                {
                                    ReadProcessMemory(DebugProcess.hProcess, 
                                        (LPVOID)pos, (LPVOID)dllInfo->name, 510,
                                        &len);
                                    dllInfo->name[len] = 0;
                                    if (dllInfo->fUnicode)
                                    {
                                        for (i = 0; i < len; i += 2)
                                            dllInfo->name[i / 2] = dllInfo
                                                ->name[i];
                                    }
joinx:
	                                dllInfo->dbg_info = GetDebugInfo((LPVOID)
	                                    dllInfo->base, dllInfo->name, TRUE);
	                                if (dllInfo->dbg_info)
	                                    ava = " ...Debug info loaded";
	                                sprintf(buf, "DLL Loading: %s%s\r\n",
	                                    dllInfo->name, ava);
									SendErrorMessage(ERR_DEBUG_WINDOW, buf);
								}
								else
									if (GetFileNameOfDLL(hpsapiLib, DebugProcess.hProcess, dllInfo->base, &dllInfo->name[0]))
										goto joinx;
                            }
							else
								if (GetFileNameOfDLL(hpsapiLib, DebugProcess.hProcess, dllInfo->base, &dllInfo->name[0]))
									goto joinx;

                            while (*info && (unsigned)(*info)->base < (unsigned)
                                stDE.u.LoadDll.lpBaseOfDll)
                                info = &(*info)->next;
                            dllInfo->next =  *info;
                            *info = dllInfo;
                            if (dllInfo->dbg_info && (debugProject
                                ->buildFlags &BF_BREAKDLL))
                            {
                                int addr = GetMainAddress(dllInfo->dbg_info);
                                if (addr)
                                {
                                    BREAKPOINT **p =
                                        &DebugProcess.breakpoints.next;
                                    while (*p)
                                        p = &(*p)->next;
                                    *p = calloc(sizeof(BREAKPOINT), 1);
                                    if (*p)
                                    {
                                        GetBreakpointLine(addr, &(*p)->module,
                                            &(*p)->linenum);
                                        (*p)->address = addr;
                                        dllInfo->breakpoint = addr;
                                        for (i = 0; i < numberofdrawwindows; i
                                            ++)
                                            InvalidateRect(children[i], 0, 0);
                                    }
                                }
                            }
                            // set breakpoints for recently loaded DLL.
                            TagRegenBreakPoints();
                            GetRegs(stDE.dwProcessId, stDE.dwThreadId);
                            SetBreakPoints(DebugProcess.idProcess, FALSE);
                            SetRegs(stDE.dwProcessId, stDE.dwThreadId);
                            SetThreadPriority(GetCurrentThread(),
                                THREAD_PRIORITY_LOWEST);
                        }
                        dwContinueStatus = DBG_CONTINUE;
                    }
                    break;
                case UNLOAD_DLL_DEBUG_EVENT:
                    {
                        DLL_INFO **info = &DebugProcess.dll_info;
                        while (*info && (*info)->base != (int)
                            stDE.u.UnloadDll.lpBaseOfDll)
                            info = &(*info)->next;

                        if (*info)
                        {
                            DLL_INFO *x = (*info);
                            sprintf(buf, "DLL Unloading: %s\r\n", (*info)->name)
                                ;
							SendErrorMessage(ERR_DEBUG_WINDOW, buf);
                            *info = (*info)->next;
                            FreeDebugInfo(x->dbg_info);
                            free(x);
                        }
                        dwContinueStatus = DBG_CONTINUE;
                    }
                    break;

                case CREATE_THREAD_DEBUG_EVENT:
                    {
                        char name[256];
                        th = &DebugProcess.threads;
                        while (*th)
                            th = &(*th)->next;
                        *th = calloc(1,sizeof(THREAD));
                        if (*th)
                        {
                            memset(*th, 0, sizeof(THREAD));
                            (*th)->idThread = stDE.dwThreadId;
                            (*th)->hThread = stDE.u.CreateThread.hThread;
                        }
                        if (!FindFunctionName(name, (int)
                            stDE.u.CreateThread.lpStartAddress))
                            name[0] = 0;
                        sprintf(buf, "Thread creation: %08x %08x %s\r\n",
                            stDE.dwThreadId, stDE.u.CreateThread.lpStartAddress,
                            name);
                        if (*th)
                            strcpy((*th)->name, name);
						SendErrorMessage(ERR_DEBUG_WINDOW, buf);
                        if (isTerminating)
                            SuspendThread(stDE.u.CreateThread.hThread);
                        GetRegs(stDE.dwProcessId, stDE.dwThreadId);
                        (*th)->regs.Dr7 = 0;
                        SetRegs(stDE.dwProcessId, stDE.dwThreadId);
                        dwContinueStatus = DBG_CONTINUE;
                    }
                    break;
                case EXIT_THREAD_DEBUG_EVENT:
					if (DebugProcess.threads)
                    {
                        th = &DebugProcess.threads;
                        while ((*th) && (*th)->idThread != stDE.dwThreadId)
                            th = &(*th)->next;
                        if (*th)
                        {
                            THREAD *p =  *th;
                            sprintf(buf, "Thread exit: %08x %s\r\n", p
                                ->idThread, p->name);
							SendErrorMessage(ERR_DEBUG_WINDOW, buf);
                            CloseHandle(p->hThread);
                            (*th) = (*th)->next;
                            free(p);
                        }
                    }
					if (stDE.u.ExitThread.dwExitCode == STATUS_CONTROL_C_EXIT)
					{
	                    if (uState != Aborting)
							if (debugProject->buildFlags & BF_SHOWRETURNCODE)
							{
								DWORD exitCode;
								ProcessToTop(stDE.dwProcessId);
								ExtendedMessageBox("Debugger", MB_SETFOREGROUND | MB_SYSTEMMODAL, "Process complete. Exit code: %d", stDE.u.ExitProcess.dwExitCode);
								bShownExitCode = TRUE;
							}
					}
                    dwContinueStatus = DBG_CONTINUE;
                    break;

                case OUTPUT_DEBUG_STRING_EVENT:
                    {
                        char buf2[256];
                        int len = stDE.u.DebugString.nDebugStringLength;
                        if (len > 255)
                            len = 255;
                        memset(buf2, 0, 256);
                        ReadProcessMemory(DebugProcess.hProcess,
                            stDE.u.DebugString.lpDebugStringData, buf2, len, 0);
						SetErrorColor(ERR_DEBUG_WINDOW, 0xff0000);
						SendErrorMessage(ERR_DEBUG_WINDOW, buf2);
                        dwContinueStatus = DBG_CONTINUE;
                    }
                    break;

                case RIP_EVENT:
                    {
                        dwContinueStatus = DBG_CONTINUE;
                    }
                    break;

                case EXCEPTION_DEBUG_EVENT:
                    {
                        switch (stDE.u.Exception.ExceptionRecord.ExceptionCode)
                        {
						case DBG_CONTROL_C:
						case DBG_CONTROL_BREAK:
                        case EXCEPTION_SINGLE_STEP:
                            ClearTraceFlag(stDE.dwProcessId, stDE.dwThreadId);
                            #ifdef HBREAK
                                if (hbp = hbpCheck(stDE.dwThreadId))
                                {
                                    ContinueStep = FALSE;
                                }
                                else
                            #endif 
                            if (ContinueStep)
                            {
                                if (!SittingOnBreakPoint(&stDE))
                                {
                                    ContinueStep = FALSE;
                                    GetRegs(stDE.dwProcessId, stDE.dwThreadId);
                                    SetBreakPoints(stDE.dwProcessId, bSeenMain);
                                    SetRegs(stDE.dwProcessId, stDE.dwThreadId);
                                    dwContinueStatus = DBG_CONTINUE;
                                    break;
                                }
                            }
                        case EXCEPTION_BREAKPOINT:
                            bSeenMain = bSetMainBP;
                            GetRegs(stDE.dwProcessId, stDE.dwThreadId);
                            ClearBreakPoints(stDE.dwProcessId);
                            if (((int)
                                stDE.u.Exception.ExceptionRecord.ExceptionAddress != DebugProcess.breakpoints.address) || stDE.dwThreadId == DebugProcess.idTempBpThread)
                            {
                                if (bSeenInitialBP)
                                {
                                    if 
                                        (stDE.u.Exception.ExceptionRecord.ExceptionCode == EXCEPTION_BREAKPOINT && (isLocalBreakPoint((int)stDE.u.Exception.ExceptionRecord.ExceptionAddress) || (int)stDE.u.Exception.ExceptionRecord.ExceptionAddress == DebugProcess.breakpoints.address))
                                    {
                                        StoppedThread->regs.Eip--;
                                    }
                                    if (StoppedThread == DebugProcess.threads
                                        && StoppedThread->oldaddr)
                                    {
                                        StoppedThread->regs.Eip = StoppedThread
                                            ->oldaddr;
                                       
                                            stDE.u.Exception.ExceptionRecord.ExceptionAddress = (LPVOID)StoppedThread->oldaddr;
                                        while (StoppedThread->suspcount)
                                        {
                                            StoppedThread->suspcount--;
                                            SuspendThread(StoppedThread
                                                ->hThread);
                                        }
                                        StoppedThread->oldaddr = 0;
                                        freeBreakPoint(DebugProcess.hProcess,
                                            &StoppedThread->breakpoint);
                                    }
                                    ClearTempBreakPoint(stDE.dwProcessId);
                                    if (!terminating && uState != SteppingOut
                                        && !IsStepping(&stDE))
                                    {
                                        ProcessToTop(GetCurrentProcessId());
                                        dwContinueStatus = HandleBreakpoint
                                            (&stDE);
                                        ProcessToTop(stDE.dwProcessId);
                                    }
                                    else
                                        dwContinueStatus = DBG_CONTINUE;
                                }
                                else
                                {
                                    DWORD addr;
                                    bSeenInitialBP = TRUE;
                                    /* This had to be deferred for win2K */
                                    DebugProcess.ExitAddr =
                                        FindExitProcessAddress
                                        (DebugProcess.hProcess, base);
                                    if (addr = GetMainAddress
                                        (DebugProcess.dbg_info))
                                    {
                                        if (stopWinMain)
                                            SetTempBreakPoint(stDE.dwProcessId,
                                                stDE.dwThreadId, addr);
                                    }
                                    else
                                    {
                                        ClearTempBreakPoint(stDE.dwProcessId);
                                        if (stopWinMain)
                                            SetTempBreakPoint(stDE.dwProcessId,
                                                stDE.dwThreadId, GetEntryPoint()
                                                );
                                    }
                                    bSetMainBP = TRUE;
									
                                    dwContinueStatus = DBG_CONTINUE;
                                }
                                isSteppingOut(&stDE);
                            }
                            else
                            {
                                dwContinueStatus = DBG_CONTINUE;
                            }
                            // WIN32 doesn't support the DBG_TERMINATE_PROCESS flag, so we
                            // have to go to some effort to get the process terminated.
                            // This started at process creation time, when we found the address
                            // of the ExitProcess function if there was one.
                            doterm: if (dwContinueStatus ==
                                DBG_TERMINATE_PROCESS)
                            {
                                // suspend all the threads so we won't get
                                // exceptions while we are closing.  We have
                                // to defer the actual close until no more events
                                // are coming in to prevent a clash between
                                // the shutdown and threads that are just
                                // starting
                                THREAD *th = DebugProcess.threads;
                                while (th)
                                {
                                    SuspendThread(th->hThread);
                                    th = th->next;
                                }
                                terminating = isTerminating = TRUE;
                                dwContinueStatus = DBG_CONTINUE;
                            }
                            if (!SingleStepping && !isTerminating)
                            if (SittingOnBreakPoint(&stDE))
                            {
                                ContinueStep = TRUE;
                                SingleStep(stDE.dwProcessId, stDE.dwThreadId);
                            }
                            else
                            {
                                SetBreakPoints(stDE.dwProcessId, bSeenMain);
                            }
                            SetRegs(stDE.dwProcessId, stDE.dwThreadId);

                            break;

                        default:
                            GetRegs(stDE.dwProcessId, stDE.dwThreadId);
                            ClearBreakPoints(stDE.dwProcessId);
                            ProcessToTop(GetCurrentProcessId());
                            dwContinueStatus = HandleException(&stDE);
                            if (dwContinueStatus == DBG_TERMINATE_PROCESS)
                                goto doterm;
                            SetRegs(stDE.dwProcessId, stDE.dwThreadId);
                            ProcessToTop(stDE.dwProcessId);
                            break;
                        }
                    }
                    break;

                    // For any other events, just continue on.
                default:
                    {
                        dwContinueStatus = DBG_EXCEPTION_NOT_HANDLED;
                    }
                    break;
            }
        }
        else
        {
            dwContinueStatus = DBG_CONTINUE;
            bContinue = TRUE;
            if (terminating)
            {
                // if we get here all threads have been stopped, and there
                // has been a 0.5 second delay since the last debug event.
                // We assume there are no more debug events sitting there
                // if there were things become unstable when we exit
                terminating = FALSE;
                if (DebugProcess.ExitAddr)
                {
                    // Blast an exit process call into the main thread, and resume it
                    GetRegs(DebugProcess.idProcess, DebugProcess.threads
                        ->idThread);
                    BlastExitProcFunc(DebugProcess.hProcess,
                        DebugProcess.idProcess, StoppedThread->idThread,
                        DebugProcess.ExitAddr);
                    SetRegs(DebugProcess.idProcess, DebugProcess.threads
                        ->idThread);
                    while ((int)ResumeThread(StoppedThread->hThread) > 1)
                        ;
                    PostThreadMessage(stDE.dwThreadId, WM_NULL, 0, 0);
                }
                else
                {
                    // This should never happen, unless we don't have ExitProcess
                    // in the executable file.  Our tools don't do that.
                    TerminateProcess(DebugProcess.hProcess, 0);
                    ExtendedMessageBox("Debugger", MB_SETFOREGROUND |
                        MB_SYSTEMMODAL, 
                        "A forced termination has been used.\n  This may leave the system in an unstable state.");
                }
            }
        }
        // Pass on to the operating system.
        ContinueDebugEvent(stDE.dwProcessId, stDE.dwThreadId, dwContinueStatus);

    }
	if (debugProject->buildType == BT_CONSOLE)
	{
		FreeConsole();
	}
    CloseHandle(stProcessInfo.hThread);
    CloseHandle(stProcessInfo.hProcess);

    CloseHandle(StartupSem);
    CloseHandle(BreakpointSem);
    debugProject->dbgview = 0;
    debugProject->dbgview |= dmgrHideWindow(DID_ASMWND, TRUE) << DID_ASMWND;
    debugProject->dbgview |= dmgrHideWindow(DID_WATCHWND, TRUE) <<
        DID_WATCHWND;
    debugProject->dbgview |= dmgrHideWindow(DID_MEMWND, TRUE) << DID_MEMWND;
    debugProject->dbgview |= dmgrHideWindow(DID_STACKWND, TRUE) <<
        DID_STACKWND;
    debugProject->dbgview |= dmgrHideWindow(DID_THREADWND, TRUE) <<
        DID_THREADWND;
    debugProject->dbgview |= dmgrHideWindow(DID_REGWND, TRUE) << DID_REGWND;

	PostMessage(hwndFrame, WM_INITMENUPOPUP, 0, 0);

    ProcessToTop(GetCurrentProcessId());
    uState = notDebugging;
    PostMessage(hwndRegister, WM_COMMAND, ID_SETADDRESS, 0);
    //    PostMessage(hwndWatch,WM_ADDWATCH,0,0) ;
    InvalidateRect(hwndRegister, 0, TRUE);
    i = SendMessage(hwndToolDebug, TB_GETSTATE, IDM_STARTSTOP, 0);
    SendMessage(hwndToolDebug, TB_SETSTATE, IDM_STARTSTOP, MAKELONG
        (~TBSTATE_CHECKED &i, 0));
    RedrawAllBreakpoints();
    PostMessage(hwndFrame, WM_REDRAWTOOLBAR, 0, 0);
	if (hpsapiLib)
		FreeLibrary(hpsapiLib);
}
