예제 #1
0
LONG WINAPI PtokaX_UnhandledExceptionFilter(LPEXCEPTION_POINTERS ExceptionInfo) {
    static volatile LONG PermLock = 0;

    // When unhandled exception happen then permanently 'lock' here. We terminate after first exception.
    while(InterlockedExchange(&PermLock, 1) == 1) {
		::Sleep(10);
	}

    // Set failure hook
	__pfnDliFailureHook2 = PtokaX_FailHook;

    // Check if we have debug symbols
    if(FileExist(sDebugSymbolsFile.c_str()) == false) {
#ifdef _BUILD_GUI
        ::MessageBox(NULL, "Something bad happen and PtokaX crashed. PtokaX was not able to collect any information why this happen because file with debug symbols"
			" (PtokaX.pdb) is missing. If you know why this crash happen then please report it as bug to [email protected]!",
            "PtokaX crashed!", MB_OK | MB_ICONERROR);
#else
        AppendLog("Something bad happen and PtokaX crashed. PtokaX was not able to collect any information why this happen because file with debug symbols"
            " (PtokaX.pdb) is missing. If you know why this crash happen then please report it as bug to [email protected]!");
#endif

        ExceptionHandlingUnitialize();

		exit(EXIT_FAILURE);
	}

	// Initialize debug symbols
    SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_FAIL_CRITICAL_ERRORS | SYMOPT_LOAD_LINES);
    if(SymInitialize(GetCurrentProcess(), PATH.c_str(), TRUE) == FALSE) {
#ifdef _BUILD_GUI
        ::MessageBox(NULL, "Something bad happen and PtokaX crashed. PtokaX was not able to collect any information why this happen because initializatin of"
			" debug symbols failed. If you know why this crash happen then please report it as bug to [email protected]!",
            "PtokaX crashed!", MB_OK | MB_ICONERROR);
#else
        AppendLog("Something bad happen and PtokaX crashed. PtokaX was not able to collect any information why this happen because initializatin of"
            " debug symbols failed. If you know why this crash happen then please report it as bug to [email protected]!");
#endif

        ExceptionHandlingUnitialize();

		exit(EXIT_FAILURE);
    }

    // Generate crash log filename
    time_t acc_time;
    time(&acc_time);

    struct tm *tm = localtime(&acc_time);
    strftime(sDebugBuf, 128, "Crash-%d.%m.%Y-%H.%M.%S.log", tm);

    // Open crash file
    FILE * fw = fopen((sLogPath + sDebugBuf).c_str(), "w");
    if(fw == NULL) {
#ifdef _BUILD_GUI
        ::MessageBox(NULL, "Something bad happen and PtokaX crashed. PtokaX was not able to create file with information why this crash happen."
			" If you know why this crash happen then please report it as bug to [email protected]!",
            "PtokaX crashed!", MB_OK | MB_ICONERROR);
#else
        AppendLog("Something bad happen and PtokaX crashed. PtokaX was not able to create file with information why this crash happen."
            " If you know why this crash happen then please report it as bug to [email protected]!");
#endif

        ExceptionHandlingUnitialize();
        SymCleanup(GetCurrentProcess());

		exit(EXIT_FAILURE);
    }

    string sCrashMsg = "Something bad happen and PtokaX crashed. PtokaX collected information why this crash happen to file ";
    sCrashMsg += string(sDebugBuf);
    sCrashMsg += ", please send that file to [email protected]!";

    // Write PtokaX version, build and exception code
	fprintf(fw, "PtokaX version: " PtokaXVersionString " [build " BUILD_NUMBER "]"
#ifdef _M_X64
        " (x64)"
#endif
        "\nException Code: %x\n", ExceptionInfo->ExceptionRecord->ExceptionCode);

    {
        // Write windoze version where we crashed if is possible
        OSVERSIONINFOEX ver;
        memset(&ver, 0, sizeof(OSVERSIONINFOEX));
        ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

        if(GetVersionEx((OSVERSIONINFO*)&ver) != 0) {
			fprintf(fw, "Windows version: %d.%d SP: %d\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.wServicePackMajor);
        }
    }

    // Write date and time when crash happen
    strftime(sDebugBuf, 128, "Date and time: %d.%m.%Y %H:%M:%S\n\n", tm);
    fprintf(fw, sDebugBuf);

    STACKFRAME64 sf64CallStack;
    memset(&sf64CallStack, 0, sizeof(STACKFRAME64));

    sf64CallStack.AddrPC.Mode      = AddrModeFlat;
    sf64CallStack.AddrStack.Mode   = AddrModeFlat;
    sf64CallStack.AddrFrame.Mode   = AddrModeFlat;

#ifdef _M_X64
    sf64CallStack.AddrPC.Offset    = ExceptionInfo->ContextRecord->Rip;
    sf64CallStack.AddrStack.Offset = ExceptionInfo->ContextRecord->Rsp;
    sf64CallStack.AddrFrame.Offset = ExceptionInfo->ContextRecord->Rbp;
#else
    sf64CallStack.AddrPC.Offset    = ExceptionInfo->ContextRecord->Eip;
    sf64CallStack.AddrStack.Offset = ExceptionInfo->ContextRecord->Esp;
    sf64CallStack.AddrFrame.Offset = ExceptionInfo->ContextRecord->Ebp;
#endif

	// Write where crash happen
    fprintf(fw, "Exception location:\n");

    GetSourceFileInfo(sf64CallStack.AddrPC.Offset, fw);
	GetFunctionInfo(sf64CallStack.AddrPC.Offset, fw);

	// Try to write callstack
    fprintf(fw, "\nCall stack:\n");

    // We don't want it like never ending story, limit call stack to 100 lines
	for(uint32_t ui32i = 0; ui32i < 100; ui32i++) {
		if(StackWalk64(
#ifdef _M_X64
			IMAGE_FILE_MACHINE_AMD64,
#else
			IMAGE_FILE_MACHINE_I386,
#endif
			GetCurrentProcess(), GetCurrentThread(), &sf64CallStack, ExceptionInfo->ContextRecord, NULL,
            SymFunctionTableAccess64, SymGetModuleBase64, NULL) == FALSE || sf64CallStack.AddrFrame.Offset == 0) {
            break;
        }

        GetSourceFileInfo(sf64CallStack.AddrPC.Offset, fw);
        GetFunctionInfo(sf64CallStack.AddrPC.Offset, fw);
	}

	fclose(fw);

#ifdef _BUILD_GUI
    ::MessageBox(NULL, sCrashMsg.c_str(), "PtokaX crashed!", MB_OK | MB_ICONERROR);
#else
    AppendLog(sCrashMsg.c_str());
#endif

    ExceptionHandlingUnitialize();
    SymCleanup(GetCurrentProcess());

    exit(EXIT_FAILURE);
}
예제 #2
0
Js::FunctionInfo *InliningDecider::Inline(Js::FunctionBody *const inliner, Js::FunctionInfo* functionInfo,
    bool isConstructorCall, bool isPolymorphicCall, uint16 constantArgInfo, Js::ProfileId callSiteId, uint recursiveInlineDepth, bool allowRecursiveInlining)
{
#if defined(DBG_DUMP) || defined(ENABLE_DEBUG_CONFIG_OPTIONS)
    char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
    char16 debugStringBuffer2[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
#endif
    Js::FunctionProxy * proxy = functionInfo->GetFunctionProxy();
    if (proxy && proxy->IsFunctionBody())
    {
        if (isLoopBody && PHASE_OFF(Js::InlineInJitLoopBodyPhase, this->topFunc))
        {
            INLINE_TESTTRACE_VERBOSE(_u("INLINING: Skip Inline: Jit loop body: %s (%s)\n"), this->topFunc->GetDisplayName(),
                this->topFunc->GetDebugNumberSet(debugStringBuffer));
            return nullptr;
        }

        // Note: disable inline for debugger, as we can't bailout at return from function.
        // Alternative can be generate this bailout as part of inline, which can be done later as perf improvement.
        const auto inlinee = proxy->GetFunctionBody();
        Assert(this->jitMode == ExecutionMode::FullJit);
        if (PHASE_OFF(Js::InlinePhase, inlinee) ||
            PHASE_OFF(Js::GlobOptPhase, inlinee) ||
            !ContinueInliningUserDefinedFunctions(this->bytecodeInlinedCount) ||
            this->isInDebugMode)
        {
            return nullptr;
        }

        if (functionInfo->IsDeferred() || inlinee->GetByteCode() == nullptr)
        {
            // DeferredParse...
            INLINE_TESTTRACE(_u("INLINING: Skip Inline: No bytecode\tInlinee: %s (%s)\tCaller: %s (%s)\n"),
                inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inliner->GetDisplayName(),
                inliner->GetDebugNumberSet(debugStringBuffer2));
            return nullptr;
        }

#ifdef _M_IX86
        if (inlinee->GetHasTry())
        {
            INLINE_TESTTRACE(_u("INLINING: Skip Inline: Has try\tInlinee: %s (%s)\tCaller: %s (%s)\n"),
            inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inliner->GetDisplayName(),
            inliner->GetDebugNumberSet(debugStringBuffer2));
            return nullptr;
        }
#endif

        // This is a hard limit as the argOuts array is statically sized.
        if (inlinee->GetInParamsCount() > Js::InlineeCallInfo::MaxInlineeArgoutCount)
        {
            INLINE_TESTTRACE(_u("INLINING: Skip Inline: Params count greater then MaxInlineeArgoutCount\tInlinee: %s (%s)\tParamcount: %d\tMaxInlineeArgoutCount: %d\tCaller: %s (%s)\n"),
                inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inlinee->GetInParamsCount(), Js::InlineeCallInfo::MaxInlineeArgoutCount,
                inliner->GetDisplayName(), inliner->GetDebugNumberSet(debugStringBuffer2));
            return nullptr;
        }

        // Wasm functions can have no params
        if (inlinee->GetInParamsCount() == 0 && !inlinee->GetIsAsmjsMode())
        {
            // Inline candidate has no params, not even a this pointer.  This can only be the global function,
            // which we shouldn't inline.
            INLINE_TESTTRACE(_u("INLINING: Skip Inline: Params count is zero!\tInlinee: %s (%s)\tParamcount: %d\tCaller: %s (%s)\n"),
                inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inlinee->GetInParamsCount(),
                inliner->GetDisplayName(), inliner->GetDebugNumberSet(debugStringBuffer2));
            return nullptr;
        }

        if (inlinee->GetDontInline())
        {
            INLINE_TESTTRACE(_u("INLINING: Skip Inline: Do not inline\tInlinee: %s (%s)\tCaller: %s (%s)\n"),
                inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inliner->GetDisplayName(),
                inliner->GetDebugNumberSet(debugStringBuffer2));
            return nullptr;
        }

        // Do not inline a call to a class constructor if it isn't part of a new expression since the call will throw a TypeError anyway.
        if (inlinee->IsClassConstructor() && !isConstructorCall)
        {
            INLINE_TESTTRACE(_u("INLINING: Skip Inline: Class constructor without new keyword\tInlinee: %s (%s)\tCaller: %s (%s)\n"),
                inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inliner->GetDisplayName(),
                inliner->GetDebugNumberSet(debugStringBuffer2));
            return nullptr;
        }

        if (!DeciderInlineIntoInliner(inlinee, inliner, isConstructorCall, isPolymorphicCall, constantArgInfo, recursiveInlineDepth, allowRecursiveInlining))
        {
            return nullptr;
        }

#if defined(ENABLE_DEBUG_CONFIG_OPTIONS)
        TraceInlining(inliner, inlinee->GetDisplayName(), inlinee->GetDebugNumberSet(debugStringBuffer), inlinee->GetByteCodeCount(), this->topFunc, this->bytecodeInlinedCount, inlinee, callSiteId, this->isLoopBody);
#endif

        this->bytecodeInlinedCount += inlinee->GetByteCodeCount();
        return inlinee->GetFunctionInfo();
    }

    Js::OpCode builtInInlineCandidateOpCode;
    ValueType builtInReturnType;
    GetBuiltInInfo(functionInfo, &builtInInlineCandidateOpCode, &builtInReturnType);

    if(builtInInlineCandidateOpCode == 0 && builtInReturnType.IsUninitialized())
    {
        return nullptr;
    }

    Assert(this->jitMode == ExecutionMode::FullJit);
    if (builtInInlineCandidateOpCode != 0 &&
        (
            PHASE_OFF(Js::InlinePhase, inliner) ||
            PHASE_OFF(Js::GlobOptPhase, inliner) ||
            isConstructorCall
        ))
    {
        return nullptr;
    }

    // Note: for built-ins at this time we don't have enough data (the instr) to decide whether it's going to be inlined.
    return functionInfo;
}