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

12,281

Solution 1

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.

Solution 2

// 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;
}

Solution 3

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

Solution 4

There isn't much to it, you'll only be interested in the exception code and address. If the exception is an EXCEPTION_ACCESS_VIOLATION then you also want to dump the first two ExceptionInformation values. The first one indicates the operation (0=read, 1=write, 8=data execution prevention), the second one gives the fault address.

Solution 5

You can see the microsoft code at : http://support.microsoft.com/kb/259693 You can also check this small piece of code: http://www.codeproject.com/Articles/6503/An-NTSTATUS-lookup-application

Share:
12,281
John MacIntyre
Author by

John MacIntyre

Experienced team lead / software developer focused on Microsoft technologies.

Updated on July 22, 2022

Comments

  • John MacIntyre
    John MacIntyre almost 2 years

    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.

  • cwhisperer
    cwhisperer over 13 years
    I would argue that just the code and address isn't particularly useful, especially with ASLR on Vista/Win7, since you didn't record the module base
  • Alessandro Jacopson
    Alessandro Jacopson over 12 years
    Apart from 0 and 1, there is also 8, "If this value is 8, the thread causes a user-mode data execution prevention (DEP) violation." from "EXCEPTION_RECORD structure" msdn.microsoft.com/en-us/library/windows/desktop/…