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