LLDB mainline
LibStdcpp.cpp
Go to the documentation of this file.
1//===-- LibStdcpp.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 "LibStdcpp.h"
10#include "LibCxx.h"
11
17#include "lldb/Target/Target.h"
19#include "lldb/Utility/Endian.h"
20#include "lldb/Utility/Status.h"
21#include "lldb/Utility/Stream.h"
24#include <optional>
25
26using namespace lldb;
27using namespace lldb_private;
28using namespace lldb_private::formatters;
29
30namespace {
31
32class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
33 /*
34 (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char,
35 std::char_traits<char>, std::allocator<char> > > >) ibeg = {
36 (_Base_ptr) _M_node = 0x0000000100103910 {
37 (std::_Rb_tree_color) _M_color = _S_black
38 (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
39 (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
40 (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
41 }
42 }
43 */
44
45public:
46 explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
47
48 llvm::Expected<uint32_t> CalculateNumChildren() override;
49
50 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
51
52 lldb::ChildCacheState Update() override;
53
54 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
55
56private:
57 ExecutionContextRef m_exe_ctx_ref;
58 lldb::addr_t m_pair_address = 0;
59 CompilerType m_pair_type;
60 lldb::ValueObjectSP m_pair_sp;
61};
62
63class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
64public:
65 explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
66
67 llvm::Expected<uint32_t> CalculateNumChildren() override;
68
69 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
70
71 lldb::ChildCacheState Update() override;
72
73 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
74
75private:
76
77 // The lifetime of a ValueObject and all its derivative ValueObjects
78 // (children, clones, etc.) is managed by a ClusterManager. These
79 // objects are only destroyed when every shared pointer to any of them
80 // is destroyed, so we must not store a shared pointer to any ValueObject
81 // derived from our backend ValueObject (since we're in the same cluster).
82 ValueObject *m_ptr_obj = nullptr; // Underlying pointer (held, not owned)
83};
84
85} // end of anonymous namespace
86
87LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd(
88 lldb::ValueObjectSP valobj_sp)
89 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type(),
90 m_pair_sp() {
91 if (valobj_sp)
92 Update();
93}
94
95lldb::ChildCacheState LibstdcppMapIteratorSyntheticFrontEnd::Update() {
96 ValueObjectSP valobj_sp = m_backend.GetSP();
97 if (!valobj_sp)
99
100 TargetSP target_sp(valobj_sp->GetTargetSP());
101
102 if (!target_sp)
104
105 bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
106
107 if (!valobj_sp)
109 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
110
111 ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName("_M_node"));
112 if (!_M_node_sp)
114
115 m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
116 if (m_pair_address == 0)
118
119 m_pair_address += (is_64bit ? 32 : 16);
120
121 CompilerType my_type(valobj_sp->GetCompilerType());
122 if (my_type.GetNumTemplateArguments() >= 1) {
123 CompilerType pair_type = my_type.GetTypeTemplateArgument(0);
124 if (!pair_type)
126 m_pair_type = pair_type;
127 } else
129
131}
132
133llvm::Expected<uint32_t>
134LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
135 return 2;
136}
137
139LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
140 if (m_pair_address != 0 && m_pair_type) {
141 if (!m_pair_sp)
142 m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address,
143 m_exe_ctx_ref, m_pair_type);
144 if (m_pair_sp)
145 return m_pair_sp->GetChildAtIndex(idx);
146 }
147 return lldb::ValueObjectSP();
148}
149
150llvm::Expected<size_t>
151LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
152 ConstString name) {
153 if (name == "first")
154 return 0;
155 if (name == "second")
156 return 1;
157 return llvm::createStringError("Type has no child named '%s'",
158 name.AsCString());
159}
160
161SyntheticChildrenFrontEnd *
163 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
164 return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp)
165 : nullptr);
166}
167
168/*
169 (lldb) fr var ibeg --ptr-depth 1
170 (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >)
171 ibeg = {
172 _M_current = 0x00000001001037a0 {
173 *_M_current = 1
174 }
175 }
176 */
177
178SyntheticChildrenFrontEnd *
180 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
181 return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(
182 valobj_sp, {ConstString("_M_current")})
183 : nullptr);
184}
185
188 llvm::ArrayRef<ConstString> item_names)
190 m_item_names(item_names), m_item_sp() {
191 if (valobj_sp)
192 Update();
193}
194
196 m_item_sp.reset();
197
198 ValueObjectSP valobj_sp = m_backend.GetSP();
199 if (!valobj_sp)
201
202 ValueObjectSP item_ptr =
204 if (!item_ptr)
206 if (item_ptr->GetValueAsUnsigned(0) == 0)
208 Status err;
209 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
211 "item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref,
212 item_ptr->GetCompilerType().GetPointeeType());
213 if (err.Fail())
214 m_item_sp.reset();
216}
217
218llvm::Expected<uint32_t>
222
225 if (idx == 0)
226 return m_item_sp;
227 return lldb::ValueObjectSP();
228}
229
230llvm::Expected<size_t>
232 if (name == "item")
233 return 0;
234 return llvm::createStringError("Type has no child named '%s'",
235 name.AsCString());
236}
237
239 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
240 ValueObjectSP ptr = valobj.GetChildAtNamePath({"_M_dataplus", "_M_p"});
241 if (!ptr || !ptr->GetError().Success())
242 stream << "Summary Unavailable";
243 else
244 stream << ptr->GetSummaryAsCString();
245
246 return true;
247}
248
249LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(
250 lldb::ValueObjectSP valobj_sp)
251 : SyntheticChildrenFrontEnd(*valobj_sp) {
252 if (valobj_sp)
253 Update();
254}
255
256llvm::Expected<uint32_t>
257LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() {
258 return 1;
259}
260
262LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
263 if (!m_ptr_obj)
264 return nullptr;
265
266 if (idx == 0)
267 return m_ptr_obj->GetSP();
268
269 if (idx == 1) {
270 ValueObjectSP valobj_sp = m_backend.GetSP();
271 if (!valobj_sp)
272 return nullptr;
273
274 Status status;
275 ValueObjectSP value_sp = m_ptr_obj->Dereference(status);
276 if (status.Success())
277 return value_sp;
278 }
279 return lldb::ValueObjectSP();
280}
281
282lldb::ChildCacheState LibStdcppSharedPtrSyntheticFrontEnd::Update() {
283 auto backend = m_backend.GetSP();
284 if (!backend)
286
287 auto valobj_sp = backend->GetNonSyntheticValue();
288 if (!valobj_sp)
290
291 auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_M_ptr");
292 if (!ptr_obj_sp)
294
295 auto cast_ptr_sp = GetDesugaredSmartPointerValue(*ptr_obj_sp, *valobj_sp);
296 if (!cast_ptr_sp)
298
299 m_ptr_obj = cast_ptr_sp->Clone(ConstString("pointer")).get();
300
302}
303
304llvm::Expected<size_t>
305LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
306 if (name == "pointer")
307 return 0;
308
309 if (name == "object" || name == "$$dereference$$")
310 return 1;
311
312 return llvm::createStringError("Type has no child named '%s'",
313 name.AsCString());
314}
315
319 return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp)
320 : nullptr);
321}
322
324 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
325 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
326 if (!valobj_sp)
327 return false;
328
329 ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_M_ptr"));
330 if (!ptr_sp)
331 return false;
332
333 DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options);
334
335 ValueObjectSP pi_sp = valobj_sp->GetChildAtNamePath({"_M_refcount", "_M_pi"});
336 if (!pi_sp)
337 return false;
338
339 bool success;
340 uint64_t pi_addr = pi_sp->GetValueAsUnsigned(0, &success);
341 // Empty control field. We're done.
342 if (!success || pi_addr == 0)
343 return true;
344
345 int64_t shared_count = 0;
346 if (auto count_sp = pi_sp->GetChildMemberWithName("_M_use_count")) {
347 bool success;
348 shared_count = count_sp->GetValueAsSigned(0, &success);
349 if (!success)
350 return false;
351
352 stream.Printf(" strong=%" PRId64, shared_count);
353 }
354
355 // _M_weak_count is the number of weak references + (_M_use_count != 0).
356 if (auto weak_count_sp = pi_sp->GetChildMemberWithName("_M_weak_count")) {
357 bool success;
358 int64_t count = weak_count_sp->GetValueAsUnsigned(0, &success);
359 if (!success)
360 return false;
361
362 stream.Printf(" weak=%" PRId64, count - (shared_count != 0));
363 }
364
365 return true;
366}
367
368static uint64_t LibStdcppVariantNposValue(size_t index_byte_size) {
369 switch (index_byte_size) {
370 case 1:
371 return 0xff;
372 case 2:
373 return 0xffff;
374 default:
375 return 0xffff'ffff;
376 }
377}
378
380 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
381 ValueObjectSP valobj_sp = valobj.GetNonSyntheticValue();
382 if (!valobj_sp)
383 return false;
384
385 ValueObjectSP index_obj = valobj_sp->GetChildMemberWithName("_M_index");
386 ValueObjectSP data_obj = valobj_sp->GetChildMemberWithName("_M_u");
387 if (!index_obj || !data_obj)
388 return false;
389
390 auto index_bytes = index_obj->GetByteSize();
391 if (!index_bytes)
392 return false;
393 auto npos_value = LibStdcppVariantNposValue(*index_bytes);
394 auto index = index_obj->GetValueAsUnsigned(0);
395 if (index == npos_value) {
396 stream.Printf(" No Value");
397 return true;
398 }
399
400 auto variant_type =
401 valobj_sp->GetCompilerType().GetCanonicalType().GetNonReferenceType();
402 if (!variant_type)
403 return false;
404 if (index >= variant_type.GetNumTemplateArguments(true)) {
405 stream.Printf(" <Invalid>");
406 return true;
407 }
408
409 auto active_type = variant_type.GetTypeTemplateArgument(index, true);
410 stream << " Active Type = " << active_type.GetDisplayTypeName() << " ";
411 return true;
412}
static uint64_t LibStdcppVariantNposValue(size_t index_byte_size)
static std::optional< size_t > CalculateNumChildren(CompilerType container_elem_type, uint64_t num_elements, CompilerType element_type)
Calculates the number of elements stored in a container (with element type 'container_elem_type') as ...
A uniqued constant string class.
Definition ConstString.h:40
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
An error handling class.
Definition Status.h:118
bool Fail() const
Test for error condition.
Definition Status.cpp:294
bool Success() const
Test for success condition.
Definition Status.cpp:304
A stream class that can stream formatted output to a file.
Definition Stream.h:28
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
SyntheticChildrenFrontEnd(ValueObject &backend)
lldb::ValueObjectSP CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, CompilerType type, bool do_deref=true)
lldb::ValueObjectSP GetChildAtNamePath(llvm::ArrayRef< llvm::StringRef > names)
virtual lldb::ValueObjectSP GetNonSyntheticValue()
lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override
llvm::Expected< uint32_t > CalculateNumChildren() override
llvm::Expected< size_t > GetIndexOfChildWithName(ConstString name) override
lldb::ChildCacheState Update() override
This function is assumed to always succeed and if it fails, the front-end should know to deal with it...
VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp, llvm::ArrayRef< ConstString > item_names)
lldb::ValueObjectSP GetChildMemberWithName(ValueObject &obj, llvm::ArrayRef< ConstString > alternative_names)
Find a child member of obj_sp, trying all alternative names in order.
Definition LibCxx.cpp:63
lldb::ValueObjectSP GetDesugaredSmartPointerValue(ValueObject &ptr, ValueObject &container)
Return the ValueObjectSP of the underlying pointer member whose type is a desugared 'std::shared_ptr:...
Definition Generic.cpp:13
bool LibStdcppSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
bool LibStdcppStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
SyntheticChildrenFrontEnd * LibStdcppVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
SyntheticChildrenFrontEnd * LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
SyntheticChildrenFrontEnd * LibStdcppSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
bool LibStdcppVariantSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
void DumpCxxSmartPtrPointerSummary(Stream &stream, ValueObject &ptr, const TypeSummaryOptions &options)
Prints the summary for the pointer value of a C++ std::unique_ptr/stdshared_ptr/stdweak_ptr.
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.
@ eReuse
Children did not change and don't need to be recomputed; re-use what we computed the last time we cal...
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::Target > TargetSP