예제 #1
0
LONG NTAPI vectored_exception_handler_internal(LPEXCEPTION_POINTERS nt_exception)
{
    DWORD code = nt_exception->ExceptionRecord->ExceptionCode;
    void* fault_addr = nt_exception->ExceptionRecord->ExceptionAddress;

    Registers regs;
    // Convert NT context to Registers
    port_thread_context_to_regs(&regs, nt_exception->ContextRecord);

    // Check if TLS structure is set - probably we should produce minidump
    port_tls_data_t* tlsdata = get_private_tls_data();

    if (!tlsdata) // Tread is not attached - attach thread temporarily
    {
        int res;
        tlsdata = (port_tls_data_t*)STD_MALLOC(sizeof(port_tls_data_t));

        if (tlsdata) // Try to attach the thread
            res = port_thread_attach_local(tlsdata, TRUE, TRUE, 0);

        if (!tlsdata || res != 0)
        { // Can't process correctly; perform default actions
            if (FLAG_CORE)
                create_minidump(nt_exception);

            if (FLAG_DBG)
            {
                show_debugger_dialog(); // Workaround; EXCEPTION_CONTINUE_SEARCH does not work
                _exit(-1);
                return EXCEPTION_CONTINUE_SEARCH; // Assert dialog
            }

            _exit(-1);
        }

        // SO for alien thread can't be processed out of VEH
        if (code == STATUS_STACK_OVERFLOW &&
            sd_is_handler_registered(PORT_SIGNAL_STACK_OVERFLOW))
        {
            int result;
            size_t alt_stack_size = ALT_PAGES_COUNT*tlsdata->guard_page_size;
            void* alt_stack = map_alt_stack(alt_stack_size);
            void* stack_bottom = (void*)((POINTER_SIZE_INT)alt_stack + alt_stack_size);

            if (alt_stack)
                result = (int)(POINTER_SIZE_INT)port_call_alt_stack(
                                            port_process_signal, stack_bottom, 4,
                                            PORT_SIGNAL_STACK_OVERFLOW, &regs, fault_addr, FALSE);
            else
                result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, &regs, fault_addr, FALSE);

            if (result == 0)
            {
                if (port_thread_detach_temporary() == 0)
                    STD_FREE(tlsdata);
                if (alt_stack)
                    unmap_alt_stack(alt_stack, alt_stack_size);
                return EXCEPTION_CONTINUE_EXECUTION;
            }

            if (FLAG_CORE)
            {
                if (alt_stack)
                    port_call_alt_stack(create_minidump, stack_bottom, 1, nt_exception);
                else
                    create_minidump(nt_exception);
            }

            if (alt_stack)
                unmap_alt_stack(alt_stack, alt_stack_size);

            if (result > 0)
            {
                show_debugger_dialog(); // Workaround; EXCEPTION_CONTINUE_SEARCH does not work
                _exit(-1);
                shutdown_signals();
                return EXCEPTION_CONTINUE_SEARCH; // Assert dialog
            }

            _exit(-1);
        }
    }

    if (tlsdata->produce_core)
    {
        create_minidump(nt_exception);
        if (!tlsdata->debugger)
            _exit(-1);
    }

    if (tlsdata->debugger)
    {
        show_debugger_dialog(); // Workaround
        _exit(-1);
        // Go to handler to restore CRT/VEH settings and crash once again
//        port_set_longjump_regs(&prepare_assert_dialog, &regs, 1, &regs);
//        port_thread_regs_to_context(nt_exception->ContextRecord, &regs);
//        return EXCEPTION_CONTINUE_EXECUTION;
    }

    switch (code)
    {
    case STATUS_STACK_OVERFLOW:
        if (!sd_is_handler_registered(PORT_SIGNAL_STACK_OVERFLOW))
            return EXCEPTION_CONTINUE_SEARCH;
        break;
    case STATUS_ACCESS_VIOLATION:
        if (!sd_is_handler_registered(PORT_SIGNAL_GPF))
            return EXCEPTION_CONTINUE_SEARCH;
        break;
    case JVMTI_EXCEPTION_STATUS:
        if (!sd_is_handler_registered(PORT_SIGNAL_BREAKPOINT))
            return EXCEPTION_CONTINUE_SEARCH;
        break;
    case STATUS_INTEGER_DIVIDE_BY_ZERO:
    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
    case EXCEPTION_FLT_OVERFLOW:
    case EXCEPTION_FLT_UNDERFLOW:
    case EXCEPTION_INT_OVERFLOW:
        if (!sd_is_handler_registered(PORT_SIGNAL_ARITHMETIC))
            return EXCEPTION_CONTINUE_SEARCH;
        break;
    default:
        return EXCEPTION_CONTINUE_SEARCH;
    }

    if (code == STATUS_STACK_OVERFLOW)
    {
        tlsdata->guard_page_set = FALSE; // GUARD_PAGE was cleared by OS

        if (!tlsdata->restore_guard_page)
            tlsdata->restore_guard_page = TRUE;
    }

    // Prepare to transfering control out of VEH handler
    port_set_longjump_regs(&c_handler, &regs, 4, &regs,
        nt_exception->ExceptionRecord->ExceptionAddress,
        (void*)(size_t)nt_exception->ExceptionRecord->ExceptionCode,
        (void*)(size_t)nt_exception->ExceptionRecord->ExceptionFlags);
    // Convert prepared Registers back to NT context
    port_thread_regs_to_context(nt_exception->ContextRecord, &regs);
    // Return from VEH - presumably continue execution
    return EXCEPTION_CONTINUE_EXECUTION;
}
예제 #2
0
static void general_signal_handler(int signum, siginfo_t* info, void* context)
{
    Registers regs;

    if (!context)
        return;

    // Convert OS context to Registers
    port_thread_context_to_regs(&regs, (ucontext_t*)context);
    void* fault_addr = info ? info->si_addr : NULL;

    // Check if SIGSEGV is produced by port_read/write_memory
    port_tls_data_t* tlsdata = get_private_tls_data();
    if (tlsdata && tlsdata->violation_flag)
    {
        tlsdata->violation_flag = 0;
        regs.set_ip(tlsdata->restart_address);
        return;
    }

    if (!tlsdata) // Tread is not attached - attach thread temporarily
    {
        int res;
        tlsdata = (port_tls_data_t*)STD_MALLOC(sizeof(port_tls_data_t));

        if (tlsdata) // Try to attach the thread
            res = port_thread_attach_local(tlsdata, TRUE, TRUE, 0);

        if (!tlsdata || res != 0)
        {   // Can't process correctly; perform default actions
            if (FLAG_DBG)
            {
                bool result = gdb_crash_handler(&regs);
                _exit(-1); // Exit process if not sucessful...
            }

            if (FLAG_CORE &&
                    signum != SIGABRT) // SIGABRT can't be rethrown
            {
                signal(signum, SIG_DFL); // setup default handler
                return;
            }

            _exit(-1);
        }

        // SIGSEGV can represent SO which can't be processed out of signal handler
        if (signum == SIGSEGV && // This can occur only when a user set an alternative stack
                is_stack_overflow(tlsdata, fault_addr))
        {
            int result = port_process_signal(PORT_SIGNAL_STACK_OVERFLOW, &regs, fault_addr, FALSE);

            if (result == 0)
            {
                if (port_thread_detach_temporary() == 0)
                    STD_FREE(tlsdata);
                return;
            }

            if (result > 0)
                tlsdata->debugger = TRUE;
            else
            {
                if (FLAG_CORE)
                {   // Rethrow crash to generate core
                    signal(signum, SIG_DFL); // setup default handler
                    return;
                }
                _exit(-1);
            }
        }
    }

    if (tlsdata->debugger)
    {
        bool result = gdb_crash_handler(&regs);
        _exit(-1); // Exit process if not sucessful...
    }

    if (signum == SIGABRT && // SIGABRT can't be trown again from c_handler
            FLAG_DBG)
    {   // So attaching GDB right here
        bool result = gdb_crash_handler(&regs);
        _exit(-1); // Exit process if not sucessful...
    }

    if (signum == SIGSEGV &&
            is_stack_overflow(tlsdata, fault_addr))
    {
        // Second SO while previous SO is not processed yet - is GPF
        if (tlsdata->restore_guard_page)
            tlsdata->restore_guard_page = FALSE;
        else
        {   // To process signal on protected stack area
            port_thread_clear_guard_page();
            // Note: the call above does not disable alternative stack
            // It can't be made while we are on alternative stack
            // Alt stack will be disabled explicitly in c_handler()
            tlsdata->restore_guard_page = TRUE;
        }
    }

    // Prepare registers for transfering control out of signal handler
    void* callback = (void*)&c_handler;

    port_set_longjump_regs(callback, &regs, 3,
                           &regs, (void*)(size_t)signum, fault_addr);

    // Convert prepared Registers back to OS context
    port_thread_regs_to_context((ucontext_t*)context, &regs);
    // Return from signal handler to go to C handler
}