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 bool RichManglingContext::IsFunction() const { 87 assert(m_provider != None && "Initialize a provider first"); 88 switch (m_provider) { 89 case ItaniumPartialDemangler: 90 return m_ipd.isFunction(); 91 case PluginCxxLanguage: 92 return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->IsValid(); 93 case None: 94 return false; 95 } 96 llvm_unreachable("Fully covered switch above!"); 97 } 98 99 void RichManglingContext::processIPDStrResult(char *ipd_res, size_t res_size) { 100 // Error case: Clear the buffer. 101 if (LLVM_UNLIKELY(ipd_res == nullptr)) { 102 assert(res_size == m_ipd_buf_size && 103 "Failed IPD queries keep the original size in the N parameter"); 104 105 m_ipd_buf[0] = '\0'; 106 m_buffer = llvm::StringRef(m_ipd_buf, 0); 107 return; 108 } 109 110 // IPD's res_size includes null terminator. 111 assert(ipd_res[res_size - 1] == '\0' && 112 "IPD returns null-terminated strings and we rely on that"); 113 114 // Update buffer/size on realloc. 115 if (LLVM_UNLIKELY(ipd_res != m_ipd_buf || res_size > m_ipd_buf_size)) { 116 m_ipd_buf = ipd_res; // std::realloc freed or reused the old buffer. 117 m_ipd_buf_size = res_size; // May actually be bigger, but we can't know. 118 119 if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) 120 LLDB_LOG(log, "ItaniumPartialDemangler Realloc: new buffer size is {0}", 121 m_ipd_buf_size); 122 } 123 124 // 99% case: Just remember the string length. 125 m_buffer = llvm::StringRef(m_ipd_buf, res_size - 1); 126 } 127 128 void RichManglingContext::ParseFunctionBaseName() { 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.getFunctionBaseName(m_ipd_buf, &n); 134 processIPDStrResult(buf, n); 135 return; 136 } 137 case PluginCxxLanguage: 138 m_buffer = 139 get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename(); 140 return; 141 case None: 142 return; 143 } 144 } 145 146 void RichManglingContext::ParseFunctionDeclContextName() { 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.getFunctionDeclContextName(m_ipd_buf, &n); 152 processIPDStrResult(buf, n); 153 return; 154 } 155 case PluginCxxLanguage: 156 m_buffer = 157 get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetContext(); 158 return; 159 case None: 160 return; 161 } 162 } 163 164 void RichManglingContext::ParseFullName() { 165 assert(m_provider != None && "Initialize a provider first"); 166 switch (m_provider) { 167 case ItaniumPartialDemangler: { 168 auto n = m_ipd_buf_size; 169 auto buf = m_ipd.finishDemangle(m_ipd_buf, &n); 170 processIPDStrResult(buf, n); 171 return; 172 } 173 case PluginCxxLanguage: 174 m_buffer = get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser) 175 ->GetFullName() 176 .GetStringRef(); 177 return; 178 case None: 179 return; 180 } 181 } 182