2016-08-24 175 views
1

我正在處理小型Windows異常處理引擎,試圖從系統收集最大的信息,包括C++異常RTTI。Windows 64位VectoredExceptionHandler,MS Visual Studio 2015 C++ RTTI

在由MSVS 2015編譯的32位VectoredExceptionHandler中,我成功可以獲取std :: type_info指向正在引發的類型的RTTI的指針。它可以很容易地在((_ThrowInfo*) ExceptionPointers->ExceptionRecord->ExceptionInformation[2])->pCatchableTypeArray->arrayOfCatchableTypes[0](見classic article of Raymond Chen,來自MS的ehdata.h文件和許多其他定義)中找到。此方法基於取得編譯器構建的MSVC內置_ThrowInfo結構數據的pCatchableTypeArray成員。

但在64位環境中,_ThrowInfo不包含直接RTTI:不幸的是,pCatchableTypeArray爲NULL。在反彙編窗口中,即使在調用_CxxThrowException主MS丟擲處理程序之前,我也發現它是NULL。我搜索了許多關於MSVC中使用的新的64位異常處理機制的文章,但沒有關於RTTI的信息。但也許我錯過了一些東西。

有什麼方法可以獲得在64位MSVC環境中工作的向量化異常處理程序中拋出的C++異常的std :: type_info(或簡單鍵入名稱)?

這裏的傾倒32位和64位的異常信息的輸出:

32位(RTTI成功):

VectoredExceptionHandler(): Start 

exc->ExceptionCode    = 0xE06D7363 
exc->ExceptionAddress   = 0x74E2C54F 
exc->NumberParameters   = 3 
exc->ExceptionInformation[0]  = 0x19930520 (sig) 
exc->ExceptionInformation[1]  = 0x004FFD9C (object) 
exc->ExceptionInformation[2]  = 0x003AD85C (throwInfo) 
exc->ExceptionInformation[3]  = 0x005B18F8 (module) 

throwInfo->attributes   = 0x00000000 
throwInfo->pmfnUnwind   = 0x00000000 
throwInfo->pForwardCompat  = 0x00000000 
throwInfo->pCatchableTypeArray = 0x003AD870 

object = 0x004FFD9C 
throwInfo = 0x003AD85C 
module = 0x00000000 

throwInfo->pCatchableTypeArray = 0x003AD870 
cArray       = 0x003AD870 

cArray->arrayOfCatchableTypes[0] = 0x003AD878 
cType       = 0x003AD878 

cType->pType      = 0x003AFA70 
type        = 0x003AFA70 

type->name()      = "struct `int __cdecl main(void)'::`2'::meow_exception" 
cType->sizeOrOffset    = 4 

VectoredExceptionHandler(): End 

main(): catch (meow_exception { 3 }) 

64位(RTTI失敗)

VectoredExceptionHandler(): Start 

exc->ExceptionCode    = 0xE06D7363 
exc->ExceptionAddress   = 0x000007FEFCE0A06D 
exc->NumberParameters   = 4 
exc->ExceptionInformation[0]  = 0x0000000019930520 (sig) 
exc->ExceptionInformation[1]  = 0x000000000025FBE0 (object) 
exc->ExceptionInformation[2]  = 0x000000013FC52AB0 (throwInfo) 
exc->ExceptionInformation[3]  = 0x000000013FBE0000 (module) 

module       = 0x000000013FBE0000 

throwInfo->attributes   = 0x00000000 
throwInfo->pmfnUnwind   = 0x0000000000000000 
throwInfo->pForwardCompat  = 0x0000000000072AD0 
throwInfo->pCatchableTypeArray = 0x0000000000000000 

VectoredExceptionHandler(): End 

main(): catch (meow_exception { 3 }) 

用於獲取這些轉儲的代碼:

#include <stdio.h> 
#include <typeinfo> 
#include <windows.h> 

//-------------------------------------------------------------------------------------------------- 

const unsigned EXCEPTION_CPP_MICROSOFT     = 0xE06D7363, // '?msc' 
       EXCEPTION_CPP_MICROSOFT_EH_MAGIC_NUMBER1 = 0x19930520, // '?msc' version magic, see ehdata.h 

       EXCEPTION_OUTPUT_DEBUG_STRING   = 0x40010006, // OutputDebugString() call 
       EXCEPTION_THREAD_NAME     = 0x406D1388; // Passing name of thread to the debugger 

void OutputDebugPrintf (const char* format, ...); 

//-------------------------------------------------------------------------------------------------- 

long WINAPI VectoredExceptionHandler (EXCEPTION_POINTERS* pointers) 
    { 
    const EXCEPTION_RECORD* exc = pointers->ExceptionRecord; 

    if (exc->ExceptionCode == EXCEPTION_OUTPUT_DEBUG_STRING || 
     exc->ExceptionCode == EXCEPTION_THREAD_NAME) 
     return EXCEPTION_CONTINUE_SEARCH; 

    OutputDebugPrintf ("\n%s(): Start\n\n", __func__); 

    OutputDebugPrintf ("exc->ExceptionCode = 0x%X\n", exc->ExceptionCode); 
    OutputDebugPrintf ("exc->ExceptionAddress = 0x%p\n", exc->ExceptionAddress); 

    if (exc->ExceptionInformation[0] == EXCEPTION_CPP_MICROSOFT_EH_MAGIC_NUMBER1 && 
     exc->NumberParameters >= 3) 
     { 
     OutputDebugPrintf ("exc->NumberParameters = %u\n", exc->NumberParameters); 

     OutputDebugPrintf ("exc->ExceptionInformation[0] = 0x%p (sig)\n",  (void*) exc->ExceptionInformation[0]); 
     OutputDebugPrintf ("exc->ExceptionInformation[1] = 0x%p (object)\n", (void*) exc->ExceptionInformation[1]); 
     OutputDebugPrintf ("exc->ExceptionInformation[2] = 0x%p (throwInfo)\n", (void*) exc->ExceptionInformation[2]); 
     OutputDebugPrintf ("exc->ExceptionInformation[3] = 0x%p (module)\n", (void*) exc->ExceptionInformation[3]); 
     OutputDebugPrintf ("\n"); 

     HMODULE module = (exc->NumberParameters >= 4)? (HMODULE) exc->ExceptionInformation[3] : NULL; 

     if (module) 
      { 
      OutputDebugPrintf ("module = 0x%p\n", module); 
      OutputDebugPrintf ("\n"); 
      } 

     const _ThrowInfo* throwInfo = (const _ThrowInfo*) exc->ExceptionInformation[2]; 

     if (throwInfo) 
      { 
      OutputDebugPrintf ("throwInfo->attributes   = 0x%08X\n", throwInfo->attributes); 
      OutputDebugPrintf ("throwInfo->pmfnUnwind   = 0x%p\n", throwInfo->pmfnUnwind); 
      OutputDebugPrintf ("throwInfo->pForwardCompat  = 0x%p\n", throwInfo->pForwardCompat); 
      OutputDebugPrintf ("throwInfo->pCatchableTypeArray = 0x%p\n", throwInfo->pCatchableTypeArray); 
      OutputDebugPrintf ("\n"); 
      } 

     if (throwInfo && throwInfo->pCatchableTypeArray) 
      {    
      #define RVA_TO_VA_(type, addr) ((type) ((uintptr_t) module + (uintptr_t) (addr))) 

      OutputDebugPrintf ("object = 0x%p\n", (void*) exc->ExceptionInformation[1]); 
      OutputDebugPrintf ("throwInfo = 0x%p\n", (void*) throwInfo); 
      OutputDebugPrintf ("module = 0x%p\n", (void*) module); 
      OutputDebugPrintf ("\n"); 

      const _CatchableTypeArray* cArray = RVA_TO_VA_(const _CatchableTypeArray*, throwInfo->pCatchableTypeArray); 

      OutputDebugPrintf ("throwInfo->pCatchableTypeArray = 0x%p\n", (void*) throwInfo->pCatchableTypeArray); 
      OutputDebugPrintf ("cArray       = 0x%p\n\n", (void*) cArray); 

      const _CatchableType* cType = RVA_TO_VA_(const _CatchableType*, cArray->arrayOfCatchableTypes[0]); 

      OutputDebugPrintf ("cArray->arrayOfCatchableTypes[0] = 0x%p\n", (void*) cArray->arrayOfCatchableTypes[0]); 
      OutputDebugPrintf ("cType       = 0x%p\n\n", (void*) cType); 

      const std::type_info* type = RVA_TO_VA_(const std::type_info*, cType->pType); 

      OutputDebugPrintf ("cType->pType = 0x%p\n", (void*) cType->pType); 
      OutputDebugPrintf ("type   = 0x%p\n\n", (void*) type); 

      OutputDebugPrintf ("type->name()  = \"%s\"\n", type->name()); 
      OutputDebugPrintf ("cType->sizeOrOffset = %zu\n\n", (size_t) cType->sizeOrOffset); 

      #undef RVA_TO_VA_ 
      } 
     } 

    OutputDebugPrintf ("%s(): End\n", __func__); 
    return EXCEPTION_CONTINUE_SEARCH; 
    } 

//-------------------------------------------------------------------------------------------------- 

void OutputDebugPrintf (const char* format, ...) 
    { 
    static char buf [1024] = ""; 

    va_list arg; va_start (arg, format); 
    _vsnprintf_s (buf, sizeof (buf) - 1, _TRUNCATE, format, arg); 
    va_end (arg); 

    OutputDebugString (buf); 
    printf ("%s", buf); 
    } 

//-------------------------------------------------------------------------------------------------- 

int main() 
    {  
    OutputDebugPrintf ("\n%s(): Start\n", __func__); 

    AddVectoredExceptionHandler (1, VectoredExceptionHandler); 

    struct meow_exception { int code = 3; }; 

    try 
     { 
     throw meow_exception(); 
     } 

    catch (const meow_exception& e) 
     { 
     OutputDebugPrintf ("\n%s(): catch (meow_exception { %d })\n", __func__, e.code); 
     } 

    catch (...) 
     { 
     OutputDebugPrintf ("\n%s(): catch (...)\n", __func__); 
     } 

    OutputDebugPrintf ("\n%s(): End\n", __func__); 
    return 0; 
    } 

編譯選項:

// Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24213.1 (part of VS 2015 SP3) 

cl /c code.cpp /EHsc /W4 
link code.obj kernel32.lib /machine:x86 /subsystem:console /debug 

預先感謝您的答案和建議。

回答

0

爲了解決這個問題,我深入研究了這個問題,並發現了一些有關MSVC 64位模式的有趣事情。我發現我們不能依賴64位模式下的內部編譯器預定義類型,因爲它們中有些是錯誤的。

我比較了編譯器預定義一些內部結構,如_ThrowInfo_CatchableType的定義,與由編譯器產生的彙編列表被與/FAs命令行開關運行。

下面是這些結構從組件的文件(下面是MSVC 2015 64位版本)提取的實例:

;--------------------------------------------------------------------------------------- 
; Listing generated by Microsoft Optimizing Compiler Version 19.00.24213.1 
; Simplified: many lines skipped, some sections reordered etc -- Ded 
;--------------------------------------------------------------------------------------- 

main proc 

; struct meow_exception { int code = 3; }; 
; 
; try 
;  { 
;  throw meow_exception(); 

    ... 
    lea rdx, OFFSET FLAT:[email protected][email protected]@[email protected] ; lea &_ThrowInfo 
    lea rcx, QWORD PTR $T1[rsp] 
    call _CxxThrowException 

;--------------------------------------------------------------------------------------- 
[email protected][email protected]@[email protected]       ; _ThrowInfo 
    DD 0 
    DD 0 
    DD 0 
    DD imagerel [email protected][email protected]@[email protected]   ; &_CatchableTypeArray 

;--------------------------------------------------------------------------------------- 
[email protected][email protected]@[email protected]       ; _CatchableTypeArray 
    DD 1 
    DD imagerel [email protected][email protected]@[email protected]@84 ; &_CatchableType 

;--------------------------------------------------------------------------------------- 
[email protected][email protected]@[email protected]@84      ; _CatchableType 
    DD 0 
    DD imagerel [email protected][email protected]@[email protected]@8  ; &_TypeDescriptor 
    DD 0 
    DD 0ffffffffh 
    ORG $+4 
    DD 04h 
    DD 0 

;--------------------------------------------------------------------------------------- 
[email protected][email protected]@[email protected]@8   ; _TypeDescriptor (aka std::type_info) 
    DQ FLAT:[email protected]@[email protected] 
    DQ 0 
    DB '[email protected][email protected]@[email protected]', 0 ; Mangled type name 

;--------------------------------------------------------------------------------------- 

的這些結構中的32位版本的二進制佈局類似於64- (FLAT修飾符,而不是地址字段中的imagerelDD而不是DQ,在_TypeDescriptor中)。

然後,讓我們比較從ehdata.h文件所採取的預定義的類型此房源(FE,見well-known source by Geoff ChappellC:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\crt\src\ehdata.h文件中的MSVC 2013;不幸的是這個文件並不在MSVC存在2015年運行時代碼):

typedef const struct _s__ThrowInfo 
    { 
    unsigned int   attributes; 
    _PMFN    pmfnUnwind;   // this is a pointer! 
    int (__cdecl  *pForwardCompat) (...); // this is a pointer too! 
    _CatchableTypeArray *pCatchableTypeArray; // this is a pointer too! 
    } 
    _ThrowInfo; 

typedef const struct _s__CatchableType 
    { 
    unsigned int  properties; 
    _TypeDescriptor *pType;      // this is a pointer too! 
    _PMD    thisDisplacement; 
    int    sizeOrOffset; 
    _PMFN   copyFunction;    // this is a pointer too! 
    } 
    _CatchableType; 

在32位模式下,一切正常,因爲指針是32位的和結構的預定義的內部定義與彙編列表對應。

在64位模式下,這些結構中的指針是從模塊的圖像庫測量的RVA(相對虛擬地址)。這是衆所周知的並且有詳細記錄的功能;它真正符合上面的彙編程序列表。注意imagerel地址修飾符,這些意味着RVAs。 這些的RVAs是32位和定義爲32位DD關鍵字。

但在64位模式中,從C++側,相應的指針被認爲是64位。因此,包含指針的內部編譯器結構的C++二進制佈局(如上面的_ThrowInfo_CatchableType不對應於彙編器二進制佈局。這些結構的尺寸在C++端更大,並且字段偏移也是錯誤的。

爲了測試這一點,我定義自己的自定義結構與表示爲32位的整數類型,而不是指針相同的字段:

namespace CORRECT 
    { 
    struct ThrowInfo 
     { 
     __int32 attributes; 
     __int32 pmfnUnwind;   // now this is 32-bit RVA 
     __int32 pForwardCompat;  // now this is 32-bit RVA 
     __int32 pCatchableTypeArray; // now this is 32-bit RVA 
     }; 

    struct CatchableType 
     { 
     __int32 properties; 
     __int32 pType;    // now this is 32-bit RVA 
     _PMD thisDisplacement; 
     __int32 sizeOrOffset; 
     __int32 copyFunction;   // now this is 32-bit RVA 
     }; 
    } 

然後我傾倒的_ThrowInfo_CatchableType利用內部定義和內容我自己的定義。這裏的結果(MSVC 2015 64位):

exc->ExceptionCode    = 0xE06D7363 
exc->ExceptionAddress   = 0x000007FEFD69A06D 
exc->NumberParameters   = 4 
exc->ExceptionInformation[0]  = 0x0000000019930520 (sig) 
exc->ExceptionInformation[1]  = 0x00000000002BF8B0 (object) 
exc->ExceptionInformation[2]  = 0x000000013F9C4210 (throwInfo) 
exc->ExceptionInformation[3]  = 0x000000013F950000 (module) 

Built-in: _ThrowInfo, size 28 
_throwInfo->attributes   = 0x00000000 [ofs: 0, size: 4, type: unsigned int] 
_throwInfo->pmfnUnwind   = 0x00000000 [ofs: 4, size: 8, type: void (__cdecl*)(void * __ptr64)] 
_throwInfo->pForwardCompat  = 0x00074230 [ofs: 12, size: 8, type: int (__cdecl*)(void)] 
_throwInfo->pCatchableTypeArray = 0x00000000 [ofs: 20, size: 8, type: struct _s__CatchableTypeArray const * __ptr64] 

Custom: CORRECT::ThrowInfo, size 16 
throwInfo->attributes   = 0x00000000 [ofs: 0, size: 4, type: int] 
throwInfo->pmfnUnwind   = 0x00000000 [ofs: 4, size: 4, type: int] 
throwInfo->pForwardCompat  = 0x00000000 [ofs: 8, size: 4, type: int] 
throwInfo->pCatchableTypeArray = 0x00074230 [ofs: 12, size: 4, type: int] 

throwInfo->pCatchableTypeArray = 0x0000000000074230 
cArray       = 0x000000013F9C4230 

Built-in: _CatchableType, size 36 
_cType->properties    = 0x00000000 [ofs: 0, size: 4, type: unsigned int] 
_cType->pType     = 0x00075D58 [ofs: 4, size: 8, type: struct _TypeDescriptor * __ptr64] 
_cType->thisDisplacement.mdisp = 0xFFFFFFFF [ofs: 12, size: 4, type: int] 
_cType->thisDisplacement.pdisp = 0x00000000 [ofs: 16, size: 4, type: int] 
_cType->thisDisplacement.vdisp = 0x00000004 [ofs: 20, size: 4, type: int] 
_cType->sizeOrOffset    = 0x00000000 [ofs: 24, size: 4, type: int] 
_cType->copyFunction    = 0x00000000 [ofs: 28, size: 8, type: void (__cdecl*)(void * __ptr64)] 

Custom: CORRECT::CatchableType, size 28 
cType->properties    = 0x00000000 [ofs: 0, size: 4, type: int] 
cType->pType      = 0x00075D58 [ofs: 4, size: 4, type: int] 
cType->thisDisplacement.mdisp = 0x00000000 [ofs: 8, size: 4, type: int] 
cType->thisDisplacement.pdisp = 0xFFFFFFFF [ofs: 12, size: 4, type: int] 
cType->thisDisplacement.vdisp = 0x00000000 [ofs: 16, size: 4, type: int] 
cType->sizeOrOffset    = 0x00000004 [ofs: 20, size: 4, type: int] 
cType->copyFunction    = 0x00000000 [ofs: 24, size: 4, type: int] 

cArray->arrayOfCatchableTypes[0] = 0x0000000000074240 
cType       = 0x000000013F9C4240 

cType->pType      = 0x0000000000075D58 
type        = 0x000000013F9C5D58 

type->name()      = "struct `int __cdecl main(void)'::`2'::meow_exception" 
cType->sizeOrOffset    = 4 

見,在整個結構的尺寸的差異(28比16字節,36比28字節),指針構件(8 VS 4字節)和錯誤的偏移量。

當使用CORRECT::定義,很容易得到正確的RTTI所需。

來自MSVC 2013運行時間源的原始C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\crt\src\ehdata.h文件包含條件預處理器指令#ifdef _EH_RELATIVE_OFFSETS,它將替代指向偏移量的指針。但預定義的內部編譯器類型始終包含64位錯誤指針。

因此,使用RTTI結構的內部定義在64位模式下不可靠。一個應該使用其自己的定義,其中指針成員表示爲32位整數(或#define _EH_RELATIVE_OFFSETS和使用ehdata.h上述)。之後,請不要忘記像往常一樣通過添加ImageBase地址手動將RVAs轉換爲常用的C++指針。但是不應該相信這樣的結構中的指針成員和包含這樣的指針的定義,因爲它們並不反映真正的64位二進制佈局。

我測試了它與MSVC 2010,並且得到了相同的結果。

下面是在64位環境MSVC得到正確的RTTI代碼:

#include <stdio.h> 
#include <typeinfo> 
#include <stdexcept> 
#include <windows.h> 

//------------------------------------------------------------------------------------------------------------------------------ 
//! These definitions are based on assembly listings produded by the compiler (/FAs) rather than built-in ones 
//! @{ 

#pragma pack (push, 4) 

namespace CORRECT 
    { 

    struct CatchableType 
     { 
     __int32 properties; 
     __int32 pType; 
     _PMD thisDisplacement; 
     __int32 sizeOrOffset; 
     __int32 copyFunction; 
     }; 

    struct ThrowInfo 
     { 
     __int32 attributes; 
     __int32 pmfnUnwind; 
     __int32 pForwardCompat; 
     __int32 pCatchableTypeArray; 
     }; 

    } 

#pragma pack (pop) 

//! @} 
//------------------------------------------------------------------------------------------------------------------------------ 

const unsigned EXCEPTION_CPP_MICROSOFT     = 0xE06D7363, // '?msc' 
       EXCEPTION_CPP_MICROSOFT_EH_MAGIC_NUMBER1 = 0x19930520, // '?msc' version magic, see ehdata.h 

       EXCEPTION_OUTPUT_DEBUG_STRING   = 0x40010006, // OutputDebugString() call 
       EXCEPTION_THREAD_NAME     = 0x406D1388; // Passing name of thread to the debugger 

void OutputDebugPrintf (const char* format, ...); 

//------------------------------------------------------------------------------------------------------------------------------ 

long WINAPI VectoredExceptionHandler (EXCEPTION_POINTERS* pointers) 
    { 
    const EXCEPTION_RECORD* exc = pointers->ExceptionRecord; 

    if (exc->ExceptionCode == EXCEPTION_OUTPUT_DEBUG_STRING || 
     exc->ExceptionCode == EXCEPTION_THREAD_NAME) 
     return EXCEPTION_CONTINUE_SEARCH; 

    OutputDebugPrintf ("\n%s(): Start\n\n", __FUNCTION__); 

    OutputDebugPrintf   ("exc->ExceptionCode    = 0x%X\n", exc->ExceptionCode); 
    OutputDebugPrintf   ("exc->ExceptionAddress   = 0x%p\n", exc->ExceptionAddress); 

    if (exc->ExceptionInformation[0] == EXCEPTION_CPP_MICROSOFT_EH_MAGIC_NUMBER1 && 
     exc->NumberParameters >= 3) 
     { 
     OutputDebugPrintf  ("exc->NumberParameters   = %u\n", exc->NumberParameters); 

     OutputDebugPrintf  ("exc->ExceptionInformation[0]  = 0x%p (sig)\n",  (void*) exc->ExceptionInformation[0]); 
     OutputDebugPrintf  ("exc->ExceptionInformation[1]  = 0x%p (object)\n", (void*) exc->ExceptionInformation[1]); 
     OutputDebugPrintf  ("exc->ExceptionInformation[2]  = 0x%p (throwInfo)\n", (void*) exc->ExceptionInformation[2]); 

     if (exc->NumberParameters >= 4) 
      OutputDebugPrintf ("exc->ExceptionInformation[3]  = 0x%p (module)\n", (void*) exc->ExceptionInformation[3]); 

     OutputDebugPrintf ("\n"); 

     HMODULE module = (exc->NumberParameters >= 4)? (HMODULE) exc->ExceptionInformation[3] : NULL; 

     #define RVA_TO_VA_(type, addr) ((type) ((uintptr_t) module + (uintptr_t) (addr))) 

     const   _ThrowInfo* _throwInfo = (const   _ThrowInfo*) exc->ExceptionInformation[2]; 
     const CORRECT::ThrowInfo* throwInfo = (const CORRECT::ThrowInfo*) exc->ExceptionInformation[2]; 

     #define DUMP_(var, struc, field) OutputDebugPrintf ("%-32s = 0x%08X [ofs: %2u, size: %u, type: %s]\n", \ 
                  #var "->" #field, (var)->field,     \ 
                  offsetof (struc, field), sizeof ((var)->field), \ 
                  typeid ((var)->field) .name()); 
     if (_throwInfo) 
      { 
      OutputDebugPrintf ("Built-in: _ThrowInfo, size %u\n", sizeof (_ThrowInfo)); 
      DUMP_ (_throwInfo, _ThrowInfo, attributes); 
      DUMP_ (_throwInfo, _ThrowInfo, pmfnUnwind); 
      DUMP_ (_throwInfo, _ThrowInfo, pForwardCompat); 
      DUMP_ (_throwInfo, _ThrowInfo, pCatchableTypeArray); 
      OutputDebugPrintf ("\n"); 
      } 
     else 
      OutputDebugPrintf ("_throwInfo is NULL\n"); 

     if (throwInfo) 
      { 
      OutputDebugPrintf ("Custom: CORRECT::ThrowInfo, size %u\n", sizeof (CORRECT::ThrowInfo)); 
      DUMP_ (throwInfo, CORRECT::ThrowInfo, attributes); 
      DUMP_ (throwInfo, CORRECT::ThrowInfo, pmfnUnwind); 
      DUMP_ (throwInfo, CORRECT::ThrowInfo, pForwardCompat); 
      DUMP_ (throwInfo, CORRECT::ThrowInfo, pCatchableTypeArray); 
      OutputDebugPrintf ("\n"); 
      } 
     else 
      OutputDebugPrintf ("throwInfo is NULL\n"); 

     if (throwInfo) 
      {    
      const _CatchableTypeArray* cArray = RVA_TO_VA_(const _CatchableTypeArray*, throwInfo->pCatchableTypeArray); 

      OutputDebugPrintf ("throwInfo->pCatchableTypeArray = 0x%p\n", (void*)(ptrdiff_t) throwInfo->pCatchableTypeArray); 
      OutputDebugPrintf ("cArray       = 0x%p\n\n", (void*)   cArray); 

      const   _CatchableType* _cType = RVA_TO_VA_(const   _CatchableType*, cArray->arrayOfCatchableTypes[0]); 
      const CORRECT::CatchableType* cType = RVA_TO_VA_(const CORRECT::CatchableType*, cArray->arrayOfCatchableTypes[0]); 

      OutputDebugPrintf ("Built-in: _CatchableType, size %u\n", sizeof (_CatchableType)); 
      DUMP_ (_cType, _CatchableType, properties); 
      DUMP_ (_cType, _CatchableType, pType); 
      DUMP_ (_cType, _CatchableType, thisDisplacement.mdisp); 
      DUMP_ (_cType, _CatchableType, thisDisplacement.pdisp); 
      DUMP_ (_cType, _CatchableType, thisDisplacement.vdisp); 
      DUMP_ (_cType, _CatchableType, sizeOrOffset); 
      DUMP_ (_cType, _CatchableType, copyFunction); 
      OutputDebugPrintf ("\n"); 

      OutputDebugPrintf ("Custom: CORRECT::CatchableType, size %u\n", sizeof (CORRECT::CatchableType)); 
      DUMP_ (cType, CORRECT::CatchableType, properties); 
      DUMP_ (cType, CORRECT::CatchableType, pType); 
      DUMP_ (cType, CORRECT::CatchableType, thisDisplacement.mdisp); 
      DUMP_ (cType, CORRECT::CatchableType, thisDisplacement.pdisp); 
      DUMP_ (cType, CORRECT::CatchableType, thisDisplacement.vdisp); 
      DUMP_ (cType, CORRECT::CatchableType, sizeOrOffset); 
      DUMP_ (cType, CORRECT::CatchableType, copyFunction); 
      OutputDebugPrintf ("\n"); 

      OutputDebugPrintf ("cArray->arrayOfCatchableTypes[0] = 0x%p\n", (void*) cArray->arrayOfCatchableTypes[0]); 
      OutputDebugPrintf ("cType       = 0x%p\n\n", (void*) cType); 

      const std::type_info* type = RVA_TO_VA_(const std::type_info*, cType->pType); 

      OutputDebugPrintf ("cType->pType      = 0x%p\n", (void*)(ptrdiff_t) cType->pType); 
      OutputDebugPrintf ("type        = 0x%p\n\n", (void*)   type); 

      OutputDebugPrintf ("type->name()      = \"%s\"\n", type->name()); 
      OutputDebugPrintf ("cType->sizeOrOffset    = %u\n\n", (unsigned) cType->sizeOrOffset); 

      } 

     #undef DUMP_ 
     #undef RVA_TO_VA_ 
     } 

    OutputDebugPrintf ("%s(): End\n", __FUNCTION__); 
    return EXCEPTION_CONTINUE_SEARCH; 
    } 

//------------------------------------------------------------------------------------------------------------------------------ 

void OutputDebugPrintf (const char* format, ...) 
    { 
    static char buf [1024] = ""; 

    va_list arg; va_start (arg, format); 
    _vsnprintf_s (buf, sizeof (buf) - 1, _TRUNCATE, format, arg); 
    va_end (arg); 

    OutputDebugString (buf); 
    printf ("%s", buf); 
    } 

//------------------------------------------------------------------------------------------------------------------------------ 

int main() 
    {  
    OutputDebugPrintf ("\nCompiled with MSVC %d, %d-bit\n", _MSC_VER, 8 * sizeof (void*)); 
    OutputDebugPrintf ("\n%s(): Start\n", __FUNCTION__); 

    AddVectoredExceptionHandler (1, VectoredExceptionHandler); 

    struct meow_exception { int code; meow_exception() : code (3) {} }; 

    try 
     { 
     throw meow_exception(); 
     } 

    catch (const meow_exception& e) 
     { 
     OutputDebugPrintf ("\n%s(): catch (meow_exception { %d })\n", __FUNCTION__, e.code); 
     } 

    catch (...) 
     { 
     OutputDebugPrintf ("\n%s(): catch (...)\n", __FUNCTION__); 
     } 

    OutputDebugPrintf ("\n%s(): End\n", __FUNCTION__); 
    return 0; 
    }