1 //===-- LibCxxBitset.cpp ----------------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "LibCxx.h"
11 #include "lldb/DataFormatters/FormattersHelpers.h"
12 #include "lldb/Symbol/ClangASTContext.h"
13 #include "lldb/Target/Target.h"
14
15 using namespace lldb;
16 using namespace lldb_private;
17
18 namespace {
19
20 class BitsetFrontEnd : public SyntheticChildrenFrontEnd {
21 public:
22 BitsetFrontEnd(ValueObject &valobj);
23
GetIndexOfChildWithName(const ConstString & name)24 size_t GetIndexOfChildWithName(const ConstString &name) override {
25 return formatters::ExtractIndexFromString(name.GetCString());
26 }
27
MightHaveChildren()28 bool MightHaveChildren() override { return true; }
29 bool Update() override;
CalculateNumChildren()30 size_t CalculateNumChildren() override { return m_elements.size(); }
31 ValueObjectSP GetChildAtIndex(size_t idx) override;
32
33 private:
34 std::vector<ValueObjectSP> m_elements;
35 ValueObjectSP m_first;
36 CompilerType m_bool_type;
37 ByteOrder m_byte_order = eByteOrderInvalid;
38 uint8_t m_byte_size = 0;
39 };
40 } // namespace
41
BitsetFrontEnd(ValueObject & valobj)42 BitsetFrontEnd::BitsetFrontEnd(ValueObject &valobj)
43 : SyntheticChildrenFrontEnd(valobj) {
44 m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool);
45 if (auto target_sp = m_backend.GetTargetSP()) {
46 m_byte_order = target_sp->GetArchitecture().GetByteOrder();
47 m_byte_size = target_sp->GetArchitecture().GetAddressByteSize();
48 Update();
49 }
50 }
51
Update()52 bool BitsetFrontEnd::Update() {
53 m_elements.clear();
54 m_first.reset();
55
56 TargetSP target_sp = m_backend.GetTargetSP();
57 if (!target_sp)
58 return false;
59 size_t capping_size = target_sp->GetMaximumNumberOfChildrenToDisplay();
60
61 size_t size = 0;
62 if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(0))
63 size = arg->value.getLimitedValue(capping_size);
64
65 m_elements.assign(size, ValueObjectSP());
66
67 m_first = m_backend.GetChildMemberWithName(ConstString("__first_"), true);
68 return false;
69 }
70
GetChildAtIndex(size_t idx)71 ValueObjectSP BitsetFrontEnd::GetChildAtIndex(size_t idx) {
72 if (idx >= m_elements.size() || !m_first)
73 return ValueObjectSP();
74
75 if (m_elements[idx])
76 return m_elements[idx];
77
78 ExecutionContext ctx = m_backend.GetExecutionContextRef().Lock(false);
79 CompilerType type;
80 ValueObjectSP chunk;
81 // For small bitsets __first_ is not an array, but a plain size_t.
82 if (m_first->GetCompilerType().IsArrayType(&type, nullptr, nullptr)) {
83 llvm::Optional<uint64_t> bit_size =
84 type.GetBitSize(ctx.GetBestExecutionContextScope());
85 if (!bit_size || *bit_size == 0)
86 return {};
87 chunk = m_first->GetChildAtIndex(idx / *bit_size, true);
88 } else {
89 type = m_first->GetCompilerType();
90 chunk = m_first;
91 }
92 if (!type || !chunk)
93 return {};
94
95 llvm::Optional<uint64_t> bit_size =
96 type.GetBitSize(ctx.GetBestExecutionContextScope());
97 if (!bit_size || *bit_size == 0)
98 return {};
99 size_t chunk_idx = idx % *bit_size;
100 uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx));
101 DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size);
102
103 m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(),
104 data, ctx, m_bool_type);
105
106 return m_elements[idx];
107 }
108
LibcxxBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)109 SyntheticChildrenFrontEnd *formatters::LibcxxBitsetSyntheticFrontEndCreator(
110 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
111 if (valobj_sp)
112 return new BitsetFrontEnd(*valobj_sp);
113 return nullptr;
114 }
115