LLDB mainline
GenericList.cpp
Go to the documentation of this file.
1//===-- GenericList.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 "LibCxx.h"
10#include "MsvcStl.h"
11
13#include "lldb/Target/Target.h"
14#include "lldb/Utility/Status.h"
18
19using namespace lldb;
20using namespace lldb_private;
21using namespace lldb_private::formatters;
22
23namespace {
24
25enum class StlType {
26 LibCxx,
27 MsvcStl,
28};
29
30template <StlType Stl> class ListEntry {
31public:
32 ListEntry() = default;
33 ListEntry(ValueObjectSP entry_sp) : m_entry_sp(std::move(entry_sp)) {}
34 ListEntry(ValueObject *entry)
35 : m_entry_sp(entry ? entry->GetSP() : ValueObjectSP()) {}
36
37 uint64_t value() const {
38 if (!m_entry_sp)
39 return 0;
40 return m_entry_sp->GetValueAsUnsigned(0);
41 }
42
43 ListEntry next();
44 ListEntry prev();
45
46 bool null() { return (value() == 0); }
47
48 explicit operator bool() { return GetEntry() && !null(); }
49
50 ValueObjectSP GetEntry() { return m_entry_sp; }
51
52 void SetEntry(ValueObjectSP entry) { m_entry_sp = entry; }
53
54 bool operator==(const ListEntry &rhs) const { return value() == rhs.value(); }
55
56 bool operator!=(const ListEntry &rhs) const { return !(*this == rhs); }
57
58private:
59 ValueObjectSP m_entry_sp;
60};
61
62template <> ListEntry<StlType::LibCxx> ListEntry<StlType::LibCxx>::next() {
63 if (!m_entry_sp)
64 return ListEntry();
65 return ListEntry(m_entry_sp->GetChildMemberWithName("__next_"));
66}
67
68template <> ListEntry<StlType::LibCxx> ListEntry<StlType::LibCxx>::prev() {
69 if (!m_entry_sp)
70 return ListEntry();
71 return ListEntry(m_entry_sp->GetChildMemberWithName("__prev_"));
72}
73
74template <> ListEntry<StlType::MsvcStl> ListEntry<StlType::MsvcStl>::next() {
75 if (!m_entry_sp)
76 return ListEntry();
77 return ListEntry(m_entry_sp->GetChildMemberWithName("_Next"));
78}
79
80template <> ListEntry<StlType::MsvcStl> ListEntry<StlType::MsvcStl>::prev() {
81 if (!m_entry_sp)
82 return ListEntry();
83 return ListEntry(m_entry_sp->GetChildMemberWithName("_Prev"));
84}
85
86template <StlType Stl> class ListIterator {
87public:
88 ListIterator() = default;
89 ListIterator(ListEntry<Stl> entry) : m_entry(std::move(entry)) {}
90 ListIterator(ValueObjectSP entry) : m_entry(std::move(entry)) {}
91 ListIterator(ValueObject *entry) : m_entry(entry) {}
92
93 ValueObjectSP value() { return m_entry.GetEntry(); }
94
95 ValueObjectSP advance(size_t count) {
96 if (count == 0)
97 return m_entry.GetEntry();
98 if (count == 1) {
99 next();
100 return m_entry.GetEntry();
101 }
102 while (count > 0) {
103 next();
104 count--;
105 if (m_entry.null())
106 return lldb::ValueObjectSP();
107 }
108 return m_entry.GetEntry();
109 }
110
111 bool operator==(const ListIterator &rhs) const {
112 return (rhs.m_entry == m_entry);
113 }
114
115protected:
116 void next() { m_entry = m_entry.next(); }
117
118 void prev() { m_entry = m_entry.prev(); }
119
120private:
121 ListEntry<Stl> m_entry;
122};
123
124template <StlType Stl>
125class AbstractListFrontEnd : public SyntheticChildrenFrontEnd {
126public:
127 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override {
128 auto optional_idx = formatters::ExtractIndexFromString(name.GetCString());
129 if (!optional_idx) {
130 return llvm::createStringError("Type has no child named '%s'",
131 name.AsCString());
132 }
133 return *optional_idx;
134 }
135 lldb::ChildCacheState Update() override;
136
137protected:
138 AbstractListFrontEnd(ValueObject &valobj)
139 : SyntheticChildrenFrontEnd(valobj) {}
140
141 size_t m_count = 0;
142 ValueObject *m_head = nullptr;
143
144 static constexpr bool g_use_loop_detect = true;
145 size_t m_loop_detected = 0; // The number of elements that have had loop
146 // detection run over them.
147 ListEntry<Stl> m_slow_runner; // Used for loop detection
148 ListEntry<Stl> m_fast_runner; // Used for loop detection
149
150 size_t m_list_capping_size = 0;
151 CompilerType m_element_type;
152 std::map<size_t, ListIterator<Stl>> m_iterators;
153
154 bool HasLoop(size_t count);
155 ValueObjectSP GetItem(size_t idx);
156};
157
158class LibCxxForwardListFrontEnd : public AbstractListFrontEnd<StlType::LibCxx> {
159public:
160 LibCxxForwardListFrontEnd(ValueObject &valobj);
161
162 llvm::Expected<uint32_t> CalculateNumChildren() override;
163 ValueObjectSP GetChildAtIndex(uint32_t idx) override;
164 lldb::ChildCacheState Update() override;
165};
166
167class LibCxxListFrontEnd : public AbstractListFrontEnd<StlType::LibCxx> {
168public:
169 LibCxxListFrontEnd(lldb::ValueObjectSP valobj_sp);
170
171 llvm::Expected<uint32_t> CalculateNumChildren() override;
172
173 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
174
175 lldb::ChildCacheState Update() override;
176
177private:
178 lldb::addr_t m_node_address = 0;
179 ValueObject *m_tail = nullptr;
180};
181
182class MsvcStlForwardListFrontEnd
183 : public AbstractListFrontEnd<StlType::MsvcStl> {
184public:
185 MsvcStlForwardListFrontEnd(ValueObject &valobj);
186
187 llvm::Expected<uint32_t> CalculateNumChildren() override;
188 ValueObjectSP GetChildAtIndex(uint32_t idx) override;
189 lldb::ChildCacheState Update() override;
190};
191
192class MsvcStlListFrontEnd : public AbstractListFrontEnd<StlType::MsvcStl> {
193public:
194 MsvcStlListFrontEnd(lldb::ValueObjectSP valobj_sp);
195
196 llvm::Expected<uint32_t> CalculateNumChildren() override;
197
198 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
199
200 lldb::ChildCacheState Update() override;
201
202private:
203 ValueObject *m_tail = nullptr;
204};
205
206} // end anonymous namespace
207
208template <StlType Stl>
209lldb::ChildCacheState AbstractListFrontEnd<Stl>::Update() {
210 m_loop_detected = 0;
211 m_count = UINT32_MAX;
212 m_head = nullptr;
213 m_list_capping_size = 0;
214 m_slow_runner.SetEntry(nullptr);
215 m_fast_runner.SetEntry(nullptr);
216 m_iterators.clear();
217
218 if (m_backend.GetTargetSP())
219 m_list_capping_size =
220 m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
221 if (m_list_capping_size == 0)
222 m_list_capping_size = 255;
223
224 CompilerType list_type = m_backend.GetCompilerType();
225 if (list_type.IsReferenceType())
226 list_type = list_type.GetNonReferenceType();
227
228 if (list_type.GetNumTemplateArguments() == 0)
230 m_element_type = list_type.GetTypeTemplateArgument(0);
231
233}
234
235template <StlType Stl> bool AbstractListFrontEnd<Stl>::HasLoop(size_t count) {
236 if (!g_use_loop_detect)
237 return false;
238 // don't bother checking for a loop if we won't actually need to jump nodes
239 if (m_count < 2)
240 return false;
241
242 if (m_loop_detected == 0) {
243 // This is the first time we are being run (after the last update). Set up
244 // the loop invariant for the first element.
245 m_slow_runner = ListEntry<Stl>(m_head).next();
246 m_fast_runner = m_slow_runner.next();
247 m_loop_detected = 1;
248 }
249
250 // Loop invariant:
251 // Loop detection has been run over the first m_loop_detected elements. If
252 // m_slow_runner == m_fast_runner then the loop has been detected after
253 // m_loop_detected elements.
254 const size_t steps_to_run = std::min(count, m_count);
255 while (m_loop_detected < steps_to_run && m_slow_runner && m_fast_runner &&
256 m_slow_runner != m_fast_runner) {
257
258 m_slow_runner = m_slow_runner.next();
259 m_fast_runner = m_fast_runner.next().next();
260 m_loop_detected++;
261 }
262 if (count <= m_loop_detected)
263 return false; // No loop in the first m_loop_detected elements.
264 if (!m_slow_runner || !m_fast_runner)
265 return false; // Reached the end of the list. Definitely no loops.
266 return m_slow_runner == m_fast_runner;
267}
268
269template <StlType Stl>
270ValueObjectSP AbstractListFrontEnd<Stl>::GetItem(size_t idx) {
271 size_t advance = idx;
272 ListIterator<Stl> current(m_head);
273 if (idx > 0) {
274 auto cached_iterator = m_iterators.find(idx - 1);
275 if (cached_iterator != m_iterators.end()) {
276 current = cached_iterator->second;
277 advance = 1;
278 }
279 }
280 ValueObjectSP value_sp = current.advance(advance);
281 m_iterators[idx] = current;
282 return value_sp;
283}
284
285LibCxxForwardListFrontEnd::LibCxxForwardListFrontEnd(ValueObject &valobj)
286 : AbstractListFrontEnd(valobj) {
287 Update();
288}
289
290llvm::Expected<uint32_t> LibCxxForwardListFrontEnd::CalculateNumChildren() {
291 if (m_count != UINT32_MAX)
292 return m_count;
293
294 ListEntry<StlType::LibCxx> current(m_head);
295 m_count = 0;
296 while (current && m_count < m_list_capping_size) {
297 ++m_count;
298 current = current.next();
299 }
300 return m_count;
301}
302
303ValueObjectSP LibCxxForwardListFrontEnd::GetChildAtIndex(uint32_t idx) {
304 if (idx >= CalculateNumChildrenIgnoringErrors())
305 return nullptr;
306
307 if (!m_head)
308 return nullptr;
309
310 if (HasLoop(idx + 1))
311 return nullptr;
312
313 ValueObjectSP current_sp = GetItem(idx);
314 if (!current_sp)
315 return nullptr;
316
317 current_sp = current_sp->GetChildAtIndex(1); // get the __value_ child
318 if (!current_sp)
319 return nullptr;
320
321 // we need to copy current_sp into a new object otherwise we will end up with
322 // all items named __value_
323 DataExtractor data;
325 current_sp->GetData(data, error);
326 if (error.Fail())
327 return nullptr;
328
329 return CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(), data,
330 m_backend.GetExecutionContextRef(),
331 m_element_type);
332}
333
334lldb::ChildCacheState LibCxxForwardListFrontEnd::Update() {
335 AbstractListFrontEnd::Update();
336
337 Status err;
338 ValueObjectSP backend_addr(m_backend.AddressOf(err));
339 if (err.Fail() || !backend_addr)
341
342 auto list_base_sp = m_backend.GetChildAtIndex(0);
343 if (!list_base_sp)
345
346 // Anonymous strucutre index is in base class at index 0.
347 auto [impl_sp, is_compressed_pair] =
348 GetValueOrOldCompressedPair(*list_base_sp, /*anon_struct_idx=*/0,
349 "__before_begin_", "__before_begin_");
350 if (!impl_sp)
351 return ChildCacheState::eRefetch;
352
353 if (is_compressed_pair)
354 impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
355
356 if (!impl_sp)
357 return ChildCacheState::eRefetch;
358
359 m_head = impl_sp->GetChildMemberWithName("__next_").get();
360
361 return ChildCacheState::eRefetch;
362}
363
364LibCxxListFrontEnd::LibCxxListFrontEnd(lldb::ValueObjectSP valobj_sp)
365 : AbstractListFrontEnd(*valobj_sp) {
366 if (valobj_sp)
367 Update();
368}
369
370llvm::Expected<uint32_t> LibCxxListFrontEnd::CalculateNumChildren() {
371 if (m_count != UINT32_MAX)
372 return m_count;
373 if (!m_head || !m_tail || m_node_address == 0)
374 return 0;
375
376 auto [size_node_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
377 m_backend, /*anon_struct_idx=*/1, "__size_", "__size_alloc_");
378 if (is_compressed_pair)
379 size_node_sp = GetFirstValueOfLibCXXCompressedPair(*size_node_sp);
380
381 if (size_node_sp)
382 m_count = size_node_sp->GetValueAsUnsigned(UINT32_MAX);
383
384 if (m_count != UINT32_MAX)
385 return m_count;
386
387 uint64_t next_val = m_head->GetValueAsUnsigned(0);
388 uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
389 if (next_val == 0 || prev_val == 0)
390 return 0;
391 if (next_val == m_node_address)
392 return 0;
393 if (next_val == prev_val)
394 return 1;
395 uint64_t size = 2;
396 ListEntry<StlType::LibCxx> current(m_head);
397 while (current.next() && current.next().value() != m_node_address) {
398 size++;
399 current = current.next();
400 if (size > m_list_capping_size)
401 break;
402 }
403 return m_count = (size - 1);
404}
405
406lldb::ValueObjectSP LibCxxListFrontEnd::GetChildAtIndex(uint32_t idx) {
407 static ConstString g_value("__value_");
408 static ConstString g_next("__next_");
409
410 if (idx >= CalculateNumChildrenIgnoringErrors())
411 return lldb::ValueObjectSP();
412
413 if (!m_head || !m_tail || m_node_address == 0)
414 return lldb::ValueObjectSP();
415
416 if (HasLoop(idx + 1))
417 return lldb::ValueObjectSP();
418
419 ValueObjectSP current_sp = GetItem(idx);
420 if (!current_sp)
421 return lldb::ValueObjectSP();
422
423 current_sp = current_sp->GetChildAtIndex(1); // get the __value_ child
424 if (!current_sp)
425 return lldb::ValueObjectSP();
426
427 if (current_sp->GetName() == g_next) {
428 ProcessSP process_sp(current_sp->GetProcessSP());
429 if (!process_sp)
430 return lldb::ValueObjectSP();
431
432 // if we grabbed the __next_ pointer, then the child is one pointer deep-er
433 lldb::addr_t addr = current_sp->GetParent()->GetPointerValue().address;
434 addr = addr + 2 * process_sp->GetAddressByteSize();
435 ExecutionContext exe_ctx(process_sp);
436 current_sp =
437 CreateValueObjectFromAddress("__value_", addr, exe_ctx, m_element_type);
438 if (!current_sp)
439 return lldb::ValueObjectSP();
440 }
441
442 // we need to copy current_sp into a new object otherwise we will end up with
443 // all items named __value_
444 DataExtractor data;
446 current_sp->GetData(data, error);
447 if (error.Fail())
448 return lldb::ValueObjectSP();
449
450 StreamString name;
451 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
452 return CreateValueObjectFromData(name.GetString(), data,
453 m_backend.GetExecutionContextRef(),
454 m_element_type);
455}
456
457lldb::ChildCacheState LibCxxListFrontEnd::Update() {
458 AbstractListFrontEnd::Update();
459 m_tail = nullptr;
460 m_node_address = 0;
461
462 Status err;
463 ValueObjectSP backend_addr(m_backend.AddressOf(err));
464 if (err.Fail() || !backend_addr)
466 m_node_address = backend_addr->GetValueAsUnsigned(0);
467 if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS)
469 ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__end_"));
470 if (!impl_sp)
472 m_head = impl_sp->GetChildMemberWithName("__next_").get();
473 m_tail = impl_sp->GetChildMemberWithName("__prev_").get();
475}
476
477MsvcStlForwardListFrontEnd::MsvcStlForwardListFrontEnd(ValueObject &valobj)
478 : AbstractListFrontEnd(valobj) {
479 Update();
480}
481
482llvm::Expected<uint32_t> MsvcStlForwardListFrontEnd::CalculateNumChildren() {
483 if (m_count != UINT32_MAX)
484 return m_count;
485
486 ListEntry<StlType::MsvcStl> current(m_head);
487 m_count = 0;
488 while (current && m_count < m_list_capping_size) {
489 ++m_count;
490 current = current.next();
491 }
492 return m_count;
493}
494
495ValueObjectSP MsvcStlForwardListFrontEnd::GetChildAtIndex(uint32_t idx) {
496 if (idx >= CalculateNumChildrenIgnoringErrors())
497 return nullptr;
498
499 if (!m_head)
500 return nullptr;
501
502 if (HasLoop(idx + 1))
503 return nullptr;
504
505 ValueObjectSP current_sp = GetItem(idx);
506 if (!current_sp)
507 return nullptr;
508
509 current_sp = current_sp->GetChildAtIndex(1); // get the _Myval child
510 if (!current_sp)
511 return nullptr;
512
513 // we need to copy current_sp into a new object otherwise we will end up with
514 // all items named _Myval
515 DataExtractor data;
517 current_sp->GetData(data, error);
518 if (error.Fail())
519 return nullptr;
520
521 return CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(), data,
522 m_backend.GetExecutionContextRef(),
523 m_element_type);
524}
525
526lldb::ChildCacheState MsvcStlForwardListFrontEnd::Update() {
527 AbstractListFrontEnd::Update();
528
529 if (auto head_sp =
530 m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Myhead"}))
531 m_head = head_sp.get();
532
533 return ChildCacheState::eRefetch;
534}
535
536MsvcStlListFrontEnd::MsvcStlListFrontEnd(lldb::ValueObjectSP valobj_sp)
537 : AbstractListFrontEnd(*valobj_sp) {
538 if (valobj_sp)
539 Update();
540}
541
542llvm::Expected<uint32_t> MsvcStlListFrontEnd::CalculateNumChildren() {
543 if (m_count != UINT32_MAX)
544 return m_count;
545 if (!m_head || !m_tail)
546 return 0;
547
548 auto size_sp =
549 m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Mysize"});
550 if (!size_sp)
551 return llvm::createStringError("Failed to resolve size.");
552
553 m_count = size_sp->GetValueAsUnsigned(UINT32_MAX);
554 if (m_count == UINT32_MAX)
555 return llvm::createStringError("Failed to read size value.");
556
557 return m_count;
558}
559
560lldb::ValueObjectSP MsvcStlListFrontEnd::GetChildAtIndex(uint32_t idx) {
561 if (idx >= CalculateNumChildrenIgnoringErrors())
562 return lldb::ValueObjectSP();
563
564 if (!m_head || !m_tail)
565 return lldb::ValueObjectSP();
566
567 if (HasLoop(idx + 1))
568 return lldb::ValueObjectSP();
569
570 ValueObjectSP current_sp = GetItem(idx);
571 if (!current_sp)
572 return lldb::ValueObjectSP();
573
574 current_sp = current_sp->GetChildAtIndex(2); // get the _Myval child
575 if (!current_sp)
576 return lldb::ValueObjectSP();
577
578 // we need to copy current_sp into a new object otherwise we will end up with
579 // all items named _Myval
580 DataExtractor data;
582 current_sp->GetData(data, error);
583 if (error.Fail())
584 return lldb::ValueObjectSP();
585
586 StreamString name;
587 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
588 return CreateValueObjectFromData(name.GetString(), data,
589 m_backend.GetExecutionContextRef(),
590 m_element_type);
591}
592
593lldb::ChildCacheState MsvcStlListFrontEnd::Update() {
594 AbstractListFrontEnd::Update();
595 m_tail = nullptr;
596 m_head = nullptr;
597
598 ValueObjectSP last =
599 m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Myhead"});
600 if (!last)
602 ValueObjectSP first = last->GetChildMemberWithName("_Next");
603 if (!first)
605
606 m_head = first.get();
607 m_tail = last.get();
608
610}
611
614 return (valobj_sp ? new LibCxxListFrontEnd(valobj_sp) : nullptr);
615}
616
620 return valobj_sp ? new LibCxxForwardListFrontEnd(*valobj_sp) : nullptr;
621}
622
624 if (auto valobj_sp = valobj.GetNonSyntheticValue())
625 return valobj_sp->GetChildMemberWithName("_Mypair") != nullptr;
626
627 return false;
628}
629
632 lldb::ValueObjectSP valobj_sp) {
633 return (valobj_sp ? new MsvcStlListFrontEnd(valobj_sp) : nullptr);
634}
635
639 return valobj_sp ? new MsvcStlForwardListFrontEnd(*valobj_sp) : nullptr;
640}
static llvm::raw_ostream & error(Stream &strm)
static std::optional< size_t > CalculateNumChildren(CompilerType container_elem_type, uint64_t num_elements, CompilerType element_type)
Calculates the number of elements stored in a container (with element type 'container_elem_type') as ...
Generic representation of a type in a programming language.
CompilerType GetTypeTemplateArgument(size_t idx, bool expand_pack=false) const
size_t GetNumTemplateArguments(bool expand_pack=false) const
Return the number of template arguments the type has.
CompilerType GetNonReferenceType() const
If this type is a reference to a type (L value or R value reference), return a new type with the refe...
bool IsReferenceType(CompilerType *pointee_type=nullptr, bool *is_rvalue=nullptr) const
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
const char * GetCString() const
Get the string value as a C string.
bool Fail() const
Test for error condition.
Definition Status.cpp:294
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
virtual uint64_t GetValueAsUnsigned(uint64_t fail_value, bool *success=nullptr)
virtual lldb::ValueObjectSP GetChildMemberWithName(llvm::StringRef name, bool can_create=true)
lldb::ValueObjectSP GetChildAtNamePath(llvm::ArrayRef< llvm::StringRef > names)
virtual lldb::ValueObjectSP GetNonSyntheticValue()
#define LLDB_INVALID_ADDRESS
#define UINT32_MAX
std::optional< size_t > ExtractIndexFromString(const char *item_name)
SyntheticChildrenFrontEnd * MsvcStlListSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp)
SyntheticChildrenFrontEnd * MsvcStlForwardListSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp)
lldb::ValueObjectSP GetFirstValueOfLibCXXCompressedPair(ValueObject &pair)
Definition LibCxx.cpp:75
SyntheticChildrenFrontEnd * LibcxxStdListSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
std::pair< lldb::ValueObjectSP, bool > GetValueOrOldCompressedPair(ValueObject &obj, size_t anon_struct_idx, llvm::StringRef child_name, llvm::StringRef compressed_pair_name)
Returns the ValueObjectSP of the child of obj.
Definition LibCxx.cpp:106
bool IsMsvcStlList(ValueObject &valobj)
SyntheticChildrenFrontEnd * LibcxxStdForwardListSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
A class that represents a running process on the host machine.
bool operator!=(const Address &lhs, const Address &rhs)
Definition Address.cpp:1017
ChildCacheState
Specifies if children need to be re-computed after a call to SyntheticChildrenFrontEnd::Update.
@ eRefetch
Children need to be recomputed dynamically.
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
std::shared_ptr< lldb_private::Process > ProcessSP
uint64_t addr_t
Definition lldb-types.h:80
bool LLDB_API operator==(const SBAddress &lhs, const SBAddress &rhs)
Definition SBAddress.cpp:60