C++从LPEXCEPTION_POINTERS获取调用堆栈
#pragma once #include <map>
#include <vector> 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 << "\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<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);
}
}
参考并优化自:https://www.codeproject.com/Articles/41923/Get-the-call-stack-when-an-exception-is-being-caug
C++从LPEXCEPTION_POINTERS获取调用堆栈的更多相关文章
- C/C++中手动获取调用堆栈【转】
转自:http://blog.csdn.net/kevinlynx/article/details/39269507 版权声明:本文为博主原创文章,未经博主允许不得转载. 当我们的程序core掉之后, ...
- delphi中获取调用堆栈信息
异常堆栈有利于分析程序的错误,Delphi的Exception有StackTrace属性,但是值为空,因为StackTrace的信息收集Delphi委托给了第三方组件来完成,真是脑子有毛病! 借助于m ...
- VC++ 崩溃处理以及打印调用堆栈
title: VC++ 崩溃处理以及打印调用堆栈 tags: [VC++, 结构化异常处理, 崩溃日志记录] date: 2018-08-28 20:59:54 categories: windows ...
- C#获取当前堆栈的各调用方法列表
在使用.NET编写的代码在debug时很容易进行排查和定位问题,一旦项目上线并出现问题的话那么只能依靠系统日志来进行问题排查和定位,但当项目复杂时,即各种方法间相互调用将导致要获取具体的出错方法或调用 ...
- c# 如何获取当前方法的调用堆栈
c# 调试程序时常常需要借助 call stack 查看调用堆栈,实际上通过code也可以获取: class Program { static void Main(string[] args) { T ...
- 在 Visual Studio 中调试时映射调用堆栈上的方法
本文转自:https://msdn.microsoft.com/zh-cn/library/dn194476.aspx 1.创建代码图,以便在调试时对调用堆栈进行可视化跟踪. 你可以在图中进行标注以跟 ...
- .NET 中获取调用方法名
在写记录日志功能时,需要记录日志调用方所在的模块名.命名空间名.类名以及方法名,想到使用的是反射(涉及到反射请注意性能),但具体是哪一块儿还不了解,于是搜索,整理如下: 需要添加相应的命名空间: us ...
- Windbg查看调用堆栈(k*)
无论是分析程序崩溃原因,还是解决程序hang问题,我们最常查看的就是程序调用堆栈.学会windbg调用堆栈命令,以及理解堆栈中的各个参数的意义就显得至关重要. 上图就是一个典型的Win ...
- 怎样重建一个损坏的调用堆栈(callstack)
原文作者:Aaron Ballman原文时间:2011年07月04日原文地址:http://blog.aaronballman.com/2011/07/reconstructing-a-corrupt ...
随机推荐
- 还分不清 Cookie、Session、Token、JWT?一篇文章讲清楚
还分不清 Cookie.Session.Token.JWT?一篇文章讲清楚 转载来源 公众号:前端加加 作者:秋天不落叶 什么是认证(Authentication) 通俗地讲就是验证当前用户的身份,证 ...
- 【NOI2001】方程的解数 题解(dfs+哈希)
题目描述 已知一个方程 k1*x1^p1+k2*x2^p2……+kn*xn^pn=0. 求解的个数.其中1<=x<=150,1<=p<=6; 答案在int范围内 输入格式 第一 ...
- Java项目中经常遇到的一些异常情况
一. 1. java.lang.nullpointerexception 这个异常大家肯定都经常遇到,异常的解释是"程序遇上了空指针",简单地说就是调用了未经初始化的对象或者是不存 ...
- MinIO很强-让我放弃FastDFS拥抱MinIO的8个理由
目前可用于文件存储的网络服务选择有很多,比如阿里云OSS.七牛云.腾讯云等等,但是收费都有点小贵.为了帮公司节约成本,之前一直是使用fastDFS作为文件服务器,准确的说是图片服务器.直到我发现了Mi ...
- 将vscode打造成强大的C/C++ IDE
一.安装 你可以直接从微软官网下载,如果你想要一个纯净的vscode(微软官方的有一项商标.一个插件库.一个 C# 调试器以及遥测),可以手动编译https://github.com/microsof ...
- 【API进阶之路】无法想象!大龄码农的硬盘里有这么多宝藏
摘要:通过把所需建立的工具库做成云容器化应用,用CCE引擎,通过API网关调用云容器引擎中的容器应用.不仅顺应了云原生的发展趋势,还能随时弹性扩容,满足公司规模化发展的需求. 公司开完年中会后,大家的 ...
- js、jQuery、ajax面试题
1.javascript的typeof返回哪些数据类型. 答案:string,boolean,number,undefined,function,object 2.例举3种强制类型转换和2种隐式类型转 ...
- 了解JS压缩图片,这一篇就够了
前言 公司的移动端业务需要在用户上传图片是由前端压缩图片大小,再上传到服务器,这样可以减少移动端上行流量,减少用户上传等待时长,优化用户体验. 插播一下,本文案例已整理成插件,已上传npm ,可通过 ...
- jqgrid 自定义文本框、选择框等查询
要实现jqgrid的自定义查询可通过表格获取查询的条件,再给jqgrid表格发送postData参数. HTML: <table id="querytable" border ...
- Gitlab-CI/CD 1
Gitlab-Runner自动构建服务器搭建1 这里讲到的gitlab仓库指的是https://gitlab.com/,自建gitlab仓库也基本相同. 项目的构建打包过程相对比较消耗系统性能,所以g ...