Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieving unknown exception information

How can I get information about an unknown exception, like in the code below?

void foo()
{
  throw 'A';
}

...
try
{
  foo();
}
catch (const std::exception& exc)
{
  std::cout << exc.what();
}
catch (long e)
{
  std::cout << e;
}
catch (...)
{
  std::cout << "???\n";  // code ends up here
}
...

The code ends up at this line, which is expected:

std::cout << "???\n";

As far as I know, there is not much I can do to retrieve whatever exception information in the catch(...) block.

But, is there maybe some Microsoft-specific C++ extensions that allows to do so?

Environment:

  • Windows 10
  • Windows Desktop application using MFC
like image 776
Jabberwocky Avatar asked Dec 14 '25 11:12

Jabberwocky


1 Answers

#include <ehdata.h>

EXTERN_C 
_CRTIMP
PSTR 
__CRTDECL 
__unDNameEx(
            _Out_ PSTR buffer, 
            _In_ PCSTR mangled, 
            _In_ DWORD cb,
            _In_ void* (__cdecl* memget)(DWORD),
            _In_ void (__cdecl* memfree)(void*),
            _In_ PCSTR (__cdecl* GetParameter)(long i),
            _In_ DWORD flags
            );

static PCSTR __cdecl GetParameter(long /*i*/)
{
    return "";
}

static void* __cdecl fAlloc(ULONG cb)
{
    return LocalAlloc(LMEM_FIXED, (ULONG)cb);
}

static void __cdecl fFree(void* pv)
{
    LocalFree(pv);
}

void PrintName(PCSTR Name)
{
    if ('.' == *Name++)
    {
        PSTR buf = 0, name = 0;

        int len = 0;

        while (0 < (len = _snprintf(name, len, "?_@@YAX%s@Z", Name)))
        {
            if (name)
            {
                len += 0x20;
                len <<= 1;
                if (buf == __unDNameEx(buf = (PSTR)alloca(len), name, len, fAlloc, fFree, GetParameter, UNDNAME_DEFAULT))
                {
                    if (buf = strchr(buf, '('))
                    {
                        buf++;
                        name = buf + strlen(buf)-1;
                        if (')' == *name)
                        {
                            *name = 0;
                            DbgPrint("\tcatch (%hs ) { /***/ }\n", buf);

                            return ;
                        }

                    }
                }
                break;
            }

            name = (PSTR)alloca(++len);
        }
    }

    DbgPrint("\tcatch (%hs ) { ... }\n", Name - 1);
}

EXTERN_C
_CRTIMP
void 
__CRTDECL
__DestructExceptionObject(PEXCEPTION_RECORD ExceptionRecord, BOOLEAN bDestruct);

NTSTATUS seh(PEXCEPTION_RECORD ExceptionRecord)
{
    DbgPrint("%x [%x] at %p\n", ExceptionRecord->ExceptionCode, 
        ExceptionRecord->ExceptionFlags, ExceptionRecord->ExceptionAddress);

    if (ULONG NumberParameters = ExceptionRecord->NumberParameters)
    {
        DbgPrint("%u params: [ ", NumberParameters);
        PULONG_PTR ExceptionInformation = ExceptionRecord->ExceptionInformation;
        do 
        {
            DbgPrint("%p, ", *ExceptionInformation++);
        } while (--NumberParameters);
        DbgPrint("]\n");
    }

    switch (ExceptionRecord->ExceptionCode)
    {
    case EH_EXCEPTION_NUMBER:
        if (!(EXCEPTION_SOFTWARE_ORIGINATE & ExceptionRecord->ExceptionFlags))
        {
            __debugbreak();
        }

        if (EH_EXCEPTION_PARAMETERS <= ExceptionRecord->NumberParameters)
        {
            void **pExceptionObject = reinterpret_cast<void **>(ExceptionRecord->ExceptionInformation[1]);
            ThrowInfo *pTI = reinterpret_cast<ThrowInfo *>(ExceptionRecord->ExceptionInformation[2]);
            ULONG_PTR ImageBase = ExceptionRecord->ExceptionInformation[3];

            DbgPrint("c++[%x]: pExceptionObject=%p\n", ExceptionRecord->ExceptionInformation[0], *pExceptionObject);

            switch (ExceptionRecord->ExceptionInformation[0])
            {
            case EH_MAGIC_NUMBER1:
            case EH_MAGIC_NUMBER2:
            case EH_MAGIC_NUMBER3:
                CatchableTypeArray* p = THROW_CTARRAY_IB(*pTI,ImageBase);
                if (ULONG nCatchableTypes = p->nCatchableTypes)
                {
                    const int* arrayOfCatchableTypes = p->arrayOfCatchableTypes;
                    do 
                    {
                        CatchableType* pt = (CatchableType*)RtlOffsetToPointer(ImageBase, *arrayOfCatchableTypes++);
                        TypeDescriptor* pType = (TypeDescriptor*)RtlOffsetToPointer(ImageBase, pt->pType);

                        PrintName(pType->name);

                    } while (--nCatchableTypes);
                }
                break;
            }

            //  exported by ucrtbase but included to public ucrt.lib
            // __DestructExceptionObject(ExceptionRecord, TRUE);// optional call

            if (PMFN pmfnUnwind = pTI->pmfnUnwind)
            {
                reinterpret_cast<void (__cdecl * )(void*)>(RtlOffsetToPointer(ImageBase, pmfnUnwind))(*pExceptionObject);
            }
        }
        return EXCEPTION_EXECUTE_HANDLER;
    }

    return EXCEPTION_CONTINUE_SEARCH;
}
void Handler_CPP()
{
    try
    {
        foo();
    }
    catch (const std::exception& exc)
    {
        std::cout << exc.what();
    }
    catch (long e)
    {
        std::cout << e;
    }
}

void Handler_C()
{
    __try {
        Handler_CPP();
    } __except(seh(GetExceptionInformation()->ExceptionRecord)){

        __nop();
    }
}

(this code is designed for x64, where _EH_RELATIVE_TYPEINFO is true, however possible here use macros from ehdata.h, like THROW_CTARRAY_IB

like image 64
RbMm Avatar answered Dec 16 '25 02:12

RbMm