#pragma once
#include
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
#include
#pragma warning(push)
#pragma warning(disable : 4091)
#include
#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 << "\\r\\n";
if (itc != m\_mapCodeDesc.end())
{
m\_ostringstream << "Exception: " << itc->second << "\\r\\n";
}
// m\_ostringstream << "------------------------------------------------------------------\\r\\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 << " ";
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 << "\\r\\n";
}
return m\_ostringstream.str();
}
DWORD StackTracer::GetExceptionCode()
{
return m_dwExceptionCode;
}
std::vector
{
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);
}
}
参考并优化自:https://www.codeproject.com/Articles/41923/Get-the-call-stack-when-an-exception-is-being-caug
手机扫一扫
移动阅读更方便
你可能感兴趣的文章