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