1 | //===-- TypeSynthetic.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 | |
10 | |
11 | |
12 | #include "lldb/lldb-enumerations.h" |
13 | #include "lldb/lldb-public.h" |
14 | |
15 | #include "lldb/Core/Debugger.h" |
16 | #include "lldb/DataFormatters/TypeSynthetic.h" |
17 | #include "lldb/Interpreter/CommandInterpreter.h" |
18 | #include "lldb/Interpreter/ScriptInterpreter.h" |
19 | #include "lldb/Symbol/CompilerType.h" |
20 | #include "lldb/Target/Target.h" |
21 | #include "lldb/Utility/StreamString.h" |
22 | |
23 | using namespace lldb; |
24 | using namespace lldb_private; |
25 | |
26 | void TypeFilterImpl::AddExpressionPath(const std::string &path) { |
27 | bool need_add_dot = true; |
28 | if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[') |
29 | need_add_dot = false; |
30 | // add a '.' symbol to help forgetful users |
31 | if (!need_add_dot) |
32 | m_expression_paths.push_back(x: path); |
33 | else |
34 | m_expression_paths.push_back(x: std::string("." ) + path); |
35 | } |
36 | |
37 | bool TypeFilterImpl::SetExpressionPathAtIndex(size_t i, |
38 | const std::string &path) { |
39 | if (i >= GetCount()) |
40 | return false; |
41 | bool need_add_dot = true; |
42 | if (path[0] == '.' || (path[0] == '-' && path[1] == '>') || path[0] == '[') |
43 | need_add_dot = false; |
44 | // add a '.' symbol to help forgetful users |
45 | if (!need_add_dot) |
46 | m_expression_paths[i] = path; |
47 | else |
48 | m_expression_paths[i] = std::string("." ) + path; |
49 | return true; |
50 | } |
51 | |
52 | size_t |
53 | TypeFilterImpl::FrontEnd::GetIndexOfChildWithName(ConstString name) { |
54 | const char *name_cstr = name.GetCString(); |
55 | if (name_cstr) { |
56 | for (size_t i = 0; i < filter->GetCount(); i++) { |
57 | const char *expr_cstr = filter->GetExpressionPathAtIndex(i); |
58 | if (expr_cstr) { |
59 | if (*expr_cstr == '.') |
60 | expr_cstr++; |
61 | else if (*expr_cstr == '-' && *(expr_cstr + 1) == '>') |
62 | expr_cstr += 2; |
63 | } |
64 | if (expr_cstr) { |
65 | if (!::strcmp(s1: name_cstr, s2: expr_cstr)) |
66 | return i; |
67 | } |
68 | } |
69 | } |
70 | return UINT32_MAX; |
71 | } |
72 | |
73 | std::string TypeFilterImpl::GetDescription() { |
74 | StreamString sstr; |
75 | sstr.Printf(format: "%s%s%s {\n" , Cascades() ? "" : " (not cascading)" , |
76 | SkipsPointers() ? " (skip pointers)" : "" , |
77 | SkipsReferences() ? " (skip references)" : "" ); |
78 | |
79 | for (size_t i = 0; i < GetCount(); i++) { |
80 | sstr.Printf(format: " %s\n" , GetExpressionPathAtIndex(i)); |
81 | } |
82 | |
83 | sstr.Printf(format: "}" ); |
84 | return std::string(sstr.GetString()); |
85 | } |
86 | |
87 | SyntheticChildren::SyntheticChildren(const Flags &flags) : m_flags(flags) {} |
88 | |
89 | SyntheticChildren::~SyntheticChildren() = default; |
90 | |
91 | CXXSyntheticChildren::CXXSyntheticChildren( |
92 | const SyntheticChildren::Flags &flags, const char *description, |
93 | CreateFrontEndCallback callback) |
94 | : SyntheticChildren(flags), m_create_callback(std::move(callback)), |
95 | m_description(description ? description : "" ) {} |
96 | |
97 | CXXSyntheticChildren::~CXXSyntheticChildren() = default; |
98 | |
99 | bool SyntheticChildren::IsScripted() { return false; } |
100 | |
101 | std::string SyntheticChildren::GetDescription() { return "" ; } |
102 | |
103 | SyntheticChildrenFrontEnd::AutoPointer |
104 | SyntheticChildren::GetFrontEnd(ValueObject &backend) { |
105 | return nullptr; |
106 | } |
107 | |
108 | std::string CXXSyntheticChildren::GetDescription() { |
109 | StreamString sstr; |
110 | sstr.Printf(format: "%s%s%s %s" , Cascades() ? "" : " (not cascading)" , |
111 | SkipsPointers() ? " (skip pointers)" : "" , |
112 | SkipsReferences() ? " (skip references)" : "" , |
113 | m_description.c_str()); |
114 | |
115 | return std::string(sstr.GetString()); |
116 | } |
117 | |
118 | uint32_t |
119 | SyntheticChildrenFrontEnd::CalculateNumChildrenIgnoringErrors(uint32_t max) { |
120 | auto value_or_err = CalculateNumChildren(max); |
121 | if (value_or_err) |
122 | return *value_or_err; |
123 | LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), value_or_err.takeError(), |
124 | "{0}" ); |
125 | return 0; |
126 | } |
127 | |
128 | lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromExpression( |
129 | llvm::StringRef name, llvm::StringRef expression, |
130 | const ExecutionContext &exe_ctx) { |
131 | ValueObjectSP valobj_sp( |
132 | ValueObject::CreateValueObjectFromExpression(name, expression, exe_ctx)); |
133 | if (valobj_sp) |
134 | valobj_sp->SetSyntheticChildrenGenerated(true); |
135 | return valobj_sp; |
136 | } |
137 | |
138 | lldb::ValueObjectSP SyntheticChildrenFrontEnd::CreateValueObjectFromAddress( |
139 | llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, |
140 | CompilerType type) { |
141 | ValueObjectSP valobj_sp( |
142 | ValueObject::CreateValueObjectFromAddress(name, address, exe_ctx, type)); |
143 | if (valobj_sp) |
144 | valobj_sp->SetSyntheticChildrenGenerated(true); |
145 | return valobj_sp; |
146 | } |
147 | |
148 | lldb::ValueObjectSP SyntheticChildrenFrontEnd::( |
149 | llvm::StringRef name, const DataExtractor &data, |
150 | const ExecutionContext &exe_ctx, CompilerType type) { |
151 | ValueObjectSP valobj_sp( |
152 | ValueObject::CreateValueObjectFromData(name, data, exe_ctx, type)); |
153 | if (valobj_sp) |
154 | valobj_sp->SetSyntheticChildrenGenerated(true); |
155 | return valobj_sp; |
156 | } |
157 | |
158 | ScriptedSyntheticChildren::FrontEnd::FrontEnd(std::string pclass, |
159 | ValueObject &backend) |
160 | : SyntheticChildrenFrontEnd(backend), m_python_class(pclass), |
161 | m_wrapper_sp(), m_interpreter(nullptr) { |
162 | if (backend.GetID() == LLDB_INVALID_UID) |
163 | return; |
164 | |
165 | TargetSP target_sp = backend.GetTargetSP(); |
166 | |
167 | if (!target_sp) |
168 | return; |
169 | |
170 | m_interpreter = target_sp->GetDebugger().GetScriptInterpreter(); |
171 | |
172 | if (m_interpreter != nullptr) |
173 | m_wrapper_sp = m_interpreter->CreateSyntheticScriptedProvider( |
174 | class_name: m_python_class.c_str(), valobj: backend.GetSP()); |
175 | } |
176 | |
177 | ScriptedSyntheticChildren::FrontEnd::~FrontEnd() = default; |
178 | |
179 | lldb::ValueObjectSP |
180 | ScriptedSyntheticChildren::FrontEnd::GetChildAtIndex(uint32_t idx) { |
181 | if (!m_wrapper_sp || !m_interpreter) |
182 | return lldb::ValueObjectSP(); |
183 | |
184 | return m_interpreter->GetChildAtIndex(implementor: m_wrapper_sp, idx); |
185 | } |
186 | |
187 | bool ScriptedSyntheticChildren::FrontEnd::IsValid() { |
188 | return (m_wrapper_sp && m_wrapper_sp->IsValid() && m_interpreter); |
189 | } |
190 | |
191 | llvm::Expected<uint32_t> |
192 | ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren() { |
193 | if (!m_wrapper_sp || m_interpreter == nullptr) |
194 | return 0; |
195 | return m_interpreter->CalculateNumChildren(implementor: m_wrapper_sp, UINT32_MAX); |
196 | } |
197 | |
198 | llvm::Expected<uint32_t> |
199 | ScriptedSyntheticChildren::FrontEnd::CalculateNumChildren(uint32_t max) { |
200 | if (!m_wrapper_sp || m_interpreter == nullptr) |
201 | return 0; |
202 | return m_interpreter->CalculateNumChildren(implementor: m_wrapper_sp, max); |
203 | } |
204 | |
205 | lldb::ChildCacheState ScriptedSyntheticChildren::FrontEnd::Update() { |
206 | if (!m_wrapper_sp || m_interpreter == nullptr) |
207 | return lldb::ChildCacheState::eRefetch; |
208 | |
209 | return m_interpreter->UpdateSynthProviderInstance(implementor: m_wrapper_sp) |
210 | ? lldb::ChildCacheState::eReuse |
211 | : lldb::ChildCacheState::eRefetch; |
212 | } |
213 | |
214 | bool ScriptedSyntheticChildren::FrontEnd::MightHaveChildren() { |
215 | if (!m_wrapper_sp || m_interpreter == nullptr) |
216 | return false; |
217 | |
218 | return m_interpreter->MightHaveChildrenSynthProviderInstance(implementor: m_wrapper_sp); |
219 | } |
220 | |
221 | size_t ScriptedSyntheticChildren::FrontEnd::GetIndexOfChildWithName( |
222 | ConstString name) { |
223 | if (!m_wrapper_sp || m_interpreter == nullptr) |
224 | return UINT32_MAX; |
225 | return m_interpreter->GetIndexOfChildWithName(implementor: m_wrapper_sp, |
226 | child_name: name.GetCString()); |
227 | } |
228 | |
229 | lldb::ValueObjectSP ScriptedSyntheticChildren::FrontEnd::GetSyntheticValue() { |
230 | if (!m_wrapper_sp || m_interpreter == nullptr) |
231 | return nullptr; |
232 | |
233 | return m_interpreter->GetSyntheticValue(implementor: m_wrapper_sp); |
234 | } |
235 | |
236 | ConstString ScriptedSyntheticChildren::FrontEnd::GetSyntheticTypeName() { |
237 | if (!m_wrapper_sp || m_interpreter == nullptr) |
238 | return ConstString(); |
239 | |
240 | return m_interpreter->GetSyntheticTypeName(implementor: m_wrapper_sp); |
241 | } |
242 | |
243 | std::string ScriptedSyntheticChildren::GetDescription() { |
244 | StreamString sstr; |
245 | sstr.Printf(format: "%s%s%s Python class %s" , Cascades() ? "" : " (not cascading)" , |
246 | SkipsPointers() ? " (skip pointers)" : "" , |
247 | SkipsReferences() ? " (skip references)" : "" , |
248 | m_python_class.c_str()); |
249 | |
250 | return std::string(sstr.GetString()); |
251 | } |
252 | |