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