https://github.com/junligong/WinCrashHandler.git
1、创建MiniDump
2、获取到dump信息![](https://img-blog.csdnimg.cn/43f3aedc984f4c09824daf4e5be1ae6f.png)
3、自定义完成(上报功能,需要自定义完成)
4、相关流程
stepA:注册崩溃handlers
void main()
{
WinCrashHandler ch;
ch.SetProcessExceptionHandlers();
ch.SetThreadExceptionHandlers();
.............
}
stepB:崩溃Handlers实现
#pragma once
#include "stdafx.h"
class WinCrashHandler
{
public:
// Constructor
WinCrashHandler();
// Destructor
virtual ~WinCrashHandler();
// Sets exception handlers that work on per-process basis
void SetProcessExceptionHandlers();
// Installs C++ exception handlers that function on per-thread basis
void SetThreadExceptionHandlers();
// Collects current process state.
static void GetExceptionPointers(
DWORD dwExceptionCode,
EXCEPTION_POINTERS** pExceptionPointers);
// This method creates minidump of the process
static void CreateMiniDump(EXCEPTION_POINTERS* pExcPtrs);
/* Exception handler functions. */
static LONG WINAPI SehHandler(PEXCEPTION_POINTERS pExceptionPtrs);
static void __cdecl TerminateHandler();
static void __cdecl UnexpectedHandler();
static void __cdecl PureCallHandler();
static void __cdecl InvalidParameterHandler(const wchar_t* expression,
const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved);
static int __cdecl NewHandler(size_t);
static void SigabrtHandler(int);
static void SigfpeHandler(int /*code*/, int subcode);
static void SigintHandler(int);
static void SigillHandler(int);
static void SigsegvHandler(int);
static void SigtermHandler(int);
};
#include "stdafx.h"
#include "WinCrashHandler.h"
#include "StackTracer.h"
#ifndef _AddressOfReturnAddress
// Taken from: http://msdn.microsoft.com/en-us/library/s975zw7k(VS.71).aspx
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
// _ReturnAddress and _AddressOfReturnAddress should be prototyped before use
EXTERNC void * _AddressOfReturnAddress(void);
EXTERNC void * _ReturnAddress(void);
#endif
WinCrashHandler::WinCrashHandler()
{
}
WinCrashHandler::~WinCrashHandler()
{
}
void WinCrashHandler::SetProcessExceptionHandlers()
{
// Install top-level SEH handler
SetUnhandledExceptionFilter(SehHandler);
// Catch pure virtual function calls.
// Because there is one _purecall_handler for the whole process,
// calling this function immediately impacts all threads. The last
// caller on any thread sets the handler.
// http://msdn.microsoft.com/en-us/library/t296ys27.aspx
_set_purecall_handler(PureCallHandler);
// Catch new operator memory allocation exceptions
_set_new_handler(NewHandler);
// Catch invalid parameter exceptions.
_set_invalid_parameter_handler(InvalidParameterHandler);
// Set up C++ signal handlers
_set_abort_behavior(_CALL_REPORTFAULT, _CALL_REPORTFAULT);
// Catch an abnormal program termination
signal(SIGABRT, SigabrtHandler);
// Catch illegal instruction handler
signal(SIGINT, SigintHandler);
// Catch a termination request
signal(SIGTERM, SigtermHandler);
}
void WinCrashHandler::SetThreadExceptionHandlers()
{
// Catch terminate() calls.
// In a multithreaded environment, terminate functions are maintained
// separately for each thread. Each new thread needs to install its own
// terminate function. Thus, each thread is in charge of its own termination handling.
// http://msdn.microsoft.com/en-us/library/t6fk7h29.aspx
set_terminate(TerminateHandler);
// Catch unexpected() calls.
// In a multithreaded environment, unexpected functions are maintained
// separately for each thread. Each new thread needs to install its own
// unexpected function. Thus, each thread is in charge of its own unexpected handling.
// http://msdn.microsoft.com/en-us/library/h46t5b69.aspx
set_unexpected(UnexpectedHandler);
// Catch a floating point error
typedef void (*sigh)(int);
signal(SIGFPE, (sigh)SigfpeHandler);
// Catch an illegal instruction
signal(SIGILL, SigillHandler);
// Catch illegal storage access errors
signal(SIGSEGV, SigsegvHandler);
}
// The following code gets exception pointers using a workaround found in CRT code.
void WinCrashHandler::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;
}
// This method creates minidump of the process
void WinCrashHandler::CreateMiniDump(EXCEPTION_POINTERS* pExcPtrs)
{
std::string str_msg = StackTracer::GetExceptionStackTrace(pExcPtrs);
HMODULE hDbgHelp = NULL;
HANDLE hFile = NULL;
MINIDUMP_EXCEPTION_INFORMATION mei;
MINIDUMP_CALLBACK_INFORMATION mci;
// Load dbghelp.dll
hDbgHelp = LoadLibrary(_T("dbghelp.dll"));
if(hDbgHelp==NULL)
{
// Error - couldn't load dbghelp.dll
return;
}
// Create the minidump file
hFile = CreateFile(
_T("crashdump.dmp"),
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if(hFile==INVALID_HANDLE_VALUE)
{
// Couldn't create file
return;
}
// Write minidump to the file
mei.ThreadId = GetCurrentThreadId();
mei.ExceptionPointers = pExcPtrs;
mei.ClientPointers = FALSE;
mci.CallbackRoutine = NULL;
mci.CallbackParam = NULL;
typedef BOOL (WINAPI *LPMINIDUMPWRITEDUMP)(
HANDLE hProcess,
DWORD ProcessId,
HANDLE hFile,
MINIDUMP_TYPE DumpType,
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
CONST PMINIDUMP_USER_STREAM_INFORMATION UserEncoderParam,
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
LPMINIDUMPWRITEDUMP pfnMiniDumpWriteDump =
(LPMINIDUMPWRITEDUMP)GetProcAddress(hDbgHelp, "MiniDumpWriteDump");
if(!pfnMiniDumpWriteDump)
{
// Bad MiniDumpWriteDump function
return;
}
HANDLE hProcess = GetCurrentProcess();
DWORD dwProcessId = GetCurrentProcessId();
BOOL bWriteDump = pfnMiniDumpWriteDump(
hProcess,
dwProcessId,
hFile,
MiniDumpNormal,
&mei,
NULL,
&mci);
if(!bWriteDump)
{
// Error writing dump.
return;
}
// Close file
CloseHandle(hFile);
// Unload dbghelp.dll
FreeLibrary(hDbgHelp);
}
// Structured exception handler
LONG WINAPI WinCrashHandler::SehHandler(PEXCEPTION_POINTERS pExceptionPtrs)
{
// Write minidump file
CreateMiniDump(pExceptionPtrs);
// Terminate process
TerminateProcess(GetCurrentProcess(), 1);
// Unreacheable code
return EXCEPTION_EXECUTE_HANDLER;
}
// CRT terminate() call handler
void __cdecl WinCrashHandler::TerminateHandler()
{
// Abnormal program termination (terminate() function was called)
// Retrieve exception information
EXCEPTION_POINTERS* pExceptionPtrs = NULL;
GetExceptionPointers(0, &pExceptionPtrs);
// Write minidump file
CreateMiniDump(pExceptionPtrs);
// Terminate process
TerminateProcess(GetCurrentProcess(), 1);
}
// CRT unexpected() call handler
void __cdecl WinCrashHandler::UnexpectedHandler()
{
// Unexpected error (unexpected() function was called)
// Retrieve exception information
EXCEPTION_POINTERS* pExceptionPtrs = NULL;
GetExceptionPointers(0, &pExceptionPtrs);
// Write minidump file
CreateMiniDump(pExceptionPtrs);
// Terminate process
TerminateProcess(GetCurrentProcess(), 1);
}
// CRT Pure virtual method call handler
void __cdecl WinCrashHandler::PureCallHandler()
{
// Pure virtual function call
// Retrieve exception information
EXCEPTION_POINTERS* pExceptionPtrs = NULL;
GetExceptionPointers(0, &pExceptionPtrs);
// Write minidump file
CreateMiniDump(pExceptionPtrs);
// Terminate process
TerminateProcess(GetCurrentProcess(), 1);
}
// CRT invalid parameter handler
void __cdecl WinCrashHandler::InvalidParameterHandler(
const wchar_t* expression,
const wchar_t* function,
const wchar_t* file,
unsigned int line,
uintptr_t pReserved)
{
pReserved;
// Invalid parameter exception
// Retrieve exception information
EXCEPTION_POINTERS* pExceptionPtrs = NULL;
GetExceptionPointers(0, &pExceptionPtrs);
// Write minidump file
CreateMiniDump(pExceptionPtrs);
// Terminate process
TerminateProcess(GetCurrentProcess(), 1);
}
// CRT new operator fault handler
int __cdecl WinCrashHandler::NewHandler(size_t)
{
// 'new' operator memory allocation exception
// Retrieve exception information
EXCEPTION_POINTERS* pExceptionPtrs = NULL;
GetExceptionPointers(0, &pExceptionPtrs);
// Write minidump file
CreateMiniDump(pExceptionPtrs);
// Terminate process
TerminateProcess(GetCurrentProcess(), 1);
// Unreacheable code
return 0;
}
// CRT SIGABRT signal handler
void WinCrashHandler::SigabrtHandler(int)
{
// Caught SIGABRT C++ signal
// Retrieve exception information
EXCEPTION_POINTERS* pExceptionPtrs = NULL;
GetExceptionPointers(0, &pExceptionPtrs);
// Write minidump file
CreateMiniDump(pExceptionPtrs);
// Terminate process
TerminateProcess(GetCurrentProcess(), 1);
}
// CRT SIGFPE signal handler
void WinCrashHandler::SigfpeHandler(int /*code*/, int subcode)
{
// Floating point exception (SIGFPE)
EXCEPTION_POINTERS* pExceptionPtrs = (PEXCEPTION_POINTERS)_pxcptinfoptrs;
// Write minidump file
CreateMiniDump(pExceptionPtrs);
// Terminate process
TerminateProcess(GetCurrentProcess(), 1);
}
// CRT sigill signal handler
void WinCrashHandler::SigillHandler(int)
{
// Illegal instruction (SIGILL)
// Retrieve exception information
EXCEPTION_POINTERS* pExceptionPtrs = NULL;
GetExceptionPointers(0, &pExceptionPtrs);
// Write minidump file
CreateMiniDump(pExceptionPtrs);
// Terminate process
TerminateProcess(GetCurrentProcess(), 1);
}
// CRT sigint signal handler
void WinCrashHandler::SigintHandler(int)
{
// Interruption (SIGINT)
// Retrieve exception information
EXCEPTION_POINTERS* pExceptionPtrs = NULL;
GetExceptionPointers(0, &pExceptionPtrs);
// Write minidump file
CreateMiniDump(pExceptionPtrs);
// Terminate process
TerminateProcess(GetCurrentProcess(), 1);
}
// CRT SIGSEGV signal handler
void WinCrashHandler::SigsegvHandler(int)
{
// Invalid storage access (SIGSEGV)
PEXCEPTION_POINTERS pExceptionPtrs = (PEXCEPTION_POINTERS)_pxcptinfoptrs;
// Write minidump file
CreateMiniDump(pExceptionPtrs);
// Terminate process
TerminateProcess(GetCurrentProcess(), 1);
}
// CRT SIGTERM signal handler
void WinCrashHandler::SigtermHandler(int)
{
// Termination request (SIGTERM)
// Retrieve exception information
EXCEPTION_POINTERS* pExceptionPtrs = NULL;
GetExceptionPointers(0, &pExceptionPtrs);
// Write minidump file
CreateMiniDump(pExceptionPtrs);
// Terminate process
TerminateProcess(GetCurrentProcess(), 1);
}
stepC:注册信息转字符串
#pragma once
#include <map>
#include <vector>
#include <sstream>
#include <tchar.h>
#include "windows.h"
struct FunctionCall
{
DWORD64 Address;
std::string ModuleName;
std::string FunctionName;
std::string FileName;
int LineNumber;
public:
FunctionCall() :
Address(0),
ModuleName(""),
FunctionName(""),
FileName(""),
LineNumber(0)
{
}
public:
static std::string GetFileName(const std::string& fullpath)
{
size_t index = fullpath.find_last_of('\\');
if (index == std::string::npos)
{
return fullpath;
}
return fullpath.substr(index + 1);
}
};
class StackTracer
{
public:
static std::string GetExceptionStackTrace(LPEXCEPTION_POINTERS e);
private:
// Always return EXCEPTION_EXECUTE_HANDLER after getting the call stack
LONG ExceptionFilter(LPEXCEPTION_POINTERS e);
// return the exception message along with call stacks
std::string GetExceptionMsg();
// Return exception code and call stack data structure so that
// user could customize their own message format
DWORD GetExceptionCode();
std::vector<FunctionCall> GetExceptionCallStack();
private:
StackTracer(void);
~StackTracer(void);
// The main function to handle exception
LONG __stdcall HandleException(LPEXCEPTION_POINTERS e);
// Work through the stack upwards to get the entire call stack
void TraceCallStack(CONTEXT* pContext);
private:
DWORD m_dwExceptionCode;
std::vector<FunctionCall> m_vecCallStack;
typedef std::map<DWORD, const char*> CodeDescMap;
CodeDescMap m_mapCodeDesc;
DWORD m_dwMachineType; // Machine type matters when trace the call stack (StackWalk64)
};
#include "stdafx.h"
#include "StackTracer.h"
#include <sstream>
#include <tchar.h>
#pragma warning(push)
#pragma warning(disable : 4091)
#include <DbgHelp.h>
#pragma warning(pop)
#pragma comment(lib, "Dbghelp.lib")
const int CALLSTACK_DEPTH = 24;
// Translate exception code to description
#define CODE_DESCR(code) CodeDescMap::value_type(code, #code)
StackTracer::StackTracer(void)
:m_dwExceptionCode(0)
{
// Get machine type
m_dwMachineType = 0;
size_t Count = 256;
TCHAR wszProcessor[256] = { 0 };
::_tgetenv_s(&Count, wszProcessor, _T("PROCESSOR_ARCHITECTURE"));
if (wszProcessor)
{
if ((!wcscmp(_T("EM64T"), wszProcessor)) || !wcscmp(_T("AMD64"), wszProcessor))
{
m_dwMachineType = IMAGE_FILE_MACHINE_AMD64;
}
else if (!wcscmp(_T("x86"), wszProcessor))
{
m_dwMachineType = IMAGE_FILE_MACHINE_I386;
}
}
// Exception code description
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_ACCESS_VIOLATION));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_DATATYPE_MISALIGNMENT));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_BREAKPOINT));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_SINGLE_STEP));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_ARRAY_BOUNDS_EXCEEDED));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_FLT_DENORMAL_OPERAND));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_FLT_DIVIDE_BY_ZERO));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_FLT_INEXACT_RESULT));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_FLT_INVALID_OPERATION));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_FLT_OVERFLOW));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_FLT_STACK_CHECK));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_FLT_UNDERFLOW));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_INT_DIVIDE_BY_ZERO));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_INT_OVERFLOW));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_PRIV_INSTRUCTION));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_IN_PAGE_ERROR));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_ILLEGAL_INSTRUCTION));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_NONCONTINUABLE_EXCEPTION));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_STACK_OVERFLOW));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_INVALID_DISPOSITION));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_GUARD_PAGE));
m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_INVALID_HANDLE));
//m_mapCodeDesc.insert(CODE_DESCR(EXCEPTION_POSSIBLE_DEADLOCK));
// Any other exception code???
}
StackTracer::~StackTracer(void)
{
}
std::string StackTracer::GetExceptionStackTrace(LPEXCEPTION_POINTERS e)
{
StackTracer tracer;
tracer.HandleException(e);
return tracer.GetExceptionMsg();
}
LONG StackTracer::ExceptionFilter(LPEXCEPTION_POINTERS e)
{
return HandleException(e);
}
std::string StackTracer::GetExceptionMsg()
{
std::ostringstream m_ostringstream;
// Exception Code
CodeDescMap::iterator itc = m_mapCodeDesc.find(m_dwExceptionCode);
char Code[72];
sprintf_s(Code, "0x%x", m_dwExceptionCode);
m_ostringstream << "Exception Code: " << Code << "\n";
if (itc != m_mapCodeDesc.end())
{
m_ostringstream << "Exception: " << itc->second << "\n";
}
// Call Stack
std::vector<FunctionCall>::iterator itbegin = m_vecCallStack.begin();
std::vector<FunctionCall>::iterator itend = m_vecCallStack.end();
std::vector<FunctionCall>::iterator it;
for (it = itbegin; it < itend; it++)
{
std::string strModule = it->ModuleName.empty() ? "UnknownModule" : it->ModuleName;
m_ostringstream << strModule << "\n";
char Addrs[128];
sprintf_s(Addrs, "0x%llx", it->Address);
m_ostringstream << Addrs;
if (!it->FunctionName.empty())
{
m_ostringstream << " " << it->FunctionName;
}
if (!it->FileName.empty())
{
m_ostringstream << " " << it->FileName << "[" << it->LineNumber << "]";
}
m_ostringstream << " ";
}
return m_ostringstream.str();
}
DWORD StackTracer::GetExceptionCode()
{
return m_dwExceptionCode;
}
std::vector<FunctionCall> StackTracer::GetExceptionCallStack()
{
return m_vecCallStack;
}
LONG __stdcall StackTracer::HandleException(LPEXCEPTION_POINTERS e)
{
m_dwExceptionCode = e->ExceptionRecord->ExceptionCode;
m_vecCallStack.clear();
HANDLE hProcess = INVALID_HANDLE_VALUE;
// Initializes the symbol handler
if (!SymInitialize(GetCurrentProcess(), NULL, TRUE))
{
SymCleanup(hProcess);
return EXCEPTION_EXECUTE_HANDLER;
}
// Work through the call stack upwards.
TraceCallStack(e->ContextRecord);
// ...
SymCleanup(hProcess);
return(EXCEPTION_EXECUTE_HANDLER);
}
// Work through the stack to get the entire call stack
void StackTracer::TraceCallStack(CONTEXT* pContext)
{
// Initialize stack frame
STACKFRAME64 sf;
memset(&sf, 0, sizeof(STACKFRAME));
#if defined(_WIN64)
sf.AddrPC.Offset = pContext->Rip;
sf.AddrStack.Offset = pContext->Rsp;
sf.AddrFrame.Offset = pContext->Rbp;
#elif defined(WIN32)
sf.AddrPC.Offset = pContext->Eip;
sf.AddrStack.Offset = pContext->Esp;
sf.AddrFrame.Offset = pContext->Ebp;
#endif
sf.AddrPC.Mode = AddrModeFlat;
sf.AddrStack.Mode = AddrModeFlat;
sf.AddrFrame.Mode = AddrModeFlat;
if (0 == m_dwMachineType)
return;
// Walk through the stack frames.
HANDLE hProcess = GetCurrentProcess();
HANDLE hThread = GetCurrentThread();
while (StackWalk64(m_dwMachineType, hProcess, hThread, &sf, pContext, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0))
{
if (sf.AddrFrame.Offset == 0 || m_vecCallStack.size() >= CALLSTACK_DEPTH)
break;
// 1. Get function name at the address
const int nBuffSize = (sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64);
ULONG64 symbolBuffer[nBuffSize];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
FunctionCall curCall;
curCall.Address = sf.AddrPC.Offset;
DWORD64 moduleBase = SymGetModuleBase64(hProcess, sf.AddrPC.Offset);
char ModuleName[MAX_PATH];
if (moduleBase && GetModuleFileNameA((HINSTANCE)moduleBase, ModuleName, MAX_PATH))
{
curCall.ModuleName = FunctionCall::GetFileName(ModuleName);
}
DWORD64 dwSymDisplacement = 0;
if (SymFromAddr(hProcess, sf.AddrPC.Offset, &dwSymDisplacement, pSymbol))
{
curCall.FunctionName = std::string(pSymbol->Name);
}
//2. get line and file name at the address
IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE64) };
DWORD dwLineDisplacement = 0;
if (SymGetLineFromAddr64(hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo))
{
curCall.FileName = FunctionCall::GetFileName(std::string(lineInfo.FileName));
curCall.LineNumber = lineInfo.LineNumber;
}
// Call stack stored
m_vecCallStack.push_back(curCall);
}
}