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