Есть ли функция для преобразования структуры EXCEPTION_POINTERS в строку? - PullRequest
7 голосов
/ 19 августа 2010

Кто-нибудь знает о функции для преобразования структуры EXCEPTION_POINTERS, возвращаемой из GetExceptionInformation (), в строку, которую я могу записать в журнал?

Я не хочу снимать свои, если это уже сделано.

РЕДАКТИРОВАТЬ: В основном, я добавил блоки __try {} __except () {}, чтобы приложение изящно провалилось при критической ошибке. Пока я работаю над этим, я пытаюсь записать как можно более подробное сообщение об ошибке, чтобы найти проблему, которую мы должны решить. В идеале, я хотел бы распечатать имя файла и строку, в которой он не получился, но я сомневаюсь, что это возможно, поэтому я надеюсь сбросить всю информацию об исключениях в надежде, что мы сможем приблизиться как можно ближе точно определить причину проблемы.

Ответы [ 5 ]

13 голосов
/ 30 ноября 2012
// 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;
}
4 голосов
/ 19 августа 2010

Такой функции нет, так как вам понадобятся личные символы, чтобы написать что-нибудь значимое.Dbghelp.dll помогает в этом (в частности, функция StackWalk и ее 64-битный вариант)

Что вы хотите получить из записи об исключении, чтобы поместить в журнал?Просто код исключения?Контекст регистра?Возвращение стека?

РЕДАКТИРОВАТЬ: Кроме того, если вы просто ничего не делаете, но зарегистрируетесь для Отчеты об ошибках Windows , вы можете просто использовать удивительный сервис Microsoft и получить сбойОтвалы обратно, подкупленные популярностью.Если вы можете, это лучший способ для записи аварийных дампов.

2 голосов
/ 19 августа 2010

В этом нет ничего особенного, вас будут интересовать только код и адрес исключения. Если исключением является EXCEPTION_ACCESS_VIOLATION, то вы также хотите сбросить первые два значения ExceptionInformation. Первый указывает на операцию (0 = чтение, 1 = запись, 8 = предотвращение выполнения данных), второй - адрес ошибки.

2 голосов
/ 19 августа 2010

Отсюда.

#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;
    }
}
1 голос
/ 05 апреля 2014

Вы можете увидеть код Microsoft по адресу: http://support.microsoft.com/kb/259693 Вы также можете проверить этот маленький кусочек кода: http://www.codeproject.com/Articles/6503/An-NTSTATUS-lookup-application

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...