xref: /freebsd/contrib/llvm-project/lldb/source/Core/RichManglingContext.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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