/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Language/CPlusPlus/GenericBitset.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- GenericBitset.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 "LibStdcpp.h" |
11 | | #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" |
12 | | #include "lldb/DataFormatters/FormattersHelpers.h" |
13 | | #include "lldb/Target/Target.h" |
14 | | #include <optional> |
15 | | |
16 | | using namespace lldb; |
17 | | using namespace lldb_private; |
18 | | |
19 | | namespace { |
20 | | |
21 | | /// This class can be used for handling bitsets from both libcxx and libstdcpp. |
22 | | class GenericBitsetFrontEnd : public SyntheticChildrenFrontEnd { |
23 | | public: |
24 | | enum class StdLib { |
25 | | LibCxx, |
26 | | LibStdcpp, |
27 | | }; |
28 | | |
29 | | GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib); |
30 | | |
31 | 0 | size_t GetIndexOfChildWithName(ConstString name) override { |
32 | 0 | return formatters::ExtractIndexFromString(name.GetCString()); |
33 | 0 | } |
34 | | |
35 | 2 | bool MightHaveChildren() override { return true; } |
36 | | bool Update() override; |
37 | 20 | size_t CalculateNumChildren() override { return m_elements.size(); } |
38 | | ValueObjectSP GetChildAtIndex(size_t idx) override; |
39 | | |
40 | | private: |
41 | | llvm::StringRef GetDataContainerMemberName(); |
42 | | |
43 | | // The lifetime of a ValueObject and all its derivative ValueObjects |
44 | | // (children, clones, etc.) is managed by a ClusterManager. These |
45 | | // objects are only destroyed when every shared pointer to any of them |
46 | | // is destroyed, so we must not store a shared pointer to any ValueObject |
47 | | // derived from our backend ValueObject (since we're in the same cluster). |
48 | | // Value objects created from raw data (i.e. in a different cluster) must |
49 | | // be referenced via shared pointer to keep them alive, however. |
50 | | std::vector<ValueObjectSP> m_elements; |
51 | | ValueObject *m_first = nullptr; |
52 | | CompilerType m_bool_type; |
53 | | ByteOrder m_byte_order = eByteOrderInvalid; |
54 | | uint8_t m_byte_size = 0; |
55 | | StdLib m_stdlib; |
56 | | }; |
57 | | } // namespace |
58 | | |
59 | | GenericBitsetFrontEnd::GenericBitsetFrontEnd(ValueObject &valobj, StdLib stdlib) |
60 | 20 | : SyntheticChildrenFrontEnd(valobj), m_stdlib(stdlib) { |
61 | 20 | m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool); |
62 | 20 | if (auto target_sp = m_backend.GetTargetSP()) { |
63 | 20 | m_byte_order = target_sp->GetArchitecture().GetByteOrder(); |
64 | 20 | m_byte_size = target_sp->GetArchitecture().GetAddressByteSize(); |
65 | 20 | Update(); |
66 | 20 | } |
67 | 20 | } |
68 | | |
69 | 40 | llvm::StringRef GenericBitsetFrontEnd::GetDataContainerMemberName() { |
70 | 40 | static constexpr llvm::StringLiteral s_libcxx_case("__first_"); |
71 | 40 | static constexpr llvm::StringLiteral s_libstdcpp_case("_M_w"); |
72 | 40 | switch (m_stdlib) { |
73 | 40 | case StdLib::LibCxx: |
74 | 40 | return s_libcxx_case; |
75 | 0 | case StdLib::LibStdcpp: |
76 | 0 | return s_libstdcpp_case; |
77 | 40 | } |
78 | 0 | llvm_unreachable("Unknown StdLib enum"); |
79 | 0 | } |
80 | | |
81 | 40 | bool GenericBitsetFrontEnd::Update() { |
82 | 40 | m_elements.clear(); |
83 | 40 | m_first = nullptr; |
84 | | |
85 | 40 | TargetSP target_sp = m_backend.GetTargetSP(); |
86 | 40 | if (!target_sp) |
87 | 0 | return false; |
88 | | |
89 | 40 | size_t size = 0; |
90 | | |
91 | 40 | if (auto arg = m_backend.GetCompilerType().GetIntegralTemplateArgument(0)) |
92 | 40 | size = arg->value.getLimitedValue(); |
93 | | |
94 | 40 | m_elements.assign(size, ValueObjectSP()); |
95 | 40 | m_first = |
96 | 40 | m_backend.GetChildMemberWithName(GetDataContainerMemberName()).get(); |
97 | 40 | return false; |
98 | 40 | } |
99 | | |
100 | 6.49k | ValueObjectSP GenericBitsetFrontEnd::GetChildAtIndex(size_t idx) { |
101 | 6.49k | if (idx >= m_elements.size() || !m_first) |
102 | 0 | return ValueObjectSP(); |
103 | | |
104 | 6.49k | if (m_elements[idx]) |
105 | 0 | return m_elements[idx]; |
106 | | |
107 | 6.49k | ExecutionContext ctx = m_backend.GetExecutionContextRef().Lock(false); |
108 | 6.49k | CompilerType type; |
109 | 6.49k | ValueObjectSP chunk; |
110 | | // For small bitsets __first_ is not an array, but a plain size_t. |
111 | 6.49k | if (m_first->GetCompilerType().IsArrayType(&type)) { |
112 | 6.42k | std::optional<uint64_t> bit_size = |
113 | 6.42k | type.GetBitSize(ctx.GetBestExecutionContextScope()); |
114 | 6.42k | if (!bit_size || *bit_size == 0) |
115 | 0 | return {}; |
116 | 6.42k | chunk = m_first->GetChildAtIndex(idx / *bit_size); |
117 | 6.42k | } else { |
118 | 78 | type = m_first->GetCompilerType(); |
119 | 78 | chunk = m_first->GetSP(); |
120 | 78 | } |
121 | 6.49k | if (!type || !chunk) |
122 | 0 | return {}; |
123 | | |
124 | 6.49k | std::optional<uint64_t> bit_size = |
125 | 6.49k | type.GetBitSize(ctx.GetBestExecutionContextScope()); |
126 | 6.49k | if (!bit_size || *bit_size == 0) |
127 | 0 | return {}; |
128 | 6.49k | size_t chunk_idx = idx % *bit_size; |
129 | 6.49k | uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx)); |
130 | 6.49k | DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size); |
131 | | |
132 | 6.49k | m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(), |
133 | 6.49k | data, ctx, m_bool_type); |
134 | | |
135 | 6.49k | return m_elements[idx]; |
136 | 6.49k | } |
137 | | |
138 | | SyntheticChildrenFrontEnd *formatters::LibStdcppBitsetSyntheticFrontEndCreator( |
139 | 0 | CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { |
140 | 0 | if (valobj_sp) |
141 | 0 | return new GenericBitsetFrontEnd(*valobj_sp, |
142 | 0 | GenericBitsetFrontEnd::StdLib::LibStdcpp); |
143 | 0 | return nullptr; |
144 | 0 | } |
145 | | |
146 | | SyntheticChildrenFrontEnd *formatters::LibcxxBitsetSyntheticFrontEndCreator( |
147 | 20 | CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { |
148 | 20 | if (valobj_sp) |
149 | 20 | return new GenericBitsetFrontEnd(*valobj_sp, |
150 | 20 | GenericBitsetFrontEnd::StdLib::LibCxx); |
151 | 0 | return nullptr; |
152 | 20 | } |