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 
15 using namespace lldb;
16 using namespace lldb_private;
17 
18 // RichManglingContext
19 RichManglingContext::~RichManglingContext() {
20   std::free(m_ipd_buf);
21   ResetCxxMethodParser();
22 }
23 
24 void 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.hasValue()) {
28     assert(m_provider == PluginCxxLanguage);
29     delete get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser);
30     m_cxx_method_parser.reset();
31   }
32 }
33 
34 void 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 
41 bool RichManglingContext::FromItaniumName(ConstString mangled) {
42   bool err = m_ipd.partialDemangle(mangled.GetCString());
43   if (!err) {
44     ResetProvider(ItaniumPartialDemangler);
45   }
46 
47   if (Log *log = GetLog(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 
60 bool RichManglingContext::FromCxxMethodName(ConstString demangled) {
61   ResetProvider(PluginCxxLanguage);
62   m_cxx_method_parser = new CPlusPlusLanguage::MethodName(demangled);
63   return true;
64 }
65 
66 bool 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>(m_cxx_method_parser)->GetBasename();
75     return base_name.startswith("~");
76   }
77   case None:
78     return false;
79   }
80   llvm_unreachable("Fully covered switch above!");
81 }
82 
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 
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 get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
122         ->GetBasename();
123   case None:
124     return {};
125   }
126   llvm_unreachable("Fully covered switch above!");
127 }
128 
129 llvm::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(m_ipd_buf, &n);
135     return processIPDStrResult(buf, n);
136   }
137   case PluginCxxLanguage:
138     return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
139         ->GetContext();
140   case None:
141     return {};
142   }
143   llvm_unreachable("Fully covered switch above!");
144 }
145 
146 llvm::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(m_ipd_buf, &n);
152     return processIPDStrResult(buf, n);
153   }
154   case PluginCxxLanguage:
155     return get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
156         ->GetFullName()
157         .GetStringRef();
158   case None:
159     return {};
160   }
161   llvm_unreachable("Fully covered switch above!");
162 }
163