15ffd83dbSDimitry Andric //===-- RichManglingContext.cpp -------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "lldb/Core/RichManglingContext.h" 100b57cec5SDimitry Andric #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" 1181ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h" 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric using namespace lldb; 160b57cec5SDimitry Andric using namespace lldb_private; 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric // RichManglingContext 19fe6060f1SDimitry Andric RichManglingContext::~RichManglingContext() { 20fe6060f1SDimitry Andric std::free(m_ipd_buf); 21fe6060f1SDimitry Andric ResetCxxMethodParser(); 22fe6060f1SDimitry Andric } 23fe6060f1SDimitry Andric 24fe6060f1SDimitry Andric void RichManglingContext::ResetCxxMethodParser() { 250b57cec5SDimitry Andric // If we want to support parsers for other languages some day, we need a 260b57cec5SDimitry Andric // switch here to delete the correct parser type. 27bdd1243dSDimitry Andric if (m_cxx_method_parser.has_value()) { 280b57cec5SDimitry Andric assert(m_provider == PluginCxxLanguage); 290b57cec5SDimitry Andric delete get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser); 300b57cec5SDimitry Andric m_cxx_method_parser.reset(); 310b57cec5SDimitry Andric } 32fe6060f1SDimitry Andric } 33fe6060f1SDimitry Andric 34fe6060f1SDimitry Andric void RichManglingContext::ResetProvider(InfoProvider new_provider) { 35fe6060f1SDimitry Andric ResetCxxMethodParser(); 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric assert(new_provider != None && "Only reset to a valid provider"); 380b57cec5SDimitry Andric m_provider = new_provider; 390b57cec5SDimitry Andric } 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric bool RichManglingContext::FromItaniumName(ConstString mangled) { 420b57cec5SDimitry Andric bool err = m_ipd.partialDemangle(mangled.GetCString()); 430b57cec5SDimitry Andric if (!err) { 440b57cec5SDimitry Andric ResetProvider(ItaniumPartialDemangler); 450b57cec5SDimitry Andric } 460b57cec5SDimitry Andric 4781ad6265SDimitry Andric if (Log *log = GetLog(LLDBLog::Demangle)) { 480b57cec5SDimitry Andric if (!err) { 490b57cec5SDimitry Andric ParseFullName(); 500b57cec5SDimitry Andric LLDB_LOG(log, "demangled itanium: {0} -> \"{1}\"", mangled, m_ipd_buf); 510b57cec5SDimitry Andric } else { 520b57cec5SDimitry Andric LLDB_LOG(log, "demangled itanium: {0} -> error: failed to demangle", 530b57cec5SDimitry Andric mangled); 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric } 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric return !err; // true == success 580b57cec5SDimitry Andric } 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric bool RichManglingContext::FromCxxMethodName(ConstString demangled) { 610b57cec5SDimitry Andric ResetProvider(PluginCxxLanguage); 620b57cec5SDimitry Andric m_cxx_method_parser = new CPlusPlusLanguage::MethodName(demangled); 630b57cec5SDimitry Andric return true; 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric bool RichManglingContext::IsCtorOrDtor() const { 670b57cec5SDimitry Andric assert(m_provider != None && "Initialize a provider first"); 680b57cec5SDimitry Andric switch (m_provider) { 690b57cec5SDimitry Andric case ItaniumPartialDemangler: 700b57cec5SDimitry Andric return m_ipd.isCtorOrDtor(); 710b57cec5SDimitry Andric case PluginCxxLanguage: { 720b57cec5SDimitry Andric // We can only check for destructors here. 730b57cec5SDimitry Andric auto base_name = 740b57cec5SDimitry Andric get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename(); 75*5f757f3fSDimitry Andric return base_name.starts_with("~"); 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric case None: 780b57cec5SDimitry Andric return false; 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric llvm_unreachable("Fully covered switch above!"); 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric 83d56accc7SDimitry Andric llvm::StringRef RichManglingContext::processIPDStrResult(char *ipd_res, 84d56accc7SDimitry Andric size_t res_size) { 850b57cec5SDimitry Andric // Error case: Clear the buffer. 860b57cec5SDimitry Andric if (LLVM_UNLIKELY(ipd_res == nullptr)) { 870b57cec5SDimitry Andric assert(res_size == m_ipd_buf_size && 880b57cec5SDimitry Andric "Failed IPD queries keep the original size in the N parameter"); 890b57cec5SDimitry Andric 900b57cec5SDimitry Andric m_ipd_buf[0] = '\0'; 91d56accc7SDimitry Andric return llvm::StringRef(m_ipd_buf, 0); 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric // IPD's res_size includes null terminator. 950b57cec5SDimitry Andric assert(ipd_res[res_size - 1] == '\0' && 960b57cec5SDimitry Andric "IPD returns null-terminated strings and we rely on that"); 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric // Update buffer/size on realloc. 990b57cec5SDimitry Andric if (LLVM_UNLIKELY(ipd_res != m_ipd_buf || res_size > m_ipd_buf_size)) { 1000b57cec5SDimitry Andric m_ipd_buf = ipd_res; // std::realloc freed or reused the old buffer. 1010b57cec5SDimitry Andric m_ipd_buf_size = res_size; // May actually be bigger, but we can't know. 1020b57cec5SDimitry Andric 10381ad6265SDimitry Andric if (Log *log = GetLog(LLDBLog::Demangle)) 1040b57cec5SDimitry Andric LLDB_LOG(log, "ItaniumPartialDemangler Realloc: new buffer size is {0}", 1050b57cec5SDimitry Andric m_ipd_buf_size); 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric // 99% case: Just remember the string length. 109d56accc7SDimitry Andric return llvm::StringRef(m_ipd_buf, res_size - 1); 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric 112d56accc7SDimitry Andric llvm::StringRef RichManglingContext::ParseFunctionBaseName() { 1130b57cec5SDimitry Andric assert(m_provider != None && "Initialize a provider first"); 1140b57cec5SDimitry Andric switch (m_provider) { 1150b57cec5SDimitry Andric case ItaniumPartialDemangler: { 1160b57cec5SDimitry Andric auto n = m_ipd_buf_size; 1170b57cec5SDimitry Andric auto buf = m_ipd.getFunctionBaseName(m_ipd_buf, &n); 118d56accc7SDimitry Andric return processIPDStrResult(buf, n); 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric case PluginCxxLanguage: 121d56accc7SDimitry Andric return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser) 122d56accc7SDimitry Andric ->GetBasename(); 1230b57cec5SDimitry Andric case None: 124d56accc7SDimitry Andric return {}; 1250b57cec5SDimitry Andric } 12681ad6265SDimitry Andric llvm_unreachable("Fully covered switch above!"); 1270b57cec5SDimitry Andric } 1280b57cec5SDimitry Andric 129d56accc7SDimitry Andric llvm::StringRef RichManglingContext::ParseFunctionDeclContextName() { 1300b57cec5SDimitry Andric assert(m_provider != None && "Initialize a provider first"); 1310b57cec5SDimitry Andric switch (m_provider) { 1320b57cec5SDimitry Andric case ItaniumPartialDemangler: { 1330b57cec5SDimitry Andric auto n = m_ipd_buf_size; 1340b57cec5SDimitry Andric auto buf = m_ipd.getFunctionDeclContextName(m_ipd_buf, &n); 135d56accc7SDimitry Andric return processIPDStrResult(buf, n); 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric case PluginCxxLanguage: 138d56accc7SDimitry Andric return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser) 139d56accc7SDimitry Andric ->GetContext(); 1400b57cec5SDimitry Andric case None: 141d56accc7SDimitry Andric return {}; 1420b57cec5SDimitry Andric } 14381ad6265SDimitry Andric llvm_unreachable("Fully covered switch above!"); 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric 146d56accc7SDimitry Andric llvm::StringRef RichManglingContext::ParseFullName() { 1470b57cec5SDimitry Andric assert(m_provider != None && "Initialize a provider first"); 1480b57cec5SDimitry Andric switch (m_provider) { 1490b57cec5SDimitry Andric case ItaniumPartialDemangler: { 1500b57cec5SDimitry Andric auto n = m_ipd_buf_size; 1510b57cec5SDimitry Andric auto buf = m_ipd.finishDemangle(m_ipd_buf, &n); 152d56accc7SDimitry Andric return processIPDStrResult(buf, n); 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric case PluginCxxLanguage: 155d56accc7SDimitry Andric return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser) 1560b57cec5SDimitry Andric ->GetFullName() 1570b57cec5SDimitry Andric .GetStringRef(); 1580b57cec5SDimitry Andric case None: 159d56accc7SDimitry Andric return {}; 1600b57cec5SDimitry Andric } 16181ad6265SDimitry Andric llvm_unreachable("Fully covered switch above!"); 1620b57cec5SDimitry Andric } 163