#define liblldb_Mangled_h_
#if defined(__cplusplus)
+#include "lldb/lldb-enumerations.h"
+#include "lldb/lldb-forward.h"
+
#include "lldb/Utility/ConstString.h"
-#include "lldb/lldb-enumerations.h" // for LanguageType
-#include "llvm/ADT/StringRef.h" // for StringRef
-#include <stddef.h> // for size_t
+#include "llvm/ADT/StringRef.h"
-namespace lldb_private {
-class RegularExpression;
-}
-namespace lldb_private {
-class Stream;
-}
+#include <memory>
+#include <stddef.h>
namespace lldb_private {
return true;
return GetDemangledName(language) == name;
}
-
bool NameMatches(const RegularExpression ®ex,
lldb::LanguageType language) const;
//----------------------------------------------------------------------
lldb::LanguageType GuessLanguage() const;
+ /// Function signature for filtering mangled names.
+ using SkipMangledNameFn = bool(llvm::StringRef, ManglingScheme);
+
+ //----------------------------------------------------------------------
+ /// Trigger explicit demangling to obtain rich mangling information. This is
+ /// optimized for batch processing while populating a name index. To get the
+ /// pure demangled name string for a single entity, use GetDemangledName()
+ /// instead.
+ ///
+ /// For names that match the Itanium mangling scheme, this uses LLVM's
+ /// ItaniumPartialDemangler. All other names fall back to LLDB's builtin
+ /// parser currently.
+ ///
+ /// This function is thread-safe when used with different \a context
+ /// instances in different threads.
+ ///
+ /// @param[in] context
+ /// The context for this function. A single instance can be stack-
+ /// allocated in the caller's frame and used for multiple calls.
+ ///
+ /// @param[in] skip_mangled_name
+ /// A filtering function for skipping entities based on name and mangling
+ /// scheme. This can be null if unused.
+ ///
+ /// @return
+ /// True on success, false otherwise.
+ //----------------------------------------------------------------------
+ bool DemangleWithRichManglingInfo(RichManglingContext &context,
+ SkipMangledNameFn *skip_mangled_name);
+
private:
//----------------------------------------------------------------------
/// Mangled member variables.
--- /dev/null
+//===-- RichManglingContext.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RichManglingContext_h_
+#define liblldb_RichManglingContext_h_
+
+#include "lldb/lldb-forward.h"
+#include "lldb/lldb-private.h"
+
+#include "lldb/Utility/ConstString.h"
+
+#include "llvm/ADT/Any.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Demangle/Demangle.h"
+
+namespace lldb_private {
+
+/// Uniform wrapper for access to rich mangling information from different
+/// providers. See Mangled::DemangleWithRichManglingInfo()
+class RichManglingContext {
+public:
+ RichManglingContext()
+ : m_provider(None), m_ipd_buf_size(2048), m_ipd_str_len(0) {
+ m_ipd_buf = static_cast<char *>(std::malloc(m_ipd_buf_size));
+ m_ipd_buf[m_ipd_str_len] = '\0';
+ }
+
+ ~RichManglingContext() { std::free(m_ipd_buf); }
+
+ /// Use the ItaniumPartialDemangler to obtain rich mangling information from
+ /// the given mangled name.
+ bool FromItaniumName(const ConstString &mangled);
+
+ /// Use the legacy language parser implementation to obtain rich mangling
+ /// information from the given demangled name.
+ bool FromCxxMethodName(const ConstString &demangled);
+
+ /// If this symbol describes a constructor or destructor.
+ bool IsCtorOrDtor() const;
+
+ /// If this symbol describes a function.
+ bool IsFunction() const;
+
+ /// Get the base name of a function. This doesn't include trailing template
+ /// arguments, ie "a::b<int>" gives "b". The result will overwrite the
+ /// internal buffer. It can be obtained via GetBufferRef().
+ void ParseFunctionBaseName();
+
+ /// Get the context name for a function. For "a::b::c", this function returns
+ /// "a::b". The result will overwrite the internal buffer. It can be obtained
+ /// via GetBufferRef().
+ void ParseFunctionDeclContextName();
+
+ /// Get the entire demangled name. The result will overwrite the internal
+ /// buffer. It can be obtained via GetBufferRef().
+ void ParseFullName();
+
+ /// Obtain a StringRef to the internal buffer that holds the result of the
+ /// most recent ParseXy() operation. The next ParseXy() call invalidates it.
+ llvm::StringRef GetBufferRef() const {
+ assert(m_provider != None && "Initialize a provider first");
+ return m_buffer;
+ }
+
+private:
+ enum InfoProvider { None, ItaniumPartialDemangler, PluginCxxLanguage };
+
+ /// Selects the rich mangling info provider.
+ InfoProvider m_provider;
+
+ /// Reference to the buffer used for results of ParseXy() operations.
+ llvm::StringRef m_buffer;
+
+ /// Members for ItaniumPartialDemangler
+ llvm::ItaniumPartialDemangler m_ipd;
+ char *m_ipd_buf;
+ size_t m_ipd_buf_size;
+ size_t m_ipd_str_len;
+
+ /// Members for PluginCxxLanguage
+ /// Cannot forward declare inner class CPlusPlusLanguage::MethodName. The
+ /// respective header is in Plugins and including it from here causes cyclic
+ /// dependency. Instead keep a llvm::Any and cast it on-access in the cpp.
+ llvm::Any m_cxx_method_parser;
+
+ /// Clean up memory and set a new info provider for this instance.
+ void ResetProvider(InfoProvider new_provider);
+
+ /// Uniform handling of string buffers for ItaniumPartialDemangler.
+ void processIPDStrResult(char *ipd_res, size_t res_len);
+
+ /// Cast the given parser to the given type. Ideally we would have a type
+ /// trait to deduce \a ParserT from a given InfoProvider, but unfortunately we
+ /// can't access CPlusPlusLanguage::MethodName from within the header.
+ template <class ParserT> static ParserT *get(llvm::Any parser) {
+ assert(parser.hasValue());
+ assert(llvm::any_isa<ParserT *>(parser));
+ return llvm::any_cast<ParserT *>(parser);
+ }
+};
+
+} // namespace lldb_private
+
+#endif
void SymbolIndicesToSymbolContextList(std::vector<uint32_t> &symbol_indexes,
SymbolContextList &sc_list);
+ void RegisterMangledNameEntry(
+ NameToIndexMap::Entry &entry, std::set<const char *> &class_contexts,
+ std::vector<std::pair<NameToIndexMap::Entry, const char *>> &backlog,
+ RichManglingContext &rmc);
+
+ void RegisterBacklogEntry(const NameToIndexMap::Entry &entry,
+ const char *decl_context,
+ const std::set<const char *> &class_contexts);
+
DISALLOW_COPY_AND_ASSIGN(Symtab);
};
class RegisterValue;
class RegularExpression;
class REPL;
+class RichManglingContext;
class Scalar;
class ScriptInterpreter;
class ScriptInterpreterLocker;
} // namespace lldb
+//----------------------------------------------------------------------
+// llvm forward declarations
+//----------------------------------------------------------------------
+namespace llvm {
+
+struct ItaniumPartialDemangler;
+class StringRef;
+
+} // namespace llvm
+
#endif // #if defined(__cplusplus)
#endif // LLDB_lldb_forward_h_
8C3BD9961EF45DA50016C343 /* MainThreadCheckerRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C3BD9951EF45D9B0016C343 /* MainThreadCheckerRuntime.cpp */; };
2689004313353E0400698AC0 /* Mangled.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BC7E8010F1B85900F91463 /* Mangled.cpp */; };
4F29D3CF21010FA3003B549A /* MangledTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4F29D3CD21010F84003B549A /* MangledTest.cpp */; };
+ 4FBC04EF211A06820015A814 /* RichManglingContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 4FBC04EE211A06820015A814 /* RichManglingContext.h */; };
+ 4FBC04ED211A06200015A814 /* RichManglingContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4FBC04EC211A06200015A814 /* RichManglingContext.cpp */; };
+ 4FBC04F5211A13770015A814 /* RichManglingContextTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4FBC04F3211A0F0F0015A814 /* RichManglingContextTest.cpp */; };
4CD44CFC20B37C440003557C /* ManualDWARFIndex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CD44CF920B37C440003557C /* ManualDWARFIndex.cpp */; };
49DCF702170E70120092F75E /* Materializer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49DCF700170E70120092F75E /* Materializer.cpp */; };
2690B3711381D5C300ECFBAE /* Memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2690B3701381D5C300ECFBAE /* Memory.cpp */; };
26BC7E8010F1B85900F91463 /* Mangled.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Mangled.cpp; path = source/Core/Mangled.cpp; sourceTree = "<group>"; };
26BC7D6910F1B77400F91463 /* Mangled.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mangled.h; path = include/lldb/Core/Mangled.h; sourceTree = "<group>"; };
4F29D3CD21010F84003B549A /* MangledTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MangledTest.cpp; sourceTree = "<group>"; };
+ 4FBC04EE211A06820015A814 /* RichManglingContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RichManglingContext.h; path = include/lldb/Core/RichManglingContext.h; sourceTree = "<group>"; };
+ 4FBC04EC211A06200015A814 /* RichManglingContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RichManglingContext.cpp; path = source/Core/RichManglingContext.cpp; sourceTree = "<group>"; };
+ 4FBC04F3211A0F0F0015A814 /* RichManglingContextTest.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RichManglingContextTest.cpp; sourceTree = "<group>"; };
4CD44CF920B37C440003557C /* ManualDWARFIndex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ManualDWARFIndex.cpp; sourceTree = "<group>"; };
4CD44D0020B37C580003557C /* ManualDWARFIndex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ManualDWARFIndex.h; sourceTree = "<group>"; };
2682100C143A59AE004BCF2D /* MappedHash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MappedHash.h; path = include/lldb/Core/MappedHash.h; sourceTree = "<group>"; };
23CB14E51D66CBEB00EDDDE1 /* Core */ = {
isa = PBXGroup;
children = (
+ 23CB14E61D66CC0E00EDDDE1 /* BroadcasterTest.cpp */,
+ 23CB14E71D66CC0E00EDDDE1 /* CMakeLists.txt */,
+ 23CB14E81D66CC0E00EDDDE1 /* DataExtractorTest.cpp */,
58A080B12112AB2200D5580F /* HighlighterTest.cpp */,
- 4F29D3CD21010F84003B549A /* MangledTest.cpp */,
9A3D43E31F3237D500EB767C /* ListenerTest.cpp */,
+ 4F29D3CD21010F84003B549A /* MangledTest.cpp */,
+ 4FBC04F3211A0F0F0015A814 /* RichManglingContextTest.cpp */,
9A3D43E11F3237D500EB767C /* StreamCallbackTest.cpp */,
- 23CB14E71D66CC0E00EDDDE1 /* CMakeLists.txt */,
- 23CB14E61D66CC0E00EDDDE1 /* BroadcasterTest.cpp */,
- 23CB14E81D66CC0E00EDDDE1 /* DataExtractorTest.cpp */,
);
path = Core;
sourceTree = "<group>";
26BC7D7110F1B77400F91463 /* PluginManager.h */,
26BC7E8A10F1B85900F91463 /* PluginManager.cpp */,
2626B6AD143E1BEA00EF935C /* RangeMap.h */,
+ 4FBC04EE211A06820015A814 /* RichManglingContext.h */,
+ 4FBC04EC211A06200015A814 /* RichManglingContext.cpp */,
26BC7CF910F1B71400F91463 /* SearchFilter.h */,
26BC7E1510F1B83100F91463 /* SearchFilter.cpp */,
26BC7D7510F1B77400F91463 /* Section.h */,
2619C4862107A9A2009CDE81 /* RegisterContextMinidump_ARM64.h in Headers */,
AF235EB11FBE77B6009C5541 /* RegisterContextPOSIX_ppc64le.h in Headers */,
267F68501CC02E270086832B /* RegisterContextPOSIXCore_s390x.h in Headers */,
+ 4FBC04EF211A06820015A814 /* RichManglingContext.h in Headers */,
4984BA181B979C08008658D4 /* ExpressionVariable.h in Headers */,
26C7C4841BFFEA7E009BD01F /* WindowsMiniDump.h in Headers */,
30B38A001CAAA6D7009524E3 /* ClangUtil.h in Headers */,
9A2057181F3B861400F6C293 /* TestType.cpp in Sources */,
9A2057171F3B861400F6C293 /* TestDWARFCallFrameInfo.cpp in Sources */,
4F29D3CF21010FA3003B549A /* MangledTest.cpp in Sources */,
+ 4FBC04F5211A13770015A814 /* RichManglingContextTest.cpp in Sources */,
9A3D43EC1F3237F900EB767C /* ListenerTest.cpp in Sources */,
9A3D43DC1F3151C400EB767C /* TimeoutTest.cpp in Sources */,
9A3D43D61F3151C400EB767C /* ConstStringTest.cpp in Sources */,
4C0083401B9F9BA900D5CF24 /* UtilityFunction.cpp in Sources */,
AF415AE71D949E4400FCE0D4 /* x86AssemblyInspectionEngine.cpp in Sources */,
26474CCD18D0CB5B0073DEBA /* RegisterContextPOSIX_x86.cpp in Sources */,
+ 4FBC04ED211A06200015A814 /* RichManglingContext.cpp in Sources */,
AEB0E4591BD6E9F800B24093 /* LLVMUserExpression.cpp in Sources */,
2689FFEF13353DB600698AC0 /* Breakpoint.cpp in Sources */,
267A47FB1B1411C40021A5BC /* NativeRegisterContext.cpp in Sources */,
ModuleList.cpp
Opcode.cpp
PluginManager.cpp
+ RichManglingContext.cpp
SearchFilter.cpp
Section.cpp
SourceManager.cpp
#pragma comment(lib, "dbghelp.lib")
#endif
+#include "lldb/Core/RichManglingContext.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Logging.h"
}
//----------------------------------------------------------------------
+// Local helpers for different demangling implementations.
+//----------------------------------------------------------------------
+static char *GetMSVCDemangledStr(const char *M) {
+#if defined(_MSC_VER)
+ const size_t demangled_length = 2048;
+ char *demangled_cstr = static_cast<char *>(::malloc(demangled_length));
+ ::ZeroMemory(demangled_cstr, demangled_length);
+ DWORD result = safeUndecorateName(M, demangled_cstr, demangled_length);
+
+ if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
+ if (demangled_cstr && demangled_cstr[0])
+ log->Printf("demangled msvc: %s -> \"%s\"", M, demangled_cstr);
+ else
+ log->Printf("demangled msvc: %s -> error: 0x%lu", M, result);
+ }
+
+ if (result != 0) {
+ return demangled_cstr;
+ } else {
+ ::free(demangled_cstr);
+ return nullptr;
+ }
+#else
+ return nullptr;
+#endif
+}
+
+static char *GetItaniumDemangledStr(const char *M,
+ llvm::ItaniumPartialDemangler &ipd) {
+ char *demangled_cstr = nullptr;
+ bool err = ipd.partialDemangle(M);
+ if (!err) {
+ // Default buffer and size (will realloc in case it's too small).
+ size_t demangled_size = 80;
+ demangled_cstr = static_cast<char *>(std::malloc(demangled_size));
+ demangled_cstr = ipd.finishDemangle(demangled_cstr, &demangled_size);
+
+ assert(demangled_cstr &&
+ "finishDemangle must always succeed if partialDemangle did");
+ assert(demangled_cstr[demangled_size - 1] == '\0' &&
+ "Expected demangled_size to return length including trailing null");
+ }
+
+ if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
+ if (demangled_cstr)
+ log->Printf("demangled itanium: %s -> \"%s\"", M, demangled_cstr);
+ else
+ log->Printf("demangled itanium: %s -> error: failed to demangle", M);
+ }
+
+ return demangled_cstr;
+}
+
+//----------------------------------------------------------------------
+// Explicit demangling for scheduled requests during batch processing. This
+// makes use of ItaniumPartialDemangler's rich demangle info
+//----------------------------------------------------------------------
+bool Mangled::DemangleWithRichManglingInfo(
+ RichManglingContext &context, SkipMangledNameFn *skip_mangled_name) {
+ // We need to generate and cache the demangled name.
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat,
+ "Mangled::DemangleWithRichNameIndexInfo (m_mangled = %s)",
+ m_mangled.GetCString());
+
+ // Others are not meant to arrive here. ObjC names or C's main() for example
+ // have their names stored in m_demangled, while m_mangled is empty.
+ assert(m_mangled);
+
+ // Check whether or not we are interested in this name at all.
+ ManglingScheme scheme = cstring_mangling_scheme(m_mangled.GetCString());
+ if (skip_mangled_name && skip_mangled_name(m_mangled.GetStringRef(), scheme))
+ return false;
+
+ switch (scheme) {
+ case eManglingSchemeNone:
+ // The current mangled_name_filter would allow llvm_unreachable here.
+ return false;
+
+ case eManglingSchemeItanium:
+ // We want the rich mangling info here, so we don't care whether or not
+ // there is a demangled string in the pool already.
+ if (context.FromItaniumName(m_mangled)) {
+ // If we got an info, we have a name. Copy to string pool and connect the
+ // counterparts to accelerate later access in GetDemangledName().
+ context.ParseFullName();
+ m_demangled.SetStringWithMangledCounterpart(context.GetBufferRef(),
+ m_mangled);
+ return true;
+ } else {
+ m_demangled.SetCString("");
+ return false;
+ }
+
+ case eManglingSchemeMSVC: {
+ // We have no rich mangling for MSVC-mangled names yet, so first try to
+ // demangle it if necessary.
+ if (!m_demangled && !m_mangled.GetMangledCounterpart(m_demangled)) {
+ if (char *d = GetMSVCDemangledStr(m_mangled.GetCString())) {
+ // If we got an info, we have a name. Copy to string pool and connect
+ // the counterparts to accelerate later access in GetDemangledName().
+ m_demangled.SetStringWithMangledCounterpart(llvm::StringRef(d),
+ m_mangled);
+ ::free(d);
+ } else {
+ m_demangled.SetCString("");
+ }
+ }
+
+ if (m_demangled.IsEmpty()) {
+ // Cannot demangle it, so don't try parsing.
+ return false;
+ } else {
+ // Demangled successfully, we can try and parse it with
+ // CPlusPlusLanguage::MethodName.
+ return context.FromCxxMethodName(m_demangled);
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------------------
// Generate the demangled name on demand using this accessor. Code in this
// class will need to use this accessor if it wishes to decode the demangled
// name. The result is cached and will be kept until a new string value is
Timer scoped_timer(func_cat, "Mangled::GetDemangledName (m_mangled = %s)",
m_mangled.GetCString());
- Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE);
-
// Don't bother running anything that isn't mangled
const char *mangled_name = m_mangled.GetCString();
ManglingScheme mangling_scheme{cstring_mangling_scheme(mangled_name)};
// add it to our map.
char *demangled_name = nullptr;
switch (mangling_scheme) {
- case eManglingSchemeMSVC: {
-#if defined(_MSC_VER)
- if (log)
- log->Printf("demangle msvc: %s", mangled_name);
- const size_t demangled_length = 2048;
- demangled_name = static_cast<char *>(::malloc(demangled_length));
- ::ZeroMemory(demangled_name, demangled_length);
- DWORD result =
- safeUndecorateName(mangled_name, demangled_name, demangled_length);
- if (log) {
- if (demangled_name && demangled_name[0])
- log->Printf("demangled msvc: %s -> \"%s\"", mangled_name,
- demangled_name);
- else
- log->Printf("demangled msvc: %s -> error: 0x%lu", mangled_name,
- result);
- }
-
- if (result == 0) {
- free(demangled_name);
- demangled_name = nullptr;
- }
-#endif
+ case eManglingSchemeMSVC:
+ demangled_name = GetMSVCDemangledStr(mangled_name);
break;
- }
case eManglingSchemeItanium: {
- llvm::ItaniumPartialDemangler IPD;
- bool demangle_err = IPD.partialDemangle(mangled_name);
- if (!demangle_err) {
- // Default buffer and size (realloc is used in case it's too small).
- size_t demangled_size = 80;
- demangled_name = static_cast<char *>(::malloc(demangled_size));
- demangled_name = IPD.finishDemangle(demangled_name, &demangled_size);
- }
-
- if (log) {
- if (demangled_name)
- log->Printf("demangled itanium: %s -> \"%s\"", mangled_name,
- demangled_name);
- else
- log->Printf("demangled itanium: %s -> error: failed to demangle",
- mangled_name);
- }
+ llvm::ItaniumPartialDemangler ipd;
+ demangled_name = GetItaniumDemangledStr(mangled_name, ipd);
break;
}
case eManglingSchemeNone:
- break;
+ llvm_unreachable("eManglingSchemeNone was handled already");
}
if (demangled_name) {
- m_demangled.SetStringWithMangledCounterpart(demangled_name, m_mangled);
+ m_demangled.SetStringWithMangledCounterpart(
+ llvm::StringRef(demangled_name), m_mangled);
free(demangled_name);
}
}
--- /dev/null
+//===-- RichManglingContext.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/RichManglingContext.h"
+
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h"
+
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+
+#include "llvm/ADT/StringRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RichManglingContext
+//----------------------------------------------------------------------
+void RichManglingContext::ResetProvider(InfoProvider new_provider) {
+ // If we want to support parsers for other languages some day, we need a
+ // switch here to delete the correct parser type.
+ if (m_cxx_method_parser.hasValue()) {
+ assert(m_provider == PluginCxxLanguage);
+ delete get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser);
+ m_cxx_method_parser.reset();
+ }
+
+ assert(new_provider != None && "Only reset to a valid provider");
+ m_provider = new_provider;
+}
+
+bool RichManglingContext::FromItaniumName(const ConstString &mangled) {
+ bool err = m_ipd.partialDemangle(mangled.GetCString());
+ if (!err) {
+ ResetProvider(ItaniumPartialDemangler);
+ }
+
+ if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
+ if (!err) {
+ ParseFullName();
+ LLDB_LOG(log, "demangled itanium: {0} -> \"{1}\"", mangled, m_ipd_buf);
+ } else {
+ LLDB_LOG(log, "demangled itanium: {0} -> error: failed to demangle",
+ mangled);
+ }
+ }
+
+ return !err; // true == success
+}
+
+bool RichManglingContext::FromCxxMethodName(const ConstString &demangled) {
+ ResetProvider(PluginCxxLanguage);
+ m_cxx_method_parser = new CPlusPlusLanguage::MethodName(demangled);
+ return true;
+}
+
+bool RichManglingContext::IsCtorOrDtor() const {
+ assert(m_provider != None && "Initialize a provider first");
+ switch (m_provider) {
+ case ItaniumPartialDemangler:
+ return m_ipd.isCtorOrDtor();
+ case PluginCxxLanguage: {
+ // We can only check for destructors here.
+ auto base_name =
+ get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename();
+ return base_name.startswith("~");
+ }
+ case None:
+ return false;
+ }
+}
+
+bool RichManglingContext::IsFunction() const {
+ assert(m_provider != None && "Initialize a provider first");
+ switch (m_provider) {
+ case ItaniumPartialDemangler:
+ return m_ipd.isFunction();
+ case PluginCxxLanguage:
+ return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->IsValid();
+ case None:
+ return false;
+ }
+}
+
+void RichManglingContext::processIPDStrResult(char *ipd_res, size_t res_size) {
+ if (LLVM_UNLIKELY(ipd_res == nullptr)) {
+ assert(res_size == m_ipd_buf_size &&
+ "Failed IPD queries keep the original size in the N parameter");
+
+ // Error case: Clear the buffer.
+ m_ipd_str_len = 0;
+ m_ipd_buf[m_ipd_str_len] = '\0';
+ } else {
+ // IPD's res_size includes null terminator.
+ size_t res_len = res_size - 1;
+ assert(ipd_res[res_len] == '\0' &&
+ "IPD returns null-terminated strings and we rely on that");
+
+ if (LLVM_UNLIKELY(ipd_res != m_ipd_buf)) {
+ // Realloc case: Take over the new buffer.
+ m_ipd_buf = ipd_res; // std::realloc freed or reused the old buffer.
+ m_ipd_buf_size =
+ res_size; // Actual buffer may be bigger, but we can't know.
+ m_ipd_str_len = res_len;
+
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE);
+ if (log)
+ log->Printf("ItaniumPartialDemangler Realloc: new buffer size %lu",
+ m_ipd_buf_size);
+ } else {
+ // 99% case: Just remember the string length.
+ m_ipd_str_len = res_len;
+ }
+ }
+
+ m_buffer = llvm::StringRef(m_ipd_buf, m_ipd_str_len);
+}
+
+void RichManglingContext::ParseFunctionBaseName() {
+ assert(m_provider != None && "Initialize a provider first");
+ switch (m_provider) {
+ case ItaniumPartialDemangler: {
+ auto n = m_ipd_buf_size;
+ auto buf = m_ipd.getFunctionBaseName(m_ipd_buf, &n);
+ processIPDStrResult(buf, n);
+ return;
+ }
+ case PluginCxxLanguage:
+ m_buffer =
+ get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename();
+ return;
+ case None:
+ return;
+ }
+}
+
+void RichManglingContext::ParseFunctionDeclContextName() {
+ assert(m_provider != None && "Initialize a provider first");
+ switch (m_provider) {
+ case ItaniumPartialDemangler: {
+ auto n = m_ipd_buf_size;
+ auto buf = m_ipd.getFunctionDeclContextName(m_ipd_buf, &n);
+ processIPDStrResult(buf, n);
+ return;
+ }
+ case PluginCxxLanguage:
+ m_buffer =
+ get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetContext();
+ return;
+ case None:
+ return;
+ }
+}
+
+void RichManglingContext::ParseFullName() {
+ assert(m_provider != None && "Initialize a provider first");
+ switch (m_provider) {
+ case ItaniumPartialDemangler: {
+ auto n = m_ipd_buf_size;
+ auto buf = m_ipd.finishDemangle(m_ipd_buf, &n);
+ processIPDStrResult(buf, n);
+ return;
+ }
+ case PluginCxxLanguage:
+ m_buffer = get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
+ ->GetFullName()
+ .GetStringRef();
+ return;
+ case None:
+ return;
+ }
+}
#include <map>
#include <set>
-#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
#include "Plugins/Language/ObjC/ObjCLanguage.h"
+
#include "lldb/Core/Module.h"
+#include "lldb/Core/RichManglingContext.h"
#include "lldb/Core/STLUtils.h"
#include "lldb/Core/Section.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/Timer.h"
+#include "llvm/ADT/StringRef.h"
+
using namespace lldb;
using namespace lldb_private;
//----------------------------------------------------------------------
// InitNameIndexes
//----------------------------------------------------------------------
+static bool lldb_skip_name(llvm::StringRef mangled,
+ Mangled::ManglingScheme scheme) {
+ switch (scheme) {
+ case Mangled::eManglingSchemeItanium: {
+ if (mangled.size() < 3 || !mangled.startswith("_Z"))
+ return true;
+
+ // Avoid the following types of symbols in the index.
+ switch (mangled[2]) {
+ case 'G': // guard variables
+ case 'T': // virtual tables, VTT structures, typeinfo structures + names
+ case 'Z': // named local entities (if we eventually handle
+ // eSymbolTypeData, we will want this back)
+ return true;
+
+ default:
+ break;
+ }
+
+ // Include this name in the index.
+ return false;
+ }
+
+ // No filters for this scheme yet. Include all names in indexing.
+ case Mangled::eManglingSchemeMSVC:
+ return false;
+
+ // Don't try and demangle things we can't categorize.
+ case Mangled::eManglingSchemeNone:
+ return true;
+ }
+}
+
void Symtab::InitNameIndexes() {
// Protected function, no need to lock mutex...
if (!m_name_indexes_computed) {
m_name_to_index.Reserve(actual_count);
#endif
- NameToIndexMap::Entry entry;
-
- // The "const char *" in "class_contexts" must come from a
- // ConstString::GetCString()
+ // The "const char *" in "class_contexts" and backlog::value_type::second
+ // must come from a ConstString::GetCString()
std::set<const char *> class_contexts;
- UniqueCStringMap<uint32_t> mangled_name_to_index;
- std::vector<const char *> symbol_contexts(num_symbols, nullptr);
+ std::vector<std::pair<NameToIndexMap::Entry, const char *>> backlog;
+ backlog.reserve(num_symbols / 2);
+
+ // Instantiation of the demangler is expensive, so better use a single one
+ // for all entries during batch processing.
+ RichManglingContext rmc;
+ NameToIndexMap::Entry entry;
for (entry.value = 0; entry.value < num_symbols; ++entry.value) {
- const Symbol *symbol = &m_symbols[entry.value];
+ Symbol *symbol = &m_symbols[entry.value];
// Don't let trampolines get into the lookup by name map If we ever need
// the trampoline symbols to be searchable by name we can remove this and
if (symbol->IsTrampoline())
continue;
- const Mangled &mangled = symbol->GetMangled();
+ // If the symbol's name string matched a Mangled::ManglingScheme, it is
+ // stored in the mangled field.
+ Mangled &mangled = symbol->GetMangled();
entry.cstring = mangled.GetMangledName();
if (entry.cstring) {
m_name_to_index.Append(entry);
m_name_to_index.Append(entry);
}
- const SymbolType symbol_type = symbol->GetType();
- if (symbol_type == eSymbolTypeCode ||
- symbol_type == eSymbolTypeResolver) {
- llvm::StringRef entry_ref(entry.cstring.GetStringRef());
- if (entry_ref[0] == '_' && entry_ref[1] == 'Z' &&
- (entry_ref[2] != 'T' && // avoid virtual table, VTT structure,
- // typeinfo structure, and typeinfo
- // name
- entry_ref[2] != 'G' && // avoid guard variables
- entry_ref[2] != 'Z')) // named local entities (if we
- // eventually handle eSymbolTypeData,
- // we will want this back)
- {
- CPlusPlusLanguage::MethodName cxx_method(
- mangled.GetDemangledName(lldb::eLanguageTypeC_plus_plus));
- entry.cstring = ConstString(cxx_method.GetBasename());
- if (entry.cstring) {
- // ConstString objects permanently store the string in the pool
- // so calling GetCString() on the value gets us a const char *
- // that will never go away
- const char *const_context =
- ConstString(cxx_method.GetContext()).GetCString();
-
- if (!const_context || const_context[0] == 0) {
- // No context for this function so this has to be a basename
- m_basename_to_index.Append(entry);
- // If there is no context (no namespaces or class scopes that
- // come before the function name) then this also could be a
- // fullname.
- m_name_to_index.Append(entry);
- } else {
- entry_ref = entry.cstring.GetStringRef();
- if (entry_ref[0] == '~' ||
- !cxx_method.GetQualifiers().empty()) {
- // The first character of the demangled basename is '~' which
- // means we have a class destructor. We can use this
- // information to help us know what is a class and what
- // isn't.
- if (class_contexts.find(const_context) == class_contexts.end())
- class_contexts.insert(const_context);
- m_method_to_index.Append(entry);
- } else {
- if (class_contexts.find(const_context) !=
- class_contexts.end()) {
- // The current decl context is in our "class_contexts"
- // which means this is a method on a class
- m_method_to_index.Append(entry);
- } else {
- // We don't know if this is a function basename or a
- // method, so put it into a temporary collection so once we
- // are done we can look in class_contexts to see if each
- // entry is a class or just a function and will put any
- // remaining items into m_method_to_index or
- // m_basename_to_index as needed
- mangled_name_to_index.Append(entry);
- symbol_contexts[entry.value] = const_context;
- }
- }
- }
- }
- }
+ const SymbolType type = symbol->GetType();
+ if (type == eSymbolTypeCode || type == eSymbolTypeResolver) {
+ if (mangled.DemangleWithRichManglingInfo(rmc, lldb_skip_name))
+ RegisterMangledNameEntry(entry, class_contexts, backlog, rmc);
}
}
+ // Symbol name strings that didn't match a Mangled::ManglingScheme, are
+ // stored in the demangled field.
entry.cstring = mangled.GetDemangledName(symbol->GetLanguage());
if (entry.cstring) {
m_name_to_index.Append(entry);
}
}
- size_t count;
- if (!mangled_name_to_index.IsEmpty()) {
- count = mangled_name_to_index.GetSize();
- for (size_t i = 0; i < count; ++i) {
- if (mangled_name_to_index.GetValueAtIndex(i, entry.value)) {
- entry.cstring = mangled_name_to_index.GetCStringAtIndex(i);
- if (symbol_contexts[entry.value] &&
- class_contexts.find(symbol_contexts[entry.value]) !=
- class_contexts.end()) {
- m_method_to_index.Append(entry);
- } else {
- // If we got here, we have something that had a context (was inside
- // a namespace or class) yet we don't know if the entry
- m_method_to_index.Append(entry);
- m_basename_to_index.Append(entry);
- }
- }
- }
+ for (const auto &record : backlog) {
+ RegisterBacklogEntry(record.first, record.second, class_contexts);
}
+
m_name_to_index.Sort();
m_name_to_index.SizeToFit();
m_selector_to_index.Sort();
}
}
+void Symtab::RegisterMangledNameEntry(
+ NameToIndexMap::Entry &entry, std::set<const char *> &class_contexts,
+ std::vector<std::pair<NameToIndexMap::Entry, const char *>> &backlog,
+ RichManglingContext &rmc) {
+ // Only register functions that have a base name.
+ rmc.ParseFunctionBaseName();
+ llvm::StringRef base_name = rmc.GetBufferRef();
+ if (base_name.empty())
+ return;
+
+ // The base name will be our entry's name.
+ entry.cstring = ConstString(base_name);
+
+ rmc.ParseFunctionDeclContextName();
+ llvm::StringRef decl_context = rmc.GetBufferRef();
+
+ // Register functions with no context.
+ if (decl_context.empty()) {
+ // This has to be a basename
+ m_basename_to_index.Append(entry);
+ // If there is no context (no namespaces or class scopes that come before
+ // the function name) then this also could be a fullname.
+ m_name_to_index.Append(entry);
+ return;
+ }
+
+ // Make sure we have a pool-string pointer and see if we already know the
+ // context name.
+ const char *decl_context_ccstr = ConstString(decl_context).GetCString();
+ auto it = class_contexts.find(decl_context_ccstr);
+
+ // Register constructors and destructors. They are methods and create
+ // declaration contexts.
+ if (rmc.IsCtorOrDtor()) {
+ m_method_to_index.Append(entry);
+ if (it == class_contexts.end())
+ class_contexts.insert(it, decl_context_ccstr);
+ return;
+ }
+
+ // Register regular methods with a known declaration context.
+ if (it != class_contexts.end()) {
+ m_method_to_index.Append(entry);
+ return;
+ }
+
+ // Regular methods in unknown declaration contexts are put to the backlog. We
+ // will revisit them once we processed all remaining symbols.
+ backlog.push_back(std::make_pair(entry, decl_context_ccstr));
+}
+
+void Symtab::RegisterBacklogEntry(
+ const NameToIndexMap::Entry &entry, const char *decl_context,
+ const std::set<const char *> &class_contexts) {
+ auto it = class_contexts.find(decl_context);
+ if (it != class_contexts.end()) {
+ m_method_to_index.Append(entry);
+ } else {
+ // If we got here, we have something that had a context (was inside
+ // a namespace or class) yet we don't know the entry
+ m_method_to_index.Append(entry);
+ m_basename_to_index.Append(entry);
+ }
+}
+
void Symtab::PreloadSymbols() {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
InitNameIndexes();
EventTest.cpp
ListenerTest.cpp
MangledTest.cpp
+ RichManglingContextTest.cpp
StreamCallbackTest.cpp
LINK_LIBS
--- /dev/null
+//===-- RichManglingContextTest.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/RichManglingContext.h"
+
+#include "lldb/Utility/ConstString.h"
+
+#include "gtest/gtest.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+TEST(RichManglingContextTest, Basic) {
+ RichManglingContext RMC;
+ ConstString mangled("_ZN3foo3barEv");
+ EXPECT_TRUE(RMC.FromItaniumName(mangled));
+
+ EXPECT_TRUE(RMC.IsFunction());
+ EXPECT_FALSE(RMC.IsCtorOrDtor());
+
+ RMC.ParseFunctionDeclContextName();
+ EXPECT_EQ("foo", RMC.GetBufferRef());
+
+ RMC.ParseFunctionBaseName();
+ EXPECT_EQ("bar", RMC.GetBufferRef());
+
+ RMC.ParseFullName();
+ EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
+}
+
+TEST(RichManglingContextTest, FromCxxMethodName) {
+ RichManglingContext ItaniumRMC;
+ ConstString mangled("_ZN3foo3barEv");
+ EXPECT_TRUE(ItaniumRMC.FromItaniumName(mangled));
+
+ RichManglingContext CxxMethodRMC;
+ ConstString demangled("foo::bar()");
+ EXPECT_TRUE(CxxMethodRMC.FromCxxMethodName(demangled));
+
+ EXPECT_TRUE(ItaniumRMC.IsFunction() == CxxMethodRMC.IsFunction());
+ EXPECT_TRUE(ItaniumRMC.IsCtorOrDtor() == CxxMethodRMC.IsCtorOrDtor());
+
+ ItaniumRMC.ParseFunctionDeclContextName();
+ CxxMethodRMC.ParseFunctionDeclContextName();
+ EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef());
+
+ ItaniumRMC.ParseFunctionBaseName();
+ CxxMethodRMC.ParseFunctionBaseName();
+ EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef());
+
+ ItaniumRMC.ParseFullName();
+ CxxMethodRMC.ParseFullName();
+ EXPECT_TRUE(ItaniumRMC.GetBufferRef() == CxxMethodRMC.GetBufferRef());
+}
+
+TEST(RichManglingContextTest, SwitchProvider) {
+ RichManglingContext RMC;
+ llvm::StringRef mangled = "_ZN3foo3barEv";
+ llvm::StringRef demangled = "foo::bar()";
+
+ EXPECT_TRUE(RMC.FromItaniumName(ConstString(mangled)));
+ RMC.ParseFullName();
+ EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
+
+ EXPECT_TRUE(RMC.FromCxxMethodName(ConstString(demangled)));
+ RMC.ParseFullName();
+ EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
+
+ EXPECT_TRUE(RMC.FromItaniumName(ConstString(mangled)));
+ RMC.ParseFullName();
+ EXPECT_EQ("foo::bar()", RMC.GetBufferRef());
+}
+
+TEST(RichManglingContextTest, IPDRealloc) {
+ // The demangled name should fit into the Itanium default buffer.
+ const char *short_mangled = "_ZN3foo3barEv";
+
+ // The demangled name for this will certainly not fit into the default buffer.
+ const char *long_mangled =
+ "_ZNK3shk6detail17CallbackPublisherIZNS_5ThrowERKNSt15__exception_"
+ "ptr13exception_ptrEEUlOT_E_E9SubscribeINS0_9ConcatMapINS0_"
+ "18CallbackSubscriberIZNS_6GetAllIiNS1_IZZNS_9ConcatMapIZNS_6ConcatIJNS1_"
+ "IZZNS_3MapIZZNS_7IfEmptyIS9_EEDaS7_ENKUlS6_E_clINS1_IZZNS_4TakeIiEESI_"
+ "S7_ENKUlS6_E_clINS1_IZZNS_6FilterIZNS_9ElementAtEmEUlS7_E_EESI_S7_"
+ "ENKUlS6_E_clINS1_IZZNSL_ImEESI_S7_ENKUlS6_E_clINS1_IZNS_4FromINS0_"
+ "22InfiniteRangeContainerIiEEEESI_S7_EUlS7_E_EEEESI_S6_EUlS7_E_EEEESI_S6_"
+ "EUlS7_E_EEEESI_S6_EUlS7_E_EEEESI_S6_EUlS7_E_EESI_S7_ENKUlS6_E_clIS14_"
+ "EESI_S6_EUlS7_E_EERNS1_IZZNSH_IS9_EESI_S7_ENKSK_IS14_EESI_S6_EUlS7_E0_"
+ "EEEEESI_DpOT_EUlS7_E_EESI_S7_ENKUlS6_E_clINS1_IZNS_5StartIJZNS_"
+ "4JustIJS19_S1C_EEESI_S1F_EUlvE_ZNS1K_IJS19_S1C_EEESI_S1F_EUlvE0_EEESI_"
+ "S1F_EUlS7_E_EEEESI_S6_EUlS7_E_EEEESt6vectorIS6_SaIS6_EERKT0_NS_"
+ "12ElementCountEbEUlS7_E_ZNSD_IiS1Q_EES1T_S1W_S1X_bEUlOS3_E_ZNSD_IiS1Q_"
+ "EES1T_S1W_S1X_bEUlvE_EES1G_S1O_E25ConcatMapValuesSubscriberEEEDaS7_";
+
+ RichManglingContext RMC;
+
+ // Demangle the short one and remember the buffer address.
+ EXPECT_TRUE(RMC.FromItaniumName(ConstString(short_mangled)));
+ RMC.ParseFullName();
+ const char *short_demangled_ptr = RMC.GetBufferRef().data();
+
+ // Demangle the long one and make sure the buffer address changed.
+ EXPECT_TRUE(RMC.FromItaniumName(ConstString(long_mangled)));
+ RMC.ParseFullName();
+ const char *long_demangled_ptr = RMC.GetBufferRef().data();
+
+ EXPECT_TRUE(short_demangled_ptr != long_demangled_ptr);
+}