Example #1
1
static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp)
{
    // Might be called from unmanaged thread.
#ifndef _CPU_X86_64_
    *ip = (uintptr_t)cursor->stackframe.AddrPC.Offset;
    *sp = (uintptr_t)cursor->stackframe.AddrStack.Offset;
    if (*ip == 0 || *ip == ((uintptr_t)0)-1) {
        if (!readable_pointer((LPCVOID)*sp))
            return 0;
        cursor->stackframe.AddrPC.Offset = *(DWORD32*)*sp;      // POP EIP (aka RET)
        cursor->stackframe.AddrStack.Offset += sizeof(void*);
        return cursor->stackframe.AddrPC.Offset != 0;
    }

    BOOL result = StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), hMainThread,
        &cursor->stackframe, &cursor->context, NULL, JuliaFunctionTableAccess64, JuliaGetModuleBase64, NULL);
    return result;
#else
    *ip = (uintptr_t)cursor->Rip;
    *sp = (uintptr_t)cursor->Rsp;
    if (*ip == 0 || *ip == ((uintptr_t)0)-1) {
        if (!readable_pointer((LPCVOID)*sp))
            return 0;
        cursor->Rip = *(DWORD64*)*sp;      // POP RIP (aka RET)
        cursor->Rsp += sizeof(void*);
        return cursor->Rip != 0;
    }

    DWORD64 ImageBase = JuliaGetModuleBase64(GetCurrentProcess(), cursor->Rip);
    if (!ImageBase)
        return 0;

    PRUNTIME_FUNCTION FunctionEntry = (PRUNTIME_FUNCTION)JuliaFunctionTableAccess64(GetCurrentProcess(), cursor->Rip);
    if (!FunctionEntry) { // assume this is a NO_FPO RBP-based function
        cursor->Rsp = cursor->Rbp;                 // MOV RSP, RBP
        if (!readable_pointer((LPCVOID)cursor->Rsp))
            return 0;
        cursor->Rbp = *(DWORD64*)cursor->Rsp;      // POP RBP
        cursor->Rsp += sizeof(void*);
        cursor->Rip = *(DWORD64*)cursor->Rsp;      // POP RIP (aka RET)
        cursor->Rsp += sizeof(void*);
    }
    else {
        PVOID HandlerData;
        DWORD64 EstablisherFrame;
        (void)RtlVirtualUnwind(
                0 /*UNW_FLAG_NHANDLER*/,
                ImageBase,
                cursor->Rip,
                FunctionEntry,
                cursor,
                &HandlerData,
                &EstablisherFrame,
                NULL);
    }
    return cursor->Rip != 0;
#endif
}
Example #2
0
    StackTrace::StackTrace(_EXCEPTION_POINTERS* exception_pointers)
    {
        // 使用StackWalk64()获得异常堆栈信息.
        count_ = 0;
        // 初始化堆栈查核行程.
        STACKFRAME64 stack_frame;
        memset(&stack_frame, 0, sizeof(stack_frame));
#if defined(_WIN64)
        int machine_type = IMAGE_FILE_MACHINE_AMD64;
        stack_frame.AddrPC.Offset = exception_pointers->ContextRecord->Rip;
        stack_frame.AddrFrame.Offset = exception_pointers->ContextRecord->Rbp;
        stack_frame.AddrStack.Offset = exception_pointers->ContextRecord->Rsp;
#else
        int machine_type = IMAGE_FILE_MACHINE_I386;
        stack_frame.AddrPC.Offset = exception_pointers->ContextRecord->Eip;
        stack_frame.AddrFrame.Offset = exception_pointers->ContextRecord->Ebp;
        stack_frame.AddrStack.Offset = exception_pointers->ContextRecord->Esp;
#endif
        stack_frame.AddrPC.Mode = AddrModeFlat;
        stack_frame.AddrFrame.Mode = AddrModeFlat;
        stack_frame.AddrStack.Mode = AddrModeFlat;
        while(StackWalk64(machine_type,
            GetCurrentProcess(),
            GetCurrentThread(),
            &stack_frame,
            exception_pointers->ContextRecord,
            NULL,
            &SymFunctionTableAccess64,
            &SymGetModuleBase64,
            NULL) && count_<arraysize(trace_))
        {
            trace_[count_++] = reinterpret_cast<void*>(stack_frame.AddrPC.Offset);
        }
    }
Example #3
0
static int jl_unw_init(bt_cursor_t *cursor, bt_context_t *Context)
{
    // Might be called from unmanaged thread.
    if (needsSymRefreshModuleList && hSymRefreshModuleList != 0 && !jl_in_stackwalk) {
        jl_in_stackwalk = 1;
        hSymRefreshModuleList(GetCurrentProcess());
        jl_in_stackwalk = 0;
        needsSymRefreshModuleList = 0;
    }
#if !defined(_CPU_X86_64_)
    if (jl_in_stackwalk) {
        return 0;
    }
    jl_in_stackwalk = 1;
    memset(&cursor->stackframe, 0, sizeof(cursor->stackframe));
    cursor->stackframe.AddrPC.Offset = Context->Eip;
    cursor->stackframe.AddrStack.Offset = Context->Esp;
    cursor->stackframe.AddrFrame.Offset = Context->Ebp;
    cursor->stackframe.AddrPC.Mode = AddrModeFlat;
    cursor->stackframe.AddrStack.Mode = AddrModeFlat;
    cursor->stackframe.AddrFrame.Mode = AddrModeFlat;
    cursor->context = *Context;
    BOOL result = StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), hMainThread,
        &cursor->stackframe, &cursor->context, NULL, JuliaFunctionTableAccess64, JuliaGetModuleBase64, NULL);
    jl_in_stackwalk = 0;
    return result;
#else
    *cursor = *Context;
    return 1;
#endif
}
Example #4
0
static void getStack(CONTEXT& context, char* out, int max_size)
{
	BOOL result;
	HANDLE process;
	HANDLE thread;
	STACKFRAME64 stack;
	char symbol_mem[sizeof(IMAGEHLP_SYMBOL64) + 256];
	IMAGEHLP_SYMBOL64* symbol = (IMAGEHLP_SYMBOL64*)symbol_mem;
	DWORD64 displacement;
	char name[256];
	copyString(out, max_size, "Crash callstack:\n");
	memset(&stack, 0, sizeof(STACKFRAME64));

	process = GetCurrentProcess();
	thread = GetCurrentThread();
	displacement = 0;
	DWORD machineType;
#ifdef _WIN64
	machineType = IMAGE_FILE_MACHINE_IA64;
	stack.AddrPC.Offset = context.Rip;
	stack.AddrPC.Mode = AddrModeFlat;
	stack.AddrStack.Offset = context.Rsp;
	stack.AddrStack.Mode = AddrModeFlat;
	stack.AddrFrame.Offset = context.Rbp;
	stack.AddrFrame.Mode = AddrModeFlat;
#else
	machineType = IMAGE_FILE_MACHINE_I386;
	stack.AddrPC.Offset = context.Eip;
	stack.AddrPC.Mode = AddrModeFlat;
	stack.AddrStack.Offset = context.Esp;
	stack.AddrStack.Mode = AddrModeFlat;
	stack.AddrFrame.Offset = context.Ebp;
	stack.AddrFrame.Mode = AddrModeFlat;
#endif

	do
	{
		result = StackWalk64(machineType,
			process,
			thread,
			&stack,
			&context,
			NULL,
			SymFunctionTableAccess64,
			SymGetModuleBase64,
			NULL);

		symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
		symbol->MaxNameLength = 255;

		SymGetSymFromAddr64(process, (ULONG64)stack.AddrPC.Offset, &displacement, symbol);
		UnDecorateSymbolName(symbol->Name, (PSTR)name, 256, UNDNAME_COMPLETE);

		catString(out, max_size, symbol->Name);
		catString(out, max_size, "\n");

	} while (result);
}
// getStackTrace - Traces the stack as far back as possible, or until 'maxdepth'
//   frames have been traced. Populates the CallStack with one entry for each
//   stack frame traced.
//
//   Note: This function uses a documented Windows API to walk the stack. This
//     API is supposed to be the most reliable way to walk the stack. It claims
//     to be able to walk stack frames that do not follow the conventional stack
//     frame layout. However, this robustness comes at a cost: it is *extremely*
//     slow compared to walking frames by following frame (base) pointers.
//
//  - maxdepth (IN): Maximum number of frames to trace back.
//
//  - framepointer (IN): Frame (base) pointer at which to begin the stack trace.
//      If NULL, then the stack trace will begin at this function.
//
//  Return Value:
//
//    None.
//
VOID SafeCallStack::getStackTrace (UINT32 maxdepth, const context_t& context)
{
    UINT_PTR* framePointer = context.fp;
    DWORD   architecture   = X86X64ARCHITECTURE;
    CONTEXT currentContext;
    memset(&currentContext, 0, sizeof(currentContext));

    // Get the required values for initialization of the STACKFRAME64 structure
    // to be passed to StackWalk64(). Required fields are AddrPC and AddrFrame.
#if defined(_M_IX86)
    UINT_PTR programcounter = *(framePointer + 1);
    UINT_PTR stackpointer   = (*framePointer) - maxdepth * 10 * sizeof(void*);  // An approximation.
    currentContext.SPREG  = stackpointer;
    currentContext.BPREG  = (DWORD64)framePointer;
    currentContext.IPREG  = programcounter;
#elif defined(_M_X64)
    currentContext.SPREG  = context.Rsp;
    currentContext.BPREG  = (DWORD64)framePointer;
    currentContext.IPREG  = context.Rip;
#else
    // If you want to retarget Visual Leak Detector to another processor
    // architecture then you'll need to provide architecture-specific code to
    // obtain the program counter and stack pointer from the given frame pointer.
#error "Visual Leak Detector is not supported on this architecture."
#endif // _M_IX86 || _M_X64

    // Initialize the STACKFRAME64 structure.
    STACKFRAME64 frame;
    memset(&frame, 0x0, sizeof(frame));
    frame.AddrPC.Offset       = currentContext.IPREG;
    frame.AddrPC.Mode         = AddrModeFlat;
    frame.AddrStack.Offset    = currentContext.SPREG;
    frame.AddrStack.Mode      = AddrModeFlat;
    frame.AddrFrame.Offset    = currentContext.BPREG;
    frame.AddrFrame.Mode      = AddrModeFlat;
    frame.Virtual             = TRUE;

    // Walk the stack.
    CriticalSectionLocker cs(g_stackWalkLock);
    UINT32 count = 0;
    while (count < maxdepth) {
        count++;
        DbgTrace(L"dbghelp32.dll %i: StackWalk64\n", GetCurrentThreadId());
        if (!StackWalk64(architecture, g_currentProcess, g_currentThread, &frame, &currentContext, NULL,
            SymFunctionTableAccess64, SymGetModuleBase64, NULL)) {
                // Couldn't trace back through any more frames.
                break;
        }
        if (frame.AddrFrame.Offset == 0) {
            // End of stack.
            break;
        }

        // Push this frame's program counter onto the CallStack.
        push_back((UINT_PTR)frame.AddrPC.Offset);
    }
}
Example #6
0
/******************************************************************
 *		stack_fetch_frames
 *
 * Do a backtrace on the current thread
 */
unsigned stack_fetch_frames(const CONTEXT* _ctx)
{
    STACKFRAME64 sf;
    unsigned     nf = 0;
    /* as native stackwalk can modify the context passed to it, simply copy
     * it to avoid any damage
     */
    CONTEXT      ctx = *_ctx, prevctx = ctx;

    HeapFree(GetProcessHeap(), 0, dbg_curr_thread->frames);
    dbg_curr_thread->frames = NULL;

    memset(&sf, 0, sizeof(sf));
    be_cpu->get_addr(dbg_curr_thread->handle, &ctx, be_cpu_addr_frame, &sf.AddrFrame);
    be_cpu->get_addr(dbg_curr_thread->handle, &ctx, be_cpu_addr_pc, &sf.AddrPC);
    be_cpu->get_addr(dbg_curr_thread->handle, &ctx, be_cpu_addr_stack, &sf.AddrStack);

    /* don't confuse StackWalk by passing in inconsistent addresses */
    if ((sf.AddrPC.Mode == AddrModeFlat) && (sf.AddrFrame.Mode != AddrModeFlat))
    {
        sf.AddrFrame.Offset = (ULONG_PTR)memory_to_linear_addr(&sf.AddrFrame);
        sf.AddrFrame.Mode = AddrModeFlat;
    }

    while (StackWalk64(be_cpu->machine, dbg_curr_process->handle,
                       dbg_curr_thread->handle, &sf, &ctx, stack_read_mem,
                       SymFunctionTableAccess64, SymGetModuleBase64, NULL))
    {
        dbg_curr_thread->frames = dbg_heap_realloc(dbg_curr_thread->frames,
                                  (nf + 1) * sizeof(dbg_curr_thread->frames[0]));

        dbg_curr_thread->frames[nf].addr_pc      = sf.AddrPC;
        dbg_curr_thread->frames[nf].linear_pc    = (DWORD_PTR)memory_to_linear_addr(&sf.AddrPC);
        dbg_curr_thread->frames[nf].addr_frame   = sf.AddrFrame;
        dbg_curr_thread->frames[nf].linear_frame = (DWORD_PTR)memory_to_linear_addr(&sf.AddrFrame);
        dbg_curr_thread->frames[nf].addr_stack   = sf.AddrStack;
        dbg_curr_thread->frames[nf].linear_stack = (DWORD_PTR)memory_to_linear_addr(&sf.AddrStack);
        dbg_curr_thread->frames[nf].context      = prevctx;
        /* FIXME: can this heuristic be improved: we declare first context always valid, and next ones
         * if it has been modified by the call to StackWalk...
         */
        dbg_curr_thread->frames[nf].is_ctx_valid =
            (nf == 0 ||
             (dbg_curr_thread->frames[nf - 1].is_ctx_valid &&
              memcmp(&dbg_curr_thread->frames[nf - 1].context, &ctx, sizeof(ctx))));
        prevctx = ctx;
        nf++;
        /* we've probably gotten ourselves into an infinite loop so bail */
        if (nf > 200) break;
    }
    dbg_curr_thread->curr_frame = -1;
    dbg_curr_thread->num_frames = nf;
    stack_set_frame_internal(0);
    return nf;
}
Example #7
0
void stack_walk(CString& strStack, PCONTEXT p_context)
{ 

	CONTEXT * pContext = p_context;

	HANDLE hCurrentProcess = ::GetCurrentProcess();
	HANDLE hCurrentThread  = ::GetCurrentThread();

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

	sStackFrame.AddrPC.Offset	= pContext->Eip;
	sStackFrame.AddrPC.Mode		= AddrModeFlat;
	sStackFrame.AddrStack.Offset= pContext->Esp;
	sStackFrame.AddrStack.Mode	= AddrModeFlat;
	sStackFrame.AddrFrame.Offset= pContext->Ebp;
	sStackFrame.AddrFrame.Mode	= AddrModeFlat;

	USES_CONVERSION;

	//TCHAR atszCallbackBuffer[1024];
	//DWORD dwLen = 0;

	SymInitialize(GetCurrentProcess(),NULL,TRUE);

	while(StackWalk64(IMAGE_FILE_MACHINE_I386,hCurrentProcess,hCurrentThread,&sStackFrame,pContext,0,0,0,0))
	{
		if( sStackFrame.AddrFrame.Offset == 0 )
		{
			break;
		}

		strStack.Format(L"%s[%08X]", strStack,sStackFrame.AddrPC.Offset);

		BYTE sym_buffer[sizeof(IMAGEHLP_SYMBOL) + 512];
		PIMAGEHLP_SYMBOL p_symbol = (PIMAGEHLP_SYMBOL)sym_buffer;
		p_symbol->SizeOfStruct = sizeof(sym_buffer);
		p_symbol->MaxNameLength = 512;

		// Displacement of the input address, relative to the start of the symbol
		DWORD sym_displacement = 0;  
		if (!SymGetSymFromAddr(::GetCurrentProcess(), sStackFrame.AddrPC.Offset, &sym_displacement, p_symbol))
		{
			p_symbol->Name[0] = 0;
		}
		TCHAR sz_module[MAX_PATH] = {0};
		UINT_PTR section = 0, offset = 0;
		get_logical_address((PVOID)(UINT_PTR)sStackFrame.AddrPC.Offset, sz_module, sizeof(sz_module));

		strStack.Format(L"%s\t%s\t%s\r\n",strStack,A2T(p_symbol->Name),sz_module);

	}

	SymCleanup(GetCurrentProcess());
}
uint SymEngine::GetCallstack(HANDLE hThread, CONTEXT& context, CallStackBuffer& callstack) 
{
	// We can't initialize dbghelp.dll here => http://microsoft.public.windbg.narkive.com/G2WkSt2k/stackwalk64-performance-problems
	// Otherwise it will be 5x times slower
	// Init();

	STACKFRAME64 stackFrame;
	memset(&stackFrame, 0, sizeof(STACKFRAME64));
	DWORD machineType;

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

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

	uint index = 0;
	while (	StackWalk64(machineType, GetCurrentProcess(), hThread, &stackFrame, &context, nullptr, &SymFunctionTableAccess64, &SymGetModuleBase64, nullptr) )
	{
		DWORD64 dwAddress = stackFrame.AddrPC.Offset;
		if (!dwAddress)
			break;

		if (index == callstack.size())
			return 0; // Too long callstack - possible error, let's skip it

		if (index > 0 && callstack[index - 1] == dwAddress)
			continue;

		callstack[index] = dwAddress;
		++index;
	}

	return index;
}
Example #9
0
size_t backtrace_from_exception(
    LPEXCEPTION_POINTERS exception,
    void** frames,
    size_t n_frames) {
  std::call_once(sym_init_once, sym_init);

  auto context = exception->ContextRecord;
  auto thread = GetCurrentThread();
  STACKFRAME64 frame;
  DWORD image;
  size_t i = 0;
#ifdef _M_IX86
  image = IMAGE_FILE_MACHINE_I386;
  frame.AddrPC.Offset = context->Eip;
  frame.AddrPC.Mode = AddrModeFlat;
  frame.AddrFrame.Offset = context->Ebp;
  frame.AddrFrame.Mode = AddrModeFlat;
  frame.AddrStack.Offset = context->Esp;
  frame.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
  image = IMAGE_FILE_MACHINE_AMD64;
  frame.AddrPC.Offset = context->Rip;
  frame.AddrPC.Mode = AddrModeFlat;
  frame.AddrFrame.Offset = context->Rsp;
  frame.AddrFrame.Mode = AddrModeFlat;
  frame.AddrStack.Offset = context->Rsp;
  frame.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
  image = IMAGE_FILE_MACHINE_IA64;
  frame.AddrPC.Offset = context->StIIP;
  frame.AddrPC.Mode = AddrModeFlat;
  frame.AddrFrame.Offset = context->IntSp;
  frame.AddrFrame.Mode = AddrModeFlat;
  frame.AddrBStore.Offset = context->RsBSP;
  frame.AddrBStore.Mode = AddrModeFlat;
  frame.AddrStack.Offset = context->IntSp;
  frame.AddrStack.Mode = AddrModeFlat;
#else
  return 0; // No stack trace for you!
#endif
  while (i < n_frames && StackWalk64(
                             image,
                             proc,
                             thread,
                             &frame,
                             context,
                             nullptr,
                             nullptr,
                             nullptr,
                             nullptr)) {
    frames[i++] = (void*)frame.AddrPC.Offset;
  }
  return i;
}
Example #10
0
void MemoryManager::RecordStackTrace(AllocHeader* pAllocation)
{
#ifdef USE_STACKTRACE
	LPRtlCaptureContext pfnRtlCaptureContext=(LPRtlCaptureContext)GetProcAddress(GetModuleHandleW(L"kernel32.dll"),"RtlCaptureContext");
	if(!pfnRtlCaptureContext) {
		return;
	}

	CONTEXT ctx;
	pfnRtlCaptureContext(&ctx);

	STACKFRAME64 theStackFrame;
	memset(&theStackFrame,0,sizeof(theStackFrame));
	#ifdef _M_IX86
		DWORD dwMachineType=IMAGE_FILE_MACHINE_I386;
		theStackFrame.AddrPC.Offset=ctx.Eip;
		theStackFrame.AddrPC.Mode=AddrModeFlat;
		theStackFrame.AddrFrame.Offset=ctx.Ebp;
		theStackFrame.AddrFrame.Mode=AddrModeFlat;
		theStackFrame.AddrStack.Offset=ctx.Esp;
		theStackFrame.AddrStack.Mode=AddrModeFlat;
	#elif _M_X64
		DWORD dwMachineType=IMAGE_FILE_MACHINE_AMD64;
		theStackFrame.AddrPC.Offset=ctx.Rip;
		theStackFrame.AddrPC.Mode=AddrModeFlat;
		theStackFrame.AddrFrame.Offset=ctx.Rsp;
		theStackFrame.AddrFrame.Mode=AddrModeFlat;
		theStackFrame.AddrStack.Offset=ctx.Rsp;
		theStackFrame.AddrStack.Mode=AddrModeFlat;
	#elif _M_IA64
		DWORD dwMachineType=IMAGE_FILE_MACHINE_IA64;
		theStackFrame.AddrPC.Offset=ctx.StIIP;
		theStackFrame.AddrPC.Mode=AddrModeFlat;
		theStackFrame.AddrFrame.Offset=ctx.IntSp;
		theStackFrame.AddrFrame.Mode=AddrModeFlat;
		theStackFrame.AddrBStore.Offset=ctx.RsBSP;
		theStackFrame.AddrBStore.Mode=AddrModeFlat;
		theStackFrame.AddrStack.Offset=ctx.IntSp;
		theStackFrame.AddrStack.Mode=AddrModeFlat;
	#else
	#	error "Platform not supported!"
	#endif

	memset(pAllocation->nPC,0,sizeof(pAllocation->nPC));
	for(int i=0;i<AllocHeader::cnMaxStackFrames;++i) {
		pAllocation->nPC[i]=theStackFrame.AddrPC.Offset;
		if(!StackWalk64(dwMachineType,GetCurrentProcess(),GetCurrentThread(),&theStackFrame,&ctx,NULL,SymFunctionTableAccess64,SymGetModuleBase64,NULL)) {
			break;
		}
	}
#endif
	UNREFERENCED_PARAMETER(pAllocation);
}
Example #11
0
static int jl_unw_step(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp)
{
    // Might be called from unmanaged thread.
#ifndef _CPU_X86_64_
    *ip = (uintptr_t)cursor->stackframe.AddrPC.Offset;
    *sp = (uintptr_t)cursor->stackframe.AddrStack.Offset;
    BOOL result = StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), hMainThread,
        &cursor->stackframe, &cursor->context, NULL, JuliaFunctionTableAccess64, JuliaGetModuleBase64, NULL);
    return result;
#else
    *ip = (uintptr_t)cursor->Rip;
    *sp = (uintptr_t)cursor->Rsp;
    DWORD64 ImageBase = JuliaGetModuleBase64(GetCurrentProcess(), cursor->Rip);
    if (!ImageBase)
        return 0;

    PRUNTIME_FUNCTION FunctionEntry = (PRUNTIME_FUNCTION)JuliaFunctionTableAccess64(GetCurrentProcess(), cursor->Rip);
    if (!FunctionEntry) { // assume this is a NO_FPO RBP-based function
        MEMORY_BASIC_INFORMATION mInfo;

        cursor->Rsp = cursor->Rbp;                 // MOV RSP, RBP

        // Check whether the pointer is valid and executable before dereferencing
        // to avoid segfault while recording. See #10638.
        if (VirtualQuery((LPCVOID)cursor->Rsp, &mInfo, sizeof(MEMORY_BASIC_INFORMATION)) == 0)
            return 0;
        DWORD X = mInfo.AllocationProtect;
        if (!((X&PAGE_READONLY) || (X&PAGE_READWRITE) || (X&PAGE_WRITECOPY) || (X&PAGE_EXECUTE_READ)) ||
              (X&PAGE_GUARD) || (X&PAGE_NOACCESS))
            return 0;

        cursor->Rbp = *(DWORD64*)cursor->Rsp;      // POP RBP
        cursor->Rsp = cursor->Rsp + sizeof(void*);
        cursor->Rip = *(DWORD64*)cursor->Rsp;      // POP RIP (aka RET)
        cursor->Rsp = cursor->Rsp + sizeof(void*);
    }
    else {
        PVOID HandlerData;
        DWORD64 EstablisherFrame;
        (void)RtlVirtualUnwind(
                0 /*UNW_FLAG_NHANDLER*/,
                ImageBase,
                cursor->Rip,
                FunctionEntry,
                cursor,
                &HandlerData,
                &EstablisherFrame,
                NULL);
    }
    return cursor->Rip != 0;
#endif
}
Example #12
0
void CDebugger::PrintCallStack(DWORD dwThreadId, DWORD dwProcessId) {
    STACKFRAME64 stackFrame = { 0 };
    const DWORD_PTR dwMaxFrames = 50;

    UpdateContext(dwThreadId);

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

    DWORD dwMachineType = IMAGE_FILE_MACHINE_I386;
    stackFrame.AddrPC.Offset = m_context.Eip;
    stackFrame.AddrFrame.Offset = m_context.Ebp;
    stackFrame.AddrStack.Offset = m_context.Esp;

    HANDLE hThread = OpenThread(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, dwThreadId);
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcessId);

    m_pSymbols->RefreshSymbols(hProcess);

    // Print call stack
    stringstream ssCallStack;
    for (int i = 0; i < dwMaxFrames; ++i) {
        bool bSuccess = StackWalk64(dwMachineType, hProcess, hThread, &stackFrame,
            (dwMachineType == IMAGE_FILE_MACHINE_I386 ? nullptr : &m_context), nullptr,
            SymFunctionTableAccess64, SymGetModuleBase64, nullptr);
        if (!bSuccess || stackFrame.AddrPC.Offset == 0) {
            cout <<  "StackWalk64 finished." << endl;
            break;
        }

        IMAGEHLP_MODULE64 module = {0};
        module.SizeOfStruct = sizeof(module);
        SymGetModuleInfo64(hProcess, (DWORD64)stackFrame.AddrPC.Offset, &module);

        //SymLoadModuleEx(hProcess, NULL, module.LoadedImageName, NULL, module.BaseOfImage,  0,  NULL, 0);
        //cout << "modulePath: " << module.LoadedImageName << ", baseofdll: " << module.BaseOfImage << ", symbol: " << module.LoadedPdbName << endl;
        PSYMBOL_INFO pSymInfo = m_pSymbols->SymbolFromAddress(stackFrame.AddrPC.Offset);
        if (pSymInfo) {
            ssCallStack << "#" << dec << i << " " <<  module.ModuleName << "!" << pSymInfo->Name << endl;
        } else {
            ssCallStack << "#" << dec << i << " " <<  module.ModuleName << "!" << "unknown" << endl;
        }

        delete pSymInfo;
    }

    m_pCrash->GetHash(ssCallStack.str());
    m_pCrash->AddLog("\nCall Stack\n" + ssCallStack.str());
}
/*
 *   StackTracer::Walk
 *      Walks on the stack, each walk is one frame of backtrace
 *      Returns a frame or null if the walk on the park is not possible anymore
 */
StackTracer::Trace* StackTracer::Walk()
{
    if (StackWalk64(IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), GetCurrentThread(),
        &frame, &context, NULL, NULL, NULL, NULL))
    {
        trace.module = GetModuleFromAddress((void*)frame.AddrPC.Offset);
        trace.frame = (void*)frame.AddrFrame.Offset;
        trace.stack = (void*)frame.AddrStack.Offset;
        trace.pc = (void*)frame.AddrPC.Offset;
        trace.ret = (void*)frame.AddrReturn.Offset;
        return &trace;
    }
    return nullptr;
}
Example #14
0
  void generate_stack_walk(std::ostream & os, CONTEXT ctx, int skip) {
    STACKFRAME64 sf = {};
    #ifdef _M_IX86
      DWORD machine_type  = IMAGE_FILE_MACHINE_I386;
      sf.AddrPC.Offset    = ctx.Eip;
      sf.AddrPC.Mode      = AddrModeFlat;
      sf.AddrStack.Offset = ctx.Esp;
      sf.AddrStack.Mode   = AddrModeFlat;
      sf.AddrFrame.Offset = ctx.Ebp;
      sf.AddrFrame.Mode   = AddrModeFlat;
    #elif defined(_M_X64)
	    DWORD machine_type  = IMAGE_FILE_MACHINE_AMD64;
	    sf.AddrPC.Offset    = ctx.Rip;
	    sf.AddrPC.Mode      = AddrModeFlat;
	    sf.AddrFrame.Offset = ctx.Rsp;
	    sf.AddrFrame.Mode   = AddrModeFlat;
	    sf.AddrStack.Offset = ctx.Rsp;
	    sf.AddrStack.Mode   = AddrModeFlat;
	  #else
	    #error Unsupported platform
	  #endif
     
    HANDLE process = GetCurrentProcess();
    HANDLE thread = GetCurrentThread();
    
    os << std::uppercase;
    for (;;) {
      SetLastError(0);
      BOOL stack_walk_ok = StackWalk64(machine_type, process, thread, &sf,
                                      &ctx, 0, &SymFunctionTableAccess64, 
                                      &SymGetModuleBase64, 0);
      if (!stack_walk_ok || !sf.AddrFrame.Offset) return;
      
      if (skip) {
        --skip;
      } else {
        // write the address
        os << std::hex << reinterpret_cast<void *>(sf.AddrPC.Offset) << "|" << std::dec;

        write_module_name(os, process, sf.AddrPC.Offset);
        write_function_name(os, process, sf.AddrPC.Offset);
        write_file_and_line(os, process, sf.AddrPC.Offset);

        os << "\n";
      }
    }
  }
Example #15
0
static LONG WINAPI TopLevelExceptionFilter(_EXCEPTION_POINTERS* exceptionInfo)
{
	static struct {
		LONG used;
		CONTEXT contextRecord;
		STACKFRAME64 stackFrame;
		PVOID addrOffsets[32];
	} work;

	if( InterlockedExchange(&work.used, 1) == 0 ){
		SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
		if( SymInitialize(GetCurrentProcess(), NULL, TRUE) ){
			work.addrOffsets[0] = exceptionInfo->ExceptionRecord->ExceptionAddress;
			work.contextRecord = *exceptionInfo->ContextRecord;
			work.stackFrame.AddrPC.Mode = AddrModeFlat;
			work.stackFrame.AddrFrame.Mode = AddrModeFlat;
			work.stackFrame.AddrStack.Mode = AddrModeFlat;
#if defined(_M_IX86) || defined(_M_X64)
#ifdef _M_X64
			work.stackFrame.AddrPC.Offset = work.contextRecord.Rip;
			work.stackFrame.AddrFrame.Offset = work.contextRecord.Rbp;
			work.stackFrame.AddrStack.Offset = work.contextRecord.Rsp;
#else
			work.stackFrame.AddrPC.Offset = work.contextRecord.Eip;
			work.stackFrame.AddrFrame.Offset = work.contextRecord.Ebp;
			work.stackFrame.AddrStack.Offset = work.contextRecord.Esp;
#endif
			for( int i = 1; i < _countof(work.addrOffsets) - 1 && StackWalk64(
#ifdef _M_X64
				IMAGE_FILE_MACHINE_AMD64,
#else
				IMAGE_FILE_MACHINE_I386,
#endif
				GetCurrentProcess(), GetCurrentThread(), &work.stackFrame, &work.contextRecord,
				NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL); i++ ){
				work.addrOffsets[i] = (PVOID)work.stackFrame.AddrPC.Offset;
			}
#endif
			OutputStackTrace(exceptionInfo->ExceptionRecord->ExceptionCode, work.addrOffsets);
			SymCleanup(GetCurrentProcess());
		}
	}
	return EXCEPTION_CONTINUE_SEARCH;
}
Example #16
0
		void StackWalker::GenerateStackTrace(std::ostream& os, CONTEXT ctx, int skip) 
		{
			STACKFRAME64 sf		= {};
			sf.AddrPC.Offset    = ctx.Eip;
			sf.AddrPC.Mode      = AddrModeFlat;
			sf.AddrStack.Offset = ctx.Esp;
			sf.AddrStack.Mode   = AddrModeFlat;
			sf.AddrFrame.Offset = ctx.Ebp;
			sf.AddrFrame.Mode   = AddrModeFlat;

			HANDLE process	= GetCurrentProcess();
			HANDLE thread	= GetCurrentThread();

			os << std::uppercase;
			for (;;) 
			{
				SetLastError(0);
				BOOL stack_walk_ok = StackWalk64(	IMAGE_FILE_MACHINE_I386, process, thread, &sf,
													&ctx, 0, &SymFunctionTableAccess64, 
													&SymGetModuleBase64, 0);

				if (!stack_walk_ok || !sf.AddrFrame.Offset) return;

				if (skip) 
				{
					--skip;
				} 
				else 
				{
					// write the address

					os << std::hex << reinterpret_cast<void *>(sf.AddrPC.Offset) << " | " << std::dec;

					WriteModuleName(os, process, sf.AddrPC.Offset);
					WriteFunctionName(os, process, sf.AddrPC.Offset);
					WriteFileAndLine(os, process, sf.AddrPC.Offset);

					os << "\n";
				}
			}
		}
void CExceptionParser::ParseCallStack(PCONTEXT pContextRecord,UINT MaxLoopCount)
{
	if(m_hProcess==NULL)
		return;


	static HINSTANCE LastInstance=NULL;

	static ADDRESS_INFO AddressInfo;

	static STACKFRAME64 StackFrame;

	ZeroMemory(&StackFrame,sizeof(StackFrame));

	StackFrame.AddrPC.Offset=pContextRecord->Eip;
	StackFrame.AddrPC.Mode=AddrModeFlat;
	StackFrame.AddrStack.Offset=pContextRecord->Esp;
	StackFrame.AddrStack.Mode=AddrModeFlat;
	StackFrame.AddrFrame.Offset=pContextRecord->Ebp;
	StackFrame.AddrFrame.Mode=AddrModeFlat;

	while(MaxLoopCount&&StackWalk64(IMAGE_FILE_MACHINE_I386,m_hProcess,GetCurrentThread(),
		&StackFrame,pContextRecord,0,SymFunctionTableAccess64,SymGetModuleBase64,0))
	{
		if(StackFrame.AddrFrame.Offset==0)
			break;
		if(GetAddressInfo(StackFrame.AddrPC.Offset,&AddressInfo))
		{
			if(LastInstance!=AddressInfo.hInstance)
			{	
				LastInstance=AddressInfo.hInstance;
				PrintLog("调用模块:%s",AddressInfo.ModuleName);
			}
			PrintLog("调用地址:0x%X",(DWORD)StackFrame.AddrPC.Offset);
			PrintLog("地址描述:函数(%s),文件(%s)(%d)",AddressInfo.SymbolInfo.Name,AddressInfo.CppFileName,AddressInfo.LineNumber);
		}				
		
		MaxLoopCount--;
	}
}
Example #18
0
int KDumpModuleAnalyzer::MoveStack()
{
	int nResult = false;
	int nRetCode = false;

	nRetCode = StackWalk64(
		IMAGE_FILE_MACHINE_I386, 
		m_hProcess, 
		m_hThread, 
		&m_Stackframe, 
		&m_Context, 
		NULL,//ReadProcessMemory, 
		SymFunctionTableAccess64, 
		SymGetModuleBase64, 
		NULL
	);
	KG_PROCESS_ERROR(nRetCode);
	if (m_Stackframe.AddrPC.Offset != m_Stackframe.AddrReturn.Offset)
	{
		m_nCurRecursionCount = 0;
	}
	else
	{
		m_nCurRecursionCount++;
		KG_PROCESS_ERROR(m_nCurRecursionCount < MAX_RECURSION_COUNT);
	}


	m_dwStackAddress = m_Stackframe.AddrPC.Offset;
	nResult = true;
Exit0:
#ifdef OPEN_LOG_AND_BREAK
	KLogPrintf("MoveStack:%s", nResult ? "Success" : "Fail");
#endif
	return nResult;
}
Example #19
0
int ZCE_LIB::backtrace_stack(ZCE_LOG_PRIORITY dbg_lvl,
                             const char *dbg_info)
{

    //跟踪函数的层数
    const size_t SIZE_OF_BACKTRACE_FUNC = 100;

#if defined(ZCE_OS_LINUX)
    ZCE_LOG(dbg_lvl, "[BACKTRACE]This program compiled by Linux GCC. %s", dbg_info);
    //Windows 下必须是2008或者VISTA之后的SDK才支持,
#elif defined(ZCE_OS_WINDOWS) && ZCE_SUPPORT_WINSVR2008 == 1
    ZCE_LOG(dbg_lvl, "[BACKTRACE]This program compiled by Windows Visual studio .%s", dbg_info);
#else
    ZCE_UNUSED_ARG(SIZE_OF_BACKTRACE_FUNC);
    ZCE_LOG(dbg_lvl, "[BACKTRACE]back_trace_stack don't support this system.%s", dbg_info);
#endif


    //这个方法是提供给Linux 下的GCC使用的
#if defined(ZCE_OS_LINUX)


    void *backtrace_buffer[SIZE_OF_BACKTRACE_FUNC];
    char **symbols_strings;

    int sz_of_stack = ::backtrace(backtrace_buffer, SIZE_OF_BACKTRACE_FUNC);

    //
    symbols_strings = ::backtrace_symbols(backtrace_buffer, sz_of_stack);

    if (symbols_strings == NULL)
    {
        ZCE_LOG(dbg_lvl, "%s", "[BACKTRACE] backtrace_symbols return fail.");
    }

    //打印所有的堆栈信息,有些时候信息无法显示符号表,建议使用
    for (int j = 0; j < sz_of_stack; j++)
    {
        ZCE_LOG(dbg_lvl, "[BACKTRACE] %u, %s.", j + 1, symbols_strings[j]);
    }

    //释放空间
    ::free(symbols_strings);

#elif defined(ZCE_OS_WINDOWS) && ZCE_SUPPORT_WINSVR2008 == 1

    //我还没有时间看完dbghelp所有的东西,目前的代码参考后一个版本居多,目前这个东东必须有pdb文件,
    //http://blog.csdn.net/skies457/article/details/7201185

    // Max length of symbols' name.
    const size_t MAX_NAME_LENGTH = 256;

    // Store register addresses.
    CONTEXT context;
    // Call stack.
    STACKFRAME64 stackframe;
    // Handle to current process & thread.
    HANDLE process, cur_thread;
    // Generally it can be subsitituted with 0xFFFFFFFF & 0xFFFFFFFE.
    // Debugging symbol's information.
    PSYMBOL_INFO symbol;
    // Source information (file name & line number)
    IMAGEHLP_LINE64 source_info;
    // Source line displacement.
    DWORD displacement;

    // Initialize PSYMBOL_INFO structure.
    // Allocate a properly-sized block.
    symbol = (PSYMBOL_INFO)malloc(sizeof(SYMBOL_INFO) + (MAX_NAME_LENGTH) * sizeof(char));
    memset(symbol, 0, sizeof(SYMBOL_INFO) + (MAX_NAME_LENGTH) * sizeof(TCHAR));
    symbol->SizeOfStruct = sizeof(SYMBOL_INFO);  // SizeOfStruct *MUST BE* set to sizeof(SYMBOL_INFO).
    symbol->MaxNameLen = MAX_NAME_LENGTH;

    // Initialize IMAGEHLP_LINE64 structure.
    memset(&source_info, 0, sizeof(IMAGEHLP_LINE64));
    source_info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);

    // Initialize STACKFRAME64 structure.
    RtlCaptureContext(&context);            // Get context.
    memset(&stackframe, 0, sizeof(STACKFRAME64));

    // Fill in register addresses (EIP, ESP, EBP).

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

#if defined ZCE_WIN32
    stackframe.AddrPC.Offset = context.Eip;
    stackframe.AddrStack.Offset = context.Esp;
    stackframe.AddrFrame.Offset = context.Ebp;
#elif defined ZCE_WIN64
    stackframe.AddrPC.Offset = context.Rip;
    stackframe.AddrStack.Offset = context.Rsp;
    stackframe.AddrFrame.Offset = context.Rbp;
#else
#endif
    // Get current process & thread.
    process = GetCurrentProcess();
    cur_thread = GetCurrentThread();

    // Initialize dbghelp library.
    if (!SymInitialize(process, NULL, TRUE))
    {
        return -1;
    }

    //这些空间是绝对足够的,我也不做详细的检查了
    const size_t LINE_OUTLEN = 1024;
    char line_out[LINE_OUTLEN];
    int use_len = 0;

    uint32_t k = 0;
    // Enumerate call stack frame.
    while (StackWalk64(IMAGE_FILE_MACHINE_I386,
                       process,
                       cur_thread,
                       &stackframe,
                       &context,
                       NULL,
                       SymFunctionTableAccess64,
                       SymGetModuleBase64,
                       NULL))
    {
        use_len = 0;
        // End reaches.
        if (stackframe.AddrFrame.Offset == 0 || k > SIZE_OF_BACKTRACE_FUNC)
        {
            break;
        }

        // Get symbol.
        if (SymFromAddr(process, stackframe.AddrPC.Offset, NULL, symbol))
        {
            use_len += snprintf(line_out + use_len, LINE_OUTLEN - use_len, " %s", symbol->Name);

        }

        if (SymGetLineFromAddr64(process, stackframe.AddrPC.Offset,
                                 &displacement,
                                 &source_info))
        {
            // Get source information.
            use_len += snprintf(line_out + use_len, LINE_OUTLEN - use_len, "\t[ %s: %d] at addr 0x % 08LX",
                                source_info.FileName,
                                source_info.LineNumber,
                                stackframe.AddrPC.Offset);
        }
        else
        {
            // If err_code == 0x1e7, no symbol was found.
            if (GetLastError() == 0x1E7)
            {
                use_len += snprintf(line_out + use_len, LINE_OUTLEN - use_len, "%s", "\tNo debug symbol loaded for this function.");
            }
        }
        ZCE_LOG(dbg_lvl, "[BACKTRACE] %u, %s.", k + 1, line_out);
        ++k;
    }

    SymCleanup(process);    // Clean up and exit.
    free(symbol);

#endif

    //
    return 0;

}
Example #20
0
    /**
     * Print stack trace (using a specified stack context) to "os"
     * 
     * @param context   CONTEXT record for stack trace
     * @param os        ostream& to receive printed stack backtrace
     */
    void printWindowsStackTrace( CONTEXT& context, std::ostream& os ) {
        SimpleMutex::scoped_lock lk(_stackTraceMutex);
        HANDLE process = GetCurrentProcess();
        BOOL ret = SymInitialize(process, getSymbolSearchPath(process), TRUE);
        if ( ret == FALSE ) {
            DWORD dosError = GetLastError();
            log() << "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 );

        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 ) {
            std::stringstream ss;
            ss << traceList[i].moduleName << " ";
            size_t width = traceList[i].moduleName.length();
            while ( width < moduleWidth ) {
                ss << " ";
                ++width;
            }
            ss << traceList[i].sourceAndLine << " ";
            width = traceList[i].sourceAndLine.length();
            while ( width < sourceWidth ) {
                ss << " ";
                ++width;
            }
            ss << traceList[i].symbolAndOffset;
            log() << ss.str() << std::endl;
        }
    }
Example #21
0
bool DebugInfo::SendStackTrace()
#endif
{
    const unsigned int maxTrace = 256;
    void* stacktrace[maxTrace];

#ifdef _WIN32

#ifndef _MSC_VER
    CONTEXT context;
    LPCONTEXT ctx = NULL;

    HMODULE kernel32 = LoadLibrary("kernel32.dll");
    HMODULE dbghelp = LoadLibrary("dbghelp.dll");

    if ((!kernel32) || (!dbghelp))
    {
        return(false);
    }

    RtlCaptureContextType RtlCaptureContext = (RtlCaptureContextType)(GetProcAddress(kernel32, "RtlCaptureContext"));

    SymInitializeType SymInitialize = (SymInitializeType)(GetProcAddress(dbghelp, "SymInitialize"));
    SymCleanupType SymCleanup = (SymCleanupType)(GetProcAddress(dbghelp, "SymCleanup"));

    StackWalkType StackWalk64 = (StackWalkType)(GetProcAddress(dbghelp, "StackWalk64"));
    PFUNCTION_TABLE_ACCESS_ROUTINE64 SymFunctionTableAccess64 = (PFUNCTION_TABLE_ACCESS_ROUTINE64)(GetProcAddress(dbghelp, "SymFunctionTableAccess64"));
    PGET_MODULE_BASE_ROUTINE64 SymGetModuleBase64 = (PGET_MODULE_BASE_ROUTINE64)(GetProcAddress(dbghelp, "SymGetModuleBase64"));

    if ((!SymInitialize) || (!StackWalk64) || (!SymFunctionTableAccess64) || (!SymGetModuleBase64) || (!RtlCaptureContext))
    {
        return(false);
    }
#endif

    if (!SymInitialize(GetCurrentProcess(), NULL, true))
    {
        return(false);
    }

#ifndef _MSC_VER
    if (!ctx)
    {
        context.ContextFlags = CONTEXT_FULL;
        RtlCaptureContext(&context);
        ctx = &context;
    }
#endif

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

#ifdef _WIN64
    frame.AddrPC.Offset = ctx->Rip;
    frame.AddrStack.Offset = ctx->Rsp;
    frame.AddrFrame.Offset = ctx->Rbp;
#else
    frame.AddrPC.Offset = ctx->Eip;
    frame.AddrStack.Offset = ctx->Esp;
    frame.AddrFrame.Offset = ctx->Ebp;
#endif

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

    HANDLE process = GetCurrentProcess();
    HANDLE thread = GetCurrentThread();

    unsigned num_frames = 0;
    while (StackWalk64(
#ifdef _WIN64
                IMAGE_FILE_MACHINE_AMD64,
#else
                IMAGE_FILE_MACHINE_I386,
#endif
                process, thread, &frame,
                ctx, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL) && (num_frames < maxTrace))
    {
        LOG.lprintf("Reading stack frame %d\n", num_frames);
        stacktrace[num_frames++] = (void*) frame.AddrPC.Offset;
    }

    SymCleanup(GetCurrentProcess());

    /*CaptureStackBackTraceType CaptureStackBackTrace = (CaptureStackBackTraceType)(GetProcAddress(LoadLibraryA("kernel32.dll"), "RtlCaptureStackBackTrace"));

    if (!CaptureStackBackTrace)
    {
        return(false);
    }

    unsigned num_frames = CaptureStackBackTrace(0, maxTrace, stacktrace, NULL);
    LOG.lprintf("Read Frames %d\n", num_frames);
    */
#else
    unsigned num_frames = backtrace(stacktrace, maxTrace);
#endif

    LOG.lprintf("Will now send %d stack frames\n", num_frames);

    if (!SendString("StackTrace"))
        return(false);

    num_frames *= sizeof(void*);

    return(SendString((char*) &stacktrace, num_frames));
}
Example #22
0
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 symbolRecordSize = sizeof(SYMBOL_INFO) + nameSize;
    boost::scoped_array<char> symbolBuffer( new char[symbolRecordSize] );
    memset( symbolBuffer.get(), 0, symbolRecordSize );
    SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>( symbolBuffer.get() );
    symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
    symbol->MaxNameLen = nameSize;

    std::vector<TraceItem> traceList;
    TraceItem traceItem;
    size_t moduleWidth = 0;
    size_t fileWidth = 0;
    size_t frameCount = 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 ) {
            frameCount = i;
            break;
        }

        // module (executable) name
        IMAGEHLP_MODULE64 module;
        memset ( &module, 0, sizeof(module) );
        module.SizeOfStruct = sizeof(module);
        ret = SymGetModuleInfo64( process, frame64.AddrPC.Offset, &module );
        char* moduleName = module.LoadedImageName;
        char* backslash = strrchr( moduleName, '\\' );
        if ( backslash ) {
            moduleName = backslash + 1;
        }
        traceItem.module = moduleName;
        size_t len = traceItem.module.length();
        if ( len > moduleWidth ) {
            moduleWidth = len;
        }

        // source code filename and line number
        IMAGEHLP_LINE64 line;
        memset( &line, 0, sizeof(line) );
        line.SizeOfStruct = sizeof(line);
        DWORD displacement32;
        ret = SymGetLineFromAddr64( process, frame64.AddrPC.Offset, &displacement32, &line );
        if ( ret ) {
            std::string filename( line.FileName );
            std::string::size_type start = filename.find( "\\src\\mongo\\" );
            if ( start == std::string::npos ) {
                start = filename.find( "\\src\\third_party\\" );
            }
            if ( start != std::string::npos ) {
                std::string shorter( "..." );
                shorter += filename.substr( start );
                traceItem.sourceFile.swap( shorter );
            }
            else {
                traceItem.sourceFile.swap( filename );
            }
            len = traceItem.sourceFile.length() + 3;
            traceItem.lineNumber = line.LineNumber;
            if ( traceItem.lineNumber < 10 ) {
                len += 1;
            }
            else if ( traceItem.lineNumber < 100 ) {
                len += 2;
            }
            else if ( traceItem.lineNumber < 1000 ) {
                len += 3;
            }
            else if ( traceItem.lineNumber < 10000 ) {
                len += 4;
            }
            else {
                len += 5;
            }
            traceItem.sourceLength = len;
            if ( len > fileWidth ) {
                fileWidth = len;
            }
        }
        else {
            traceItem.sourceFile.clear();
            traceItem.sourceLength = 0;
        }

        // symbol name and offset from symbol
        DWORD64 displacement;
        ret = SymFromAddr( process, frame64.AddrPC.Offset, &displacement, symbol );
        if ( ret ) {
            traceItem.symbol = symbol->Name;
            traceItem.instructionOffset = displacement;
        }
        else {
            traceItem.symbol = "???";
            traceItem.instructionOffset = 0;
        }

        // add to list
        traceList.push_back( traceItem );
    }
    SymCleanup( process );

    // print list
    ++moduleWidth;
    ++fileWidth;
    for ( size_t i = 0; i < frameCount; ++i ) {
        os << traceList[i].module << " ";
        size_t width = traceList[i].module.length();
        while ( width < moduleWidth ) {
            os << " ";
            ++width;
        }
        if ( traceList[i].sourceFile.length() ) {
            os << traceList[i].sourceFile << "(" << std::dec << traceList[i].lineNumber << ") ";
        }
        width = traceList[i].sourceLength;
        while ( width < fileWidth ) {
            os << " ";
            ++width;
        }
        os << traceList[i].symbol << "+0x" << std::hex << traceList[i].instructionOffset;
        os << std::endl;
    }
}
Example #23
0
GCallStack::GCallStack(HANDLE hThread, CONTEXT& c)
{
	if (!_bLockInit) // only init the single instance of the CRITICAL_SECTION 1 time for the many instances of GCallStack
	{
		InitializeCriticalSection(&_DbgHelpLock);
		_bLockInit = true;
	}

	DWORD imageType = IMAGE_FILE_MACHINE_I386;
	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId());
	int frameNum = 0; // counts walked frames
	int MAX_STACK_FRAMES = 7777; // in C# the maximum stack frames imposed by the language is 1000.  Arbitrary limit to guarantee no condition of infinate walking in corrupted memory.
	DWORD offsetFromLine; // tells us line number in the source file
#if defined(_LINUX64) || defined(_WIN64) || defined(_IOS)
	unsigned __int64 offsetFromSymbol; // tells us how far from the symbol we were
#else
	DWORD offsetFromSymbol; // tells us how far from the symbol we were
#endif

	DWORD symOptions; // symbol handler settings
	IMAGEHLP_SYMBOL *pSym = (IMAGEHLP_SYMBOL *) malloc( IMGSYMLEN + MAXNAMELEN );

	GString strStackName(MAXNAMELEN + 512); // undecorated method/function name + Source file and line number

	IMAGEHLP_MODULE Module;
	IMAGEHLP_LINE Line;
	STACKFRAME64 s; // in/out stackframe
	memset( &s, '\0', sizeof s );

//  note: converted code from [std::string symSearchPath] to [GString symSearchPath] so it will compile with the _UNICODE build flag - 8/18/2014
	GString symSearchPath;

#ifdef _UNICODE
	wchar_t *tt = 0, *p;
	tt = new wchar_t[TTBUFLEN];
#else
	char *tt = 0, *p;
	tt = new char[TTBUFLEN];
#endif

	// build symbol search path from:
	symSearchPath = "";
	// current directory
	if (GetCurrentDirectory(TTBUFLEN, tt))
		symSearchPath << tt << "; ";
	// dir with executable
	if ( GetModuleFileName( 0, tt, TTBUFLEN ) )
	{
#ifdef _UNICODE
		for (p = tt + wcslen(tt) - 1; p >= tt; --p)
#else
		for (p = tt + strlen(tt) - 1; p >= tt; --p)	// VC6 does not have a _tcsclen() and we still support VC6
#endif
		{
			// locate the rightmost path separator
			if ( *p == '\\' || *p == '/' || *p == ':' )
				break;
		}
		// if we found one, p is pointing at it; if not, tt only contains an exe name (no path), and p points before its first byte
		if ( p != tt ) // path sep found?
		{
			if ( *p == ':' ) // we leave colons in place
				++ p;
			*p = '\0'; // eliminate the exe name and last path sep
			symSearchPath << tt << "; "; 
		}
	}
	// environment variable _NT_SYMBOL_PATH
	GString g("_NT_SYMBOL_PATH");
	if (GetEnvironmentVariable(g, tt, TTBUFLEN))
		symSearchPath << tt << "; ";
	// environment variable _NT_ALTERNATE_SYMBOL_PATH
	g = "_NT_ALTERNATE_SYMBOL_PATH";
	if (GetEnvironmentVariable(g, tt, TTBUFLEN))
		symSearchPath << tt << "; ";
	// environment variable SYSTEMROOT
	g = "SYSTEMROOT";
	if (GetEnvironmentVariable(g, tt, TTBUFLEN))
		symSearchPath << tt << "; ";

	if ( symSearchPath.size() > 0 ) // if we added anything, we have a trailing semicolon
		symSearchPath = symSearchPath.substr( 0, symSearchPath.size() - 1 );

	// 8/20/2014 note: In older Windows API's SymInitialize()'s 2nd argument was not defined as "const char *", it was only "char *" 
	// Although "const" was not defined, the API call is "const" in behavior.  In newer versions of the Windows API this has been fixed.
	// In newer versions - SymInitialize's 2nd argument may resolve to either "const char *" OR "const wchar_t *", and in those builds the
	// GString has a default conversion to the correct string type, however in the older build configurations, GString does not (and should not)
	// know how to resolve to a "char *" by default, so in that case the preprocessor directive isolates the code needed to convert to "char *" 

#if defined(_MSC_VER) && _MSC_VER <= 1200
	if (!SymInitialize(hProcess, symSearchPath.Buf(),	false))	// symSearchPath == (char *)
#else
	if (!SymInitialize(hProcess, symSearchPath,			true))  // symSearchPath == (const char *)  --OR--  (const wchar_t *) depending on the _UNICODE preprocessor definition
#endif
	{
		goto tagCleanUp;
	}

	symOptions = SymGetOptions();
	symOptions |= SYMOPT_LOAD_LINES;
	symOptions &= ~SYMOPT_UNDNAME;
	SymSetOptions( symOptions );

	enumAndLoadModuleSymbols( hProcess, GetCurrentProcessId() );

	// init STACKFRAME for first call, definitions found in ImageHlp.h
#ifdef _M_IX86
	imageType = IMAGE_FILE_MACHINE_I386;
	s.AddrPC.Offset = c.Eip;
	s.AddrPC.Mode = AddrModeFlat;
	s.AddrFrame.Offset = c.Ebp;
	s.AddrFrame.Mode = AddrModeFlat;
	s.AddrStack.Offset = c.Esp;
	s.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
	imageType = IMAGE_FILE_MACHINE_AMD64;
	s.AddrPC.Offset = c.Rip;
	s.AddrPC.Mode = AddrModeFlat;
	s.AddrFrame.Offset = c.Rsp;
	s.AddrFrame.Mode = AddrModeFlat;
	s.AddrStack.Offset = c.Rsp;
	s.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
	imageType = IMAGE_FILE_MACHINE_IA64;
	s.AddrPC.Offset = c.StIIP;
	s.AddrPC.Mode = AddrModeFlat;
	s.AddrFrame.Offset = c.IntSp;
	s.AddrFrame.Mode = AddrModeFlat;
	s.AddrBStore.Offset = c.RsBSP;
	s.AddrBStore.Mode = AddrModeFlat;
	s.AddrStack.Offset = c.IntSp;
	s.AddrStack.Mode = AddrModeFlat;
#endif

	memset( pSym, '\0', IMGSYMLEN + MAXNAMELEN );
	pSym->SizeOfStruct = IMGSYMLEN;
	pSym->MaxNameLength = MAXNAMELEN;

	memset( &Line, '\0', sizeof Line );
	Line.SizeOfStruct = sizeof Line;

	memset( &Module, '\0', sizeof Module );
	Module.SizeOfStruct = sizeof Module;

	offsetFromSymbol = 0;

	
	//	DbgHelp is single threaded, so acquire a lock.
	EnterCriticalSection(&_DbgHelpLock);

	while ( frameNum < MAX_STACK_FRAMES )
	{
		// get next stack frame (StackWalk(), SymFunctionTableAccess(), SymGetModuleBase())
		// if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can
		// assume that either you are done, or that the stack is so hosed that the next deeper frame could not be found.
#ifdef _WIN64
		if (!StackWalk64(imageType, hProcess, hThread, &s, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
#else
		if (!StackWalk(imageType, hProcess, hThread, &s, &c, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL))
#endif
			break;  // Maybe it failed, maybe we have finished walking the stack

		if ( s.AddrPC.Offset != 0 )
		{ 
			// Most likely a valid stack rame
			
			// show procedure info 
			if ( ! SymGetSymFromAddr64( hProcess, s.AddrPC.Offset, &offsetFromSymbol, pSym ) )
			{
				break;
			}
			else
			{
				// UnDecorateSymbolName() to get the Class::Method or function() name in tyhe callstack
				strStackName.Empty();
 				UnDecorateSymbolName(pSym->Name, strStackName._str, MAXNAMELEN, UNDNAME_COMPLETE);
				strStackName.SetLength(strlen(strStackName._str));

				// SymGetLineFromAddr() to get the source.cpp and the line number 
				IMAGEHLP_LINE64 Line;
				if (SymGetLineFromAddr64(hProcess, s.AddrPC.Offset, &offsetFromLine, &Line) != FALSE)
				{
					GString g(Line.FileName);  // Line.FileName conains the "c:\Full\Path\TO\Source.cpp"
					
					// Builds string "Foo::Bar[Source.cpp]@777"
					strStackName << "[" << g.StartingAt(g.ReverseFind("\\") + 1) << "]@" << Line.LineNumber; 
				}

				// add the GString to the GStringList, do not add frame 0 because it will always be GException::GSeception where we divided by 0
				if (frameNum > 0)
					_stk += strStackName;
			}
		}
		else
		{
			// base reached
			SetLastError(0);
			break;
		}

		++frameNum;
	}
	
	LeaveCriticalSection(&_DbgHelpLock);


	// de-init symbol handler etc. (SymCleanup())
	SymCleanup( hProcess );
	free( pSym );
tagCleanUp:;	
	delete [] tt;
	CloseHandle(hProcess);
}
Example #24
0
void DoStackWalk
    (LPCONTEXT lpContextRecord)

{
    STACKFRAME64         stackFrame = {0};
    CONTEXT              context;
    HANDLE               hProcess,
                         hThread;
////CallstackEntry       csEntry;
////IMAGEHLP_SYMBOL64   *pSym = NULL;
////IMAGEHLP_MODULE64_V2 Module;
////IMAGEHLP_LINE64      Line;
    LPBYTE               caller;            // Ptr to caller in stack trace
    APLU3264             nearAddress,       // Offset from closest address
                         nearIndex,         // Index into StartAddresses
                         nearAddress0,      // Offset from closest address
                         nearIndex0,        // Index into StartAddresses
                         nearAddress1,      // Offset from closest address
                         nearIndex1;        // Index into StartAddresses
    WCHAR                wszTemp[1024];     // Temp output save area
////char                 szAppDPFE[_MAX_PATH],
////                     szDir  [_MAX_DIR],
////                     szDrive[_MAX_DRIVE],
////                     szSymPath[_MAX_PATH];
////PSYMBOL_INFO         lpSymInfo;         // Ptr to ...

    // Initialize the handles
    hProcess = GetCurrentProcess ();
    hThread  = GetCurrentThread ();

////// Allocate space for the symbol name struc
////pSym = (IMAGEHLP_SYMBOL64 *) malloc (sizeof (IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
////if (!pSym)
////    goto CLEANUP;       // Not enough memory...
////memset (pSym, 0, sizeof (IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
////pSym->SizeOfStruct = sizeof (IMAGEHLP_SYMBOL64);
////pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;

////// Allocate space for the symbol info struc
////lpSymInfo = (PSYMBOL_INFO) malloc (sizeof (SYMBOL_INFO) + STACKWALK_MAX_NAMELEN);
////if (lpSymInfo EQ NULL)
////    goto CLEANUP;       // Not enough memory...
////memset (lpSymInfo, 0, sizeof (SYMBOL_INFO) + STACKWALK_MAX_NAMELEN);
////lpSymInfo->SizeOfStruct = sizeof (SYMBOL_INFO);
////lpSymInfo->MaxNameLen   = STACKWALK_MAX_NAMELEN;

////memset (&Line, 0, sizeof (Line));
////Line.SizeOfStruct = sizeof (Line);

////memset (&Module, 0, sizeof (Module));
////Module.SizeOfStruct = sizeof (Module);

////if (GetModuleFileNameA (_hInstance, szAppDPFE, sizeof (szSymPath)))
////{
////    // Split out the drive and path from the module filename
////    _splitpath (szAppDPFE, szDrive, szDir, NULL, NULL);
////
////    // Create the .HLP file name
////    _makepath  (szSymPath, szDrive, szDir, NULL, NULL);
////} else
////    szSymPath[0] = '\0';
////
////// Set the symbol options
////SymSetOptions (SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
////
////// Initialize the symbols
////SymInitialize (hProcess, szSymPath, TRUE);

    // Copy the outer ContextRecord
    context = *lpContextRecord;

    // Initialize these fields before the first call to StackWalk64
#ifdef _WIN64
    stackFrame.AddrPC.Offset     = lpContextRecord->Rip;    // Starting instruction address
    stackFrame.AddrFrame.Offset  = lpContextRecord->Rbp;    // Starting frame address
    stackFrame.AddrStack.Offset  = lpContextRecord->Rsp;    // Starting stack address
#elif defined (_WIN32)
    stackFrame.AddrPC.Offset     = lpContextRecord->Eip;    // Starting instruction address
    stackFrame.AddrFrame.Offset  = lpContextRecord->Ebp;    // Starting frame address
    stackFrame.AddrStack.Offset  = lpContextRecord->Esp;    // Starting stack address
#else
  #error Need code for this architecture.
#endif
    stackFrame.AddrPC.Segment    = 0;                       // Used for 16-bit addressing only
    stackFrame.AddrPC.Mode       = AddrModeFlat;            // Use flat mode addressing
    stackFrame.AddrFrame.Segment = 0;                       // Used for 16-bit addressing only
    stackFrame.AddrFrame.Mode    = AddrModeFlat;            // Use flat mode addressing
    stackFrame.AddrStack.Segment = 0;                       // Used for 16-bit addressing only
    stackFrame.AddrStack.Mode    = AddrModeFlat;            // Use flat mode addressing

    // Walk the stack
    while (StackWalk64 (
#ifdef _WIN64
                        IMAGE_FILE_MACHINE_AMD64,   // Machine architecture type
#elif defined (_WIN32)
                        IMAGE_FILE_MACHINE_I386,    // Machine architecture type
#else
  #error Need code for this architecture.
#endif
                        hProcess,                   // Process handle
                        hThread,                    // Thread handle
                       &stackFrame,                 // Ptr to stack frame (input/output)
                       &context,                    // Ptr to context struc (output)
                        NULL,                       // Ptr to ReadMemoryRoutine (may be NULL)
                       &SymFunctionTableAccess64,   // Ptr to function table access routine
                       &SymGetModuleBase64,         // Ptr to get module base routine
                        NULL))                      // Ptr to translate address routine for 16-bit addresses
    {
        // Check for infinite loop
        if (stackFrame.AddrPC.Offset EQ stackFrame.AddrReturn.Offset)
            break;

        // Check for valid instruction offset
        if (stackFrame.AddrPC.Offset EQ 0)
            break;

////    // Initialize the CallstackEntry struc
////    csEntry.offset             = stackFrame.AddrPC.Offset;
////    csEntry.name[0]            = 0;
////    csEntry.undName[0]         = 0;
////    csEntry.undFullName[0]     = 0;
////    csEntry.offsetFromSmybol   = 0;
////    csEntry.offsetFromLine     = 0;
////    csEntry.lineFileName[0]    = 0;
////    csEntry.lineNumber         = 0;
////    csEntry.loadedImageName[0] = 0;
////    csEntry.moduleName[0]      = 0;

////    DbgBrk ();

////    // Get the symbol name
////    if (SymFromAddr (hProcess, stackFrame.AddrPC.Offset, &csEntry.offsetFromSmybol, lpSymInfo))
////    {
////        DbgBrk ();
////
////
////
////    } // End IF

////    // Get the symbol name
////    if (SymGetSymFromAddr64 (hProcess, stackFrame.AddrPC.Offset, &csEntry.offsetFromSmybol, pSym))
////    {
////        DbgBrk ();
////
////        // Copy to temporary storage
////        strcpy (csEntry.name, pSym->Name);
////
////        // Undecorate the symbol name
////        UnDecorateSymbolName (pSym->Name, csEntry.undName,     STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY);
////        UnDecorateSymbolName (pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE);
////    } // End IF

////    GetLastError ();

        caller = (LPBYTE) stackFrame.AddrPC.Offset;

        // Format the address
        FindRoutineAddress (caller, &nearAddress0, &nearIndex0, FALSE);
        FindRoutineAddress (caller, &nearAddress1, &nearIndex1, TRUE);
        if (nearAddress0 < nearAddress1)
        {
            nearAddress = nearAddress0;
            nearIndex   = nearIndex0;
        } else
        {
            nearAddress = nearAddress1;
            nearIndex   = nearIndex1;
        } // End IF/ELSE

        // If the address is out of bounds, just display the address
        if (nearAddress > 0x00100000)
            // Format the addresses
            MySprintfW (wszTemp,
                        sizeof (wszTemp),
                       L"%p -- EBP = %p",
                        caller,
                        stackFrame.AddrFrame.Offset);
        else
            // Format the addresses
            MySprintfW (wszTemp,
                        sizeof (wszTemp),
                       L"%p (%S + %p) -- EBP = %p",
                        caller,
                        StartAddresses[nearIndex].StartAddressName,
                        nearAddress,
                        stackFrame.AddrFrame.Offset);
#define NewMsg(a)   SendMessageW (hWndCC_LB, LB_ADDSTRING, 0, (LPARAM) (a)); UpdateWindow (hWndCC_LB)
        NewMsg (wszTemp);
#undef  NewMsg
    } // End WHILE
////CLEANUP:
////if (lpSymInfo)
////    free (lpSymInfo);
////if (pSym)
////    free (pSym);
} // End DoStackWalk
Example #25
0
void PrintCallStack(const CONTEXT *pContext)
{
    HANDLE hProcess = GetCurrentProcess();
    SymInitialize(hProcess, NULL, TRUE);
    CONTEXT c = *pContext;

    STACKFRAME64 sf;
    memset(&sf, 0, sizeof(STACKFRAME64));
    DWORD dwImageType = IMAGE_FILE_MACHINE_I386;

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

    HANDLE hThread = GetCurrentThread();

    while (true)
    {
        if (!StackWalk64(dwImageType, hProcess, hThread, &sf, &c, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
            break;

        DWORD64 address = sf.AddrPC.Offset;
        if (address == 0)
            break;
       
        // Get symbol name
        char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)] = {0};
        PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
        pSymbol->MaxNameLen = MAX_SYM_NAME ;
        pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
        SymFromAddr(hProcess, address, NULL, pSymbol);

        // Get module name
        IMAGEHLP_MODULE64 moduleInfo = {0};
        moduleInfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64);
        TCHAR* szModule = _T("");
        // SymGetModuleInfo64 will fail in unicode version
        // http://msdn.microsoft.com/en-us/library/windows/desktop/ms681336(v=vs.85).aspx
        if (SymGetModuleInfo64(hProcess, address, &moduleInfo))
            szModule = moduleInfo.ModuleName;

        // Get file name and line count
        IMAGEHLP_LINE64 lineInfo = {0};
        lineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
        DWORD displacement;
        if (SymGetLineFromAddr64(hProcess, address, &displacement, &lineInfo))
        {
            _tprintf(_T("%016llX %s!%s [%s @ %lu]\n"), pSymbol->Address, szModule, pSymbol->Name, lineInfo.FileName, lineInfo.LineNumber);
        }
        else
        {
            _tprintf(_T("%016llX %s!%s\n"), pSymbol->Address, szModule, pSymbol->Name);
        }
    }

    SymCleanup(hProcess);
}
Example #26
0
void StackDump( LPVOID pMem, DWORD dwBytes)
{
		STACKFRAME64 stStackFrame = {0};
        CONTEXT stContext = {0};
        stContext.ContextFlags = CONTEXT_ALL;    
        __asm    call x
        __asm x: pop eax
        __asm    mov stContext.Eip, eax
        __asm    mov stContext.Ebp, ebp
        __asm    mov stContext.Esp, esp

        stStackFrame.AddrPC.Offset = stContext.Eip;
        stStackFrame.AddrPC.Mode = AddrModeFlat;
        stStackFrame.AddrFrame.Offset = stContext.Ebp;
        stStackFrame.AddrFrame.Mode = AddrModeFlat;
        stStackFrame.AddrStack.Offset = stContext.Esp;
        stStackFrame.AddrStack.Mode = AddrModeFlat;
 
//         BYTE SymBol[ sizeof(SYMBOL_INFO) + STACKWALK_MAX_NAMELEN ] = {0};
// 
//         SYMBOL_INFO* pSymbol = (SYMBOL_INFO*)SymBol;
//         pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
//         pSymbol->MaxNameLen = STACKWALK_MAX_NAMELEN;
// 
//         IMAGEHLP_LINE64 Line = {0};
//         Line.SizeOfStruct = sizeof( IMAGEHLP_LINE64 );
        
        HANDLE hProcess = GetCurrentProcess();
        MEM_INFO stInfo;
        //stInfo.parCallStack = new STACK_ARRAY;
        
		//void * p = AllocMem(sizeof(STACK_ARRAY));
        //stInfo.parCallStack = new( (void*)p ) STACK_ARRAY;
        
        stInfo.nMemSize = dwBytes;
        for( int i =0; i < g_Config::g_StackDepth ; i++ )// only retrieve 40 functions
        {
            BOOL b = StackWalk64( IMAGE_FILE_MACHINE_I386, hProcess, GetCurrentThread(), 
                              &stStackFrame ,&stContext, 0, 
                              SymFunctionTableAccess64 , SymGetModuleBase64, NULL );
            if ( !b )
            {
               break;
            }
            DWORD64 dwDisplacement = 0;
            if (stStackFrame.AddrPC.Offset == stStackFrame.AddrReturn.Offset)
            {
              break;
            }

//////////////////////////////////////////////////////////////////////////
        //if( SymFromAddr( hProcess, stStackFrame.AddrPC.Offset, &dwDisplacement, pSymbol ))
        //{
        //		CString cs = "Ordinal823";
        //	if( cs == pSymbol->Name)
        //		{
        //			break;
        //		}
        //			
        //}
//////////////////////////////////////////////////////////////////////////

            if( i <= 1 )// ignore the functions on the top of stack which is our own.
            {
                continue;
            }
			stInfo.parCallStack.push_back( stStackFrame.AddrPC.Offset );
        }
        g_Config::m_MemMap[pMem] = stInfo;        
}
Example #27
0
void kul_real_se_handler(EXCEPTION_POINTERS* pExceptionInfo){
	const std::string& tid(kul::this_thread::id());
	uint sig = pExceptionInfo->ExceptionRecord->ExceptionCode;
	if(pExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
    	for(auto& f : kul::SignalStatic::INSTANCE().se) f(sig = 11);

    if(!kul::SignalStatic::INSTANCE().q){
	    HANDLE process = GetCurrentProcess();
	    SymInitialize(process, NULL, TRUE);

	    CONTEXT context_record = *pExceptionInfo->ContextRecord;

	    STACKFRAME64 stack_frame;
	    memset(&stack_frame, 0, sizeof(stack_frame));
	    #if defined(_WIN64)
	    int machine_type = IMAGE_FILE_MACHINE_AMD64;
	    stack_frame.AddrPC.Offset = context_record.Rip;
	    stack_frame.AddrFrame.Offset = context_record.Rbp;
	    stack_frame.AddrStack.Offset = context_record.Rsp;
	    #else
	    int machine_type = IMAGE_FILE_MACHINE_I386;
	    stack_frame.AddrPC.Offset = context_record.Eip;
	    stack_frame.AddrFrame.Offset = context_record.Ebp;
	    stack_frame.AddrStack.Offset = context_record.Esp;
	    #endif
	    stack_frame.AddrPC.Mode = AddrModeFlat;
	    stack_frame.AddrFrame.Mode = AddrModeFlat;
	    stack_frame.AddrStack.Mode = AddrModeFlat;

	    SYMBOL_INFO* symbol;
	    symbol               = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 );
	    symbol->MaxNameLen   = 255;
	    symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
	    std::cout << "[bt] Stacktrace:" << std::endl;
	    while (StackWalk64(machine_type,
	        GetCurrentProcess(),
	        GetCurrentThread(),
	        &stack_frame,
	        &context_record,
	        NULL,
	        &SymFunctionTableAccess64,
	        &SymGetModuleBase64,
	        NULL)) {

	        DWORD64 displacement = 0;
	        if (SymFromAddr(process, (DWORD64)stack_frame.AddrPC.Offset, &displacement, symbol)){
	        	DWORD  dwDisplacement;
				IMAGEHLP_LINE64 line;
				IMAGEHLP_MODULE64 moduleInfo;
	            ZeroMemory(&moduleInfo, sizeof(IMAGEHLP_MODULE64));
	            moduleInfo.SizeOfStruct = sizeof(moduleInfo);

	            std::cout << "[bt] ";
	            if (::SymGetModuleInfo64(process, symbol->ModBase, &moduleInfo))
	            	std::cout << moduleInfo.ModuleName << " ";

	            std::cout << symbol->Name << " + [0x" << std::hex << displacement << "]"; 

				if (SymGetLineFromAddr64(process, (DWORD64)stack_frame.AddrPC.Offset, &dwDisplacement, &line))
					std::cout << " - " << line.FileName << ": " << std::to_string(line.LineNumber);
				else
					std::cout << " - ??:";
				std::cout << std::endl;
	        }
	    }
    }
	exit(sig);
}
Example #28
0
static void	print_backtrace(CONTEXT *pctx)
{
	SymGetLineFromAddrW64_func_t	zbx_SymGetLineFromAddrW64 = NULL;
	SymFromAddr_func_t		zbx_SymFromAddr	= NULL;

	CONTEXT			ctx, ctxcount;
	STACKFRAME64		s, scount;
	PSYMBOL_INFO		pSym = NULL;
	HMODULE			hModule;
	HANDLE			hProcess, hThread;
	DWORD64			offset;
	wchar_t			szProcessName[MAX_PATH];
	char			*process_name = NULL, *process_path = NULL, *frame = NULL;
	size_t			frame_alloc = 0, frame_offset;
	int			nframes = 0;

	ctx = *pctx;

	zabbix_log(LOG_LEVEL_CRIT, "=== Backtrace: ===");

	memset(&s, 0, sizeof(s));

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

#ifdef _M_X64
	s.AddrPC.Offset = ctx.Rip;
	s.AddrFrame.Offset = ctx.Rbp;
	s.AddrStack.Offset = ctx.Rsp;
#else
	s.AddrPC.Offset = ctx.Eip;
	s.AddrFrame.Offset = ctx.Ebp;
	s.AddrStack.Offset = ctx.Esp;
#endif
	hProcess = GetCurrentProcess();
	hThread = GetCurrentThread();

	if (0 != GetModuleFileNameEx(hProcess, NULL, szProcessName, ARRSIZE(szProcessName)))
	{
		char	*ptr;
		int	path_alloc = 0, path_offset = 0;

		process_name = zbx_unicode_to_utf8(szProcessName);

		if (NULL != (ptr = strstr(process_name, progname)))
			zbx_strncpy_alloc(&process_path, &path_alloc, &path_offset, process_name, ptr - process_name);
	}

	if (NULL != (hModule = GetModuleHandle(TEXT("DbgHelp.DLL"))))
	{
		zbx_SymGetLineFromAddrW64 = (SymGetLineFromAddrW64_func_t)GetProcAddress(hModule,
				"SymGetLineFromAddr64");
		zbx_SymFromAddr = (SymFromAddr_func_t)GetProcAddress(hModule, "SymFromAddr");
	}

	if (NULL != zbx_SymFromAddr || NULL != zbx_SymGetLineFromAddrW64)
	{
		SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES);

		if (FALSE != SymInitialize(hProcess, process_path, TRUE))
		{
			pSym = (PSYMBOL_INFO) zbx_malloc(NULL, sizeof(SYMBOL_INFO) + MAX_SYM_NAME);
			memset(pSym, 0, sizeof(SYMBOL_INFO) + MAX_SYM_NAME);
			pSym->SizeOfStruct = sizeof(SYMBOL_INFO);
			pSym->MaxNameLen = MAX_SYM_NAME;
		}
	}

	scount = s;
	ctxcount = ctx;

	/* get number of frames, ctxcount may be modified during StackWalk64() calls */
	while (TRUE == StackWalk64(ZBX_IMAGE_FILE_MACHINE, hProcess, hThread, &scount, &ctxcount, NULL, NULL, NULL,
			NULL))
	{
		if (0 == scount.AddrReturn.Offset)
			break;
		nframes++;
	}

	while (TRUE == StackWalk64(ZBX_IMAGE_FILE_MACHINE, hProcess, hThread, &s, &ctx, NULL, NULL, NULL, NULL))
	{
		frame_offset = 0;
		zbx_snprintf_alloc(&frame, &frame_alloc, &frame_offset, "%d: %s", nframes--,
				NULL == process_name ? "(unknown)" : process_name);

		if (NULL != pSym)
		{
			DWORD		dwDisplacement;
			IMAGEHLP_LINE64	line = {sizeof(IMAGEHLP_LINE64)};

			zbx_chrcpy_alloc(&frame, &frame_alloc, &frame_offset, '(');
			if (NULL != zbx_SymFromAddr &&
					TRUE == zbx_SymFromAddr(hProcess, s.AddrPC.Offset, &offset, pSym))
			{
				zbx_snprintf_alloc(&frame, &frame_alloc, &frame_offset, "%s+0x%lx", pSym->Name, offset);
			}

			if (NULL != zbx_SymGetLineFromAddrW64 && TRUE == zbx_SymGetLineFromAddrW64(hProcess,
					s.AddrPC.Offset, &dwDisplacement, &line))
			{
				zbx_snprintf_alloc(&frame, &frame_alloc, &frame_offset, " %s:%d", line.FileName,
						line.LineNumber);
			}
			zbx_chrcpy_alloc(&frame, &frame_alloc, &frame_offset, ')');
		}

		zabbix_log(LOG_LEVEL_CRIT, "%s [0x%lx]", frame, s.AddrPC.Offset);

		if (0 == s.AddrReturn.Offset)
			break;
	}

	SymCleanup(hProcess);

	zbx_free(frame);
	zbx_free(process_path);
	zbx_free(process_name);
	zbx_free(pSym);
}
Example #29
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);
}
Example #30
0
void stackgetcallstack(duint csp, std::vector<CALLSTACKENTRY> & callstackVector, bool cache)
{
    if(cache)
    {
        SHARED_ACQUIRE(LockCallstackCache);
        auto found = CallstackCache.find(csp);
        if(found != CallstackCache.end())
        {
            callstackVector = found->second;
            return;
        }
        callstackVector.clear();
        return;
    }

    // Gather context data
    CONTEXT context;
    memset(&context, 0, sizeof(CONTEXT));

    context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;

    if(SuspendThread(hActiveThread) == -1)
        return;

    if(!GetThreadContext(hActiveThread, &context))
        return;

    if(ResumeThread(hActiveThread) == -1)
        return;

    // Set up all frame data
    STACKFRAME64 frame;
    ZeroMemory(&frame, sizeof(STACKFRAME64));

#ifdef _M_IX86
    DWORD machineType = IMAGE_FILE_MACHINE_I386;
    frame.AddrPC.Offset = context.Eip;
    frame.AddrPC.Mode = AddrModeFlat;
    frame.AddrFrame.Offset = context.Ebp;
    frame.AddrFrame.Mode = AddrModeFlat;
    frame.AddrStack.Offset = csp;
    frame.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
    DWORD machineType = IMAGE_FILE_MACHINE_AMD64;
    frame.AddrPC.Offset = context.Rip;
    frame.AddrPC.Mode = AddrModeFlat;
    frame.AddrFrame.Offset = context.Rsp;
    frame.AddrFrame.Mode = AddrModeFlat;
    frame.AddrStack.Offset = csp;
    frame.AddrStack.Mode = AddrModeFlat;
#endif

    const int MaxWalks = 50;
    // Container for each callstack entry (50 pre-allocated entries)
    callstackVector.clear();
    callstackVector.reserve(MaxWalks);

    for(auto i = 0; i < MaxWalks; i++)
    {
        if(!StackWalk64(
                    machineType,
                    fdProcessInfo->hProcess,
                    hActiveThread,
                    &frame,
                    &context,
                    StackReadProcessMemoryProc64,
                    SymFunctionTableAccess64,
                    StackGetModuleBaseProc64,
                    StackTranslateAddressProc64))
        {
            // Maybe it failed, maybe we have finished walking the stack
            break;
        }

        if(frame.AddrPC.Offset != 0)
        {
            // Valid frame
            CALLSTACKENTRY entry;
            memset(&entry, 0, sizeof(CALLSTACKENTRY));

            StackEntryFromFrame(&entry, (duint)frame.AddrFrame.Offset + sizeof(duint), (duint)frame.AddrPC.Offset, (duint)frame.AddrReturn.Offset);
            callstackVector.push_back(entry);
        }
        else
        {
            // Base reached
            break;
        }
    }

    EXCLUSIVE_ACQUIRE(LockCallstackCache);
    if(CallstackCache.size() > MAX_CALLSTACK_CACHE)
        CallstackCache.clear();
    CallstackCache[csp] = callstackVector;
}