From 15394881a8c01f82f125af797a5c63cd40c71527 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 4 Jun 2009 01:47:05 +0000 Subject: [PATCH] * Implemented demangling support for the current gcc ABI. Looks good so far save for the additional '&'/'*' print_demangled_call() is printing for reference/pointer arguments. * Moved the new demangler and the gcc 2 demangler into the same module always supporting both (the right one is chosen). In mixed gcc 2/gcc 4 environments we obviously need both of them. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30954 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- build/jam/HaikuImage | 9 +- src/add-ons/kernel/debugger/demangle/Jamfile | 32 +- .../kernel/debugger/demangle/demangle.cpp | 84 + .../kernel/debugger/demangle/demangle.h | 27 + src/add-ons/kernel/debugger/demangle/gcc2.cpp | 41 +- .../kernel/debugger/demangle/gcc3+.cpp | 3994 ++++++++++++++++- 6 files changed, 3966 insertions(+), 221 deletions(-) create mode 100644 src/add-ons/kernel/debugger/demangle/demangle.cpp create mode 100644 src/add-ons/kernel/debugger/demangle/demangle.h diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 4e5b64072c..7361b82a3c 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -183,8 +183,8 @@ AddFilesToHaikuImage system add-ons kernel busses usb : uhci ohci ehci ; AddFilesToHaikuImage system add-ons kernel console : vga_text ; AddFilesToHaikuImage system add-ons kernel debugger - : $(X86_ONLY)disasm hangman invalidate_on_exit - usb_keyboard run_on_exit ; + : demangle $(X86_ONLY)disasm hangman + invalidate_on_exit usb_keyboard run_on_exit ; AddFilesToHaikuImage system add-ons kernel file_systems : $(SYSTEM_ADD_ONS_FILE_SYSTEMS) ; AddFilesToHaikuImage system add-ons kernel generic @@ -197,11 +197,6 @@ AddFilesToHaikuImage system add-ons kernel interrupt_controllers if $(TARGET_ARCH) = x86 { AddFilesToHaikuImage system add-ons kernel cpu : generic_x86 ; - - if $(HAIKU_GCC_VERSION[1]) = 2 { - AddFilesToHaikuImage system add-ons kernel debugger demangle : - gcc2 ; - } } # drivers diff --git a/src/add-ons/kernel/debugger/demangle/Jamfile b/src/add-ons/kernel/debugger/demangle/Jamfile index 48149b6610..96b3ef5148 100644 --- a/src/add-ons/kernel/debugger/demangle/Jamfile +++ b/src/add-ons/kernel/debugger/demangle/Jamfile @@ -2,34 +2,8 @@ SubDir HAIKU_TOP src add-ons kernel debugger demangle ; UsePrivateHeaders kernel ; -# GCC3/4 only solution (using parts of libsubc++) -if $(HAIKU_GCC_VERSION[1]) >= 3 { - rule ExtractObject - { - SetupKernel $(2) ; - Depends $(1) : $(2) ; - Objects $(1) ; - - MakeLocateDebug $(1) ; - } - - actions ExtractObject - { - #$(TARGET_AR) $(LINKFLAGS) -o "$(1)" "$(2)" $(LINKLIBS) ; - pwd - echo $(TARGET_AR) -x "$(2)" "$(1)" - } - - ExtractObject cp-demangle.o : $(TARGET_STATIC_LIBSUPC++) foo ; - - KernelAddon gcc3+ : - gcc3+.cpp - cp-demangle.o - ; -} - -# GCC2 solution - -KernelAddon gcc2 : +KernelAddon demangle : + demangle.cpp gcc2.cpp + gcc3+.cpp ; diff --git a/src/add-ons/kernel/debugger/demangle/demangle.cpp b/src/add-ons/kernel/debugger/demangle/demangle.cpp new file mode 100644 index 0000000000..cf9919125f --- /dev/null +++ b/src/add-ons/kernel/debugger/demangle/demangle.cpp @@ -0,0 +1,84 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "demangle.h" + +#include + +#include + + +static inline bool +looks_like_gcc3_symbol(const char* symbol) +{ + return strncmp(symbol, "_Z", 2) == 0; +} + + +static const char* +demangle_symbol(const char* mangledName, char* buffer, size_t bufferSize, + bool* _isObjectMethod) +{ + // try the gcc3 demangler, if it looks like a gcc3 symbol + const char* demangled = NULL; + if (looks_like_gcc3_symbol(mangledName)) { + demangled = demangle_symbol_gcc3(mangledName, buffer, bufferSize, + _isObjectMethod); + if (demangled != NULL) + return demangled; + } + + // fallback is gcc2 + return demangle_symbol_gcc2(mangledName, buffer, bufferSize, + _isObjectMethod); +} + + +static status_t +get_next_argument(uint32* _cookie, const char* mangledName, char* name, + size_t nameSize, int32* _type, size_t* _argumentLength) +{ + // try the gcc3 demangler, if it looks like a gcc3 symbol + if (looks_like_gcc3_symbol(mangledName)) { + status_t error = get_next_argument_gcc3(_cookie, mangledName, name, + nameSize, _type, _argumentLength); + if (error == B_OK) + return B_OK; + } + + // fallback is gcc2 + return get_next_argument_gcc2(_cookie, mangledName, name, nameSize, _type, + _argumentLength); +} + + +static status_t +std_ops(int32 op, ...) +{ + switch (op) { + case B_MODULE_INIT: + case B_MODULE_UNINIT: + return B_OK; + } + + return B_BAD_VALUE; +} + + +static struct debugger_demangle_module_info sModuleInfo = { + { + "debugger/demangle/v1", + 0, + std_ops + }, + + demangle_symbol, + get_next_argument, +}; + +module_info* modules[] = { + (module_info*)&sModuleInfo, + NULL +}; diff --git a/src/add-ons/kernel/debugger/demangle/demangle.h b/src/add-ons/kernel/debugger/demangle/demangle.h new file mode 100644 index 0000000000..b3c4237723 --- /dev/null +++ b/src/add-ons/kernel/debugger/demangle/demangle.h @@ -0,0 +1,27 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef DEMANGLE_H +#define DEMANGLE_H + +#include + + +// gcc 2 +const char* demangle_symbol_gcc2(const char* name, char* buffer, + size_t bufferSize, bool* _isObjectMethod); +status_t get_next_argument_gcc2(uint32* _cookie, const char* symbol, + char* name, size_t nameSize, int32* _type, + size_t* _argumentLength); + + +// gcc 3+ +const char* demangle_symbol_gcc3(const char* name, char* buffer, + size_t bufferSize, bool* _isObjectMethod); +status_t get_next_argument_gcc3(uint32* _cookie, const char* symbol, + char* name, size_t nameSize, int32* _type, + size_t* _argumentLength); + + +#endif // DEMANGLE_H diff --git a/src/add-ons/kernel/debugger/demangle/gcc2.cpp b/src/add-ons/kernel/debugger/demangle/gcc2.cpp index 6ef6686bd3..4b9acec12d 100644 --- a/src/add-ons/kernel/debugger/demangle/gcc2.cpp +++ b/src/add-ons/kernel/debugger/demangle/gcc2.cpp @@ -12,6 +12,8 @@ #include +#include "demangle.h" + //#define TRACE_GCC2_DEMANGLER #ifdef TRACE_GCC2_DEMANGLER @@ -420,7 +422,7 @@ get_next_argument_internal(uint32* _cookie, const char* symbol, char* name, const char* -demangle_symbol(const char* name, char* buffer, size_t bufferSize, +demangle_symbol_gcc2(const char* name, char* buffer, size_t bufferSize, bool* _isObjectMethod) { size_t nameLength; @@ -467,44 +469,9 @@ demangle_symbol(const char* name, char* buffer, size_t bufferSize, status_t -get_next_argument(uint32* _cookie, const char* symbol, char* name, +get_next_argument_gcc2(uint32* _cookie, const char* symbol, char* name, size_t nameSize, int32* _type, size_t* _argumentLength) { return get_next_argument_internal(_cookie, symbol, name, nameSize, _type, _argumentLength, false); } - - -static status_t -std_ops(int32 op, ...) -{ -#if __GNUC__ != 2 - return B_NOT_SUPPORTED; -#else - switch (op) { - case B_MODULE_INIT: - case B_MODULE_UNINIT: - return B_OK; - } - - return B_BAD_VALUE; -#endif -} - - -static struct debugger_demangle_module_info sModuleInfo = { - { - "debugger/demangle/gcc2/v1", - 0, - std_ops - }, - - demangle_symbol, - get_next_argument, -}; - -module_info *modules[] = { - (module_info *)&sModuleInfo, - NULL -}; - diff --git a/src/add-ons/kernel/debugger/demangle/gcc3+.cpp b/src/add-ons/kernel/debugger/demangle/gcc3+.cpp index 238867ee0d..590de881f0 100644 --- a/src/add-ons/kernel/debugger/demangle/gcc3+.cpp +++ b/src/add-ons/kernel/debugger/demangle/gcc3+.cpp @@ -1,174 +1,3872 @@ /* - * Copyright 2008, François Revol, revol@free.fr + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #include -#include +#include +#include #include #include -#include +#include -#define DEMANGLE_BUFFER_SIZE (16*1024) -static char sDemangleBuffer[DEMANGLE_BUFFER_SIZE]; +#include -extern "C" void set_debug_demangle_hook(const char *(*demangle_hook)(const char *)); +#include -/* gcc's __cxa_demangle calls malloc and friends... - * we don't want to let it call the real one from inside the kernel debugger... - * instead we just return it a static buffer. - */ - -void * -malloc(size_t len) -{ - if (len < DEMANGLE_BUFFER_SIZE) - return sDemangleBuffer; - return NULL; -} +#include "demangle.h" -void -free(void *ptr) -{ -} +// C++ ABI: http://www.codesourcery.com/public/cxx-abi/abi.html -void * -realloc(void * oldPtr, size_t newSize) -{ - return NULL; -} +//#define TRACE_GCC3_DEMANGLER +#ifdef TRACE_GCC3_DEMANGLER +# define TRACE(x...) PRINT(x) +# define DEBUG_SCOPE(name) DebugScope debug(name, fInput.String()) +#else +# define TRACE(x...) ; +# define DEBUG_SCOPE(name) do {} while (false) +#endif - -/* doesn't work, va_list sux... */ -#if 0 -class DemangleDebugOutputFilter : public DebugOutputFilter { -public: - DemangleDebugOutputFilter(); - virtual ~DemangleDebugOutputFilter(); - void SetChain(DebugOutputFilter *chain); - virtual void PrintString(const char* string); - virtual void Print(const char* format, va_list args); -private: - DebugOutputFilter *fChained; -}; - - -DemangleDebugOutputFilter::DemangleDebugOutputFilter() -{ -} - - -DemangleDebugOutputFilter::~DemangleDebugOutputFilter() -{ -} - - -void -DemangleDebugOutputFilter::SetChain(DebugOutputFilter *chain) -{ - fChained = chain; -} - - -void -DemangleDebugOutputFilter::PrintString(const char* string) -{ - fChained->PrintString(string); -} - - -void -DemangleDebugOutputFilter::Print(const char* format, va_list args) -{ - int i; - const char *p = format; - while ((p = strchr(p, '%'))) { - if (p[1] == '%') { - p+=2; - continue; - } - p++; - while (*p && !isalpha(*p)) - p++; - switch (*p) { - case 's': - { - const char **ptr = &va_arg(args, char *); - //char *symbol = va_arg(args, char *); - char *symbol = *ptr; - char *demangled; - size_t length = DEMANGLE_BUFFER_SIZE; - int status; - - demangled = abi::__cxa_demangle(symbol, sDemangleBuffer, &length, &status); - if (status > 0) { - } - break; - } - case 'd': - case 'i': - { - int d; - d = va_arg(args, int); - break; - } - case 'L': - { - long long d; - d = va_arg(args, long long); - break; - } - case 'f': - { - float f; - f = va_arg(args, float); - break; - } - case '\0': - break; - default: - panic("unknown printf format\n"); - break; - } - i++; - } - fChained->Print(format, args); -} +#ifdef _KERNEL_MODE +# define PRINT(format...) kprintf(format) +# define VPRINT(format, args) PRINT("%s", format) + // no vkprintf() +# define NEW(constructor) new(kdebug_alloc) constructor +# define DELETE(object) DebugAlloc::destroy(object) +#else +# define PRINT(format...) printf(format) +# define VPRINT(format, args) vprintf(format, args) +# define NEW(constructor) new(std::nothrow) constructor +# define DELETE(object) delete object #endif -static const char * -demangle_symbol(const char *sym, char* buffer, size_t bufferSize, - bool* _isObjectMethod) -{ - char *demangled; - size_t length = DEMANGLE_BUFFER_SIZE; - int status; +typedef long number_type; - demangled = abi::__cxa_demangle(sym, sDemangleBuffer, &length, &status); - if (status == 0) - return demangled; - // something bad happened - return sym; +enum { + ERROR_OK = 0, + ERROR_NOT_MANGLED, + ERROR_UNSUPPORTED, + ERROR_INVALID, + ERROR_BUFFER_TOO_SMALL, + ERROR_NO_MEMORY, + ERROR_INTERNAL, + ERROR_INVALID_PARAMETER_INDEX +}; + +// object classification +enum object_type { + OBJECT_TYPE_UNKNOWN, + OBJECT_TYPE_DATA, + OBJECT_TYPE_FUNCTION, + OBJECT_TYPE_METHOD_CLASS, + OBJECT_TYPE_METHOD_OBJECT, + OBJECT_TYPE_METHOD_UNKNOWN +}; + +// prefix classification +enum prefix_type { + PREFIX_NONE, + PREFIX_NAMESPACE, + PREFIX_CLASS, + PREFIX_UNKNOWN +}; + +// type classification +enum type_type { + TYPE_ELLIPSIS, + TYPE_VOID, + TYPE_WCHAR_T, + TYPE_BOOL, + TYPE_CHAR, + TYPE_SIGNED_CHAR, + TYPE_UNSIGNED_CHAR, + TYPE_SHORT, + TYPE_UNSIGNED_SHORT, + TYPE_INT, + TYPE_UNSIGNED_INT, + TYPE_LONG, + TYPE_UNSIGNED_LONG, + TYPE_LONG_LONG, + TYPE_UNSIGNED_LONG_LONG, + TYPE_INT128, + TYPE_UNSIGNED_INT128, + TYPE_FLOAT, + TYPE_DOUBLE, + TYPE_LONG_DOUBLE, + TYPE_FLOAT128, + TYPE_DFLOAT16, + TYPE_DFLOAT32, + TYPE_DFLOAT64, + TYPE_DFLOAT128, + TYPE_CHAR16_T, + TYPE_CHAR32_T, + + TYPE_UNKNOWN, + TYPE_CONST_CHAR_POINTER, + TYPE_POINTER, + TYPE_REFERENCE +}; + +const char* const kTypeNames[] = { + "...", + "void", + "wchar_t", + "bool", + "char", + "signed char", + "unsigned char", + "short", + "unsigned short", + "int", + "unsigned int", + "long", + "unsigned long", + "long long", + "unsigned long long", + "__int128", + "unsigned __int128", + "float", + "double", + "long double", + "__float128", + "__dfloat16", // TODO: Official names for the __dfloat*! + "__dfloat32", + "__dfloat64", + "__dfloat64", + "char16_t", + "char32_t", + + "?", + "char const*", + "void*", + "void&" +}; + + +// CV qualifier flags +enum { + CV_QUALIFIER_RESTRICT = 0x1, + CV_QUALIFIER_VOLATILE = 0x2, + CV_QUALIFIER_CONST = 0x4 +}; + +enum type_modifier { + TYPE_QUALIFIER_POINTER = 0, + TYPE_QUALIFIER_REFERENCE, + TYPE_QUALIFIER_RVALUE_REFERENCE, + TYPE_QUALIFIER_COMPLEX, + TYPE_QUALIFIER_IMAGINARY +}; + +static const char* const kTypeModifierSuffixes[] = { + "*", + "&", + "&&", + " complex", + " imaginary" +}; + +struct operator_info { + const char* mangled_name; + const char* name; + int argument_count; + int flags; +}; + +// operator flags +enum { + OPERATOR_TYPE_PARAM = 0x01, + OPERATOR_IS_MEMBER = 0x02 +}; + + +static const operator_info kOperatorInfos[] = { + { "nw", "new", -1, OPERATOR_IS_MEMBER }, + { "na", "new[]", -1, OPERATOR_IS_MEMBER }, + { "dl", "delete", -1, OPERATOR_IS_MEMBER }, + { "da", "delete[]", -1, OPERATOR_IS_MEMBER }, + { "ps", "+", 1, 0 }, // unary + { "ng", "-", 1, 0 }, // unary + { "ad", "&", 1, 0 }, // unary + { "de", "*", 1, 0 }, // unary + { "co", "~", 1, 0 }, + { "pl", "+", 2, 0 }, + { "mi", "-", 2, 0 }, + { "ml", "*", 2, 0 }, + { "dv", "/", 2, 0 }, + { "rm", "%", 2, 0 }, + { "an", "&", 2, 0 }, + { "or", "|", 2, 0 }, + { "eo", "^", 2, 0 }, + { "aS", "=", 2, 0 }, + { "pL", "+=", 2, 0 }, + { "mI", "-=", 2, 0 }, + { "mL", "*=", 2, 0 }, + { "dV", "/=", 2, 0 }, + { "rM", "%=", 2, 0 }, + { "aN", "&=", 2, 0 }, + { "oR", "|=", 2, 0 }, + { "eO", "^=", 2, 0 }, + { "ls", "<<", 2, 0 }, + { "rs", ">>", 2, 0 }, + { "lS", "<<=", 2, 0 }, + { "rS", ">>=", 2, 0 }, + { "eq", "==", 2, 0 }, + { "ne", "!=", 2, 0 }, + { "lt", "<", 2, 0 }, + { "gt", ">", 2, 0 }, + { "le", "<=", 2, 0 }, + { "ge", ">=", 2, 0 }, + { "nt", "!", 1, 0 }, + { "aa", "&&", 2, 0 }, + { "oo", "||", 2, 0 }, + { "pp", "++", 1, 0 }, + { "mm", "--", 1, 0 }, + { "cm", ",", -1, 0 }, + { "pm", "->*", 2, 0 }, + { "pt", "->", 2, 0 }, + { "cl", "()", -1, 0 }, + { "ix", "[]", -1, 0 }, + { "qu", "?", 3, 0 }, + { "st", "sizeof", 1, OPERATOR_TYPE_PARAM }, // type + { "sz", "sizeof", 1, 0 }, // expression + { "at", "alignof", 1, OPERATOR_TYPE_PARAM }, // type + { "az", "alignof", 1, 0 }, // expression + {} +}; + + +#ifdef TRACE_GCC3_DEMANGLER + +struct DebugScope { + DebugScope(const char* functionName, const char* remainingString = NULL) + : + fParent(sGlobalScope), + fFunctionName(functionName), + fLevel(fParent != NULL ? fParent->fLevel + 1 : 0) + { + sGlobalScope = this; + if (remainingString != NULL) { + PRINT("%*s%s(): \"%s\"\n", fLevel * 2, "", fFunctionName, + remainingString); + } else + PRINT("%*s%s()\n", fLevel * 2, "", fFunctionName); + } + + ~DebugScope() + { + sGlobalScope = fParent; + PRINT("%*s%s() done\n", fLevel * 2, "", fFunctionName); + } + + static void Print(const char* format,...) + { + int level = sGlobalScope != NULL ? sGlobalScope->fLevel : 0; + + va_list args; + va_start(args, format); + PRINT("%*s", (level + 1) * 2, ""); + VPRINT(format, args); + va_end(args); + } + +private: + DebugScope* fParent; + const char* fFunctionName; + int fLevel; + + static DebugScope* sGlobalScope; +}; + +DebugScope* DebugScope::sGlobalScope = NULL; + +#endif // TRACE_GCC3_DEMANGLER + + +class Input { +public: + Input() + : + fString(NULL), + fLength(0) + { + } + + void SetTo(const char* string, size_t length) + { + fString = string; + fLength = length; + } + + const char* String() const + { + return fString; + } + + int CharsRemaining() const + { + return fLength; + } + + void Skip(size_t count) + { + if (count > fLength) { + PRINT("Input::Skip(): fOffset > fLength\n"); + return; + } + + fString += count; + fLength -= count; + } + + bool HasPrefix(char prefix) const + { + return fLength > 0 && fString[0] == prefix; + } + + bool HasPrefix(const char* prefix) const + { + size_t prefixLen = strlen(prefix); + return prefixLen <= fLength + && strncmp(fString, prefix, strlen(prefix)) == 0; + } + + bool SkipPrefix(char prefix) + { + if (!HasPrefix(prefix)) + return false; + + fString++; + fLength--; + return true; + } + + bool SkipPrefix(const char* prefix) + { + size_t prefixLen = strlen(prefix); + if (prefixLen <= fLength && strncmp(fString, prefix, prefixLen) != 0) + return false; + + fString += prefixLen; + fLength -= prefixLen; + return true; + } + + char operator[](size_t index) const + { + if (index >= fLength) { + PRINT("Input::operator[](): fOffset + index >= fLength\n"); + return '\0'; + } + + return fString[index]; + } + +private: + const char* fString; + size_t fLength; +}; + + +class NameBuffer { +public: + NameBuffer(char* buffer, size_t size) + : + fBuffer(buffer), + fSize(size), + fLength(0), + fOverflow(false) + { + } + + bool IsEmpty() const + { + return fLength == 0; + } + + char LastChar() const + { + return fLength > 0 ? fBuffer[fLength - 1] : '\0'; + } + + bool HadOverflow() const + { + return fOverflow; + } + + char* Terminate() + { + fBuffer[fLength] = '\0'; + return fBuffer; + } + + bool Append(const char* string, size_t length) + { + if (fLength + length >= fSize) { + fOverflow = true; + return false; + } + + memcpy(fBuffer + fLength, string, length); + fLength += length; + return true; + } + + bool Append(const char* string) + { + return Append(string, strlen(string)); + } + +private: + char* fBuffer; + size_t fSize; + size_t fLength; + bool fOverflow; +}; + + +struct TypeInfo { + type_type type; + int cvQualifiers; + + TypeInfo() + : + type(TYPE_UNKNOWN), + cvQualifiers(0) + { + } + + TypeInfo(type_type type) + : + type(type), + cvQualifiers(0) + { + } + + TypeInfo(const TypeInfo& other, int cvQualifiers = 0) + : + type(other.type), + cvQualifiers(other.cvQualifiers | cvQualifiers) + { + } + + TypeInfo& operator=(const TypeInfo& other) + { + type = other.type; + cvQualifiers = other.cvQualifiers; + return *this; + } +}; + + +struct DemanglingParameters { + bool objectNameOnly; + + DemanglingParameters(bool objectNameOnly) + : + objectNameOnly(objectNameOnly) + { + } +}; + + +struct DemanglingInfo : DemanglingParameters { + object_type objectType; + + DemanglingInfo(bool objectNameOnly) + : + DemanglingParameters(objectNameOnly), + objectType(OBJECT_TYPE_UNKNOWN) + { + } +}; + + +struct ParameterInfo { + TypeInfo type; + + ParameterInfo() + { + } +}; + + +class Node; + +struct NameDecorationInfo { + const Node* firstDecorator; + const Node* closestCVDecoratorList; + + NameDecorationInfo(const Node* decorator) + : + firstDecorator(decorator), + closestCVDecoratorList(NULL) + { + } +}; + +struct CVQualifierInfo { + const Node* firstCVQualifier; + const Node* firstNonCVQualifier; + + CVQualifierInfo() + : + firstCVQualifier(NULL), + firstNonCVQualifier(NULL) + { + } +}; + + +class Node { +public: + Node() + : + fNextAllocated(NULL), + fParent(NULL), + fNext(NULL), + fNextReferenceable(NULL), + fReferenceable(true) + { + } + + virtual ~Node() + { + } + + Node* NextAllocated() const { return fNextAllocated; } + void SetNextAllocated(Node* node) { fNextAllocated = node; } + + Node* Parent() const { return fParent; } + virtual void SetParent(Node* node) { fParent = node; } + + Node* Next() const { return fNext; } + void SetNext(Node* node) { fNext = node; } + + bool IsReferenceable() const { return fReferenceable; } + void SetReferenceable(bool flag) { fReferenceable = flag; } + + Node* NextReferenceable() const { return fNextReferenceable; } + void SetNextReferenceable(Node* node) { fNextReferenceable = node; } + + virtual bool GetName(NameBuffer& buffer) const = 0; + + virtual bool GetDecoratedName(NameBuffer& buffer, + NameDecorationInfo& decorationInfo) const + { + if (!GetName(buffer)) + return false; + + return decorationInfo.firstDecorator == NULL + || decorationInfo.firstDecorator->AddDecoration(buffer, NULL); + } + + virtual bool AddDecoration(NameBuffer& buffer, + const Node* stopDecorator) const + { + return true; + } + + virtual void GetCVQualifierInfo(CVQualifierInfo& info) const + { + info.firstNonCVQualifier = this; + } + + virtual Node* GetUnqualifiedNode(Node* beforeNode) + { + return this; + } + + virtual bool IsTemplatized() const + { + return false; + } + + virtual Node* TemplateParameterAt(int index) const + { + return NULL; + } + + virtual bool IsNoReturnValueFunction() const + { + return false; + } + + virtual bool IsTypeName(const char* name, size_t length) const + { + return false; + } + + virtual object_type ObjectType() const + { + return OBJECT_TYPE_UNKNOWN; + } + + virtual prefix_type PrefixType() const + { + return PREFIX_NONE; + } + + virtual TypeInfo Type() const + { + return TypeInfo(); + } + +private: + Node* fNextAllocated; + Node* fParent; + Node* fNext; + Node* fNextReferenceable; + bool fReferenceable; +}; + + +class NamedTypeNode : public Node { +public: + NamedTypeNode(Node* name) + : + fName(name) + { + if (fName != NULL) + fName->SetParent(this); + } + + virtual bool GetName(NameBuffer& buffer) const + { + return fName == NULL || fName->GetName(buffer); + } + + virtual bool IsNoReturnValueFunction() const + { + return fName != NULL && fName->IsNoReturnValueFunction(); + } + + virtual TypeInfo Type() const + { + return fName != NULL ? fName->Type() : TypeInfo(); + } + +protected: + Node* fName; +}; + + +class SubstitutionNode : public Node { +public: + SubstitutionNode(Node* node) + : + fNode(node) + { + } + + virtual bool GetName(NameBuffer& buffer) const + { + return fNode->GetName(buffer); + } + + virtual bool GetDecoratedName(NameBuffer& buffer, + NameDecorationInfo& decorationInfo) const + { + return fNode->GetDecoratedName(buffer, decorationInfo); + } + + virtual bool AddDecoration(NameBuffer& buffer, + const Node* stopDecorator) const + { + return fNode->AddDecoration(buffer, stopDecorator); + } + + virtual void GetCVQualifierInfo(CVQualifierInfo& info) const + { + fNode->GetCVQualifierInfo(info); + } + + virtual bool IsTemplatized() const + { + return fNode->IsTemplatized(); + } + + virtual Node* TemplateParameterAt(int index) const + { + return fNode->TemplateParameterAt(index); + } + + virtual bool IsNoReturnValueFunction() const + { + return fNode->IsNoReturnValueFunction(); + } + + virtual bool IsTypeName(const char* name, size_t length) const + { + return fNode->IsTypeName(name, length); + } + + virtual object_type ObjectType() const + { + return fNode->ObjectType(); + } + + virtual prefix_type PrefixType() const + { + return fNode->PrefixType(); + } + + virtual TypeInfo Type() const + { + return fNode->Type(); + } + +private: + Node* fNode; +}; + + +class ArrayNode : public NamedTypeNode { +public: + ArrayNode(Node* type, int dimension) + : + NamedTypeNode(type), + fDimensionExpression(NULL), + fDimensionNumber(dimension) + { + } + + ArrayNode(Node* type, Node* dimension) + : + NamedTypeNode(type), + fDimensionExpression(dimension), + fDimensionNumber(0) + { + fDimensionExpression->SetParent(this); + } + + virtual bool GetName(NameBuffer& buffer) const + { + if (!fName->GetName(buffer)) + return false; + + buffer.Append("[", 1); + + if (fDimensionExpression != NULL) { + if (!fDimensionExpression->GetName(buffer)) + return false; + } else { + char stringBuffer[16]; + snprintf(stringBuffer, sizeof(stringBuffer), "%d", + fDimensionNumber); + buffer.Append(stringBuffer); + } + + return buffer.Append("]", 1); + } + + virtual object_type ObjectType() const + { + return OBJECT_TYPE_DATA; + } + + virtual TypeInfo Type() const + { +// TODO: Check! + return TypeInfo(TYPE_POINTER); + } + + +private: + Node* fDimensionExpression; + int fDimensionNumber; +}; + + +class ObjectNode : public NamedTypeNode { +public: + ObjectNode(Node* name) + : + NamedTypeNode(name) + { + } + + virtual bool GetObjectName(NameBuffer& buffer, + const DemanglingParameters& parameters) + { + if (parameters.objectNameOnly) + return fName != NULL ? fName->GetName(buffer) : true; + + return GetName(buffer); + } + + virtual object_type ObjectType() const + { + return OBJECT_TYPE_DATA; + } + + virtual Node* ParameterAt(uint32 index) const + { + return NULL; + } +}; + + +class SimpleNameNode : public Node { +public: + SimpleNameNode(const char* name) + : + fName(name), + fLength(strlen(name)) + { + } + + SimpleNameNode(const char* name, size_t length) + : + fName(name), + fLength(length) + { + } + + virtual bool GetName(NameBuffer& buffer) const + { + return buffer.Append(fName, fLength); + } + +protected: + const char* fName; + size_t fLength; +}; + + +class SimpleTypeNode : public SimpleNameNode { +public: + SimpleTypeNode(const char* name) + : + SimpleNameNode(name), + fType(TYPE_UNKNOWN) + { + } + + SimpleTypeNode(type_type type) + : + SimpleNameNode(kTypeNames[type]), + fType(type) + { + } + + virtual bool IsTypeName(const char* name, size_t length) const + { + return fLength == length && strcmp(fName, name) == 0; + } + + virtual object_type ObjectType() const + { + return OBJECT_TYPE_DATA; + } + + virtual TypeInfo Type() const + { + return TypeInfo(fType); + } + +private: + type_type fType; +}; + + +class TypedNumberLiteralNode : public Node { +public: + TypedNumberLiteralNode(Node* type, const char* number, size_t length) + : + fType(type), + fNumber(number), + fLength(length) + { + fType->SetParent(this); + } + + virtual bool GetName(NameBuffer& buffer) const + { + // If the type is bool and the number is 0 or 1, we use "false" or + // "true" respectively. + if (fType->IsTypeName("bool", 4) && fLength == 1 + && (fNumber[0] == '0' || fNumber[0] == '1')) { + return buffer.Append(fNumber[0] == '0' ? "false" : "true"); + } + + // Add the type in parentheses. The GNU demangler omits "int", so do we. + if (!fType->IsTypeName("int", 3)) { + buffer.Append("("); + if (!fType->GetName(buffer)) + return false; + buffer.Append(")"); + } + + // add the number -- replace a leading 'n' by '-', if necessary + if (fLength > 0 && fNumber[0] == 'n') { + buffer.Append("-"); + return buffer.Append(fNumber + 1, fLength - 1); + } + + return buffer.Append(fNumber, fLength); + } + + virtual object_type ObjectType() const + { + return OBJECT_TYPE_DATA; + } + +private: + Node* fType; + const char* fNumber; + size_t fLength; +}; + + +class XtructorNode : public Node { +public: + XtructorNode(bool constructor, char type) + : + fConstructor(constructor), + fType(type) + { + } + + virtual void SetParent(Node* node) + { + fUnqualifiedNode = node->GetUnqualifiedNode(this); + Node::SetParent(node); + } + + virtual bool GetName(NameBuffer& buffer) const + { + if (fUnqualifiedNode == NULL) + return false; + + if (!fConstructor) + buffer.Append("~"); + + return fUnqualifiedNode->GetName(buffer); + } + + virtual bool IsNoReturnValueFunction() const + { + return true; + } + + virtual object_type ObjectType() const + { + return OBJECT_TYPE_METHOD_CLASS; + } + +private: + bool fConstructor; + char fType; + Node* fUnqualifiedNode; +}; + + +class SpecialNameNode : public Node { +public: + SpecialNameNode(const char* name, Node* child) + : + fName(name), + fChild(child) + { + fChild->SetParent(this); + } + + virtual bool GetName(NameBuffer& buffer) const + { + return buffer.Append(fName) && fChild->GetName(buffer); + } + +protected: + const char* fName; + Node* fChild; +}; + + +class DecoratingNode : public Node { +public: + DecoratingNode(Node* child) + : + fChildNode(child) + { + fChildNode->SetParent(this); + } + + virtual bool GetName(NameBuffer& buffer) const + { + NameDecorationInfo decorationInfo(this); + return fChildNode->GetDecoratedName(buffer, decorationInfo); + } + + virtual bool GetDecoratedName(NameBuffer& buffer, + NameDecorationInfo& decorationInfo) const + { + decorationInfo.closestCVDecoratorList = NULL; + return fChildNode->GetDecoratedName(buffer, decorationInfo); + } + +protected: + Node* fChildNode; +}; + + +class CVQualifiersNode : public DecoratingNode { +public: + CVQualifiersNode(int qualifiers, Node* child) + : + DecoratingNode(child), + fCVQualifiers(qualifiers) + { + } + + virtual bool GetDecoratedName(NameBuffer& buffer, + NameDecorationInfo& decorationInfo) const + { + if (decorationInfo.closestCVDecoratorList == NULL) + decorationInfo.closestCVDecoratorList = this; + return fChildNode->GetDecoratedName(buffer, decorationInfo); + } + + virtual bool AddDecoration(NameBuffer& buffer, + const Node* stopDecorator) const + { + if (this == stopDecorator) + return true; + + if (!fChildNode->AddDecoration(buffer, stopDecorator)) + return false; + + if ((fCVQualifiers & CV_QUALIFIER_RESTRICT) != 0) + buffer.Append(" restrict"); + if ((fCVQualifiers & CV_QUALIFIER_VOLATILE) != 0) + buffer.Append(" volatile"); + if ((fCVQualifiers & CV_QUALIFIER_CONST) != 0) + buffer.Append(" const"); + + return true; + } + + virtual void GetCVQualifierInfo(CVQualifierInfo& info) const + { + if (info.firstCVQualifier == NULL) + info.firstCVQualifier = this; + fChildNode->GetCVQualifierInfo(info); + } + + virtual bool IsTemplatized() const + { + return fChildNode->IsTemplatized(); + } + + virtual Node* TemplateParameterAt(int index) const + { + return fChildNode->TemplateParameterAt(index); + } + + virtual bool IsNoReturnValueFunction() const + { + return fChildNode->IsNoReturnValueFunction(); + } + + virtual object_type ObjectType() const + { + return fChildNode->ObjectType(); + } + + virtual prefix_type PrefixType() const + { + return fChildNode->PrefixType(); + } + + virtual TypeInfo Type() const + { + return TypeInfo(fChildNode->Type(), fCVQualifiers); + } + +private: + int fCVQualifiers; +}; + + +class TypeModifierNode : public DecoratingNode { +public: + TypeModifierNode(type_modifier modifier, Node* child) + : + DecoratingNode(child), + fModifier(modifier) + { + } + + virtual bool AddDecoration(NameBuffer& buffer, + const Node* stopDecorator) const + { + if (this == stopDecorator) + return true; + + return fChildNode->AddDecoration(buffer, stopDecorator) + && buffer.Append(kTypeModifierSuffixes[fModifier]); + } + + virtual object_type ObjectType() const + { + return OBJECT_TYPE_DATA; + } + + virtual TypeInfo Type() const + { + TypeInfo type = fChildNode->Type(); + if (type.type == TYPE_CHAR + && (type.cvQualifiers & CV_QUALIFIER_CONST) != 0) { + return TypeInfo(TYPE_CONST_CHAR_POINTER); + } + + switch (fModifier) { + case TYPE_QUALIFIER_POINTER: + return TypeInfo(TYPE_POINTER); + case TYPE_QUALIFIER_REFERENCE: + return TypeInfo(TYPE_REFERENCE); + default: + return TypeInfo(); + } + } + +private: + type_modifier fModifier; +}; + + +class VendorTypeModifierNode : public DecoratingNode { +public: + VendorTypeModifierNode(Node* name, Node* child) + : + DecoratingNode(child), + fName(name) + { + fName->SetParent(this); + } + + virtual bool AddDecoration(NameBuffer& buffer, + const Node* stopDecorator) const + { + if (this == stopDecorator) + return true; + + return fChildNode->AddDecoration(buffer, stopDecorator) + && buffer.Append(" ") + && fName->GetName(buffer); + } + + virtual object_type ObjectType() const + { + return OBJECT_TYPE_DATA; + } + +private: + Node* fName; +}; + + +class OperatorNode : public Node { +public: + OperatorNode(const operator_info* info) + : + fInfo(info) + { + SetReferenceable(false); + } + + virtual bool GetName(NameBuffer& buffer) const + { + return buffer.Append( + isalpha(fInfo->name[0]) ? "operator " : "operator") + && buffer.Append(fInfo->name); + } + + virtual object_type ObjectType() const + { + return (fInfo->flags & OPERATOR_IS_MEMBER) != 0 + ? OBJECT_TYPE_METHOD_CLASS : OBJECT_TYPE_UNKNOWN; + } + +private: + const operator_info* fInfo; +}; + + +class VendorOperatorNode : public Node { +public: + VendorOperatorNode(Node* name) + : + fName(name) + { + fName->SetParent(this); + SetReferenceable(false); + } + + virtual bool GetName(NameBuffer& buffer) const + { + return buffer.Append("operator ") + && fName->GetName(buffer); + } + +private: + Node* fName; +}; + + +class CastOperatorNode : public Node { +public: + CastOperatorNode(Node* child) + : + fChildNode(child) + { + fChildNode->SetParent(this); + } + + virtual bool GetName(NameBuffer& buffer) const + { + return buffer.Append("operator ") && fChildNode->GetName(buffer); + } + + virtual bool IsNoReturnValueFunction() const + { + return true; + } + + virtual object_type ObjectType() const + { + return OBJECT_TYPE_METHOD_OBJECT; + } + +private: + Node* fChildNode; +}; + + +class PrefixedNode : public Node { +public: + PrefixedNode(Node* prefix, Node* node) + : + fPrefixNode(prefix), + fNode(node) + { + fPrefixNode->SetParent(this); + fNode->SetParent(this); + } + + virtual bool GetName(NameBuffer& buffer) const + { + if (!fPrefixNode->GetName(buffer)) + return false; + + buffer.Append("::"); + return fNode->GetName(buffer); + } + + virtual Node* GetUnqualifiedNode(Node* beforeNode) + { + return beforeNode == fNode + ? fPrefixNode->GetUnqualifiedNode(beforeNode) + : fNode->GetUnqualifiedNode(beforeNode); + } + + virtual bool IsNoReturnValueFunction() const + { + return fNode->IsNoReturnValueFunction(); + } + + virtual object_type ObjectType() const + { + return fNode->ObjectType(); + } + + virtual prefix_type PrefixType() const + { + return PREFIX_UNKNOWN; + } + +private: + Node* fPrefixNode; + Node* fNode; +}; + + +typedef PrefixedNode DependentNameNode; + + +class TemplateNode : public Node { +public: + TemplateNode(Node* base) + : + fBase(base), + fFirstArgument(NULL), + fLastArgument(NULL) + { + fBase->SetParent(this); + } + + void AddArgument(Node* child) + { + child->SetParent(this); + + if (fLastArgument != NULL) { + fLastArgument->SetNext(child); + fLastArgument = child; + } else { + fFirstArgument = child; + fLastArgument = child; + } + } + + virtual bool GetName(NameBuffer& buffer) const + { + if (!fBase->GetName(buffer)) + return false; + + buffer.Append("<"); + + Node* child = fFirstArgument; + while (child != NULL) { + if (child != fFirstArgument) + buffer.Append(", "); + + if (!child->GetName(buffer)) + return false; + + child = child->Next(); + } + + // add a space between consecutive '>' + if (buffer.LastChar() == '>') + buffer.Append(" "); + + return buffer.Append(">"); + } + + virtual Node* GetUnqualifiedNode(Node* beforeNode) + { + return fBase != beforeNode + ? fBase->GetUnqualifiedNode(beforeNode) : this; + } + + virtual bool IsTemplatized() const + { + return true; + } + + virtual Node* TemplateParameterAt(int index) const + { + Node* child = fFirstArgument; + while (child != NULL) { + if (index == 0) + return child; + index--; + child = child->Next(); + } + + return NULL; + } + + virtual bool IsNoReturnValueFunction() const + { + return fBase->IsNoReturnValueFunction(); + } + + virtual object_type ObjectType() const + { + return fBase->ObjectType(); + } + + virtual prefix_type PrefixType() const + { + return fBase->PrefixType(); + } + +protected: + Node* fBase; + Node* fFirstArgument; + Node* fLastArgument; +}; + + +class MultiSubExpressionsNode : public Node { +public: + MultiSubExpressionsNode() + : + fFirstSubExpression(NULL), + fLastSubExpression(NULL) + { + } + + void AddSubExpression(Node* child) + { + child->SetParent(this); + + if (fLastSubExpression != NULL) { + fLastSubExpression->SetNext(child); + fLastSubExpression = child; + } else { + fFirstSubExpression = child; + fLastSubExpression = child; + } + } + +protected: + Node* fFirstSubExpression; + Node* fLastSubExpression; +}; + + +class CallNode : public MultiSubExpressionsNode { +public: + CallNode() + { + } + + virtual bool GetName(NameBuffer& buffer) const + { + // TODO: Use the real syntax! + buffer.Append("call("); + + Node* child = fFirstSubExpression; + while (child != NULL) { + if (child != fFirstSubExpression) + buffer.Append(", "); + + if (!child->GetName(buffer)) + return false; + + child = child->Next(); + } + + buffer.Append(")"); + + return true; + } +}; + + +class OperatorExpressionNode : public MultiSubExpressionsNode { +public: + OperatorExpressionNode(const operator_info* info) + : + fInfo(info) + { + } + + virtual bool GetName(NameBuffer& buffer) const + { + bool isIdentifier = isalpha(fInfo->name[0]) || fInfo->name[0] == '_'; + + if (fInfo->argument_count == 1 || isIdentifier + || fInfo->argument_count > 3 + || (fInfo->argument_count == 3 && strcmp(fInfo->name, "?") != 0)) { + // prefix operator + buffer.Append(fInfo->name); + + if (isIdentifier) + buffer.Append("("); + + Node* child = fFirstSubExpression; + while (child != NULL) { + if (child != fFirstSubExpression) + buffer.Append(", "); + + if (!child->GetName(buffer)) + return false; + + child = child->Next(); + } + + if (isIdentifier) + buffer.Append(")"); + + return true; + } + + Node* arg1 = fFirstSubExpression; + Node* arg2 = arg1->Next(); + + buffer.Append("("); + + if (fInfo->argument_count == 2) { + // binary infix operator + if (!arg1->GetName(buffer)) + return false; + + buffer.Append(" "); + buffer.Append(fInfo->name); + buffer.Append(" "); + + if (!arg2->GetName(buffer)) + return false; + + return buffer.Append(")"); + } + + Node* arg3 = arg2->Next(); + + if (fInfo->argument_count == 2) { + // trinary operator "... ? ... : ..." + if (!arg1->GetName(buffer)) + return false; + + buffer.Append(" ? "); + + if (!arg2->GetName(buffer)) + return false; + + buffer.Append(" : "); + + if (!arg3->GetName(buffer)) + return false; + + return buffer.Append(")"); + } + + return false; + } + +private: + const operator_info* fInfo; +}; + + +class ConversionExpressionNode : public MultiSubExpressionsNode { +public: + ConversionExpressionNode(Node* type) + : + fType(type) + { + fType->SetParent(this); + } + + virtual bool GetName(NameBuffer& buffer) const + { + buffer.Append("("); + + if (!fType->GetName(buffer)) + return false; + + buffer.Append(")("); + + Node* child = fFirstSubExpression; + while (child != NULL) { + if (child != fFirstSubExpression) + buffer.Append(", "); + + if (!child->GetName(buffer)) + return false; + + child = child->Next(); + } + + return buffer.Append(")"); + } + +private: + Node* fType; +}; + + +class PointerToMemberNode : public DecoratingNode { +public: + PointerToMemberNode(Node* classType, Node* memberType) + : + DecoratingNode(memberType), + fClassType(classType) + { + fClassType->SetParent(this); + } + + virtual bool AddDecoration(NameBuffer& buffer, + const Node* stopDecorator) const + { + if (this == stopDecorator) + return true; + + if (!fChildNode->AddDecoration(buffer, stopDecorator)) + return false; + + // In most cases we need a space before the name. In some it is + // superfluous, though. + if (!buffer.IsEmpty() && buffer.LastChar() != '(') + buffer.Append(" "); + + if (!fClassType->GetName(buffer)) + return false; + + return buffer.Append("::*"); + } + + virtual object_type ObjectType() const + { + return OBJECT_TYPE_DATA; + } + + virtual TypeInfo Type() const + { + // TODO: Method pointers aren't ordinary pointers. Though we might not + // be able to determine the difference. + return TypeInfo(TYPE_POINTER); + } + + +private: + Node* fClassType; +}; + + +class FunctionNode : public ObjectNode { +public: + FunctionNode(Node* nameNode, bool hasReturnType, bool isExternC) + : + ObjectNode(nameNode), + fFirstTypeNode(NULL), + fLastTypeNode(NULL), + fHasReturnType(hasReturnType), + fIsExternC(isExternC) + { + } + + void AddType(Node* child) + { + child->SetParent(this); + + if (fLastTypeNode != NULL) { + fLastTypeNode->SetNext(child); + fLastTypeNode = child; + } else { + fFirstTypeNode = child; + fLastTypeNode = child; + } + } + + virtual bool GetName(NameBuffer& buffer) const + { + NameDecorationInfo decorationInfo(NULL); + return GetDecoratedName(buffer, decorationInfo); + } + + virtual bool GetDecoratedName(NameBuffer& buffer, + NameDecorationInfo& decorationInfo) const + { + // write 'extern "C"' +// if (fIsExternC) +// buffer.Append("extern \"C\""); + + // write the return type + Node* child = fFirstTypeNode; + if (_HasReturnType() && child != NULL) { + if (!child->GetName(buffer)) + return false; + child = child->Next(); + + buffer.Append(" ", 1); + } + + // write the function name + if (fName == NULL) + buffer.Append("(", 1); + + CVQualifierInfo info; + if (fName != NULL) { + // skip CV qualifiers on our name -- we'll add them later + fName->GetCVQualifierInfo(info); + if (info.firstNonCVQualifier != NULL + && !info.firstNonCVQualifier->GetName(buffer)) { + return false; + } + } + + // add non-CV qualifier decorations + if (decorationInfo.firstDecorator != NULL) { + if (!decorationInfo.firstDecorator->AddDecoration(buffer, + decorationInfo.closestCVDecoratorList)) { + return false; + } + } + + if (fName == NULL) + buffer.Append(")", 1); + + // add the parameter types + buffer.Append("("); + + // don't add a single "void" parameter + if (child != NULL && child->Next() == NULL + && child->IsTypeName("void", 4)) { + child = NULL; + } + + Node* firstParam = child; + while (child != NULL) { + if (child != firstParam) + buffer.Append(", "); + + if (!child->GetName(buffer)) + return false; + + child = child->Next(); + } + + buffer.Append(")"); + + // add CV qualifiers on our name + if (info.firstCVQualifier != NULL) { + if (!info.firstCVQualifier->AddDecoration(buffer, + info.firstNonCVQualifier)) { + return false; + } + } + + // add CV qualifiers on us + if (decorationInfo.closestCVDecoratorList != NULL) + decorationInfo.closestCVDecoratorList->AddDecoration(buffer, NULL); + + return true; + } + + virtual object_type ObjectType() const + { + // no name, no fun + if (fName == NULL) + return OBJECT_TYPE_FUNCTION; + + // check our name's prefix + switch (fName->PrefixType()) { + case PREFIX_NONE: + case PREFIX_NAMESPACE: + return OBJECT_TYPE_FUNCTION; + case PREFIX_CLASS: + case PREFIX_UNKNOWN: + break; + } + + // Our name has a prefix, but we don't know, whether it is a class or + // namespace. Let's ask our name what it thinks it is. + object_type type = fName->ObjectType(); + switch (type) { + case OBJECT_TYPE_FUNCTION: + case OBJECT_TYPE_METHOD_CLASS: + case OBJECT_TYPE_METHOD_OBJECT: + case OBJECT_TYPE_METHOD_UNKNOWN: + // That's as good as it gets. + return type; + case OBJECT_TYPE_UNKNOWN: + case OBJECT_TYPE_DATA: + default: + // Obviously our name doesn't have a clue. + return OBJECT_TYPE_METHOD_UNKNOWN; + } + } + + virtual Node* ParameterAt(uint32 index) const + { + // skip return type + Node* child = fFirstTypeNode; + if (_HasReturnType() && child != NULL) + child = child->Next(); + + // ignore a single "void" parameter + if (child != NULL && child->Next() == NULL + && child->IsTypeName("void", 4)) { + return NULL; + } + + // get the type at the index + while (child != NULL && index > 0) { + child = child->Next(); + index--; + } + + return child; + } + +private: + bool _HasReturnType() const + { + return fHasReturnType + || fName == NULL + || (fName->IsTemplatized() && !fName->IsNoReturnValueFunction()); + } + +private: + Node* fFirstTypeNode; + Node* fLastTypeNode; + bool fHasReturnType; + bool fIsExternC; +}; + + +// #pragma mark - Demangler + + +class Demangler { +public: + Demangler(); + + int Demangle(const char* mangledName, char* buffer, + size_t size, + DemanglingInfo& demanglingInfo); + int GetParameterInfo(const char* mangledName, + uint32 index, char* buffer, size_t size, + ParameterInfo& info); + + // actually private, but public to make gcc 2 happy + inline bool _SetError(int error); + inline void _AddAllocatedNode(Node* node); + +private: + template struct NodeCreator; + + inline bool _SkipExpected(char c); + inline bool _SkipExpected(const char* string); + + void _Init(); + void _Cleanup(); + + int _Demangle(const char* mangledName, char* buffer, + size_t size, + DemanglingInfo& demanglingInfo); + int _GetParameterInfo(const char* mangledName, + uint32 index, char* buffer, size_t size, + ParameterInfo& info); + + int _Parse(const char* mangledName, + const char*& versionSuffix, + ObjectNode*& _node); + + bool _ParseEncoding(ObjectNode*& _node); + bool _ParseSpecialName(Node*& _node); + bool _ParseCallOffset(bool& nonVirtual, + number_type& offset1, number_type& offset2); + bool _ParseName(Node*& _node); + bool _ParseNestedName(Node*& _node); + bool _ParseNestedNameInternal(Node*& _node); + bool _ParseLocalName(Node*& _node); + bool _ParseUnqualifiedName(Node*& _node); + bool _ParseSourceName(Node*& _node); + bool _ParseOperatorName(Node*& _node); + bool _ParseType(Node*& _node); + bool _ParseTypeInternal(Node*& _node); + void _ParseCVQualifiers(int& qualifiers); + bool _ParseTypeWithModifier(type_modifier modifier, + int toSkip, Node*& _node); + bool _TryParseBuiltinType(Node*& _node); + bool _ParseFunctionType(FunctionNode*& _node);; + bool _ParseArrayType(Node*& _node); + bool _ParsePointerToMemberType(Node*& _node); + bool _ParseTemplateParam(Node*& _node); + bool _ParseSubstitution(Node*& _node); + bool _ParseSubstitutionInternal(Node*& _node); + bool _ParseBareFunctionType(FunctionNode* node); + bool _ParseTemplateArgs(Node* node, Node*& _node); + bool _ParseTemplateArg(Node*& _node); + bool _ParseExpression(Node*& _node); + bool _ParseExpressionPrimary(Node*& _node); + bool _ParseNumber(number_type& number); + + bool _CreateNodeAndSkip(const char* name, + size_t length, int toSkip, Node*& _node); + bool _CreateNodeAndSkip(const char* name, int toSkip, + Node*& _node); + bool _CreateTypeNodeAndSkip(type_type type, + int toSkip, Node*& _node); + bool _CreateTypeNodeAndSkip(const char* name, + const char* prefix, + const char* templateArgs, int toSkip, + Node*& _node); + + void _RegisterReferenceableNode(Node* node); + bool _CreateSubstitutionNode(int index, + Node*& _node); + +private: + Input fInput; + int fError; + Node* fAllocatedNodes; + Node* fFirstReferenceableNode; + Node* fLastReferenceableNode; + Node* fTemplatizedNode; +}; + + +template +struct Demangler::NodeCreator { + NodeCreator(Demangler* demangler) + : + fDemangler(demangler) + { + } + + template + inline bool operator()(ReturnType*& _node) const + { + _node = NEW(NodeType); + if (_node == NULL) + return fDemangler->_SetError(ERROR_NO_MEMORY); + + fDemangler->_AddAllocatedNode(_node); + return true; + } + + template + inline bool operator()(ParameterType1 arg1, ReturnType*& _node) const + { + _node = NEW(NodeType(arg1)); + if (_node == NULL) + return fDemangler->_SetError(ERROR_NO_MEMORY); + + fDemangler->_AddAllocatedNode(_node); + return true; + } + + template + inline bool operator()(ParameterType1 arg1, ParameterType2 arg2, + ReturnType*& _node) const + { + _node = NEW(NodeType(arg1, arg2)); + if (_node == NULL) + return fDemangler->_SetError(ERROR_NO_MEMORY); + + fDemangler->_AddAllocatedNode(_node); + return true; + } + + template + inline bool operator()(ParameterType1 arg1, ParameterType2 arg2, + ParameterType3 arg3, ReturnType*& _node) const + { + _node = NEW(NodeType(arg1, arg2, arg3)); + if (_node == NULL) + return fDemangler->_SetError(ERROR_NO_MEMORY); + + fDemangler->_AddAllocatedNode(_node); + return true; + } + +private: + Demangler* fDemangler; +}; + + +inline bool +Demangler::_SetError(int error) +{ + if (fError == ERROR_OK) { + fError = error; +#ifdef TRACE_GCC3_DEMANGLER + DebugScope::Print("_SetError(): %d, remaining input: \"%s\"\n", + error, fInput.String()); +#endif + } + return false; } -static struct debugger_demangle_module_info sModuleInfo = { - { - "debugger/demangle/gcc3+/v1", - 0, - NULL - }, +inline void +Demangler::_AddAllocatedNode(Node* node) +{ + node->SetNextAllocated(fAllocatedNodes); + fAllocatedNodes = node; +} - demangle_symbol, - NULL, -}; -module_info *modules[] = { - (module_info *)&sModuleInfo, - NULL -}; +inline bool +Demangler::_SkipExpected(char c) +{ + return fInput.SkipPrefix(c) || _SetError(ERROR_INVALID); +} + +inline bool +Demangler::_SkipExpected(const char* string) +{ + return fInput.SkipPrefix(string) || _SetError(ERROR_INVALID); +} + + +Demangler::Demangler() + : + fInput(), + fAllocatedNodes(NULL) +{ +} + + +int +Demangler::Demangle(const char* mangledName, char* buffer, size_t size, + DemanglingInfo& demanglingInfo) +{ + DEBUG_SCOPE("Demangle"); + + _Init(); + + int result = _Demangle(mangledName, buffer, size, demanglingInfo); + + _Cleanup(); + + return result; +} + + +int +Demangler::GetParameterInfo(const char* mangledName, uint32 index, char* buffer, + size_t size, ParameterInfo& info) +{ + DEBUG_SCOPE("GetParameterInfo"); + + _Init(); + + int result = _GetParameterInfo(mangledName, index, buffer, size, info); + + _Cleanup(); + + return result; +} + + +void +Demangler::_Init() +{ + fError = ERROR_OK; + + fFirstReferenceableNode = NULL; + fLastReferenceableNode = NULL; + fAllocatedNodes = NULL; + fTemplatizedNode = NULL; +} + + +void +Demangler::_Cleanup() +{ + while (fAllocatedNodes != NULL) { + Node* node = fAllocatedNodes; + fAllocatedNodes = node->NextAllocated(); + DELETE(node); + } +} + + +int +Demangler::_Demangle(const char* mangledName, char* buffer, size_t size, + DemanglingInfo& demanglingInfo) +{ + // parse the name + const char* versionSuffix; + ObjectNode* node; + int error = _Parse(mangledName, versionSuffix, node); + if (error != ERROR_OK) + return error; + + NameBuffer nameBuffer(buffer, size); + bool success = node->GetObjectName(nameBuffer, demanglingInfo); + + // If versioned, append the unmodified version string + if (success && versionSuffix != NULL) + nameBuffer.Append(versionSuffix); + + if (nameBuffer.HadOverflow()) + return ERROR_BUFFER_TOO_SMALL; + + if (!success) + return ERROR_INTERNAL; + + demanglingInfo.objectType = node->ObjectType(); + + nameBuffer.Terminate(); + return ERROR_OK; +} + + +int +Demangler::_GetParameterInfo(const char* mangledName, uint32 index, + char* buffer, size_t size, ParameterInfo& info) +{ + // parse the name + const char* versionSuffix; + ObjectNode* node; + int error = _Parse(mangledName, versionSuffix, node); + if (error != ERROR_OK) + return error; + + // get the parameter node + Node* parameter = node->ParameterAt(index); + if (parameter == NULL) + return ERROR_INVALID_PARAMETER_INDEX; + + // get the parameter name + NameBuffer nameBuffer(buffer, size); + bool success = parameter->GetName(nameBuffer); + + if (nameBuffer.HadOverflow()) + return ERROR_BUFFER_TOO_SMALL; + + if (!success) + return ERROR_INTERNAL; + + nameBuffer.Terminate(); + + // get the type + info.type = parameter->Type(); + + return ERROR_OK; +} + + +int +Demangler::_Parse(const char* mangledName, const char*& versionSuffix, + ObjectNode*& _node) +{ + // To support versioned symbols, we ignore the version suffix when + // demangling. + versionSuffix = strchr(mangledName, '@'); + fInput.SetTo(mangledName, + versionSuffix != NULL + ? versionSuffix - mangledName : strlen(mangledName)); + + // ::= _Z + + if (!fInput.SkipPrefix("_Z")) + return ERROR_NOT_MANGLED; + + if (!_ParseEncoding(_node)) + return fError; + + if (fInput.CharsRemaining() != 0) { + // bogus at end of input + return ERROR_INVALID; + } + + return ERROR_OK; +} + + +bool +Demangler::_ParseEncoding(ObjectNode*& _node) +{ + DEBUG_SCOPE("_ParseEncoding"); + + // ::= + // ::= + // ::= + + // NOTE: This is not in the specs: Local entities seem to be prefixed + // by an 'L'. + fInput.SkipPrefix('L'); + + // parse , if it is one + Node* name; + if (fInput.HasPrefix('T') || fInput.HasPrefix("GV")) { + return _ParseSpecialName(name) + && NodeCreator(this)(name, _node); + } + + // either or + if (!_ParseName(name)) + return false; + + if (fInput.CharsRemaining() == 0 || fInput.HasPrefix('E')) { + // + return NodeCreator(this)(name, _node); + } + + // -- parse remaining + FunctionNode* functionNode; + if (!NodeCreator(this)(name, false, false, functionNode)) + return false; + _node = functionNode; + + // If our name is templatized, we push it onto the templatized node + // stack while parsing the function parameters. + Node* previousTemplatizedNode = fTemplatizedNode; + if (name->IsTemplatized()) + fTemplatizedNode = name; + + if (!_ParseBareFunctionType(functionNode)) + return false; + + fTemplatizedNode = previousTemplatizedNode; + + return true; +} + + +bool +Demangler::_ParseSpecialName(Node*& _node) +{ + DEBUG_SCOPE("_ParseSpecialName"); + + if (fInput.CharsRemaining() == 0) + return _SetError(ERROR_INVALID); + + // ::= GV # Guard variable for one-time + // # initialization + // # No + if (!fInput.SkipPrefix('T')) { + Node* name; + return _SkipExpected("GV") + && _ParseName(name) + && NodeCreator(this)("guard variable for ", + name, _node); + } + + // ::= TV # virtual table + // ::= TT # VTT structure (construction vtable + // # index) + // ::= TI # typeinfo structure + // ::= TS # typeinfo name (null-terminated byte + // # string) + const char* prefix = NULL; + switch (fInput[0]) { + case 'V': + prefix = "vtable for "; + break; + case 'T': + prefix = "VTT for "; + break; + case 'I': + prefix = "typeinfo for "; + break; + case 'S': + prefix = "typeinfo name for "; + break; + } + + if (prefix != NULL) { + fInput.Skip(1); + Node* type; + return _ParseType(type) + && NodeCreator(this)(prefix, type, _node); + } + + // ::= Tc + // # base is the nominal target function of thunk + // # first call-offset is 'this' adjustment + // # second call-offset is result adjustment + if (fInput.SkipPrefix('c')) { + bool nonVirtual; + number_type offset1; + number_type offset2; + ObjectNode* name; + return _ParseCallOffset(nonVirtual, offset1, offset2) + && _ParseCallOffset(nonVirtual, offset1, offset2) + && _ParseEncoding(name) + && NodeCreator(this)( + "covariant return thunk to ", name, _node); + } + + // ::= T + // # base is the nominal target function of thunk + bool nonVirtual; + number_type offset1; + number_type offset2; + ObjectNode* name; + return _ParseCallOffset(nonVirtual, offset1, offset2) + && _ParseEncoding(name) + && NodeCreator(this)( + nonVirtual ? "non-virtual thunk to " : "virtual thunk to ", + name, _node); +} + + +bool +Demangler::_ParseCallOffset(bool& nonVirtual, number_type& offset1, + number_type& offset2) +{ + // ::= h _ + // ::= v _ + // ::= + // # non-virtual base override + // ::= _ + // # virtual base override, with vcall offset + + // non-virtual + if (fInput.SkipPrefix('h')) { + nonVirtual = true; + return _ParseNumber(offset1) && _SkipExpected('_'); + } + + // virtual + nonVirtual = false; + return _SkipExpected('v') + && _ParseNumber(offset1) + && _SkipExpected('_') + && _ParseNumber(offset2) + && _SkipExpected('_'); +} + +bool +Demangler::_ParseName(Node*& _node) +{ + DEBUG_SCOPE("_ParseName"); + + if (fInput.CharsRemaining() == 0) + return _SetError(ERROR_INVALID); + + // ::= + // ::= + // ::= + // ::= # See Scope Encoding below + // + // ::= + // ::= St # ::std:: + // + // ::= + // ::= + + switch (fInput[0]) { + case 'N': + // + return _ParseNestedName(_node); + case 'Z': + // + return _ParseLocalName(_node); + case 'S': + { + // + if (!fInput.HasPrefix("St")) { + if (!_ParseSubstitution(_node)) + return false; + break; + } + + // std:: namespace + fInput.Skip(2); + + Node* prefix; + if (!NodeCreator(this)("std", prefix)) + return false; + + // + Node* node; + if (!_ParseUnqualifiedName(node) + || !NodeCreator(this)(prefix, node, _node)) { + return false; + } + + break; + } + default: + // + if (!_ParseUnqualifiedName(_node)) + return false; + break; + } + + // We get here for the names that might be an . + // Check whether are following. + if (!fInput.HasPrefix('I')) + return true; + + // is referenceable + _RegisterReferenceableNode(_node); + + return _ParseTemplateArgs(_node, _node); +} + + +bool +Demangler::_ParseNestedName(Node*& _node) +{ + DEBUG_SCOPE("_ParseNestedName"); + + // ::= N [] E + // ::= N [] + // E + // + // ::= [r] [V] [K] # restrict (C99), volatile, const + // + // ::= + // ::= + // ::= + // ::= # empty + // ::= + // + // ::=