大鼻子的椅子 · 使用剪贴板 - Win32 apps | ...· 1 周前 · |
大气的饼干 · mx350能吃鸡吗 - 百度· 2 月前 · |
小胡子的石榴 · 烟台经济技术开发区 工作动态 ...· 2 月前 · |
旅行中的蛋挞 · 司法行政(法律服务)案例库· 1 年前 · |
跑龙套的土豆 · 魁拔杂谈 周末了,给大家推荐个动漫,名字叫魁 ...· 1 年前 · |
还单身的弓箭 · Python爬虫:调用百度翻译接口实现中英翻 ...· 1 年前 · |
我使用以下代码在异常上遍历堆栈( 注意:必须发布时运行它,以便正确地将堆栈跟踪的所需输出接收到控制台,而不是在调试模式下,否则它只会显示弹出式):
#include "stdafx.h"
#include <process.h>
#include <iostream>
#include <Windows.h>
#include "dbghelp.h"
using namespace std;
#define TRACE_MAX_FUNCTION_NAME_LENGTH 1024
#define TRACE_LOG_ERRORS FALSE
#define TRACE_DUMP_NAME L"Exception.dmp"
void function2()
int a = 0;
int b = 0;
throw new exception;
void function1()
int a = 0;
function2();
void function0()
function1();
static void threadFunction(void *param)
function0();
LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS exception)
CONTEXT context = *(exception->ContextRecord);
HANDLE thread = GetCurrentThread();
HANDLE process = GetCurrentProcess();
STACKFRAME64 frame;
memset(&frame, 0, sizeof(STACKFRAME64));
DWORD image;
#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.Rbp;
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
#error "This platform is not supported."
#endif
SYMBOL_INFO *symbol = (SYMBOL_INFO *)malloc(sizeof(SYMBOL_INFO)+(TRACE_MAX_FUNCTION_NAME_LENGTH - 1) * sizeof(TCHAR));
symbol->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64 *)malloc(sizeof(IMAGEHLP_LINE64));
line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
DWORD displacement;
SymInitialize(process, NULL, TRUE);
while (StackWalk(image, process, thread, &frame, &context, NULL, NULL, NULL, NULL))
if (SymFromAddr(process, frame.AddrPC.Offset, NULL, symbol))
if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &displacement, line))
printf("\tat %s in %s: line: %lu: address: 0x%0X\n", symbol->Name, line->FileName, line->LineNumber, symbol->Address);
else if (TRACE_LOG_ERRORS)
printf("Error from SymGetLineFromAddr64: %lu.\n", GetLastError());
else if (TRACE_LOG_ERRORS)
printf("Error from SymFromAddr: %lu.\n", GetLastError());
DWORD error = GetLastError();
if (error && TRACE_LOG_ERRORS)
printf("Error from StackWalk64: %lu.\n", error);
HANDLE dumpFile = CreateFile(TRACE_DUMP_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
MINIDUMP_EXCEPTION_INFORMATION exceptionInformation;
exceptionInformation.ThreadId = GetCurrentThreadId();
exceptionInformation.ExceptionPointers = exception;
exceptionInformation.ClientPointers = FALSE;
if (MiniDumpWriteDump(process, GetProcessId(process), dumpFile, MiniDumpNormal, exception ? &exceptionInformation : NULL, NULL, NULL))
printf("Wrote a dump.");
return EXCEPTION_CONTINUE_SEARCH;
int _tmain(int argc, _TCHAR* argv[])
SetUnhandledExceptionFilter(UnhandledExceptionFilter);
_beginthread(threadFunction, 0, NULL);
printf("Press any key to exit.\n");
cin.get();
return 0;
}
输出:
Press any key to exit.
at threadFunction in c:\users\<youruseraccount>\documents\visual studio 2013\project
s\stacktracing\stacktracing\stacktracing.cpp: line: 135: address: 0x498B12D0
Wrote a dump.
问题是,上面的跟踪只包含
line: 135
,它对应于对
threadFunction
中的
function0();
的调用。但是,作为堆栈跟踪的一部分,我希望它包括
line: 29
,它在其中执行
throw new exception;
。为什么它不把它作为堆栈跟踪的一部分呢?我如何使它也包括堆栈跟踪的这一部分?
FatalExceptionFilter
,但这是不好的,因为它有自己的警告,因为它必须在任何地方使用,我想要一个顶级的解决方案。我想捕捉所有顶级异常,我想知道它们到底是在哪里抛出的。
这个代码是在Windows 8.1 64位计算机上运行的。它是一个在发布版build/platform x64下编译的MSVC++控制台应用程序。
Update:我已经使用_set_se_translator方法和Petr的建议尝试了以下内容,但是它似乎仍然不想工作。实际上,零异常的除法被抛出时不被处理,没有什么处理它:
#include "stdafx.h"
#include <process.h>
#include <iostream>
#include <Windows.h>
#include "dbghelp.h"
using namespace std;
#define TRACE_MAX_FUNCTION_NAME_LENGTH 1024
#define TRACE_LOG_ERRORS FALSE
#define TRACE_DUMP_NAME L"Exception.dmp"
void function2()
int a = 0;
int b = 0;
// The loop below should throw an unhandled exception.
for (int *i = 0; *i < 100; i++)
*i = 10000;
void function1()
int a = 0;
function2();
void function0()
function1();
void ShowStackTrace(EXCEPTION_POINTERS* exception)
CONTEXT context = *(exception->ContextRecord);
HANDLE thread = GetCurrentThread();
HANDLE process = GetCurrentProcess();
STACKFRAME64 frame;
memset(&frame, 0, sizeof(STACKFRAME64));
DWORD image;
#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.Rbp;
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
#error "This platform is not supported."
#endif
SYMBOL_INFO *symbol = (SYMBOL_INFO *)malloc(sizeof(SYMBOL_INFO)+(TRACE_MAX_FUNCTION_NAME_LENGTH - 1) * sizeof(TCHAR));
symbol->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64 *)malloc(sizeof(IMAGEHLP_LINE64));
line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
DWORD displacement;
SymInitialize(process, NULL, TRUE);
while (StackWalk(image, process, thread, &frame, &context, NULL, NULL, NULL, NULL))
if (SymFromAddr(process, frame.AddrPC.Offset, NULL, symbol))
if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &displacement, line))
printf("\tat %s in %s: line: %lu: address: 0x%0X\n", symbol->Name, line->FileName, line->LineNumber, symbol->Address);
else if (TRACE_LOG_ERRORS)
printf("Error from SymGetLineFromAddr64: %lu.\n", GetLastError());
else if (TRACE_LOG_ERRORS)
printf("Error from SymFromAddr: %lu.\n", GetLastError());
DWORD error = GetLastError();
if (error && TRACE_LOG_ERRORS)
printf("Error from StackWalk64: %lu.\n", error);
HANDLE dumpFile = CreateFile(TRACE_DUMP_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
MINIDUMP_EXCEPTION_INFORMATION exceptionInformation;
exceptionInformation.ThreadId = GetCurrentThreadId();
exceptionInformation.ExceptionPointers = exception;
exceptionInformation.ClientPointers = FALSE;
if (MiniDumpWriteDump(process, GetProcessId(process), dumpFile, MiniDumpNormal, exception ? &exceptionInformation : NULL, NULL, NULL))
printf("Wrote a dump.");
void ShowStackTrace(CONTEXT *aContext)
CONTEXT context = *aContext;
HANDLE thread = GetCurrentThread();
HANDLE process = GetCurrentProcess();
STACKFRAME64 frame;
memset(&frame, 0, sizeof(STACKFRAME64));
DWORD image;
#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.Rbp;
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
#error "This platform is not supported."
#endif
SYMBOL_INFO *symbol = (SYMBOL_INFO *)malloc(sizeof(SYMBOL_INFO)+(TRACE_MAX_FUNCTION_NAME_LENGTH - 1) * sizeof(TCHAR));
symbol->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64 *)malloc(sizeof(IMAGEHLP_LINE64));
line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
DWORD displacement;
SymInitialize(process, NULL, TRUE);
while (StackWalk(image, process, thread, &frame, &context, NULL, NULL, NULL, NULL))
if (SymFromAddr(process, frame.AddrPC.Offset, NULL, symbol))
if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &displacement, line))
printf("\tat %s in %s: line: %lu: address: 0x%0X\n", symbol->Name, line->FileName, line->LineNumber, symbol->Address);
else if (TRACE_LOG_ERRORS)
printf("Error from SymGetLineFromAddr64: %lu.\n", GetLastError());
else if (TRACE_LOG_ERRORS)
printf("Error from SymFromAddr: %lu.\n", GetLastError());
DWORD error = GetLastError();
if (error && TRACE_LOG_ERRORS)
printf("Error from StackWalk64: %lu.\n", error);
HANDLE dumpFile = CreateFile(TRACE_DUMP_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (MiniDumpWriteDump(process, GetProcessId(process), dumpFile, MiniDumpNormal, NULL, NULL, NULL))
printf("Wrote a dump.");
class CustomException {
public:
CustomException(EXCEPTION_POINTERS *exception = nullptr)
CONTEXT context;
ZeroMemory(&context, sizeof(CONTEXT));
if (exception)
// In case of an SEH exception.
ShowStackTrace(exception);
// In case of a C++ exception.
RtlCaptureContext(&context);
ShowStackTrace(&context);
void SEHExceptionTranslator(unsigned int, EXCEPTION_POINTERS *exception){
throw CustomException(exception);
static void threadFunction(void *param)
_set_se_translator(SEHExceptionTranslator);
function0();
LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS exception)
CONTEXT context = *(exception->ContextRecord);
HANDLE thread = GetCurrentThread();
HANDLE process = GetCurrentProcess();
STACKFRAME64 frame;
memset(&frame, 0, sizeof(STACKFRAME64));
DWORD image;
#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.Rbp;
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
#error "This platform is not supported."
#endif
SYMBOL_INFO *symbol = (SYMBOL_INFO *)malloc(sizeof(SYMBOL_INFO)+(TRACE_MAX_FUNCTION_NAME_LENGTH - 1) * sizeof(TCHAR));
symbol->MaxNameLen = TRACE_MAX_FUNCTION_NAME_LENGTH;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64 *)malloc(sizeof(IMAGEHLP_LINE64));
line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
DWORD displacement;
while (StackWalk(image, process, thread, &frame, &context, NULL, NULL, NULL, NULL))
if (SymFromAddr(process, frame.AddrPC.Offset, NULL, symbol))
if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &displacement, line))
printf("\tat %s in %s: line: %lu: address: 0x%0X\n", symbol->Name, line->FileName, line->LineNumber, symbol->Address);
else if (TRACE_LOG_ERRORS)
printf("Error from SymGetLineFromAddr64: %lu.\n", GetLastError());
else if (TRACE_LOG_ERRORS)
printf("Error from SymFromAddr: %lu.\n", GetLastError());
DWORD error = GetLastError();
if (error && TRACE_LOG_ERRORS)
printf("Error from StackWalk64: %lu.\n", error);
HANDLE dumpFile = CreateFile(TRACE_DUMP_NAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
MINIDUMP_EXCEPTION_INFORMATION exceptionInformation;
exceptionInformation.ThreadId = GetCurrentThreadId();
exceptionInformation.ExceptionPointers = exception;
exceptionInformation.ClientPointers = FALSE;
if (MiniDumpWriteDump(process, GetProcessId(process), dumpFile, MiniDumpNormal, exception ? &exceptionInformation : NULL, NULL, NULL))
printf("Wrote a dump.");
return EXCEPTION_CONTINUE_SEARCH;
int _tmain(int argc, _TCHAR* argv[])
SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
SymInitialize(GetCurrentProcess(), NULL, TRUE);
_set_se_translator(SEHExceptionTranslator);
SetUnhandledExceptionFilter(UnhandledExceptionFilter);
_beginthread(threadFunction, 0, NULL);
printf("Press any key to exit.\n");
cin.get();
SymCleanup(GetCurrentProcess());
return 0;
}
发布于 2014-03-18 19:22:19
编辑:
在与OP的作者进行了广泛的讨论之后,我们找到了在调用堆栈跟踪中只有最顶层函数
function0()
才“注册”时“意外”行为的解释。事实上,正如在注释部分早期推测的那样,这是因为所有其他函数都会在发布版构建中内联。用
解密规范
装饰所有函数,确保它们不是内联的。在这种情况下,将获得预期的调用堆栈跟踪.下面描述的处理C++/SE异常的方案仍然有效,尽管它无助于OP作者无法更改生产代码的问题,而且只能处理未处理的异常。编辑的
结束.
只是在评论的部分太长之前做出一个快速的回答。
.map
文件中获取函数的名称。
DbgHelp.dll
中的函数是单线程的,应该在整个过程中调用一次。这意味着
::SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
、
::SymInitialize(::GetCurrentProcess(), 0, 1);
和
::SymCleanup(::GetCurrentProcess());
应该分别在
main()
的开头和结尾被调用。
throw MyException();
和
MyException
对象时,可以跟踪调用堆栈。
_set_se_translator()
并创建一个translator函数,该函数抛出一个C++异常类对象,并将
EXCEPTION_POINTERS *
传递给它的构造函数。然后使用
EXCEPTION_POINTERS *
保存线程上下文来跟踪调用堆栈。
基本上,您有一个定制的C++异常类,其构造函数看起来如下(警告:没有测试):
class MyException {
public:
MyException(EXCEPTION_POINTERS * _ptr = nullptr) {
::CONTEXT context_;
::ZeroMemory( &context_, sizeof(::CONTEXT));
CONTEXT * pcontext_ = &context_;
if(_ptr) pcontext_ = _ptr->ContextRecord; // in case of SE translator
else ::RtlCaptureContext(&context_); // in case of 'throw MyException();'
// Call-stack tracing using pcontext_ here...
// Other stuff for MyException class...
};
因此,要将它与
throw
和
_set_se_translator
一起使用,您可以使用
throw MyException();
和
void my_translator(unsigned int, EXCEPTION_POINTERS * _ptr){
throw MyException(_ptr);
}
发布于 2018-04-20 21:55:42
使用最近的dbghelp.dll (以及相应的最近的MSVC),您也可以找到内联帧的功能/位置。
在
StackWalk()
之前添加以下内容
DWORD frameCount = 0;
将其添加到
StackWalk()
循环(但在
SymFromAddr()
之前):
DWORD64 addr = frame.AddrPC.Offset;
// make sure the location of the calling function is reported, and not of the next statement
if (frameCount != 0 && addr != 0) addr--;
frameCount++;
// number of inlined frames, if any
DWORD inlineTrace = SymAddrIncludeInlineTrace (process, addr);
if (inlineTrace != 0)
DWORD inlineContext, frameIndex;
// the inline context is needed
if (SymQueryInlineTrace (process, addr, 0, addr, addr, &inlineContext, &frameIndex))
for (DWORD i = 0; i < inlineTrace; i++)
DWORD64 displacement64 = 0;
// similar to SymFromAddr()
if (SymFromInlineContext (process, addr, inlineContext, &displacement64, symbol))
DWORD displacement = 0;
// similar to SymGetLineFromAddr64()
if (SymGetLineFromInlineContext (process, addr, inlineContext, 0, &displacement, line))
printf("inline: at %s in %s: line: %lu: address: 0x%0X\n",
symbol->Name, line->FileName, line->LineNumber, symbol->Address);