// 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 #include #include // XXX: Compiled directly into the core for performance reasons // Will still work fine compiled independently, just at about a // 50-100% performance penalty due to FFI overhead #ifdef BINARYNINJACORE_LIBRARY #include "qualifiedname.h" #include "type.h" #include "architecture.h" #include "binaryview.h" #include "demangle.h" #define BN BinaryNinjaCore #define _STD_STRING BinaryNinjaCore::string #define _STD_VECTOR BinaryNinjaCore::vector #else #include "binaryninjaapi.h" #define BN BinaryNinja #define _STD_STRING std::string #define _STD_VECTOR std::vector #endif #include "demangled_type_node.h" class DemangleException: public std::exception { _STD_STRING m_message; public: DemangleException(_STD_STRING msg="Attempt to read beyond bounds or missing expected character"): m_message(msg){} virtual const char* what() const noexcept { return m_message.c_str(); } }; class DemangleGNU3Reader { public: DemangleGNU3Reader(const _STD_STRING& data); void Reset(const _STD_STRING& data); _STD_STRING PeekString(size_t count=1); #ifdef GNUDEMANGLE_DEBUG _STD_STRING GetRaw(); #endif _STD_STRING ReadString(size_t count=1); 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() { if (1 > Length()) throw DemangleException(); return m_data[m_offset++]; } void Consume(size_t count=1) { 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; BN::QualifiedName m_varName; DemangleGNU3Reader m_reader; BN::Architecture* m_arch; _STD_VECTOR m_substitute; _STD_VECTOR m_templateSubstitute; _STD_VECTOR<_STD_VECTOR> m_functionSubstitute; _STD_STRING m_lastName; BNNameType m_nameType; bool m_localType; bool m_hasReturnType; bool m_isParameter; bool m_shouldDeleteReader; bool m_topLevel; bool m_isOperatorOverload; // Forward template reference support (for cv conversion operator types). // When m_permitForwardTemplateRefs is true, DemangleTemplateSubstitution() // returns a placeholder instead of throwing for out-of-bounds template params. // m_pendingForwardRefs records which param indices have placeholders so that // ResolveForwardTemplateRefs() can patch them once template args are known. bool m_permitForwardTemplateRefs; bool m_inLocalName; struct ForwardRef { size_t index; }; _STD_VECTOR m_pendingForwardRefs; void ResolveForwardTemplateRefs(DemangledTypeNode& type, const _STD_VECTOR<_STD_STRING>& args); static _STD_STRING ForwardRefPlaceholder(size_t index); enum SymbolType { Function, FunctionWithReturn, Data, VTable, Rtti, Name}; BN::QualifiedName DemangleBaseUnresolvedName(); 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(); DemangledTypeNode DemangleUnqualifiedName(); _STD_STRING DemangleSourceName(); _STD_STRING DemangleNumberAsString(); _STD_STRING DemangleExpression(); _STD_STRING DemanglePrimaryExpression(); DemangledTypeNode DemangleName(); DemangledTypeNode DemangleLocalName(); void DemangleCVQualifiers(bool& cnst, bool& vltl, bool& rstrct); DemangledTypeNode DemangleSubstitution(); DemangledTypeNode DemangleTemplateSubstitution(); void DemangleTemplateArgs(_STD_VECTOR<_STD_STRING>& args, bool* hadNonTypeArg = nullptr); DemangledTypeNode DemangleFunction(bool cnst, bool vltl); DemangledTypeNode DemangleType(); int64_t DemangleNumber(); DemangledTypeNode DemangleNestedName(bool* allTypeTemplateArgs = nullptr); void PushTemplateType(const DemangledTypeNode& type); 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); #ifdef GNUDEMANGLE_DEBUG const DemangledTypeNode& GetTemplateType(size_t ref); void PrintTables(); #endif public: DemangleGNU3(BN::Architecture* arch, const _STD_STRING& mangledName); void Reset(BN::Architecture* arch, const _STD_STRING& mangledName); DemangledTypeNode DemangleSymbol(BN::QualifiedName& varName); BN::QualifiedName GetVarName() const { return m_varName; } }; class DemangleGNU3Static { public: static bool IsGNU3MangledString(const _STD_STRING& name); static bool DemangleGlobalHeader(_STD_STRING& name, _STD_STRING& header); static bool DemangleStringGNU3(BN::Architecture* arch, const _STD_STRING& name, BN::Ref& outType, BN::QualifiedName& outVarName); };