LLDB mainline
MsvcStlAtomic.cpp
Go to the documentation of this file.
1//===-- MsvcStlAtomic.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 "MsvcStl.h"
10
12#include "llvm/Support/ErrorExtras.h"
13
14using namespace lldb;
15using namespace lldb_private;
16
17namespace lldb_private {
18namespace formatters {
19
21public:
23 bool is_smart_ptr);
24
25 llvm::Expected<uint32_t> CalculateNumChildren() override;
26
27 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
28
30
31 llvm::Expected<size_t> GetIndexOfChildWithName(llvm::StringRef name) override;
32
33private:
35 bool m_is_smart_ptr = false;
36};
37
38} // namespace formatters
39} // namespace lldb_private
40
42 ValueObjectSP storage_sp = valobj.GetChildMemberWithName("_Storage");
43 if (!storage_sp)
44 return nullptr;
45
46 CompilerType backend_type = valobj.GetCompilerType();
47 if (!backend_type)
48 return nullptr;
49
50 CompilerType element_type = backend_type.GetTypeTemplateArgument(0);
51 if (!element_type) {
52 // PDB doesn't have info about templates, so use value_type which equals T.
53 element_type = backend_type.GetDirectNestedTypeWithName("value_type");
54
55 if (!element_type)
56 return nullptr;
57 }
58
59 return storage_sp->Cast(element_type);
60}
61
66
71
74 uint32_t idx) {
75 if (idx == 0 && m_storage)
76 return m_storage->GetSP();
77 return nullptr;
78}
79
82 m_storage = nullptr;
83
84 ValueObjectSP value;
85 if (m_is_smart_ptr) {
86 ValueObjectSP ptr = m_backend.GetChildMemberWithName("_Ptr");
87 if (!ptr)
88 return lldb::eRefetch;
89 value = ValueOfAtomic(*ptr);
90 } else {
91 value = ValueOfAtomic(m_backend);
92 }
93
94 if (value)
95 m_storage = value->Clone("Value").get();
96
97 return lldb::eRefetch;
98}
99
100llvm::Expected<size_t>
102 GetIndexOfChildWithName(llvm::StringRef name) {
103 if (name == "Value" || (m_is_smart_ptr && name == "$$dereference$$"))
104 return 0;
105 return llvm::createStringErrorV("type has no child named '{0}'", name);
106}
107
111 bool is_smart_ptr = false;
112 if (valobj_sp && IsMsvcStlAtomic(*valobj_sp, &is_smart_ptr))
113 return new MsvcStlAtomicSyntheticFrontEnd(valobj_sp, is_smart_ptr);
114 return nullptr;
115}
116
118 const CompilerType &locked_ptr_type) {
119 ConstString locked_name = locked_ptr_type.GetTypeName();
120 llvm::StringRef pointee_name = locked_name;
121 if (!pointee_name.consume_front("std::_Locked_pointer<"))
122 return {};
123 if (!pointee_name.consume_back(">"))
124 return {};
125
126 TypeQuery query(pointee_name, TypeQueryOptions::e_find_one);
127 TypeResults results;
128 target.GetImages().FindTypes(/*search_first=*/nullptr, query, results);
129 if (TypeSP type_sp = results.GetFirstType())
130 return type_sp->GetFullCompilerType();
131 return {};
132}
133
135 ValueObject &rep_wrap,
136 Stream &stream,
137 const TypeSummaryOptions &options) {
138 // rep_wrap: _Locked_pointer<_Ref_count_base> {
139 // static constexpr uintptr_t _Lock_mask = 3;
140 // static constexpr uintptr_t _Ptr_value_mask = ~_Lock_mask;
141 //
142 // atomic<uintptr_t> _Storage;
143 // }
144 ValueObjectSP rep_storage_sp = rep_wrap.GetChildMemberWithName("_Storage");
145 if (!rep_storage_sp)
146 return false;
147 ValueObjectSP rep_ptr_sp = ValueOfAtomic(*rep_storage_sp);
148 if (!rep_ptr_sp)
149 return false;
150
151 bool ok = false;
152 uint64_t rep_ptr_val = rep_ptr_sp->GetValueAsUnsigned(0, &ok);
153 if (!ok)
154 return false;
155
156 CompilerType rep_type = rep_wrap.GetCompilerType();
157 if (!rep_type)
158 return false;
159 CompilerDecl ptr_value_decl =
160 rep_type.GetStaticFieldWithName("_Ptr_value_mask");
161 if (!ptr_value_decl)
162 return false;
163 uint64_t rep_ptr_mask = ptr_value_decl.GetConstantValue().ULongLong(~(3ULL));
164 rep_ptr_val &= rep_ptr_mask;
165
166 CompilerType ref_count_base = rep_type.GetTypeTemplateArgument(0);
167 if (!ref_count_base) {
168 // PDB: Search for the type by name, as it doesn't know about templates.
169 // Unfortunately, there's no typedef inside the type.
170 TargetSP target = rep_wrap.GetTargetSP();
171 if (!target)
172 return false;
173 ref_count_base = FindLockedPointeeType(*target, rep_type);
174 if (!ref_count_base)
175 return false;
176 }
177
179 "", rep_ptr_val, rep_wrap.GetExecutionContextRef(), ref_count_base);
180 if (!rep)
181 return false;
182
183 return formatters::DumpMsvcStlSmartPointerSummary(ptr, *rep, rep_ptr_val,
184 stream, options);
185}
186
188 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
189 ValueObjectSP non_synth = valobj.GetNonSyntheticValue();
190 if (!non_synth)
191 return false;
192 ValueObjectSP value_sp = valobj.GetChildAtIndex(0);
193 if (!value_sp)
194 return false;
195
196 ValueObjectSP smart_ptr_rep = non_synth->GetChildMemberWithName("_Repptr");
197 if (smart_ptr_rep)
198 return AtomicSharedPtrSummaryProvider(*value_sp, *smart_ptr_rep, stream,
199 options);
200
201 std::string summary;
202 if (value_sp->GetSummaryAsCString(summary, options) && !summary.empty()) {
203 stream << summary;
204 return true;
205 }
206 return false;
207}
208
210 bool *is_smart_ptr) {
211 if (auto valobj_sp = valobj.GetNonSyntheticValue()) {
212 bool has_storage = valobj_sp->GetChildMemberWithName("_Storage") != nullptr;
213 bool has_smart =
214 !has_storage && valobj_sp->GetChildMemberWithName("_Ptr") != nullptr;
215 if (is_smart_ptr)
216 *is_smart_ptr = has_smart;
217
218 return has_storage || has_smart;
219 }
220 return false;
221}
static CompilerType FindLockedPointeeType(Target &target, const CompilerType &locked_ptr_type)
static ValueObjectSP ValueOfAtomic(ValueObject &valobj)
static bool AtomicSharedPtrSummaryProvider(ValueObject &ptr, ValueObject &rep_wrap, Stream &stream, const TypeSummaryOptions &options)
Represents a generic declaration such as a function declaration.
Scalar GetConstantValue() const
Generic representation of a type in a programming language.
CompilerType GetTypeTemplateArgument(size_t idx, bool expand_pack=false) const
CompilerDecl GetStaticFieldWithName(llvm::StringRef name) const
CompilerType GetDirectNestedTypeWithName(llvm::StringRef name) const
ConstString GetTypeName(bool BaseOnly=false) const
A uniqued constant string class.
Definition ConstString.h:40
void FindTypes(Module *search_first, const TypeQuery &query, lldb_private::TypeResults &results) const
Find types using a type-matching object that contains all search parameters.
unsigned long long ULongLong(unsigned long long fail_value=0) const
Definition Scalar.cpp:366
A stream class that can stream formatted output to a file.
Definition Stream.h:28
SyntheticChildrenFrontEnd(ValueObject &backend)
const ModuleList & GetImages() const
Get accessor for the images for this process.
Definition Target.h:1283
A class that contains all state required for type lookups.
This class tracks the state and results of a TypeQuery.
virtual lldb::ValueObjectSP GetChildAtIndex(uint32_t idx, bool can_create=true)
virtual lldb::ValueObjectSP GetChildMemberWithName(llvm::StringRef name, bool can_create=true)
lldb::TargetSP GetTargetSP() const
CompilerType GetCompilerType()
virtual lldb::ValueObjectSP GetNonSyntheticValue()
const ExecutionContextRef & GetExecutionContextRef() const
static lldb::ValueObjectSP CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, CompilerType type, bool do_deref=true, ValueObject *parent=nullptr)
Given an address either create a value object containing the value at that address,...
MsvcStlAtomicSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp, bool is_smart_ptr)
llvm::Expected< uint32_t > CalculateNumChildren() override
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override
llvm::Expected< size_t > GetIndexOfChildWithName(llvm::StringRef name) override
Determine the index of a named child.
lldb::ChildCacheState Update() override
This function is assumed to always succeed and if it fails, the front-end should know to deal with it...
bool DumpMsvcStlSmartPointerSummary(ValueObject &ptr, ValueObject &rep, uint64_t ctrl_addr, Stream &stream, const TypeSummaryOptions &options)
bool IsMsvcStlAtomic(ValueObject &valobj, bool *is_smart_ptr=nullptr)
SyntheticChildrenFrontEnd * MsvcStlAtomicSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp)
bool MsvcStlAtomicSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
A class that represents a running process on the host machine.
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::Type > TypeSP
std::shared_ptr< lldb_private::Target > TargetSP