1 //===-- RichManglingContext.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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Core/RichManglingContext.h" 10 #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" 11 #include "lldb/Utility/LLDBLog.h" 12 13 #include "llvm/ADT/StringRef.h" 14 15 using namespace lldb; 16 using namespace lldb_private; 17 18 // RichManglingContext 19 RichManglingContext::~RichManglingContext() { 20 std::free(m_ipd_buf); 21 ResetCxxMethodParser(); 22 } 23 24 void RichManglingContext::ResetCxxMethodParser() { 25 // If we want to support parsers for other languages some day, we need a 26 // switch here to delete the correct parser type. 27 if (m_cxx_method_parser.hasValue()) { 28 assert(m_provider == PluginCxxLanguage); 29 delete get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser); 30 m_cxx_method_parser.reset(); 31 } 32 } 33 34 void RichManglingContext::ResetProvider(InfoProvider new_provider) { 35 ResetCxxMethodParser(); 36 37 assert(new_provider != None && "Only reset to a valid provider"); 38 m_provider = new_provider; 39 } 40 41 bool RichManglingContext::FromItaniumName(ConstString mangled) { 42 bool err = m_ipd.partialDemangle(mangled.GetCString()); 43 if (!err) { 44 ResetProvider(ItaniumPartialDemangler); 45 } 46 47 if (Log *log = GetLog(LLDBLog::Demangle)) { 48 if (!err) { 49 ParseFullName(); 50 LLDB_LOG(log, "demangled itanium: {0} -> \"{1}\"", mangled, m_ipd_buf); 51 } else { 52 LLDB_LOG(log, "demangled itanium: {0} -> error: failed to demangle", 53 mangled); 54 } 55 } 56 57 return !err; // true == success 58 } 59 60 bool RichManglingContext::FromCxxMethodName(ConstString demangled) { 61 ResetProvider(PluginCxxLanguage); 62 m_cxx_method_parser = new CPlusPlusLanguage::MethodName(demangled); 63 return true; 64 } 65 66 bool RichManglingContext::IsCtorOrDtor() const { 67 assert(m_provider != None && "Initialize a provider first"); 68 switch (m_provider) { 69 case ItaniumPartialDemangler: 70 return m_ipd.isCtorOrDtor(); 71 case PluginCxxLanguage: { 72 // We can only check for destructors here. 73 auto base_name = 74 get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename(); 75 return base_name.startswith("~"); 76 } 77 case None: 78 return false; 79 } 80 llvm_unreachable("Fully covered switch above!"); 81 } 82 83 llvm::StringRef RichManglingContext::processIPDStrResult(char *ipd_res, 84 size_t res_size) { 85 // Error case: Clear the buffer. 86 if (LLVM_UNLIKELY(ipd_res == nullptr)) { 87 assert(res_size == m_ipd_buf_size && 88 "Failed IPD queries keep the original size in the N parameter"); 89 90 m_ipd_buf[0] = '\0'; 91 return llvm::StringRef(m_ipd_buf, 0); 92 } 93 94 // IPD's res_size includes null terminator. 95 assert(ipd_res[res_size - 1] == '\0' && 96 "IPD returns null-terminated strings and we rely on that"); 97 98 // Update buffer/size on realloc. 99 if (LLVM_UNLIKELY(ipd_res != m_ipd_buf || res_size > m_ipd_buf_size)) { 100 m_ipd_buf = ipd_res; // std::realloc freed or reused the old buffer. 101 m_ipd_buf_size = res_size; // May actually be bigger, but we can't know. 102 103 if (Log *log = GetLog(LLDBLog::Demangle)) 104 LLDB_LOG(log, "ItaniumPartialDemangler Realloc: new buffer size is {0}", 105 m_ipd_buf_size); 106 } 107 108 // 99% case: Just remember the string length. 109 return llvm::StringRef(m_ipd_buf, res_size - 1); 110 } 111 112 llvm::StringRef RichManglingContext::ParseFunctionBaseName() { 113 assert(m_provider != None && "Initialize a provider first"); 114 switch (m_provider) { 115 case ItaniumPartialDemangler: { 116 auto n = m_ipd_buf_size; 117 auto buf = m_ipd.getFunctionBaseName(m_ipd_buf, &n); 118 return processIPDStrResult(buf, n); 119 } 120 case PluginCxxLanguage: 121 return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser) 122 ->GetBasename(); 123 case None: 124 return {}; 125 } 126 } 127 128 llvm::StringRef RichManglingContext::ParseFunctionDeclContextName() { 129 assert(m_provider != None && "Initialize a provider first"); 130 switch (m_provider) { 131 case ItaniumPartialDemangler: { 132 auto n = m_ipd_buf_size; 133 auto buf = m_ipd.getFunctionDeclContextName(m_ipd_buf, &n); 134 return processIPDStrResult(buf, n); 135 } 136 case PluginCxxLanguage: 137 return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser) 138 ->GetContext(); 139 case None: 140 return {}; 141 } 142 } 143 144 llvm::StringRef RichManglingContext::ParseFullName() { 145 assert(m_provider != None && "Initialize a provider first"); 146 switch (m_provider) { 147 case ItaniumPartialDemangler: { 148 auto n = m_ipd_buf_size; 149 auto buf = m_ipd.finishDemangle(m_ipd_buf, &n); 150 return processIPDStrResult(buf, n); 151 } 152 case PluginCxxLanguage: 153 return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser) 154 ->GetFullName() 155 .GetStringRef(); 156 case None: 157 return {}; 158 } 159 } 160