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 lldb::ChildCacheState Update() override;
128
129protected:
130 AbstractListFrontEnd(ValueObject &valobj)
131 : SyntheticChildrenFrontEnd(valobj) {}
132
133 size_t m_count = 0;
134 ValueObject *m_head = nullptr;
135
136 static constexpr bool g_use_loop_detect = true;
137 size_t m_loop_detected = 0; // The number of elements that have had loop
138 // detection run over them.
139 ListEntry<Stl> m_slow_runner; // Used for loop detection
140 ListEntry<Stl> m_fast_runner; // Used for loop detection
141
142 size_t m_list_capping_size = 0;
143 CompilerType m_element_type;
144 std::map<size_t, ListIterator<Stl>> m_iterators;
145
146 bool HasLoop(size_t count);
147 ValueObjectSP GetItem(size_t idx);
148};
149
150class LibCxxForwardListFrontEnd : public AbstractListFrontEnd<StlType::LibCxx> {
151public:
152 LibCxxForwardListFrontEnd(ValueObject &valobj);
153
154 llvm::Expected<uint32_t> CalculateNumChildren() override;
155 ValueObjectSP GetChildAtIndex(uint32_t idx) override;
156 lldb::ChildCacheState Update() override;
157};
158
159class LibCxxListFrontEnd : public AbstractListFrontEnd<StlType::LibCxx> {
160public:
161 LibCxxListFrontEnd(lldb::ValueObjectSP valobj_sp);
162
163 llvm::Expected<uint32_t> CalculateNumChildren() override;
164
165 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
166
167 lldb::ChildCacheState Update() override;
168
169private:
170 lldb::addr_t m_node_address = 0;
171 ValueObject *m_tail = nullptr;
172};
173
174class MsvcStlForwardListFrontEnd
175 : public AbstractListFrontEnd<StlType::MsvcStl> {
176public:
177 MsvcStlForwardListFrontEnd(ValueObject &valobj);
178
179 llvm::Expected<uint32_t> CalculateNumChildren() override;
180 ValueObjectSP GetChildAtIndex(uint32_t idx) override;
181 lldb::ChildCacheState Update() override;
182};
183
184class MsvcStlListFrontEnd : public AbstractListFrontEnd<StlType::MsvcStl> {
185public:
186 MsvcStlListFrontEnd(lldb::ValueObjectSP valobj_sp);
187
188 llvm::Expected<uint32_t> CalculateNumChildren() override;
189
190 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
191
192 lldb::ChildCacheState Update() override;
193
194private:
195 ValueObject *m_tail = nullptr;
196};
197
198/// Gets the (forward-)list element type from the head node instead of the
199/// template arguments. This is needed with PDB as it doesn't have info about
200/// the template arguments.
201CompilerType GetMsvcStlElementTypeFromHead(ValueObject &head) {
202 auto val_sp = head.GetChildMemberWithName("_Myval");
203 if (val_sp)
204 return val_sp->GetCompilerType();
205 return CompilerType();
206}
207
208} // end anonymous namespace
209
210template <StlType Stl>
211lldb::ChildCacheState AbstractListFrontEnd<Stl>::Update() {
212 m_loop_detected = 0;
213 m_count = UINT32_MAX;
214 m_head = nullptr;
215 m_list_capping_size = 0;
216 m_slow_runner.SetEntry(nullptr);
217 m_fast_runner.SetEntry(nullptr);
218 m_iterators.clear();
219
220 if (m_backend.GetTargetSP())
221 m_list_capping_size =
222 m_backend.GetTargetSP()->GetMaximumNumberOfChildrenToDisplay();
223 if (m_list_capping_size == 0)
224 m_list_capping_size = 255;
225
226 CompilerType list_type = m_backend.GetCompilerType();
227 if (list_type.IsReferenceType())
228 list_type = list_type.GetNonReferenceType();
229
230 if (list_type.GetNumTemplateArguments() == 0)
232 m_element_type = list_type.GetTypeTemplateArgument(0);
233
235}
236
237template <StlType Stl> bool AbstractListFrontEnd<Stl>::HasLoop(size_t count) {
238 if (!g_use_loop_detect)
239 return false;
240 // don't bother checking for a loop if we won't actually need to jump nodes
241 if (m_count < 2)
242 return false;
243
244 if (m_loop_detected == 0) {
245 // This is the first time we are being run (after the last update). Set up
246 // the loop invariant for the first element.
247 m_slow_runner = ListEntry<Stl>(m_head).next();
248 m_fast_runner = m_slow_runner.next();
249 m_loop_detected = 1;
250 }
251
252 // Loop invariant:
253 // Loop detection has been run over the first m_loop_detected elements. If
254 // m_slow_runner == m_fast_runner then the loop has been detected after
255 // m_loop_detected elements.
256 const size_t steps_to_run = std::min(count, m_count);
257 while (m_loop_detected < steps_to_run && m_slow_runner && m_fast_runner &&
258 m_slow_runner != m_fast_runner) {
259
260 m_slow_runner = m_slow_runner.next();
261 m_fast_runner = m_fast_runner.next().next();
262 m_loop_detected++;
263 }
264 if (count <= m_loop_detected)
265 return false; // No loop in the first m_loop_detected elements.
266 if (!m_slow_runner || !m_fast_runner)
267 return false; // Reached the end of the list. Definitely no loops.
268 return m_slow_runner == m_fast_runner;
269}
270
271template <StlType Stl>
272ValueObjectSP AbstractListFrontEnd<Stl>::GetItem(size_t idx) {
273 size_t advance = idx;
274 ListIterator<Stl> current(m_head);
275 if (idx > 0) {
276 auto cached_iterator = m_iterators.find(idx - 1);
277 if (cached_iterator != m_iterators.end()) {
278 current = cached_iterator->second;
279 advance = 1;
280 }
281 }
282 ValueObjectSP value_sp = current.advance(advance);
283 m_iterators[idx] = current;
284 return value_sp;
285}
286
287LibCxxForwardListFrontEnd::LibCxxForwardListFrontEnd(ValueObject &valobj)
288 : AbstractListFrontEnd(valobj) {
289 Update();
290}
291
292llvm::Expected<uint32_t> LibCxxForwardListFrontEnd::CalculateNumChildren() {
293 if (m_count != UINT32_MAX)
294 return m_count;
295
296 ListEntry<StlType::LibCxx> current(m_head);
297 m_count = 0;
298 while (current && m_count < m_list_capping_size) {
299 ++m_count;
300 current = current.next();
301 }
302 return m_count;
303}
304
305ValueObjectSP LibCxxForwardListFrontEnd::GetChildAtIndex(uint32_t idx) {
306 if (idx >= CalculateNumChildrenIgnoringErrors())
307 return nullptr;
308
309 if (!m_head)
310 return nullptr;
311
312 if (HasLoop(idx + 1))
313 return nullptr;
314
315 ValueObjectSP current_sp = GetItem(idx);
316 if (!current_sp)
317 return nullptr;
318
319 current_sp = current_sp->GetChildAtIndex(1); // get the __value_ child
320 if (!current_sp)
321 return nullptr;
322
323 // we need to copy current_sp into a new object otherwise we will end up with
324 // all items named __value_
325 DataExtractor data;
327 current_sp->GetData(data, error);
328 if (error.Fail())
329 return nullptr;
330
331 return CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(), data,
332 m_backend.GetExecutionContextRef(),
333 m_element_type);
334}
335
336lldb::ChildCacheState LibCxxForwardListFrontEnd::Update() {
337 AbstractListFrontEnd::Update();
338
339 Status err;
340 ValueObjectSP backend_addr(m_backend.AddressOf(err));
341 if (err.Fail() || !backend_addr)
343
344 auto list_base_sp = m_backend.GetChildAtIndex(0);
345 if (!list_base_sp)
347
348 // Anonymous strucutre index is in base class at index 0.
349 auto [impl_sp, is_compressed_pair] = GetValueOrOldCompressedPair(
350 *list_base_sp, "__before_begin_", "__before_begin_");
351 if (!impl_sp)
352 return ChildCacheState::eRefetch;
353
354 if (is_compressed_pair)
355 impl_sp = GetFirstValueOfLibCXXCompressedPair(*impl_sp);
356
357 if (!impl_sp)
358 return ChildCacheState::eRefetch;
359
360 m_head = impl_sp->GetChildMemberWithName("__next_").get();
361
362 return ChildCacheState::eRefetch;
363}
364
365LibCxxListFrontEnd::LibCxxListFrontEnd(lldb::ValueObjectSP valobj_sp)
366 : AbstractListFrontEnd(*valobj_sp) {
367 if (valobj_sp)
368 Update();
369}
370
371llvm::Expected<uint32_t> LibCxxListFrontEnd::CalculateNumChildren() {
372 if (m_count != UINT32_MAX)
373 return m_count;
374 if (!m_head || !m_tail || m_node_address == 0)
375 return 0;
376
377 auto [size_node_sp, is_compressed_pair] =
378 GetValueOrOldCompressedPair(m_backend, "__size_", "__size_alloc_");
379 if (is_compressed_pair)
380 size_node_sp = GetFirstValueOfLibCXXCompressedPair(*size_node_sp);
381
382 if (size_node_sp)
383 m_count = size_node_sp->GetValueAsUnsigned(UINT32_MAX);
384
385 if (m_count != UINT32_MAX)
386 return m_count;
387
388 uint64_t next_val = m_head->GetValueAsUnsigned(0);
389 uint64_t prev_val = m_tail->GetValueAsUnsigned(0);
390 if (next_val == 0 || prev_val == 0)
391 return 0;
392 if (next_val == m_node_address)
393 return 0;
394 if (next_val == prev_val)
395 return 1;
396 uint64_t size = 2;
397 ListEntry<StlType::LibCxx> current(m_head);
398 while (current.next() && current.next().value() != m_node_address) {
399 size++;
400 current = current.next();
401 if (size > m_list_capping_size)
402 break;
403 }
404 return m_count = (size - 1);
405}
406
407lldb::ValueObjectSP LibCxxListFrontEnd::GetChildAtIndex(uint32_t idx) {
408 static ConstString g_value("__value_");
409 static ConstString g_next("__next_");
410
411 if (idx >= CalculateNumChildrenIgnoringErrors())
412 return lldb::ValueObjectSP();
413
414 if (!m_head || !m_tail || m_node_address == 0)
415 return lldb::ValueObjectSP();
416
417 if (HasLoop(idx + 1))
418 return lldb::ValueObjectSP();
419
420 ValueObjectSP current_sp = GetItem(idx);
421 if (!current_sp)
422 return lldb::ValueObjectSP();
423
424 current_sp = current_sp->GetChildAtIndex(1); // get the __value_ child
425 if (!current_sp)
426 return lldb::ValueObjectSP();
427
428 if (current_sp->GetName() == g_next) {
429 ProcessSP process_sp(current_sp->GetProcessSP());
430 if (!process_sp)
431 return lldb::ValueObjectSP();
432
433 // if we grabbed the __next_ pointer, then the child is one pointer deep-er
434 lldb::addr_t addr = current_sp->GetParent()->GetPointerValue().address;
435 addr = addr + 2 * process_sp->GetAddressByteSize();
436 ExecutionContext exe_ctx(process_sp);
437 current_sp =
438 CreateValueObjectFromAddress("__value_", addr, exe_ctx, m_element_type);
439 if (!current_sp)
440 return lldb::ValueObjectSP();
441 }
442
443 // we need to copy current_sp into a new object otherwise we will end up with
444 // all items named __value_
445 DataExtractor data;
447 current_sp->GetData(data, error);
448 if (error.Fail())
449 return lldb::ValueObjectSP();
450
451 StreamString name;
452 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
453 return CreateValueObjectFromData(name.GetString(), data,
454 m_backend.GetExecutionContextRef(),
455 m_element_type);
456}
457
458lldb::ChildCacheState LibCxxListFrontEnd::Update() {
459 AbstractListFrontEnd::Update();
460 m_tail = nullptr;
461 m_node_address = 0;
462
463 Status err;
464 ValueObjectSP backend_addr(m_backend.AddressOf(err));
465 if (err.Fail() || !backend_addr)
467 m_node_address = backend_addr->GetValueAsUnsigned(0);
468 if (!m_node_address || m_node_address == LLDB_INVALID_ADDRESS)
470 ValueObjectSP impl_sp(m_backend.GetChildMemberWithName("__end_"));
471 if (!impl_sp)
473 m_head = impl_sp->GetChildMemberWithName("__next_").get();
474 m_tail = impl_sp->GetChildMemberWithName("__prev_").get();
476}
477
478MsvcStlForwardListFrontEnd::MsvcStlForwardListFrontEnd(ValueObject &valobj)
479 : AbstractListFrontEnd(valobj) {
480 Update();
481}
482
483llvm::Expected<uint32_t> MsvcStlForwardListFrontEnd::CalculateNumChildren() {
484 if (m_count != UINT32_MAX)
485 return m_count;
486
487 ListEntry<StlType::MsvcStl> current(m_head);
488 m_count = 0;
489 while (current && m_count < m_list_capping_size) {
490 ++m_count;
491 current = current.next();
492 }
493 return m_count;
494}
495
496ValueObjectSP MsvcStlForwardListFrontEnd::GetChildAtIndex(uint32_t idx) {
497 if (idx >= CalculateNumChildrenIgnoringErrors())
498 return nullptr;
499
500 if (!m_head)
501 return nullptr;
502
503 if (HasLoop(idx + 1))
504 return nullptr;
505
506 ValueObjectSP current_sp = GetItem(idx);
507 if (!current_sp)
508 return nullptr;
509
510 current_sp = current_sp->GetChildAtIndex(1); // get the _Myval child
511 if (!current_sp)
512 return nullptr;
513
514 // we need to copy current_sp into a new object otherwise we will end up with
515 // all items named _Myval
516 DataExtractor data;
518 current_sp->GetData(data, error);
519 if (error.Fail())
520 return nullptr;
521
522 return CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(), data,
523 m_backend.GetExecutionContextRef(),
524 m_element_type);
525}
526
527lldb::ChildCacheState MsvcStlForwardListFrontEnd::Update() {
528 AbstractListFrontEnd::Update();
529
530 if (auto head_sp =
531 m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Myhead"}))
532 m_head = head_sp.get();
533
534 // With PDB, we can't get the element type from the template arguments
535 if (!m_element_type && m_head)
536 m_element_type = GetMsvcStlElementTypeFromHead(*m_head);
537
538 return ChildCacheState::eRefetch;
539}
540
541MsvcStlListFrontEnd::MsvcStlListFrontEnd(lldb::ValueObjectSP valobj_sp)
542 : AbstractListFrontEnd(*valobj_sp) {
543 if (valobj_sp)
544 Update();
545}
546
547llvm::Expected<uint32_t> MsvcStlListFrontEnd::CalculateNumChildren() {
548 if (m_count != UINT32_MAX)
549 return m_count;
550 if (!m_head || !m_tail)
551 return 0;
552
553 auto size_sp =
554 m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Mysize"});
555 if (!size_sp)
556 return llvm::createStringError("Failed to resolve size.");
557
558 m_count = size_sp->GetValueAsUnsigned(UINT32_MAX);
559 if (m_count == UINT32_MAX)
560 return llvm::createStringError("Failed to read size value.");
561
562 return m_count;
563}
564
565lldb::ValueObjectSP MsvcStlListFrontEnd::GetChildAtIndex(uint32_t idx) {
566 if (idx >= CalculateNumChildrenIgnoringErrors())
567 return lldb::ValueObjectSP();
568
569 if (!m_head || !m_tail)
570 return lldb::ValueObjectSP();
571
572 if (HasLoop(idx + 1))
573 return lldb::ValueObjectSP();
574
575 ValueObjectSP current_sp = GetItem(idx);
576 if (!current_sp)
577 return lldb::ValueObjectSP();
578
579 current_sp = current_sp->GetChildAtIndex(2); // get the _Myval child
580 if (!current_sp)
581 return lldb::ValueObjectSP();
582
583 // we need to copy current_sp into a new object otherwise we will end up with
584 // all items named _Myval
585 DataExtractor data;
587 current_sp->GetData(data, error);
588 if (error.Fail())
589 return lldb::ValueObjectSP();
590
591 StreamString name;
592 name.Printf("[%" PRIu64 "]", (uint64_t)idx);
593 return CreateValueObjectFromData(name.GetString(), data,
594 m_backend.GetExecutionContextRef(),
595 m_element_type);
596}
597
598lldb::ChildCacheState MsvcStlListFrontEnd::Update() {
599 AbstractListFrontEnd::Update();
600 m_tail = nullptr;
601 m_head = nullptr;
602
603 ValueObjectSP last =
604 m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Myhead"});
605 if (!last)
607 ValueObjectSP first = last->GetChildMemberWithName("_Next");
608 if (!first)
610
611 m_head = first.get();
612 m_tail = last.get();
613
614 // With PDB, we can't get the element type from the template arguments
615 if (!m_element_type && m_head)
616 m_element_type = GetMsvcStlElementTypeFromHead(*m_head);
617
619}
620
622 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
623 return (valobj_sp ? new LibCxxListFrontEnd(valobj_sp) : nullptr);
624}
625
626SyntheticChildrenFrontEnd *
628 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
629 return valobj_sp ? new LibCxxForwardListFrontEnd(*valobj_sp) : nullptr;
630}
631
633 if (auto valobj_sp = valobj.GetNonSyntheticValue())
634 return valobj_sp->GetChildMemberWithName("_Mypair") != nullptr;
635
636 return false;
637}
638
641 lldb::ValueObjectSP valobj_sp) {
642 return (valobj_sp ? new MsvcStlListFrontEnd(valobj_sp) : nullptr);
643}
644
648 return valobj_sp ? new MsvcStlForwardListFrontEnd(*valobj_sp) : nullptr;
649}
static llvm::raw_ostream & error(Stream &strm)
static void advance(TSLexer *lexer)
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
bool Fail() const
Test for error condition.
Definition Status.cpp:293
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
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, 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