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
18#include "lldb/Target/Target.h"
20#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 = CreateChildValueObjectFromAddress("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
190 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
191 ValueObjectSP ptr = valobj.GetChildAtNamePath({"_M_dataplus", "_M_p"});
192 if (!ptr || !ptr->GetError().Success())
193 stream << "Summary Unavailable";
194 else
195 stream << ptr->GetSummaryAsCString();
196
197 return true;
198}
199
200template <StringPrinter::StringElementType element_type>
201static bool formatStringViewImpl(ValueObject &valobj, Stream &stream,
202 const TypeSummaryOptions &summary_options,
203 std::string prefix_token) {
204 auto data_sp = valobj.GetChildMemberWithName("_M_str");
205 auto size_sp = valobj.GetChildMemberWithName("_M_len");
206 if (!data_sp || !size_sp)
207 return false;
208
209 bool success = false;
210 uint64_t size = size_sp->GetValueAsUnsigned(0, &success);
211 if (!success) {
212 stream << "Summary Unavailable";
213 return true;
214 }
215
216 StreamString scratch_stream;
218 scratch_stream, summary_options, data_sp, size, prefix_token);
219
220 if (success)
221 stream << scratch_stream.GetData();
222 else
223 stream << "Summary Unavailable";
224 return true;
225}
226
228 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
229 auto wchar_t_size = GetWCharByteSize(valobj);
230 if (!wchar_t_size)
231 return false;
232
233 switch (*wchar_t_size) {
234 case 1:
236 options, "L");
237 case 2:
239 options, "L");
240 case 4:
242 options, "L");
243 }
244 return false;
245}
246
247template <StringElementType element_type>
248static constexpr const char *getPrefixToken() {
249 switch (element_type) {
250 case StringElementType::ASCII:
251 return "";
252 case StringElementType::UTF8:
253 return "u8";
254 case StringElementType::UTF16:
255 return "u";
256 case StringElementType::UTF32:
257 return "U";
258 }
259 llvm_unreachable("invalid element type");
260}
261
262template <StringPrinter::StringElementType element_type>
268
270 StringElementType::ASCII>(ValueObject &, Stream &,
271 const TypeSummaryOptions &);
273 StringElementType::UTF8>(ValueObject &, Stream &,
274 const TypeSummaryOptions &);
276 StringElementType::UTF16>(ValueObject &, Stream &,
277 const TypeSummaryOptions &);
279 StringElementType::UTF32>(ValueObject &, Stream &,
280 const TypeSummaryOptions &);
281
282LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(
283 lldb::ValueObjectSP valobj_sp)
284 : SyntheticChildrenFrontEnd(*valobj_sp) {
285 if (valobj_sp)
286 Update();
287}
288
289llvm::Expected<uint32_t>
290LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren() {
291 return 1;
292}
293
295LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(uint32_t idx) {
296 if (!m_ptr_obj)
297 return nullptr;
298
299 if (idx == 0)
300 return m_ptr_obj->GetSP();
301
302 if (idx == 1) {
303 ValueObjectSP valobj_sp = m_backend.GetSP();
304 if (!valobj_sp)
305 return nullptr;
306
307 Status status;
308 ValueObjectSP value_sp = m_ptr_obj->Dereference(status);
309 if (status.Success())
310 return value_sp;
311 }
312 return lldb::ValueObjectSP();
313}
314
315lldb::ChildCacheState LibStdcppSharedPtrSyntheticFrontEnd::Update() {
316 auto backend = m_backend.GetSP();
317 if (!backend)
319
320 auto valobj_sp = backend->GetNonSyntheticValue();
321 if (!valobj_sp)
323
324 auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("_M_ptr");
325 if (!ptr_obj_sp)
327
328 auto cast_ptr_sp = GetDesugaredSmartPointerValue(*ptr_obj_sp, *valobj_sp);
329 if (!cast_ptr_sp)
331
332 m_ptr_obj = cast_ptr_sp->Clone("pointer").get();
333
335}
336
337llvm::Expected<size_t>
338LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {
339 if (name == "pointer")
340 return 0;
341
342 if (name == "object" || name == "$$dereference$$")
343 return 1;
344
345 return llvm::createStringErrorV("type has no child named '{0}'", name);
346}
347
348SyntheticChildrenFrontEnd *
350 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
351 return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp)
352 : nullptr);
353}
354
356 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
357 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
358 if (!valobj_sp)
359 return false;
360
361 ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("_M_ptr"));
362 if (!ptr_sp)
363 return false;
364
365 DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options);
366
367 ValueObjectSP pi_sp = valobj_sp->GetChildAtNamePath({"_M_refcount", "_M_pi"});
368 if (!pi_sp)
369 return false;
370
371 bool success;
372 uint64_t pi_addr = pi_sp->GetValueAsUnsigned(0, &success);
373 // Empty control field. We're done.
374 if (!success || pi_addr == 0)
375 return true;
376
377 int64_t shared_count = 0;
378 if (auto count_sp = pi_sp->GetChildMemberWithName("_M_use_count")) {
379 bool success;
380 shared_count = count_sp->GetValueAsSigned(0, &success);
381 if (!success)
382 return false;
383
384 stream.Printf(" strong=%" PRId64, shared_count);
385 }
386
387 // _M_weak_count is the number of weak references + (_M_use_count != 0).
388 if (auto weak_count_sp = pi_sp->GetChildMemberWithName("_M_weak_count")) {
389 bool success;
390 int64_t count = weak_count_sp->GetValueAsUnsigned(0, &success);
391 if (!success)
392 return false;
393
394 stream.Printf(" weak=%" PRId64, count - (shared_count != 0));
395 }
396
397 return true;
398}
399
400static uint64_t LibStdcppVariantNposValue(size_t index_byte_size) {
401 switch (index_byte_size) {
402 case 1:
403 return 0xff;
404 case 2:
405 return 0xffff;
406 default:
407 return 0xffff'ffff;
408 }
409}
410
412 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
413 ValueObjectSP valobj_sp = valobj.GetNonSyntheticValue();
414 if (!valobj_sp)
415 return false;
416
417 ValueObjectSP index_obj = valobj_sp->GetChildMemberWithName("_M_index");
418 ValueObjectSP data_obj = valobj_sp->GetChildMemberWithName("_M_u");
419 if (!index_obj || !data_obj)
420 return false;
421
422 auto index_bytes_or_err = index_obj->GetByteSize();
423 if (!index_bytes_or_err) {
425 index_bytes_or_err.takeError(),
426 "failed to get variant index byte size: {0}");
427 return false;
428 }
429 auto npos_value = LibStdcppVariantNposValue(*index_bytes_or_err);
430 auto index = index_obj->GetValueAsUnsigned(0);
431 if (index == npos_value) {
432 stream.Printf(" No Value");
433 return true;
434 }
435
436 auto variant_type =
437 valobj_sp->GetCompilerType().GetCanonicalType().GetNonReferenceType();
438 if (!variant_type)
439 return false;
440 if (index >= variant_type.GetNumTemplateArguments(true)) {
441 stream.Printf(" <Invalid>");
442 return true;
443 }
444
445 auto active_type = variant_type.GetTypeTemplateArgument(index, true);
446 stream << " Active Type = " << active_type.GetDisplayTypeName() << " ";
447 return true;
448}
449
450static std::optional<int64_t>
452 lldb::ValueObjectSP value_sp = valobj.GetChildMemberWithName("_M_value");
453 if (!value_sp)
454 return std::nullopt;
455 bool success;
456 int64_t value = value_sp->GetValueAsSigned(0, &success);
457 if (!success)
458 return std::nullopt;
459 return value;
460}
461
463 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
464 std::optional<int64_t> value = LibStdcppExtractOrderingValue(valobj);
465 if (!value)
466 return false;
467 switch (*value) {
468 case -1:
469 stream << "less";
470 break;
471 case 0:
472 stream << "equivalent";
473 break;
474 case 1:
475 stream << "greater";
476 break;
477 case -128:
478 case 2:
479 stream << "unordered";
480 break;
481 default:
482 return false;
483 }
484 return true;
485}
486
488 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
489 std::optional<int64_t> value = LibStdcppExtractOrderingValue(valobj);
490 if (!value)
491 return false;
492 switch (*value) {
493 case -1:
494 stream << "less";
495 break;
496 case 0:
497 stream << "equivalent";
498 break;
499 case 1:
500 stream << "greater";
501 break;
502 default:
503 return false;
504 }
505 return true;
506}
507
509 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
510 std::optional<int64_t> value = LibStdcppExtractOrderingValue(valobj);
511 if (!value)
512 return false;
513 switch (*value) {
514 case -1:
515 stream << "less";
516 break;
517 case 0:
518 stream << "equal";
519 break;
520 case 1:
521 stream << "greater";
522 break;
523 default:
524 return false;
525 }
526 return true;
527}
528
530 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
531 ValueObjectSP impl_sp = valobj.GetChildMemberWithName("_M_impl");
532 if (!impl_sp)
533 return false;
534
535 ValueObjectSP file_sp = impl_sp->GetChildMemberWithName("_M_file_name");
536 ValueObjectSP function_sp =
537 impl_sp->GetChildMemberWithName("_M_function_name");
538 ValueObjectSP line_sp = impl_sp->GetChildMemberWithName("_M_line");
539 ValueObjectSP column_sp = impl_sp->GetChildMemberWithName("_M_column");
540
541 if (!file_sp || !function_sp || !line_sp || !column_sp)
542 return false;
543
544 bool success = false;
545 uint64_t line = line_sp->GetValueAsUnsigned(0, &success);
546 if (!success)
547 return false;
548
549 uint64_t column = column_sp->GetValueAsUnsigned(0, &success);
550 if (!success)
551 return false;
552
553 const char *file = file_sp->GetSummaryAsCString();
554 stream.Format("{0}:{1}:{2}", file ? file : "<unknown>", line, column);
555
556 if (const char *function = function_sp->GetSummaryAsCString())
557 stream.Printf(" (%s)", function);
558
559 return true;
560}
static bool formatStringViewImpl(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options, std::string prefix_token)
Definition LibCxx.cpp:725
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:405
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 ...
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
void Format(const char *format, Args &&... args)
Forwards the arguments to llvm::formatv and writes to the stream.
Definition Stream.h:370
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
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(llvm::StringRef 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 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 LibStdcppSourceLocationSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
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:338
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