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