brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.4 KiB · f7683c5 Raw
574 lines · cpp
1//===-- Mangled.cpp -------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Core/Mangled.h"10 11#include "lldb/Core/DataFileCache.h"12#include "lldb/Core/DemangledNameInfo.h"13#include "lldb/Core/RichManglingContext.h"14#include "lldb/Target/Language.h"15#include "lldb/Utility/ConstString.h"16#include "lldb/Utility/DataEncoder.h"17#include "lldb/Utility/LLDBLog.h"18#include "lldb/Utility/Log.h"19#include "lldb/Utility/RegularExpression.h"20#include "lldb/Utility/Stream.h"21#include "lldb/lldb-enumerations.h"22 23#include "llvm/ADT/StringExtras.h"24#include "llvm/ADT/StringRef.h"25#include "llvm/Demangle/Demangle.h"26#include "llvm/Support/Compiler.h"27 28#include <mutex>29#include <string>30#include <string_view>31#include <utility>32 33#include <cstdlib>34#include <cstring>35using namespace lldb_private;36 37#pragma mark Mangled38 39bool Mangled::IsMangledName(llvm::StringRef name) {40  return Mangled::GetManglingScheme(name) != Mangled::eManglingSchemeNone;41}42 43Mangled::ManglingScheme Mangled::GetManglingScheme(llvm::StringRef name) {44  if (name.empty())45    return Mangled::eManglingSchemeNone;46 47  if (name.starts_with("?"))48    return Mangled::eManglingSchemeMSVC;49 50  if (name.starts_with("_R"))51    return Mangled::eManglingSchemeRustV0;52 53  if (name.starts_with("_D")) {54    // A dlang mangled name begins with `_D`, followed by a numeric length. One55    // known exception is the symbol `_Dmain`.56    // See `SymbolName` and `LName` in57    // https://dlang.org/spec/abi.html#name_mangling58    llvm::StringRef buf = name.drop_front(2);59    if (!buf.empty() && (llvm::isDigit(buf.front()) || name == "_Dmain"))60      return Mangled::eManglingSchemeD;61  }62 63  if (name.starts_with("_Z"))64    return Mangled::eManglingSchemeItanium;65 66  // ___Z is a clang extension of block invocations67  if (name.starts_with("___Z"))68    return Mangled::eManglingSchemeItanium;69 70  // Swift's older style of mangling used "_T" as a mangling prefix. This can71  // lead to false positives with other symbols that just so happen to start72  // with "_T". To minimize the chance of that happening, we only return true73  // for select old-style swift mangled names. The known cases are ObjC classes74  // and protocols. Classes are either prefixed with "_TtC" or "_TtGC".75  // Protocols are prefixed with "_TtP".76  if (name.starts_with("_TtC") || name.starts_with("_TtGC") ||77      name.starts_with("_TtP"))78    return Mangled::eManglingSchemeSwift;79 80  // Swift 4.2 used "$S" and "_$S".81  // Swift 5 and onward uses "$s" and "_$s".82  // Swift also uses "@__swiftmacro_" as a prefix for mangling filenames.83  // Embedded Swift introduced "$e" and  "_$e" as Swift mangling prefixes.84  if (name.starts_with("$S") || name.starts_with("_$S") ||85      name.starts_with("$s") || name.starts_with("_$s") ||86      name.starts_with("$e") || name.starts_with("_$e") ||87      name.starts_with("@__swiftmacro_"))88    return Mangled::eManglingSchemeSwift;89 90  return Mangled::eManglingSchemeNone;91}92 93Mangled::Mangled(ConstString s) : m_mangled(), m_demangled() {94  if (s)95    SetValue(s);96}97 98Mangled::Mangled(llvm::StringRef name) {99  if (!name.empty())100    SetValue(ConstString(name));101}102 103// Convert to bool operator. This allows code to check any Mangled objects104// to see if they contain anything valid using code such as:105//106//  Mangled mangled(...);107//  if (mangled)108//  { ...109Mangled::operator bool() const { return m_mangled || m_demangled; }110 111// Clear the mangled and demangled values.112void Mangled::Clear() {113  m_mangled.Clear();114  m_demangled.Clear();115  m_demangled_info.reset();116}117 118// Compare the string values.119int Mangled::Compare(const Mangled &a, const Mangled &b) {120  return ConstString::Compare(a.GetName(ePreferMangled),121                              b.GetName(ePreferMangled));122}123 124void Mangled::SetValue(ConstString name) {125  if (name) {126    if (IsMangledName(name.GetStringRef())) {127      m_demangled.Clear();128      m_mangled = name;129      m_demangled_info.reset();130    } else {131      m_demangled = name;132      m_mangled.Clear();133      m_demangled_info.reset();134    }135  } else {136    m_demangled.Clear();137    m_mangled.Clear();138    m_demangled_info.reset();139  }140}141 142// Local helpers for different demangling implementations.143static char *GetMSVCDemangledStr(llvm::StringRef M) {144  char *demangled_cstr = llvm::microsoftDemangle(145      M, nullptr, nullptr,146      llvm::MSDemangleFlags(147          llvm::MSDF_NoAccessSpecifier | llvm::MSDF_NoCallingConvention |148          llvm::MSDF_NoMemberType | llvm::MSDF_NoVariableType));149 150  if (Log *log = GetLog(LLDBLog::Demangle)) {151    if (demangled_cstr && demangled_cstr[0])152      LLDB_LOGF(log, "demangled msvc: %s -> \"%s\"", M.data(), demangled_cstr);153    else154      LLDB_LOGF(log, "demangled msvc: %s -> error", M.data());155  }156 157  return demangled_cstr;158}159 160static std::pair<char *, DemangledNameInfo>161GetItaniumDemangledStr(const char *M) {162  char *demangled_cstr = nullptr;163 164  DemangledNameInfo info;165  llvm::ItaniumPartialDemangler ipd;166  bool err = ipd.partialDemangle(M);167  if (!err) {168    // Default buffer and size (OutputBuffer will realloc in case it's too169    // small).170    size_t demangled_size = 80;171    demangled_cstr = static_cast<char *>(std::malloc(80));172 173    TrackingOutputBuffer OB(demangled_cstr, demangled_size);174    demangled_cstr = ipd.finishDemangle(&OB);175    info = std::move(OB.NameInfo);176 177    assert(demangled_cstr &&178           "finishDemangle must always succeed if partialDemangle did");179    assert(demangled_cstr[OB.getCurrentPosition() - 1] == '\0' &&180           "Expected demangled_size to return length including trailing null");181  }182 183  if (Log *log = GetLog(LLDBLog::Demangle)) {184    if (demangled_cstr)185      LLDB_LOGF(log, "demangled itanium: %s -> \"%s\"", M, demangled_cstr);186    else187      LLDB_LOGF(log, "demangled itanium: %s -> error: failed to demangle", M);188 189    if (!info.hasBasename())190      LLDB_LOGF(log,191                "demangled itanium: %s -> error: failed to retrieve name info",192                M);193  }194 195  return {demangled_cstr, std::move(info)};196}197 198static char *GetRustV0DemangledStr(llvm::StringRef M) {199  char *demangled_cstr = llvm::rustDemangle(M);200 201  if (Log *log = GetLog(LLDBLog::Demangle)) {202    if (demangled_cstr && demangled_cstr[0])203      LLDB_LOG(log, "demangled rustv0: {0} -> \"{1}\"", M, demangled_cstr);204    else205      LLDB_LOG(log, "demangled rustv0: {0} -> error: failed to demangle",206               static_cast<std::string_view>(M));207  }208 209  return demangled_cstr;210}211 212static char *GetDLangDemangledStr(llvm::StringRef M) {213  char *demangled_cstr = llvm::dlangDemangle(M);214 215  if (Log *log = GetLog(LLDBLog::Demangle)) {216    if (demangled_cstr && demangled_cstr[0])217      LLDB_LOG(log, "demangled dlang: {0} -> \"{1}\"", M, demangled_cstr);218    else219      LLDB_LOG(log, "demangled dlang: {0} -> error: failed to demangle",220               static_cast<std::string_view>(M));221  }222 223  return demangled_cstr;224}225 226// Explicit demangling for scheduled requests during batch processing. This227// makes use of ItaniumPartialDemangler's rich demangle info228bool Mangled::GetRichManglingInfo(RichManglingContext &context,229                                  SkipMangledNameFn *skip_mangled_name) {230  // Others are not meant to arrive here. ObjC names or C's main() for example231  // have their names stored in m_demangled, while m_mangled is empty.232  assert(m_mangled);233 234  // Check whether or not we are interested in this name at all.235  ManglingScheme scheme = GetManglingScheme(m_mangled.GetStringRef());236  if (skip_mangled_name && skip_mangled_name(m_mangled.GetStringRef(), scheme))237    return false;238 239  switch (scheme) {240  case eManglingSchemeNone:241    // The current mangled_name_filter would allow llvm_unreachable here.242    return false;243 244  case eManglingSchemeItanium:245    // We want the rich mangling info here, so we don't care whether or not246    // there is a demangled string in the pool already.247    return context.FromItaniumName(m_mangled);248 249  case eManglingSchemeMSVC: {250    // We have no rich mangling for MSVC-mangled names yet, so first try to251    // demangle it if necessary.252    if (!m_demangled && !m_mangled.GetMangledCounterpart(m_demangled)) {253      if (char *d = GetMSVCDemangledStr(m_mangled)) {254        // Without the rich mangling info we have to demangle the full name.255        // Copy it to string pool and connect the counterparts to accelerate256        // later access in GetDemangledName().257        m_demangled.SetStringWithMangledCounterpart(llvm::StringRef(d),258                                                    m_mangled);259        ::free(d);260      } else {261        m_demangled.SetCString("");262      }263    }264 265    if (m_demangled.IsEmpty()) {266      // Cannot demangle it, so don't try parsing.267      return false;268    } else {269      // Demangled successfully, we can try and parse it with270      // CPlusPlusLanguage::CxxMethodName.271      return context.FromCxxMethodName(m_demangled);272    }273  }274 275  case eManglingSchemeRustV0:276  case eManglingSchemeD:277  case eManglingSchemeSwift:278    // Rich demangling scheme is not supported279    return false;280  }281  llvm_unreachable("Fully covered switch above!");282}283 284ConstString Mangled::GetDemangledName() const {285  return GetDemangledNameImpl(/*force=*/false);286}287 288std::optional<DemangledNameInfo> const &Mangled::GetDemangledInfo() const {289  if (!m_demangled_info)290    GetDemangledNameImpl(/*force=*/true);291 292  return m_demangled_info;293}294 295// Generate the demangled name on demand using this accessor. Code in this296// class will need to use this accessor if it wishes to decode the demangled297// name. The result is cached and will be kept until a new string value is298// supplied to this object, or until the end of the object's lifetime.299ConstString Mangled::GetDemangledNameImpl(bool force) const {300  if (!m_mangled)301    return m_demangled;302 303  // Re-use previously demangled names.304  if (!force && !m_demangled.IsNull())305    return m_demangled;306 307  if (!force && m_mangled.GetMangledCounterpart(m_demangled) &&308      !m_demangled.IsNull())309    return m_demangled;310 311  // We didn't already mangle this name, demangle it and if all goes well312  // add it to our map.313  char *demangled_name = nullptr;314  switch (GetManglingScheme(m_mangled.GetStringRef())) {315  case eManglingSchemeMSVC:316    demangled_name = GetMSVCDemangledStr(m_mangled);317    break;318  case eManglingSchemeItanium: {319    std::pair<char *, DemangledNameInfo> demangled =320        GetItaniumDemangledStr(m_mangled.GetCString());321    demangled_name = demangled.first;322    m_demangled_info.emplace(std::move(demangled.second));323    break;324  }325  case eManglingSchemeRustV0:326    demangled_name = GetRustV0DemangledStr(m_mangled);327    break;328  case eManglingSchemeD:329    demangled_name = GetDLangDemangledStr(m_mangled);330    break;331  case eManglingSchemeSwift:332    // Demangling a swift name requires the swift compiler. This is333    // explicitly unsupported on llvm.org.334    break;335  case eManglingSchemeNone:336    // Don't bother demangling anything that isn't mangled.337    break;338  }339 340  if (demangled_name) {341    m_demangled.SetStringWithMangledCounterpart(demangled_name, m_mangled);342    free(demangled_name);343  }344 345  if (m_demangled.IsNull()) {346    // Set the demangled string to the empty string to indicate we tried to347    // parse it once and failed.348    m_demangled.SetCString("");349  }350 351  return m_demangled;352}353 354ConstString Mangled::GetDisplayDemangledName() const {355  if (Language *lang = Language::FindPlugin(GuessLanguage()))356    return lang->GetDisplayDemangledName(*this);357  return GetDemangledName();358}359 360bool Mangled::NameMatches(const RegularExpression &regex) const {361  if (m_mangled && regex.Execute(m_mangled.GetStringRef()))362    return true;363 364  ConstString demangled = GetDemangledName();365  return demangled && regex.Execute(demangled.GetStringRef());366}367 368// Get the demangled name if there is one, else return the mangled name.369ConstString Mangled::GetName(Mangled::NamePreference preference) const {370  if (preference == ePreferMangled && m_mangled)371    return m_mangled;372 373  // Call the accessor to make sure we get a demangled name in case it hasn't374  // been demangled yet...375  ConstString demangled = GetDemangledName();376 377  if (preference == ePreferDemangledWithoutArguments) {378    if (Language *lang = Language::FindPlugin(GuessLanguage())) {379      return lang->GetDemangledFunctionNameWithoutArguments(*this);380    }381  }382  if (preference == ePreferDemangled) {383    if (demangled)384      return demangled;385    return m_mangled;386  }387  return demangled;388}389 390// Dump a Mangled object to stream "s". We don't force our demangled name to be391// computed currently (we don't use the accessor).392void Mangled::Dump(Stream *s) const {393  if (m_mangled) {394    *s << ", mangled = " << m_mangled;395  }396  if (m_demangled) {397    const char *demangled = m_demangled.AsCString();398    s->Printf(", demangled = %s", demangled[0] ? demangled : "<error>");399  }400}401 402// Dumps a debug version of this string with extra object and state information403// to stream "s".404void Mangled::DumpDebug(Stream *s) const {405  s->Printf("%*p: Mangled mangled = ", static_cast<int>(sizeof(void *) * 2),406            static_cast<const void *>(this));407  m_mangled.DumpDebug(s);408  s->Printf(", demangled = ");409  m_demangled.DumpDebug(s);410}411 412// Return the size in byte that this object takes in memory. The size includes413// the size of the objects it owns, and not the strings that it references414// because they are shared strings.415size_t Mangled::MemorySize() const {416  return m_mangled.MemorySize() + m_demangled.MemorySize();417}418 419// We "guess" the language because we can't determine a symbol's language from420// it's name.  For example, a Pascal symbol can be mangled using the C++421// Itanium scheme, and defined in a compilation unit within the same module as422// other C++ units.  In addition, different targets could have different ways423// of mangling names from a given language, likewise the compilation units424// within those targets.425lldb::LanguageType Mangled::GuessLanguage() const {426  lldb::LanguageType result = lldb::eLanguageTypeUnknown;427  // Ask each language plugin to check if the mangled name belongs to it.428  Language::ForEach([this, &result](Language *l) {429    if (l->SymbolNameFitsToLanguage(*this)) {430      result = l->GetLanguageType();431      return IterationAction::Stop;432    }433    return IterationAction::Continue;434  });435  return result;436}437 438// Dump OBJ to the supplied stream S.439Stream &operator<<(Stream &s, const Mangled &obj) {440  if (obj.GetMangledName())441    s << "mangled = '" << obj.GetMangledName() << "'";442 443  ConstString demangled = obj.GetDemangledName();444  if (demangled)445    s << ", demangled = '" << demangled << '\'';446  else447    s << ", demangled = <error>";448  return s;449}450 451// When encoding Mangled objects we can get away with encoding as little452// information as is required. The enumeration below helps us to efficiently453// encode Mangled objects.454enum MangledEncoding {455  /// If the Mangled object has neither a mangled name or demangled name we can456  /// encode the object with one zero byte using the Empty enumeration.457  Empty = 0u,458  /// If the Mangled object has only a demangled name and no mangled named, we459  /// can encode only the demangled name.460  DemangledOnly = 1u,461  /// If the mangle name can calculate the demangled name (it is the462  /// mangled/demangled counterpart), then we only need to encode the mangled463  /// name as the demangled name can be recomputed.464  MangledOnly = 2u,465  /// If we have a Mangled object with two different names that are not related466  /// then we need to save both strings. This can happen if we have a name that467  /// isn't a true mangled name, but we want to be able to lookup a symbol by468  /// name and type in the symbol table. We do this for Objective C symbols like469  /// "OBJC_CLASS_$_NSValue" where the mangled named will be set to470  /// "OBJC_CLASS_$_NSValue" and the demangled name will be manually set to471  /// "NSValue". If we tried to demangled the name "OBJC_CLASS_$_NSValue" it472  /// would fail, but in these cases we want these unrelated names to be473  /// preserved.474  MangledAndDemangled = 3u475};476 477bool Mangled::Decode(const DataExtractor &data, lldb::offset_t *offset_ptr,478                     const StringTableReader &strtab) {479  m_mangled.Clear();480  m_demangled.Clear();481  m_demangled_info.reset();482  MangledEncoding encoding = (MangledEncoding)data.GetU8(offset_ptr);483  switch (encoding) {484    case Empty:485      return true;486 487    case DemangledOnly:488      m_demangled.SetString(strtab.Get(data.GetU32(offset_ptr)));489      return true;490 491    case MangledOnly:492      m_mangled.SetString(strtab.Get(data.GetU32(offset_ptr)));493      return true;494 495    case MangledAndDemangled:496      m_mangled.SetString(strtab.Get(data.GetU32(offset_ptr)));497      m_demangled.SetString(strtab.Get(data.GetU32(offset_ptr)));498      return true;499  }500  return false;501}502/// The encoding format for the Mangled object is as follows:503///504/// uint8_t encoding;505/// char str1[]; (only if DemangledOnly, MangledOnly)506/// char str2[]; (only if MangledAndDemangled)507///508/// The strings are stored as NULL terminated UTF8 strings and str1 and str2509/// are only saved if we need them based on the encoding.510///511/// Some mangled names have a mangled name that can be demangled by the built512/// in demanglers. These kinds of mangled objects know when the mangled and513/// demangled names are the counterparts for each other. This is done because514/// demangling is very expensive and avoiding demangling the same name twice515/// saves us a lot of compute time. For these kinds of names we only need to516/// save the mangled name and have the encoding set to "MangledOnly".517///518/// If a mangled obejct has only a demangled name, then we save only that string519/// and have the encoding set to "DemangledOnly".520///521/// Some mangled objects have both mangled and demangled names, but the522/// demangled name can not be computed from the mangled name. This is often used523/// for runtime named, like Objective C runtime V2 and V3 names. Both these524/// names must be saved and the encoding is set to "MangledAndDemangled".525///526/// For a Mangled object with no names, we only need to set the encoding to527/// "Empty" and not store any string values.528void Mangled::Encode(DataEncoder &file, ConstStringTable &strtab) const {529  MangledEncoding encoding = Empty;530  if (m_mangled) {531    encoding = MangledOnly;532    if (m_demangled) {533      // We have both mangled and demangled names. If the demangled name is the534      // counterpart of the mangled name, then we only need to save the mangled535      // named. If they are different, we need to save both.536      ConstString s;537      if (!(m_mangled.GetMangledCounterpart(s) && s == m_demangled))538        encoding = MangledAndDemangled;539    }540  } else if (m_demangled) {541    encoding = DemangledOnly;542  }543  file.AppendU8(encoding);544  switch (encoding) {545    case Empty:546      break;547    case DemangledOnly:548      file.AppendU32(strtab.Add(m_demangled));549      break;550    case MangledOnly:551      file.AppendU32(strtab.Add(m_mangled));552      break;553    case MangledAndDemangled:554      file.AppendU32(strtab.Add(m_mangled));555      file.AppendU32(strtab.Add(m_demangled));556      break;557  }558}559 560ConstString Mangled::GetBaseName() const {561  const auto &demangled_info = GetDemangledInfo();562  if (!demangled_info.has_value())563    return {};564 565  ConstString demangled_name = GetDemangledName();566  if (!demangled_name)567    return {};568 569  const char *name_str = demangled_name.AsCString();570  const auto &range = demangled_info->BasenameRange;571  return ConstString(572      llvm::StringRef(name_str + range.first, range.second - range.first));573}574