我一直试图让Windows应用程序在发生崩溃(内存访问不良或零除)或标准c ++异常时转储callstack。
我已经构建了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;
换句话说,它只会崩溃"通常"
有人有提示吗?
答案 0 :(得分:1)
/EHa
switch告诉编译器你想在C ++ SEH
块中处理try/catch
个异常。在您的代码中,您使用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
}
答案 1 :(得分:0)
以下解决方案跨平台工作(包含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;
}