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 "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
11#include "lldb/Utility/LLDBLog.h"
12
13#include "llvm/ADT/StringRef.h"
14
15using namespace lldb;
16using namespace lldb_private;
17
18// RichManglingContext
19RichManglingContext::~RichManglingContext() {
20 std::free(ptr: m_ipd_buf);
21 ResetCxxMethodParser();
22}
23
24void RichManglingContext::ResetCxxMethodParser() {
25 // If we want to support parsers for other languages some day, we need a
26 // switch here to delete the correct parser type.
27 if (m_cxx_method_parser.has_value()) {
28 assert(m_provider == PluginCxxLanguage);
29 delete get<CPlusPlusLanguage::MethodName>(parser: m_cxx_method_parser);
30 m_cxx_method_parser.reset();
31 }
32}
33
34void RichManglingContext::ResetProvider(InfoProvider new_provider) {
35 ResetCxxMethodParser();
36
37 assert(new_provider != None && "Only reset to a valid provider");
38 m_provider = new_provider;
39}
40
41bool RichManglingContext::FromItaniumName(ConstString mangled) {
42 bool err = m_ipd.partialDemangle(MangledName: mangled.GetCString());
43 if (!err) {
44 ResetProvider(new_provider: ItaniumPartialDemangler);
45 }
46
47 if (Log *log = GetLog(mask: LLDBLog::Demangle)) {
48 if (!err) {
49 ParseFullName();
50 LLDB_LOG(log, "demangled itanium: {0} -> \"{1}\"", mangled, m_ipd_buf);
51 } else {
52 LLDB_LOG(log, "demangled itanium: {0} -> error: failed to demangle",
53 mangled);
54 }
55 }
56
57 return !err; // true == success
58}
59
60bool RichManglingContext::FromCxxMethodName(ConstString demangled) {
61 ResetProvider(new_provider: PluginCxxLanguage);
62 m_cxx_method_parser = new CPlusPlusLanguage::MethodName(demangled);
63 return true;
64}
65
66bool RichManglingContext::IsCtorOrDtor() const {
67 assert(m_provider != None && "Initialize a provider first");
68 switch (m_provider) {
69 case ItaniumPartialDemangler:
70 return m_ipd.isCtorOrDtor();
71 case PluginCxxLanguage: {
72 // We can only check for destructors here.
73 auto base_name =
74 get<CPlusPlusLanguage::MethodName>(parser: m_cxx_method_parser)->GetBasename();
75 return base_name.starts_with(Prefix: "~");
76 }
77 case None:
78 return false;
79 }
80 llvm_unreachable("Fully covered switch above!");
81}
82
83llvm::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(mask: 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
112llvm::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(Buf: m_ipd_buf, N: &n);
118 return processIPDStrResult(ipd_res: buf, res_size: n);
119 }
120 case PluginCxxLanguage:
121 return get<CPlusPlusLanguage::MethodName>(parser: m_cxx_method_parser)
122 ->GetBasename();
123 case None:
124 return {};
125 }
126 llvm_unreachable("Fully covered switch above!");
127}
128
129llvm::StringRef RichManglingContext::ParseFunctionDeclContextName() {
130 assert(m_provider != None && "Initialize a provider first");
131 switch (m_provider) {
132 case ItaniumPartialDemangler: {
133 auto n = m_ipd_buf_size;
134 auto buf = m_ipd.getFunctionDeclContextName(Buf: m_ipd_buf, N: &n);
135 return processIPDStrResult(ipd_res: buf, res_size: n);
136 }
137 case PluginCxxLanguage:
138 return get<CPlusPlusLanguage::MethodName>(parser: m_cxx_method_parser)
139 ->GetContext();
140 case None:
141 return {};
142 }
143 llvm_unreachable("Fully covered switch above!");
144}
145
146llvm::StringRef RichManglingContext::ParseFullName() {
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.finishDemangle(Buf: m_ipd_buf, N: &n);
152 return processIPDStrResult(ipd_res: buf, res_size: n);
153 }
154 case PluginCxxLanguage:
155 return get<CPlusPlusLanguage::MethodName>(parser: m_cxx_method_parser)
156 ->GetFullName()
157 .GetStringRef();
158 case None:
159 return {};
160 }
161 llvm_unreachable("Fully covered switch above!");
162}
163

source code of lldb/source/Core/RichManglingContext.cpp