1 | //===-- LibCxxAtomic.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 "LibCxxAtomic.h" |
10 | #include "lldb/DataFormatters/FormattersHelpers.h" |
11 | |
12 | using namespace lldb; |
13 | using namespace lldb_private; |
14 | using namespace lldb_private::formatters; |
15 | |
16 | // |
17 | // We are supporting two versions of libc++ std::atomic |
18 | // |
19 | // Given std::atomic<int> i; |
20 | // |
21 | // The previous version of std::atomic was laid out like this |
22 | // |
23 | // (lldb) frame var -L -R i |
24 | // 0x00007ffeefbff9a0: (std::__1::atomic<int>) i = { |
25 | // 0x00007ffeefbff9a0: std::__1::__atomic_base<int, true> = { |
26 | // 0x00007ffeefbff9a0: std::__1::__atomic_base<int, false> = { |
27 | // 0x00007ffeefbff9a0: __a_ = 5 |
28 | // } |
29 | // } |
30 | // } |
31 | // |
32 | // In this case we need to obtain __a_ and the current version is laid out as so |
33 | // |
34 | // (lldb) frame var -L -R i |
35 | // 0x00007ffeefbff9b0: (std::__1::atomic<int>) i = { |
36 | // 0x00007ffeefbff9b0: std::__1::__atomic_base<int, true> = { |
37 | // 0x00007ffeefbff9b0: std::__1::__atomic_base<int, false> = { |
38 | // 0x00007ffeefbff9b0: __a_ = { |
39 | // 0x00007ffeefbff9b0: std::__1::__cxx_atomic_base_impl<int> = { |
40 | // 0x00007ffeefbff9b0: __a_value = 5 |
41 | // } |
42 | // } |
43 | // } |
44 | // } |
45 | //} |
46 | // |
47 | // In this case we need to obtain __a_value |
48 | // |
49 | // The below method covers both cases and returns the relevant member as a |
50 | // ValueObjectSP |
51 | // |
52 | ValueObjectSP |
53 | lldb_private::formatters::GetLibCxxAtomicValue(ValueObject &valobj) { |
54 | ValueObjectSP non_sythetic = valobj.GetNonSyntheticValue(); |
55 | if (!non_sythetic) |
56 | return {}; |
57 | |
58 | ValueObjectSP member__a_ = non_sythetic->GetChildMemberWithName(name: "__a_" ); |
59 | if (!member__a_) |
60 | return {}; |
61 | |
62 | ValueObjectSP member__a_value = |
63 | member__a_->GetChildMemberWithName(name: "__a_value" ); |
64 | if (!member__a_value) |
65 | return member__a_; |
66 | |
67 | return member__a_value; |
68 | } |
69 | |
70 | bool lldb_private::formatters::LibCxxAtomicSummaryProvider( |
71 | ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { |
72 | |
73 | if (ValueObjectSP atomic_value = GetLibCxxAtomicValue(valobj)) { |
74 | std::string summary; |
75 | if (atomic_value->GetSummaryAsCString(destination&: summary, options) && |
76 | summary.size() > 0) { |
77 | stream.Printf(format: "%s" , summary.c_str()); |
78 | return true; |
79 | } |
80 | } |
81 | |
82 | return false; |
83 | } |
84 | |
85 | namespace lldb_private { |
86 | namespace formatters { |
87 | class LibcxxStdAtomicSyntheticFrontEnd : public SyntheticChildrenFrontEnd { |
88 | public: |
89 | LibcxxStdAtomicSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); |
90 | |
91 | ~LibcxxStdAtomicSyntheticFrontEnd() override = default; |
92 | |
93 | llvm::Expected<uint32_t> CalculateNumChildren() override; |
94 | |
95 | lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override; |
96 | |
97 | lldb::ChildCacheState Update() override; |
98 | |
99 | llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override; |
100 | |
101 | private: |
102 | ValueObject *m_real_child = nullptr; |
103 | }; |
104 | } // namespace formatters |
105 | } // namespace lldb_private |
106 | |
107 | lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd:: |
108 | LibcxxStdAtomicSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) |
109 | : SyntheticChildrenFrontEnd(*valobj_sp) {} |
110 | |
111 | lldb::ChildCacheState |
112 | lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::Update() { |
113 | ValueObjectSP atomic_value = GetLibCxxAtomicValue(valobj&: m_backend); |
114 | if (atomic_value) |
115 | m_real_child = GetLibCxxAtomicValue(valobj&: m_backend).get(); |
116 | |
117 | return lldb::ChildCacheState::eRefetch; |
118 | } |
119 | |
120 | llvm::Expected<uint32_t> lldb_private::formatters:: |
121 | LibcxxStdAtomicSyntheticFrontEnd::CalculateNumChildren() { |
122 | return m_real_child ? 1 : 0; |
123 | } |
124 | |
125 | lldb::ValueObjectSP |
126 | lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::GetChildAtIndex( |
127 | uint32_t idx) { |
128 | if (idx == 0) |
129 | return m_real_child->GetSP()->Clone(new_name: ConstString("Value" )); |
130 | return nullptr; |
131 | } |
132 | |
133 | llvm::Expected<size_t> |
134 | lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd:: |
135 | GetIndexOfChildWithName(ConstString name) { |
136 | if (name == "Value" ) |
137 | return 0; |
138 | return llvm::createStringError(Fmt: "Type has no child named '%s'" , |
139 | Vals: name.AsCString()); |
140 | } |
141 | |
142 | SyntheticChildrenFrontEnd * |
143 | lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator( |
144 | CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { |
145 | if (valobj_sp) |
146 | return new LibcxxStdAtomicSyntheticFrontEnd(valobj_sp); |
147 | return nullptr; |
148 | } |
149 | |