我一直试图让一个Windows应用程序在发生崩溃(内存访问错误或零除)或标准c ++exception时转储调用堆栈。
我build立了StackWalker,并把它链接到我的应用程序中,并用/ EHa编译我的应用程序。
#include "win/StackWalker.h" extern int runapp(int argc, char **argv); // The exception filter function: LONG WINAPI ExpFilter(EXCEPTION_POINTERS* pExp, DWORD dwExpCode) { StackWalker sw; sw.ShowCallstack(GetCurrentThread(), pExp->ContextRecord); return EXCEPTION_EXECUTE_HANDLER; } int main(int argc, char *argv[]) { __try { return runapp(argc, argv); } __except (ExpFilter(GetExceptionInformation(), GetExceptionCode())) { } }
真正的程序是通过runapp()启动的,因为不可能直接在__try范围内实例化需要展开(销毁)的对象。
我的问题是,当我强制我的程序崩溃使用此代码时没有被捕获:
int *data1 = 0; *data1 = 0;
换句话说,它只是“正常”
有人有提示吗?
/EHa
开关告诉编译器你要处理C ++ try/catch
块内部的SEH
异常。 在你的代码中,你使用SEH
异常处理程序。 这是我正在使用的一种工作方法:
dbgutils.h
#pragma once #include <eh.h> #include <windows.h> #include <string> #include <sstream> #include <iomanip> #include <boost/optional.hpp> #include "StackWalker.h" class CSO3SEHException { public: CSO3SEHException(unsigned int nCode, EXCEPTION_POINTERS* pEx); std::string what(); std::string stack(); private: std::string m_sWhat, m_sStack; std::string seName(const unsigned int& nCode); boost::optional<std::string> seInfo(unsigned int nCode, EXCEPTION_POINTERS* pEx); void seStack(EXCEPTION_POINTERS* pEx); void seExceptionInfo(unsigned int nCode, EXCEPTION_POINTERS* pEx); }; class CCustomStackWalker : public StackWalker { public: CCustomStackWalker(std::stringstream* ss); protected: virtual void OnOutput(LPCSTR szText); private: std::stringstream* m_sOut; }; void _so3_seh_translate(unsigned int code, _EXCEPTION_POINTERS *ep); void ReportSEHException(CSO3SEHException& ex);
dbgutils.cpp
#include "dbgutils.h" CCustomStackWalker::CCustomStackWalker(std::stringstream* ss) { m_sOut = ss; } void CCustomStackWalker::OnOutput(LPCSTR szText) { size_t sLen = strlen(szText); std::string s = std::string(szText, sLen); (*m_sOut) << s << std::endl; } CSO3SEHException::CSO3SEHException(unsigned int nCode, EXCEPTION_POINTERS* pEx) { seExceptionInfo(nCode, pEx); seStack(pEx); } std::string CSO3SEHException::what() { return(m_sWhat); } std::string CSO3SEHException::stack() { return(m_sStack); } std::string CSO3SEHException::seName(const unsigned int& nCode) { switch (nCode) { case EXCEPTION_ACCESS_VIOLATION: return ("Access Violation"); case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return ("Range Check"); case EXCEPTION_BREAKPOINT: return ("Breakpoint"); case EXCEPTION_DATATYPE_MISALIGNMENT: return ("Datatype misaligment"); case EXCEPTION_ILLEGAL_INSTRUCTION: return ("Illegal instruction"); case EXCEPTION_INT_DIVIDE_BY_ZERO: return ("Divide by zero"); case EXCEPTION_INT_OVERFLOW: return ("Integer overflow"); case EXCEPTION_PRIV_INSTRUCTION: return ("Privileged instruction"); case EXCEPTION_STACK_OVERFLOW: return ("Stack overflow"); default: return("UNKNOWN EXCEPTION"); } } boost::optional<std::string> CSO3SEHException::seInfo(unsigned int nCode, EXCEPTION_POINTERS* pEx) { std::stringstream ss; if (EXCEPTION_ACCESS_VIOLATION == nCode) { ss << (pEx->ExceptionRecord->ExceptionInformation[0] ? "write " : " read"); ss << std::hex << std::setfill('0'); ss << " of address 0x" << std::setw(2*sizeof(void*)) << (unsigned)pEx->ExceptionRecord->ExceptionInformation[1]; return(ss.str()); } return(nullptr); } void CSO3SEHException::seStack(EXCEPTION_POINTERS* pEx) { std::stringstream ss; CCustomStackWalker sw(&ss); sw.ShowCallstack(GetCurrentThread(), pEx->ContextRecord); m_sStack = ss.str(); } void CSO3SEHException::seExceptionInfo(unsigned int nCode, EXCEPTION_POINTERS* pEx) { std::stringstream ss; ss << seName(nCode); ss << std::hex << std::setfill('0'); ss << " at 0x" << std::setw(2*sizeof(void*)) << pEx->ExceptionRecord->ExceptionAddress; auto pSInfo = seInfo(nCode, pEx); if (pSInfo) ss << *pSInfo; m_sWhat = ss.str(); } void _so3_seh_translate(unsigned int code, _EXCEPTION_POINTERS *ep) { throw CSO3SEHException(code, ep); } void ReportSEHException(CSO3SEHException& ex) { std::string sError = ex.what(); std::string sStack = ex.stack(); //do some error reporting here }
在你的代码中的某处:
//You have to call _set_se_translator in all threads _set_se_translator(_so3_seh_translate); try { //do something exception-prone } catch (CSO3SEHException & pSEH) { ReportSEHException(pSEH); } catch (std::exception& err) { //handle c++ exceptions }
以下解决方案跨平台工作(包括StackWalker )。 不幸的是,它只能在posix系统的各个线程上运行。
如果有人有一个解决方案来捕捉在Windows上的所有线程崩溃/异常请告诉。
#include <stdio.h> #include <signal.h> #include <stdlib.h> #ifdef WINDOWS_OS #include <windows.h> #include "StackWalker.h" #include <DbgHelp.h> #include <iostream> void seg_handler(int sig) { unsigned int i; void * stack[ 100 ]; unsigned short frames; SYMBOL_INFO * symbol; HANDLE process; process = GetCurrentProcess(); SymInitialize( process, NULL, TRUE ); frames = CaptureStackBackTrace( 0, 100, stack, NULL ); symbol = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 ); symbol->MaxNameLen = 255; symbol->SizeOfStruct = sizeof( SYMBOL_INFO ); for( i = 0; i < frames; i++ ) { SymFromAddr( process, ( DWORD64 )( stack[ i ] ), 0, symbol ); printf( "%i: %s - 0x%0X\n", frames - i - 1, symbol->Name, symbol->Address ); } free( symbol ); StackWalker sw; sw.ShowCallstack(GetCurrentThread()); exit(1); } void std_handler( void ) { seg_handler(1); } #else #include <execinfo.h> #include <unistd.h> void seg_handler(int sig) { void *array[10]; size_t size; // get void*'s for all entries on the stack size = backtrace(array, 10); // print out all the frames to stderr fprintf(stderr, "Error: signal %d:\n", sig); backtrace_symbols_fd(array, size, STDERR_FILENO); exit(1); } void std_handler( void ) { void *trace_elems[20]; int trace_elem_count(backtrace( trace_elems, 20 )); char **stack_syms(backtrace_symbols( trace_elems, trace_elem_count )); for ( int i = 0 ; i < trace_elem_count ; ++i ) { std::cout << stack_syms[i] << "\n"; } free( stack_syms ); exit(1); } #endif int main(int argc, char *argv[]) { signal(SIGSEGV, seg_handler); std::set_terminate( std_handler ); // Main Program // Crash int *a = 0; *a = 1; }