Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/ValueObject/ValueObjectSynthetic.cpp
213764 views
1
//===-- ValueObjectSynthetic.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/ValueObject/ValueObjectSynthetic.h"
10
11
#include "lldb/Core/Value.h"
12
#include "lldb/DataFormatters/TypeSynthetic.h"
13
#include "lldb/Target/ExecutionContext.h"
14
#include "lldb/Utility/ConstString.h"
15
#include "lldb/Utility/LLDBLog.h"
16
#include "lldb/Utility/Log.h"
17
#include "lldb/Utility/Status.h"
18
#include "lldb/ValueObject/ValueObject.h"
19
20
#include "llvm/ADT/STLExtras.h"
21
#include <optional>
22
23
namespace lldb_private {
24
class Declaration;
25
}
26
27
using namespace lldb_private;
28
29
class DummySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
30
public:
31
DummySyntheticFrontEnd(ValueObject &backend)
32
: SyntheticChildrenFrontEnd(backend) {}
33
34
llvm::Expected<uint32_t> CalculateNumChildren() override {
35
return m_backend.GetNumChildren();
36
}
37
38
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override {
39
return m_backend.GetChildAtIndex(idx);
40
}
41
42
llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
43
return m_backend.GetIndexOfChildWithName(name);
44
}
45
46
bool MightHaveChildren() override { return m_backend.MightHaveChildren(); }
47
48
lldb::ChildCacheState Update() override {
49
return lldb::ChildCacheState::eRefetch;
50
}
51
};
52
53
ValueObjectSynthetic::ValueObjectSynthetic(ValueObject &parent,
54
lldb::SyntheticChildrenSP filter)
55
: ValueObject(parent), m_synth_sp(std::move(filter)), m_children_byindex(),
56
m_name_toindex(), m_synthetic_children_cache(),
57
m_synthetic_children_count(UINT32_MAX),
58
m_parent_type_name(parent.GetTypeName()),
59
m_might_have_children(eLazyBoolCalculate),
60
m_provides_value(eLazyBoolCalculate) {
61
SetName(parent.GetName());
62
// Copying the data of an incomplete type won't work as it has no byte size.
63
if (m_parent->GetCompilerType().IsCompleteType())
64
CopyValueData(m_parent);
65
CreateSynthFilter();
66
}
67
68
ValueObjectSynthetic::~ValueObjectSynthetic() = default;
69
70
CompilerType ValueObjectSynthetic::GetCompilerTypeImpl() {
71
return m_parent->GetCompilerType();
72
}
73
74
ConstString ValueObjectSynthetic::GetTypeName() {
75
return m_parent->GetTypeName();
76
}
77
78
ConstString ValueObjectSynthetic::GetQualifiedTypeName() {
79
return m_parent->GetQualifiedTypeName();
80
}
81
82
ConstString ValueObjectSynthetic::GetDisplayTypeName() {
83
if (ConstString synth_name = m_synth_filter_up->GetSyntheticTypeName())
84
return synth_name;
85
86
return m_parent->GetDisplayTypeName();
87
}
88
89
llvm::Expected<uint32_t>
90
ValueObjectSynthetic::CalculateNumChildren(uint32_t max) {
91
Log *log = GetLog(LLDBLog::DataFormatters);
92
93
UpdateValueIfNeeded();
94
if (m_synthetic_children_count < UINT32_MAX)
95
return m_synthetic_children_count <= max ? m_synthetic_children_count : max;
96
97
if (max < UINT32_MAX) {
98
auto num_children = m_synth_filter_up->CalculateNumChildren(max);
99
LLDB_LOGF(log,
100
"[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
101
"%s and type %s, the filter returned %u child values",
102
GetName().AsCString(), GetTypeName().AsCString(),
103
num_children ? *num_children : 0);
104
return num_children;
105
} else {
106
auto num_children_or_err = m_synth_filter_up->CalculateNumChildren(max);
107
if (!num_children_or_err) {
108
m_synthetic_children_count = 0;
109
return num_children_or_err;
110
}
111
auto num_children = (m_synthetic_children_count = *num_children_or_err);
112
LLDB_LOGF(log,
113
"[ValueObjectSynthetic::CalculateNumChildren] for VO of name "
114
"%s and type %s, the filter returned %u child values",
115
GetName().AsCString(), GetTypeName().AsCString(), num_children);
116
return num_children;
117
}
118
}
119
120
lldb::ValueObjectSP
121
ValueObjectSynthetic::GetDynamicValue(lldb::DynamicValueType valueType) {
122
if (!m_parent)
123
return lldb::ValueObjectSP();
124
if (IsDynamic() && GetDynamicValueType() == valueType)
125
return GetSP();
126
return m_parent->GetDynamicValue(valueType);
127
}
128
129
bool ValueObjectSynthetic::MightHaveChildren() {
130
if (m_might_have_children == eLazyBoolCalculate)
131
m_might_have_children =
132
(m_synth_filter_up->MightHaveChildren() ? eLazyBoolYes : eLazyBoolNo);
133
return (m_might_have_children != eLazyBoolNo);
134
}
135
136
llvm::Expected<uint64_t> ValueObjectSynthetic::GetByteSize() {
137
return m_parent->GetByteSize();
138
}
139
140
lldb::ValueType ValueObjectSynthetic::GetValueType() const {
141
return m_parent->GetValueType();
142
}
143
144
void ValueObjectSynthetic::CreateSynthFilter() {
145
ValueObject *valobj_for_frontend = m_parent;
146
if (m_synth_sp->WantsDereference()) {
147
CompilerType type = m_parent->GetCompilerType();
148
if (type.IsValid() && type.IsPointerOrReferenceType()) {
149
Status error;
150
lldb::ValueObjectSP deref_sp = m_parent->Dereference(error);
151
if (error.Success())
152
valobj_for_frontend = deref_sp.get();
153
}
154
}
155
m_synth_filter_up = (m_synth_sp->GetFrontEnd(*valobj_for_frontend));
156
if (!m_synth_filter_up)
157
m_synth_filter_up = std::make_unique<DummySyntheticFrontEnd>(*m_parent);
158
}
159
160
bool ValueObjectSynthetic::UpdateValue() {
161
Log *log = GetLog(LLDBLog::DataFormatters);
162
163
SetValueIsValid(false);
164
m_error.Clear();
165
166
if (!m_parent->UpdateValueIfNeeded(false)) {
167
// our parent could not update.. as we are meaningless without a parent,
168
// just stop
169
if (m_parent->GetError().Fail())
170
m_error = m_parent->GetError().Clone();
171
return false;
172
}
173
174
// Regenerate the synthetic filter if our typename changes. When the (dynamic)
175
// type of an object changes, so does their synthetic filter of choice.
176
ConstString new_parent_type_name = m_parent->GetTypeName();
177
if (new_parent_type_name != m_parent_type_name) {
178
LLDB_LOGF(log,
179
"[ValueObjectSynthetic::UpdateValue] name=%s, type changed "
180
"from %s to %s, recomputing synthetic filter",
181
GetName().AsCString(), m_parent_type_name.AsCString(),
182
new_parent_type_name.AsCString());
183
m_parent_type_name = new_parent_type_name;
184
CreateSynthFilter();
185
}
186
187
// let our backend do its update
188
if (m_synth_filter_up->Update() == lldb::ChildCacheState::eRefetch) {
189
LLDB_LOGF(log,
190
"[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
191
"filter said caches are stale - clearing",
192
GetName().AsCString());
193
// filter said that cached values are stale
194
{
195
std::lock_guard<std::mutex> guard(m_child_mutex);
196
m_children_byindex.clear();
197
m_name_toindex.clear();
198
}
199
// usually, an object's value can change but this does not alter its
200
// children count for a synthetic VO that might indeed happen, so we need
201
// to tell the upper echelons that they need to come back to us asking for
202
// children
203
m_flags.m_children_count_valid = false;
204
{
205
std::lock_guard<std::mutex> guard(m_child_mutex);
206
m_synthetic_children_cache.clear();
207
}
208
m_synthetic_children_count = UINT32_MAX;
209
m_might_have_children = eLazyBoolCalculate;
210
} else {
211
LLDB_LOGF(log,
212
"[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
213
"filter said caches are still valid",
214
GetName().AsCString());
215
}
216
217
m_provides_value = eLazyBoolCalculate;
218
219
lldb::ValueObjectSP synth_val(m_synth_filter_up->GetSyntheticValue());
220
221
if (synth_val && synth_val->CanProvideValue()) {
222
LLDB_LOGF(log,
223
"[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
224
"filter said it can provide a value",
225
GetName().AsCString());
226
227
m_provides_value = eLazyBoolYes;
228
CopyValueData(synth_val.get());
229
} else {
230
LLDB_LOGF(log,
231
"[ValueObjectSynthetic::UpdateValue] name=%s, synthetic "
232
"filter said it will not provide a value",
233
GetName().AsCString());
234
235
m_provides_value = eLazyBoolNo;
236
// Copying the data of an incomplete type won't work as it has no byte size.
237
if (m_parent->GetCompilerType().IsCompleteType())
238
CopyValueData(m_parent);
239
}
240
241
SetValueIsValid(true);
242
return true;
243
}
244
245
lldb::ValueObjectSP ValueObjectSynthetic::GetChildAtIndex(uint32_t idx,
246
bool can_create) {
247
Log *log = GetLog(LLDBLog::DataFormatters);
248
249
LLDB_LOGF(log,
250
"[ValueObjectSynthetic::GetChildAtIndex] name=%s, retrieving "
251
"child at index %u",
252
GetName().AsCString(), idx);
253
254
UpdateValueIfNeeded();
255
256
ValueObject *valobj;
257
bool child_is_cached;
258
{
259
std::lock_guard<std::mutex> guard(m_child_mutex);
260
auto cached_child_it = m_children_byindex.find(idx);
261
child_is_cached = cached_child_it != m_children_byindex.end();
262
if (child_is_cached)
263
valobj = cached_child_it->second;
264
}
265
266
if (!child_is_cached) {
267
if (can_create && m_synth_filter_up != nullptr) {
268
LLDB_LOGF(log,
269
"[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
270
"index %u not cached and will be created",
271
GetName().AsCString(), idx);
272
273
lldb::ValueObjectSP synth_guy = m_synth_filter_up->GetChildAtIndex(idx);
274
275
LLDB_LOGF(
276
log,
277
"[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at index "
278
"%u created as %p (is "
279
"synthetic: %s)",
280
GetName().AsCString(), idx, static_cast<void *>(synth_guy.get()),
281
synth_guy.get()
282
? (synth_guy->IsSyntheticChildrenGenerated() ? "yes" : "no")
283
: "no");
284
285
if (!synth_guy)
286
return synth_guy;
287
288
{
289
std::lock_guard<std::mutex> guard(m_child_mutex);
290
if (synth_guy->IsSyntheticChildrenGenerated())
291
m_synthetic_children_cache.push_back(synth_guy);
292
m_children_byindex[idx] = synth_guy.get();
293
}
294
synth_guy->SetPreferredDisplayLanguageIfNeeded(
295
GetPreferredDisplayLanguage());
296
return synth_guy;
297
} else {
298
LLDB_LOGF(log,
299
"[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
300
"index %u not cached and cannot "
301
"be created (can_create = %s, synth_filter = %p)",
302
GetName().AsCString(), idx, can_create ? "yes" : "no",
303
static_cast<void *>(m_synth_filter_up.get()));
304
305
return lldb::ValueObjectSP();
306
}
307
} else {
308
LLDB_LOGF(log,
309
"[ValueObjectSynthetic::GetChildAtIndex] name=%s, child at "
310
"index %u cached as %p",
311
GetName().AsCString(), idx, static_cast<void *>(valobj));
312
313
return valobj->GetSP();
314
}
315
}
316
317
lldb::ValueObjectSP
318
ValueObjectSynthetic::GetChildMemberWithName(llvm::StringRef name,
319
bool can_create) {
320
UpdateValueIfNeeded();
321
322
auto index_or_err = GetIndexOfChildWithName(name);
323
324
if (!index_or_err) {
325
llvm::consumeError(index_or_err.takeError());
326
return lldb::ValueObjectSP();
327
}
328
329
return GetChildAtIndex(*index_or_err, can_create);
330
}
331
332
llvm::Expected<size_t>
333
ValueObjectSynthetic::GetIndexOfChildWithName(llvm::StringRef name_ref) {
334
UpdateValueIfNeeded();
335
336
ConstString name(name_ref);
337
338
std::optional<uint32_t> found_index = std::nullopt;
339
{
340
std::lock_guard<std::mutex> guard(m_child_mutex);
341
auto name_to_index = m_name_toindex.find(name.GetCString());
342
if (name_to_index != m_name_toindex.end())
343
found_index = name_to_index->second;
344
}
345
346
if (!found_index && m_synth_filter_up != nullptr) {
347
auto index_or_err = m_synth_filter_up->GetIndexOfChildWithName(name);
348
if (!index_or_err)
349
return index_or_err.takeError();
350
std::lock_guard<std::mutex> guard(m_child_mutex);
351
m_name_toindex[name.GetCString()] = *index_or_err;
352
return *index_or_err;
353
} else if (!found_index && m_synth_filter_up == nullptr) {
354
return llvm::createStringError("Type has no child named '%s'",
355
name.AsCString());
356
} else if (found_index)
357
return *found_index;
358
359
return llvm::createStringError("Type has no child named '%s'",
360
name.AsCString());
361
}
362
363
bool ValueObjectSynthetic::IsInScope() { return m_parent->IsInScope(); }
364
365
lldb::ValueObjectSP ValueObjectSynthetic::GetNonSyntheticValue() {
366
return m_parent->GetSP();
367
}
368
369
void ValueObjectSynthetic::CopyValueData(ValueObject *source) {
370
if (!source->UpdateValueIfNeeded())
371
return;
372
m_value = source->GetValue();
373
ExecutionContext exe_ctx(GetExecutionContextRef());
374
m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
375
}
376
377
bool ValueObjectSynthetic::CanProvideValue() {
378
if (!UpdateValueIfNeeded())
379
return false;
380
if (m_provides_value == eLazyBoolYes)
381
return true;
382
return m_parent->CanProvideValue();
383
}
384
385
bool ValueObjectSynthetic::SetValueFromCString(const char *value_str,
386
Status &error) {
387
return m_parent->SetValueFromCString(value_str, error);
388
}
389
390
void ValueObjectSynthetic::SetFormat(lldb::Format format) {
391
if (m_parent) {
392
m_parent->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
393
m_parent->SetFormat(format);
394
}
395
this->ValueObject::SetFormat(format);
396
this->ClearUserVisibleData(eClearUserVisibleDataItemsAll);
397
}
398
399
void ValueObjectSynthetic::SetPreferredDisplayLanguage(
400
lldb::LanguageType lang) {
401
this->ValueObject::SetPreferredDisplayLanguage(lang);
402
if (m_parent)
403
m_parent->SetPreferredDisplayLanguage(lang);
404
}
405
406
lldb::LanguageType ValueObjectSynthetic::GetPreferredDisplayLanguage() {
407
if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {
408
if (m_parent)
409
return m_parent->GetPreferredDisplayLanguage();
410
return lldb::eLanguageTypeUnknown;
411
} else
412
return m_preferred_display_language;
413
}
414
415
bool ValueObjectSynthetic::IsSyntheticChildrenGenerated() {
416
if (m_parent)
417
return m_parent->IsSyntheticChildrenGenerated();
418
return false;
419
}
420
421
void ValueObjectSynthetic::SetSyntheticChildrenGenerated(bool b) {
422
if (m_parent)
423
m_parent->SetSyntheticChildrenGenerated(b);
424
this->ValueObject::SetSyntheticChildrenGenerated(b);
425
}
426
427
bool ValueObjectSynthetic::GetDeclaration(Declaration &decl) {
428
if (m_parent)
429
return m_parent->GetDeclaration(decl);
430
431
return ValueObject::GetDeclaration(decl);
432
}
433
434
uint64_t ValueObjectSynthetic::GetLanguageFlags() {
435
if (m_parent)
436
return m_parent->GetLanguageFlags();
437
return this->ValueObject::GetLanguageFlags();
438
}
439
440
void ValueObjectSynthetic::SetLanguageFlags(uint64_t flags) {
441
if (m_parent)
442
m_parent->SetLanguageFlags(flags);
443
else
444
this->ValueObject::SetLanguageFlags(flags);
445
}
446
447