summaryrefslogtreecommitdiff
path: root/lldb/source/Core/Mangled.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Core/Mangled.cpp')
-rw-r--r--lldb/source/Core/Mangled.cpp438
1 files changed, 438 insertions, 0 deletions
diff --git a/lldb/source/Core/Mangled.cpp b/lldb/source/Core/Mangled.cpp
new file mode 100644
index 000000000000..b06656aa3fb7
--- /dev/null
+++ b/lldb/source/Core/Mangled.cpp
@@ -0,0 +1,438 @@
+//===-- Mangled.cpp ---------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Mangled.h"
+
+#include "lldb/Core/RichManglingContext.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/Logging.h"
+#include "lldb/Utility/RegularExpression.h"
+#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/Timer.h"
+#include "lldb/lldb-enumerations.h"
+
+#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+#include "Plugins/Language/ObjC/ObjCLanguage.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Demangle/Demangle.h"
+#include "llvm/Support/Compiler.h"
+
+#include <mutex>
+#include <string>
+#include <utility>
+
+#include <stdlib.h>
+#include <string.h>
+using namespace lldb_private;
+
+static inline Mangled::ManglingScheme cstring_mangling_scheme(const char *s) {
+ if (s) {
+ if (s[0] == '?')
+ return Mangled::eManglingSchemeMSVC;
+ if (s[0] == '_' && s[1] == 'Z')
+ return Mangled::eManglingSchemeItanium;
+ }
+ return Mangled::eManglingSchemeNone;
+}
+
+static inline bool cstring_is_mangled(const char *s) {
+ return cstring_mangling_scheme(s) != Mangled::eManglingSchemeNone;
+}
+
+static ConstString
+get_demangled_name_without_arguments(ConstString mangled,
+ ConstString demangled) {
+ // This pair is <mangled name, demangled name without function arguments>
+ static std::pair<ConstString, ConstString>
+ g_most_recent_mangled_to_name_sans_args;
+
+ // Need to have the mangled & demangled names we're currently examining as
+ // statics so we can return a const ref to them at the end of the func if we
+ // don't have anything better.
+ static ConstString g_last_mangled;
+ static ConstString g_last_demangled;
+
+ if (mangled && g_most_recent_mangled_to_name_sans_args.first == mangled) {
+ return g_most_recent_mangled_to_name_sans_args.second;
+ }
+
+ g_last_demangled = demangled;
+ g_last_mangled = mangled;
+
+ const char *mangled_name_cstr = mangled.GetCString();
+
+ if (demangled && mangled_name_cstr && mangled_name_cstr[0]) {
+ if (mangled_name_cstr[0] == '_' && mangled_name_cstr[1] == 'Z' &&
+ (mangled_name_cstr[2] != 'T' && // avoid virtual table, VTT structure,
+ // typeinfo structure, and typeinfo
+ // mangled_name
+ mangled_name_cstr[2] != 'G' && // avoid guard variables
+ mangled_name_cstr[2] != 'Z')) // named local entities (if we eventually
+ // handle eSymbolTypeData, we will want
+ // this back)
+ {
+ CPlusPlusLanguage::MethodName cxx_method(demangled);
+ if (!cxx_method.GetBasename().empty()) {
+ std::string shortname;
+ if (!cxx_method.GetContext().empty())
+ shortname = cxx_method.GetContext().str() + "::";
+ shortname += cxx_method.GetBasename().str();
+ ConstString result(shortname.c_str());
+ g_most_recent_mangled_to_name_sans_args.first = mangled;
+ g_most_recent_mangled_to_name_sans_args.second = result;
+ return g_most_recent_mangled_to_name_sans_args.second;
+ }
+ }
+ }
+
+ if (demangled)
+ return g_last_demangled;
+ return g_last_mangled;
+}
+
+#pragma mark Mangled
+
+Mangled::Mangled(ConstString s) : m_mangled(), m_demangled() {
+ if (s)
+ SetValue(s);
+}
+
+Mangled::Mangled(llvm::StringRef name) {
+ if (!name.empty())
+ SetValue(ConstString(name));
+}
+
+// Convert to pointer operator. This allows code to check any Mangled objects
+// to see if they contain anything valid using code such as:
+//
+// Mangled mangled(...);
+// if (mangled)
+// { ...
+Mangled::operator void *() const {
+ return (m_mangled) ? const_cast<Mangled *>(this) : nullptr;
+}
+
+// Logical NOT operator. This allows code to check any Mangled objects to see
+// if they are invalid using code such as:
+//
+// Mangled mangled(...);
+// if (!file_spec)
+// { ...
+bool Mangled::operator!() const { return !m_mangled; }
+
+// Clear the mangled and demangled values.
+void Mangled::Clear() {
+ m_mangled.Clear();
+ m_demangled.Clear();
+}
+
+// Compare the string values.
+int Mangled::Compare(const Mangled &a, const Mangled &b) {
+ return ConstString::Compare(
+ a.GetName(lldb::eLanguageTypeUnknown, ePreferMangled),
+ b.GetName(lldb::eLanguageTypeUnknown, ePreferMangled));
+}
+
+// Set the string value in this objects. If "mangled" is true, then the mangled
+// named is set with the new value in "s", else the demangled name is set.
+void Mangled::SetValue(ConstString s, bool mangled) {
+ if (s) {
+ if (mangled) {
+ m_demangled.Clear();
+ m_mangled = s;
+ } else {
+ m_demangled = s;
+ m_mangled.Clear();
+ }
+ } else {
+ m_demangled.Clear();
+ m_mangled.Clear();
+ }
+}
+
+void Mangled::SetValue(ConstString name) {
+ if (name) {
+ if (cstring_is_mangled(name.GetCString())) {
+ m_demangled.Clear();
+ m_mangled = name;
+ } else {
+ m_demangled = name;
+ m_mangled.Clear();
+ }
+ } else {
+ m_demangled.Clear();
+ m_mangled.Clear();
+ }
+}
+
+// Local helpers for different demangling implementations.
+static char *GetMSVCDemangledStr(const char *M) {
+ char *demangled_cstr = llvm::microsoftDemangle(
+ M, nullptr, nullptr, nullptr,
+ llvm::MSDemangleFlags(llvm::MSDF_NoAccessSpecifier |
+ llvm::MSDF_NoCallingConvention |
+ llvm::MSDF_NoMemberType));
+
+ if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
+ if (demangled_cstr && demangled_cstr[0])
+ LLDB_LOGF(log, "demangled msvc: %s -> \"%s\"", M, demangled_cstr);
+ else
+ LLDB_LOGF(log, "demangled msvc: %s -> error", M);
+ }
+
+ return demangled_cstr;
+}
+
+static char *GetItaniumDemangledStr(const char *M) {
+ char *demangled_cstr = nullptr;
+
+ llvm::ItaniumPartialDemangler ipd;
+ 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)
+ LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr);
+ else
+ LLDB_LOGF(log, "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);
+ }
+ }
+ }
+ llvm_unreachable("Fully covered switch above!");
+}
+
+// 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
+// supplied to this object, or until the end of the object's lifetime.
+ConstString
+Mangled::GetDemangledName(lldb::LanguageType language) const {
+ // Check to make sure we have a valid mangled name and that we haven't
+ // already decoded our mangled name.
+ if (m_mangled && m_demangled.IsNull()) {
+ // We need to generate and cache the demangled name.
+ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
+ Timer scoped_timer(func_cat, "Mangled::GetDemangledName (m_mangled = %s)",
+ m_mangled.GetCString());
+
+ // Don't bother running anything that isn't mangled
+ const char *mangled_name = m_mangled.GetCString();
+ ManglingScheme mangling_scheme{cstring_mangling_scheme(mangled_name)};
+ if (mangling_scheme != eManglingSchemeNone &&
+ !m_mangled.GetMangledCounterpart(m_demangled)) {
+ // We didn't already mangle this name, demangle it and if all goes well
+ // add it to our map.
+ char *demangled_name = nullptr;
+ switch (mangling_scheme) {
+ case eManglingSchemeMSVC:
+ demangled_name = GetMSVCDemangledStr(mangled_name);
+ break;
+ case eManglingSchemeItanium: {
+ demangled_name = GetItaniumDemangledStr(mangled_name);
+ break;
+ }
+ case eManglingSchemeNone:
+ llvm_unreachable("eManglingSchemeNone was handled already");
+ }
+ if (demangled_name) {
+ m_demangled.SetStringWithMangledCounterpart(
+ llvm::StringRef(demangled_name), m_mangled);
+ free(demangled_name);
+ }
+ }
+ if (m_demangled.IsNull()) {
+ // Set the demangled string to the empty string to indicate we tried to
+ // parse it once and failed.
+ m_demangled.SetCString("");
+ }
+ }
+
+ return m_demangled;
+}
+
+ConstString
+Mangled::GetDisplayDemangledName(lldb::LanguageType language) const {
+ return GetDemangledName(language);
+}
+
+bool Mangled::NameMatches(const RegularExpression &regex,
+ lldb::LanguageType language) const {
+ if (m_mangled && regex.Execute(m_mangled.AsCString()))
+ return true;
+
+ ConstString demangled = GetDemangledName(language);
+ return demangled && regex.Execute(demangled.AsCString());
+}
+
+// Get the demangled name if there is one, else return the mangled name.
+ConstString Mangled::GetName(lldb::LanguageType language,
+ Mangled::NamePreference preference) const {
+ if (preference == ePreferMangled && m_mangled)
+ return m_mangled;
+
+ ConstString demangled = GetDemangledName(language);
+
+ if (preference == ePreferDemangledWithoutArguments) {
+ return get_demangled_name_without_arguments(m_mangled, demangled);
+ }
+ if (preference == ePreferDemangled) {
+ // Call the accessor to make sure we get a demangled name in case it hasn't
+ // been demangled yet...
+ if (demangled)
+ return demangled;
+ return m_mangled;
+ }
+ return demangled;
+}
+
+// Dump a Mangled object to stream "s". We don't force our demangled name to be
+// computed currently (we don't use the accessor).
+void Mangled::Dump(Stream *s) const {
+ if (m_mangled) {
+ *s << ", mangled = " << m_mangled;
+ }
+ if (m_demangled) {
+ const char *demangled = m_demangled.AsCString();
+ s->Printf(", demangled = %s", demangled[0] ? demangled : "<error>");
+ }
+}
+
+// Dumps a debug version of this string with extra object and state information
+// to stream "s".
+void Mangled::DumpDebug(Stream *s) const {
+ s->Printf("%*p: Mangled mangled = ", static_cast<int>(sizeof(void *) * 2),
+ static_cast<const void *>(this));
+ m_mangled.DumpDebug(s);
+ s->Printf(", demangled = ");
+ m_demangled.DumpDebug(s);
+}
+
+// Return the size in byte that this object takes in memory. The size includes
+// the size of the objects it owns, and not the strings that it references
+// because they are shared strings.
+size_t Mangled::MemorySize() const {
+ return m_mangled.MemorySize() + m_demangled.MemorySize();
+}
+
+// We "guess" the language because we can't determine a symbol's language from
+// it's name. For example, a Pascal symbol can be mangled using the C++
+// Itanium scheme, and defined in a compilation unit within the same module as
+// other C++ units. In addition, different targets could have different ways
+// of mangling names from a given language, likewise the compilation units
+// within those targets.
+lldb::LanguageType Mangled::GuessLanguage() const {
+ ConstString mangled = GetMangledName();
+ if (mangled) {
+ const char *mangled_name = mangled.GetCString();
+ if (CPlusPlusLanguage::IsCPPMangledName(mangled_name))
+ return lldb::eLanguageTypeC_plus_plus;
+ else if (ObjCLanguage::IsPossibleObjCMethodName(mangled_name))
+ return lldb::eLanguageTypeObjC;
+ } else {
+ // ObjC names aren't really mangled, so they won't necessarily be in the
+ // mangled name slot.
+ ConstString demangled_name = GetDemangledName(lldb::eLanguageTypeUnknown);
+ if (demangled_name
+ && ObjCLanguage::IsPossibleObjCMethodName(demangled_name.GetCString()))
+ return lldb::eLanguageTypeObjC;
+
+ }
+ return lldb::eLanguageTypeUnknown;
+}
+
+// Dump OBJ to the supplied stream S.
+Stream &operator<<(Stream &s, const Mangled &obj) {
+ if (obj.GetMangledName())
+ s << "mangled = '" << obj.GetMangledName() << "'";
+
+ ConstString demangled =
+ obj.GetDemangledName(lldb::eLanguageTypeUnknown);
+ if (demangled)
+ s << ", demangled = '" << demangled << '\'';
+ else
+ s << ", demangled = <error>";
+ return s;
+}