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 
11 using namespace lldb;
12 using namespace lldb_private;
13 using namespace lldb_private::formatters;
14 
15 //
16 // We are supporting two versions of libc++ std::atomic
17 //
18 // Given std::atomic<int> i;
19 //
20 // The previous version of std::atomic was laid out like this
21 //
22 // (lldb) frame var -L -R i
23 // 0x00007ffeefbff9a0: (std::__1::atomic<int>) i = {
24 // 0x00007ffeefbff9a0:   std::__1::__atomic_base<int, true> = {
25 // 0x00007ffeefbff9a0:     std::__1::__atomic_base<int, false> = {
26 // 0x00007ffeefbff9a0:       __a_ = 5
27 //        }
28 //    }
29 // }
30 //
31 // In this case we need to obtain __a_ and the current version is laid out as so
32 //
33 // (lldb) frame var -L -R i
34 // 0x00007ffeefbff9b0: (std::__1::atomic<int>) i = {
35 // 0x00007ffeefbff9b0:   std::__1::__atomic_base<int, true> = {
36 // 0x00007ffeefbff9b0:     std::__1::__atomic_base<int, false> = {
37 // 0x00007ffeefbff9b0:       __a_ = {
38 // 0x00007ffeefbff9b0:         std::__1::__cxx_atomic_base_impl<int> = {
39 // 0x00007ffeefbff9b0:           __a_value = 5
40 //                }
41 //          }
42 //       }
43 //    }
44 //}
45 //
46 // In this case we need to obtain __a_value
47 //
48 // The below method covers both cases and returns the relevant member as a
49 // ValueObjectSP
50 //
51 ValueObjectSP
52 lldb_private::formatters::GetLibCxxAtomicValue(ValueObject &valobj) {
53   ValueObjectSP non_sythetic = valobj.GetNonSyntheticValue();
54   if (!non_sythetic)
55     return {};
56 
57   ValueObjectSP member__a_ =
58       non_sythetic->GetChildMemberWithName(ConstString("__a_"), true);
59   if (!member__a_)
60     return {};
61 
62   ValueObjectSP member__a_value =
63       member__a_->GetChildMemberWithName(ConstString("__a_value"), true);
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(summary, options) &&
76         summary.size() > 0) {
77       stream.Printf("%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   size_t CalculateNumChildren() override;
94 
95   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
96 
97   bool Update() override;
98 
99   bool MightHaveChildren() override;
100 
101   size_t GetIndexOfChildWithName(ConstString name) override;
102 
103   lldb::ValueObjectSP GetSyntheticValue() override;
104 
105 private:
106   ValueObject *m_real_child;
107 };
108 } // namespace formatters
109 } // namespace lldb_private
110 
111 lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::
112     LibcxxStdAtomicSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
113     : SyntheticChildrenFrontEnd(*valobj_sp), m_real_child(nullptr) {}
114 
115 bool lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::Update() {
116   ValueObjectSP atomic_value = GetLibCxxAtomicValue(m_backend);
117   if (atomic_value)
118     m_real_child = GetLibCxxAtomicValue(m_backend).get();
119 
120   return false;
121 }
122 
123 bool lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::
124     MightHaveChildren() {
125   return true;
126 }
127 
128 size_t lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::
129     CalculateNumChildren() {
130   return m_real_child ? m_real_child->GetNumChildren() : 0;
131 }
132 
133 lldb::ValueObjectSP
134 lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::GetChildAtIndex(
135     size_t idx) {
136   return m_real_child ? m_real_child->GetChildAtIndex(idx, true) : nullptr;
137 }
138 
139 size_t lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::
140     GetIndexOfChildWithName(ConstString name) {
141   return m_real_child ? m_real_child->GetIndexOfChildWithName(name)
142                       : UINT32_MAX;
143 }
144 
145 lldb::ValueObjectSP lldb_private::formatters::LibcxxStdAtomicSyntheticFrontEnd::
146     GetSyntheticValue() {
147   if (m_real_child && m_real_child->CanProvideValue())
148     return m_real_child->GetSP();
149   return nullptr;
150 }
151 
152 SyntheticChildrenFrontEnd *
153 lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator(
154     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
155   if (valobj_sp)
156     return new LibcxxStdAtomicSyntheticFrontEnd(valobj_sp);
157   return nullptr;
158 }
159