コード例 #1
12
ファイル: tgt_minidump.c プロジェクト: howard5888/wineT
static enum dbg_start minidump_do_reload(struct tgt_process_minidump_data* data)
{
    ULONG                       size;
    MINIDUMP_DIRECTORY*         dir;
    void*                       stream;
    DWORD                       pid = 1; /* by default */
    HANDLE                      hProc = (HANDLE)0x900DBAAD;
    int                         i;
    MINIDUMP_MODULE_LIST*       mml;
    MINIDUMP_MODULE*            mm;
    MINIDUMP_STRING*            mds;
    char                        exec_name[1024];
    char                        name[1024];
    unsigned                    len;

    /* fetch PID */
    if (MiniDumpReadDumpStream(data->mapping, MiscInfoStream, &dir, &stream, &size))
    {
        MINIDUMP_MISC_INFO* mmi = (MINIDUMP_MISC_INFO*)stream;
        if (mmi->Flags1 & MINIDUMP_MISC1_PROCESS_ID)
            pid = mmi->ProcessId;
    }

    /* fetch executable name (it's normally the first one in module list) */
    strcpy(exec_name, "<minidump-exec>"); /* default */
    if (MiniDumpReadDumpStream(data->mapping, ModuleListStream, &dir, &stream, &size))
    {
        mml = (MINIDUMP_MODULE_LIST*)stream;
        if (mml->NumberOfModules)
        {
            char*               ptr;

            mm = &mml->Modules[0];
            mds = (MINIDUMP_STRING*)((char*)data->mapping + mm->ModuleNameRva);
            len = WideCharToMultiByte(CP_ACP, 0, mds->Buffer,
                                      mds->Length / sizeof(WCHAR), 
                                      name, sizeof(name) - 1, NULL, NULL);
            name[len] = 0;
            for (ptr = name + len - 1; ptr >= name; ptr--)
            {
                if (*ptr == '/' || *ptr == '\\')
                {
                    strcpy(exec_name, ptr + 1);
                    break;
                }
            }
            if (ptr < name) strcpy(exec_name, name);
        }
    }

    if (MiniDumpReadDumpStream(data->mapping, SystemInfoStream, &dir, &stream, &size))
    {
        MINIDUMP_SYSTEM_INFO*   msi = (MINIDUMP_SYSTEM_INFO*)stream;
        const char *str;
        char tmp[128];

        dbg_printf("WineDbg starting on minidump on pid %lu\n", pid);
        switch (msi->ProcessorArchitecture)
        {
        case PROCESSOR_ARCHITECTURE_UNKNOWN: 
            str = "Unknown";
            break;
        case PROCESSOR_ARCHITECTURE_INTEL:
            strcpy(tmp, "Intel ");
            switch (msi->ProcessorLevel)
            {
            case 3: str = "80386"; break;
            case 4: str = "80486"; break;
            case 5: str = "Pentium"; break;
            case 6: str = "Pentium Pro/II"; break;
            default: str = "???"; break;
            }
            strcat(tmp, str);
            if (msi->ProcessorLevel == 3 || msi->ProcessorLevel == 4)
            {
                if (HIWORD(msi->ProcessorRevision) == 0xFF)
                    sprintf(tmp + strlen(tmp), "-%c%d",
                            'A' + HIBYTE(LOWORD(msi->ProcessorRevision)),
                            LOBYTE(LOWORD(msi->ProcessorRevision)));
                else
                    sprintf(tmp + strlen(tmp), "-%c%d",
                            'A' + HIWORD(msi->ProcessorRevision),
                            LOWORD(msi->ProcessorRevision));
            }
            else sprintf(tmp + strlen(tmp), "-%d.%d",
                         HIWORD(msi->ProcessorRevision),
                         LOWORD(msi->ProcessorRevision));
            str = tmp;
            break;
        case PROCESSOR_ARCHITECTURE_MIPS:
            str = "Mips";
            break;
        case PROCESSOR_ARCHITECTURE_ALPHA:
            str = "Alpha";
            break;
        case PROCESSOR_ARCHITECTURE_PPC:
            str = "PowerPC";
            break;
        default:
            str = "???";
            break;
        }
        dbg_printf("  %s was running on #%d %s CPU%s",
                   exec_name, msi->u.s.NumberOfProcessors, str, 
                   msi->u.s.NumberOfProcessors < 2 ? "" : "s");
        switch (msi->MajorVersion)
        {
        case 3:
            switch (msi->MinorVersion)
            {
            case 51: str = "NT 3.51"; break;
            default: str = "3-????"; break;
            }
            break;
        case 4:
            switch (msi->MinorVersion)
            {
            case 0: str = (msi->PlatformId == VER_PLATFORM_WIN32_NT) ? "NT 4.0" : "95"; break;
            case 10: str = "98"; break;
            case 90: str = "ME"; break;
            default: str = "5-????"; break;
            }
            break;
        case 5:
            switch (msi->MinorVersion)
            {
            case 0: str = "2000"; break;
            case 1: str = "XP"; break;
            case 2: str = "Server 2003"; break;
            default: str = "5-????"; break;
            }
            break;
        default: str = "???"; break;
        }
        dbg_printf(" on Windows %s (%lu)\n", str, msi->BuildNumber);
        /* FIXME CSD: msi->CSDVersionRva */
    }

    dbg_curr_process = dbg_add_process(&be_process_minidump_io, pid, hProc);
    dbg_curr_pid = pid;
    dbg_curr_process->pio_data = data;
    dbg_set_process_name(dbg_curr_process, exec_name);

    SymInitialize(hProc, NULL, FALSE);

    if (MiniDumpReadDumpStream(data->mapping, ThreadListStream, &dir, &stream, &size))
    {
        MINIDUMP_THREAD_LIST*     mtl = (MINIDUMP_THREAD_LIST*)stream;
        MINIDUMP_THREAD*          mt = &mtl->Threads[0];

        dbg_add_thread(dbg_curr_process, mt->ThreadId, NULL, 
                       (void*)(DWORD_PTR)mt->Teb);
    }
    /* first load ELF modules, then do the PE ones */
    if (MiniDumpReadDumpStream(data->mapping, Wine_ElfModuleListStream, &dir,
                               &stream, &size))
    {
        char    buffer[MAX_PATH];

        mml = (MINIDUMP_MODULE_LIST*)stream;
        for (i = 0, mm = &mml->Modules[0]; i < mml->NumberOfModules; i++, mm++)
        {
            mds = (MINIDUMP_STRING*)((char*)data->mapping + mm->ModuleNameRva);
            len = WideCharToMultiByte(CP_ACP, 0, mds->Buffer,
                                      mds->Length / sizeof(WCHAR), 
                                      name, sizeof(name) - 1, NULL, NULL);
            name[len] = 0;
            if (SymFindFileInPath(hProc, NULL, name, (void*)(DWORD_PTR)mm->CheckSum,
                                  0, 0, SSRVOPT_DWORD, buffer, validate_file, NULL))
                SymLoadModule(hProc, NULL, buffer, NULL, mm->BaseOfImage, mm->SizeOfImage);
            else
                SymLoadModuleEx(hProc, NULL, name, NULL, mm->BaseOfImage, mm->SizeOfImage,
                                NULL, SLMFLAG_VIRTUAL);
        }
    }
    if (MiniDumpReadDumpStream(data->mapping, ModuleListStream, &dir, &stream, &size))
    {
        mml = (MINIDUMP_MODULE_LIST*)stream;
        for (i = 0, mm = &mml->Modules[0]; i < mml->NumberOfModules; i++, mm++)
        {
            mds = (MINIDUMP_STRING*)((char*)data->mapping + mm->ModuleNameRva);
            len = WideCharToMultiByte(CP_ACP, 0, mds->Buffer,
                                      mds->Length / sizeof(WCHAR), 
                                      name, sizeof(name) - 1, NULL, NULL);
            name[len] = 0;
            SymLoadModule(hProc, NULL, name, NULL, 
                          mm->BaseOfImage, mm->SizeOfImage);
        }
    }
    if (MiniDumpReadDumpStream(data->mapping, ExceptionStream, &dir, &stream, &size))
    {
        MINIDUMP_EXCEPTION_STREAM*      mes = (MINIDUMP_EXCEPTION_STREAM*)stream;

        if ((dbg_curr_thread = dbg_get_thread(dbg_curr_process, mes->ThreadId)))
        {
            ADDRESS64   addr;

            dbg_curr_tid = mes->ThreadId;
            dbg_curr_thread->in_exception = TRUE;
            dbg_curr_thread->excpt_record.ExceptionCode = mes->ExceptionRecord.ExceptionCode;
            dbg_curr_thread->excpt_record.ExceptionFlags = mes->ExceptionRecord.ExceptionFlags;
            dbg_curr_thread->excpt_record.ExceptionRecord = (void*)(DWORD_PTR)mes->ExceptionRecord.ExceptionRecord;
            dbg_curr_thread->excpt_record.ExceptionAddress = (void*)(DWORD_PTR)mes->ExceptionRecord.ExceptionAddress;
            dbg_curr_thread->excpt_record.NumberParameters = mes->ExceptionRecord.NumberParameters;
            for (i = 0; i < dbg_curr_thread->excpt_record.NumberParameters; i++)
            {
                dbg_curr_thread->excpt_record.ExceptionInformation[i] = mes->ExceptionRecord.ExceptionInformation[i];
            }
            memcpy(&dbg_context, (char*)data->mapping + mes->ThreadContext.Rva,
                   min(sizeof(dbg_context), mes->ThreadContext.DataSize));
            memory_get_current_pc(&addr);
            stack_fetch_frames();
            be_cpu->print_context(dbg_curr_thread->handle, &dbg_context, 0);
            stack_info();
            be_cpu->print_segment_info(dbg_curr_thread->handle, &dbg_context);
            stack_backtrace(mes->ThreadId);
            source_list_from_addr(&addr, 0);
        }
    }
    return start_ok;
}
コード例 #2
0
/******************************************************************
 *		backtrace_tid
 *
 * Do a backtrace on a thread from its process and its identifier
 * (preserves current thread and context information)
 */
static void backtrace_tid(struct dbg_process* pcs, DWORD tid)
{
    struct dbg_thread*  thread = dbg_curr_thread;

    if (!(dbg_curr_thread = dbg_get_thread(pcs, tid)))
        dbg_printf("Unknown thread id (%04x) in process (%04x)\n", tid, pcs->pid);
    else
    {
        CONTEXT context;

        dbg_curr_tid = dbg_curr_thread->tid;
        memset(&context, 0, sizeof(context));
        context.ContextFlags = CONTEXT_FULL;
        if (SuspendThread(dbg_curr_thread->handle) != -1)
        {
            if (!GetThreadContext(dbg_curr_thread->handle, &context))
            {
                dbg_printf("Can't get context for thread %04x in current process\n",
                           tid);
            }
            else
            {
                stack_fetch_frames(&context);
                backtrace();
            }
            ResumeThread(dbg_curr_thread->handle);
        }
        else dbg_printf("Can't suspend thread %04x in current process\n", tid);
    }
    dbg_curr_thread = thread;
    dbg_curr_tid = thread ? thread->tid : 0;
}
コード例 #3
0
static unsigned dbg_handle_debug_event(DEBUG_EVENT* de)
{
    union {
        char	bufferA[256];
        WCHAR	buffer[256];
    } u;
    DWORD       cont = DBG_CONTINUE;

    dbg_curr_pid = de->dwProcessId;
    dbg_curr_tid = de->dwThreadId;

    if ((dbg_curr_process = dbg_get_process(de->dwProcessId)) != NULL)
        dbg_curr_thread = dbg_get_thread(dbg_curr_process, de->dwThreadId);
    else
        dbg_curr_thread = NULL;

    switch (de->dwDebugEventCode)
    {
    case EXCEPTION_DEBUG_EVENT:
        if (!dbg_curr_thread)
        {
            WINE_ERR("%04x:%04x: not a registered process or thread (perhaps a 16 bit one ?)\n",
                     de->dwProcessId, de->dwThreadId);
            break;
        }

        WINE_TRACE("%04x:%04x: exception code=%08x\n",
                   de->dwProcessId, de->dwThreadId,
                   de->u.Exception.ExceptionRecord.ExceptionCode);

        if (dbg_curr_process->continue_on_first_exception)
        {
            dbg_curr_process->continue_on_first_exception = FALSE;
            if (!DBG_IVAR(BreakOnAttach)) break;
        }
        if (dbg_fetch_context())
        {
            cont = dbg_handle_exception(&de->u.Exception.ExceptionRecord,
                                        de->u.Exception.dwFirstChance);
            if (cont && dbg_curr_thread)
            {
                SetThreadContext(dbg_curr_thread->handle, &dbg_context);
            }
        }
        break;

    case CREATE_PROCESS_DEBUG_EVENT:
        dbg_curr_process = dbg_add_process(&be_process_active_io, de->dwProcessId,
                                           de->u.CreateProcessInfo.hProcess);
        if (dbg_curr_process == NULL)
        {
            WINE_ERR("Couldn't create process\n");
            break;
        }
        fetch_module_name(de->u.CreateProcessInfo.lpImageName,
                          de->u.CreateProcessInfo.fUnicode,
                          de->u.CreateProcessInfo.lpBaseOfImage,
                          u.buffer, sizeof(u.buffer) / sizeof(WCHAR), TRUE);

        WINE_TRACE("%04x:%04x: create process '%s'/%p @%p (%u<%u>)\n",
                   de->dwProcessId, de->dwThreadId,
                   wine_dbgstr_w(u.buffer),
                   de->u.CreateProcessInfo.lpImageName,
                   de->u.CreateProcessInfo.lpStartAddress,
                   de->u.CreateProcessInfo.dwDebugInfoFileOffset,
                   de->u.CreateProcessInfo.nDebugInfoSize);
        dbg_set_process_name(dbg_curr_process, u.buffer);

        if (!dbg_init(dbg_curr_process->handle, u.buffer, FALSE))
            dbg_printf("Couldn't initiate DbgHelp\n");
        if (!dbg_load_module(dbg_curr_process->handle, de->u.CreateProcessInfo.hFile, u.buffer,
                             (DWORD_PTR)de->u.CreateProcessInfo.lpBaseOfImage, 0))
            dbg_printf("couldn't load main module (%u)\n", GetLastError());

        WINE_TRACE("%04x:%04x: create thread I @%p\n",
                   de->dwProcessId, de->dwThreadId, de->u.CreateProcessInfo.lpStartAddress);

        dbg_curr_thread = dbg_add_thread(dbg_curr_process,
                                         de->dwThreadId,
                                         de->u.CreateProcessInfo.hThread,
                                         de->u.CreateProcessInfo.lpThreadLocalBase);
        if (!dbg_curr_thread)
        {
            WINE_ERR("Couldn't create thread\n");
            break;
        }
        dbg_init_current_process();
        dbg_init_current_thread(de->u.CreateProcessInfo.lpStartAddress);
        break;

    case EXIT_PROCESS_DEBUG_EVENT:
        WINE_TRACE("%04x:%04x: exit process (%d)\n",
                   de->dwProcessId, de->dwThreadId, de->u.ExitProcess.dwExitCode);

        if (dbg_curr_process == NULL)
        {
            WINE_ERR("Unknown process\n");
            break;
        }
        tgt_process_active_close_process(dbg_curr_process, FALSE);
        dbg_printf("Process of pid=%04x has terminated\n", de->dwProcessId);
        break;

    case CREATE_THREAD_DEBUG_EVENT:
        WINE_TRACE("%04x:%04x: create thread D @%p\n",
                   de->dwProcessId, de->dwThreadId, de->u.CreateThread.lpStartAddress);

        if (dbg_curr_process == NULL)
        {
            WINE_ERR("Unknown process\n");
            break;
        }
        if (dbg_get_thread(dbg_curr_process, de->dwThreadId) != NULL)
        {
            WINE_TRACE("Thread already listed, skipping\n");
            break;
        }

        dbg_curr_thread = dbg_add_thread(dbg_curr_process,
                                         de->dwThreadId,
                                         de->u.CreateThread.hThread,
                                         de->u.CreateThread.lpThreadLocalBase);
        if (!dbg_curr_thread)
        {
            WINE_ERR("Couldn't create thread\n");
            break;
        }
        dbg_init_current_thread(de->u.CreateThread.lpStartAddress);
        break;

    case EXIT_THREAD_DEBUG_EVENT:
        WINE_TRACE("%04x:%04x: exit thread (%d)\n",
                   de->dwProcessId, de->dwThreadId, de->u.ExitThread.dwExitCode);

        if (dbg_curr_thread == NULL)
        {
            WINE_ERR("Unknown thread\n");
            break;
        }
        /* FIXME: remove break point set on thread startup */
        dbg_del_thread(dbg_curr_thread);
        break;

    case LOAD_DLL_DEBUG_EVENT:
        if (dbg_curr_thread == NULL)
        {
            WINE_ERR("Unknown thread\n");
            break;
        }
        fetch_module_name(de->u.LoadDll.lpImageName,
                          de->u.LoadDll.fUnicode,
                          de->u.LoadDll.lpBaseOfDll,
                          u.buffer, sizeof(u.buffer) / sizeof(WCHAR), FALSE);

        WINE_TRACE("%04x:%04x: loads DLL %s @%p (%u<%u>)\n",
                   de->dwProcessId, de->dwThreadId,
                   wine_dbgstr_w(u.buffer), de->u.LoadDll.lpBaseOfDll,
                   de->u.LoadDll.dwDebugInfoFileOffset,
                   de->u.LoadDll.nDebugInfoSize);
        dbg_load_module(dbg_curr_process->handle, de->u.LoadDll.hFile, u.buffer,
                        (DWORD_PTR)de->u.LoadDll.lpBaseOfDll, 0);
        break_set_xpoints(FALSE);
        break_check_delayed_bp();
        break_set_xpoints(TRUE);
        if (DBG_IVAR(BreakOnDllLoad))
        {
            dbg_printf("Stopping on DLL %s loading at 0x%08lx\n",
                       dbg_W2A(u.buffer, -1), (unsigned long)de->u.LoadDll.lpBaseOfDll);
            if (dbg_fetch_context()) cont = 0;
        }
        break;

    case UNLOAD_DLL_DEBUG_EVENT:
        WINE_TRACE("%04x:%04x: unload DLL @%p\n",
                   de->dwProcessId, de->dwThreadId,
                   de->u.UnloadDll.lpBaseOfDll);
        break_delete_xpoints_from_module((unsigned long)de->u.UnloadDll.lpBaseOfDll);
        SymUnloadModule(dbg_curr_process->handle,
                        (unsigned long)de->u.UnloadDll.lpBaseOfDll);
        break;

    case OUTPUT_DEBUG_STRING_EVENT:
        if (dbg_curr_thread == NULL)
        {
            WINE_ERR("Unknown thread\n");
            break;
        }

        memory_get_string(dbg_curr_process,
                          de->u.DebugString.lpDebugStringData, TRUE,
                          de->u.DebugString.fUnicode, u.bufferA, sizeof(u.bufferA));
        WINE_TRACE("%04x:%04x: output debug string (%s)\n",
                   de->dwProcessId, de->dwThreadId, u.bufferA);
        break;

    case RIP_EVENT:
        WINE_TRACE("%04x:%04x: rip error=%u type=%u\n",
                   de->dwProcessId, de->dwThreadId, de->u.RipInfo.dwError,
                   de->u.RipInfo.dwType);
        break;

    default:
        WINE_TRACE("%04x:%04x: unknown event (%x)\n",
                   de->dwProcessId, de->dwThreadId, de->dwDebugEventCode);
    }
    if (!cont) return TRUE;  /* stop execution */
    ContinueDebugEvent(de->dwProcessId, de->dwThreadId, cont);
    return FALSE;  /* continue execution */
}
コード例 #4
0
static DWORD dbg_handle_exception(const EXCEPTION_RECORD* rec, BOOL first_chance)
{
    BOOL                is_debug = FALSE;
    THREADNAME_INFO*    pThreadName;
    struct dbg_thread*  pThread;

    assert(dbg_curr_thread);

    WINE_TRACE("exception=%x first_chance=%c\n",
               rec->ExceptionCode, first_chance ? 'Y' : 'N');

    switch (rec->ExceptionCode)
    {
    case EXCEPTION_BREAKPOINT:
    case EXCEPTION_SINGLE_STEP:
        is_debug = TRUE;
        break;
    case EXCEPTION_NAME_THREAD:
        pThreadName = (THREADNAME_INFO*)(rec->ExceptionInformation);
        if (pThreadName->dwThreadID == -1)
            pThread = dbg_curr_thread;
        else
            pThread = dbg_get_thread(dbg_curr_process, pThreadName->dwThreadID);
        if(!pThread)
        {
            dbg_printf("Thread ID=%04x not in our list of threads -> can't rename\n", pThreadName->dwThreadID);
            return DBG_CONTINUE;
        }
        if (dbg_read_memory(pThreadName->szName, pThread->name, 9))
            dbg_printf("Thread ID=%04x renamed using MS VC6 extension (name==\"%s\")\n",
                       pThread->tid, pThread->name);
        return DBG_CONTINUE;
    }

    if (first_chance && !is_debug && !DBG_IVAR(BreakOnFirstChance) &&
            !(rec->ExceptionFlags & EH_STACK_INVALID))
    {
        /* pass exception to program except for debug exceptions */
        return DBG_EXCEPTION_NOT_HANDLED;
    }

    if (!is_debug)
    {
        /* print some infos */
        dbg_printf("%s: ",
                   first_chance ? "First chance exception" : "Unhandled exception");
        switch (rec->ExceptionCode)
        {
        case EXCEPTION_INT_DIVIDE_BY_ZERO:
            dbg_printf("divide by zero");
            break;
        case EXCEPTION_INT_OVERFLOW:
            dbg_printf("overflow");
            break;
        case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
            dbg_printf("array bounds");
            break;
        case EXCEPTION_ILLEGAL_INSTRUCTION:
            dbg_printf("illegal instruction");
            break;
        case EXCEPTION_STACK_OVERFLOW:
            dbg_printf("stack overflow");
            break;
        case EXCEPTION_PRIV_INSTRUCTION:
            dbg_printf("privileged instruction");
            break;
        case EXCEPTION_ACCESS_VIOLATION:
            if (rec->NumberParameters == 2)
                dbg_printf("page fault on %s access to 0x%08lx",
                           rec->ExceptionInformation[0] == EXCEPTION_WRITE_FAULT ? "write" :
                           rec->ExceptionInformation[0] == EXCEPTION_EXECUTE_FAULT ? "execute" : "read",
                           rec->ExceptionInformation[1]);
            else
                dbg_printf("page fault");
            break;
        case EXCEPTION_DATATYPE_MISALIGNMENT:
            dbg_printf("Alignment");
            break;
        case DBG_CONTROL_C:
            dbg_printf("^C");
            break;
        case CONTROL_C_EXIT:
            dbg_printf("^C");
            break;
        case STATUS_POSSIBLE_DEADLOCK:
        {
            ADDRESS64       addr;

            addr.Mode   = AddrModeFlat;
            addr.Offset = rec->ExceptionInformation[0];

            dbg_printf("wait failed on critical section ");
            print_address(&addr, FALSE);
        }
        if (!DBG_IVAR(BreakOnCritSectTimeOut))
        {
            dbg_printf("\n");
            return DBG_EXCEPTION_NOT_HANDLED;
        }
        break;
        case EXCEPTION_WINE_STUB:
        {
            char dll[32], name[64];
            memory_get_string(dbg_curr_process,
                              (void*)rec->ExceptionInformation[0], TRUE, FALSE,
                              dll, sizeof(dll));
            if (HIWORD(rec->ExceptionInformation[1]))
                memory_get_string(dbg_curr_process,
                                  (void*)rec->ExceptionInformation[1], TRUE, FALSE,
                                  name, sizeof(name));
            else
                sprintf( name, "%ld", rec->ExceptionInformation[1] );
            dbg_printf("unimplemented function %s.%s called", dll, name);
        }
        break;
        case EXCEPTION_WINE_ASSERTION:
            dbg_printf("assertion failed");
            break;
        case EXCEPTION_VM86_INTx:
            dbg_printf("interrupt %02lx in vm86 mode", rec->ExceptionInformation[0]);
            break;
        case EXCEPTION_VM86_STI:
            dbg_printf("sti in vm86 mode");
            break;
        case EXCEPTION_VM86_PICRETURN:
            dbg_printf("PIC return in vm86 mode");
            break;
        case EXCEPTION_FLT_DENORMAL_OPERAND:
            dbg_printf("denormal float operand");
            break;
        case EXCEPTION_FLT_DIVIDE_BY_ZERO:
            dbg_printf("divide by zero");
            break;
        case EXCEPTION_FLT_INEXACT_RESULT:
            dbg_printf("inexact float result");
            break;
        case EXCEPTION_FLT_INVALID_OPERATION:
            dbg_printf("invalid float operation");
            break;
        case EXCEPTION_FLT_OVERFLOW:
            dbg_printf("floating point overflow");
            break;
        case EXCEPTION_FLT_UNDERFLOW:
            dbg_printf("floating point underflow");
            break;
        case EXCEPTION_FLT_STACK_CHECK:
            dbg_printf("floating point stack check");
            break;
        case CXX_EXCEPTION:
            if(rec->NumberParameters == 3 && rec->ExceptionInformation[0] == CXX_FRAME_MAGIC)
                dbg_printf("C++ exception(object = 0x%08lx, type = 0x%08lx)",
                           rec->ExceptionInformation[1], rec->ExceptionInformation[2]);
            else
                dbg_printf("C++ exception with strange parameter count %d or magic 0x%08lx",
                           rec->NumberParameters, rec->ExceptionInformation[0]);
            break;
        default:
            dbg_printf("0x%08x", rec->ExceptionCode);
            break;
        }
    }
    if( (rec->ExceptionFlags & EH_STACK_INVALID) ) {
        dbg_printf( ", invalid program stack" );
    }

    if (dbg_exception_prolog(is_debug, first_chance, rec))
    {
        dbg_interactiveP = TRUE;
        return 0;
    }
    dbg_exception_epilog();

    return DBG_CONTINUE;
}