本文介绍了为什么不使用SetUnhandledExceptionFilter堆栈步行正常?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 我正在使用以下代码来排除异常(注意:),您必须在发行版中运行它才能正确地将堆栈跟踪输出到控制台,而不是调试模式,否则它只会显示一个弹出窗口): #includestdafx.h #include< ; process.h> #include< iostream> #include< Windows.h> #includedbghelp.h using namespace std; #define TRACE_MAX_FUNCTION_NAME_LENGTH 1024 #define TRACE_LOG_ERRORS FALSE #define TRACE_DUMP_NAME LException.dmp void function2() { int a = 0; int b = 0; 抛出新的异常; } 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框架; memset(& frame,0,sizeof(STACKFRAME64)); DWORD图像; #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不支持此平台。 #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位移; SymInitialize(process,NULL,TRUE); while(StackWalk(image,process,thread,& frame,& context,NULL,NULL,NULL,NULL)) { if(SymFromAddr(process,frame.AddrPC。偏移,NULL,符号)) { if(SymGetLineFromAddr64(process,frame.AddrPC.Offset,& displacement,line)) { printf(\tat %s in%s:line:%lu:address:0x%0X\\\,symbol-> Name,line-> FileName,line-> LineNumber,symbol-> Address); } else if(TRACE_LOG_ERRORS) { printf(SymGetLineFromAddr64错误:%lu.\\\,GetLastError()); } } else if(TRACE_LOG_ERRORS) { printf(SymFromAddr的错误:%lu.\\\,GetLastError()); } } DWORD error = GetLastError(); if(error&& TRACE_LOG_ERRORS) { printf(StackWalk64错误:%lu.\\\,错误); } HANDLE dumpFile = CreateFile(TRACE_DUMP_NAME,GENERIC_READ | GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); MINIDUMP_EXCEPTION_INFORMATION异常信息; exceptionInformation.ThreadId = GetCurrentThreadId(); exceptionInformation.ExceptionPointers = exception; exceptionInformation.ClientPointers = FALSE; if(MiniDumpWriteDump(process,GetProcessId(process),dumpFile,MiniDumpNormal,exception?& exceptionInformation:NULL,NULL,NULL)) { printf(写一个转储 ; } return EXCEPTION_CONTINUE_SEARCH; } int _tmain(int argc,_TCHAR * argv []) { SetUnhandledExceptionFilter(UnhandledExceptionFilter); _beginthread(threadFunction,0,NULL); printf(按任意键退出。\); cin.get(); return 0; } 输出: 按任意键退出。 在线程功能c:\users\< youruseraccount> \documents\visual studio 2013\project s\stacktracing\stacktracing\stacktracing.cpp:line:135:address :0x498B12D0 写了一个转储。 问题是,上述跟踪仅包含行:135 ,它对应于调用 function0(); 在 threadFunction 中的调用。但是,我希望它作为堆栈跟踪的一部分包含 line:29 ,其中它执行抛出新异常; 。为什么不将其作为堆栈跟踪的一部分?我如何使它也包括堆栈跟踪的这一部分? 到目前为止,我已经能够实现此功能的唯一方法是使用 __尝试和 __ except(FatalExceptionFilter(GetExceptionCode(),GetExceptionInformation()))阻止调用 function0 ();并将其传递给 FatalExceptionFilter ,但这并不好,因为它有自己的注意事项,因为它必须在任何地方使用,我想要一个顶部级的解决方案。我想要捕获所有顶级异常,我想知道他们在哪里被抛出。 P.S。该代码正在Windows 8.1,64位机器下运行。它是一个在版本构建/平台x64下编译的MSVC ++控制台应用程序。 更新:我已经尝试使用_set_se_translator方法和Petr的建议,但仍然似乎不想工作。事实上,除以零异常的方式被抛出未处理的东西,没有处理它: #includestdafx.h #include< process.h> #include< iostream> #include< Windows.h> #includedbghelp.h using namespace std; #define TRACE_MAX_FUNCTION_NAME_LENGTH 1024 #define TRACE_LOG_ERRORS FALSE #define TRACE_DUMP_NAME LException.dmp void function2() { int a = 0; int b = 0; //下面的循环应该会抛出一个未处理的异常。 (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框架; memset(& frame,0,sizeof(STACKFRAME64)); DWORD图像; #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不支持此平台。 #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位移; SymInitialize(process,NULL,TRUE); while(StackWalk(image,process,thread,& frame,& context,NULL,NULL,NULL,NULL)) { if(SymFromAddr(process,frame.AddrPC。偏移,NULL,符号)) { if(SymGetLineFromAddr64(process,frame.AddrPC.Offset,& displacement,line)) { printf(\tat %s in%s:line:%lu:address:0x%0X\\\,symbol-> Name,line-> FileName,line-> LineNumber,symbol-> Address); } else if(TRACE_LOG_ERRORS) { printf(SymGetLineFromAddr64错误:%lu.\\\,GetLastError()); } } else if(TRACE_LOG_ERRORS) { printf(SymFromAddr的错误:%lu.\\\,GetLastError()); } } DWORD error = GetLastError(); if(error&& TRACE_LOG_ERRORS) { printf(StackWalk64错误:%lu.\\\,错误); } HANDLE dumpFile = CreateFile(TRACE_DUMP_NAME,GENERIC_READ | GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); MINIDUMP_EXCEPTION_INFORMATION异常信息; exceptionInformation.ThreadId = GetCurrentThreadId(); exceptionInformation.ExceptionPointers = exception; exceptionInformation.ClientPointers = FALSE; if(MiniDumpWriteDump(process,GetProcessId(process),dumpFile,MiniDumpNormal,exception?& exceptionInformation:NULL,NULL,NULL)) { printf(写一个转储 ; } } void ShowStackTrace(CONTEXT * aContext) { CONTEXT context = * aContext; HANDLE thread = GetCurrentThread(); HANDLE process = GetCurrentProcess(); STACKFRAME64框架; memset(& frame,0,sizeof(STACKFRAME64)); DWORD图像; #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不支持此平台。 #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位移; SymInitialize(process,NULL,TRUE); while(StackWalk(image,process,thread,& frame,& context,NULL,NULL,NULL,NULL)) { if(SymFromAddr(process,frame.AddrPC。偏移,NULL,符号)) { if(SymGetLineFromAddr64(process,frame.AddrPC.Offset,& displacement,line)) { printf(\tat %s in%s:line:%lu:address:0x%0X\\\,symbol-> Name,line-> FileName,line-> LineNumber,symbol-> Address); } else if(TRACE_LOG_ERRORS) { printf(SymGetLineFromAddr64错误:%lu.\\\,GetLastError()); } } else if(TRACE_LOG_ERRORS) { printf(SymFromAddr的错误:%lu.\\\,GetLastError()); } } DWORD error = GetLastError(); if(error&& TRACE_LOG_ERRORS) { printf(StackWalk64错误:%lu.\\\,错误); } 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(写一个转储); } } class CustomException { public: CustomException(EXCEPTION_POINTERS * exception = nullptr) { CONTEXT上下文; ZeroMemory(& context,sizeof(CONTEXT)); if(exception) { //如果是SEH异常。 ShowStackTrace(异常); } else { //如果是C ++异常。 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框架; memset(& frame,0,sizeof(STACKFRAME64)); DWORD图像; #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不支持此平台。 #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位移; while(StackWalk(image,process,thread,& frame,& context,NULL,NULL,NULL,NULL)) { if(SymFromAddr(process,frame.AddrPC。偏移,NULL,符号)) { if(SymGetLineFromAddr64(process,frame.AddrPC.Offset,& displacement,line)) { printf(\tat %s in%s:line:%lu:address:0x%0X\\\,symbol-> Name,line-> FileName,line-> LineNumber,symbol-> Address); } else if(TRACE_LOG_ERRORS) { printf(SymGetLineFromAddr64错误:%lu.\\\,GetLastError()); } } else if(TRACE_LOG_ERRORS) { printf(SymFromAddr的错误:%lu.\\\,GetLastError()); } } DWORD error = GetLastError(); if(error&& TRACE_LOG_ERRORS) { printf(StackWalk64错误:%lu.\\\,错误); } HANDLE dumpFile = CreateFile(TRACE_DUMP_NAME,GENERIC_READ | GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); MINIDUMP_EXCEPTION_INFORMATION异常信息; exceptionInformation.ThreadId = GetCurrentThreadId(); exceptionInformation.ExceptionPointers = exception; exceptionInformation.ClientPointers = FALSE; if(MiniDumpWriteDump(process,GetProcessId(process),dumpFile,MiniDumpNormal,exception?& exceptionInformation:NULL,NULL,NULL)) { printf(写一个转储 ; } 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(按任意键退出。\); cin.get(); SymCleanup(GetCurrentProcess()); return 0; } 解决方案 编辑: / strong>在与OP作者的聊天中进行了广泛的讨论之后,当只有最大功能 function0()在通话中被注册时,我们发现了意外行为的解释-堆栈跟踪。事实上,正如在评论部分早期所推测的那样,这是因为所有其他功能在版本构建中被内联。使用 __declspec(noinline)来装饰所有功能,确保它们不内联。在这种情况下,获得预期的调用堆栈跟踪...下面描述的处理C ++ / SE异常的方案仍然有效,尽管它不能帮助OP作者的问题,他不能更改生产代码,并且必须处理只有未处理的例外。 编辑结束 在评论部分过长之前,请快速回答。 检查此线程用于堆栈跟踪例程,还允许您从 .map 文件中获取函数名称。 DbgHelp.dll 中的函数是单线程的,在整个过程中应该调用一次。这意味着 :: SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); , :: SymInitialize(:: GetCurrentProcess(),0,1); 和 :: SymCleanup(:: GetCurrentProcess()); 应该在$ code> main()。 要跟踪C ++异常的调用堆栈,请将堆栈跟踪放在自定义C ++异常类构造函数中。这样,当您抛出MyException(); 和 MyException 对象时,您可以跟踪调用堆栈。 / p> 为了做到这一点,当SE被提出(如除零),你使用 _set_se_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; //在SE翻译器的情况下 else :: RtlCaptureContext(& context_); //在throw MyException();' //使用pcontext_的调用堆栈跟踪... } //其他东西MyException class ... }; 所以要用 throw code> _set_se_translator 你使用 throw MyException(); 和 void my_translator(unsigned int,EXCEPTION_POINTERS * _ptr){ throw MyException(_ptr); } I am using the following code to walk the stack on an exception (note: you must run it in release in order to properly receive the desired output of the stack trace to the console, not in debug mode or else it will only show a popup):#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;}Output:Press any key to exit. at threadFunction in c:\users\<youruseraccount>\documents\visual studio 2013\projects\stacktracing\stacktracing\stacktracing.cpp: line: 135: address: 0x498B12D0Wrote a dump.The problem is that, the above trace contains only line: 135, which corresponds to the call to the call to function0(); in threadFunction. However, I would like it to include, as part of the stack trace, line: 29, where it does a throw new exception;. Why doesn't it include this as part of the stack trace? How can I make it also include this part of the stack trace? The only way I have been able to achieve this functionality so far is to use __try and __except(FatalExceptionFilter(GetExceptionCode(), GetExceptionInformation())) blocks around the call to function0(); and pass the except to a FatalExceptionFilter, but this is no good because it has its own caveats since it would have to be used everywhere, and I want a top-level solution. I want to catch all top level exceptions, and I want to know exactly where they were thrown.P.S. This code is being run under a Windows 8.1, 64-bit machine. It is an MSVC++ console application compiled under a Release build/platform x64.Update: I have tried the following using the _set_se_translator method and Petr's suggestions but it still doesn't seem to want to work. In fact, the divide by zero exception gets thrown unhandled, and nothing handles it:#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;} 解决方案 EDIT: After an extensive discussion in chat with the OP's author we found the explanation for the "unexpected" behavior when only topmost function function0() gets "registered" in a call-stack trace. Indeed, as was speculated very early on in comments' section, it is so because all other functions get inlined in the release build. Decorating all functions with __declspec(noinline) ensures they are not inlined. In this case, the expected call-stack trace is obtained... The scheme to handle C++/SE exception described below is still valid, albeit it does not help the OP author's problem where he cannot change the production code, and has to deal only with unhandled exceptions. End of EDIT.Just making a quick answer before the comments' section gets too long.Check this thread for a stack-tracing routine that also allows you to get functions' names from .map files.Functions in DbgHelp.dll are single threaded and should be called once for the whole process. That means ::SymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);, ::SymInitialize(::GetCurrentProcess(), 0, 1); and ::SymCleanup(::GetCurrentProcess()); should be called in the beginning and in the end of main(), respectively.To trace call stack of C++ exception you put stack tracing in your custom C++ exception class constructor. This way, when you throw MyException(); and MyException object is being constructed you can trace the call stack.To do the same for when SE is raised (like division by zero), you use _set_se_translator() and make a translator function that throws a C++ exception class object with EXCEPTION_POINTERS * passed to its constructor. Then you use EXCEPTION_POINTERS * to saved thread context to trace the call stack.Basically, you have a custom C++ exception class with a constructor that looks something this (warning: wasn't tested):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... };So to use it with throw and _set_se_translator you usethrow MyException();andvoid my_translator(unsigned int, EXCEPTION_POINTERS * _ptr){ throw MyException(_ptr);} 这篇关于为什么不使用SetUnhandledExceptionFilter堆栈步行正常?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!