Beispiel #1
0
/*************************************************************
 *            __wine_exception_handler (NTDLL.@)
 *
 * Exception handler for exception blocks declared in Wine code.
 */
DWORD __wine_exception_handler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame,
                                CONTEXT *context, LPVOID pdispatcher )
{
    __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame;

    if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))
        return ExceptionContinueSearch;
    if (wine_frame->u.filter)
    {
        EXCEPTION_POINTERS ptrs;
        ptrs.ExceptionRecord = record;
        ptrs.ContextRecord = context;
        switch(wine_frame->u.filter( &ptrs ))
        {
        case EXCEPTION_CONTINUE_SEARCH:
            return ExceptionContinueSearch;
        case EXCEPTION_CONTINUE_EXECUTION:
            return ExceptionContinueExecution;
        case EXCEPTION_EXECUTE_HANDLER:
            break;
        default:
            MESSAGE( "Invalid return value from exception filter\n" );
            assert( FALSE );
        }
    }
    /* hack to make GetExceptionCode() work in handler */
    wine_frame->ExceptionCode   = record->ExceptionCode;
    wine_frame->ExceptionRecord = wine_frame;

    RtlUnwind( frame, 0, record, 0 );
    __wine_pop_frame( frame );
    longjmp( wine_frame->jmp, 1 );
}
Beispiel #2
0
/*******************************************************************
 *         EXC_CallHandler
 *
 * Call an exception handler, setting up an exception frame to catch exceptions
 * happening during the handler execution.
 * Please do not change the first 4 parameters order in any way - some exceptions handlers
 * rely on Base Pointer (EBP) to have a fixed position related to the exception frame
 */
static DWORD EXC_CallHandler( EXCEPTION_RECORD *record, EXCEPTION_FRAME *frame,
                              CONTEXT *context, EXCEPTION_FRAME **dispatcher,
                              PEXCEPTION_HANDLER handler, PEXCEPTION_HANDLER nested_handler)
{
    EXC_NESTED_FRAME newframe;
    DWORD ret;

    newframe.frame.Handler = nested_handler;
    newframe.prevFrame     = frame;
    __wine_push_frame( &newframe.frame );
    TRACE( "calling handler at %p code=%lx flags=%lx\n",
           handler, record->ExceptionCode, record->ExceptionFlags );
    ret = handler( record, frame, context, dispatcher );
    TRACE( "handler returned %lx\n", ret );
    __wine_pop_frame( &newframe.frame );
    return ret;
}
Beispiel #3
0
/**********************************************************************
 *           K32WOWCallback16Ex         (KERNEL32.55)
 */
BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags,
                                DWORD cbArgs, LPVOID pArgs, LPDWORD pdwRetCode )
{
#ifdef __i386__
    /*
     * Arguments must be prepared in the correct order by the caller
     * (both for PASCAL and CDECL calling convention), so we simply
     * copy them to the 16-bit stack ...
     */
    char *stack = (char *)CURRENT_STACK16 - cbArgs;

    memcpy( stack, pArgs, cbArgs );

    if (dwFlags & (WCB16_REGS|WCB16_REGS_LONG))
    {
        CONTEXT *context = (CONTEXT *)pdwRetCode;

        if (TRACE_ON(relay))
        {
            DWORD count = cbArgs / sizeof(WORD);
            WORD * wstack = (WORD *)stack;

            DPRINTF("%04lx:CallTo16(func=%04lx:%04x,ds=%04lx",
                    GetCurrentThreadId(),
                    context->SegCs, LOWORD(context->Eip), context->SegDs );
            while (count) DPRINTF( ",%04x", wstack[--count] );
            DPRINTF(") ss:sp=%04x:%04x",
                    SELECTOROF(NtCurrentTeb()->WOW32Reserved), OFFSETOF(NtCurrentTeb()->WOW32Reserved) );
            DPRINTF(" ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x bp=%04x es=%04x fs=%04x\n",
                    (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
                    (WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi,
                    (WORD)context->Ebp, (WORD)context->SegEs, (WORD)context->SegFs );
            SYSLEVEL_CheckNotLevel( 2 );
        }

        if (context->EFlags & 0x00020000)  /* v86 mode */
        {
            EXCEPTION_REGISTRATION_RECORD frame;
            frame.Handler = vm86_handler;
            __wine_push_frame( &frame );
            __wine_enter_vm86( context );
            __wine_pop_frame( &frame );
        }
        else
        {
            /* push return address */
            if (dwFlags & WCB16_REGS_LONG)
            {
                stack -= sizeof(DWORD);
                *((DWORD *)stack) = HIWORD(call16_ret_addr);
                stack -= sizeof(DWORD);
                *((DWORD *)stack) = LOWORD(call16_ret_addr);
                cbArgs += 2 * sizeof(DWORD);
            }
            else
            {
                stack -= sizeof(SEGPTR);
                *((SEGPTR *)stack) = call16_ret_addr;
                cbArgs += sizeof(SEGPTR);
            }

            /*
             * Start call by checking for pending events.
             * Note that wine_call_to_16_regs overwrites context stack
             * pointer so we may modify it here without a problem.
             */
            if (NtCurrentTeb()->dpmi_vif)
            {
                context->SegSs = wine_get_ds();
                context->Esp   = (DWORD)stack;
                insert_event_check( context );
                cbArgs += (DWORD)stack - context->Esp;
            }

            _EnterWin16Lock();
            wine_call_to_16_regs( context, cbArgs, call16_handler );
            _LeaveWin16Lock();
        }

        if (TRACE_ON(relay))
        {
            DPRINTF("%04lx:RetFrom16() ss:sp=%04x:%04x ",
                    GetCurrentThreadId(), SELECTOROF(NtCurrentTeb()->WOW32Reserved),
                    OFFSETOF(NtCurrentTeb()->WOW32Reserved));
            DPRINTF(" ax=%04x bx=%04x cx=%04x dx=%04x bp=%04x sp=%04x\n",
                    (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
                    (WORD)context->Edx, (WORD)context->Ebp, (WORD)context->Esp );
            SYSLEVEL_CheckNotLevel( 2 );
        }
    }
    else
    {
        DWORD ret;

        if (TRACE_ON(relay))
        {
            DWORD count = cbArgs / sizeof(WORD);
            WORD * wstack = (WORD *)stack;

            DPRINTF("%04lx:CallTo16(func=%04x:%04x,ds=%04x",
                    GetCurrentThreadId(), HIWORD(vpfn16), LOWORD(vpfn16),
                    SELECTOROF(NtCurrentTeb()->WOW32Reserved) );
            while (count) DPRINTF( ",%04x", wstack[--count] );
            DPRINTF(") ss:sp=%04x:%04x\n",
                    SELECTOROF(NtCurrentTeb()->WOW32Reserved), OFFSETOF(NtCurrentTeb()->WOW32Reserved) );
            SYSLEVEL_CheckNotLevel( 2 );
        }

        /* push return address */
        stack -= sizeof(SEGPTR);
        *((SEGPTR *)stack) = call16_ret_addr;
        cbArgs += sizeof(SEGPTR);

        /*
         * Actually, we should take care whether the called routine cleans up
         * its stack or not.  Fortunately, our wine_call_to_16 core doesn't rely on
         * the callee to do so; after the routine has returned, the 16-bit
         * stack pointer is always reset to the position it had before.
         */
        _EnterWin16Lock();
        ret = wine_call_to_16( (FARPROC16)vpfn16, cbArgs, call16_handler );
        if (pdwRetCode) *pdwRetCode = ret;
        _LeaveWin16Lock();

        if (TRACE_ON(relay))
        {
            DPRINTF("%04lx:RetFrom16() ss:sp=%04x:%04x retval=%08lx\n",
                    GetCurrentThreadId(), SELECTOROF(NtCurrentTeb()->WOW32Reserved),
                    OFFSETOF(NtCurrentTeb()->WOW32Reserved), ret);
            SYSLEVEL_CheckNotLevel( 2 );
        }
    }
#else
    assert(0);  /* cannot call to 16-bit on non-Intel architectures */
#endif  /* __i386__ */

    return TRUE;  /* success */
}
Beispiel #4
0
void WINAPI EXC_RtlUnwind( PEXCEPTION_FRAME pEndFrame, LPVOID unusedEip,
                           PEXCEPTION_RECORD pRecord, DWORD returnEax,
                           CONTEXT *context )
{
    EXCEPTION_RECORD record, newrec;
    PEXCEPTION_FRAME frame, dispatch;

#ifdef __i386__
    context->Eax = returnEax;
#endif

    /* build an exception record, if we do not have one */
    if (!pRecord)
    {
        record.ExceptionCode    = STATUS_UNWIND;
        record.ExceptionFlags   = 0;
        record.ExceptionRecord  = NULL;
        record.ExceptionAddress = GET_IP(context);
        record.NumberParameters = 0;
        pRecord = &record;
    }

    pRecord->ExceptionFlags |= EH_UNWINDING | (pEndFrame ? 0 : EH_EXIT_UNWIND);

    TRACE( "code=%lx flags=%lx\n", pRecord->ExceptionCode, pRecord->ExceptionFlags );

    /* get chain of exception frames */
    frame = NtCurrentTeb()->except;
    while ((frame != (PEXCEPTION_FRAME)0xffffffff) && (frame != pEndFrame))
    {
        /* Check frame address */
        if (pEndFrame && (frame > pEndFrame))
        {
            newrec.ExceptionCode    = STATUS_INVALID_UNWIND_TARGET;
            newrec.ExceptionFlags   = EH_NONCONTINUABLE;
            newrec.ExceptionRecord  = pRecord;
            newrec.NumberParameters = 0;
            RtlRaiseException( &newrec );  /* never returns */
        }
        if (((void*)frame < NtCurrentTeb()->stack_low) ||
            ((void*)(frame+1) > NtCurrentTeb()->stack_top) ||
            (int)frame & 3)
        {
            newrec.ExceptionCode    = STATUS_BAD_STACK;
            newrec.ExceptionFlags   = EH_NONCONTINUABLE;
            newrec.ExceptionRecord  = pRecord;
            newrec.NumberParameters = 0;
            RtlRaiseException( &newrec );  /* never returns */
        }

        /* Call handler */
        switch(EXC_CallHandler( pRecord, frame, context, &dispatch,
                                frame->Handler, EXC_UnwindHandler ))
        {
        case ExceptionContinueSearch:
            break;
        case ExceptionCollidedUnwind:
            frame = dispatch;
            break;
        default:
            newrec.ExceptionCode    = STATUS_INVALID_DISPOSITION;
            newrec.ExceptionFlags   = EH_NONCONTINUABLE;
            newrec.ExceptionRecord  = pRecord;
            newrec.NumberParameters = 0;
            RtlRaiseException( &newrec );  /* never returns */
            break;
        }
        frame = __wine_pop_frame( frame );
    }
}
Beispiel #5
0
/**********************************************************************
 *           K32WOWCallback16Ex         (KERNEL32.55)
 */
BOOL WINAPI K32WOWCallback16Ex( DWORD vpfn16, DWORD dwFlags,
                                DWORD cbArgs, LPVOID pArgs, LPDWORD pdwRetCode )
{
    /*
     * Arguments must be prepared in the correct order by the caller
     * (both for PASCAL and CDECL calling convention), so we simply
     * copy them to the 16-bit stack ...
     */
    char *stack = (char *)CURRENT_STACK16 - cbArgs;

    memcpy( stack, pArgs, cbArgs );

    if (dwFlags & (WCB16_REGS|WCB16_REGS_LONG))
    {
        CONTEXT *context = (CONTEXT *)pdwRetCode;

        if (TRACE_ON(relay))
        {
            DWORD count = cbArgs / sizeof(WORD);
            WORD * wstack = (WORD *)stack;

            TRACE_(relay)( "\1CallTo16(func=%04x:%04x", context->SegCs, LOWORD(context->Eip) );
            while (count) TRACE_(relay)( ",%04x", wstack[--count] );
            TRACE_(relay)( ") ss:sp=%04x:%04x ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x bp=%04x ds=%04x es=%04x\n",
                           SELECTOROF(NtCurrentTeb()->WOW32Reserved),
                           OFFSETOF(NtCurrentTeb()->WOW32Reserved),
                           (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
                           (WORD)context->Edx, (WORD)context->Esi, (WORD)context->Edi,
                           (WORD)context->Ebp, (WORD)context->SegDs, (WORD)context->SegEs );
            SYSLEVEL_CheckNotLevel( 2 );
        }

        if (context->EFlags & 0x00020000)  /* v86 mode */
        {
            EXCEPTION_REGISTRATION_RECORD frame;
            frame.Handler = vm86_handler;
            errno = 0;
            __wine_push_frame( &frame );
            __wine_enter_vm86( context );
            __wine_pop_frame( &frame );
            if (errno != 0)  /* enter_vm86 will fail with ENOSYS on x64 kernels */
            {
                WARN("__wine_enter_vm86 failed (errno=%d)\n", errno);
                if (errno == ENOSYS)
                    SetLastError(ERROR_NOT_SUPPORTED);
                else
                    SetLastError(ERROR_GEN_FAILURE);
                return FALSE;
            }
        }
        else
        {
            /* push return address */
            if (dwFlags & WCB16_REGS_LONG)
            {
                stack -= sizeof(DWORD);
                *((DWORD *)stack) = HIWORD(call16_ret_addr);
                stack -= sizeof(DWORD);
                *((DWORD *)stack) = LOWORD(call16_ret_addr);
                cbArgs += 2 * sizeof(DWORD);
            }
            else
            {
                stack -= sizeof(SEGPTR);
                *((SEGPTR *)stack) = call16_ret_addr;
                cbArgs += sizeof(SEGPTR);
            }

            /*
             * Start call by checking for pending events.
             * Note that wine_call_to_16_regs overwrites context stack
             * pointer so we may modify it here without a problem.
             */
            if (get_vm86_teb_info()->dpmi_vif)
            {
                context->SegSs = wine_get_ds();
                context->Esp   = (DWORD)stack;
                insert_event_check( context );
                cbArgs += (DWORD)stack - context->Esp;
            }

            _EnterWin16Lock();
            wine_call_to_16_regs( context, cbArgs, call16_handler );
            _LeaveWin16Lock();
        }

        if (TRACE_ON(relay))
        {
            TRACE_(relay)( "\1RetFrom16() ss:sp=%04x:%04x ax=%04x bx=%04x cx=%04x dx=%04x bp=%04x sp=%04x\n",
                           SELECTOROF(NtCurrentTeb()->WOW32Reserved),
                           OFFSETOF(NtCurrentTeb()->WOW32Reserved),
                           (WORD)context->Eax, (WORD)context->Ebx, (WORD)context->Ecx,
                           (WORD)context->Edx, (WORD)context->Ebp, (WORD)context->Esp );
            SYSLEVEL_CheckNotLevel( 2 );
        }
    }
    else
    {
        DWORD ret;

        if (TRACE_ON(relay))
        {
            DWORD count = cbArgs / sizeof(WORD);
            WORD * wstack = (WORD *)stack;

            TRACE_(relay)( "\1CallTo16(func=%04x:%04x,ds=%04x",
                           HIWORD(vpfn16), LOWORD(vpfn16), SELECTOROF(NtCurrentTeb()->WOW32Reserved) );
            while (count) TRACE_(relay)( ",%04x", wstack[--count] );
            TRACE_(relay)( ") ss:sp=%04x:%04x\n", SELECTOROF(NtCurrentTeb()->WOW32Reserved),
                           OFFSETOF(NtCurrentTeb()->WOW32Reserved) );
            SYSLEVEL_CheckNotLevel( 2 );
        }

        /* push return address */
        stack -= sizeof(SEGPTR);
        *((SEGPTR *)stack) = call16_ret_addr;
        cbArgs += sizeof(SEGPTR);

        /*
         * Actually, we should take care whether the called routine cleans up
         * its stack or not.  Fortunately, our wine_call_to_16 core doesn't rely on
         * the callee to do so; after the routine has returned, the 16-bit
         * stack pointer is always reset to the position it had before.
         */
        _EnterWin16Lock();
        ret = wine_call_to_16( (FARPROC16)vpfn16, cbArgs, call16_handler );
        if (pdwRetCode) *pdwRetCode = ret;
        _LeaveWin16Lock();

        if (TRACE_ON(relay))
        {
            TRACE_(relay)( "\1RetFrom16() ss:sp=%04x:%04x retval=%08x\n",
                           SELECTOROF(NtCurrentTeb()->WOW32Reserved),
                           OFFSETOF(NtCurrentTeb()->WOW32Reserved), ret );
            SYSLEVEL_CheckNotLevel( 2 );
        }
    }

    return TRUE;  /* success */
}