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.has_value()) { 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 llvm_unreachable("Fully covered switch above!"); 127 } 128 129 llvm::StringRef RichManglingContext::ParseFunctionDeclContextName() { 130 assert(m_provider != None && "Initialize a provider first"); 131 switch (m_provider) { 132 case ItaniumPartialDemangler: { 133 auto n = m_ipd_buf_size; 134 auto buf = m_ipd.getFunctionDeclContextName(m_ipd_buf, &n); 135 return processIPDStrResult(buf, n); 136 } 137 case PluginCxxLanguage: 138 return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser) 139 ->GetContext(); 140 case None: 141 return {}; 142 } 143 llvm_unreachable("Fully covered switch above!"); 144 } 145 146 llvm::StringRef RichManglingContext::ParseFullName() { 147 assert(m_provider != None && "Initialize a provider first"); 148 switch (m_provider) { 149 case ItaniumPartialDemangler: { 150 auto n = m_ipd_buf_size; 151 auto buf = m_ipd.finishDemangle(m_ipd_buf, &n); 152 return processIPDStrResult(buf, n); 153 } 154 case PluginCxxLanguage: 155 return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser) 156 ->GetFullName() 157 .GetStringRef(); 158 case None: 159 return {}; 160 } 161 llvm_unreachable("Fully covered switch above!"); 162 } 163