summaryrefslogtreecommitdiff
path: root/demangler/gnu3
diff options
context:
space:
mode:
authorPeter LaFosse <peter@vector35.com>2026-03-10 12:27:34 -0400
committerPeter LaFosse <peter@vector35.com>2026-03-26 17:56:23 -0400
commit260ca61d94134b6743807e29f64b5ce4f6918d73 (patch)
tree9b77dc9990873549f096c5eae00a2b924215946b /demangler/gnu3
parent0789f70c4a7496cf23672011cdb5bf5b8a5738c6 (diff)
Rewrite GNU3 demangler for performance using DemangledTypeNode
Replace the TypeBuilder-based demangling path with a lightweight DemangledTypeNode representation that defers type object construction until the symbol is fully parsed. This avoids repeated heap allocation and ref-count churn during recursive descent. Key changes: - Add DemangledTypeNode / demangled_type_node.{h,cpp}: a compact IR that mirrors the type grammar without allocating BN Type objects - Use a thread_local demangler instance to amortize vector allocations across calls - Also commonize some of the demangled string length calculations. Result: ~3x throughput improvement on a 180K-symbol corpus with 97.7% success rate (matching the previous implementation). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'demangler/gnu3')
-rw-r--r--demangler/gnu3/demangle_gnu3.cpp821
-rw-r--r--demangler/gnu3/demangle_gnu3.h134
-rw-r--r--demangler/gnu3/demangled_type_node.cpp531
-rw-r--r--demangler/gnu3/demangled_type_node.h171
4 files changed, 1209 insertions, 448 deletions
diff --git a/demangler/gnu3/demangle_gnu3.cpp b/demangler/gnu3/demangle_gnu3.cpp
index d36fcedf..c8fec64f 100644
--- a/demangler/gnu3/demangle_gnu3.cpp
+++ b/demangler/gnu3/demangle_gnu3.cpp
@@ -49,8 +49,7 @@ void MyLogDebug(string fmt, ...)
#else
#define indent()
#define dedent()
-void MyLogDebug(string fmt, ...)
-{ (void)fmt; }
+#define MyLogDebug(...) do {} while(0)
#endif
static inline void rtrim(string &s)
@@ -59,78 +58,218 @@ static inline void rtrim(string &s)
}
-static string GetTemplateString(vector<FunctionParameter> args)
+static size_t TotalStringSize(const _STD_VECTOR<_STD_STRING>& v)
+{
+ size_t n = 0;
+ for (const auto& s : v)
+ n += s.size();
+ return n;
+}
+
+
+static string GetTemplateString(const vector<string>& args)
{
- string name = "<";
+ // Pre-calculate total length to avoid reallocations
+ size_t total = 2; // "<" + ">"
for (size_t i = 0; i < args.size(); i++)
{
if (i != 0)
- {
- name += ", ";
- }
+ total += 2; // ", "
+ total += args[i].size();
+ }
+ total += 1; // possible " " before ">"
- name += args[i].name;
+ string name;
+ name.reserve(total);
+ name += '<';
+ for (size_t i = 0; i < args.size(); i++)
+ {
+ if (i != 0)
+ name += ", ";
+ name += args[i];
}
rtrim(name);
if (name.back() == '>')
name += " "; //Be c++03 compliant where we can
- name += ">";
+ name += '>';
return name;
}
-static void ExtendTypeName(TypeBuilder& type, const string& extend)
+static string GetOperator(char elm1, char elm2)
{
- QualifiedName qn = type.GetTypeName();
- if (qn.StringSize() + extend.size() > MAX_DEMANGLE_LENGTH)
- throw DemangleException("Detected adversarial mangled string");
- if (qn.size() > 0)
- qn.back() += extend;
- else
- qn.push_back(extend);
-
- // This type might not be an NTR (Vector35/binaryninja-api#6261)
- if (type.GetClass() == NamedTypeReferenceClass)
+ switch (hash(elm1, elm2))
{
- type.SetNamedTypeReference(
- NamedTypeReference::GenerateAutoDemangledTypeReference(type.GetNamedTypeReference()->GetTypeReferenceClass(), qn)
- );
+ case hash('d','c'): return "dynamic_cast";
+ case hash('s','c'): return "static_cast";
+ case hash('c','c'): return "const_cast";
+ case hash('r','c'): return "reinterpret_cast";
+ case hash('t','i'): return "typeid";
+ case hash('t','e'): return "typeid";
+ case hash('s','t'): return "sizeof";
+ case hash('s','z'): return "sizeof";
+ case hash('a','t'): return "alignof";
+ case hash('a','z'): return "alignof";
+ case hash('n','x'): return "noexcept";
+ case hash('s','Z'): return "sizeof...";
+ case hash('s','P'): return "sizeof...";
+ case hash('s','p'): return "";
+ case hash('t','w'): return "throw";
+ case hash('t','r'): return "throw";
+ case hash('l','s'): return "<<"; // <<
+ case hash('r','s'): return ">>"; // >>
+ case hash('a','S'): return "="; // =
+ case hash('n','t'): return "!"; // !
+ case hash('e','q'): return "=="; // ==
+ case hash('n','e'): return "!="; // !=
+ case hash('i','x'): return "[]"; // []
+ case hash('d','t'): return "."; // .
+ case hash('p','t'): return "->"; // ->
+ case hash('m','l'): return "*"; // *
+ case hash('p','p'): return "++"; // ++ (postfix in <expression> context)
+ case hash('m','m'): return "--"; // -- (postfix in <expression> context)
+ case hash('n','g'): return "-"; // - (unary)
+ case hash('m','i'): return "-"; // -
+ case hash('p','s'): return "+"; // + (unary)
+ case hash('p','l'): return "+"; // +
+ case hash('a','d'): return "&"; // & (unary)
+ case hash('a','n'): return "&"; // &
+ case hash('p','m'): return "->*"; // ->*
+ case hash('d','v'): return "/"; // /
+ case hash('r','m'): return "%"; // %
+ case hash('l','t'): return "<"; // <
+ case hash('l','e'): return "<="; // <=
+ case hash('g','t'): return ">"; // >
+ case hash('g','e'): return ">="; // >=
+ case hash('c','m'): return ","; // ,
+ case hash('c','l'): return "()"; // ()
+ case hash('c','o'): return "~"; // ~
+ case hash('e','o'): return "^"; // ^
+ case hash('o','r'): return "|"; // |
+ case hash('a','a'): return "&&"; // &&
+ case hash('o','o'): return "||"; // ||
+ case hash('d','e'): return "*"; // * (unary)
+ case hash('m','L'): return "*="; // *=
+ case hash('p','L'): return "+="; // +=
+ case hash('m','I'): return "-="; // -=
+ case hash('d','V'): return "/="; // /=
+ case hash('r','M'): return "%="; // %=
+ case hash('r','S'): return ">>="; // >>=
+ case hash('l','S'): return "<<="; // <<=
+ case hash('a','N'): return "&="; // &=
+ case hash('o','R'): return "|="; // |=
+ case hash('e','O'): return "^="; // ^=
+ case hash('d','l'): return "delete"; // delete
+ case hash('d','a'): return "delete[]"; // delete[]
+ case hash('n','w'): return "new"; // new
+ case hash('n','a'): return "new[]"; // new []
+ default: return "";
}
}
-
-static TypeBuilder CreateUnknownType(const QualifiedName& s)
+static BNNameType GetNameType(char elm1, char elm2)
{
- return TypeBuilder::NamedType(NamedTypeReference::GenerateAutoDemangledTypeReference(UnknownNamedTypeClass, s));
+ switch (hash(elm1, elm2))
+ {
+ case hash('n','t'): return OperatorNotNameType; // !
+ case hash('n','g'): return OperatorMinusNameType; // - (unary)
+ case hash('p','s'): return OperatorPlusNameType; // + (unary)
+ case hash('a','d'): return OperatorBitAndNameType; // & (unary)
+ case hash('d','e'): return OperatorStarNameType; // * (unary)
+ case hash('i','x'): return OperatorArrayNameType; // []
+ case hash('p','p'): return OperatorIncrementNameType; // ++ (postfix in <expression> context)
+ case hash('m','m'): return OperatorDecrementNameType; // -- (postfix in <expression> context)
+ case hash('l','s'): return OperatorLeftShiftNameType; // <<
+ case hash('r','s'): return OperatorRightShiftNameType; // >>
+ case hash('a','S'): return OperatorAssignNameType; // =
+ case hash('e','q'): return OperatorEqualNameType; // ==
+ case hash('n','e'): return OperatorNotEqualNameType; // !=
+ case hash('p','t'): return OperatorArrowNameType; // ->
+ case hash('m','l'): return OperatorStarNameType; // *
+ case hash('m','i'): return OperatorMinusNameType; // -
+ case hash('p','l'): return OperatorPlusNameType; // +
+ case hash('a','n'): return OperatorBitAndNameType; // &
+ case hash('p','m'): return OperatorArrowStarNameType; // ->*
+ case hash('d','v'): return OperatorDivideNameType; // /
+ case hash('r','m'): return OperatorModulusNameType; // %
+ case hash('l','t'): return OperatorLessThanNameType; // <
+ case hash('l','e'): return OperatorLessThanEqualNameType; // <=
+ case hash('g','t'): return OperatorGreaterThanNameType; // >
+ case hash('g','e'): return OperatorGreaterThanEqualNameType; // >=
+ case hash('c','m'): return OperatorCommaNameType; // ,
+ case hash('c','l'): return OperatorParenthesesNameType; // ()
+ case hash('c','o'): return OperatorTildeNameType; // ~
+ case hash('e','o'): return OperatorXorNameType; // ^
+ case hash('o','r'): return OperatorBitOrNameType; // |
+ case hash('a','a'): return OperatorLogicalAndNameType; // &&
+ case hash('o','o'): return OperatorLogicalOrNameType; // ||
+ case hash('m','L'): return OperatorStarEqualNameType; // *=
+ case hash('p','L'): return OperatorPlusEqualNameType; // +=
+ case hash('m','I'): return OperatorMinusEqualNameType; // -=
+ case hash('d','V'): return OperatorDivideEqualNameType; // /=
+ case hash('r','M'): return OperatorModulusEqualNameType; // %=
+ case hash('r','S'): return OperatorRightShiftEqualNameType; // >>=
+ case hash('l','S'): return OperatorLeftShiftEqualNameType; // <<=
+ case hash('a','N'): return OperatorAndEqualNameType; // &=
+ case hash('o','R'): return OperatorOrEqualNameType; // |=
+ case hash('e','O'): return OperatorXorEqualNameType; // ^=
+ case hash('d','l'): return OperatorDeleteNameType; // delete
+ case hash('d','a'): return OperatorDeleteArrayNameType; // delete[]
+ case hash('n','w'): return OperatorNewNameType; // new
+ case hash('n','a'): return OperatorNewArrayNameType; // new []
+ case hash('C','1'): return ConstructorNameType;
+ case hash('C','2'): return ConstructorNameType;
+ case hash('C','3'): return ConstructorNameType;
+ case hash('C','4'): return ConstructorNameType;
+ case hash('C','5'): return ConstructorNameType;
+ case hash('D','0'): return DestructorNameType;
+ case hash('D','1'): return DestructorNameType;
+ case hash('D','2'): return DestructorNameType;
+ case hash('D','3'): return DestructorNameType;
+ case hash('D','4'): return DestructorNameType;
+ case hash('D','5'): return DestructorNameType;
+ default:
+ return NoNameType;
+ }
}
-
-static TypeBuilder CreateUnknownType(const string& s)
+static int8_t HexToDec(char c)
{
- return TypeBuilder::NamedType(NamedTypeReference::GenerateAutoDemangledTypeReference(UnknownNamedTypeClass, {s}));
+ if (isdigit(c))
+ {
+ return c - '0';
+ }
+ else if(islower(c) && c <= 'f')
+ {
+ return c - 'a' + 10;
+ }
+ return -1;
}
-DemangleGNU3::Reader::Reader(const string& data): m_data(data), m_offset(0)
+
+// ===== Reader implementation (non-templated) =====
+
+DemangleGNU3Reader::DemangleGNU3Reader(const string& data): m_data(data), m_offset(0)
{}
-string DemangleGNU3::Reader::PeekString(size_t count)
+void DemangleGNU3Reader::Reset(const string& data)
{
- if (count > Length())
- return "\0";
- return m_data.substr(m_offset, count);
+ m_data = data;
+ m_offset = 0;
}
-char DemangleGNU3::Reader::Peek()
+string DemangleGNU3Reader::PeekString(size_t count)
{
- if (1 > Length())
- return '\0';
- return (char)m_data[m_offset];
+ if (count > Length())
+ return "\0";
+ return m_data.substr(m_offset, count);
}
-bool DemangleGNU3::Reader::NextIsOneOf(const string& list)
+
+bool DemangleGNU3Reader::NextIsOneOf(const string& list)
{
char elm = Peek();
for (auto a : list)
@@ -142,21 +281,14 @@ bool DemangleGNU3::Reader::NextIsOneOf(const string& list)
}
-string DemangleGNU3::Reader::GetRaw()
+string DemangleGNU3Reader::GetRaw()
{
return m_data.substr(m_offset);
}
-char DemangleGNU3::Reader::Read()
-{
- if (1 > Length())
- throw DemangleException();
- return m_data[m_offset++];
-}
-
-string DemangleGNU3::Reader::ReadString(size_t count)
+string DemangleGNU3Reader::ReadString(size_t count)
{
if (count > Length())
throw DemangleException();
@@ -167,7 +299,7 @@ string DemangleGNU3::Reader::ReadString(size_t count)
}
-string DemangleGNU3::Reader::ReadUntil(char sentinal)
+string DemangleGNU3Reader::ReadUntil(char sentinal)
{
size_t pos = m_data.find_first_of(sentinal, m_offset);
if (pos == string::npos)
@@ -176,46 +308,74 @@ string DemangleGNU3::Reader::ReadUntil(char sentinal)
}
-void DemangleGNU3::Reader::UnRead(size_t count)
+
+// ===== DemangleGNU3 implementation =====
+
+DemangleGNU3::DemangleGNU3(Architecture* arch, const string& mangledName) :
+ m_reader(mangledName),
+ m_arch(arch),
+ m_isParameter(false),
+ m_shouldDeleteReader(true),
+ m_topLevel(true),
+ m_isOperatorOverload(false)
{
- if (count <= m_offset)
- m_offset -= count;
+ MyLogDebug("%s : %s\n", __FUNCTION__, m_reader.GetRaw().c_str());
}
-void DemangleGNU3::Reader::Consume(size_t count)
+void DemangleGNU3::Reset(Architecture* arch, const string& mangledName)
{
- if (count > Length())
- throw DemangleException();
- m_offset += count;
+ m_reader.Reset(mangledName);
+ m_arch = arch;
+ m_varName.clear();
+ m_substitute.clear();
+ m_templateSubstitute.clear();
+ m_functionSubstitute.clear();
+ m_lastName.clear();
+ m_nameType = {};
+ m_localType = {};
+ m_hasReturnType = {};
+ m_isParameter = false;
+ m_shouldDeleteReader = true;
+ m_topLevel = true;
+ m_isOperatorOverload = false;
}
-size_t DemangleGNU3::Reader::Length() const
+DemangledTypeNode DemangleGNU3::CreateUnknownType(const QualifiedName& s)
{
- return m_data.length() - m_offset;
+ return DemangledTypeNode::NamedType(UnknownNamedTypeClass, s);
}
-DemangleGNU3::DemangleGNU3(Architecture* arch, const string& mangledName) :
- m_reader(mangledName),
- m_arch(arch),
- m_isParameter(false),
- m_shouldDeleteReader(true),
- m_topLevel(true),
- m_isOperatorOverload(false)
+DemangledTypeNode DemangleGNU3::CreateUnknownType(const string& s)
{
- MyLogDebug("%s : %s\n", __FUNCTION__, m_reader.GetRaw().c_str());
+ return DemangledTypeNode::NamedType(UnknownNamedTypeClass, _STD_VECTOR<_STD_STRING>{s});
+}
+
+
+void DemangleGNU3::ExtendTypeName(DemangledTypeNode& type, const string& extend)
+{
+ if (type.NameStringSize() + extend.size() > MAX_DEMANGLE_LENGTH)
+ throw DemangleException("Detected adversarial mangled string");
+
+ {
+ auto& qn = type.GetMutableTypeName();
+ if (qn.size() > 0)
+ qn.back() += extend;
+ else
+ qn.push_back(extend);
+ }
}
-void DemangleGNU3::PushTemplateType(TypeBuilder type)
+void DemangleGNU3::PushTemplateType(const DemangledTypeNode& type)
{
m_templateSubstitute.push_back(type);
}
-const TypeBuilder& DemangleGNU3::GetTemplateType(size_t ref)
+const DemangledTypeNode& DemangleGNU3::GetTemplateType(size_t ref)
{
if (ref >= m_templateSubstitute.size())
{
@@ -226,13 +386,13 @@ const TypeBuilder& DemangleGNU3::GetTemplateType(size_t ref)
}
-void DemangleGNU3::PushType(TypeBuilder type)
+void DemangleGNU3::PushType(const DemangledTypeNode& type)
{
m_substitute.push_back(type);
}
-const TypeBuilder& DemangleGNU3::GetType(size_t ref)
+const DemangledTypeNode& DemangleGNU3::GetType(size_t ref)
{
if (ref >= m_substitute.size())
{
@@ -287,7 +447,7 @@ string DemangleGNU3::DemangleSourceName()
}
-TypeBuilder DemangleGNU3::DemangleFunction(bool cnst, bool vltl)
+DemangledTypeNode DemangleGNU3::DemangleFunction(bool cnst, bool vltl)
{
indent();
MyLogDebug("%s : %s\n", __FUNCTION__, m_reader.GetRaw().c_str());
@@ -298,26 +458,26 @@ TypeBuilder DemangleGNU3::DemangleFunction(bool cnst, bool vltl)
m_reader.Consume();
}
- TypeBuilder retType = DemangleType();
+ DemangledTypeNode retType = DemangleType();
- vector<FunctionParameter> params;
+ ParamList params;
old_isparam = m_isParameter;
m_isParameter = true;
m_functionSubstitute.push_back({});
int i = 0;
while (m_reader.Peek() != 'E')
{
- TypeBuilder param = DemangleType();
+ DemangledTypeNode param = DemangleType();
if (param.GetClass() == VoidTypeClass)
continue;
MyLogDebug("Var_%d - %s\n", i++, param.GetString().c_str());
m_functionSubstitute.back().push_back(param);
- params.push_back({"", param.Finalize(), true, Variable()});
+ params.push_back({"", std::make_shared<DemangledTypeNode>(std::move(param))});
}
m_reader.Consume();
m_functionSubstitute.pop_back();
m_isParameter = old_isparam;
- TypeBuilder newType = TypeBuilder::FunctionType(retType.Finalize(), nullptr, params);
+ DemangledTypeNode newType = DemangledTypeNode::FunctionType(std::move(retType), nullptr, std::move(params));
PushType(newType);
newType.SetConst(cnst);
@@ -331,7 +491,7 @@ TypeBuilder DemangleGNU3::DemangleFunction(bool cnst, bool vltl)
}
-const TypeBuilder& DemangleGNU3::DemangleTemplateSubstitution()
+const DemangledTypeNode& DemangleGNU3::DemangleTemplateSubstitution()
{
indent();
MyLogDebug("%s : %s\n", __FUNCTION__, m_reader.GetRaw().c_str());
@@ -365,11 +525,11 @@ const TypeBuilder& DemangleGNU3::DemangleTemplateSubstitution()
}
-TypeBuilder DemangleGNU3::DemangleType()
+DemangledTypeNode DemangleGNU3::DemangleType()
{
indent();
MyLogDebug("%s : %s\n", __FUNCTION__, m_reader.GetRaw().c_str());
- TypeBuilder type;
+ DemangledTypeNode type;
bool cnst = false, vltl = false, rstrct = false;
bool substitute = false;
QualifiedName name;
@@ -399,7 +559,7 @@ TypeBuilder DemangleGNU3::DemangleType()
if (m_reader.Peek() == 'I')
{
m_reader.Consume();
- vector<FunctionParameter> args;
+ vector<string> args;
DemangleTemplateArgs(args);
ExtendTypeName(type, GetTemplateString(args));
type.SetHasTemplateArguments(true);
@@ -412,9 +572,9 @@ TypeBuilder DemangleGNU3::DemangleType()
{
m_reader.Consume(1);
type = DemangleUnqualifiedName();
- QualifiedName qn = type.GetTypeName();
+ auto qn = type.GetTypeName();
qn.insert(qn.begin(), "std");
- type.SetTypeName(qn);
+ type.SetTypeName(std::move(qn));
substitute = true;
}
else
@@ -426,7 +586,7 @@ TypeBuilder DemangleGNU3::DemangleType()
m_reader.Consume();
if (substitute)
PushType(type);
- vector<FunctionParameter> args;
+ vector<string> args;
DemangleTemplateArgs(args);
ExtendTypeName(type, GetTemplateString(args));
type.SetHasTemplateArguments(true);
@@ -445,22 +605,19 @@ TypeBuilder DemangleGNU3::DemangleType()
if (m_reader.Peek() == 's')
{
m_reader.Consume();
- type = TypeBuilder::NamedType(NamedTypeReference::GenerateAutoDemangledTypeReference(
- StructNamedTypeClass, {DemangleSourceName()}));
+ type = DemangledTypeNode::NamedType(StructNamedTypeClass, _STD_VECTOR<_STD_STRING>{DemangleSourceName()});
break;
}
else if (m_reader.Peek() == 'u')
{
m_reader.Consume();
- type = TypeBuilder::NamedType(NamedTypeReference::GenerateAutoDemangledTypeReference(
- UnionNamedTypeClass, {DemangleSourceName()}));
+ type = DemangledTypeNode::NamedType(UnionNamedTypeClass, _STD_VECTOR<_STD_STRING>{DemangleSourceName()});
break;
}
else if (m_reader.Peek() == 'e')
{
m_reader.Consume();
- type = TypeBuilder::NamedType(NamedTypeReference::GenerateAutoDemangledTypeReference(
- EnumNamedTypeClass, {DemangleSourceName()}),
+ type = DemangledTypeNode::NamedType(EnumNamedTypeClass, QualifiedName({DemangleSourceName()}),
m_arch->GetDefaultIntegerSize(), m_arch->GetDefaultIntegerSize());
break;
}
@@ -473,7 +630,7 @@ TypeBuilder DemangleGNU3::DemangleType()
m_reader.Consume();
if (substitute)
PushType(type);
- vector<FunctionParameter> args;
+ vector<string> args;
DemangleTemplateArgs(args);
ExtendTypeName(type, GetTemplateString(args));
type.SetHasTemplateArguments(true);
@@ -481,50 +638,59 @@ TypeBuilder DemangleGNU3::DemangleType()
break;
}
case 'P':
- type = TypeBuilder::PointerType(m_arch, DemangleType().Finalize(), cnst, vltl, PointerReferenceType);
+ {
+ DemangledTypeNode child = DemangleType();
+ type = DemangledTypeNode::PointerType(m_arch, std::move(child), cnst, vltl, PointerReferenceType);
substitute = true;
break;
+ }
case 'R':
- type = TypeBuilder::PointerType(m_arch, DemangleType().Finalize(), cnst, vltl, ReferenceReferenceType);
+ {
+ DemangledTypeNode child = DemangleType();
+ type = DemangledTypeNode::PointerType(m_arch, std::move(child), cnst, vltl, ReferenceReferenceType);
substitute = true;
break;
+ }
case 'O':
- type = TypeBuilder::PointerType(m_arch, DemangleType().Finalize(), cnst, vltl, RValueReferenceType);
+ {
+ DemangledTypeNode child = DemangleType();
+ type = DemangledTypeNode::PointerType(m_arch, std::move(child), cnst, vltl, RValueReferenceType);
substitute = true;
break;
+ }
case 'C': //TODO:complex
case 'G': //TODO:imaginary
case 'U': //TODO:vendor extended type
throw DemangleException();
- case 'v': type = TypeBuilder::VoidType(); break;
- case 'w': type = TypeBuilder::IntegerType(4, false, "wchar_t"); break; //TODO: verify
- case 'b': type = TypeBuilder::BoolType(); break;
- case 'c': type = TypeBuilder::IntegerType(1, true); break;
- case 'a': type = TypeBuilder::IntegerType(1, true); break;
- case 'h': type = TypeBuilder::IntegerType(1, false); break;
- case 's': type = TypeBuilder::IntegerType(2, true); break;
- case 't': type = TypeBuilder::IntegerType(2, false); break;
- case 'i': type = TypeBuilder::IntegerType(4, true); break;
- case 'j': type = TypeBuilder::IntegerType(4, false); break;
- case 'l': type = TypeBuilder::IntegerType(m_arch->GetAddressSize(), true); break; //long
- case 'm': type = TypeBuilder::IntegerType(m_arch->GetAddressSize(), false); break; //ulong
- case 'x': type = TypeBuilder::IntegerType(8, true); break;
- case 'y': type = TypeBuilder::IntegerType(8, false); break;
- case 'n': type = TypeBuilder::IntegerType(16, true); break;
- case 'o': type = TypeBuilder::IntegerType(16, false); break;
- case 'f': type = TypeBuilder::FloatType(4); break;
- case 'd': type = TypeBuilder::FloatType(8); break;
- case 'e': type = TypeBuilder::FloatType(10); break;
- case 'g': type = TypeBuilder::FloatType(16); break;
- case 'z': type = TypeBuilder::VarArgsType(); break;
+ case 'v': type = DemangledTypeNode::VoidType(); break;
+ case 'w': type = DemangledTypeNode::IntegerType(4, false, "wchar_t"); break; //TODO: verify
+ case 'b': type = DemangledTypeNode::BoolType(); break;
+ case 'c': type = DemangledTypeNode::IntegerType(1, true); break;
+ case 'a': type = DemangledTypeNode::IntegerType(1, true); break;
+ case 'h': type = DemangledTypeNode::IntegerType(1, false); break;
+ case 's': type = DemangledTypeNode::IntegerType(2, true); break;
+ case 't': type = DemangledTypeNode::IntegerType(2, false); break;
+ case 'i': type = DemangledTypeNode::IntegerType(4, true); break;
+ case 'j': type = DemangledTypeNode::IntegerType(4, false); break;
+ case 'l': type = DemangledTypeNode::IntegerType(m_arch->GetAddressSize(), true); break; //long
+ case 'm': type = DemangledTypeNode::IntegerType(m_arch->GetAddressSize(), false); break; //ulong
+ case 'x': type = DemangledTypeNode::IntegerType(8, true); break;
+ case 'y': type = DemangledTypeNode::IntegerType(8, false); break;
+ case 'n': type = DemangledTypeNode::IntegerType(16, true); break;
+ case 'o': type = DemangledTypeNode::IntegerType(16, false); break;
+ case 'f': type = DemangledTypeNode::FloatType(4); break;
+ case 'd': type = DemangledTypeNode::FloatType(8); break;
+ case 'e': type = DemangledTypeNode::FloatType(10); break;
+ case 'g': type = DemangledTypeNode::FloatType(16); break;
+ case 'z': type = DemangledTypeNode::VarArgsType(); break;
case 'M': // TODO: Make into pointer to function member
{
- TypeBuilder name = DemangleType();
- TypeBuilder member = DemangleType();
- string fullName = member.GetStringBeforeName() + "(" + name.GetString() + "::*)" + member.GetStringAfterName();
+ DemangledTypeNode memberName = DemangleType();
+ DemangledTypeNode member = DemangleType();
+ string fullName = member.GetStringBeforeName() + "(" + memberName.GetString() + "::*)" + member.GetStringAfterName();
//member.SetScope(NonStaticScope);
- //TypeBuilder ptr = TypeBuilder::PointerType(m_arch, member, cnst, vltl);
- //QualifiedName qn({name.GetString(), "*"});
+ //DemangledTypeNode ptr = DemangledTypeNode::PointerType(m_arch, member, cnst, vltl);
+ //QualifiedName qn({memberName.GetString(), "*"});
type = CreateUnknownType(fullName);
break;
}
@@ -532,12 +698,12 @@ TypeBuilder DemangleGNU3::DemangleType()
case 'D':
switch (m_reader.Read())
{
- case 'd': type = TypeBuilder::FloatType(8); break;
- case 'e': type = TypeBuilder::FloatType(16); break;
- case 'f': type = TypeBuilder::FloatType(4); break;
- case 'h': type = TypeBuilder::FloatType(2); break;
- case 'i': type = TypeBuilder::IntegerType(4, true, "char32_t"); break;
- case 's': type = TypeBuilder::IntegerType(2, true, "char16_t"); break;
+ case 'd': type = DemangledTypeNode::FloatType(8); break;
+ case 'e': type = DemangledTypeNode::FloatType(16); break;
+ case 'f': type = DemangledTypeNode::FloatType(4); break;
+ case 'h': type = DemangledTypeNode::FloatType(2); break;
+ case 'i': type = DemangledTypeNode::IntegerType(4, true, "char32_t"); break;
+ case 's': type = DemangledTypeNode::IntegerType(2, true, "char16_t"); break;
case 'a': type = CreateUnknownType("auto"); break; //auto type
case 'c': type = CreateUnknownType("decltype(auto)"); break; //decltype(auto)
case 'n':
@@ -559,7 +725,8 @@ TypeBuilder DemangleGNU3::DemangleType()
uint64_t size = DemangleNumber();
if (m_reader.Read() != '_')
throw DemangleException();
- type = TypeBuilder::ArrayType(DemangleType().Finalize(), size);
+ DemangledTypeNode child = DemangleType();
+ type = DemangledTypeNode::ArrayType(std::move(child), size);
break;
}
default:
@@ -580,7 +747,8 @@ TypeBuilder DemangleGNU3::DemangleType()
uint64_t size = DemangleNumber();
if (m_reader.Read() != '_')
throw DemangleException();
- type = TypeBuilder::ArrayType(DemangleType().Finalize(), size);
+ DemangledTypeNode child = DemangleType();
+ type = DemangledTypeNode::ArrayType(std::move(child), size);
}
else
{
@@ -616,7 +784,7 @@ TypeBuilder DemangleGNU3::DemangleType()
substitute = false;
m_reader.Consume();
PushType(type);
- vector<FunctionParameter> args;
+ vector<string> args;
DemangleTemplateArgs(args);
ExtendTypeName(type, GetTemplateString(args));
type.SetHasTemplateArguments(true);
@@ -633,7 +801,7 @@ TypeBuilder DemangleGNU3::DemangleType()
}
-TypeBuilder DemangleGNU3::DemangleSubstitution()
+DemangledTypeNode DemangleGNU3::DemangleSubstitution()
{
static const QualifiedName stdAllocatorName(vector<string>{"std", "allocator"});
static const QualifiedName stdBasicStringName(vector<string>{"std", "basic_string"});
@@ -694,7 +862,7 @@ TypeBuilder DemangleGNU3::DemangleSubstitution()
string DemangleGNU3::DemangleNumberAsString()
{
bool negativeFactor = false;
- if ( m_reader.Peek() == 'n')
+ if (m_reader.Peek() == 'n')
{
negativeFactor = true;
m_reader.Consume();
@@ -703,15 +871,32 @@ string DemangleGNU3::DemangleNumberAsString()
string number;
while (isdigit(m_reader.Peek()))
{
- number += m_reader.ReadString(1);
+ number += m_reader.Read();
}
- return (negativeFactor?"-":"") + number;
+ if (negativeFactor)
+ return "-" + number;
+ return number;
}
// number ::= [n] <decimal>
int64_t DemangleGNU3::DemangleNumber()
{
- return std::stol(DemangleNumberAsString().c_str());
+ bool negative = false;
+ if (m_reader.Peek() == 'n')
+ {
+ negative = true;
+ m_reader.Consume();
+ }
+
+ if (!isdigit(m_reader.Peek()))
+ throw DemangleException();
+
+ int64_t result = 0;
+ do
+ {
+ result = result * 10 + (m_reader.Read() - '0');
+ } while (isdigit(m_reader.Peek()));
+ return negative ? -result : result;
}
@@ -728,18 +913,6 @@ string DemangleGNU3::DemangleInitializer()
return out;
}
-static int8_t HexToDec(char c)
-{
- if (isdigit(c))
- {
- return c - '0';
- }
- else if(islower(c) && c <= 'f')
- {
- return c - 'a' + 10;
- }
- return -1;
-}
string DemangleGNU3::DemanglePrimaryExpression()
{
@@ -757,7 +930,7 @@ string DemangleGNU3::DemanglePrimaryExpression()
m_reader.Consume(2);
oldTopLevel = m_topLevel;
m_topLevel = false;
- TypeBuilder t = DemangleSymbol(tmpList);
+ DemangledTypeNode t = DemangleSymbol(tmpList);
m_topLevel = oldTopLevel;
out += t.GetStringBeforeName();
out += tmpList.GetString();
@@ -894,149 +1067,13 @@ string DemangleGNU3::DemangleExpressionList()
return expr;
}
-static string GetOperator(char elm1, char elm2)
-{
- switch (hash(elm1, elm2))
- {
- case hash('d','c'): return "dynamic_cast";
- case hash('s','c'): return "static_cast";
- case hash('c','c'): return "const_cast";
- case hash('r','c'): return "reinterpret_cast";
- case hash('t','i'): return "typeid";
- case hash('t','e'): return "typeid";
- case hash('s','t'): return "sizeof";
- case hash('s','z'): return "sizeof";
- case hash('a','t'): return "alignof";
- case hash('a','z'): return "alignof";
- case hash('n','x'): return "noexcept";
- case hash('s','Z'): return "sizeof...";
- case hash('s','P'): return "sizeof...";
- case hash('s','p'): return "";
- case hash('t','w'): return "throw";
- case hash('t','r'): return "throw";
- case hash('l','s'): return "<<"; // <<
- case hash('r','s'): return ">>"; // >>
- case hash('a','S'): return "="; // =
- case hash('n','t'): return "!"; // !
- case hash('e','q'): return "=="; // ==
- case hash('n','e'): return "!="; // !=
- case hash('i','x'): return "[]"; // []
- case hash('d','t'): return "."; // .
- case hash('p','t'): return "->"; // ->
- case hash('m','l'): return "*"; // *
- case hash('p','p'): return "++"; // ++ (postfix in <expression> context)
- case hash('m','m'): return "--"; // -- (postfix in <expression> context)
- case hash('n','g'): return "-"; // - (unary)
- case hash('m','i'): return "-"; // -
- case hash('p','s'): return "+"; // + (unary)
- case hash('p','l'): return "+"; // +
- case hash('a','d'): return "&"; // & (unary)
- case hash('a','n'): return "&"; // &
- case hash('p','m'): return "->*"; // ->*
- case hash('d','v'): return "/"; // /
- case hash('r','m'): return "%"; // %
- case hash('l','t'): return "<"; // <
- case hash('l','e'): return "<="; // <=
- case hash('g','t'): return ">"; // >
- case hash('g','e'): return ">="; // >=
- case hash('c','m'): return ","; // ,
- case hash('c','l'): return "()"; // ()
- case hash('c','o'): return "~"; // ~
- case hash('e','o'): return "^"; // ^
- case hash('o','r'): return "|"; // |
- case hash('a','a'): return "&&"; // &&
- case hash('o','o'): return "||"; // ||
- case hash('d','e'): return "*"; // * (unary)
- case hash('m','L'): return "*="; // *=
- case hash('p','L'): return "+="; // +=
- case hash('m','I'): return "-="; // -=
- case hash('d','V'): return "/="; // /=
- case hash('r','M'): return "%="; // %=
- case hash('r','S'): return ">>="; // >>=
- case hash('l','S'): return "<<="; // <<=
- case hash('a','N'): return "&="; // &=
- case hash('o','R'): return "|="; // |=
- case hash('e','O'): return "^="; // ^=
- case hash('d','l'): return "delete"; // delete
- case hash('d','a'): return "delete[]"; // delete[]
- case hash('n','w'): return "new"; // new
- case hash('n','a'): return "new[]"; // new []
- default: return "";
- }
-}
-static BNNameType GetNameType(char elm1, char elm2)
-{
- switch (hash(elm1, elm2))
- {
- case hash('n','t'): return OperatorNotNameType; // !
- case hash('n','g'): return OperatorMinusNameType; // - (unary)
- case hash('p','s'): return OperatorPlusNameType; // + (unary)
- case hash('a','d'): return OperatorBitAndNameType; // & (unary)
- case hash('d','e'): return OperatorStarNameType; // * (unary)
- case hash('i','x'): return OperatorArrayNameType; // []
- case hash('p','p'): return OperatorIncrementNameType; // ++ (postfix in <expression> context)
- case hash('m','m'): return OperatorDecrementNameType; // -- (postfix in <expression> context)
- case hash('l','s'): return OperatorLeftShiftNameType; // <<
- case hash('r','s'): return OperatorRightShiftNameType; // >>
- case hash('a','S'): return OperatorAssignNameType; // =
- case hash('e','q'): return OperatorEqualNameType; // ==
- case hash('n','e'): return OperatorNotEqualNameType; // !=
- case hash('p','t'): return OperatorArrowNameType; // ->
- case hash('m','l'): return OperatorStarNameType; // *
- case hash('m','i'): return OperatorMinusNameType; // -
- case hash('p','l'): return OperatorPlusNameType; // +
- case hash('a','n'): return OperatorBitAndNameType; // &
- case hash('p','m'): return OperatorArrowStarNameType; // ->*
- case hash('d','v'): return OperatorDivideNameType; // /
- case hash('r','m'): return OperatorModulusNameType; // %
- case hash('l','t'): return OperatorLessThanNameType; // <
- case hash('l','e'): return OperatorLessThanEqualNameType; // <=
- case hash('g','t'): return OperatorGreaterThanNameType; // >
- case hash('g','e'): return OperatorGreaterThanEqualNameType; // >=
- case hash('c','m'): return OperatorCommaNameType; // ,
- case hash('c','l'): return OperatorParenthesesNameType; // ()
- case hash('c','o'): return OperatorTildeNameType; // ~
- case hash('e','o'): return OperatorXorNameType; // ^
- case hash('o','r'): return OperatorBitOrNameType; // |
- case hash('a','a'): return OperatorLogicalAndNameType; // &&
- case hash('o','o'): return OperatorLogicalOrNameType; // ||
- case hash('m','L'): return OperatorStarEqualNameType; // *=
- case hash('p','L'): return OperatorPlusEqualNameType; // +=
- case hash('m','I'): return OperatorMinusEqualNameType; // -=
- case hash('d','V'): return OperatorDivideEqualNameType; // /=
- case hash('r','M'): return OperatorModulusEqualNameType; // %=
- case hash('r','S'): return OperatorRightShiftEqualNameType; // >>=
- case hash('l','S'): return OperatorLeftShiftEqualNameType; // <<=
- case hash('a','N'): return OperatorAndEqualNameType; // &=
- case hash('o','R'): return OperatorOrEqualNameType; // |=
- case hash('e','O'): return OperatorXorEqualNameType; // ^=
- case hash('d','l'): return OperatorDeleteNameType; // delete
- case hash('d','a'): return OperatorDeleteArrayNameType; // delete[]
- case hash('n','w'): return OperatorNewNameType; // new
- case hash('n','a'): return OperatorNewArrayNameType; // new []
- case hash('C','1'): return ConstructorNameType;
- case hash('C','2'): return ConstructorNameType;
- case hash('C','3'): return ConstructorNameType;
- case hash('C','4'): return ConstructorNameType;
- case hash('C','5'): return ConstructorNameType;
- case hash('D','0'): return DestructorNameType;
- case hash('D','1'): return DestructorNameType;
- case hash('D','2'): return DestructorNameType;
- case hash('D','3'): return DestructorNameType;
- case hash('D','4'): return DestructorNameType;
- case hash('D','5'): return DestructorNameType;
- default:
- return NoNameType;
- }
-}
-
-TypeBuilder DemangleGNU3::DemangleUnqualifiedName()
+DemangledTypeNode DemangleGNU3::DemangleUnqualifiedName()
{
indent()
MyLogDebug("%s: '%s'\n", __FUNCTION__, m_reader.GetRaw().c_str());
- TypeBuilder outType;
+ DemangledTypeNode outType;
char elm1 = m_reader.Read();
char elm2 = m_reader.Read();
switch (hash(elm1, elm2))
@@ -1143,13 +1180,13 @@ TypeBuilder DemangleGNU3::DemangleUnqualifiedName()
{
string name;
name = "'lambda";
- vector<TypeBuilder> params;
+ vector<DemangledTypeNode> lambdaParams;
do
{
- TypeBuilder param = DemangleType();
+ DemangledTypeNode param = DemangleType();
if (param.GetClass() == VoidTypeClass)
break;
- params.push_back(std::move(param));
+ lambdaParams.push_back(std::move(param));
}while (m_reader.Peek() != 'E');
m_reader.Consume();
@@ -1161,11 +1198,11 @@ TypeBuilder DemangleGNU3::DemangleUnqualifiedName()
throw DemangleException();
name += "'(";
- for (size_t i = 0; i < params.size(); i++)
+ for (size_t i = 0; i < lambdaParams.size(); i++)
{
if (i != 0)
name += ", ";
- name += params[i].GetString();
+ name += lambdaParams[i].GetString();
}
name += ")";
m_lastName = name;
@@ -1232,7 +1269,7 @@ QualifiedName DemangleGNU3::DemangleBaseUnresolvedName()
if (m_reader.Peek() == 'I')
{
m_reader.Consume();
- vector<FunctionParameter> args;
+ vector<string> args;
DemangleTemplateArgs(args);
out.back() += GetTemplateString(args);
PushType(CreateUnknownType(out));
@@ -1253,7 +1290,7 @@ QualifiedName DemangleGNU3::DemangleBaseUnresolvedName()
if (m_reader.Peek() == 'I')
{
m_reader.Consume();
- vector<FunctionParameter> args;
+ vector<string> args;
DemangleTemplateArgs(args);
out.back() += GetTemplateString(args);
}
@@ -1264,14 +1301,14 @@ QualifiedName DemangleGNU3::DemangleBaseUnresolvedName()
}
-TypeBuilder DemangleGNU3::DemangleUnresolvedType()
+DemangledTypeNode DemangleGNU3::DemangleUnresolvedType()
{
indent();
MyLogDebug("%s: '%s'\n", __FUNCTION__, m_reader.GetRaw().c_str());
//<unresolved-type> ::= <template-param> [ <template-args> ] # T:: or T<X,Y>::
// ::= <decltype> # decltype(p)::
// ::= <substitution>
- TypeBuilder type;
+ DemangledTypeNode type;
if (m_reader.Peek() == 'T')
{
m_reader.Consume();
@@ -1280,7 +1317,7 @@ TypeBuilder DemangleGNU3::DemangleUnresolvedType()
{
PushType(type);
m_reader.Consume();
- vector<FunctionParameter> args;
+ vector<string> args;
DemangleTemplateArgs(args);
ExtendTypeName(type, GetTemplateString(args));
type.SetHasTemplateArguments(true);
@@ -1403,7 +1440,7 @@ string DemangleGNU3::DemangleExpression()
return GetOperator(elm1, elm2) + "(" + DemangleTypeString() + ")";
case hash('s','P'):
{
- vector<FunctionParameter> args;
+ vector<string> args;
DemangleTemplateArgs(args);
return "sizeof...(" + GetTemplateString(args) + ")...";
}
@@ -1471,7 +1508,7 @@ string DemangleGNU3::DemangleExpression()
return "(" + DemangleExpressionList() + ")";
case hash('c','v'): //type (expression)
{
- TypeBuilder type = DemangleType();
+ DemangledTypeNode type = DemangleType();
out = type.GetString();
if (m_reader.Peek() == '_')
out += " (" + DemangleExpressionList() + ")";
@@ -1495,7 +1532,7 @@ string DemangleGNU3::DemangleExpression()
// ::= fL <L-1 num> p <CV> <prm-2 num> _ # L > 0, second and later parameters
bool cnst = false, vltl = false, rstrct = false;
- TypeBuilder type;
+ DemangledTypeNode type;
int64_t listNumber = 0;
int64_t elementNum = 0;
char elm;
@@ -1566,11 +1603,10 @@ string DemangleGNU3::DemangleExpression()
do
{
out += DemangleSourceName();
- PushType(TypeBuilder::NamedType(NamedTypeReference::GenerateAutoDemangledTypeReference(
- UnknownNamedTypeClass, out)));
+ PushType(DemangledTypeNode::NamedType(UnknownNamedTypeClass, _STD_VECTOR<_STD_STRING>{out}));
if (m_reader.Peek() == 'I')
{
- vector<FunctionParameter> args;
+ vector<string> args;
m_reader.Consume();
//<tmplate-args>
DemangleTemplateArgs(args);
@@ -1590,7 +1626,7 @@ string DemangleGNU3::DemangleExpression()
out += DemangleSourceName();
if (m_reader.Peek() == 'I')
{
- vector<FunctionParameter> args;
+ vector<string> args;
m_reader.Consume();
//<tmplate-args>
DemangleTemplateArgs(args);
@@ -1613,7 +1649,7 @@ string DemangleGNU3::DemangleExpression()
out = DemangleSourceName();
if (m_reader.Peek() == 'I')
{
- vector<FunctionParameter> args;
+ vector<string> args;
m_reader.Consume();
//<tmplate-args>
DemangleTemplateArgs(args);
@@ -1625,11 +1661,11 @@ string DemangleGNU3::DemangleExpression()
}
-void DemangleGNU3::DemangleTemplateArgs(vector<FunctionParameter>& args)
+void DemangleGNU3::DemangleTemplateArgs(vector<string>& args)
{
indent();
MyLogDebug("%s:: '%s'\n", __FUNCTION__, m_reader.GetRaw().c_str());
- TypeBuilder tmp;
+ DemangledTypeNode tmp;
bool tmpValid = false;
string expr;
bool topLevel;
@@ -1640,12 +1676,12 @@ void DemangleGNU3::DemangleTemplateArgs(vector<FunctionParameter>& args)
{
case 'L':
expr = DemanglePrimaryExpression();
- args.push_back({expr, nullptr, true, Variable()});
+ args.push_back(expr);
tmp = CreateUnknownType(expr);
tmpValid = true;
break;
case 'X':
- args.push_back({DemangleExpression(), nullptr, true, Variable()});
+ args.push_back(DemangleExpression());
if (m_reader.Read() != 'E')
throw DemangleException();
break;
@@ -1658,7 +1694,7 @@ void DemangleGNU3::DemangleTemplateArgs(vector<FunctionParameter>& args)
m_topLevel = false;
tmp = DemangleType();
m_topLevel = topLevel;
- args.push_back({tmp.GetString(), nullptr, true, Variable()});
+ args.push_back(tmp.GetString());
tmpValid = true;
}
if (m_topLevel && tmpValid)
@@ -1674,7 +1710,7 @@ void DemangleGNU3::DemangleTemplateArgs(vector<FunctionParameter>& args)
}
-TypeBuilder DemangleGNU3::DemangleNestedName()
+DemangledTypeNode DemangleGNU3::DemangleNestedName()
{
/*
This can be either a qualified name like: "foo::bar::bas"
@@ -1708,13 +1744,12 @@ TypeBuilder DemangleGNU3::DemangleNestedName()
indent();
MyLogDebug("%s:: '%s'\n", __FUNCTION__, m_reader.GetRaw().c_str());
- TypeBuilder type = TypeBuilder::NamedType(NamedTypeReference::GenerateAutoDemangledTypeReference(
- UnknownNamedTypeClass, QualifiedName()));
+ DemangledTypeNode type = DemangledTypeNode::NamedType(UnknownNamedTypeClass, QualifiedName());
bool cnst = false, vltl = false, rstrct = false;
bool ref = false;
bool rvalueRef = false;
bool substitute = true;
- TypeBuilder newType;
+ DemangledTypeNode newType;
bool base = false;
bool isTemplate = false;
bool hasB = false;
@@ -1757,7 +1792,7 @@ TypeBuilder DemangleGNU3::DemangleNestedName()
{
if (!base)
throw DemangleException();
- vector<FunctionParameter> args;
+ vector<string> args;
DemangleTemplateArgs(args);
ExtendTypeName(type, GetTemplateString(args));
type.SetHasTemplateArguments(true);
@@ -1774,12 +1809,15 @@ TypeBuilder DemangleGNU3::DemangleNestedName()
if (!isTemplate)
{
type.SetNameType(newType.GetNameType());
- QualifiedName newName = type.GetTypeName() + newType.GetTypeName();
- if (newName.StringSize() > MAX_DEMANGLE_LENGTH)
+ auto aNames = type.GetTypeName();
+ auto bNames = newType.GetTypeName();
+ _STD_VECTOR<_STD_STRING> newName;
+ newName.reserve(aNames.size() + bNames.size());
+ newName.insert(newName.end(), aNames.begin(), aNames.end());
+ newName.insert(newName.end(), bNames.begin(), bNames.end());
+ if (TotalStringSize(newName) > MAX_DEMANGLE_LENGTH)
throw DemangleException("Detected adversarial mangled string");
- type.SetNamedTypeReference(
- NamedTypeReference::GenerateAutoDemangledTypeReference(type.GetNamedTypeReference()->GetTypeReferenceClass(), newName)
- );
+ type.SetNTR(type.GetNTRClass(), newName);
type.SetHasTemplateArguments(false);
}
if (substitute && m_reader.Peek() != 'E')
@@ -1814,11 +1852,11 @@ TypeBuilder DemangleGNU3::DemangleNestedName()
}
-TypeBuilder DemangleGNU3::DemangleLocalName()
+DemangledTypeNode DemangleGNU3::DemangleLocalName()
{
indent();
MyLogDebug("%s '%s'\n", __FUNCTION__, m_reader.GetRaw().c_str());
- TypeBuilder type;
+ DemangledTypeNode type;
QualifiedName varName;
bool oldTopLevel = m_topLevel;
m_topLevel = false;
@@ -1833,12 +1871,17 @@ TypeBuilder DemangleGNU3::DemangleLocalName()
if (m_reader.Peek() != 's')
{
//<entity name>
- TypeBuilder tmpType = DemangleName();
- type = TypeBuilder::NamedType(NamedTypeReference::GenerateAutoDemangledTypeReference(UnknownNamedTypeClass, varName));
- QualifiedName newName = type.GetTypeName() + tmpType.GetTypeName();
- if (newName.StringSize() > MAX_DEMANGLE_LENGTH)
+ DemangledTypeNode tmpType = DemangleName();
+ type = DemangledTypeNode::NamedType(UnknownNamedTypeClass, varName);
+ auto aNames = type.GetTypeName();
+ auto bNames = tmpType.GetTypeName();
+ _STD_VECTOR<_STD_STRING> newName;
+ newName.reserve(aNames.size() + bNames.size());
+ newName.insert(newName.end(), aNames.begin(), aNames.end());
+ newName.insert(newName.end(), bNames.begin(), bNames.end());
+ if (TotalStringSize(newName) > MAX_DEMANGLE_LENGTH)
throw DemangleException("Detected adversarial mangled string");
- type.SetTypeName(newName);
+ type.SetTypeName(std::move(newName));
type.SetConst(tmpType.IsConst());
type.SetVolatile(tmpType.IsVolatile());
type.SetPointerSuffix(tmpType.GetPointerSuffix());
@@ -1846,7 +1889,7 @@ TypeBuilder DemangleGNU3::DemangleLocalName()
else
{
m_reader.Consume();
- type = TypeBuilder::NamedType(NamedTypeReference::GenerateAutoDemangledTypeReference(UnknownNamedTypeClass, varName));
+ type = DemangledTypeNode::NamedType(UnknownNamedTypeClass, varName);
}
// [<discriminator>]
//TODO: What do we do with discriminators?
@@ -1870,7 +1913,7 @@ TypeBuilder DemangleGNU3::DemangleLocalName()
}
-TypeBuilder DemangleGNU3::DemangleName()
+DemangledTypeNode DemangleGNU3::DemangleName()
{
indent();
MyLogDebug("%s '%s'\n", __FUNCTION__, m_reader.GetRaw().c_str());
@@ -1886,7 +1929,7 @@ TypeBuilder DemangleGNU3::DemangleName()
<unscoped-template-name> ::= <unscoped-name>
::= <substitution>
*/
- TypeBuilder type;
+ DemangledTypeNode type;
bool substitute = false;
switch (m_reader.Read())
{
@@ -1895,9 +1938,9 @@ TypeBuilder DemangleGNU3::DemangleName()
{
m_reader.Consume(1);
type = DemangleUnqualifiedName();
- QualifiedName qn = type.GetTypeName();
+ auto qn = type.GetTypeName();
qn.insert(qn.begin(), "std");
- type.SetTypeName(qn);
+ type.SetTypeName(std::move(qn));
substitute = true;
}
else
@@ -1910,7 +1953,7 @@ TypeBuilder DemangleGNU3::DemangleName()
m_reader.Consume();
if (substitute)
PushType(type);
- vector<FunctionParameter> args;
+ vector<string> args;
DemangleTemplateArgs(args);
ExtendTypeName(type, GetTemplateString(args));
type.SetHasTemplateArguments(true);
@@ -1937,7 +1980,7 @@ TypeBuilder DemangleGNU3::DemangleName()
{
PushType(type);
//<unscoped-template-name>
- vector<FunctionParameter> args;
+ vector<string> args;
m_reader.Consume();
//<tmplate-args>
DemangleTemplateArgs(args);
@@ -1952,15 +1995,15 @@ TypeBuilder DemangleGNU3::DemangleName()
}
-TypeBuilder DemangleGNU3::DemangleSymbol(QualifiedName& varName)
+DemangledTypeNode DemangleGNU3::DemangleSymbol(QualifiedName& varName)
{
indent();
MyLogDebug("%s: %s\n", __FUNCTION__, m_reader.GetRaw().c_str());
- TypeBuilder returnType;
+ DemangledTypeNode returnType;
bool isReturnTypeUnknown = false;
- TypeBuilder type;
- vector<FunctionParameter> params;
- Confidence<bool> cnst = false, vltl = false, rstrct = false;
+ DemangledTypeNode type;
+ ParamList params;
+ bool cnst = false, vltl = false, rstrct = false;
bool oldTopLevel;
QualifiedName name;
@@ -1987,9 +2030,9 @@ TypeBuilder DemangleGNU3::DemangleSymbol(QualifiedName& varName)
throw DemangleException();
case 'V':
{
- TypeBuilder t = DemangleSymbol(name);
+ DemangledTypeNode t = DemangleSymbol(name);
varName.push_back("guard_variable_for_" + t.GetTypeAndName(name));
- type = TypeBuilder::IntegerType(1, false);
+ type = DemangledTypeNode::IntegerType(1, false);
if (m_reader.Length() == 0)
return type;
//function parameters
@@ -2037,13 +2080,13 @@ TypeBuilder DemangleGNU3::DemangleSymbol(QualifiedName& varName)
throw DemangleException();
case 'C':
{
- TypeBuilder t = DemangleType();
+ DemangledTypeNode t = DemangleType();
DemangleNumberAsString();
if (m_reader.Read() != '_')
throw DemangleException();
- return TypeBuilder::NamedType(NamedTypeReference::GenerateAutoDemangledTypeReference(UnknownNamedTypeClass,
- {"construction_vtable_for_" + DemangleTypeString() + "-in-" + t.GetString()}));
+ return DemangledTypeNode::NamedType(UnknownNamedTypeClass,
+ _STD_VECTOR<_STD_STRING>{"construction_vtable_for_" + DemangleTypeString() + "-in-" + t.GetString()});
}
case 'D':
LogWarn("Unsupported: 'typeinfo common proxy'\n");
@@ -2058,32 +2101,32 @@ TypeBuilder DemangleGNU3::DemangleSymbol(QualifiedName& varName)
throw DemangleException();
oldTopLevel = m_topLevel;
m_topLevel = false;
- TypeBuilder t = DemangleSymbol(name);
+ DemangledTypeNode t = DemangleSymbol(name);
m_topLevel = oldTopLevel;
- return TypeBuilder::NamedType(
- NamedTypeReference::GenerateAutoDemangledTypeReference(UnknownNamedTypeClass,
- {"non-virtual_thunk_to_" + name.GetString() + t.GetStringAfterName()}));
+ return DemangledTypeNode::NamedType(UnknownNamedTypeClass,
+ _STD_VECTOR<_STD_STRING>{"non-virtual_thunk_to_" + name.GetString() + t.GetStringAfterName()});
}
case 'H':
LogWarn("Unsupported: 'TLS init function'\n");
throw DemangleException();
case 'I':
- return TypeBuilder::NamedType(NamedTypeReference::GenerateAutoDemangledTypeReference(StructNamedTypeClass,
- {"typeinfo_for_" + DemangleTypeString()}));
+ return DemangledTypeNode::NamedType(StructNamedTypeClass,
+ _STD_VECTOR<_STD_STRING>{"typeinfo_for_" + DemangleTypeString()});
case 'J':
LogWarn("Unsupported: 'java class'\n");
throw DemangleException();
case 'S':
{
- TypeBuilder t = DemangleType();
+ DemangledTypeNode t = DemangleType();
varName = vector<string>{"typeinfo_name_for_" + t.GetString()};
- return TypeBuilder::ArrayType(Type::IntegerType(1, true), 0);
+ DemangledTypeNode elemType = DemangledTypeNode::IntegerType(1, true);
+ return DemangledTypeNode::ArrayType(std::move(elemType), 0);
}
case 'T': //VTT
{
- TypeBuilder t = DemangleType();
- return TypeBuilder::NamedType(NamedTypeReference::GenerateAutoDemangledTypeReference(StructNamedTypeClass,
- {"VTT_for_" + t.GetString()}));
+ DemangledTypeNode t = DemangleType();
+ return DemangledTypeNode::NamedType(StructNamedTypeClass,
+ _STD_VECTOR<_STD_STRING>{"VTT_for_" + t.GetString()});
}
case 'v': //TODO: Convert to whatever the actual type is!
{
@@ -2095,16 +2138,14 @@ TypeBuilder DemangleGNU3::DemangleSymbol(QualifiedName& varName)
throw DemangleException();
oldTopLevel = m_topLevel;
m_topLevel = false;
- TypeBuilder t = DemangleSymbol(name);
+ DemangledTypeNode t = DemangleSymbol(name);
m_topLevel = oldTopLevel;
- return TypeBuilder::NamedType(
- NamedTypeReference::GenerateAutoDemangledTypeReference(UnknownNamedTypeClass,
- {"virtual_thunk_to_" + name.GetString() + t.GetStringAfterName()}));
+ return DemangledTypeNode::NamedType(UnknownNamedTypeClass,
+ _STD_VECTOR<_STD_STRING>{"virtual_thunk_to_" + name.GetString() + t.GetStringAfterName()});
}
case 'V': //Vtable
- return TypeBuilder::NamedType(
- NamedTypeReference::GenerateAutoDemangledTypeReference(StructNamedTypeClass,
- {"vtable_for_" + DemangleTypeString()}));
+ return DemangledTypeNode::NamedType(StructNamedTypeClass,
+ _STD_VECTOR<_STD_STRING>{"vtable_for_" + DemangleTypeString()});
case 'W':
MyLogDebug("Unsupported: 'TLS wrapper function'\n");
throw DemangleException();
@@ -2130,7 +2171,7 @@ TypeBuilder DemangleGNU3::DemangleSymbol(QualifiedName& varName)
varName = type.GetTypeName();
cnst = type.IsConst();
vltl = type.IsVolatile();
- set<BNPointerSuffix> suffix = type.GetPointerSuffix();
+ auto suffix = type.GetPointerSuffix();
if (m_reader.Peek() == 'J')
{
m_reader.Consume();
@@ -2139,7 +2180,7 @@ TypeBuilder DemangleGNU3::DemangleSymbol(QualifiedName& varName)
if (m_reader.Peek() == 'B')
{
m_reader.Consume();
- TypeBuilder t = DemangleUnqualifiedName();
+ DemangledTypeNode t = DemangleUnqualifiedName();
if (t.GetString() == "cxx11")
{
@@ -2151,7 +2192,7 @@ TypeBuilder DemangleGNU3::DemangleSymbol(QualifiedName& varName)
type.GetNameType() == ConstructorNameType ||
type.GetNameType() == DestructorNameType)
{
- returnType = TypeBuilder::VoidType();
+ returnType = DemangledTypeNode::VoidType();
}
else if (m_isParameter || type.HasTemplateArguments())
{
@@ -2160,11 +2201,11 @@ TypeBuilder DemangleGNU3::DemangleSymbol(QualifiedName& varName)
else
{
isReturnTypeUnknown = true;
- returnType = TypeBuilder::IntegerType(m_arch->GetAddressSize(), true);
+ returnType = DemangledTypeNode::IntegerType(m_arch->GetAddressSize(), true);
}
m_functionSubstitute.push_back({});
- for (size_t i = 0; m_reader.Length() > 0; i++)
+ while (m_reader.Length() > 0)
{
if (m_reader.Peek() == 'E')
{
@@ -2191,7 +2232,7 @@ TypeBuilder DemangleGNU3::DemangleSymbol(QualifiedName& varName)
MyLogDebug("Var_%d: %s\n", i, m_reader.GetRaw().c_str());
if (m_reader.PeekString(2) == "@@")
break;
- TypeBuilder param = DemangleType();
+ DemangledTypeNode param = DemangleType();
if (param.GetClass() == VoidTypeClass)
{
if (m_reader.Peek() == 'E')
@@ -2202,8 +2243,9 @@ TypeBuilder DemangleGNU3::DemangleSymbol(QualifiedName& varName)
break;
}
m_functionSubstitute.back().push_back(param);
- params.push_back({"", param.Finalize(), true, Variable()});
- if (param.GetClass() == VarArgsTypeClass)
+ bool isVarArgs = param.GetClass() == VarArgsTypeClass;
+ params.push_back({"", std::make_shared<DemangledTypeNode>(std::move(param))});
+ if (isVarArgs)
{
if (m_reader.Peek() == 'E')
{
@@ -2216,13 +2258,14 @@ TypeBuilder DemangleGNU3::DemangleSymbol(QualifiedName& varName)
m_functionSubstitute.pop_back();
m_isParameter = false;
- type = TypeBuilder::FunctionType(returnType.Finalize()->
- WithConfidence(isReturnTypeUnknown ? BN_MINIMUM_CONFIDENCE : BN_DEFAULT_CONFIDENCE), nullptr, params);
+ type = DemangledTypeNode::FunctionType(std::move(returnType), nullptr, std::move(params));
+ if (isReturnTypeUnknown)
+ type.SetReturnTypeConfidence(BN_MINIMUM_CONFIDENCE);
type.SetPointerSuffix(suffix);
type.SetConst(cnst);
type.SetVolatile(vltl);
- if (rstrct.GetValue())
+ if (rstrct)
type.SetPointerSuffix({RestrictSuffix});
// PrintTables();
@@ -2234,7 +2277,9 @@ TypeBuilder DemangleGNU3::DemangleSymbol(QualifiedName& varName)
}
-bool DemangleGNU3::IsGNU3MangledString(const string& name)
+// ===== Non-templated static methods =====
+
+bool DemangleGNU3Static::IsGNU3MangledString(const string& name)
{
string headerless = name;
string header;
@@ -2248,7 +2293,7 @@ bool DemangleGNU3::IsGNU3MangledString(const string& name)
}
-bool DemangleGNU3::DemangleGlobalHeader(string& name, string& header)
+bool DemangleGNU3Static::DemangleGlobalHeader(string& name, string& header)
{
size_t strippedCount = 0;
string encoded = name;
@@ -2281,19 +2326,7 @@ bool DemangleGNU3::DemangleGlobalHeader(string& name, string& header)
}
-bool DemangleGNU3::DemangleStringGNU3(Architecture* arch, const string& name, Ref<Type>& outType, QualifiedName& outVarName, const Ref<BinaryView>& view)
-{
- return DemangleStringGNU3(arch, name, outType, outVarName);
-}
-
-
-bool DemangleGNU3::DemangleStringGNU3(Architecture* arch, const string& name, Ref<Type>& outType, QualifiedName& outVarName, BinaryView* view)
-{
- return DemangleStringGNU3(arch, name, outType, outVarName);
-}
-
-
-bool DemangleGNU3::DemangleStringGNU3(Architecture* arch, const string& name, Ref<Type>& outType, QualifiedName& outVarName)
+bool DemangleGNU3Static::DemangleStringGNU3(Architecture* arch, const string& name, Ref<Type>& outType, QualifiedName& outVarName)
{
string encoding = name;
string header;
@@ -2305,18 +2338,17 @@ bool DemangleGNU3::DemangleStringGNU3(Architecture* arch, const string& name, Re
encoding = encoding.substr(3);
else if (foundHeader && !header.empty())
{
- // Some variable constructors/destructors are __GLOBAL__I_name
- // And there are even __GLOBAL__sub_I_file_name.cpp
outVarName.clear();
outVarName.push_back(header);
outVarName.push_back(encoding);
- outType = CreateUnknownType(outVarName).Finalize();
+ outType = DemangledTypeNode::NamedType(UnknownNamedTypeClass, outVarName).Finalize();
return true;
}
else
return false;
- DemangleGNU3 demangle(arch, encoding);
+ thread_local DemangleGNU3 demangle(arch, encoding);
+ demangle.Reset(arch, encoding);
try
{
outType = demangle.DemangleSymbol(outVarName).Finalize();
@@ -2349,6 +2381,11 @@ bool DemangleGNU3::DemangleStringGNU3(Architecture* arch, const string& name, Re
}
+// ===== Explicit template instantiation =====
+
+
+// ===== Demangler plugin registration =====
+
class GNU3Demangler: public Demangler
{
public:
@@ -2359,7 +2396,7 @@ public:
virtual bool IsMangledString(const string& name) override
{
- return DemangleGNU3::IsGNU3MangledString(name);
+ return DemangleGNU3Static::IsGNU3MangledString(name);
}
#ifdef BINARYNINJACORE_LIBRARY
@@ -2370,9 +2407,7 @@ public:
Ref<BinaryView> view) override
#endif
{
- if (view)
- return DemangleGNU3::DemangleStringGNU3(arch, name, outType, outVarName, view);
- return DemangleGNU3::DemangleStringGNU3(arch, name, outType, outVarName);
+ return DemangleGNU3Static::DemangleStringGNU3(arch, name, outType, outVarName);
}
};
diff --git a/demangler/gnu3/demangle_gnu3.h b/demangler/gnu3/demangle_gnu3.h
index e26f3305..2e46e05d 100644
--- a/demangler/gnu3/demangle_gnu3.h
+++ b/demangler/gnu3/demangle_gnu3.h
@@ -35,6 +35,8 @@
#define _STD_VECTOR std::vector
#endif
+#include "demangled_type_node.h"
+
class DemangleException: public std::exception
{
_STD_STRING m_message;
@@ -43,47 +45,62 @@ public:
virtual const char* what() const noexcept { return m_message.c_str(); }
};
-class DemangleGNU3
+class DemangleGNU3Reader
{
- class Reader
+public:
+ DemangleGNU3Reader(const _STD_STRING& data);
+ void Reset(const _STD_STRING& data);
+ _STD_STRING PeekString(size_t count=1);
+ bool NextIsOneOf(const _STD_STRING& list);
+ _STD_STRING GetRaw();
+ _STD_STRING ReadString(size_t count=1);
+ _STD_STRING ReadUntil(char sentinal);
+
+ size_t Length() const { return m_data.length() - m_offset; }
+
+ char Peek()
+ {
+ if (1 > Length())
+ return '\0';
+ return (char)m_data[m_offset];
+ }
+
+ char Read()
{
- public:
- Reader(const _STD_STRING& data);
- _STD_STRING PeekString(size_t count=1);
- char Peek();
- bool NextIsOneOf(const _STD_STRING& list);
- _STD_STRING GetRaw();
- char Read();
- _STD_STRING ReadString(size_t count=1);
- _STD_STRING ReadUntil(char sentinal);
- void Consume(size_t count=1);
- size_t Length() const;
- void UnRead(size_t count=1);
- private:
- _STD_STRING m_data;
- size_t m_offset;
- };
+ if (1 > Length())
+ throw DemangleException();
+ return m_data[m_offset++];
+ }
- class SubstitutionList
+ void Consume(size_t count=1)
{
- _STD_VECTOR<BN::TypeBuilder> m_typeList;
- public:
- SubstitutionList();
- ~SubstitutionList();
- void PushType(BN::TypeBuilder t);
- void PopType();
- const BN::TypeBuilder& GetType(size_t reference) const;
- void PrintSubstitutionTable() const;
- size_t Size() const { return m_typeList.size(); }
- void Clear() { m_typeList.clear(); }
- };
+ if (count > Length())
+ throw DemangleException();
+ m_offset += count;
+ }
+
+ void UnRead(size_t count=1)
+ {
+ if (count <= m_offset)
+ m_offset -= count;
+ }
+
+private:
+ _STD_STRING m_data;
+ size_t m_offset;
+};
+
+
+class DemangleGNU3
+{
+ using ParamList = _STD_VECTOR<DemangledTypeNode::Param>;
BN::QualifiedName m_varName;
- Reader m_reader;
+ DemangleGNU3Reader m_reader;
BN::Architecture* m_arch;
- _STD_VECTOR<BN::TypeBuilder> m_substitute;
- _STD_VECTOR<BN::TypeBuilder> m_templateSubstitute;
- _STD_VECTOR<_STD_VECTOR<BN::TypeBuilder>> m_functionSubstitute;
+ _STD_VECTOR<DemangledTypeNode> m_substitute;
+ _STD_VECTOR<DemangledTypeNode> m_templateSubstitute;
+ _STD_VECTOR<_STD_VECTOR<DemangledTypeNode>> m_functionSubstitute;
_STD_STRING m_lastName;
BNNameType m_nameType;
bool m_localType;
@@ -94,46 +111,53 @@ class DemangleGNU3
bool m_isOperatorOverload;
enum SymbolType { Function, FunctionWithReturn, Data, VTable, Rtti, Name};
BN::QualifiedName DemangleBaseUnresolvedName();
- BN::TypeBuilder DemangleUnresolvedType();
+ DemangledTypeNode DemangleUnresolvedType();
_STD_STRING DemangleUnarySuffixExpression(const _STD_STRING& op);
_STD_STRING DemangleUnaryPrefixExpression(const _STD_STRING& op);
_STD_STRING DemangleBinaryExpression(const _STD_STRING& op);
_STD_STRING DemangleUnaryPrefixType(const _STD_STRING& op);
_STD_STRING DemangleTypeString();
_STD_STRING DemangleExpressionList();
- BN::TypeBuilder DemangleUnqualifiedName();
+ DemangledTypeNode DemangleUnqualifiedName();
_STD_STRING DemangleSourceName();
_STD_STRING DemangleNumberAsString();
_STD_STRING DemangleInitializer();
_STD_STRING DemangleExpression();
_STD_STRING DemanglePrimaryExpression();
- BN::TypeBuilder DemangleName();
- BN::TypeBuilder DemangleLocalName();
+ DemangledTypeNode DemangleName();
+ DemangledTypeNode DemangleLocalName();
void DemangleCVQualifiers(bool& cnst, bool& vltl, bool& rstrct);
- BN::TypeBuilder DemangleSubstitution();
- const BN::TypeBuilder& DemangleTemplateSubstitution();
- void DemangleTemplateArgs(_STD_VECTOR<BN::FunctionParameter>& args);
- bool DemangleEncoding(BN::Type** type, BN::QualifiedName& outName);
- BN::TypeBuilder DemangleFunction(bool cnst, bool vltl);
- BN::TypeBuilder DemangleType();
+ DemangledTypeNode DemangleSubstitution();
+ const DemangledTypeNode& DemangleTemplateSubstitution();
+ void DemangleTemplateArgs(_STD_VECTOR<_STD_STRING>& args);
+ DemangledTypeNode DemangleFunction(bool cnst, bool vltl);
+ DemangledTypeNode DemangleType();
int64_t DemangleNumber();
- BN::TypeBuilder DemangleNestedName();
- void PushTemplateType(BN::TypeBuilder type);
- const BN::TypeBuilder& GetTemplateType(size_t ref);
- void PushType(BN::TypeBuilder type);
- const BN::TypeBuilder& GetType(size_t ref);
- static bool DemangleGlobalHeader(_STD_STRING& name, _STD_STRING& header);
+ DemangledTypeNode DemangleNestedName();
+ void PushTemplateType(const DemangledTypeNode& type);
+ const DemangledTypeNode& GetTemplateType(size_t ref);
+ void PushType(const DemangledTypeNode& type);
+ const DemangledTypeNode& GetType(size_t ref);
+
+ DemangledTypeNode CreateUnknownType(const BN::QualifiedName& s);
+ DemangledTypeNode CreateUnknownType(const _STD_STRING& s);
+ static void ExtendTypeName(DemangledTypeNode& type, const _STD_STRING& extend);
public:
DemangleGNU3(BN::Architecture* arch, const _STD_STRING& mangledName);
- BN::TypeBuilder DemangleSymbol(BN::QualifiedName& varName);
+ void Reset(BN::Architecture* arch, const _STD_STRING& mangledName);
+ DemangledTypeNode DemangleSymbol(BN::QualifiedName& varName);
BN::QualifiedName GetVarName() const { return m_varName; }
+ void PrintTables();
+};
+
+
+class DemangleGNU3Static
+{
+public:
static bool IsGNU3MangledString(const _STD_STRING& name);
+ static bool DemangleGlobalHeader(_STD_STRING& name, _STD_STRING& header);
- // Tread lightly on this landmine; a BinaryView* will be converted to a bool; use an explicit (BN::Ref<BN::BinaryView>)view cast
- static bool DemangleStringGNU3(BN::Architecture* arch, const _STD_STRING& name, BN::Ref<BN::Type>& outType, BN::QualifiedName& outVarName, const BN::Ref<BN::BinaryView>& view);
- static bool DemangleStringGNU3(BN::Architecture* arch, const _STD_STRING& name, BN::Ref<BN::Type>& outType, BN::QualifiedName& outVarName, BN::BinaryView* view);
static bool DemangleStringGNU3(BN::Architecture* arch, const _STD_STRING& name, BN::Ref<BN::Type>& outType, BN::QualifiedName& outVarName);
- void PrintTables();
};
diff --git a/demangler/gnu3/demangled_type_node.cpp b/demangler/gnu3/demangled_type_node.cpp
new file mode 100644
index 00000000..d8a98e16
--- /dev/null
+++ b/demangler/gnu3/demangled_type_node.cpp
@@ -0,0 +1,531 @@
+// Copyright 2016-2026 Vector 35 Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "demangled_type_node.h"
+#include <cinttypes>
+
+#ifdef BINARYNINJACORE_LIBRARY
+using namespace BinaryNinjaCore;
+#define GetClass GetTypeClass
+#else
+using namespace BinaryNinja;
+using namespace std;
+#endif
+
+
+DemangledTypeNode::DemangledTypeNode()
+ : m_typeClass(VoidTypeClass), m_width(0), m_alignment(0),
+ m_const(false), m_volatile(false), m_signed(false),
+ m_hasTemplateArgs(false), m_nameType(NoNameType),
+ m_ntrClass(UnknownNamedTypeClass),
+ m_pointerReference(PointerReferenceType), m_elements(0),
+ m_returnTypeConfidence(BN_DEFAULT_CONFIDENCE)
+{
+}
+
+
+DemangledTypeNode DemangledTypeNode::VoidType()
+{
+ DemangledTypeNode n;
+ n.m_typeClass = VoidTypeClass;
+ return n;
+}
+
+
+DemangledTypeNode DemangledTypeNode::BoolType()
+{
+ DemangledTypeNode n;
+ n.m_typeClass = BoolTypeClass;
+ n.m_width = 1;
+ return n;
+}
+
+
+DemangledTypeNode DemangledTypeNode::IntegerType(size_t width, bool isSigned, const string& altName)
+{
+ DemangledTypeNode n;
+ n.m_typeClass = IntegerTypeClass;
+ n.m_width = width;
+ n.m_signed = isSigned;
+ n.m_altName = altName;
+ return n;
+}
+
+
+DemangledTypeNode DemangledTypeNode::FloatType(size_t width)
+{
+ DemangledTypeNode n;
+ n.m_typeClass = FloatTypeClass;
+ n.m_width = width;
+ return n;
+}
+
+
+DemangledTypeNode DemangledTypeNode::VarArgsType()
+{
+ DemangledTypeNode n;
+ n.m_typeClass = VarArgsTypeClass;
+ return n;
+}
+
+
+DemangledTypeNode DemangledTypeNode::PointerType(Architecture* arch, DemangledTypeNode child,
+ bool cnst, bool vltl, BNReferenceType refType)
+{
+ DemangledTypeNode n;
+ n.m_typeClass = PointerTypeClass;
+ n.m_width = arch->GetAddressSize();
+ n.m_childType = std::make_shared<DemangledTypeNode>(std::move(child));
+ n.m_const = cnst;
+ n.m_volatile = vltl;
+ n.m_pointerReference = refType;
+ return n;
+}
+
+
+DemangledTypeNode DemangledTypeNode::ArrayType(DemangledTypeNode child, uint64_t count)
+{
+ DemangledTypeNode n;
+ n.m_typeClass = ArrayTypeClass;
+ n.m_childType = std::make_shared<DemangledTypeNode>(std::move(child));
+ n.m_elements = count;
+ return n;
+}
+
+
+DemangledTypeNode DemangledTypeNode::FunctionType(DemangledTypeNode retType,
+ std::nullptr_t, vector<Param> params)
+{
+ DemangledTypeNode n;
+ n.m_typeClass = FunctionTypeClass;
+ n.m_childType = std::make_shared<DemangledTypeNode>(std::move(retType));
+ n.m_params = std::move(params);
+ return n;
+}
+
+
+DemangledTypeNode DemangledTypeNode::NamedType(BNNamedTypeReferenceClass cls,
+ vector<string> nameSegments, size_t width, size_t align)
+{
+ DemangledTypeNode n;
+ n.m_typeClass = NamedTypeReferenceClass;
+ n.m_ntrClass = cls;
+ n.m_nameSegments = std::make_shared<vector<string>>(std::move(nameSegments));
+ n.m_width = width;
+ n.m_alignment = align;
+ return n;
+}
+
+
+DemangledTypeNode DemangledTypeNode::NamedType(BNNamedTypeReferenceClass cls,
+ const QualifiedName& name, size_t width, size_t align)
+{
+ return NamedType(cls, vector<string>(name.begin(), name.end()), width, align);
+}
+
+
+void DemangledTypeNode::SetNTR(BNNamedTypeReferenceClass cls, vector<string> nameSegments)
+{
+ m_ntrClass = cls;
+ m_nameSegments = std::make_shared<vector<string>>(std::move(nameSegments));
+}
+
+
+void DemangledTypeNode::SetNTR(BNNamedTypeReferenceClass cls, const QualifiedName& name)
+{
+ SetNTR(cls, vector<string>(name.begin(), name.end()));
+}
+
+
+string DemangledTypeNode::GetTypeNameString() const
+{
+ if (!m_nameSegments)
+ return {};
+ const auto& segs = *m_nameSegments;
+ size_t n = segs.size();
+ if (n == 0)
+ return {};
+ if (n == 1)
+ return segs[0];
+
+ // Pre-reserve: sum of segments + (n-1) * 2 for "::" separators
+ size_t total = (n - 1) * 2;
+ for (const auto& s : segs)
+ total += s.size();
+
+ string result;
+ result.reserve(total);
+ result += segs[0];
+ for (size_t i = 1; i < n; i++)
+ {
+ result += "::";
+ result += segs[i];
+ }
+ return result;
+}
+
+
+size_t DemangledTypeNode::NameStringSize() const
+{
+ if (!m_nameSegments)
+ return 0;
+ size_t total = 0;
+ for (const auto& s : *m_nameSegments)
+ total += s.size();
+ return total;
+}
+
+
+string DemangledTypeNode::GetModifierString() const
+{
+ if (m_const && m_volatile)
+ return "const volatile";
+ if (m_const)
+ return "const";
+ if (m_volatile)
+ return "volatile";
+ return "";
+}
+
+
+string DemangledTypeNode::GetPointerSuffixString() const
+{
+ static const char* suffixStrings[] = {
+ "__ptr64",
+ "__unaligned",
+ "__restrict",
+ "&",
+ "&&"
+ };
+
+ string out;
+ for (auto& s : m_pointerSuffix)
+ {
+ if (!out.empty() && out.back() != ' ')
+ out += ' ';
+ out += suffixStrings[s];
+ }
+ return out;
+}
+
+
+string DemangledTypeNode::GetStringBeforeName() const
+{
+ string out;
+ AppendBeforeName(out);
+ return out;
+}
+
+
+string DemangledTypeNode::GetStringAfterName() const
+{
+ string out;
+ AppendAfterName(out);
+ return out;
+}
+
+
+void DemangledTypeNode::AppendBeforeName(string& out, const DemangledTypeNode* parentType) const
+{
+ string modifiers = GetModifierString();
+ string ptrSuffix = GetPointerSuffixString();
+
+ switch (m_typeClass)
+ {
+ case FunctionTypeClass:
+ // Return type before name
+ if (m_childType)
+ {
+ if (!out.empty() && out.back() != ' ')
+ out += " ";
+ m_childType->AppendBeforeName(out, this);
+ }
+ // If parent is a pointer, add "(" for function pointer syntax
+ if (parentType && parentType->m_typeClass == PointerTypeClass)
+ {
+ if (!out.empty() && out.back() != ' ')
+ out += " ";
+ out += "(";
+ }
+ break;
+
+ case IntegerTypeClass:
+ if (!m_altName.empty())
+ out += m_altName;
+ else if (m_signed && m_width == 1)
+ out += "char";
+ else if (m_signed)
+ out += "int" + to_string(m_width * 8) + "_t";
+ else
+ out += "uint" + to_string(m_width * 8) + "_t";
+ if (!modifiers.empty())
+ out += " " + modifiers;
+ break;
+
+ case FloatTypeClass:
+ switch (m_width)
+ {
+ case 2: out += "float16"; break;
+ case 4: out += "float"; break;
+ case 8: out += "double"; break;
+ case 10: out += "long double"; break;
+ default: out += "float" + to_string(m_width * 8); break;
+ }
+ if (!modifiers.empty())
+ out += " " + modifiers;
+ break;
+
+ case BoolTypeClass:
+ out += "bool";
+ if (!modifiers.empty())
+ out += " " + modifiers;
+ break;
+
+ case VoidTypeClass:
+ out += "void";
+ if (!modifiers.empty())
+ out += " " + modifiers;
+ break;
+
+ case VarArgsTypeClass:
+ out += "...";
+ break;
+
+ case PointerTypeClass:
+ if (m_childType)
+ m_childType->AppendBeforeName(out, this);
+ switch (m_pointerReference)
+ {
+ case ReferenceReferenceType: out += "&"; break;
+ case PointerReferenceType: out += "*"; break;
+ case RValueReferenceType: out += "&&"; break;
+ default: break;
+ }
+ if (!ptrSuffix.empty())
+ out += " " + ptrSuffix;
+ if (!modifiers.empty())
+ out += " " + modifiers;
+ break;
+
+ case ArrayTypeClass:
+ if (m_childType)
+ m_childType->AppendBeforeName(out, this);
+ if (parentType && parentType->m_typeClass == PointerTypeClass)
+ {
+ out += " (";
+ }
+ break;
+
+ case NamedTypeReferenceClass:
+ switch (m_ntrClass)
+ {
+ case ClassNamedTypeClass: out += "class "; break;
+ case StructNamedTypeClass: out += "struct "; break;
+ case UnionNamedTypeClass: out += "union "; break;
+ case EnumNamedTypeClass: out += "enum "; break;
+ default: break;
+ }
+ out += GetTypeNameString();
+ if (!modifiers.empty())
+ out += " " + modifiers;
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+static string FormatArrayCount(uint64_t elements)
+{
+ return string(fmt::format("{:#x}", elements));
+}
+
+
+void DemangledTypeNode::AppendAfterName(string& out, const DemangledTypeNode* parentType) const
+{
+ string modifiers = GetModifierString();
+ string ptrSuffix = GetPointerSuffixString();
+
+ switch (m_typeClass)
+ {
+ case FunctionTypeClass:
+ {
+ // Close the "(" from before-name if parent is pointer
+ if (parentType && parentType->m_typeClass == PointerTypeClass)
+ out += ")";
+
+ out += "(";
+ for (size_t i = 0; i < m_params.size(); i++)
+ {
+ if (i != 0)
+ out += ", ";
+ if (m_params[i].type)
+ out += m_params[i].type->GetString();
+ }
+ out += ")";
+ if (!modifiers.empty())
+ out += " " + modifiers;
+ if (!ptrSuffix.empty())
+ out += ptrSuffix;
+ // Return type's after-name tokens
+ if (m_childType)
+ m_childType->AppendAfterName(out, this);
+ break;
+ }
+ case PointerTypeClass:
+ if (m_childType)
+ m_childType->AppendAfterName(out, this);
+ break;
+ case ArrayTypeClass:
+ if (parentType && parentType->m_typeClass == PointerTypeClass)
+ out += ")";
+ out += "[" + FormatArrayCount(m_elements) + "]";
+ if (m_childType)
+ m_childType->AppendAfterName(out, this);
+ break;
+ default:
+ break;
+ }
+}
+
+
+string DemangledTypeNode::GetString() const
+{
+ const string before = GetStringBeforeName();
+ const string after = GetStringAfterName();
+ if (!before.empty() && !after.empty() && before.back() != ' ' && before.back() != '*'
+ && before.back() != '&' && after.front() != ' ' && after.front() != '['
+ && m_childType && m_childType->m_typeClass != FunctionTypeClass)
+ {
+ return before + " " + after;
+ }
+ return before + after;
+}
+
+
+string DemangledTypeNode::GetTypeAndName(const QualifiedName& name) const
+{
+ const string before = GetStringBeforeName();
+ const string qName = name.GetString();
+ const string after = GetStringAfterName();
+ if ((!before.empty() && !qName.empty() && before.back() != ' ' && qName.front() != ' ')
+ || (!before.empty() && !after.empty() && before.back() != ' ' && after.front() != ' '))
+ return before + " " + qName + after;
+ return before + qName + after;
+}
+
+
+Ref<Type> DemangledTypeNode::Finalize() const
+{
+ switch (m_typeClass)
+ {
+ case VoidTypeClass:
+ {
+ if (!m_const && !m_volatile)
+ return Type::VoidType();
+ TypeBuilder tb = TypeBuilder::VoidType();
+ tb.SetConst(m_const);
+ tb.SetVolatile(m_volatile);
+ return tb.Finalize();
+ }
+
+ case BoolTypeClass:
+ {
+ if (!m_const && !m_volatile)
+ return Type::BoolType();
+ TypeBuilder tb = TypeBuilder::BoolType();
+ tb.SetConst(m_const);
+ tb.SetVolatile(m_volatile);
+ return tb.Finalize();
+ }
+
+ case IntegerTypeClass:
+ {
+ if (!m_const && !m_volatile)
+ return Type::IntegerType(m_width, m_signed, m_altName);
+ TypeBuilder tb = TypeBuilder::IntegerType(m_width, m_signed, m_altName);
+ tb.SetConst(m_const);
+ tb.SetVolatile(m_volatile);
+ return tb.Finalize();
+ }
+
+ case FloatTypeClass:
+ {
+ if (!m_const && !m_volatile)
+ return Type::FloatType(m_width);
+ TypeBuilder tb = TypeBuilder::FloatType(m_width);
+ tb.SetConst(m_const);
+ tb.SetVolatile(m_volatile);
+ return tb.Finalize();
+ }
+
+ case VarArgsTypeClass:
+ return TypeBuilder::VarArgsType().Finalize();
+
+ case PointerTypeClass:
+ {
+ Ref<Type> child = m_childType ? m_childType->Finalize() : Ref<Type>(Type::VoidType());
+ return TypeBuilder::PointerType(m_width, child, m_const, m_volatile, m_pointerReference).Finalize();
+ }
+
+ case ArrayTypeClass:
+ {
+ Ref<Type> child = m_childType ? m_childType->Finalize() : Ref<Type>(Type::VoidType());
+ TypeBuilder tb = TypeBuilder::ArrayType(child, m_elements);
+ if (m_const)
+ tb.SetConst(m_const);
+ if (m_volatile)
+ tb.SetVolatile(m_volatile);
+ return tb.Finalize();
+ }
+
+ case FunctionTypeClass:
+ {
+ Ref<Type> retType = m_childType ? m_childType->Finalize() : Ref<Type>(Type::VoidType());
+ vector<FunctionParameter> finalParams;
+ finalParams.reserve(m_params.size());
+ for (auto& p : m_params)
+ {
+ Ref<Type> pType = p.type ? p.type->Finalize() : Ref<Type>(Type::VoidType());
+ finalParams.push_back({p.name, pType, true, Variable()});
+ }
+ TypeBuilder tb = TypeBuilder::FunctionType(retType->WithConfidence(m_returnTypeConfidence), nullptr, finalParams);
+ tb.SetConst(m_const);
+ tb.SetVolatile(m_volatile);
+ for (auto ps : m_pointerSuffix)
+ tb.AddPointerSuffix(ps);
+ tb.SetNameType(m_nameType);
+ return tb.Finalize();
+ }
+
+ case NamedTypeReferenceClass:
+ {
+ TypeBuilder tb = TypeBuilder::NamedType(
+ NamedTypeReference::GenerateAutoDemangledTypeReference(
+ m_ntrClass, QualifiedName(m_nameSegments ? *m_nameSegments : vector<string>{})),
+ m_width, m_alignment > 0 ? m_alignment : 1);
+ tb.SetConst(m_const);
+ tb.SetVolatile(m_volatile);
+ for (auto ps : m_pointerSuffix)
+ tb.AddPointerSuffix(ps);
+ tb.SetNameType(m_nameType);
+ tb.SetHasTemplateArguments(m_hasTemplateArgs);
+ return tb.Finalize();
+ }
+
+ default:
+ return Type::VoidType();
+ }
+}
diff --git a/demangler/gnu3/demangled_type_node.h b/demangler/gnu3/demangled_type_node.h
new file mode 100644
index 00000000..f272166c
--- /dev/null
+++ b/demangler/gnu3/demangled_type_node.h
@@ -0,0 +1,171 @@
+// Copyright 2016-2026 Vector 35 Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#ifdef BINARYNINJACORE_LIBRARY
+#include "qualifiedname.h"
+#include "type.h"
+#include "architecture.h"
+#ifndef BN
+#define BN BinaryNinjaCore
+#endif
+#ifndef _STD_STRING
+#define _STD_STRING BinaryNinjaCore::string
+#endif
+#ifndef _STD_VECTOR
+#define _STD_VECTOR BinaryNinjaCore::vector
+#endif
+#else
+#include "binaryninjaapi.h"
+#ifndef BN
+#define BN BinaryNinja
+#endif
+#ifndef _STD_STRING
+#define _STD_STRING std::string
+#endif
+#ifndef _STD_VECTOR
+#define _STD_VECTOR std::vector
+#endif
+#endif
+
+#include <memory>
+#ifdef BINARYNINJACORE_LIBRARY
+#include "binaryninjacore_global.h"
+#define _STD_SET BinaryNinjaCore::set
+#else
+#include <set>
+#define _STD_SET std::set
+#endif
+
+// Lightweight type representation for the GNU3 demangler.
+// This object serves as an abstraction layer between C++'s type system and our own.
+// It also removes a source of a lot of reallocation of NamedTypeReference BinaryNinja::Type objects
+// and only creates real Type objects when Finalize() is called.
+class DemangledTypeNode
+{
+public:
+ struct Param
+ {
+ _STD_STRING name;
+ std::shared_ptr<DemangledTypeNode> type;
+ };
+
+ DemangledTypeNode();
+ DemangledTypeNode(const DemangledTypeNode&) = default;
+ DemangledTypeNode(DemangledTypeNode&&) = default;
+ DemangledTypeNode& operator=(const DemangledTypeNode&) = default;
+ DemangledTypeNode& operator=(DemangledTypeNode&&) = default;
+
+ // Static factory methods matching TypeBuilder's interface
+ static DemangledTypeNode VoidType();
+ static DemangledTypeNode BoolType();
+ static DemangledTypeNode IntegerType(size_t width, bool isSigned, const _STD_STRING& altName = "");
+ static DemangledTypeNode FloatType(size_t width);
+ static DemangledTypeNode VarArgsType();
+ static DemangledTypeNode PointerType(BN::Architecture* arch, DemangledTypeNode child,
+ bool cnst, bool vltl, BNReferenceType refType);
+ static DemangledTypeNode ArrayType(DemangledTypeNode child, uint64_t count);
+ static DemangledTypeNode FunctionType(DemangledTypeNode retType,
+ std::nullptr_t, _STD_VECTOR<Param> params);
+ static DemangledTypeNode NamedType(BNNamedTypeReferenceClass cls,
+ _STD_VECTOR<_STD_STRING> nameSegments, size_t width = 0, size_t align = 0);
+ static DemangledTypeNode NamedType(BNNamedTypeReferenceClass cls,
+ const BN::QualifiedName& name, size_t width = 0, size_t align = 0);
+
+ // Getters
+ BNTypeClass GetClass() const { return m_typeClass; }
+#ifdef BINARYNINJACORE_LIBRARY
+ BNTypeClass GetTypeClass() const { return m_typeClass; }
+#endif
+ const _STD_VECTOR<_STD_STRING>& GetTypeName() const
+ {
+ if (!m_nameSegments)
+ {
+ static const _STD_VECTOR<_STD_STRING> empty;
+ return empty;
+ }
+ return *m_nameSegments;
+ }
+ _STD_VECTOR<_STD_STRING>& GetMutableTypeName()
+ {
+ if (!m_nameSegments)
+ m_nameSegments = std::make_shared<_STD_VECTOR<_STD_STRING>>();
+ else if (m_nameSegments.use_count() > 1)
+ m_nameSegments = std::make_shared<_STD_VECTOR<_STD_STRING>>(*m_nameSegments);
+ return *m_nameSegments;
+ }
+ _STD_STRING GetTypeNameString() const;
+ size_t NameStringSize() const;
+ bool IsConst() const { return m_const; }
+ bool IsVolatile() const { return m_volatile; }
+ BNNameType GetNameType() const { return m_nameType; }
+ bool HasTemplateArguments() const { return m_hasTemplateArgs; }
+ const _STD_SET<BNPointerSuffix>& GetPointerSuffix() const { return m_pointerSuffix; }
+ BNNamedTypeReferenceClass GetNTRClass() const { return m_ntrClass; }
+
+ // Setters
+ void SetTypeName(_STD_VECTOR<_STD_STRING> name) { m_nameSegments = std::make_shared<_STD_VECTOR<_STD_STRING>>(std::move(name)); }
+ void SetConst(bool c) { m_const = c; }
+ void SetVolatile(bool v) { m_volatile = v; }
+ void SetNameType(BNNameType nt) { m_nameType = nt; }
+ void SetHasTemplateArguments(bool t) { m_hasTemplateArgs = t; }
+ void SetPointerSuffix(const _STD_SET<BNPointerSuffix>& s) { m_pointerSuffix = s; }
+ void AddPointerSuffix(BNPointerSuffix ps) { m_pointerSuffix.insert(ps); }
+ void SetReturnTypeConfidence(uint8_t c) { m_returnTypeConfidence = c; }
+
+ // Named type reference operations
+ void SetNTR(BNNamedTypeReferenceClass cls, _STD_VECTOR<_STD_STRING> nameSegments);
+ void SetNTR(BNNamedTypeReferenceClass cls, const BN::QualifiedName& name);
+
+ // String formatting
+ _STD_STRING GetString() const;
+ _STD_STRING GetStringBeforeName() const;
+ _STD_STRING GetStringAfterName() const;
+ _STD_STRING GetTypeAndName(const BN::QualifiedName& name) const;
+
+ // Conversion to real Type
+ BN::Ref<BN::Type> Finalize() const;
+
+private:
+ BNTypeClass m_typeClass;
+ size_t m_width;
+ size_t m_alignment;
+ bool m_const;
+ bool m_volatile;
+ bool m_signed;
+ bool m_hasTemplateArgs;
+ BNNameType m_nameType;
+ _STD_SET<BNPointerSuffix> m_pointerSuffix;
+ _STD_STRING m_altName;
+
+ // Named type ref data
+ BNNamedTypeReferenceClass m_ntrClass;
+ std::shared_ptr<_STD_VECTOR<_STD_STRING>> m_nameSegments;
+
+ // Child type (for pointer/array/function return)
+ std::shared_ptr<DemangledTypeNode> m_childType;
+ BNReferenceType m_pointerReference;
+ uint64_t m_elements;
+
+ // Function params
+ _STD_VECTOR<Param> m_params;
+ uint8_t m_returnTypeConfidence;
+
+ // Helpers for string formatting
+ _STD_STRING GetModifierString() const;
+ _STD_STRING GetPointerSuffixString() const;
+ void AppendBeforeName(_STD_STRING& out, const DemangledTypeNode* parentType = nullptr) const;
+ void AppendAfterName(_STD_STRING& out, const DemangledTypeNode* parentType = nullptr) const;
+};