blob: 0ff602f7ad1de59e2d3ea43c4f3b1dd549a8cdec [file] [log] [blame]
Stefan Granitzf1a98df2018-08-08 21:57:37 +00001//===-- RichManglingContext.cpp ---------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "lldb/Core/RichManglingContext.h"
11
12#include "lldb/Utility/Log.h"
13#include "lldb/Utility/Logging.h"
14
15#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
16
17#include "llvm/ADT/StringRef.h"
18
19using namespace lldb;
20using namespace lldb_private;
21
22//----------------------------------------------------------------------
23// RichManglingContext
24//----------------------------------------------------------------------
25void RichManglingContext::ResetProvider(InfoProvider new_provider) {
26 // If we want to support parsers for other languages some day, we need a
27 // switch here to delete the correct parser type.
28 if (m_cxx_method_parser.hasValue()) {
29 assert(m_provider == PluginCxxLanguage);
30 delete get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser);
31 m_cxx_method_parser.reset();
32 }
33
34 assert(new_provider != None && "Only reset to a valid provider");
35 m_provider = new_provider;
36}
37
38bool RichManglingContext::FromItaniumName(const ConstString &mangled) {
39 bool err = m_ipd.partialDemangle(mangled.GetCString());
40 if (!err) {
41 ResetProvider(ItaniumPartialDemangler);
42 }
43
44 if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE)) {
45 if (!err) {
46 ParseFullName();
47 LLDB_LOG(log, "demangled itanium: {0} -> \"{1}\"", mangled, m_ipd_buf);
48 } else {
49 LLDB_LOG(log, "demangled itanium: {0} -> error: failed to demangle",
50 mangled);
51 }
52 }
53
54 return !err; // true == success
55}
56
57bool RichManglingContext::FromCxxMethodName(const ConstString &demangled) {
58 ResetProvider(PluginCxxLanguage);
59 m_cxx_method_parser = new CPlusPlusLanguage::MethodName(demangled);
60 return true;
61}
62
63bool RichManglingContext::IsCtorOrDtor() const {
64 assert(m_provider != None && "Initialize a provider first");
65 switch (m_provider) {
66 case ItaniumPartialDemangler:
67 return m_ipd.isCtorOrDtor();
68 case PluginCxxLanguage: {
69 // We can only check for destructors here.
70 auto base_name =
71 get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename();
72 return base_name.startswith("~");
73 }
74 case None:
75 return false;
76 }
77}
78
79bool 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}
90
91void RichManglingContext::processIPDStrResult(char *ipd_res, size_t res_size) {
Stefan Granitzd0514162018-08-10 15:21:33 +000092 // Error case: Clear the buffer.
Stefan Granitzf1a98df2018-08-08 21:57:37 +000093 if (LLVM_UNLIKELY(ipd_res == nullptr)) {
94 assert(res_size == m_ipd_buf_size &&
95 "Failed IPD queries keep the original size in the N parameter");
96
Stefan Granitzd0514162018-08-10 15:21:33 +000097 m_ipd_buf[0] = '\0';
98 m_buffer = llvm::StringRef(m_ipd_buf, 0);
99 return;
Stefan Granitzf1a98df2018-08-08 21:57:37 +0000100 }
101
Stefan Granitzd0514162018-08-10 15:21:33 +0000102 // IPD's res_size includes null terminator.
103 assert(ipd_res[res_size - 1] == '\0' &&
104 "IPD returns null-terminated strings and we rely on that");
105
106 // Update buffer/size on realloc.
107 if (LLVM_UNLIKELY(ipd_res != m_ipd_buf || res_size > m_ipd_buf_size)) {
108 m_ipd_buf = ipd_res; // std::realloc freed or reused the old buffer.
109 m_ipd_buf_size = res_size; // May actually be bigger, but we can't know.
110
111 if (Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_DEMANGLE))
112 LLDB_LOG(log, "ItaniumPartialDemangler Realloc: new buffer size is {0}",
113 m_ipd_buf_size);
114 }
115
116 // 99% case: Just remember the string length.
117 m_buffer = llvm::StringRef(m_ipd_buf, res_size - 1);
Stefan Granitzf1a98df2018-08-08 21:57:37 +0000118}
119
120void RichManglingContext::ParseFunctionBaseName() {
121 assert(m_provider != None && "Initialize a provider first");
122 switch (m_provider) {
123 case ItaniumPartialDemangler: {
124 auto n = m_ipd_buf_size;
125 auto buf = m_ipd.getFunctionBaseName(m_ipd_buf, &n);
126 processIPDStrResult(buf, n);
127 return;
128 }
129 case PluginCxxLanguage:
130 m_buffer =
131 get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetBasename();
132 return;
133 case None:
134 return;
135 }
136}
137
138void RichManglingContext::ParseFunctionDeclContextName() {
139 assert(m_provider != None && "Initialize a provider first");
140 switch (m_provider) {
141 case ItaniumPartialDemangler: {
142 auto n = m_ipd_buf_size;
143 auto buf = m_ipd.getFunctionDeclContextName(m_ipd_buf, &n);
144 processIPDStrResult(buf, n);
145 return;
146 }
147 case PluginCxxLanguage:
148 m_buffer =
149 get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)->GetContext();
150 return;
151 case None:
152 return;
153 }
154}
155
156void RichManglingContext::ParseFullName() {
157 assert(m_provider != None && "Initialize a provider first");
158 switch (m_provider) {
159 case ItaniumPartialDemangler: {
160 auto n = m_ipd_buf_size;
161 auto buf = m_ipd.finishDemangle(m_ipd_buf, &n);
162 processIPDStrResult(buf, n);
163 return;
164 }
165 case PluginCxxLanguage:
166 m_buffer = get<CPlusPlusLanguage::MethodName>(m_cxx_method_parser)
167 ->GetFullName()
168 .GetStringRef();
169 return;
170 case None:
171 return;
172 }
173}