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
15
19#include "lldb/Target/Target.h"
21#include "lldb/Utility/Endian.h"
22#include "lldb/Utility/Status.h"
23#include "lldb/Utility/Stream.h"
26#include "llvm/Support/ErrorExtras.h"
27#include <optional>
28
29using namespace lldb;
30using namespace lldb_private;
31using namespace lldb_private::formatters;
32
33namespace {
34
36
37class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
38 /*
39 (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char,
40 std::char_traits<char>, std::allocator<char> > > >) ibeg = {
41 (_Base_ptr) _M_node = 0x0000000100103910 {
42 (std::_Rb_tree_color) _M_color = _S_black
43 (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
44 (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
45 (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
46 }
47 }
48 */
49
50public:
51 explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
52
53 llvm::Expected<uint32_t> CalculateNumChildren() override;
54
55 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
56
57 lldb::ChildCacheState Update() override;
58
59 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
60
61private:
62 ExecutionContextRef m_exe_ctx_ref;
63 lldb::addr_t m_pair_address = 0;
64 CompilerType m_pair_type;
65 lldb::ValueObjectSP m_pair_sp;
66};
67
68class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
69public:
70 explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
71
72 llvm::Expected<uint32_t> CalculateNumChildren() override;
73
74 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
75
76 lldb::ChildCacheState Update() override;
77
78 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
79
80private:
81 // The lifetime of a ValueObject and all its derivative ValueObjects
82 // (children, clones, etc.) is managed by a ClusterManager. These
83 // objects are only destroyed when every shared pointer to any of them
84 // is destroyed, so we must not store a shared pointer to any ValueObject
85 // derived from our backend ValueObject (since we're in the same cluster).
86 ValueObject *m_ptr_obj = nullptr; // Underlying pointer (held, not owned)
87};
88
89} // end of anonymous namespace
90
91LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd(
92 lldb::ValueObjectSP valobj_sp)
93 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type(),
94 m_pair_sp() {
95 if (valobj_sp)
96 Update();
97}
98
99lldb::ChildCacheState LibstdcppMapIteratorSyntheticFrontEnd::Update() {
100 ValueObjectSP valobj_sp = m_backend.GetSP();
101 if (!valobj_sp)
103
104 TargetSP target_sp(valobj_sp->GetTargetSP());
105
106 if (!target_sp)
108
109 bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
110
111 if (!valobj_sp)
113 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
114
115 ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName("_M_node"));
116 if (!_M_node_sp)
118
119 m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
120 if (m_pair_address == 0)
122
123 m_pair_address += (is_64bit ? 32 : 16);
124
125 CompilerType my_type(valobj_sp->GetCompilerType());
126 if (my_type.GetNumTemplateArguments() >= 1) {
127 CompilerType pair_type = my_type.GetTypeTemplateArgument(0);
128 if (!pair_type)
130 m_pair_type = pair_type;
131 } else
133
135}
136
137llvm::Expected<uint32_t>
138LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
139 return 2;
140}
141
143LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
144 if (m_pair_address != 0 && m_pair_type) {
145 if (!m_pair_sp)
146 m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address,
147 m_exe_ctx_ref, m_pair_type);
148 if (m_pair_sp)
149 return m_pair_sp->GetChildAtIndex(idx);
150 }
151 return lldb::ValueObjectSP();
152}
153
154llvm::Expected<size_t>
155LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
156 ConstString name) {
157 if (name == "first")
158 return 0;
159 if (name == "second")
160 return 1;
161 return llvm::createStringErrorV("type has no child named '{0}'", name);
162}
163
164SyntheticChildrenFrontEnd *
166 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
167 return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp)
168 : nullptr);
169}
170
171/*
172 (lldb) fr var ibeg --ptr-depth 1
173 (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >)
174 ibeg = {
175 _M_current = 0x00000001001037a0 {
176 *_M_current = 1
177 }
178 }
179 */
180
181SyntheticChildrenFrontEnd *
183 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
184 return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(
185 valobj_sp, {ConstString("_M_current")})
186 : nullptr);
187}
188
191 llvm::ArrayRef<ConstString> item_names)
193 m_item_names(item_names), m_item_sp() {
194 if (valobj_sp)
195 Update();
196}
197
199 m_item_sp.reset();
200
201 ValueObjectSP valobj_sp = m_backend.GetSP();
202 if (!valobj_sp)
204
205 ValueObjectSP item_ptr =
207 if (!item_ptr)
209 if (item_ptr->GetValueAsUnsigned(0) == 0)
211 Status err;
212 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
214 "item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref,
215 item_ptr->GetCompilerType().GetPointeeType());
216 if (err.Fail())
217 m_item_sp.reset();
219}
220
221llvm::Expected<uint32_t>
225
228 if (idx == 0)
229 return m_item_sp;
230 return lldb::ValueObjectSP();
231}
232
233llvm::Expected<size_t>
235 if (name == "item")
236 return 0;
237 return llvm::createStringErrorV("type has no child named '{0}'", name);
238}
239
241 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
242 ValueObjectSP ptr = valobj.GetChildAtNamePath({"_M_dataplus", "_M_p"});
243 if (!ptr || !ptr->GetError().Success())
244 stream << "Summary Unavailable";
245 else
246 stream << ptr->GetSummaryAsCString();
247
248 return true;
249}
250
251template <StringPrinter::StringElementType element_type>
252static bool formatStringViewImpl(ValueObject &valobj, Stream &stream,
253 const TypeSummaryOptions &summary_options,
254 std::string prefix_token) {
255 auto data_sp = valobj.GetChildMemberWithName("_M_str");
256 auto size_sp = valobj.GetChildMemberWithName("_M_len");
257 if (!data_sp || !size_sp)
258 return false;
259
260 bool success = false;
261 uint64_t size = size_sp->GetValueAsUnsigned(0, &success);
262 if (!success) {
263 stream << "Summary Unavailable";
264 return true;
265 }
266
267 StreamString scratch_stream;
269 scratch_stream, summary_options, data_sp, size, prefix_token);
270
271 if (success)
272 stream << scratch_stream.GetData();
273 else
274 stream << "Summary Unavailable";
275 return true;
276}
277
279 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
280 auto wchar_t_size = GetWCharByteSize(valobj);
281 if (!wchar_t_size)
282 return false;
283
284 switch (*wchar_t_size) {
285 case 1:
287 options, "L");
288 case 2:
290 options, "L");
291 case 4:
293 options, "L");
294 }
295 return false;
296}
297
298template <StringElementType element_type>
299static constexpr const char *getPrefixToken() {
300 switch (element_type) {
301 case StringElementType::ASCII:
302 return "";
303 case StringElementType::UTF8:
304 return "u8";
305 case StringElementType::UTF16:
306 return "u";
307 case StringElementType::UTF32:
308 return "U";
309 }
310 llvm_unreachable("invalid element type");
311}
312
313template <StringPrinter::StringElementType element_type>
319
321 StringElementType::ASCII>(ValueObject &, Stream &,
322 const TypeSummaryOptions &);
324 StringElementType::UTF8>(ValueObject &, Stream &,
325 const TypeSummaryOptions &);
327 StringElementType::UTF16>(ValueObject &, Stream &,
328 const TypeSummaryOptions &);
330 StringElementType::UTF32>(ValueObject &, Stream &,
331 const TypeSummaryOptions &);
332
333LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(
334 lldb::ValueObjectSP valobj_sp)
335 : SyntheticChildrenFrontEnd(*valobj_sp) {
336 if (valobj_sp)
337 Update();
338}
339
340llvm::Expected<uint32_t>
341LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() {
342 return 1;
343}
344
346LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
347 if (!m_ptr_obj)
348 return nullptr;
349
350 if (idx == 0)
351 return m_ptr_obj->GetSP();
352
353 if (idx == 1) {
354 ValueObjectSP valobj_sp = m_backend.GetSP();
355 if (!valobj_sp)
356 return nullptr;
357
358 Status status;
359 ValueObjectSP value_sp = m_ptr_obj->Dereference(status);
360 if (status.Success())
361 return value_sp;
362 }
363 return lldb::ValueObjectSP();
364}
365
366lldb::ChildCacheState LibStdcppSharedPtrSyntheticFrontEnd::Update() {
367 auto backend = m_backend.GetSP();
368 if (!backend)
370
371 auto valobj_sp = backend->GetNonSyntheticValue();
372 if (!valobj_sp)
374
375 auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_M_ptr");
376 if (!ptr_obj_sp)
378
379 auto cast_ptr_sp = GetDesugaredSmartPointerValue(*ptr_obj_sp, *valobj_sp);
380 if (!cast_ptr_sp)
382
383 m_ptr_obj = cast_ptr_sp->Clone(ConstString("pointer")).get();
384
386}
387
388llvm::Expected<size_t>
389LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
390 if (name == "pointer")
391 return 0;
392
393 if (name == "object" || name == "$$dereference$$")
394 return 1;
395
396 return llvm::createStringErrorV("type has no child named '{0}'", name);
397}
398
399SyntheticChildrenFrontEnd *
401 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
402 return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp)
403 : nullptr);
404}
405
407 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
408 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
409 if (!valobj_sp)
410 return false;
411
412 ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_M_ptr"));
413 if (!ptr_sp)
414 return false;
415
416 DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options);
417
418 ValueObjectSP pi_sp = valobj_sp->GetChildAtNamePath({"_M_refcount", "_M_pi"});
419 if (!pi_sp)
420 return false;
421
422 bool success;
423 uint64_t pi_addr = pi_sp->GetValueAsUnsigned(0, &success);
424 // Empty control field. We're done.
425 if (!success || pi_addr == 0)
426 return true;
427
428 int64_t shared_count = 0;
429 if (auto count_sp = pi_sp->GetChildMemberWithName("_M_use_count")) {
430 bool success;
431 shared_count = count_sp->GetValueAsSigned(0, &success);
432 if (!success)
433 return false;
434
435 stream.Printf(" strong=%" PRId64, shared_count);
436 }
437
438 // _M_weak_count is the number of weak references + (_M_use_count != 0).
439 if (auto weak_count_sp = pi_sp->GetChildMemberWithName("_M_weak_count")) {
440 bool success;
441 int64_t count = weak_count_sp->GetValueAsUnsigned(0, &success);
442 if (!success)
443 return false;
444
445 stream.Printf(" weak=%" PRId64, count - (shared_count != 0));
446 }
447
448 return true;
449}
450
451static uint64_t LibStdcppVariantNposValue(size_t index_byte_size) {
452 switch (index_byte_size) {
453 case 1:
454 return 0xff;
455 case 2:
456 return 0xffff;
457 default:
458 return 0xffff'ffff;
459 }
460}
461
463 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
464 ValueObjectSP valobj_sp = valobj.GetNonSyntheticValue();
465 if (!valobj_sp)
466 return false;
467
468 ValueObjectSP index_obj = valobj_sp->GetChildMemberWithName("_M_index");
469 ValueObjectSP data_obj = valobj_sp->GetChildMemberWithName("_M_u");
470 if (!index_obj || !data_obj)
471 return false;
472
473 auto index_bytes = index_obj->GetByteSize();
474 if (!index_bytes)
475 return false;
476 auto npos_value = LibStdcppVariantNposValue(*index_bytes);
477 auto index = index_obj->GetValueAsUnsigned(0);
478 if (index == npos_value) {
479 stream.Printf(" No Value");
480 return true;
481 }
482
483 auto variant_type =
484 valobj_sp->GetCompilerType().GetCanonicalType().GetNonReferenceType();
485 if (!variant_type)
486 return false;
487 if (index >= variant_type.GetNumTemplateArguments(true)) {
488 stream.Printf(" <Invalid>");
489 return true;
490 }
491
492 auto active_type = variant_type.GetTypeTemplateArgument(index, true);
493 stream << " Active Type = " << active_type.GetDisplayTypeName() << " ";
494 return true;
495}
496
497static std::optional<int64_t>
499 lldb::ValueObjectSP value_sp = valobj.GetChildMemberWithName("_M_value");
500 if (!value_sp)
501 return std::nullopt;
502 bool success;
503 int64_t value = value_sp->GetValueAsSigned(0, &success);
504 if (!success)
505 return std::nullopt;
506 return value;
507}
508
510 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
511 std::optional<int64_t> value = LibStdcppExtractOrderingValue(valobj);
512 if (!value)
513 return false;
514 switch (*value) {
515 case -1:
516 stream << "less";
517 break;
518 case 0:
519 stream << "equivalent";
520 break;
521 case 1:
522 stream << "greater";
523 break;
524 case -128:
525 case 2:
526 stream << "unordered";
527 break;
528 default:
529 return false;
530 }
531 return true;
532}
533
535 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
536 std::optional<int64_t> value = LibStdcppExtractOrderingValue(valobj);
537 if (!value)
538 return false;
539 switch (*value) {
540 case -1:
541 stream << "less";
542 break;
543 case 0:
544 stream << "equivalent";
545 break;
546 case 1:
547 stream << "greater";
548 break;
549 default:
550 return false;
551 }
552 return true;
553}
554
556 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
557 std::optional<int64_t> value = LibStdcppExtractOrderingValue(valobj);
558 if (!value)
559 return false;
560 switch (*value) {
561 case -1:
562 stream << "less";
563 break;
564 case 0:
565 stream << "equal";
566 break;
567 case 1:
568 stream << "greater";
569 break;
570 default:
571 return false;
572 }
573 return true;
574}
static bool formatStringViewImpl(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options, std::string prefix_token)
Definition LibCxx.cpp:728
static constexpr const char * getPrefixToken()
static std::optional< int64_t > LibStdcppExtractOrderingValue(ValueObject &valobj)
static uint64_t LibStdcppVariantNposValue(size_t index_byte_size)
StringPrinter::StringElementType StringElementType
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
An error handling class.
Definition Status.h:118
bool Fail() const
Test for error condition.
Definition Status.cpp:293
bool Success() const
Test for success condition.
Definition Status.cpp:303
const char * GetData() const
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:132
SyntheticChildrenFrontEnd(ValueObject &backend)
lldb::ValueObjectSP CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, CompilerType type, bool do_deref=true)
lldb::ValueObjectSP GetSP()
virtual lldb::ValueObjectSP GetChildMemberWithName(llvm::StringRef name, bool can_create=true)
lldb::ValueObjectSP GetChildAtNamePath(llvm::ArrayRef< llvm::StringRef > names)
virtual lldb::ValueObjectSP Clone(ConstString new_name)
Creates a copy of the ValueObject with a new name and setting the current ValueObject as its parent.
virtual lldb::ValueObjectSP Dereference(Status &error)
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
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...
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 LibStdcppStringViewSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
bool LibStdcppStrongOrderingSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
std::optional< uint64_t > GetWCharByteSize(ValueObject &valobj)
bool StringBufferSummaryProvider(Stream &stream, const TypeSummaryOptions &summary_options, lldb::ValueObjectSP location_sp, uint64_t size, std::string prefix_token)
Print a summary for a string buffer to stream.
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)
bool LibStdcppPartialOrderingSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
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.
bool LibStdcppWStringViewSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
bool LibStdcppWeakOrderingSummaryProvider(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.
@ 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