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