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