From f3ea057c1bedbba987b8187a4e4839bc3e98c13a Mon Sep 17 00:00:00 2001 From: "beard%netscape.com" Date: Fri, 1 Sep 2000 03:15:30 +0000 Subject: [PATCH] added RTTI heuristics for Linux. --- gc/boehm/typeinfo.cpp | 129 +++++++++++++++++++++++++++++++----------- 1 file changed, 97 insertions(+), 32 deletions(-) diff --git a/gc/boehm/typeinfo.cpp b/gc/boehm/typeinfo.cpp index f429d6f9cf9..cdaac6246da 100644 --- a/gc/boehm/typeinfo.cpp +++ b/gc/boehm/typeinfo.cpp @@ -1,59 +1,124 @@ /* - typeinfo.cpp + typeinfo.cpp - Speculatively use RTTI on a random object. If it contains a pointer at offset 0 - that is in the current process' address space, and that so on, then attempt to - use C++ RTTI's typeid operation to obtain the name of the type. - - by Patrick C. Beard. + Speculatively use RTTI on a random object. If it contains a pointer at offset 0 + that is in the current process' address space, and that so on, then attempt to + use C++ RTTI's typeid operation to obtain the name of the type. + + by Patrick C. Beard. */ #include #include -#include + +#include "gcconfig.h" extern "C" const char* getTypeName(void* ptr); +class IUnknown { +public: + virtual long QueryInterface() = 0; + virtual long AddRef() = 0; + virtual long Release() = 0; +}; + +#if defined(MACOS) + +#include + class AddressSpace { public: - AddressSpace(); - Boolean contains(void* ptr); + AddressSpace(); + Boolean contains(void* ptr); private: - ProcessInfoRec mInfo; + ProcessInfoRec mInfo; }; AddressSpace::AddressSpace() { - ProcessSerialNumber psn = { 0, kCurrentProcess }; - mInfo.processInfoLength = sizeof(mInfo); - ::GetProcessInformation(&psn, &mInfo); + ProcessSerialNumber psn = { 0, kCurrentProcess }; + mInfo.processInfoLength = sizeof(mInfo); + ::GetProcessInformation(&psn, &mInfo); } Boolean AddressSpace::contains(void* ptr) { - UInt32 start = UInt32(mInfo.processLocation); - return (UInt32(ptr) >= start && UInt32(ptr) < (start + mInfo.processSize)); + UInt32 start = UInt32(mInfo.processLocation); + return (UInt32(ptr) >= start && UInt32(ptr) < (start + mInfo.processSize)); } -class IUnknown { - virtual long QueryInterface() = 0; - virtual long AddRef() = 0; - virtual long Release() = 0; -}; - const char* getTypeName(void* ptr) { - // construct only one of these per process. - static AddressSpace space; + // construct only one of these per process. + static AddressSpace space; - // sanity check the vtable pointer, before trying to use RTTI on the object. - void** vt = *(void***)ptr; - if (space.contains(vt) && space.contains(*vt)) { - IUnknown* u = static_cast(ptr); - const char* type = typeid(*u).name(); + // sanity check the vtable pointer, before trying to use RTTI on the object. + void** vt = *(void***)ptr; + if (vt && !(unsigned(vt) & 0x3) && space.contains(vt) && space.contains(*vt)) { + IUnknown* u = static_cast(ptr); + const char* type = typeid(*u).name(); // make sure it looks like a C++ identifier. - if (type && (isalnum(type[0]) || type[0] == '_')) - return type; - } - return "void*"; + if (type && (isalnum(type[0]) || type[0] == '_')) + return type; + } + return "void*"; } + +#endif + +#if defined(LINUX) + +#include +#include + +static jmp_buf context; + +static void handler(int signum) +{ + longjmp(context, signum); +} + +#define attempt() setjmp(context) + +class Signaller { +public: + Signaller(int signum); + ~Signaller(); + +private: + typedef void (*handler_t) (int signum); + int mSignal; + handler_t mOldHandler; +}; + +Signaller::Signaller(int signum) + : mSignal(signum), mOldHandler(signal(signum, &handler)) +{ +} + +Signaller::~Signaller() +{ + signal(mSignal, mOldHandler); +} + +const char* getTypeName(void* ptr) +{ + // sanity check the vtable pointer, before trying to use RTTI on the object. + void** vt = *(void***)ptr; + if (vt && !(unsigned(vt) & 3)) { + Signaller signaller(SIGSEGV); + if (attempt() == 0) { + IUnknown* u = static_cast(ptr); + const char* type = typeid(*u).name(); + // make sure it looks like a C++ identifier. + if (type && (isalnum(type[0]) || type[0] == '_')) { + // ECGS seems to prefix a length string. + while (isdigit(*type)) ++type; + return type; + } + } + } + return "void*"; +} + +#endif