Windows访问冲突的C ++ callstack

时间:2015-07-26 17:01:08

标签: c++ windows debugging callstack

我一直试图让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;

换句话说,它只会崩溃"通常"

有人有提示吗?

2 个答案:

答案 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;
}