我正在使用以下代码在异常上遍历堆栈(注意:您必须在发布中运行它才能正确地将堆栈跟踪的所需输出接收到控制台,而不是在调试模式下,否则它只会显示一个弹出窗口):
#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.
问题是,上面的跟踪只包含,它对应于对inline: 135
的调用。但是,我希望它包含作为堆栈跟踪的一部分,它在哪里执行. 为什么不将其包含在堆栈跟踪中?我怎样才能让它也包括堆栈跟踪的这一部分?到目前为止,我能够实现此功能的唯一方法是使用并阻止对;的调用。并将 except 传递给 a,但这并不好,因为它有自己的警告,因为它必须在任何地方使用,我想要一个顶级解决方案。我想捕获所有顶级异常,并且我想确切地知道它们被抛出的位置。function0();
threadFunction
line: 29
throw new exception;
__try
__except(FatalExceptionFilter(GetExceptionCode(), GetExceptionInformation()))
function0()
FatalExceptionFilter
PS 此代码在 Windows 8.1、64 位机器下运行。它是一个在 Release 构建/平台 x64 下编译的 MSVC++ 控制台应用程序。
更新:我已经尝试使用 _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);
}
else
{
// 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;
}