C++ RTTI in a Windows 64-bit VectoredExceptionHandler, MS Visual Studio 2015
Asked Answered
C

1

8

I'm working on small Windows Exception handling engine trying to gather maximum information from the system, including C++ exceptions RTTI.

In a 32-bit VectoredExceptionHandler compiled by MSVS 2015, I successfully can obtain std::type_info pointer to RTTI of the type being thrown. It can easily be found in ((_ThrowInfo*) ExceptionPointers->ExceptionRecord->ExceptionInformation[2])->pCatchableTypeArray->arrayOfCatchableTypes[0] (see classic article of Raymond Chen, some definitions from MS's ehdata.h file and many others). This method is based on fetching pCatchableTypeArray member of MSVC built-in _ThrowInfo structure data which is built by the compiler.

But in 64-bit environment, _ThrowInfo contains no direct RTTI: unfortunately, pCatchableTypeArray is NULL. In disassembly window, I see that it is NULL even before a call to _CxxThrowException, main MS throw-handler. I searched through a number of articles concerning new 64-bit exception-handling mechanism used in MSVC, but there is no information on RTTI. But maybe I missed something.

Are there any ways to obtain std::type_info (or simply type name) of the C++ exception being thrown in a vectored exception handler working in 64-bit MSVC environment?

Here's the output of dumping 32-bit and 64-bit exception info:

32-bit (RTTI success):

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-bit (RTTI failure)

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

The code used to get these dumps:

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

Build options:

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

Thank you in advance for the answers and advices.

Cressler answered 24/8, 2016 at 1:44 Comment(2)
One thing I've changed is to the cast of addr in RVA_TO_VA_. I think it should be uint32_t or other 32 bit type. Using uintptr_t on a 64 bit platform means you potentially include whatever happens to be in the 32 bits beyond the VA, giving you corrupt pointers. Most of the time it happened to work, because said 32 bits was 0x0, but sometimes it isn't.Moonlight
I never saw high bits other than 0's, but you're of course right.Cressler
C
10

To solve this problem I gone deeper with the research and discovered some interesting things concerning MSVC 64-bit mode. I've found that we can not rely on internal compiler-predefined types in 64-bit mode because some of them are wrong.

I compared definitions of some internal structures predefined by the compiler, such as _ThrowInfo and _CatchableType, with assembly listings produced by the compiler being run with /FAs command-line switch.

Here are the instances of these structures extracted from the assembly files (below is MSVC 2015 64-bit version):

;---------------------------------------------------------------------------------------
; 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:_TI1?AUmeow_exception@?1??main@@YAHXZ@  ; lea &_ThrowInfo
    lea  rcx, QWORD PTR $T1[rsp]
    call _CxxThrowException

;---------------------------------------------------------------------------------------
_TI1?AUmeow_exception@?1??main@@YAHXZ@                            ; _ThrowInfo
    DD  0
    DD  0
    DD  0
    DD  imagerel _CTA1?AUmeow_exception@?1??main@@YAHXZ@          ; &_CatchableTypeArray

;---------------------------------------------------------------------------------------
_CTA1?AUmeow_exception@?1??main@@YAHXZ@                           ; _CatchableTypeArray
    DD  1
    DD  imagerel _CT??_R0?AUmeow_exception@?1??main@@YAHXZ@@84    ; &_CatchableType

;---------------------------------------------------------------------------------------
_CT??_R0?AUmeow_exception@?1??main@@YAHXZ@@84                     ; _CatchableType
    DD  0
    DD  imagerel ??_R0?AUmeow_exception@?1??main@@YAHXZ@@8        ; &_TypeDescriptor
    DD  0
    DD  0ffffffffh
    ORG $+4
    DD  04h
    DD  0

;---------------------------------------------------------------------------------------
??_R0?AUmeow_exception@?1??main@@YAHXZ@@8         ; _TypeDescriptor (aka std::type_info)
    DQ  FLAT:??_7type_info@@6B@
    DQ  0
    DB  '.?AUmeow_exception@?1??main@@YAHXZ@', 0  ; Mangled type name

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

The binary layout of 32-bit version of these structures is similar to 64-bit, with some little differences (FLAT modifier instead of imagerel in address fields and DD instead of DQ in _TypeDescriptor).

Then, let's compare this listing to the predefined types taken from ehdata.h file (f.e., see well-known source by Geoff Chappell or C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\crt\src\ehdata.h file in MSVC 2013; unfortunately this file doesn't exist in MSVC 2015 runtime sources):

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;

In 32-bit mode, everything is OK because pointers are 32-bit and predefined internal definitions of structures correspond with assembly listings.

In 64-bit mode, pointers in these structures are RVAs (Relative Virtual Addresses) measured from image base of the module. This is known and well-documented feature; it truly corresponds with assembler listing above. Notice imagerel address modifiers, these mean RVAs. These RVAs are 32-bit and defined as 32-bit DD keyword.

But in 64-bit mode, from the C++ side, the corresponding pointers are considered to be 64-bit. Thus, C++ binary layout of the internal compiler structures containing pointers (such as _ThrowInfo or _CatchableType above) does not correspond to the Assembler binary layout. Sizes of these structures are greater from C++ side, and the fields offsets are wrong too.

To test this, I defined my own custom structures with the same fields represented as 32-bit integer types instead of pointers:

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

Then I dumped the contents of _ThrowInfo and _CatchableType using both internal definitions and my own definitions. Here's the result (MSVC 2015 64-bit):

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

See the differences in sizes of the whole structures (28 vs 16 bytes, 36 vs 28 bytes), of the pointer members (8 vs 4 bytes) and wrong offsets.

When using CORRECT:: definitions, it's easy to get correct RTTI desired.

The original C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\crt\src\ehdata.h file from MSVC 2013 runtime sources contains conditional preprocessor directives #ifdef _EH_RELATIVE_OFFSETS which substitute pointers to __int32 offsets. But predefined internal compiler types always contains 64-bit wrong pointers.

Thus, using internal definitions of RTTI structures are unreliable in 64-bit mode. One should use its own definitions where pointer members are represented as 32-bit integers (or #define _EH_RELATIVE_OFFSETS and use ehdata.h mentioned above). After that, don't forget manually convert RVAs to the common C++ pointers by adding ImageBase address as usual. But one should not trust pointer members in such structures and definitions containing such pointers because they don't reflect the true 64-bit binary layout.

I tested it with MSVC 2010, and got the same results.

Here's the code for getting correct RTTI in 64-bit MSVC environment:

#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;
    }
Cressler answered 26/8, 2016 at 2:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.