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