/*
* Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
* 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"
// C++ ABI: http://www.codesourcery.com/public/cxx-abi/abi.html
//#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
#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
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
};
// 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<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 _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)
{
// 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));
// <mangled-name> ::= _Z <encoding>
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");
// <encoding> ::= <function name> <bare-function-type>
// ::= <data name>
// ::= <special-name>
// NOTE: This is not in the specs: Local entities seem to be prefixed
// by an 'L'.
fInput.SkipPrefix('L');
// parse <special-name>, if it is one
Node* name;
if (fInput.HasPrefix('T') || fInput.HasPrefix("GV")) {
return _ParseSpecialName(name)
&& NodeCreator<ObjectNode>(this)(name, _node);
}
// either <data name> or <function name>
if (!_ParseName(name))
return false;
if (fInput.CharsRemaining() == 0 || fInput.HasPrefix('E')) {
// <data name>
return NodeCreator<ObjectNode>(this)(name, _node);
}
// <function name> -- parse remaining <bare-function-type>
FunctionNode* functionNode;
if (!NodeCreator<FunctionNode>(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);
// <special-name> ::= GV <object name> # Guard variable for one-time
// # initialization
// # No <type>
if (!fInput.SkipPrefix('T')) {
Node* name;
return _SkipExpected("GV")
&& _ParseName(name)
&& NodeCreator<SpecialNameNode>(this)("guard variable for ",
name, _node);
}
// <special-name> ::= TV <type> # virtual table
// ::= TT <type> # VTT structure (construction vtable
// # index)
// ::= TI <type> # typeinfo structure
// ::= TS <type> # 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<SpecialNameNode>(this)(prefix, type, _node);
}
// <special-name> ::= Tc <call-offset> <call-offset> <base encoding>
// # 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<SpecialNameNode>(this)(
"covariant return thunk to ", name, _node);
}
// <special-name> ::= T <call-offset> <base encoding>
// # 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<SpecialNameNode>(this)(
nonVirtual ? "non-virtual thunk to " : "virtual thunk to ",
name, _node);
}
bool
Demangler::_ParseCallOffset(bool& nonVirtual, number_type& offset1,
number_type& offset2)
{
// <call-offset> ::= h <nv-offset> _
// ::= v <v-offset> _
// <nv-offset> ::= <offset number>
// # non-virtual base override
// <v-offset> ::= <offset number> _ <virtual offset number>
// # 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);
// <name> ::= <nested-name>
// ::= <unscoped-name>
// ::= <unscoped-template-name> <template-args>
// ::= <local-name> # See Scope Encoding below
//
// <unscoped-name> ::= <unqualified-name>
// ::= St <unqualified-name> # ::std::
//
// <unscoped-template-name> ::= <unscoped-name>
// ::= <substitution>
switch (fInput[0]) {
case 'N':
// <nested-name>
return _ParseNestedName(_node);
case 'Z':
// <local-name>
return _ParseLocalName(_node);
case 'S':
{
// <substitution>
if (!fInput.HasPrefix("St")) {
if (!_ParseSubstitution(_node))
return false;
break;
}
// std:: namespace
fInput.Skip(2);
Node* prefix;
if (!NodeCreator<SimpleNameNode>(this)("std", prefix))
return false;
// <unqualified-name>
Node* node;
if (!_ParseUnqualifiedName(node)
|| !NodeCreator<PrefixedNode>(this)(prefix, node, _node)) {
return false;
}
break;
}
default:
// <unqualified-name>
if (!_ParseUnqualifiedName(_node))
return false;
break;
}
// We get here for the names that might be an <unscoped-template-name>.
// Check whether <template-args> are following.
if (!fInput.HasPrefix('I'))
return true;
// <unscoped-template-name> is referenceable
_RegisterReferenceableNode(_node);
return _ParseTemplateArgs(_node, _node);
}
bool
Demangler::_ParseNestedName(Node*& _node)
{
DEBUG_SCOPE("_ParseNestedName");
// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
// ::= N [<CV-qualifiers>] <template-prefix>
// <template-args> E
//
// <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const
//
// <prefix> ::= <prefix> <unqualified-name>
// ::= <template-prefix> <template-args>
// ::= <template-param>
// ::= # empty
// ::= <substitution>
//
// <template-prefix> ::= <prefix> <template unqualified-name>
// ::= <template-param>
// ::= <substitution>
if (!_SkipExpected('N'))
return false;
// parse CV qualifiers
int qualifiers;
_ParseCVQualifiers(qualifiers);
// parse the main part
if (!_ParseNestedNameInternal(_node))
return false;
// create a CV qualifiers wrapper node, if necessary
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);
// the initial prefix might be a template param or a substitution
Node* initialPrefixNode = NULL;
Node* prefixNode = NULL;
switch (fInput[0]) {
case 'T': // <template-param>
if (!_ParseTemplateParam(initialPrefixNode))
return false;
// a <prefix> or <template-prefix> and as such referenceable
_RegisterReferenceableNode(initialPrefixNode);
break;
case 'S': // <substitution>
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;
}
// join prefix and the new node
if (prefixNode != NULL) {
if (!NodeCreator<PrefixedNode>(this)(prefixNode, node, node))
return false;
}
// template arguments?
if (fInput.HasPrefix('I')) {
// <template-prefix> is referenceable
_RegisterReferenceableNode(node);
// parse the template arguments
if (!_ParseTemplateArgs(node, node))
return false;
canTerminate = true;
}
if (fInput.CharsRemaining() == 0)
return _SetError(ERROR_INVALID);
// end of nested name?
if (fInput.SkipPrefix('E')) {
// If it doesn't have template args, it must end in an
// unqualified name.
if (!canTerminate)
return _SetError(ERROR_INVALID);
_node = node;
return true;
}
// The fun continues, so this is a <prefix> or <template-prefix>
// and as such referenceable.
prefixNode = node;
_RegisterReferenceableNode(node);
}
}
bool
Demangler::_ParseLocalName(Node*& _node)
{
DEBUG_SCOPE("_ParseLocalName");
// <local-name> := Z <function encoding> E <entity name>
// [<discriminator>]
// := Z <function encoding> E s [<discriminator>]
// <discriminator> := _ <non-negative number>
// parse the function name
ObjectNode* functionName;
if (!_SkipExpected('Z')
|| !_ParseEncoding(functionName)
|| !_SkipExpected('E')) {
return false;
}
Node* entityName;
if (fInput.SkipPrefix('s')) {
// string literal
if (!NodeCreator<SimpleNameNode>(this)("string literal",
entityName)) {
return false;
}
} else {
// local type or object
if (!_ParseName(entityName))
return false;
}
// parse discriminator
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");
// <unqualified-name> ::= <operator-name>
// ::= <ctor-dtor-name>
// ::= <source-name>
//
// <source-name> ::= <positive length number> <identifier>
// <number> ::= [n] <non-negative decimal integer>
// <identifier> ::= <unqualified source code identifier>
//
// <ctor-dtor-name> ::= C1 # complete object constructor
// ::= C2 # base object constructor
// ::= C3 # complete object allocating constructor
// ::= D0 # deleting destructor
// ::= D1 # complete object destructor
// ::= D2 # base object destructor
// we need at least 2 chars
if (fInput.CharsRemaining() < 2)
return _SetError(ERROR_INVALID);
if (isdigit(fInput[0]) || (fInput[0] == 'n' && isdigit(fInput[1]))) {
// <source-name>
return _ParseSourceName(_node);
}
if (fInput[0] == 'C') {
// <ctor-dtor-name> -- constructors
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') {
// <ctor-dtor-name> -- destructors
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);
}
}
// must be an <operator-name>
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);
// <operator-name> ::= cv <type> # (cast)
if (fInput.SkipPrefix("cv")) {
Node* typeNode;
if (!_ParseType(typeNode))
return false;
return NodeCreator<CastOperatorNode>(this)(typeNode, _node);
}
// <operator-name> ::= v <digit> <source-name> # vendor extended
// operator
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");
// <type> ::= <builtin-type>
// ::= <function-type>
// ::= <class-enum-type>
// ::= <array-type>
// ::= <pointer-to-member-type>
// ::= <template-param>
// ::= <template-template-param> <template-args>
// ::= <substitution> # See Compression below
//
// <template-template-param> ::= <template-param>
// ::= <substitution>
//
// <type> ::= <CV-qualifiers> <type>
// ::= P <type> # pointer-to
// ::= R <type> # reference-to
// ::= O <type> # rvalue reference-to (C++0x)
// ::= C <type> # complex pair (C 2000)
// ::= G <type> # imaginary (C 2000)
// ::= U <source-name> <type> # vendor extended type qualifier
//
// <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const
//
// <type> ::= Dp <type> # pack expansion of (C++0x)
// ::= Dt <expression> E # decltype of an id-expression or
// # class member access (C++0x)
// ::= DT <expression> E # decltype of an expression (C++0x)
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]) {
// function type
case 'F':
{
FunctionNode* functionNode;
if (!_ParseFunctionType(functionNode))
return false;
_node = functionNode;
return true;
}
// array type
case 'A':
return _ParseArrayType(_node);
// pointer to member type
case 'M':
return _ParsePointerToMemberType(_node);
// template param
case 'T':
if (!_ParseTemplateParam(_node))
return false;
break;
// CV qualifiers
case 'r':
case 'V':
case 'K':
{
// parse CV qualifiers
int qualifiers;
_ParseCVQualifiers(qualifiers);
// parse the type
if (!_ParseType(_node))
return false;
// create the wrapper node
return NodeCreator<CVQualifiersNode>(this)(qualifiers, _node,
_node);
}
// pointer, reference, etc.
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);
// pack and decltype
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
// NOTE: Unsupported by the GNU demangler.
return _SetError(ERROR_UNSUPPORTED);
// vendor extended type qualifier
case 'U':
fInput.Skip(1);
Node* name;
Node* type;
return _ParseSourceName(name) && _ParseType(type)
&& NodeCreator<VendorTypeModifierNode>(this)(name, type,
_node);
// substitution
case 'S':
if (!fInput.HasPrefix("St")) {
if (!_ParseSubstitution(_node))
return false;
break;
}
// "St" -- the "std" namespace. The grammar is ambiguous here,
// since we could parse that as <substitution> or as
// <class-enum-type>. We assume the latter and fall through.
default:
{
// <class-enum-type> ::= <name>
Node* nameNode;
return _ParseName(nameNode)
&& NodeCreator<NamedTypeNode>(this)(nameNode, _node);
}
}
// We get here for the types that might be a <template-template-param>.
// Check whether <template-args> are following.
if (!fInput.HasPrefix('I'))
return true;
// <template-template-param> is referenceable
_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");
// <builtin-type> ::= v # void
// ::= w # wchar_t
// ::= b # bool
// ::= c # char
// ::= a # signed char
// ::= h # unsigned char
// ::= s # short
// ::= t # unsigned short
// ::= i # int
// ::= j # unsigned int
// ::= l # long
// ::= m # unsigned long
// ::= x # long long, __int64
// ::= y # unsigned long long, __int64
// ::= n # __int128
// ::= o # unsigned __int128
// ::= f # float
// ::= d # double
// ::= e # long double, __float80
// ::= g # __float128
// ::= z # ellipsis
// ::= Dd # IEEE 754r decimal floating point (64 bits)
// ::= De # IEEE 754r decimal floating point (128 bits)
// ::= Df # IEEE 754r decimal floating point (32 bits)
// ::= Dh # IEEE 754r half-precision floating point
// # (16 bits)
// ::= Di # char32_t
// ::= Ds # char16_t
// ::= u <source-name> # vendor extended type
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;
// TODO: Official names for the __dfloat*!
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");
// <function-type> ::= F [Y] <bare-function-type> E
if (!_SkipExpected('F'))
return false;
// is 'extern "C"'?
bool isExternC = fInput.SkipPrefix('Y');
// create function and parse function type
if (!NodeCreator<FunctionNode>(this)((Node*)NULL, true, isExternC,
_node)
|| !_ParseBareFunctionType(_node)) {
return false;
}
// skip terminating 'E'
return _SkipExpected('E');
}
bool
Demangler::_ParseArrayType(Node*& _node)
{
DEBUG_SCOPE("_ParseArrayType");
// <array-type> ::= A <positive dimension number> _ <element type>
// ::= A [<dimension expression>] _ <element type>
if (fInput.CharsRemaining() < 2 || !fInput.SkipPrefix('A'))
return _SetError(ERROR_INVALID);
number_type dimensionNumber;
Node* dimensionExpression = NULL;
// If it looks like a number, it must be the first production, otherwise
// the second one.
if (isdigit(fInput[0])
|| (fInput[0] == 'n' && fInput.CharsRemaining() >= 2
&& isdigit(fInput[1]))) {
if (!_ParseNumber(dimensionNumber))
return false;
} else {
if (!_ParseExpression(dimensionExpression))
return false;
}
// parse the type
Node* type;
if (!_SkipExpected('_') || !_ParseType(type))
return false;
// create the array node
return dimensionExpression != NULL
? NodeCreator<ArrayNode>(this)(type, dimensionExpression, _node)
: NodeCreator<ArrayNode>(this)(type, dimensionNumber, _node);
}
bool
Demangler::_ParsePointerToMemberType(Node*& _node)
{
DEBUG_SCOPE("_ParsePointerToMemberType");
// <pointer-to-member-type> ::= M <class type> <member type>
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");
// <template-param> ::= T_ # first template parameter
// ::= T <parameter-2 non-negative number> _
if (!_SkipExpected('T'))
return false;
if (fTemplatizedNode == NULL)
return _SetError(ERROR_INVALID);
// get the index;
number_type index = 0;
if (!fInput.HasPrefix('_')) {
if (!_ParseNumber(index))
return false;
if (index < 0)
return _SetError(ERROR_INVALID);
index++;
}
if (!_SkipExpected('_'))
return false;
// get the parameter
Node* parameter = fTemplatizedNode->TemplateParameterAt(index);
if (parameter == NULL)
return _SetError(ERROR_INVALID);
// create a substitution node
return NodeCreator<SubstitutionNode>(this)(parameter, _node);
}
bool
Demangler::_ParseSubstitution(Node*& _node)
{
DEBUG_SCOPE("_ParseSubstitution");
if (!_ParseSubstitutionInternal(_node))
return false;
// substitutions are never referenceable
_node->SetReferenceable(false);
return true;
}
bool
Demangler::_ParseSubstitutionInternal(Node*& _node)
{
DEBUG_SCOPE("_ParseSubstitutionInternal");
// <substitution> ::= S <seq-id> _
// ::= S_
//
// <substitution> ::= St # ::std::
// <substitution> ::= Sa # ::std::allocator
// <substitution> ::= Sb # ::std::basic_string
// <substitution> ::= Ss # ::std::basic_string < char,
// ::std::char_traits<char>,
// ::std::allocator<char> >
// <substitution> ::= Si # ::std::basic_istream<char,
// std::char_traits<char> >
// <substitution> ::= So # ::std::basic_ostream<char,
// std::char_traits<char> >
// <substitution> ::= Sd # ::std::basic_iostream<char,
// std::char_traits<char> >
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);
}
// parse <seq-id>
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);
// skip digits and '_'
fInput.Skip(i + 1);
return _CreateSubstitutionNode(seqID + 1, _node);
}
bool
Demangler::_ParseBareFunctionType(FunctionNode* node)
{
DEBUG_SCOPE("_ParseBareFunctionType");
// <bare-function-type> ::= <signature type>+
// # types are possible return type, then parameter types
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');
// 'E' delimits <function-type>
return true;
}
bool
Demangler::_ParseTemplateArgs(Node* node, Node*& _node)
{
DEBUG_SCOPE("_ParseTemplateArgs");
// <template-args> ::= I <template-arg>+ E
if (!_SkipExpected('I'))
return false;
// we need at least one <template-arg>
if (fInput.CharsRemaining() == 0 || fInput[0] == 'E')
return _SetError(ERROR_INVALID);
// create the node
TemplateNode* templateNode;
if (!NodeCreator<TemplateNode>(this)(node, templateNode))
return false;
_node = templateNode;
// parse the args
while (fInput.CharsRemaining() > 0 && fInput[0] != 'E') {
Node* arg;
if (!_ParseTemplateArg(arg))
return false;
templateNode->AddArgument(arg);
}
// skip the trailing 'E'
return _SkipExpected('E');
}
bool
Demangler::_ParseTemplateArg(Node*& _node)
{
DEBUG_SCOPE("_ParseTemplateArg");
// <template-arg> ::= <type> # type or template
// ::= X <expression> E # expression
// ::= <expr-primary> # simple expressions
// ::= I <template-arg>* E # argument pack
// ::= sp <expression> # pack expansion of (C++0x)
if (fInput.CharsRemaining() == 0)
return _SetError(ERROR_INVALID);
switch (fInput[0]) {
case 'X': // X <expression> E
fInput.Skip(1);
return _ParseExpression(_node) && _SkipExpected('E');
case 'L': // <expr-primary>
return _ParseExpressionPrimary(_node);
case 'I': // I <template-arg>* E
{
#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
// NOTE: Unsupported by the GNU demangler.
return _SetError(ERROR_UNSUPPORTED);
}
case 's':
if (fInput.SkipPrefix("sp")) {
// sp <expression>
#if 0
return _ParseExpression(_node);
#endif
// NOTE: Unsupported by the GNU demangler.
return _SetError(ERROR_UNSUPPORTED);
}
// fall through...
default: // <type>
return _ParseType(_node);
}
}
bool
Demangler::_ParseExpression(Node*& _node)
{
DEBUG_SCOPE("_ParseExpression");
// <expression> ::= <unary operator-name> <expression>
// ::= <binary operator-name> <expression> <expression>
// ::= <trinary operator-name> <expression> <expression>
// <expression>
// ::= cl <expression>* E # call
// ::= cv <type> expression # conversion with one
// argument
// ::= cv <type> _ <expression>* E # conversion with a
// different number of
// arguments
// ::= st <type> # sizeof (a type)
// ::= at <type> # alignof (a type)
// ::= <template-param>
// ::= <function-param>
// ::= sr <type> <unqualified-name>
// # dependent name
// ::= sr <type> <unqualified-name> <template-args>
// # dependent template-id
// ::= sZ <template-param>
// # size of a parameter pack
// ::= <expr-primary>
//
// <expr-primary> ::= L <type> <value number> E # integer literal
// ::= L <type <value float> E # floating literal
// ::= L <mangled-name> E # external name
if (fInput.CharsRemaining() == 0)
return _SetError(ERROR_INVALID);
switch (fInput[0]) {
case 'L':
return _ParseExpressionPrimary(_node);
case 'T':
return _ParseTemplateParam(_node);
// NOTE: <function-param> is not defined in the specs!
}
// must be an operator
if (fInput.CharsRemaining() < 2)
return _SetError(ERROR_INVALID);
// some operators need special handling
if (fInput.SkipPrefix("cl")) {
// cl <expression>* E # call
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")) {
// cv <type> expression # conversion with one argument
// cv <type> _ <expression>* E # conversion with a different number
// of arguments
// parse the type
Node* type;
if (!_ParseType(type))
return false;
// create a conversion expression node
ConversionExpressionNode* expression;
if (!NodeCreator<ConversionExpressionNode>(this)(type, expression))
return false;
_node = expression;
if (fInput.SkipPrefix('_')) {
// multi argument conversion
while (fInput.CharsRemaining() > 0 && fInput[0] != 'E') {
Node* subExpression;
if (!_ParseExpression(subExpression))
return false;
expression->AddSubExpression(subExpression);
}
return _SkipExpected('E');
}
// single argument conversion
Node* subExpression;
if (!_ParseExpression(subExpression))
return false;
expression->AddSubExpression(subExpression);
return true;
}
if (fInput.SkipPrefix("sr")) {
// sr <type> <unqualified-name>
// sr <type> <unqualified-name> <template-args>
// parse type and unqualified name and create the node
Node* type;
Node* name;
if (!_ParseType(type) || !_ParseUnqualifiedName(name)
|| !NodeCreator<DependentNameNode>(this)(type, name, _node)) {
return false;
}
// If there are template arguments left, add them.
if (!fInput.HasPrefix('I'))
return true;
return _ParseTemplateArgs(_node, _node);
}
if (fInput.SkipPrefix("sZ")) {
// sZ <template-param>
// NOTE: Unsupported by the GNU demangler.
return _SetError(ERROR_UNSUPPORTED);
}
// no special operator, so have a look for the others
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;
}
}
// We can only deal with operators with a fixed argument count at this
// point.
if (info == NULL || info->argument_count < 0)
return _SetError(ERROR_INVALID);
// create an operator node
OperatorExpressionNode* operatorNode;
if (!NodeCreator<OperatorExpressionNode>(this)(info, operatorNode))
return false;
// parse the arguments
int i = 0;
// the first one might be a type
if ((info->flags & OPERATOR_TYPE_PARAM) != 0) {
Node* type;
if (!_ParseType(type))
return false;
operatorNode->AddSubExpression(type);
i++;
}
// the others are expressions
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");
// <expr-primary> ::= L <type> <value number> E # integer literal
// ::= L <type <value float> E # floating literal
// ::= L <mangled-name> E # external name
if (!_SkipExpected('L'))
return false;
if (fInput.SkipPrefix("_Z")) {
ObjectNode* node;
if (!_ParseEncoding(node))
return false;
_node = node;
} else {
// number or float literal
Node* type;
if (!_ParseType(type))
return false;
// GNU's demangler doesn't really seem to parse the integer/float,
// but only replaces a leading 'n' by '-'. Good enough for us, too.
// determine the length
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);
// create the name node
if (!NodeCreator<SimpleTypeNode>(this)(name, _node))
return false;
// add the prefix
if (prefix != NULL) {
Node* prefixNode;
if (!NodeCreator<SimpleTypeNode>(this)(prefix, prefixNode)
|| !NodeCreator<PrefixedNode>(this)(prefixNode, _node, _node)) {
return false;
}
}
// wrap the node to add the template args
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)
{
// check, if not referenceable or already registered
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);
// create a substitution node
return NodeCreator<SubstitutionNode>(this)(node, _node);
}
// #pragma mark -
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;
// Set the object method return value. Unless we know for sure that it isn't
// an object method, we assume that it is.
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;
}
}
// translate the type
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;
// TODO: That's actually entry_ref!
*_argumentLength = sizeof(void*);
break;
case TYPE_WCHAR_T:
// TODO: Type/size might change!
*_type = B_UINT16_TYPE;
*_argumentLength = 2;
break;
case TYPE_UNKNOWN:
case TYPE_ELLIPSIS:
case TYPE_VOID:
default:
// Well, tell our caller *something*.
*_type = 0;
*_argumentLength = sizeof(int);
}
// assume sizeof(int) argument alignment
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
↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fUnqualifiedNode.