Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a function to convert EXCEPTION_POINTERS struct to a string?

Does anybody know of a function to convert the EXCEPTION_POINTERS structure returned from GetExceptionInformation() into a string that I can log?

I don't want to roll my own if it's already been done.

EDIT: Basically, I've added the __try{} __except(){} blocks to help the app fail gracefully on a critical error. While I'm at it, I'm trying to log as detailed of an error message as possible to locate the issue for us to resolve. Ideally, I'd like to print out the file name and line it failed on, but I doubt that's possible, so I'm hoping to dump all the exception information in the hopes that we'll be able to come as close as possible to pinpointing the exact cause of the problem.

like image 755
John MacIntyre Avatar asked Aug 19 '10 16:08

John MacIntyre


3 Answers

// Compile with /EHa
#include <windows.h>
#include <eh.h>
#include <Psapi.h>
#include <string>
#include <sstream>

class InfoFromSE
{
public:
   typedef unsigned int exception_code_t;

   static const char* opDescription( const ULONG opcode )
   {
      switch( opcode ) {
      case 0: return "read";
      case 1: return "write";
      case 8: return "user-mode data execution prevention (DEP) violation";
      default: return "unknown";
      }
   }

   static const char* seDescription( const exception_code_t& code )
   {
      switch( code ) {
         case EXCEPTION_ACCESS_VIOLATION:         return "EXCEPTION_ACCESS_VIOLATION"         ;
         case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:    return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"    ;
         case EXCEPTION_BREAKPOINT:               return "EXCEPTION_BREAKPOINT"               ;
         case EXCEPTION_DATATYPE_MISALIGNMENT:    return "EXCEPTION_DATATYPE_MISALIGNMENT"    ;
         case EXCEPTION_FLT_DENORMAL_OPERAND:     return "EXCEPTION_FLT_DENORMAL_OPERAND"     ;
         case EXCEPTION_FLT_DIVIDE_BY_ZERO:       return "EXCEPTION_FLT_DIVIDE_BY_ZERO"       ;
         case EXCEPTION_FLT_INEXACT_RESULT:       return "EXCEPTION_FLT_INEXACT_RESULT"       ;
         case EXCEPTION_FLT_INVALID_OPERATION:    return "EXCEPTION_FLT_INVALID_OPERATION"    ;
         case EXCEPTION_FLT_OVERFLOW:             return "EXCEPTION_FLT_OVERFLOW"             ;
         case EXCEPTION_FLT_STACK_CHECK:          return "EXCEPTION_FLT_STACK_CHECK"          ;
         case EXCEPTION_FLT_UNDERFLOW:            return "EXCEPTION_FLT_UNDERFLOW"            ;
         case EXCEPTION_ILLEGAL_INSTRUCTION:      return "EXCEPTION_ILLEGAL_INSTRUCTION"      ;
         case EXCEPTION_IN_PAGE_ERROR:            return "EXCEPTION_IN_PAGE_ERROR"            ;
         case EXCEPTION_INT_DIVIDE_BY_ZERO:       return "EXCEPTION_INT_DIVIDE_BY_ZERO"       ;
         case EXCEPTION_INT_OVERFLOW:             return "EXCEPTION_INT_OVERFLOW"             ;
         case EXCEPTION_INVALID_DISPOSITION:      return "EXCEPTION_INVALID_DISPOSITION"      ;
         case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "EXCEPTION_NONCONTINUABLE_EXCEPTION" ;
         case EXCEPTION_PRIV_INSTRUCTION:         return "EXCEPTION_PRIV_INSTRUCTION"         ;
         case EXCEPTION_SINGLE_STEP:              return "EXCEPTION_SINGLE_STEP"              ;
         case EXCEPTION_STACK_OVERFLOW:           return "EXCEPTION_STACK_OVERFLOW"           ;
         default: return "UNKNOWN EXCEPTION" ;
      }
   }

   static std::string information( struct _EXCEPTION_POINTERS* ep, bool has_exception_code = false, exception_code_t code = 0  )
   {
      HMODULE hm;
      ::GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast<LPCTSTR>(ep->ExceptionRecord->ExceptionAddress), &hm );
      MODULEINFO mi;
      ::GetModuleInformation( ::GetCurrentProcess(), hm, &mi, sizeof(mi) );
      char fn[MAX_PATH];
      ::GetModuleFileNameExA( ::GetCurrentProcess(), hm, fn, MAX_PATH );

      std::ostringstream oss;
      oss << "SE " << (has_exception_code?seDescription( code ):"") << " at address 0x" << std::hex << ep->ExceptionRecord->ExceptionAddress << std::dec 
         << " inside " << fn << " loaded at base address 0x" << std::hex << mi.lpBaseOfDll << "\n"; 

      if ( has_exception_code && (
           code == EXCEPTION_ACCESS_VIOLATION || 
           code == EXCEPTION_IN_PAGE_ERROR ) ) {
         oss << "Invalid operation: " << opDescription(ep->ExceptionRecord->ExceptionInformation[0]) << " at address 0x" << std::hex << ep->ExceptionRecord->ExceptionInformation[1] << std::dec << "\n";
      }

      if ( has_exception_code && code == EXCEPTION_IN_PAGE_ERROR ) {
         oss << "Underlying NTSTATUS code that resulted in the exception " << ep->ExceptionRecord->ExceptionInformation[2] << "\n";
      }

      return oss.str();
   }
};

#include <iostream>
#include <exception>

void translator( InfoFromSE::exception_code_t code, struct _EXCEPTION_POINTERS* ep )
{
   throw std::exception( InfoFromSE::information(ep,true,code).c_str() );
}

int main(int argc, char* argv[])
{
   _set_se_translator(translator);
   try{
      int* p = 0;
      std::cout << *p;
   }catch( const std::exception& e ){
      std::cerr << e.what() << "\n";
   }

   try{
      int* p = 0;
      *p = 0;
      std::cout << *p;
   }catch( const std::exception& e ){
      std::cerr << e.what() << "\n";
   }

   try{
      int a = 42;
      volatile int b = 0;
      std::cout << a/b;
   }catch( const std::exception& e ){
      std::cerr << e.what() << "\n";
   }
    return 0;
}
like image 70
Alessandro Jacopson Avatar answered Nov 19 '22 11:11

Alessandro Jacopson


There is no such function, since you'll need private symbols to write anything meaningful. The dbghelp.dll helps with some of this (specifically the StackWalk function and its 64-bit variant)

What do you want to get out of the exception record to put into the log? Just the exception code? The register context? The stack backtrace?

EDIT: Also, if you just do nothing, but register for Windows Error Reporting, you can just use Microsoft's awesome service and get the crash dumps back, bucketed by popularity. If you can, that's by-far the best way to record crash dumps.

like image 32
Ana Betts Avatar answered Nov 19 '22 13:11

Ana Betts


From here.

#include <windows.h>
#include <iostream>
#include <string.h>
#include <eh.h>
using namespace std;

static void translateSEH(unsigned int u, EXCEPTION_POINTERS* pExcept) {
  // Translate SEH exception to a C++ exception.  NOTE: compiling with /EHa is required!!
  static char msg[256];
  sprintf_s(msg, 256, "Unhandled exception 0x%08x at 0x%08x",
    pExcept->ExceptionRecord->ExceptionCode,
    pExcept->ExceptionRecord->ExceptionAddress);
  throw exception(msg);
}

int main(){
  _set_se_translator(translateSEH);
    int p = 0;
    try {
        cout<<1 / p<<endl;   
    }
  catch (std::exception& ex) {
        cout << ex.what() << endl;
    }
}
like image 2
Knowles Atchison Avatar answered Nov 19 '22 11:11

Knowles Atchison