1dda28197Spatrick //===-- RichManglingContext.cpp -------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Core/RichManglingContext.h"
10061da546Spatrick #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
11*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
12061da546Spatrick
13061da546Spatrick #include "llvm/ADT/StringRef.h"
14061da546Spatrick
15061da546Spatrick using namespace lldb;
16061da546Spatrick using namespace lldb_private;
17061da546Spatrick
18061da546Spatrick // RichManglingContext
~RichManglingContext()19be691f3bSpatrick RichManglingContext::~RichManglingContext() {
20be691f3bSpatrick std::free(m_ipd_buf);
21be691f3bSpatrick ResetCxxMethodParser();
22be691f3bSpatrick }
23be691f3bSpatrick
ResetCxxMethodParser()24be691f3bSpatrick void RichManglingContext::ResetCxxMethodParser() {
25061da546Spatrick // If we want to support parsers for other languages some day, we need a
26061da546Spatrick // switch here to delete the correct parser type.
27*f6aab3d8Srobert if (m_cxx_method_parser.has_value()) {
28061da546Spatrick assert(m_provider == PluginCxxLanguage);
29061da546Spatrick delete get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser);
30061da546Spatrick m_cxx_method_parser.reset();
31061da546Spatrick }
32be691f3bSpatrick }
33be691f3bSpatrick
ResetProvider(InfoProvider new_provider)34be691f3bSpatrick void RichManglingContext::ResetProvider(InfoProvider new_provider) {
35be691f3bSpatrick ResetCxxMethodParser();
36061da546Spatrick
37061da546Spatrick assert(new_provider != None && "Only reset to a valid provider");
38061da546Spatrick m_provider = new_provider;
39061da546Spatrick }
40061da546Spatrick
FromItaniumName(ConstString mangled)41061da546Spatrick bool RichManglingContext::FromItaniumName(ConstString mangled) {
42061da546Spatrick bool err = m_ipd.partialDemangle(mangled.GetCString());
43061da546Spatrick if (!err) {
44061da546Spatrick ResetProvider(ItaniumPartialDemangler);
45061da546Spatrick }
46061da546Spatrick
47*f6aab3d8Srobert if (Log *log = GetLog(LLDBLog::Demangle)) {
48061da546Spatrick if (!err) {
49061da546Spatrick ParseFullName();
50061da546Spatrick LLDB_LOG(log, "demangled itanium: {0} -> \"{1}\"", mangled, m_ipd_buf);
51061da546Spatrick } else {
52061da546Spatrick LLDB_LOG(log, "demangled itanium: {0} -> error: failed to demangle",
53061da546Spatrick mangled);
54061da546Spatrick }
55061da546Spatrick }
56061da546Spatrick
57061da546Spatrick return !err; // true == success
58061da546Spatrick }
59061da546Spatrick
FromCxxMethodName(ConstString demangled)60061da546Spatrick bool RichManglingContext::FromCxxMethodName(ConstString demangled) {
61061da546Spatrick ResetProvider(PluginCxxLanguage);
62061da546Spatrick m_cxx_method_parser = new CPlusPlusLanguage::MethodName(demangled);
63061da546Spatrick return true;
64061da546Spatrick }
65061da546Spatrick
IsCtorOrDtor() const66061da546Spatrick bool RichManglingContext::IsCtorOrDtor() const {
67061da546Spatrick assert(m_provider != None && "Initialize a provider first");
68061da546Spatrick switch (m_provider) {
69061da546Spatrick case ItaniumPartialDemangler:
70061da546Spatrick return m_ipd.isCtorOrDtor();
71061da546Spatrick case PluginCxxLanguage: {
72061da546Spatrick // We can only check for destructors here.
73061da546Spatrick auto base_name =
74061da546Spatrick get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename();
75061da546Spatrick return base_name.startswith("~");
76061da546Spatrick }
77061da546Spatrick case None:
78061da546Spatrick return false;
79061da546Spatrick }
80061da546Spatrick llvm_unreachable("Fully covered switch above!");
81061da546Spatrick }
82061da546Spatrick
processIPDStrResult(char * ipd_res,size_t res_size)83*f6aab3d8Srobert llvm::StringRef RichManglingContext::processIPDStrResult(char *ipd_res,
84*f6aab3d8Srobert size_t res_size) {
85061da546Spatrick // Error case: Clear the buffer.
86061da546Spatrick if (LLVM_UNLIKELY(ipd_res == nullptr)) {
87061da546Spatrick assert(res_size == m_ipd_buf_size &&
88061da546Spatrick "Failed IPD queries keep the original size in the N parameter");
89061da546Spatrick
90061da546Spatrick m_ipd_buf[0] = '\0';
91*f6aab3d8Srobert return llvm::StringRef(m_ipd_buf, 0);
92061da546Spatrick }
93061da546Spatrick
94061da546Spatrick // IPD's res_size includes null terminator.
95061da546Spatrick assert(ipd_res[res_size - 1] == '\0' &&
96061da546Spatrick "IPD returns null-terminated strings and we rely on that");
97061da546Spatrick
98061da546Spatrick // Update buffer/size on realloc.
99061da546Spatrick if (LLVM_UNLIKELY(ipd_res != m_ipd_buf || res_size > m_ipd_buf_size)) {
100061da546Spatrick m_ipd_buf = ipd_res; // std::realloc freed or reused the old buffer.
101061da546Spatrick m_ipd_buf_size = res_size; // May actually be bigger, but we can't know.
102061da546Spatrick
103*f6aab3d8Srobert if (Log *log = GetLog(LLDBLog::Demangle))
104061da546Spatrick LLDB_LOG(log, "ItaniumPartialDemangler Realloc: new buffer size is {0}",
105061da546Spatrick m_ipd_buf_size);
106061da546Spatrick }
107061da546Spatrick
108061da546Spatrick // 99% case: Just remember the string length.
109*f6aab3d8Srobert return llvm::StringRef(m_ipd_buf, res_size - 1);
110061da546Spatrick }
111061da546Spatrick
ParseFunctionBaseName()112*f6aab3d8Srobert llvm::StringRef RichManglingContext::ParseFunctionBaseName() {
113061da546Spatrick assert(m_provider != None && "Initialize a provider first");
114061da546Spatrick switch (m_provider) {
115061da546Spatrick case ItaniumPartialDemangler: {
116061da546Spatrick auto n = m_ipd_buf_size;
117061da546Spatrick auto buf = m_ipd.getFunctionBaseName(m_ipd_buf, &n);
118*f6aab3d8Srobert return processIPDStrResult(buf, n);
119061da546Spatrick }
120061da546Spatrick case PluginCxxLanguage:
121*f6aab3d8Srobert return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
122*f6aab3d8Srobert ->GetBasename();
123061da546Spatrick case None:
124*f6aab3d8Srobert return {};
125061da546Spatrick }
126*f6aab3d8Srobert llvm_unreachable("Fully covered switch above!");
127061da546Spatrick }
128061da546Spatrick
ParseFunctionDeclContextName()129*f6aab3d8Srobert llvm::StringRef RichManglingContext::ParseFunctionDeclContextName() {
130061da546Spatrick assert(m_provider != None && "Initialize a provider first");
131061da546Spatrick switch (m_provider) {
132061da546Spatrick case ItaniumPartialDemangler: {
133061da546Spatrick auto n = m_ipd_buf_size;
134061da546Spatrick auto buf = m_ipd.getFunctionDeclContextName(m_ipd_buf, &n);
135*f6aab3d8Srobert return processIPDStrResult(buf, n);
136061da546Spatrick }
137061da546Spatrick case PluginCxxLanguage:
138*f6aab3d8Srobert return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
139*f6aab3d8Srobert ->GetContext();
140061da546Spatrick case None:
141*f6aab3d8Srobert return {};
142061da546Spatrick }
143*f6aab3d8Srobert llvm_unreachable("Fully covered switch above!");
144061da546Spatrick }
145061da546Spatrick
ParseFullName()146*f6aab3d8Srobert llvm::StringRef RichManglingContext::ParseFullName() {
147061da546Spatrick assert(m_provider != None && "Initialize a provider first");
148061da546Spatrick switch (m_provider) {
149061da546Spatrick case ItaniumPartialDemangler: {
150061da546Spatrick auto n = m_ipd_buf_size;
151061da546Spatrick auto buf = m_ipd.finishDemangle(m_ipd_buf, &n);
152*f6aab3d8Srobert return processIPDStrResult(buf, n);
153061da546Spatrick }
154061da546Spatrick case PluginCxxLanguage:
155*f6aab3d8Srobert return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
156061da546Spatrick ->GetFullName()
157061da546Spatrick .GetStringRef();
158061da546Spatrick case None:
159*f6aab3d8Srobert return {};
160061da546Spatrick }
161*f6aab3d8Srobert llvm_unreachable("Fully covered switch above!");
162061da546Spatrick }
163