* Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* Copyright 2021, Jerome Duval, jerome.duval@gmail.com.
* Distributed under the terms of the MIT License.
*/
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <new>
#include <TypeConstants.h>
#ifdef _KERNEL_MODE
# include <debug_heap.h>
#endif
#include "demangle.h"
#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
#ifdef _KERNEL_MODE
# define PRINT(format...) kprintf(format)
# define VPRINT(format, args) PRINT("%s", format)
# 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
typedef long number_type;
enum {
ERROR_OK = 0,
ERROR_NOT_MANGLED,
ERROR_UNSUPPORTED,
ERROR_INVALID,
ERROR_BUFFER_TOO_SMALL,
ERROR_NO_MEMORY,
ERROR_INTERNAL,
ERROR_INVALID_PARAMETER_INDEX
};
enum object_type {
OBJECT_TYPE_UNKNOWN,
OBJECT_TYPE_DATA,
OBJECT_TYPE_FUNCTION,
OBJECT_TYPE_METHOD_CLASS,
OBJECT_TYPE_METHOD_OBJECT,
OBJECT_TYPE_METHOD_UNKNOWN
};
enum prefix_type {
PREFIX_NONE,
PREFIX_NAMESPACE,
PREFIX_CLASS,
PREFIX_UNKNOWN
};
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",
"__dfloat32",
"__dfloat64",
"__dfloat64",
"char16_t",
"char32_t",
"?",
"char const*",
"void*",
"void&"
};
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;
};
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 },
{ "ng", "-", 1, 0 },
{ "ad", "&", 1, 0 },
{ "de", "*", 1, 0 },
{ "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 },
{ "sz", "sizeof", 1, 0 },
{ "at", "alignof", 1, OPERATOR_TYPE_PARAM },
{ "az", "alignof", 1, 0 },
{}
};
#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
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
{
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 (fType->IsTypeName("bool", 4) && fLength == 1
&& (fNumber[0] == '0' || fNumber[0] == '1')) {
return buffer.Append(fNumber[0] == '0' ? "false" : "true");
}
if (!fType->IsTypeName("int", 3)) {
buffer.Append("(");
if (!fType->GetName(buffer))
return false;
buffer.Append(")");
}
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;
};
class ClonedNode : public ObjectNode {
public:
ClonedNode(Node* clone, ObjectNode* node)
:
ObjectNode(NULL),
fNode(node),
fCloneNode(clone)
{
fNode->SetParent(this);
fCloneNode->SetParent(this);
}
virtual bool GetName(NameBuffer& buffer) const
{
if (!fNode->GetName(buffer))
return false;
buffer.Append(" ", 1);
return _AppendCloneName(buffer);
}
virtual bool GetObjectName(NameBuffer& buffer,
const DemanglingParameters& parameters)
{
if (parameters.objectNameOnly) {
if (!fNode->GetObjectName(buffer, parameters))
return false;
if (!_AppendCloneName(buffer))
return false;
return buffer.Append(" ", 1);
}
return ObjectNode::GetObjectName(buffer, parameters);
}
virtual Node* GetUnqualifiedNode(Node* beforeNode)
{
return beforeNode == fCloneNode
? fNode->GetUnqualifiedNode(beforeNode)
: fCloneNode->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;
}
virtual Node* ParameterAt(uint32 index) const
{
return fNode->ParameterAt(index);
}
private:
bool _AppendCloneName(NameBuffer& buffer) const
{
buffer.Append("[clone ");
if (!fCloneNode->GetName(buffer))
return false;
buffer.Append("]");
return true;
}
private:
ObjectNode* fNode;
Node* fCloneNode;
};
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();
}
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
{
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)) {
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) {
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) {
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;
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
{
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
{
Node* child = fFirstTypeNode;
if (_HasReturnType() && child != NULL) {
if (!child->GetName(buffer))
return false;
child = child->Next();
buffer.Append(" ", 1);
}
if (fName == NULL)
buffer.Append("(", 1);
CVQualifierInfo info;
if (fName != NULL) {
fName->GetCVQualifierInfo(info);
if (info.firstNonCVQualifier != NULL
&& !info.firstNonCVQualifier->GetName(buffer)) {
return false;
}
}
if (decorationInfo.firstDecorator != NULL) {
if (!decorationInfo.firstDecorator->AddDecoration(buffer,
decorationInfo.closestCVDecoratorList)) {
return false;
}
}
if (fName == NULL)
buffer.Append(")", 1);
buffer.Append("(");
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(")");
if (info.firstCVQualifier != NULL) {
if (!info.firstCVQualifier->AddDecoration(buffer,
info.firstNonCVQualifier)) {
return false;
}
}
if (decorationInfo.closestCVDecoratorList != NULL)
decorationInfo.closestCVDecoratorList->AddDecoration(buffer, NULL);
return true;
}
virtual object_type ObjectType() const
{
if (fName == NULL)
return OBJECT_TYPE_FUNCTION;
switch (fName->PrefixType()) {
case PREFIX_NONE:
case PREFIX_NAMESPACE:
return OBJECT_TYPE_FUNCTION;
case PREFIX_CLASS:
case PREFIX_UNKNOWN:
break;
}
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:
return type;
case OBJECT_TYPE_UNKNOWN:
case OBJECT_TYPE_DATA:
default:
return OBJECT_TYPE_METHOD_UNKNOWN;
}
}
virtual Node* ParameterAt(uint32 index) const
{
Node* child = fFirstTypeNode;
if (_HasReturnType() && child != NULL)
child = child->Next();
if (child != NULL && child->Next() == NULL
&& child->IsTypeName("void", 4)) {
return NULL;
}
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;
};
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);
inline bool _SetError(int error);
inline void _AddAllocatedNode(Node* node);
private:
template<typename NodeType> 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 _ParseClone(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<typename NodeType>
struct Demangler::NodeCreator {
NodeCreator(Demangler* demangler)
:
fDemangler(demangler)
{
}
template<typename ReturnType>
inline bool operator()(ReturnType*& _node) const
{
_node = NEW(NodeType);
if (_node == NULL)
return fDemangler->_SetError(ERROR_NO_MEMORY);
fDemangler->_AddAllocatedNode(_node);
return true;
}
template<typename ParameterType1, typename ReturnType>
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<typename ParameterType1, typename ParameterType2,
typename ReturnType>
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<typename ParameterType1, typename ParameterType2,
typename ParameterType3, typename ReturnType>
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;
}
inline void
Demangler::_AddAllocatedNode(Node* node)
{
node->SetNextAllocated(fAllocatedNodes);
fAllocatedNodes = node;
}
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)
{
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 (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)
{
const char* versionSuffix;
ObjectNode* node;
int error = _Parse(mangledName, versionSuffix, node);
if (error != ERROR_OK)
return error;
Node* parameter = node->ParameterAt(index);
if (parameter == NULL)
return ERROR_INVALID_PARAMETER_INDEX;
NameBuffer nameBuffer(buffer, size);
bool success = parameter->GetName(nameBuffer);
if (nameBuffer.HadOverflow())
return ERROR_BUFFER_TOO_SMALL;
if (!success)
return ERROR_INTERNAL;
nameBuffer.Terminate();
info.type = parameter->Type();
return ERROR_OK;
}
int
Demangler::_Parse(const char* mangledName, const char*& versionSuffix,
ObjectNode*& _node)
{
versionSuffix = strchr(mangledName, '@');
fInput.SetTo(mangledName,
versionSuffix != NULL
? versionSuffix - mangledName : strlen(mangledName));
if (!fInput.SkipPrefix("_Z"))
return ERROR_NOT_MANGLED;
if (!_ParseEncoding(_node) || !_ParseClone(_node))
return fError;
if (fInput.CharsRemaining() != 0) {
return ERROR_INVALID;
}
return ERROR_OK;
}
bool
Demangler::_ParseClone(ObjectNode*& _node)
{
DEBUG_SCOPE("_ParseClone");
while (fInput.HasPrefix('.')) {
int count = fInput.CharsRemaining();
int i = 1;
while (true) {
for (; i < count && fInput[i] != '.'; i++)
;
if (i + 1 >= count || fInput[i + 1] < '0' || fInput[i + 1] > '9')
break;
i++;
}
if (i == 1)
break;
Node* clone;
if (!_CreateNodeAndSkip(fInput.String(), i, i, clone))
return false;
if (!NodeCreator<ClonedNode>(this)(clone, _node, _node))
return false;
}
return true;
}
bool
Demangler::_ParseEncoding(ObjectNode*& _node)
{
DEBUG_SCOPE("_ParseEncoding");
fInput.SkipPrefix('L');
Node* name;
if (fInput.HasPrefix('T') || fInput.HasPrefix("GV")) {
return _ParseSpecialName(name)
&& NodeCreator<ObjectNode>(this)(name, _node);
}
if (!_ParseName(name))
return false;
if (fInput.CharsRemaining() == 0 || fInput.HasPrefix('E')
|| fInput.HasPrefix('.')) {
return NodeCreator<ObjectNode>(this)(name, _node);
}
FunctionNode* functionNode;
if (!NodeCreator<FunctionNode>(this)(name, false, false, functionNode))
return false;
_node = functionNode;
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);
if (!fInput.SkipPrefix('T')) {
Node* name;
return _SkipExpected("GV")
&& _ParseName(name)
&& NodeCreator<SpecialNameNode>(this)("guard variable for ",
name, _node);
}
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<SpecialNameNode>(this)(prefix, type, _node);
}
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<SpecialNameNode>(this)(
"covariant return thunk to ", name, _node);
}
bool nonVirtual;
number_type offset1;
number_type offset2;
ObjectNode* name;
return _ParseCallOffset(nonVirtual, offset1, offset2)
&& _ParseEncoding(name)
&& NodeCreator<SpecialNameNode>(this)(
nonVirtual ? "non-virtual thunk to " : "virtual thunk to ",
name, _node);
}
bool
Demangler::_ParseCallOffset(bool& nonVirtual, number_type& offset1,
number_type& offset2)
{
if (fInput.SkipPrefix('h')) {
nonVirtual = true;
return _ParseNumber(offset1) && _SkipExpected('_');
}
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);
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;
}
fInput.Skip(2);
Node* prefix;
if (!NodeCreator<SimpleNameNode>(this)("std", prefix))
return false;
Node* node;
if (!_ParseUnqualifiedName(node)
|| !NodeCreator<PrefixedNode>(this)(prefix, node, _node)) {
return false;
}
break;
}
default:
if (!_ParseUnqualifiedName(_node))
return false;
break;
}
if (!fInput.HasPrefix('I'))
return true;
_RegisterReferenceableNode(_node);
return _ParseTemplateArgs(_node, _node);
}
bool
Demangler::_ParseNestedName(Node*& _node)
{
DEBUG_SCOPE("_ParseNestedName");
if (!_SkipExpected('N'))
return false;
int qualifiers;
_ParseCVQualifiers(qualifiers);
if (!_ParseNestedNameInternal(_node))
return false;
if (qualifiers != 0) {
return NodeCreator<CVQualifiersNode>(this)(qualifiers, _node,
_node);
}
return true;
}
bool
Demangler::_ParseNestedNameInternal(Node*& _node)
{
DEBUG_SCOPE("_ParseNestedNameMain");
if (fInput.CharsRemaining() == 0)
return _SetError(ERROR_INVALID);
Node* initialPrefixNode = NULL;
Node* prefixNode = NULL;
switch (fInput[0]) {
case 'T':
if (!_ParseTemplateParam(initialPrefixNode))
return false;
_RegisterReferenceableNode(initialPrefixNode);
break;
case 'S':
if (!_ParseSubstitution(initialPrefixNode))
return false;
break;
}
while (true) {
bool canTerminate = false;
Node* node;
if (initialPrefixNode != NULL) {
node = initialPrefixNode;
initialPrefixNode = NULL;
} else {
if (!_ParseUnqualifiedName(node))
return false;
canTerminate = true;
}
if (prefixNode != NULL) {
if (!NodeCreator<PrefixedNode>(this)(prefixNode, node, node))
return false;
}
if (fInput.HasPrefix('I')) {
_RegisterReferenceableNode(node);
if (!_ParseTemplateArgs(node, node))
return false;
canTerminate = true;
}
if (fInput.CharsRemaining() == 0)
return _SetError(ERROR_INVALID);
if (fInput.SkipPrefix('E')) {
if (!canTerminate)
return _SetError(ERROR_INVALID);
_node = node;
return true;
}
prefixNode = node;
_RegisterReferenceableNode(node);
}
}
bool
Demangler::_ParseLocalName(Node*& _node)
{
DEBUG_SCOPE("_ParseLocalName");
ObjectNode* functionName;
if (!_SkipExpected('Z')
|| !_ParseEncoding(functionName)
|| !_SkipExpected('E')) {
return false;
}
Node* entityName;
if (fInput.SkipPrefix('s')) {
if (!NodeCreator<SimpleNameNode>(this)("string literal",
entityName)) {
return false;
}
} else {
if (!_ParseName(entityName))
return false;
}
number_type discriminator = 0;
if (fInput.SkipPrefix('_')) {
if (!_ParseNumber(discriminator))
return false;
if (discriminator < 0)
return _SetError(ERROR_INVALID);
discriminator++;
}
return NodeCreator<PrefixedNode>(this)(functionName, entityName, _node);
}
bool
Demangler::_ParseUnqualifiedName(Node*& _node)
{
DEBUG_SCOPE("_ParseUnqualifiedName");
if (fInput.CharsRemaining() < 2)
return _SetError(ERROR_INVALID);
if (isdigit(fInput[0]) || (fInput[0] == 'n' && isdigit(fInput[1]))) {
return _ParseSourceName(_node);
}
if (fInput[0] == 'C') {
switch (fInput[1]) {
case '1':
case '2':
case '3':
if (!NodeCreator<XtructorNode>(this)(true, fInput[1] - '1',
_node)) {
return false;
}
fInput.Skip(2);
return true;
default:
return _SetError(ERROR_INVALID);
}
}
if (fInput[0] == 'D') {
switch (fInput[1]) {
case '0':
case '1':
case '2':
if (!NodeCreator<XtructorNode>(this)(false, fInput[1] - '0',
_node)) {
return false;
}
fInput.Skip(2);
return true;
default:
return _SetError(ERROR_INVALID);
}
}
return _ParseOperatorName(_node);
}
bool
Demangler::_ParseSourceName(Node*& _node)
{
DEBUG_SCOPE("_ParseSourceName");
if (fInput.CharsRemaining() == 0)
return _SetError(ERROR_INVALID);
number_type number;
if (!_ParseNumber(number))
return false;
if (number <= 0 || number > fInput.CharsRemaining())
return _SetError(ERROR_INVALID);
return _CreateNodeAndSkip(fInput.String(), number, number, _node);
}
bool
Demangler::_ParseOperatorName(Node*& _node)
{
DEBUG_SCOPE("_ParseOperatorName");
if (fInput.CharsRemaining() < 2)
return _SetError(ERROR_INVALID);
const operator_info* info = NULL;
for (int i = 0; kOperatorInfos[i].name != NULL; i++) {
if (fInput.SkipPrefix(kOperatorInfos[i].mangled_name)) {
info = &kOperatorInfos[i];
break;
}
}
if (info != NULL)
return NodeCreator<OperatorNode>(this)(info, _node);
if (fInput.SkipPrefix("cv")) {
Node* typeNode;
if (!_ParseType(typeNode))
return false;
return NodeCreator<CastOperatorNode>(this)(typeNode, _node);
}
if (fInput.SkipPrefix('v')) {
if (fInput.CharsRemaining() == 0 || !isdigit(fInput[0]))
return _SetError(ERROR_INVALID);
fInput.Skip(1);
Node* name;
return _ParseSourceName(name)
&& NodeCreator<VendorOperatorNode>(this)(name, _node);
}
return _SetError(ERROR_INVALID);
}
bool
Demangler::_ParseType(Node*& _node)
{
DEBUG_SCOPE("_ParseType");
if (!_ParseTypeInternal(_node))
return false;
_RegisterReferenceableNode(_node);
return true;
}
bool
Demangler::_ParseTypeInternal(Node*& _node)
{
DEBUG_SCOPE("_ParseTypeInternal");
if (_TryParseBuiltinType(_node)) {
_node->SetReferenceable(false);
return true;
}
if (fError != ERROR_OK)
return false;
if (fInput.CharsRemaining() == 0)
return _SetError(ERROR_INVALID);
switch (fInput[0]) {
case 'F':
{
FunctionNode* functionNode;
if (!_ParseFunctionType(functionNode))
return false;
_node = functionNode;
return true;
}
case 'A':
return _ParseArrayType(_node);
case 'M':
return _ParsePointerToMemberType(_node);
case 'T':
if (!_ParseTemplateParam(_node))
return false;
break;
case 'r':
case 'V':
case 'K':
{
int qualifiers;
_ParseCVQualifiers(qualifiers);
if (!_ParseType(_node))
return false;
return NodeCreator<CVQualifiersNode>(this)(qualifiers, _node,
_node);
}
case 'P':
return _ParseTypeWithModifier(TYPE_QUALIFIER_POINTER, 1, _node);
case 'R':
return _ParseTypeWithModifier(TYPE_QUALIFIER_REFERENCE, 1,
_node);
case 'O':
return _ParseTypeWithModifier(
TYPE_QUALIFIER_RVALUE_REFERENCE, 1, _node);
case 'C':
return _ParseTypeWithModifier(TYPE_QUALIFIER_COMPLEX, 1, _node);
case 'G':
return _ParseTypeWithModifier(TYPE_QUALIFIER_IMAGINARY, 1,
_node);
case 'D':
#if 0
if (fInput.CharsRemaining() < 2)
return _SetError(ERROR_INVALID);
switch(fInput[1]) {
case 'p':
fInput.Skip(2);
return _ParseType(_node);
case 't':
case 'T':
{
fInput.Skip(2);
Node* nameNode;
if (!_ParseExpression(nameNode))
return false;
if (!fInput.SkipPrefix('E'))
return ERROR_INVALID;
}
}
#endif
return _SetError(ERROR_UNSUPPORTED);
case 'U':
fInput.Skip(1);
Node* name;
Node* type;
return _ParseSourceName(name) && _ParseType(type)
&& NodeCreator<VendorTypeModifierNode>(this)(name, type,
_node);
case 'S':
if (!fInput.HasPrefix("St")) {
if (!_ParseSubstitution(_node))
return false;
break;
}
default:
{
Node* nameNode;
return _ParseName(nameNode)
&& NodeCreator<NamedTypeNode>(this)(nameNode, _node);
}
}
if (!fInput.HasPrefix('I'))
return true;
_RegisterReferenceableNode(_node);
return _ParseTemplateArgs(_node, _node);
}
void
Demangler::_ParseCVQualifiers(int& qualifiers)
{
qualifiers = 0;
if (fInput.SkipPrefix('r'))
qualifiers |= CV_QUALIFIER_RESTRICT;
if (fInput.SkipPrefix('V'))
qualifiers |= CV_QUALIFIER_VOLATILE;
if (fInput.SkipPrefix('K'))
qualifiers |= CV_QUALIFIER_CONST;
}
bool
Demangler::_ParseTypeWithModifier(type_modifier modifier, int toSkip,
Node*& _node)
{
if (toSkip > 0)
fInput.Skip(toSkip);
Node* node;
if (!_ParseType(node))
return false;
return NodeCreator<TypeModifierNode>(this)(modifier, node, _node);
}
bool
Demangler::_TryParseBuiltinType(Node*& _node)
{
DEBUG_SCOPE("_TryParseBuiltinType");
if (fInput.CharsRemaining() == 0)
return false;
switch (fInput[0]) {
case 'v':
return _CreateTypeNodeAndSkip(TYPE_VOID, 1, _node);
case 'w':
return _CreateTypeNodeAndSkip(TYPE_WCHAR_T, 1, _node);
case 'b':
return _CreateTypeNodeAndSkip(TYPE_BOOL, 1, _node);
case 'c':
return _CreateTypeNodeAndSkip(TYPE_CHAR, 1, _node);
case 'a':
return _CreateTypeNodeAndSkip(TYPE_SIGNED_CHAR, 1, _node);
case 'h':
return _CreateTypeNodeAndSkip(TYPE_UNSIGNED_CHAR, 1, _node);
case 's':
return _CreateTypeNodeAndSkip(TYPE_SHORT, 1, _node);
case 't':
return _CreateTypeNodeAndSkip(TYPE_UNSIGNED_SHORT, 1,
_node);
case 'i':
return _CreateTypeNodeAndSkip(TYPE_INT, 1, _node);
case 'j':
return _CreateTypeNodeAndSkip(TYPE_UNSIGNED_INT, 1, _node);
case 'l':
return _CreateTypeNodeAndSkip(TYPE_LONG, 1, _node);
case 'm':
return _CreateTypeNodeAndSkip(TYPE_UNSIGNED_LONG, 1, _node);
case 'x':
return _CreateTypeNodeAndSkip(TYPE_LONG_LONG, 1, _node);
case 'y':
return _CreateTypeNodeAndSkip(TYPE_UNSIGNED_LONG_LONG, 1, _node);
case 'n':
return _CreateTypeNodeAndSkip(TYPE_INT128, 1, _node);
case 'o':
return _CreateTypeNodeAndSkip(TYPE_UNSIGNED_INT128, 1, _node);
case 'f':
return _CreateTypeNodeAndSkip(TYPE_FLOAT, 1, _node);
case 'd':
return _CreateTypeNodeAndSkip(TYPE_DOUBLE, 1, _node);
case 'e':
return _CreateTypeNodeAndSkip(TYPE_LONG_DOUBLE, 1, _node);
case 'g':
return _CreateTypeNodeAndSkip(TYPE_FLOAT128, 1, _node);
case 'z':
return _CreateTypeNodeAndSkip(TYPE_ELLIPSIS, 1, _node);
case 'D':
if (fInput.CharsRemaining() < 2)
return false;
switch (fInput[1]) {
case 'd':
return _CreateTypeNodeAndSkip(TYPE_DFLOAT64, 2, _node);
case 'e':
return _CreateTypeNodeAndSkip(TYPE_DFLOAT128, 2, _node);
case 'f':
return _CreateTypeNodeAndSkip(TYPE_DFLOAT32, 2, _node);
case 'h':
return _CreateTypeNodeAndSkip(TYPE_DFLOAT16, 2, _node);
case 'i':
return _CreateTypeNodeAndSkip(TYPE_CHAR16_T, 2, _node);
case 's':
return _CreateTypeNodeAndSkip(TYPE_CHAR32_T, 2, _node);
default:
return false;
}
case 'u':
{
fInput.Skip(1);
Node* nameNode;
return _ParseSourceName(nameNode)
&& NodeCreator<NamedTypeNode>(this)(nameNode, _node);
}
default:
return false;
}
}
bool
Demangler::_ParseFunctionType(FunctionNode*& _node)
{
DEBUG_SCOPE("_ParseFunctionType");
if (!_SkipExpected('F'))
return false;
bool isExternC = fInput.SkipPrefix('Y');
if (!NodeCreator<FunctionNode>(this)((Node*)NULL, true, isExternC,
_node)
|| !_ParseBareFunctionType(_node)) {
return false;
}
return _SkipExpected('E');
}
bool
Demangler::_ParseArrayType(Node*& _node)
{
DEBUG_SCOPE("_ParseArrayType");
if (fInput.CharsRemaining() < 2 || !fInput.SkipPrefix('A'))
return _SetError(ERROR_INVALID);
number_type dimensionNumber;
Node* dimensionExpression = NULL;
if (isdigit(fInput[0])
|| (fInput[0] == 'n' && fInput.CharsRemaining() >= 2
&& isdigit(fInput[1]))) {
if (!_ParseNumber(dimensionNumber))
return false;
} else {
if (!_ParseExpression(dimensionExpression))
return false;
}
Node* type;
if (!_SkipExpected('_') || !_ParseType(type))
return false;
return dimensionExpression != NULL
? NodeCreator<ArrayNode>(this)(type, dimensionExpression, _node)
: NodeCreator<ArrayNode>(this)(type, dimensionNumber, _node);
}
bool
Demangler::_ParsePointerToMemberType(Node*& _node)
{
DEBUG_SCOPE("_ParsePointerToMemberType");
Node* classType;
Node* memberType;
return _SkipExpected('M')
&& _ParseType(classType)
&& _ParseType(memberType)
&& NodeCreator<PointerToMemberNode>(this)(classType, memberType,
_node);
}
bool
Demangler::_ParseTemplateParam(Node*& _node)
{
DEBUG_SCOPE("_ParseTemplateParam");
if (!_SkipExpected('T'))
return false;
if (fTemplatizedNode == NULL)
return _SetError(ERROR_INVALID);
number_type index = 0;
if (!fInput.HasPrefix('_')) {
if (!_ParseNumber(index))
return false;
if (index < 0)
return _SetError(ERROR_INVALID);
index++;
}
if (!_SkipExpected('_'))
return false;
Node* parameter = fTemplatizedNode->TemplateParameterAt(index);
if (parameter == NULL)
return _SetError(ERROR_INVALID);
return NodeCreator<SubstitutionNode>(this)(parameter, _node);
}
bool
Demangler::_ParseSubstitution(Node*& _node)
{
DEBUG_SCOPE("_ParseSubstitution");
if (!_ParseSubstitutionInternal(_node))
return false;
_node->SetReferenceable(false);
return true;
}
bool
Demangler::_ParseSubstitutionInternal(Node*& _node)
{
DEBUG_SCOPE("_ParseSubstitutionInternal");
if (fInput.CharsRemaining() < 2 || !fInput.SkipPrefix('S'))
return _SetError(ERROR_INVALID);
switch (fInput[0]) {
case 't':
return _CreateNodeAndSkip("std", 1, _node);
case 'a':
return _CreateTypeNodeAndSkip("allocator", "std", NULL, 1,
_node);
case 'b':
return _CreateTypeNodeAndSkip("basic_string", "std", NULL, 1,
_node);
case 's':
return _CreateTypeNodeAndSkip("basic_string", "std",
"char, std::char_traits<char>, std::allocator<char>", 1,
_node);
case 'i':
return _CreateTypeNodeAndSkip("basic_istream", "std",
"char, std::char_traits<char>", 1, _node);
case 'o':
return _CreateTypeNodeAndSkip("basic_ostream", "std",
"char, std::char_traits<char>", 1, _node);
case 'd':
return _CreateTypeNodeAndSkip("basic_iostream", "std",
"char, std::char_traits<char>", 1, _node);
case '_':
fInput.Skip(1);
return _CreateSubstitutionNode(0, _node);
}
int seqID = 0;
int count = fInput.CharsRemaining();
int i = 0;
for (; i < count && fInput[i] != '_'; i++) {
char c = fInput[i];
if (isdigit(c))
seqID = seqID * 36 + (c - '0');
else if (c >= 'A' && c <= 'Z')
seqID = seqID * 36 + 10 + (c - 'A');
else
return _SetError(ERROR_INVALID);
}
if (i == count)
return _SetError(ERROR_INVALID);
fInput.Skip(i + 1);
return _CreateSubstitutionNode(seqID + 1, _node);
}
bool
Demangler::_ParseBareFunctionType(FunctionNode* node)
{
DEBUG_SCOPE("_ParseBareFunctionType");
if (fInput.CharsRemaining() == 0)
return _SetError(ERROR_INVALID);
do {
Node* typeNode;
if (!_ParseType(typeNode))
return false;
node->AddType(typeNode);
} while (fInput.CharsRemaining() > 0 && fInput[0] != 'E'
&& fInput[0] != '.');
return true;
}
bool
Demangler::_ParseTemplateArgs(Node* node, Node*& _node)
{
DEBUG_SCOPE("_ParseTemplateArgs");
if (!_SkipExpected('I'))
return false;
if (fInput.CharsRemaining() == 0 || fInput[0] == 'E')
return _SetError(ERROR_INVALID);
TemplateNode* templateNode;
if (!NodeCreator<TemplateNode>(this)(node, templateNode))
return false;
_node = templateNode;
while (fInput.CharsRemaining() > 0 && fInput[0] != 'E') {
Node* arg;
if (!_ParseTemplateArg(arg))
return false;
templateNode->AddArgument(arg);
}
return _SkipExpected('E');
}
bool
Demangler::_ParseTemplateArg(Node*& _node)
{
DEBUG_SCOPE("_ParseTemplateArg");
if (fInput.CharsRemaining() == 0)
return _SetError(ERROR_INVALID);
switch (fInput[0]) {
case 'X':
fInput.Skip(1);
return _ParseExpression(_node) && _SkipExpected('E');
case 'L':
return _ParseExpressionPrimary(_node);
case 'I':
{
#if 0
fInput.Skip(1);
while (fInput.CharsRemaining() > 0 && fInput[0] != 'E') {
Node* arg;
if (!_ParseTemplateArg(arg))
return false;
}
if (!fInput.SkipPrefix('E'))
return _SetError(ERROR_INVALID);
return true;
#endif
return _SetError(ERROR_UNSUPPORTED);
}
case 's':
if (fInput.SkipPrefix("sp")) {
#if 0
return _ParseExpression(_node);
#endif
return _SetError(ERROR_UNSUPPORTED);
}
default:
return _ParseType(_node);
}
}
bool
Demangler::_ParseExpression(Node*& _node)
{
DEBUG_SCOPE("_ParseExpression");
if (fInput.CharsRemaining() == 0)
return _SetError(ERROR_INVALID);
switch (fInput[0]) {
case 'L':
return _ParseExpressionPrimary(_node);
case 'T':
return _ParseTemplateParam(_node);
}
if (fInput.CharsRemaining() < 2)
return _SetError(ERROR_INVALID);
if (fInput.SkipPrefix("cl")) {
CallNode* callNode;
if (!NodeCreator<CallNode>(this)(callNode))
return false;
while (fInput.CharsRemaining() > 0 && fInput[0] != 'E') {
Node* subExpression;
if (!_ParseExpression(subExpression))
return false;
callNode->AddSubExpression(subExpression);
}
_node = callNode;
return _SkipExpected('E');
}
if (fInput.SkipPrefix("cv")) {
Node* type;
if (!_ParseType(type))
return false;
ConversionExpressionNode* expression;
if (!NodeCreator<ConversionExpressionNode>(this)(type, expression))
return false;
_node = expression;
if (fInput.SkipPrefix('_')) {
while (fInput.CharsRemaining() > 0 && fInput[0] != 'E') {
Node* subExpression;
if (!_ParseExpression(subExpression))
return false;
expression->AddSubExpression(subExpression);
}
return _SkipExpected('E');
}
Node* subExpression;
if (!_ParseExpression(subExpression))
return false;
expression->AddSubExpression(subExpression);
return true;
}
if (fInput.SkipPrefix("sr")) {
Node* type;
Node* name;
if (!_ParseType(type) || !_ParseUnqualifiedName(name)
|| !NodeCreator<DependentNameNode>(this)(type, name, _node)) {
return false;
}
if (!fInput.HasPrefix('I'))
return true;
return _ParseTemplateArgs(_node, _node);
}
if (fInput.SkipPrefix("sZ")) {
return _SetError(ERROR_UNSUPPORTED);
}
const operator_info* info = NULL;
for (int i = 0; kOperatorInfos[i].name != NULL; i++) {
if (fInput.SkipPrefix(kOperatorInfos[i].mangled_name)) {
info = &kOperatorInfos[i];
break;
}
}
if (info == NULL || info->argument_count < 0)
return _SetError(ERROR_INVALID);
OperatorExpressionNode* operatorNode;
if (!NodeCreator<OperatorExpressionNode>(this)(info, operatorNode))
return false;
int i = 0;
if ((info->flags & OPERATOR_TYPE_PARAM) != 0) {
Node* type;
if (!_ParseType(type))
return false;
operatorNode->AddSubExpression(type);
i++;
}
for (; i < info->argument_count; i++) {
Node* subExpression;
if (!_ParseExpression(subExpression))
return false;
operatorNode->AddSubExpression(subExpression);
}
_node = operatorNode;
return true;
}
bool
Demangler::_ParseExpressionPrimary(Node*& _node)
{
DEBUG_SCOPE("_ParseExpressionPrimary");
if (!_SkipExpected('L'))
return false;
if (fInput.SkipPrefix("_Z")) {
ObjectNode* node;
if (!_ParseEncoding(node))
return false;
_node = node;
} else {
Node* type;
if (!_ParseType(type))
return false;
int maxLength = fInput.CharsRemaining();
int length = 0;
while (length < maxLength && fInput[length] != 'E')
length++;
if (length == 0)
return _SetError(ERROR_INVALID);
if (!NodeCreator<TypedNumberLiteralNode>(this)(type,
fInput.String(), length, _node)) {
return false;
}
fInput.Skip(length);
}
return _SkipExpected('E');
}
bool
Demangler::_ParseNumber(number_type& number)
{
DEBUG_SCOPE("_ParseNumber");
bool negative = fInput.SkipPrefix('n');
if (fInput.CharsRemaining() == 0)
return _SetError(ERROR_INVALID);
number = 0;
int count = fInput.CharsRemaining();
int i = 0;
for (; i < count && isdigit(fInput[i]); i++)
number = number * 10 + (fInput[i] - '0');
fInput.Skip(i);
if (negative)
number =-number;
return true;
}
bool
Demangler::_CreateNodeAndSkip(const char* name, size_t length, int toSkip,
Node*& _node)
{
if (toSkip > 0)
fInput.Skip(toSkip);
return NodeCreator<SimpleNameNode>(this)(name, length, _node);
}
bool
Demangler::_CreateNodeAndSkip(const char* name, int toSkip, Node*& _node)
{
return _CreateNodeAndSkip(name, strlen(name), toSkip, _node);
}
bool
Demangler::_CreateTypeNodeAndSkip(type_type type, int toSkip, Node*& _node)
{
if (toSkip > 0)
fInput.Skip(toSkip);
return NodeCreator<SimpleTypeNode>(this)(type, _node);
}
bool
Demangler::_CreateTypeNodeAndSkip(const char* name, const char* prefix,
const char* templateArgs, int toSkip, Node*& _node)
{
if (toSkip > 0)
fInput.Skip(toSkip);
if (!NodeCreator<SimpleTypeNode>(this)(name, _node))
return false;
if (prefix != NULL) {
Node* prefixNode;
if (!NodeCreator<SimpleTypeNode>(this)(prefix, prefixNode)
|| !NodeCreator<PrefixedNode>(this)(prefixNode, _node, _node)) {
return false;
}
}
if (templateArgs != NULL) {
TemplateNode* templateNode;
Node* argsNode;
if (!NodeCreator<TemplateNode>(this)(_node, templateNode)
|| !NodeCreator<SimpleTypeNode>(this)(templateArgs, argsNode)) {
return false;
}
templateNode->AddArgument(argsNode);
_node = templateNode;
}
return true;
}
void
Demangler::_RegisterReferenceableNode(Node* node)
{
if (!node->IsReferenceable() || node == fLastReferenceableNode
|| node->NextReferenceable() != NULL) {
return;
}
if (fFirstReferenceableNode == NULL) {
fFirstReferenceableNode = node;
fLastReferenceableNode = node;
} else {
fLastReferenceableNode->SetNextReferenceable(node);
fLastReferenceableNode = node;
}
}
bool
Demangler::_CreateSubstitutionNode(int index, Node*& _node)
{
Node* node = fFirstReferenceableNode;
while (node != NULL && index > 0) {
node = node->NextReferenceable();
index--;
}
if (node == NULL)
return _SetError(ERROR_INVALID);
return NodeCreator<SubstitutionNode>(this)(node, _node);
}
const char*
demangle_symbol_gcc3(const char* mangledName, char* buffer, size_t bufferSize,
bool* _isObjectMethod)
{
bool isObjectMethod;
if (_isObjectMethod == NULL)
_isObjectMethod = &isObjectMethod;
Demangler demangler;
DemanglingInfo info(true);
if (demangler.Demangle(mangledName, buffer, bufferSize, info) != ERROR_OK)
return NULL;
switch (info.objectType) {
case OBJECT_TYPE_DATA:
case OBJECT_TYPE_FUNCTION:
case OBJECT_TYPE_METHOD_CLASS:
*_isObjectMethod = false;
break;
case OBJECT_TYPE_METHOD_OBJECT:
*_isObjectMethod = true;
break;
case OBJECT_TYPE_UNKNOWN:
case OBJECT_TYPE_METHOD_UNKNOWN:
*_isObjectMethod = strstr(buffer, "::") != NULL;
break;
}
return buffer;
}
status_t
get_next_argument_gcc3(uint32* _cookie, const char* mangledName, char* name,
size_t nameSize, int32* _type, size_t* _argumentLength)
{
Demangler demangler;
ParameterInfo info;
int result = demangler.GetParameterInfo(mangledName, *_cookie, name,
nameSize, info);
if (result != ERROR_OK) {
switch (result) {
case ERROR_NOT_MANGLED:
return B_BAD_VALUE;
case ERROR_UNSUPPORTED:
return B_BAD_VALUE;
case ERROR_INVALID:
return B_BAD_VALUE;
case ERROR_BUFFER_TOO_SMALL:
return B_BUFFER_OVERFLOW;
case ERROR_NO_MEMORY:
return B_NO_MEMORY;
case ERROR_INVALID_PARAMETER_INDEX:
return B_BAD_INDEX;
case ERROR_INTERNAL:
default:
return B_ERROR;
}
}
switch (info.type.type) {
case TYPE_BOOL:
*_type = B_BOOL_TYPE;
*_argumentLength = 1;
break;
case TYPE_CHAR:
*_type = B_CHAR_TYPE;
*_argumentLength = 1;
break;
case TYPE_SIGNED_CHAR:
*_type = B_INT8_TYPE;
*_argumentLength = 1;
break;
case TYPE_UNSIGNED_CHAR:
*_type = B_UINT8_TYPE;
*_argumentLength = 1;
break;
case TYPE_SHORT:
*_type = B_INT16_TYPE;
*_argumentLength = 2;
break;
case TYPE_UNSIGNED_SHORT:
*_type = B_UINT16_TYPE;
*_argumentLength = 2;
break;
case TYPE_INT:
*_type = B_INT32_TYPE;
*_argumentLength = 4;
break;
case TYPE_UNSIGNED_INT:
*_type = B_UINT32_TYPE;
*_argumentLength = 4;
break;
case TYPE_LONG:
*_type = sizeof(long) == 4 ? B_INT32_TYPE : B_INT64_TYPE;
*_argumentLength = sizeof(long);
break;
case TYPE_UNSIGNED_LONG:
*_type = sizeof(long) == 4 ? B_UINT32_TYPE : B_UINT64_TYPE;
*_argumentLength = sizeof(long);
break;
case TYPE_LONG_LONG:
*_type = B_INT64_TYPE;
*_argumentLength = 8;
break;
case TYPE_UNSIGNED_LONG_LONG:
*_type = B_INT64_TYPE;
*_argumentLength = 8;
break;
case TYPE_INT128:
*_type = 0;
*_argumentLength = 16;
break;
case TYPE_UNSIGNED_INT128:
*_type = 0;
*_argumentLength = 16;
break;
case TYPE_FLOAT:
*_type = B_FLOAT_TYPE;
*_argumentLength = sizeof(float);
break;
case TYPE_DOUBLE:
*_type = B_DOUBLE_TYPE;
*_argumentLength = sizeof(double);
break;
case TYPE_LONG_DOUBLE:
*_type = 0;
*_argumentLength = sizeof(long double);
break;
case TYPE_FLOAT128:
*_type = 0;
*_argumentLength = 16;
break;
case TYPE_DFLOAT16:
*_argumentLength = 2;
case TYPE_DFLOAT32:
*_argumentLength *= 2;
case TYPE_DFLOAT64:
*_argumentLength *= 2;
case TYPE_DFLOAT128:
*_argumentLength *= 2;
*_type = 0;
break;
case TYPE_CHAR16_T:
*_type = B_UINT16_TYPE;
*_argumentLength = 2;
break;
case TYPE_CHAR32_T:
*_type = B_UINT32_TYPE;
*_argumentLength = 2;
break;
case TYPE_CONST_CHAR_POINTER:
*_type = B_STRING_TYPE;
*_argumentLength = sizeof(void*);
break;
case TYPE_POINTER:
*_type = B_POINTER_TYPE;
*_argumentLength = sizeof(void*);
break;
case TYPE_REFERENCE:
*_type = B_REF_TYPE;
*_argumentLength = sizeof(void*);
break;
case TYPE_WCHAR_T:
*_type = B_UINT16_TYPE;
*_argumentLength = 2;
break;
case TYPE_UNKNOWN:
case TYPE_ELLIPSIS:
case TYPE_VOID:
default:
*_type = 0;
*_argumentLength = sizeof(int);
}
if (*_argumentLength < sizeof(int))
*_argumentLength = sizeof(int);
++*_cookie;
return B_OK;
}
#ifndef _KERNEL_MODE
const char*
demangle_name_gcc3(const char* mangledName, char* buffer, size_t bufferSize)
{
Demangler demangler;
DemanglingInfo info(false);
if (demangler.Demangle(mangledName, buffer, bufferSize, info) != ERROR_OK)
return NULL;
return buffer;
}
#endif