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
18#include "lldb/Target/Target.h"
20#include "lldb/Utility/Endian.h"
21#include "lldb/Utility/Status.h"
22#include "lldb/Utility/Stream.h"
25#include <optional>
26
27using namespace lldb;
28using namespace lldb_private;
29using namespace lldb_private::formatters;
30
31namespace {
32
34
35class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
36 /*
37 (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char,
38 std::char_traits<char>, std::allocator<char> > > >) ibeg = {
39 (_Base_ptr) _M_node = 0x0000000100103910 {
40 (std::_Rb_tree_color) _M_color = _S_black
41 (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
42 (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
43 (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
44 }
45 }
46 */
47
48public:
49 explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
50
51 llvm::Expected<uint32_t> CalculateNumChildren() override;
52
53 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
54
55 lldb::ChildCacheState Update() override;
56
57 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
58
59private:
60 ExecutionContextRef m_exe_ctx_ref;
61 lldb::addr_t m_pair_address = 0;
62 CompilerType m_pair_type;
63 lldb::ValueObjectSP m_pair_sp;
64};
65
66class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
67public:
68 explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
69
70 llvm::Expected<uint32_t> CalculateNumChildren() override;
71
72 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;
73
74 lldb::ChildCacheState Update() override;
75
76 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;
77
78private:
79 // The lifetime of a ValueObject and all its derivative ValueObjects
80 // (children, clones, etc.) is managed by a ClusterManager. These
81 // objects are only destroyed when every shared pointer to any of them
82 // is destroyed, so we must not store a shared pointer to any ValueObject
83 // derived from our backend ValueObject (since we're in the same cluster).
84 ValueObject *m_ptr_obj = nullptr; // Underlying pointer (held, not owned)
85};
86
87} // end of anonymous namespace
88
89LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd(
90 lldb::ValueObjectSP valobj_sp)
91 : SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_pair_type(),
92 m_pair_sp() {
93 if (valobj_sp)
94 Update();
95}
96
97lldb::ChildCacheState LibstdcppMapIteratorSyntheticFrontEnd::Update() {
98 ValueObjectSP valobj_sp = m_backend.GetSP();
99 if (!valobj_sp)
101
102 TargetSP target_sp(valobj_sp->GetTargetSP());
103
104 if (!target_sp)
106
107 bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
108
109 if (!valobj_sp)
111 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
112
113 ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName("_M_node"));
114 if (!_M_node_sp)
116
117 m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
118 if (m_pair_address == 0)
120
121 m_pair_address += (is_64bit ? 32 : 16);
122
123 CompilerType my_type(valobj_sp->GetCompilerType());
124 if (my_type.GetNumTemplateArguments() >= 1) {
125 CompilerType pair_type = my_type.GetTypeTemplateArgument(0);
126 if (!pair_type)
128 m_pair_type = pair_type;
129 } else
131
133}
134
135llvm::Expected<uint32_t>
136LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren() {
137 return 2;
138}
139
141LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
142 if (m_pair_address != 0 && m_pair_type) {
143 if (!m_pair_sp)
144 m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address,
145 m_exe_ctx_ref, m_pair_type);
146 if (m_pair_sp)
147 return m_pair_sp->GetChildAtIndex(idx);
148 }
149 return lldb::ValueObjectSP();
150}
151
152llvm::Expected<size_t>
153LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName(
154 ConstString name) {
155 if (name == "first")
156 return 0;
157 if (name == "second")
158 return 1;
159 return llvm::createStringError("Type has no child named '%s'",
160 name.AsCString());
161}
162
163SyntheticChildrenFrontEnd *
165 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
166 return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp)
167 : nullptr);
168}
169
170/*
171 (lldb) fr var ibeg --ptr-depth 1
172 (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >)
173 ibeg = {
174 _M_current = 0x00000001001037a0 {
175 *_M_current = 1
176 }
177 }
178 */
179
180SyntheticChildrenFrontEnd *
182 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
183 return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(
184 valobj_sp, {ConstString("_M_current")})
185 : nullptr);
186}
187
190 llvm::ArrayRef<ConstString> item_names)
192 m_item_names(item_names), m_item_sp() {
193 if (valobj_sp)
194 Update();
195}
196
198 m_item_sp.reset();
199
200 ValueObjectSP valobj_sp = m_backend.GetSP();
201 if (!valobj_sp)
203
204 ValueObjectSP item_ptr =
206 if (!item_ptr)
208 if (item_ptr->GetValueAsUnsigned(0) == 0)
210 Status err;
211 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
213 "item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref,
214 item_ptr->GetCompilerType().GetPointeeType());
215 if (err.Fail())
216 m_item_sp.reset();
218}
219
220llvm::Expected<uint32_t>
224
227 if (idx == 0)
228 return m_item_sp;
229 return lldb::ValueObjectSP();
230}
231
232llvm::Expected<size_t>
234 if (name == "item")
235 return 0;
236 return llvm::createStringError("Type has no child named '%s'",
237 name.AsCString());
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::createStringError("Type has no child named '%s'",
397 name.AsCString());
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 = index_obj->GetByteSize();
475 if (!index_bytes)
476 return false;
477 auto npos_value = LibStdcppVariantNposValue(*index_bytes);
478 auto index = index_obj->GetValueAsUnsigned(0);
479 if (index == npos_value) {
480 stream.Printf(" No Value");
481 return true;
482 }
483
484 auto variant_type =
485 valobj_sp->GetCompilerType().GetCanonicalType().GetNonReferenceType();
486 if (!variant_type)
487 return false;
488 if (index >= variant_type.GetNumTemplateArguments(true)) {
489 stream.Printf(" <Invalid>");
490 return true;
491 }
492
493 auto active_type = variant_type.GetTypeTemplateArgument(index, true);
494 stream << " Active Type = " << active_type.GetDisplayTypeName() << " ";
495 return true;
496}
497
498static std::optional<int64_t>
500 lldb::ValueObjectSP value_sp = valobj.GetChildMemberWithName("_M_value");
501 if (!value_sp)
502 return std::nullopt;
503 bool success;
504 int64_t value = value_sp->GetValueAsSigned(0, &success);
505 if (!success)
506 return std::nullopt;
507 return value;
508}
509
511 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
512 std::optional<int64_t> value = LibStdcppExtractOrderingValue(valobj);
513 if (!value)
514 return false;
515 switch (*value) {
516 case -1:
517 stream << "less";
518 break;
519 case 0:
520 stream << "equivalent";
521 break;
522 case 1:
523 stream << "greater";
524 break;
525 case -128:
526 case 2:
527 stream << "unordered";
528 break;
529 default:
530 return false;
531 }
532 return true;
533}
534
536 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
537 std::optional<int64_t> value = LibStdcppExtractOrderingValue(valobj);
538 if (!value)
539 return false;
540 switch (*value) {
541 case -1:
542 stream << "less";
543 break;
544 case 0:
545 stream << "equivalent";
546 break;
547 case 1:
548 stream << "greater";
549 break;
550 default:
551 return false;
552 }
553 return true;
554}
555
557 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
558 std::optional<int64_t> value = LibStdcppExtractOrderingValue(valobj);
559 if (!value)
560 return false;
561 switch (*value) {
562 case -1:
563 stream << "less";
564 break;
565 case 0:
566 stream << "equal";
567 break;
568 case 1:
569 stream << "greater";
570 break;
571 default:
572 return false;
573 }
574 return true;
575}
static bool formatStringViewImpl(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options, std::string prefix_token)
Definition LibCxx.cpp:662
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
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
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
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
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