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