【发布时间】:2016-12-30 23:46:05
【问题描述】:
我正在开发小型 Windows 异常处理引擎,试图从系统中收集最大信息,包括 C++ 异常 RTTI。
在 MSVS 2015 编译的 32 位 VectoredExceptionHandler 中,我成功获得了指向被抛出类型的 RTTI 的 std::type_info 指针。它可以在((_ThrowInfo*) ExceptionPointers->ExceptionRecord->ExceptionInformation[2])->pCatchableTypeArray->arrayOfCatchableTypes[0] 中轻松找到(参见classic article of Raymond Chen,MS 的ehdata.h 文件中的一些定义以及许多其他文件)。该方法基于获取编译器构建的MSVC内置_ThrowInfo结构数据的pCatchableTypeArray成员。
但在 64 位环境中,_ThrowInfo 不包含直接 RTTI:不幸的是,pCatchableTypeArray 为 NULL。在反汇编窗口中,我看到它甚至在调用主 MS 抛出处理程序 _CxxThrowException 之前为 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
提前感谢您的回答和建议。
【问题讨论】:
-
我改变的一件事是 RVA_TO_VA_ 中的 addr 类型。我认为它应该是 uint32_t 或其他 32 位类型。在 64 位平台上使用 uintptr_t 意味着您可能会包含 VA 之外的 32 位中发生的任何内容,从而为您提供损坏的指针。大多数时候它碰巧工作,因为说 32 位是 0x0,但有时不是。
-
我从未见过除 0 以外的高位,但你当然是对的。
标签: c++ visual-studio exception-handling x86-64 rtti