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