xref: /freebsd/contrib/llvm-project/lldb/source/Core/RichManglingContext.cpp (revision 924226fba12cc9a228c73b956e1b7fa24c60b055)
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 llvm::StringRef RichManglingContext::processIPDStrResult(char *ipd_res,
87                                                          size_t res_size) {
88   // Error case: Clear the buffer.
89   if (LLVM_UNLIKELY(ipd_res == nullptr)) {
90     assert(res_size == m_ipd_buf_size &&
91            "Failed IPD queries keep the original size in the N parameter");
92 
93     m_ipd_buf[0] = '\0';
94     return llvm::StringRef(m_ipd_buf, 0);
95   }
96 
97   // IPD's res_size includes null terminator.
98   assert(ipd_res[res_size - 1] == '\0' &&
99          "IPD returns null-terminated strings and we rely on that");
100 
101   // Update buffer/size on realloc.
102   if (LLVM_UNLIKELY(ipd_res != m_ipd_buf || res_size > m_ipd_buf_size)) {
103     m_ipd_buf = ipd_res;       // std::realloc freed or reused the old buffer.
104     m_ipd_buf_size = res_size; // May actually be bigger, but we can't know.
105 
106     if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE))
107       LLDB_LOG(log, "ItaniumPartialDemangler Realloc: new buffer size is {0}",
108                m_ipd_buf_size);
109   }
110 
111   // 99% case: Just remember the string length.
112   return llvm::StringRef(m_ipd_buf, res_size - 1);
113 }
114 
115 llvm::StringRef RichManglingContext::ParseFunctionBaseName() {
116   assert(m_provider != None && "Initialize a provider first");
117   switch (m_provider) {
118   case ItaniumPartialDemangler: {
119     auto n = m_ipd_buf_size;
120     auto buf = m_ipd.getFunctionBaseName(m_ipd_buf, &n);
121     return processIPDStrResult(buf, n);
122   }
123   case PluginCxxLanguage:
124     return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
125         ->GetBasename();
126   case None:
127     return {};
128   }
129 }
130 
131 llvm::StringRef RichManglingContext::ParseFunctionDeclContextName() {
132   assert(m_provider != None && "Initialize a provider first");
133   switch (m_provider) {
134   case ItaniumPartialDemangler: {
135     auto n = m_ipd_buf_size;
136     auto buf = m_ipd.getFunctionDeclContextName(m_ipd_buf, &n);
137     return processIPDStrResult(buf, n);
138   }
139   case PluginCxxLanguage:
140     return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
141         ->GetContext();
142   case None:
143     return {};
144   }
145 }
146 
147 llvm::StringRef RichManglingContext::ParseFullName() {
148   assert(m_provider != None && "Initialize a provider first");
149   switch (m_provider) {
150   case ItaniumPartialDemangler: {
151     auto n = m_ipd_buf_size;
152     auto buf = m_ipd.finishDemangle(m_ipd_buf, &n);
153     return processIPDStrResult(buf, n);
154   }
155   case PluginCxxLanguage:
156     return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
157         ->GetFullName()
158         .GetStringRef();
159   case None:
160     return {};
161   }
162 }
163