diff options
| author | Peter LaFosse <peter@vector35.com> | 2026-03-10 12:27:34 -0400 |
|---|---|---|
| committer | Peter LaFosse <peter@vector35.com> | 2026-03-26 17:56:23 -0400 |
| commit | 260ca61d94134b6743807e29f64b5ce4f6918d73 (patch) | |
| tree | 9b77dc9990873549f096c5eae00a2b924215946b /demangler/gnu3 | |
| parent | 0789f70c4a7496cf23672011cdb5bf5b8a5738c6 (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.cpp | 821 | ||||
| -rw-r--r-- | demangler/gnu3/demangle_gnu3.h | 134 | ||||
| -rw-r--r-- | demangler/gnu3/demangled_type_node.cpp | 531 | ||||
| -rw-r--r-- | demangler/gnu3/demangled_type_node.h | 171 |
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; +}; |
