Example #1
0
int diag_backtrace(diag_output_t *o, diag_backtrace_param_t *p, diag_context_t *c)
{
    int cur = 0, count;
    STACKFRAME64 stackframe;
    CONTEXT context;
    HANDLE process = GetCurrentProcess();
    HANDLE thread = GetCurrentThread();
    DWORD bytes_written;

    if (c) {
        context = *c->context;
    }
    else {
        RtlCaptureContext(&context);
    }

    if (p->backtrace_count && p->backtrace_count < DIAG_BT_LIMIT) {
        count = p->backtrace_count;
    }
    else {
        count = DIAG_BT_LIMIT;
    }

    memset(&stackframe, 0, sizeof stackframe);
    stackframe.AddrPC.Mode = 
        stackframe.AddrFrame.Mode =
            stackframe.AddrStack.Mode = AddrModeFlat;

#ifdef DIAG_BITS_64
    stackframe.AddrPC.Offset    = context.Rip;
    stackframe.AddrFrame.Offset = context.Rbp;
    stackframe.AddrStack.Offset = context.Rsp;
#else
    stackframe.AddrPC.Offset    = context.Eip;
    stackframe.AddrFrame.Offset = context.Ebp;
    stackframe.AddrStack.Offset = context.Esp;
#endif

    if (!p->symbols_initialized) {
        SymInitialize(process, NULL, TRUE);
    }

    while (StackWalk64(
#ifdef DIAG_BITS_64
                       IMAGE_FILE_MACHINE_AMD64,
#else
                       IMAGE_FILE_MACHINE_I386,
#endif
                       process, thread,
                       &stackframe,
                       &context,
                       NULL,                       /* ReadMemoryRoutine */
                       SymFunctionTableAccess64,   /* FunctionTableAccessRoutine */
                       SymGetModuleBase64,         /* GetModuleBaseRoutine */
                       NULL)                       /* TranslateAddress */
           == TRUE) {
        char symbol_buffer[128] = {0};
        IMAGEHLP_SYMBOL64 *symbol = (IMAGEHLP_SYMBOL64 *)&symbol_buffer;
        DWORD64 ignored;
        const char *function;
        const char *offset;
        char address_buf[20], offset_buf[20];
        char buf[128];
        char *outch = buf;
        char *lastoutch = buf + sizeof buf - 1;

        if (cur + 1 > count) { /* avoid loop on corrupted chain, respect caller's wishes */
            break;
        }
        symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
        symbol->MaxNameLength = sizeof(symbol_buffer) - sizeof(IMAGEHLP_SYMBOL64);
        ignored = 0;
        if (SymGetSymFromAddr64(process, stackframe.AddrPC.Offset, &ignored, symbol) != TRUE) {
            function = NULL;
            offset = NULL;
        }
        else {
            function = symbol->Name;
            add_int(offset_buf, offset_buf + sizeof offset_buf - 1,
                    stackframe.AddrPC.Offset - symbol->Address, 16);
            offset = offset_buf;
        }

        add_int(address_buf, address_buf + sizeof address_buf - 1,
                stackframe.AddrPC.Offset, 16);

        if (function && !strcmp(function, "diag_backtrace")) {
            /* filter outselves out */
            continue;
        }

        cur++; /* gonna keep this frame, so count it */

        output_frame(outch, lastoutch, p->backtrace_fields,
                     NULL, /* no module path */
                     NULL, /* no module */
                     function,
                     offset,
                     address_buf);

        if (o->output_mode == DIAG_CALL_FN) {
            o->output_fn(o->user_data, buf);
        }
        else {
            WriteFile(o->outfile, buf, strlen(buf), &bytes_written, NULL);
            WriteFile(o->outfile, "\r\n", 2, &bytes_written, NULL);
        }
    }

    return 0;
}
Example #2
0
    /**
     * Print a stack backtrace for the current thread to the specified ostream.
     * 
     * @param os    ostream& to receive printed stack backtrace
     */
    void printStackTrace( std::ostream& os ) {
        HANDLE process = GetCurrentProcess();
        BOOL ret = SymInitialize( process, NULL, TRUE );
        if ( ret == FALSE ) {
            DWORD dosError = GetLastError();
            os << "Stack trace failed, SymInitialize failed with error " <<
                    std::dec << dosError << std::endl;
            return;
        }
        DWORD options = SymGetOptions();
        options |= SYMOPT_LOAD_LINES | SYMOPT_FAIL_CRITICAL_ERRORS;
        SymSetOptions( options );

        CONTEXT context;
        memset( &context, 0, sizeof(context) );
        context.ContextFlags = CONTEXT_CONTROL;
        RtlCaptureContext( &context );

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

#if defined(_M_AMD64)
        DWORD imageType = IMAGE_FILE_MACHINE_AMD64;
        frame64.AddrPC.Offset = context.Rip;
        frame64.AddrFrame.Offset = context.Rbp;
        frame64.AddrStack.Offset = context.Rsp;
#elif defined(_M_IX86)
        DWORD imageType = IMAGE_FILE_MACHINE_I386;
        frame64.AddrPC.Offset = context.Eip;
        frame64.AddrFrame.Offset = context.Ebp;
        frame64.AddrStack.Offset = context.Esp;
#else
#error Neither _M_IX86 nor _M_AMD64 were defined
#endif
        frame64.AddrPC.Mode = AddrModeFlat;
        frame64.AddrFrame.Mode = AddrModeFlat;
        frame64.AddrStack.Mode = AddrModeFlat;

        const size_t nameSize = 1024;
        const size_t symbolBufferSize = sizeof(SYMBOL_INFO) + nameSize;
        boost::scoped_array<char> symbolCharBuffer( new char[symbolBufferSize] );
        memset( symbolCharBuffer.get(), 0, symbolBufferSize );
        SYMBOL_INFO* symbolBuffer = reinterpret_cast<SYMBOL_INFO*>( symbolCharBuffer.get() );
        symbolBuffer->SizeOfStruct = sizeof(SYMBOL_INFO);
        symbolBuffer->MaxNameLen = nameSize;

        // build list
        std::vector<TraceItem> traceList;
        TraceItem traceItem;
        size_t moduleWidth = 0;
        size_t sourceWidth = 0;
        for ( size_t i = 0; i < maxBackTraceFrames; ++i ) {
            ret = StackWalk64( imageType,
                               process,
                               GetCurrentThread(),
                               &frame64,
                               &context,
                               NULL,
                               NULL,
                               NULL,
                               NULL );
            if ( ret == FALSE || frame64.AddrReturn.Offset == 0 ) {
                break;
            }
            DWORD64 address = frame64.AddrPC.Offset;
            getModuleName( process, address, &traceItem.moduleName );
            size_t width = traceItem.moduleName.length();
            if ( width > moduleWidth ) {
                moduleWidth = width;
            }
            getSourceFileAndLineNumber( process, address, &traceItem.sourceAndLine );
            width = traceItem.sourceAndLine.length();
            if ( width > sourceWidth ) {
                sourceWidth = width;
            }
            getsymbolAndOffset( process, address, symbolBuffer, &traceItem.symbolAndOffset );
            traceList.push_back( traceItem );
        }
        SymCleanup( process );

        // print list
        ++moduleWidth;
        ++sourceWidth;
        size_t frameCount = traceList.size();
        for ( size_t i = 0; i < frameCount; ++i ) {
            os << traceList[i].moduleName << " ";
            size_t width = traceList[i].moduleName.length();
            while ( width < moduleWidth ) {
                os << " ";
                ++width;
            }
            os << traceList[i].sourceAndLine << " ";
            width = traceList[i].sourceAndLine.length();
            while ( width < sourceWidth ) {
                os << " ";
                ++width;
            }
            os << traceList[i].symbolAndOffset;
            os << std::endl;
        }
    }
Example #3
0
std::string NOINLINE GetCallstack(const char *indent, const char *ignoreFilter)
{
	static bool symInitialized = false;

	HANDLE currentProcess = GetCurrentProcess();
	HANDLE currentThread = GetCurrentThread();

	if (!symInitialized)
	{
		SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
		SymInitialize(currentProcess, NULL, TRUE);
		symInitialized = true;
	}

	CONTEXT context = {};
	STACKFRAME64 stack = {};

#ifdef _M_IX86
	context.ContextFlags = CONTEXT_CONTROL;
	_asm {
		call x
		x: pop eax
		mov context.Eip, eax
		mov context.Ebp, ebp
		mov context.Esp, esp
	}
#else
	RtlCaptureContext(&context);
#endif

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

#ifdef _M_X64
	// http://msdn.microsoft.com/en-us/library/windows/desktop/ms680646(v=vs.85).aspx
	stack.AddrPC.Offset       = context.Rip;
	stack.AddrStack.Offset    = context.Rsp;
	stack.AddrFrame.Offset    = context.Rbp;
	const DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
#else
	stack.AddrPC.Offset       = context.Eip;
	stack.AddrStack.Offset    = context.Esp;
	stack.AddrFrame.Offset    = context.Ebp;
	const DWORD machineType = IMAGE_FILE_MACHINE_I386;
#endif
	const PVOID contextRecord = &context;

	std::string callstack;
	for(int i = 0; i < 128; ++i)
	{
		BOOL result = StackWalk64(machineType, currentProcess, currentThread, &stack, contextRecord, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL);
		if (!result)
			break;

		std::string symbolName = GetSymbolName((void*)stack.AddrPC.Offset, currentProcess);
		if (symbolName.find(" GetCallstack") == symbolName.length() - strlen(" GetCallstack"))
			continue;
		if (!ignoreFilter || symbolName.find(ignoreFilter) == symbolName.npos)
		{
			if (!symbolName.empty())
			{
				callstack += indent;
				callstack += symbolName;
				callstack += '\n';
			}
			ignoreFilter = 0;
		}
		if (symbolName.find(" main") == symbolName.length() - strlen(" main"))
			break;
		if (stack.AddrReturn.Offset == 0)
			break;
	}
	return callstack;
}
Example #4
0
void CCrashHandler::GetExceptionPointers(DWORD dwExceptionCode, 
  EXCEPTION_POINTERS** ppExceptionPointers)
{
  // The following code was taken from VC++ 8.0 CRT (invarg.c: line 104)
  
  EXCEPTION_RECORD ExceptionRecord;
  CONTEXT ContextRecord;
  memset(&ContextRecord, 0, sizeof(CONTEXT));
  
#ifdef _X86_

  __asm {
      mov dword ptr [ContextRecord.Eax], eax
      mov dword ptr [ContextRecord.Ecx], ecx
      mov dword ptr [ContextRecord.Edx], edx
      mov dword ptr [ContextRecord.Ebx], ebx
      mov dword ptr [ContextRecord.Esi], esi
      mov dword ptr [ContextRecord.Edi], edi
      mov word ptr [ContextRecord.SegSs], ss
      mov word ptr [ContextRecord.SegCs], cs
      mov word ptr [ContextRecord.SegDs], ds
      mov word ptr [ContextRecord.SegEs], es
      mov word ptr [ContextRecord.SegFs], fs
      mov word ptr [ContextRecord.SegGs], gs
      pushfd
      pop [ContextRecord.EFlags]
  }

  ContextRecord.ContextFlags = CONTEXT_CONTROL;
#pragma warning(push)
#pragma warning(disable:4311)
  ContextRecord.Eip = (ULONG)_ReturnAddress();
  ContextRecord.Esp = (ULONG)_AddressOfReturnAddress();
#pragma warning(pop)
  ContextRecord.Ebp = *((ULONG *)_AddressOfReturnAddress()-1);


#elif defined (_IA64_) || defined (_AMD64_)

  /* Need to fill up the Context in IA64 and AMD64. */
  RtlCaptureContext(&ContextRecord);

#else  /* defined (_IA64_) || defined (_AMD64_) */

  ZeroMemory(&ContextRecord, sizeof(ContextRecord));

#endif  /* defined (_IA64_) || defined (_AMD64_) */

  ZeroMemory(&ExceptionRecord, sizeof(EXCEPTION_RECORD));

  ExceptionRecord.ExceptionCode = dwExceptionCode;
  ExceptionRecord.ExceptionAddress = _ReturnAddress();

  ///
  
  EXCEPTION_RECORD* pExceptionRecord = new EXCEPTION_RECORD;
  memcpy(pExceptionRecord, &ExceptionRecord, sizeof(EXCEPTION_RECORD));
  CONTEXT* pContextRecord = new CONTEXT;
  memcpy(pContextRecord, &ContextRecord, sizeof(CONTEXT));

  *ppExceptionPointers = new EXCEPTION_POINTERS;
  (*ppExceptionPointers)->ExceptionRecord = pExceptionRecord;
  (*ppExceptionPointers)->ContextRecord = pContextRecord;  
}
Example #5
0
void RtlUnwindActions2 (
    IN PVOID TargetFrame OPTIONAL,
    IN PEXCEPTION_RECORD ExceptionRecord OPTIONAL,
    IN PCONTEXT ContextRecord
    )

/*++

Routine Description:

    This function initiates an unwind of procedure call frames. The machine
    state at the time of the call to unwind is captured in a context record
    and the unwinding flag is set in the exception flags of the exception
    record. If the TargetFrame parameter is not specified, then the exit unwind
    flag is also set in the exception flags of the exception record. A backward
    scan through the procedure call frames is then performed to find the target
    of the unwind operation.

    As each frame is encounter, the PC where control left the corresponding
    function is determined and used to lookup exception handler information
    in the runtime function table built by the linker. If the respective
    routine has an exception handler, then the handler is called.

    N.B. This routine is provided for backward compatibility with release 1.

Arguments:

    TargetFrame - Supplies an optional pointer to the call frame that is the
        target of the unwind. If this parameter is not specified, then an exit
        unwind is performed.

    TargetIp - Supplies an optional instruction address that specifies the
        continuation address of the unwind. This address is ignored if the
        target frame parameter is not specified.

    ExceptionRecord - Supplies an optional pointer to an exception record.

    ReturnValue - Supplies a value that is to be placed in the integer
        function return register just before continuing execution.

Return Value:

    None.

--*/

{
    // These were originally parameters but are not
    // not needed in this unwinding variant because
    // no context switch to TargetIp will be performed.
    PVOID TargetIp = NULL;
    PVOID ReturnValue = NULL;

    ULONG ControlPc;
#if EH_DBG
    ULONG ControlPcHistory[PC_HISTORY_DEPTH];
    ULONG ControlPcHistoryIndex = 0;
#endif
    DISPATCHER_CONTEXT DispatcherContext;
    EXCEPTION_DISPOSITION Disposition;
    FRAME_POINTERS EstablisherFrame;
    ULONG ExceptionFlags;
    EXCEPTION_RECORD ExceptionRecord1;
#if EH_DBG
    LONG FrameDepth = 0;
#endif
    PRUNTIME_FUNCTION FunctionEntry;
    ULONG HighLimit;
    BOOLEAN InFunction;
    ULONG LowLimit;
    ULONG NextPc;

#if EH_DBG
    if (EHRtlDebugFlags & RTL_DBG_UNWIND) {
        DbgPrint("\nRtlUnwindActions2(TargetFrame = %lx, TargetIp = %lx,, ReturnValue = %lx)\n",
                 TargetFrame, TargetIp, ReturnValue);
    }
#endif
    //
    // Get current stack limits, capture the current context, virtually
    // unwind to the caller of this routine, get the initial PC value, and
    // set the unwind target address.
    //

    __CxxGetStackLimits(&LowLimit, &HighLimit);
    RtlCaptureContext(ContextRecord);
    ControlPc = (ULONG)ContextRecord->IntRa - 4;
    FunctionEntry = RtlLookupFunctionEntry(ControlPc);
    NextPc = RtlVirtualUnwind(ControlPc,
                              FunctionEntry,
                              ContextRecord,
                              &InFunction,
                              &EstablisherFrame,
                              NULL);

    ControlPc = NextPc;
    ContextRecord->Fir = (ULONGLONG)(LONG)TargetIp;

    //
    // If an exception record is not specified, then build a local exception
    // record for use in calling exception handlers during the unwind operation.
    //

    if (ARGUMENT_PRESENT(ExceptionRecord) == FALSE) {
        ExceptionRecord = &ExceptionRecord1;
        ExceptionRecord1.ExceptionCode = STATUS_UNWIND;
        ExceptionRecord1.ExceptionRecord = NULL;
        ExceptionRecord1.ExceptionAddress = (PVOID)ControlPc;
        ExceptionRecord1.NumberParameters = 0;
    }

    //
    // If the target frame of the unwind is specified, then a normal unwind
    // is being performed. Otherwise, an exit unwind is being performed.
    //

    ExceptionFlags = EXCEPTION_UNWINDING;
    if (ARGUMENT_PRESENT(TargetFrame) == FALSE) {
        ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
    }

    //
    // Scan backward through the call frame hierarchy and call exception
    // handlers until the target frame of the unwind is reached.
    //

    do {
#if EH_DBG
        if (EHRtlDebugFlags & RTL_DBG_UNWIND_DETAIL) {
            DbgPrint("RtlUnwindActions2: Loop: FrameDepth = %d, sp = %lx, ControlPc = %lx\n",
                     FrameDepth, ContextRecord->IntSp, ControlPc);
            FrameDepth -= 1;
        }
#endif

        //
        // Lookup the function table entry using the point at which control
        // left the procedure.
        //

        FunctionEntry = RtlLookupFunctionEntry(ControlPc);

        //
        // If there is a function table entry for the routine, then virtually
        // unwind to the caller of the routine to obtain the virtual frame
        // pointer of the establisher, but don't update the context record.
        //

        if (FunctionEntry != NULL) {
            {
                CONTEXT LocalContext;
                RtlMoveMemory((PVOID)&LocalContext, ContextRecord, sizeof(CONTEXT));
                NextPc = RtlVirtualUnwind(ControlPc,
                                           FunctionEntry,
                                           &LocalContext,
                                           &InFunction,
                                           &EstablisherFrame,
                                           NULL);
            }

            //
            // If the virtual frame pointer is not within the specified stack
            // limits, the virtual frame pointer is unaligned, or the target
            // frame is below the virtual frame and an exit unwind is not being
            // performed, then raise the exception STATUS_BAD_STACK. Otherwise,
            // check to determine if the current routine has an exception
            // handler.
            //

            if ((EstablisherFrame.Virtual < LowLimit) ||
                (EstablisherFrame.Virtual > HighLimit) ||
                ((ARGUMENT_PRESENT(TargetFrame) != FALSE) &&
                 ((ULONG)TargetFrame < EstablisherFrame.Virtual)) ||
                ((EstablisherFrame.Virtual & 0xF) != 0)) {
#if EH_DBG
                DbgPrint("\n****** Warning - bad stack or target frame (unwind).\n");
                DbgPrint("  EstablisherFrame Virtual = %08lx, Real = %08lx\n",
                         EstablisherFrame.Virtual, EstablisherFrame.Real);
                DbgPrint("  TargetFrame = %08lx\n", TargetFrame);
                if ((ARGUMENT_PRESENT(TargetFrame) != FALSE) &&
                    ((ULONG)TargetFrame < EstablisherFrame.Virtual)) {
                    DbgPrint("  TargetFrame is below EstablisherFrame!\n");
                }
                DbgPrint("  Previous EstablisherFrame (sp) = %08lx\n",
                         (ULONG)ContextRecord->IntSp);
                DbgPrint("  LowLimit = %08lx, HighLimit = %08lx\n",
                         LowLimit, HighLimit);
                DbgPrint("  NextPc = %08lx, ControlPc = %08lx\n",
                         NextPc, ControlPc);
                DbgPrint("  Now raising STATUS_BAD_STACK exception.\n");
#endif
                _write(2, "C++ EH run-time failure 2 - aborting\n", 37);
                abort();

            } else if ((FunctionEntry->ExceptionHandler != NULL) && InFunction) {
#if EH_DBG
                if (EHRtlDebugFlags & RTL_DBG_DISPATCH_EXCEPTION_DETAIL) {
                    DbgPrint("RtlUnwindActions2: ExceptionHandler = %lx, HandlerData = %lx\n",
                         FunctionEntry->ExceptionHandler, FunctionEntry->HandlerData);
                }
#endif

                //
                // The frame has an exception handler.
                //
                // The control PC, establisher frame pointer, the address
                // of the function table entry, and the address of the
                // context record are all stored in the dispatcher context.
                // This information is used by the unwind linkage routine
                // and can be used by the exception handler itself.
                //
                // A linkage routine written in assembler is used to actually
                // call the actual exception handler. This is required by the
                // exception handler that is associated with the linkage
                // routine so it can have access to two sets of dispatcher
                // context when it is called.
                //

                DispatcherContext.ControlPc = ControlPc;
                DispatcherContext.FunctionEntry = FunctionEntry;
                DispatcherContext.EstablisherFrame = EstablisherFrame.Virtual;
                DispatcherContext.ContextRecord = ContextRecord;

                //
                // Call the exception handler.
                //

                do {

                    //
                    // If the establisher frame is the target of the unwind
                    // operation, then set the target unwind flag.
                    //

                    if ((ULONG)TargetFrame == EstablisherFrame.Virtual) {
                        ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
                    }

                    ExceptionRecord->ExceptionFlags = ExceptionFlags;

                    //
                    // Set the specified return value in case the exception
                    // handler directly continues execution.
                    //

                    ContextRecord->IntV0 = (ULONGLONG)(LONG)ReturnValue;
#if EH_DBG
                    if (EHRtlDebugFlags & RTL_DBG_UNWIND_DETAIL) {
                        DbgPrint("RtlUnwindActions2: calling __CxxExecuteHandlerForUnwind, ControlPc = %lx\n", ControlPc);
                    }
#endif
                    Disposition =
                        __CxxExecuteHandlerForUnwind(ExceptionRecord,
                                                    (PVOID)EstablisherFrame.Virtual,
                                                    ContextRecord,
                                                    &DispatcherContext,
                                                    FunctionEntry->ExceptionHandler);
#if EH_DBG
                    if (EHRtlDebugFlags & RTL_DBG_UNWIND_DETAIL) {
                        DbgPrint("RtlUnwindActions2: __CxxExecuteHandlerForUnwind returned Disposition = %lx\n", Disposition);
                    }
#endif

                    //
                    // Clear target unwind and collided unwind flags.
                    //

                    ExceptionFlags &= ~(EXCEPTION_COLLIDED_UNWIND |
                                        EXCEPTION_TARGET_UNWIND);

                    //
                    // Case on the handler disposition.
                    //

                    switch (Disposition) {

                        //
                        // The disposition is to continue the search.
                        //
                        // If the target frame has not been reached, then
                        // virtually unwind to the caller of the current
                        // routine, update the context record, and continue
                        // the search for a handler.
                        //

                    case ExceptionContinueSearch :
                        if (EstablisherFrame.Virtual != (ULONG)TargetFrame) {
                            NextPc = RtlVirtualUnwind(ControlPc,
                                                      FunctionEntry,
                                                      ContextRecord,
                                                      &InFunction,
                                                      &EstablisherFrame,
                                                      NULL);
                        }

                        break;

                        //
                        // The disposition is collided unwind.
                        //
                        // Set the target of the current unwind to the context
                        // record of the previous unwind, and reexecute the
                        // exception handler from the collided frame with the
                        // collided unwind flag set in the exception record.
                        //

                    case ExceptionCollidedUnwind :
                        ControlPc = DispatcherContext.ControlPc;
                        FunctionEntry = DispatcherContext.FunctionEntry;
                        ContextRecord = DispatcherContext.ContextRecord;
                        ContextRecord->Fir = (ULONGLONG)(LONG)TargetIp;
                        ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
                        EstablisherFrame.Virtual = DispatcherContext.EstablisherFrame;
                        break;

                        //
                        // All other disposition values are invalid.
                        //
                        // Raise invalid disposition exception.
                        //

                    default :
                        _write(2, "C++ EH run-time failure 3 - aborting\n", 37);
                        abort();
                    }

                } while ((ExceptionFlags & EXCEPTION_COLLIDED_UNWIND) != 0);
            } else {

                //
                // Virtually unwind to the caller of the current routine and
                // update the context record.
                //

                if (EstablisherFrame.Virtual != (ULONG)TargetFrame) {
                    NextPc = RtlVirtualUnwind(ControlPc,
                                              FunctionEntry,
                                              ContextRecord,
                                              &InFunction,
                                              &EstablisherFrame,
                                              NULL);
                }
            }

        } else {

            //
            // Set point at which control left the previous routine.
            //

            NextPc = (ULONG)ContextRecord->IntRa - 4;

            //
            // If the next control PC is the same as the old control PC, then
            // the function table is not correctly formed.
            //

            if (NextPc == ControlPc) {
#if EH_DBG
                ULONG Count;
                DbgPrint("\n****** Warning - malformed function table (unwind).\n");
                DbgPrint("ControlPc = %08lx, %08lx", NextPc, ControlPc);
                for (Count = 0; Count < PC_HISTORY_DEPTH; Count += 1) {
                    if (ControlPcHistoryIndex > 0) {
                        ControlPcHistoryIndex -= 1;
                        ControlPc = ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH];
                        DbgPrint(", %08lx", ControlPc);
                    }
                }
                DbgPrint(ControlPcHistoryIndex == 0 ? ".\n" : ", ...\n");
                DbgPrint("  Now raising STATUS_BAD_FUNCTION_TABLE exception.\n");
#endif
                _write(2, "C++ EH run-time failure 4 - aborting\n", 37);
                abort();
            }
        }

        //
        // Set point at which control left the previous routine.
        //

#if EH_DBG
        ControlPcHistory[ControlPcHistoryIndex % PC_HISTORY_DEPTH] = ControlPc;
        ControlPcHistoryIndex += 1;
#endif
        ControlPc = NextPc;

    } while ((EstablisherFrame.Virtual < HighLimit) &&
             (EstablisherFrame.Virtual != (ULONG)TargetFrame));

    //
    // If the establisher stack pointer is equal to the target frame
    // pointer, then continue execution.

    // Otherwise, something truely horrible has happend.
    //

    if (EstablisherFrame.Virtual == (ULONG)TargetFrame) {
        ContextRecord->IntV0 = (ULONGLONG)(LONG)ReturnValue;
#if EH_DBG
        if (EHRtlDebugFlags & RTL_DBG_UNWIND) {
            DbgPrint("RtlUnwindActions2: finished unwinding, and calling RtlpRestoreContext(%lx)\n",ContextRecord);
        }
#endif
        // Do not restore the context here.
        // For C++ we need to "logicaly" unwind
        //   the stack, perform several actions,
        //   and then finally "physically" unwind
        //   the stack.
        // RtlpRestoreContext(ContextRecord);
        return;

    } else {
        _write(2, "C++ EH run-time failure 1 - aborting\n", 37);
        abort();
    }
}
Example #6
0
XN_C_API XnStatus xnOSGetCurrentCallStack(XnUInt32 nFramesToSkip, XnChar** astrFrames, XnUInt32 nMaxNameLength, XnUInt32* pnFrames)
{
    if (*pnFrames == 0 || nMaxNameLength == 0)
    {
        return XN_STATUS_OK;
    }

    // Init
    if (!g_bInitialized)
    {
        Init();
        g_bInitialized = TRUE;
    }

    if (!g_bAvailable)
    {
        xnOSStrNCopy(astrFrames[0], "dbghelp.dll unavailable!", nMaxNameLength-1, nMaxNameLength);
        return XN_STATUS_ERROR;
    }

    // Get context
    CONTEXT context;
    RtlCaptureContext(&context);

    // init STACKFRAME for first call - Fill data according to processor (see WalkTrace64 and STACKFRAME64 documentation)
    STACKFRAME64 stackFrame;
    memset(&stackFrame, 0, sizeof(stackFrame));

    DWORD MachineType;
#ifdef _M_IX86
    MachineType = IMAGE_FILE_MACHINE_I386;
    stackFrame.AddrPC.Offset = context.Eip;
    stackFrame.AddrPC.Mode = AddrModeFlat;
    stackFrame.AddrFrame.Offset = context.Ebp;
    stackFrame.AddrFrame.Mode = AddrModeFlat;
    stackFrame.AddrStack.Offset = context.Esp;
    stackFrame.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
    MachineType = IMAGE_FILE_MACHINE_AMD64;
    stackFrame.AddrPC.Offset = context.Rip;
    stackFrame.AddrPC.Mode = AddrModeFlat;
    stackFrame.AddrFrame.Offset = context.Rsp;
    stackFrame.AddrFrame.Mode = AddrModeFlat;
    stackFrame.AddrStack.Offset = context.Rsp;
    stackFrame.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
    MachineType = IMAGE_FILE_MACHINE_IA64;
    stackFrame.AddrPC.Offset = context.StIIP;
    stackFrame.AddrPC.Mode = AddrModeFlat;
    stackFrame.AddrFrame.Offset = context.IntSp;
    stackFrame.AddrFrame.Mode = AddrModeFlat;
    stackFrame.AddrBStore.Offset = context.RsBSP;
    stackFrame.AddrBStore.Mode = AddrModeFlat;
    stackFrame.AddrStack.Offset = context.IntSp;
    stackFrame.AddrStack.Mode = AddrModeFlat;
#else
#error "Platform not supported!"
#endif

    XnUInt32 nFrames = 0;
    XnUInt32 iFrame = 0;
    const XnUInt32 BUFFER_SIZE = 1024;
    XnChar symbolBuffer[BUFFER_SIZE];
    SYMBOL_INFO* pSymbolInfo = (SYMBOL_INFO*)symbolBuffer;
    pSymbolInfo->SizeOfStruct = sizeof(SYMBOL_INFO);
    pSymbolInfo->MaxNameLen = BUFFER_SIZE - sizeof(SYMBOL_INFO) - 1;

    while (iFrame < *pnFrames)
    {
        // walk the stack
        if (!g_pStackWalk64(MachineType, GetCurrentProcess(), GetCurrentThread(), &stackFrame, &context, NULL, g_pSymFunctionTableAccess64, g_pSymGetModuleBase64, NULL))
        {
            // probably reached end
            break;
        }

        if (nFrames >= nFramesToSkip)
        {
            // resolve function name
            XnUInt32 nWritten;
            if (g_pSymFromAddr(GetCurrentProcess(), stackFrame.AddrPC.Offset, NULL, pSymbolInfo))
            {
                xnOSStrFormat(astrFrames[iFrame], nMaxNameLength, &nWritten, "%s()", pSymbolInfo->Name);
            }
            else
            {
                xnOSStrFormat(astrFrames[iFrame], nMaxNameLength, &nWritten, "0x%x", stackFrame.AddrPC.Offset);
            }

            ++iFrame;
        }

        ++nFrames;
    }

    *pnFrames = iFrame;

    return XN_STATUS_OK;
}
Example #7
0
int
__gnat_backtrace (void **array,
                  int size,
                  void *exclude_min,
                  void *exclude_max,
                  int skip_frames)
{
  CONTEXT context;
  UNWIND_HISTORY_TABLE history;
  int i;

  /* Get the context.  */
  RtlCaptureContext (&context);

  /* Setup unwind history table (a cached to speed-up unwinding).  */
  memset (&history, 0, sizeof (history));

  i = 0;
  while (1)
    {
      PRUNTIME_FUNCTION RuntimeFunction;
      KNONVOLATILE_CONTEXT_POINTERS NvContext;
      ULONG64 ImageBase;
      VOID *HandlerData;
      ULONG64 EstablisherFrame;

      /* Get function metadata.  */
      RuntimeFunction = RtlLookupFunctionEntry
	(context.Rip, &ImageBase, &history);

      if (!RuntimeFunction)
	{
	  /* In case of failure, assume this is a leaf function.  */
	  context.Rip = *(ULONG64 *) context.Rsp;
	  context.Rsp += 8;
	}
      else
	{
	  /* Unwind.  */
	  memset (&NvContext, 0, sizeof (KNONVOLATILE_CONTEXT_POINTERS));
	  RtlVirtualUnwind (0, ImageBase, context.Rip, RuntimeFunction,
			    &context, &HandlerData, &EstablisherFrame,
			    &NvContext);
	}

      /* 0 means bottom of the stack.  */
      if (context.Rip == 0)
	break;

      /* Skip frames.  */
      if (skip_frames > 1)
	{
	  skip_frames--;
	  continue;
	}
      /* Excluded frames.  */
      if ((void *)context.Rip >= exclude_min
	  && (void *)context.Rip <= exclude_max)
	continue;

      array[i++] = (void *)(context.Rip - 2);
      if (i >= size)
	break;
    }
  return i;
}
int Win32_Platform::Get_Stack_Trace(StackFrame* frames, int max_frames, void* platform_specific, int offset)
{	
	DBG_ASSERT(max_frames <= 512);	
	memset(frames, 0, sizeof(StackFrame) * max_frames);

	int frame_count = 0;

	if (platform_specific != NULL)
	{
		// If thread is not given, use current.
		HANDLE thread = GetCurrentThread();
		struct _EXCEPTION_POINTERS* exceptioninfo = reinterpret_cast<struct _EXCEPTION_POINTERS *>(platform_specific);

		// Capture context for this thread.
		CONTEXT context;
		ZeroMemory(&context, sizeof(CONTEXT));
	
		// 32bit has no function call to get the current
		// threads context, so its asm trickery time :3
		#ifdef PLATFORM_32BIT
		
			if (exceptioninfo != NULL)
			{
				memcpy(&context, exceptioninfo->ContextRecord, sizeof(CONTEXT));
			}
			else
			{
				context.ContextFlags = CONTEXT_CONTROL;	
				__asm
				{
				Label:
					mov [context.Ebp], ebp;
					mov [context.Esp], esp;
					mov eax, [Label];
					mov [context.Eip], eax;
				}
			}

		// 64bit does though, w00t.
		#else
	
			if (exceptioninfo != NULL)
			{
				memcpy(&context, exceptioninfo->ContextRecord, sizeof(CONTEXT));
			}
			else
			{
				RtlCaptureContext(&context);
			}

		#endif
			
		// Build the initial stack frame.
		STACKFRAME64 stackFrame;
		DWORD		 machineType;
		ZeroMemory(&stackFrame, sizeof(STACKFRAME64));
		
		#ifdef PLATFORM_X86
			machineType                 = IMAGE_FILE_MACHINE_I386;
			stackFrame.AddrPC.Offset    = context.Eip;
			stackFrame.AddrPC.Mode      = AddrModeFlat;
			stackFrame.AddrFrame.Offset = context.Ebp;
			stackFrame.AddrFrame.Mode   = AddrModeFlat;
			stackFrame.AddrStack.Offset = context.Esp;
			stackFrame.AddrStack.Mode   = AddrModeFlat;
		#elif PLATFORM_AMD64
			machineType                 = IMAGE_FILE_MACHINE_AMD64;
			stackFrame.AddrPC.Offset    = context.Rip;
			stackFrame.AddrPC.Mode      = AddrModeFlat;
			stackFrame.AddrFrame.Offset = context.Rsp;
			stackFrame.AddrFrame.Mode   = AddrModeFlat;
			stackFrame.AddrStack.Offset = context.Rsp;
			stackFrame.AddrStack.Mode   = AddrModeFlat;
		#elif PLATFORM_ITANIUM64
			machineType                 = IMAGE_FILE_MACHINE_IA64;
			stackFrame.AddrPC.Offset    = context.StIIP;
			stackFrame.AddrPC.Mode      = AddrModeFlat;
			stackFrame.AddrFrame.Offset = context.IntSp;
			stackFrame.AddrFrame.Mode   = AddrModeFlat;
			stackFrame.AddrBStore.Offset= context.RsBSP;
			stackFrame.AddrBStore.Mode  = AddrModeFlat;
			stackFrame.AddrStack.Offset = context.IntSp;
			stackFrame.AddrStack.Mode   = AddrModeFlat;
		#else
			DBG_LOG("Platform does not support stack walking.");
			return 0;

		#endif

		EnterCriticalSection(&g_dbghelp_critical_section);
		
		// Stack trace!
		int trace_offset = 0;
		while (frame_count < max_frames)
		{
			if (!StackWalk64(machineType, GetCurrentProcess(), thread, &stackFrame, 
								machineType == IMAGE_FILE_MACHINE_I386 ? NULL : &context, 
								NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
			{
				// Failure :(
				break;
			}

			if (++trace_offset <= offset)
			{
				continue;
			}
		
			if (stackFrame.AddrPC.Offset != 0)
			{
		#ifdef PLATFORM_64BIT
				frames[frame_count].Address = stackFrame.AddrPC.Offset;
		#else
				frames[frame_count].Address = stackFrame.AddrPC.Offset;
		#endif
				frame_count++;
			}
			else
			{
				// Reached the base of the stack.
				break;
			}
		}
		
		LeaveCriticalSection(&g_dbghelp_critical_section);
	}
DECLSPEC_NOINLINE
VOID
WudfVerify(
    _In_ WdfComponentType Component,
    _In_ IUMDFPlatform *Platform,
    _In_ PCWSTR Location,
    _In_ WdfDriverStopType Kind,
    _In_ WdfErrorClass Class,
    _In_ ULONG Error,
    _In_ PCSTR Message,
    _In_ bool test,
    _In_ PSTR ActiveDriver
)
{
    if(!test) {

        HRESULT hr;
        IUMDFPlatform2 *platformEx = NULL;
        
        //
        // Capture the context record so that user can go to the context
        // of the caller
        //

        CONTEXT driverStopContextRecord;

        //
        // x86 -    For this to work correctly the calling function should be 
        //          non-FPO
        //          RtlCaptureContext assumes that:
        //          it is called from a 'C' procedure with
        //          the old ebp at [ebp], the return address at [ebp+4], and
        //          old esp = ebp + 8.
        //
        // x86 -    esp is not adjusted to be of previous caller
        //
        // AMD64 -  rcx (this is what the argument is passed through)
        //          and rsp would be modified before the capture
        //          as a side effect of the RtlCaptureContext call (in addition
        //          to any modifications the current function might do)
        //
        
        RtlCaptureContext(&driverStopContextRecord);

        hr = Platform->QueryInterface(IID_IUMDFPlatform2, (PVOID*)&platformEx);
        if (SUCCEEDED(hr)) {            
            platformEx->UmdfDriverStopWithActiveDriver(
                Kind,
                WUDF_ERROR_NUMBER(Component, Kind, Class, Error),
                Location,
                Message,
                &driverStopContextRecord,
                ActiveDriver
                );
            
            //
            // Release the reference taken during QueryInterface
            //
            platformEx->Release();
            platformEx = NULL;
        } else {
            ASSERT("Unable to access the IUMDFPlatform2 COM interface from an "
                   "internal facing component");
        }
    }
}
Example #10
0
int
setjmp (
    IN jmp_buf JumpBuffer
    )

/*++

Routine Description:

    This function performs a set jump operation by capturing the current
    context, virtualy unwinding to the caller of set jump, and returns zero
    to the caller.

Arguments:

    JumpBuffer - Supplies the address of a jump buffer to store the virtual
        frame pointer and target address of the caller.

        N.B. This is an array of double to force quadword alignment.

Return Value:

    A value of zero is returned.

--*/

{

    CONTEXT ContextRecord;
    ULONG EstablisherFrame;
    PRUNTIME_FUNCTION FunctionEntry;
    BOOLEAN InFunction;
    PULONG JumpArray;
    ULONG NextPc;

    //
    // Capture the current context, virtually unwind to the caller of set
    // jump, and return zero to the caller.
    //

    JumpArray = (PULONG)&JumpBuffer[0];
    RtlCaptureContext(&ContextRecord);
    NextPc = ContextRecord.Lr - 4;
    FunctionEntry = RtlLookupFunctionEntry(NextPc);
    NextPc = RtlVirtualUnwind(NextPc,
                              FunctionEntry,
                              &ContextRecord,
                              &InFunction,
                              &EstablisherFrame,
                              NULL,
                              0,
                              0xffffffff);

    JumpArray[1] = NextPc + 4;
    FunctionEntry = RtlLookupFunctionEntry(NextPc);
    NextPc = RtlVirtualUnwind(NextPc,
                              FunctionEntry,
                              &ContextRecord,
                              &InFunction,
                              &EstablisherFrame,
                              NULL,
                              0,
                              0xffffffff);

    JumpArray[0] = EstablisherFrame;
    return 0;
}
StackTrace::StackTrace(void *their_context) {
  PCONTEXT context = reinterpret_cast<PCONTEXT>(their_context);
  CONTEXT current_context;
  if (their_context == NULL) {
    RtlCaptureContext(&current_context);
    context = &current_context;
  }

  HANDLE process = GetCurrentProcess();
  DbgHelp dbghelp(process);
  if (!dbghelp.is_loaded()) {
    goto fail;
  }

  STACKFRAME64 stack_frame;
  ZeroMemory(&stack_frame, sizeof(stack_frame));

  // http://stackoverflow.com/a/136942/249230
  stack_frame.AddrPC.Offset = context->Eip;
  stack_frame.AddrReturn.Offset = context->Eip;
  stack_frame.AddrPC.Mode = AddrModeFlat;
  stack_frame.AddrFrame.Offset = context->Ebp;
  stack_frame.AddrFrame.Mode = AddrModeFlat;
  stack_frame.AddrStack.Offset = context->Esp;
  stack_frame.AddrStack.Mode = AddrModeFlat;

  if (!dbghelp.HaveStackWalk64()) {
    goto fail;
  }

  SYMBOL_INFO *symbol = NULL;

  if (dbghelp.is_initialized()) {
    symbol = reinterpret_cast<SYMBOL_INFO*>(std::calloc(sizeof(*symbol) + kMaxSymbolNameLength, 1));
    symbol->SizeOfStruct = sizeof(*symbol);
    symbol->MaxNameLen = kMaxSymbolNameLength;

    if (dbghelp.HaveSymGetOptions() && dbghelp.HaveSymSetOptions()) {
      DWORD options = dbghelp.SymGetOptions();
      options |= SYMOPT_FAIL_CRITICAL_ERRORS;
      dbghelp.SymSetOptions(options);
    }
  }

  while (true) {
    DWORD64 address = stack_frame.AddrReturn.Offset;
    if (address <= 0) {
      break;
    }

    bool have_symbols = true;
    if (dbghelp.HaveSymGetModuleInfo64()) {
      IMAGEHLP_MODULE64 module;
      ZeroMemory(&module, sizeof(IMAGEHLP_MODULE64));
      module.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
      if (dbghelp.SymGetModuleInfo64(process, address, &module)) {
        if (!module.GlobalSymbols) {
          have_symbols = false;
        }
      }
    }

    const char *name = "";
    if (have_symbols) {
      if (dbghelp.is_initialized() && dbghelp.HaveSymFromAddr() && symbol != NULL) {
        if (dbghelp.SymFromAddr(process, address, NULL, symbol)) {
          name = symbol->Name;
        }
      }
    }

    frames_.push_back(StackFrame(reinterpret_cast<void*>(address), name));

    BOOL result = dbghelp.StackWalk64(IMAGE_FILE_MACHINE_I386, process, GetCurrentThread(), &stack_frame,
                                      (PVOID)context, NULL, NULL, NULL, NULL);
    if (!result) {
      break;
    }
  }

  if (symbol != NULL) {
    std::free(symbol);
  }

  return;

fail:
  frames_ = StackTraceGeneric(
    reinterpret_cast<void*>(context->Ebp),
    reinterpret_cast<void*>(context->Eip)).GetFrames();
}
Example #12
0
VOID
ExpRaiseException (
    IN PEXCEPTION_RECORD ExceptionRecord
    )

/*++

Routine Description:

    This function raises a software exception by building a context record
    and calling the exception dispatcher directly.

Arguments:

    ExceptionRecord - Supplies a pointer to an exception record.

Return Value:

    None.

--*/

{

    ULONG ControlPc;
    CONTEXT ContextRecord;
    ULONG EstablisherFrame;
    PRUNTIME_FUNCTION FunctionEntry;
    BOOLEAN InFunction;
    ULONG NextPc;
    NTSTATUS Status;

    //
    // Capture the current context, virtually unwind to the caller of this
    // routine, set the fault instruction address to that of the caller, and
    // call the exception dispatcher.
    //

    RtlCaptureContext(&ContextRecord);
    ControlPc = ContextRecord.Lr - 4;
    FunctionEntry = RtlLookupFunctionEntry(ControlPc);
    NextPc = RtlVirtualUnwind(ControlPc,
                              FunctionEntry,
                              &ContextRecord,
                              &InFunction,
                              &EstablisherFrame,
                              NULL,
                              0,
                              0xffffffff);

    ContextRecord.Iar = NextPc + 4;
    ExceptionRecord->ExceptionAddress = (PVOID)ContextRecord.Iar;

    //
    // If the exception is successfully dispatched, then continue execution.
    // Otherwise, give the kernel debugger a chance to handle the exception.
    //

    if (RtlDispatchException(ExceptionRecord, &ContextRecord)) {
        Status = ZwContinue(&ContextRecord, FALSE);

    } else {
        Status = ZwRaiseException(ExceptionRecord, &ContextRecord, FALSE);
    }

    //
    // Either the attempt to continue execution or the attempt to give
    // the kernel debugger a chance to handle the exception failed. Raise
    // a noncontinuable exception.
    //

    ExRaiseStatus(Status);
}
Example #13
0
VOID
ExpRaiseStatus (
    IN NTSTATUS ExceptionCode
    )

/*++

Routine Description:

    This function raises an exception with the specified status value by
    building an exception record, building a context record, and calling the
    exception dispatcher directly. The exception is marked as noncontinuable
    with no parameters. There is no return from this function.

Arguments:

    ExceptionCode - Supplies the status value to be used as the exception
        code for the exception that is to be raised.

Return Value:

    None.

--*/

{

    ULONG ControlPc;
    CONTEXT ContextRecord;
    ULONG EstablisherFrame;
    EXCEPTION_RECORD ExceptionRecord;
    PRUNTIME_FUNCTION FunctionEntry;
    BOOLEAN InFunction;
    ULONG NextPc;
    NTSTATUS Status;

    //
    // Construct an exception record.
    //

    ExceptionRecord.ExceptionCode = ExceptionCode;
    ExceptionRecord.ExceptionRecord = (PEXCEPTION_RECORD)NULL;
    ExceptionRecord.NumberParameters = 0;
    ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE;

    //
    // Capture the current context, virtually unwind to the caller of this
    // routine, set the fault instruction address to that of the caller, and
    // call the exception dispatcher.
    //

    RtlCaptureContext(&ContextRecord);
    ControlPc = ContextRecord.Lr - 4;
    FunctionEntry = RtlLookupFunctionEntry(ControlPc);
    NextPc = RtlVirtualUnwind(ControlPc,
                              FunctionEntry,
                              &ContextRecord,
                              &InFunction,
                              &EstablisherFrame,
                              NULL,
                              0,
                              0xffffffff);

    ContextRecord.Iar = NextPc + 4;
    ExceptionRecord.ExceptionAddress = (PVOID)ContextRecord.Iar;
    RtlDispatchException(&ExceptionRecord, &ContextRecord);

    //
    // An unwind was not initiated during the dispatching of a noncontinuable
    // exception. Give the kernel debugger a chance to handle the exception.
    //

    Status = ZwRaiseException(&ExceptionRecord, &ContextRecord, FALSE);

    //
    // The attempt to give the kernel debugger a chance to handle the exception
    // failed. Raise another noncontinuable exception.
    //

    ExRaiseStatus(Status);
}
Example #14
0
	void PlatformStack::CaptureStackBackTrace(uint64* backTrace, uint32 maxDepth, void* context)
	{
		if (backTrace == NULL || maxDepth == 0)
		{
			return;
		}

		if (context)
		{
			CaptureStackTraceHelper(backTrace, maxDepth, (CONTEXT*)context);
		}
		else
		{
#if USE_FAST_STACKTRACE
			//if (!GMaxCallstackDepthInitialized)
			//{
			//	DetermineMaxCallstackDepth();
			//}

			PVOID winBackTrace[MAX_CALLSTACK_DEPTH];
			uint16 numFrames = RtlCaptureStackBackTrace(0, maxDepth, winBackTrace, NULL);
			for (uint16 frameIndex = 0; frameIndex < numFrames; ++frameIndex)
			{
				backTrace[frameIndex] = (uint64)winBackTrace[frameIndex];
			}

			while (numFrames < maxDepth)
			{
				backTrace[numFrames++] = 0;
			}

#elif USE_SLOW_STACKTRACE
			InitSysStack();

			CONTEXT helperContext;
			RtlCaptureContext(&helperContext);

			CaptureStackTraceHelper(backTrace, maxDepth, &helperContext);

#elif _WIN64
			// Raise an exception so CaptureStackBackTraceHelper has access to context record.
			__try
			{
				RaiseException(0,			// Application-defined exception code.
					0,			// Zero indicates continuable exception.
					0,			// Number of arguments in args array (ignored if args is NULL)
					NULL);		// Array of arguments
			}
			// Capture the back trace.
			__except (CaptureStackTraceHelper(backTrace, maxDepth, (GetExceptionInformation())->ContextRecord))
			{
			}
#else
			// Use a bit of inline assembly to capture the information relevant to stack walking which is
			// basically EIP and EBP.
			CONTEXT HelperContext;
			memset(&HelperContext, 0, sizeof(CONTEXT));
			HelperContext.ContextFlags = CONTEXT_FULL;

			// Use a fake function call to pop the return address and retrieve EIP.
			__asm
			{
				call FakeFunctionCall
				FakeFunctionCall :
				pop eax
					mov HelperContext.Eip, eax
					mov HelperContext.Ebp, ebp
					mov HelperContext.Esp, esp
			}

			// Capture the back trace.
			CaptureStackTraceHelper(backTrace, maxDepth, &HelperContext);
#endif
		}
	}
//----------------------------------------------------------------------------//
static void dumpBacktrace(size_t frames)
{

#if defined(__ANDROID__)

    // Not implemented yet.
    CEGUI_UNUSED(frames);

#else

#if defined(_DEBUG) || defined(DEBUG)
#if defined(_MSC_VER)
    SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_INCLUDE_32BIT_MODULES);

    if (!SymInitialize(GetCurrentProcess(), 0, TRUE))
        return;

    HANDLE thread = GetCurrentThread();

    CONTEXT context;
    RtlCaptureContext(&context);

    STACKFRAME64 stackframe;
    ZeroMemory(&stackframe, sizeof(stackframe));
    stackframe.AddrPC.Mode = AddrModeFlat;
    stackframe.AddrStack.Mode = AddrModeFlat;
    stackframe.AddrFrame.Mode = AddrModeFlat;

#if _M_IX86
    stackframe.AddrPC.Offset = context.Eip;
    stackframe.AddrStack.Offset = context.Esp;
    stackframe.AddrFrame.Offset = context.Ebp;
    DWORD machine_arch = IMAGE_FILE_MACHINE_I386;
#elif _M_X64
    stackframe.AddrPC.Offset = context.Rip;
    stackframe.AddrStack.Offset = context.Rsp;
    stackframe.AddrFrame.Offset = context.Rbp;
    DWORD machine_arch = IMAGE_FILE_MACHINE_AMD64;
#endif

    char symbol_buffer[1024];
    ZeroMemory(symbol_buffer, sizeof(symbol_buffer));
    PSYMBOL_INFO symbol = reinterpret_cast<PSYMBOL_INFO>(symbol_buffer);
    symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
    symbol->MaxNameLen = sizeof(symbol_buffer) - sizeof(SYMBOL_INFO);

    Logger& logger(Logger::getSingleton());
    logger.logEvent("========== Start of Backtrace ==========", Errors);

    size_t frame_no = 0;
    while (StackWalk64(machine_arch, GetCurrentProcess(), thread, &stackframe,
                       &context, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0) &&
           stackframe.AddrPC.Offset)
    {
        symbol->Address = stackframe.AddrPC.Offset;
        DWORD64 displacement = 0;
        char signature[256];

        if (SymFromAddr(GetCurrentProcess(), symbol->Address, &displacement, symbol))
            UnDecorateSymbolName(symbol->Name, signature, sizeof(signature), UNDNAME_COMPLETE);
        else
            sprintf_s(signature, sizeof(signature), "%p", ULongToPtr(symbol->Address));
 
        IMAGEHLP_MODULE64 modinfo;
        modinfo.SizeOfStruct = sizeof(modinfo);

        const BOOL have_image_name =
            SymGetModuleInfo64(GetCurrentProcess(), symbol->Address, &modinfo);

        char outstr[512];
        sprintf_s(outstr, sizeof(outstr), "#%d %s +%#llx (%s)",
                  frame_no, signature, displacement,
                  (have_image_name ? modinfo.LoadedImageName : "????"));

        logger.logEvent(outstr, Errors);

        if (++frame_no >= frames)
            break;

        if (!stackframe.AddrReturn.Offset)
            break;
    }

    logger.logEvent("==========  End of Backtrace  ==========", Errors);

    SymCleanup(GetCurrentProcess());
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__HAIKU__)
    void* buffer[frames];
    const int received = backtrace(&buffer[0], frames);

    Logger& logger(Logger::getSingleton());

    logger.logEvent("========== Start of Backtrace ==========", Errors);

    for (int i = 0; i < received; ++i)
    {
        char outstr[512];
        Dl_info info;
        if (dladdr(buffer[i], &info))
        {
            if (!info.dli_sname)
                snprintf(outstr, 512, "#%d %p (%s)", i, buffer[i], info.dli_fname);
            else
            {
                ptrdiff_t offset = static_cast<char*>(buffer[i]) -
                                   static_cast<char*>(info.dli_saddr);

                int demangle_result = 0;
                char* demangle_name = abi::__cxa_demangle(info.dli_sname, 0, 0, &demangle_result);
                snprintf(outstr, 512, "#%d %s +%#tx (%s)",
                         i, demangle_name ? demangle_name : info.dli_sname, offset, info.dli_fname);
                std::free(demangle_name);
            }
        }
        else
            snprintf(outstr, 512, "#%d --- error ---", i);

        logger.logEvent(outstr, Errors);
    }

    logger.logEvent("==========  End of Backtrace  ==========", Errors);

#else

    CEGUI_UNUSED(frames);
    
#endif

#else

    CEGUI_UNUSED(frames);

#endif

#endif
}