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