1 //===-- LibCxx.cpp ----------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
14 // Other libraries and framework includes
16 #include "lldb/Core/Debugger.h"
17 #include "lldb/Core/FormatEntity.h"
18 #include "lldb/Core/ValueObject.h"
19 #include "lldb/Core/ValueObjectConstResult.h"
20 #include "lldb/DataFormatters/FormattersHelpers.h"
21 #include "lldb/DataFormatters/StringPrinter.h"
22 #include "lldb/DataFormatters/TypeSummary.h"
23 #include "lldb/DataFormatters/VectorIterator.h"
24 #include "lldb/Symbol/ClangASTContext.h"
25 #include "lldb/Target/ProcessStructReader.h"
26 #include "lldb/Target/Target.h"
27 #include "lldb/Utility/DataBufferHeap.h"
28 #include "lldb/Utility/Endian.h"
29 #include "lldb/Utility/Status.h"
30 #include "lldb/Utility/Stream.h"
33 using namespace lldb_private;
34 using namespace lldb_private::formatters;
36 bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider(
37 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
38 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
42 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true));
43 ValueObjectSP count_sp(valobj_sp->GetChildAtNamePath(
44 {ConstString("__cntrl_"), ConstString("__shared_owners_")}));
45 ValueObjectSP weakcount_sp(valobj_sp->GetChildAtNamePath(
46 {ConstString("__cntrl_"), ConstString("__shared_weak_owners_")}));
51 if (ptr_sp->GetValueAsUnsigned(0) == 0) {
52 stream.Printf("nullptr");
55 bool print_pointee = false;
57 ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
58 if (pointee_sp && error.Success()) {
59 if (pointee_sp->DumpPrintableRepresentation(
60 stream, ValueObject::eValueObjectRepresentationStyleSummary,
62 ValueObject::PrintableRepresentationSpecialCases::eDisable,
67 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
71 stream.Printf(" strong=%" PRIu64, 1 + count_sp->GetValueAsUnsigned(0));
74 stream.Printf(" weak=%" PRIu64, 1 + weakcount_sp->GetValueAsUnsigned(0));
80 (lldb) fr var ibeg --raw --ptr-depth 1
81 (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int,
82 std::__1::basic_string<char, std::__1::char_traits<char>,
83 std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int,
84 std::__1::basic_string<char, std::__1::char_traits<char>,
85 std::__1::allocator<char> > >, void *> *, long> >) ibeg = {
87 __ptr_ = 0x0000000100103870 {
88 std::__1::__tree_node_base<void *> = {
89 std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = {
90 __left_ = 0x0000000000000000
92 __right_ = 0x0000000000000000
93 __parent_ = 0x00000001001038b0
98 second = { std::string }
101 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
102 LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
103 : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() {
108 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() {
110 m_pair_ptr = nullptr;
112 ValueObjectSP valobj_sp = m_backend.GetSP();
116 TargetSP target_sp(valobj_sp->GetTargetSP());
124 static ConstString g___i_("__i_");
126 // this must be a ValueObject* because it is a child of the ValueObject we
127 // are producing children for it if were a ValueObjectSP, we would end up
128 // with a loop (iterator -> synthetic -> child -> parent == iterator) and
129 // that would in turn leak memory by never allowing the ValueObjects to die
130 // and free their memory
131 m_pair_ptr = valobj_sp
132 ->GetValueForExpressionPath(
133 ".__i_.__ptr_->__value_", nullptr, nullptr,
134 ValueObject::GetValueForExpressionPathOptions()
135 .DontCheckDotVsArrowSyntax()
136 .SetSyntheticChildrenTraversal(
137 ValueObject::GetValueForExpressionPathOptions::
138 SyntheticChildrenTraversal::None),
143 m_pair_ptr = valobj_sp
144 ->GetValueForExpressionPath(
145 ".__i_.__ptr_", nullptr, nullptr,
146 ValueObject::GetValueForExpressionPathOptions()
147 .DontCheckDotVsArrowSyntax()
148 .SetSyntheticChildrenTraversal(
149 ValueObject::GetValueForExpressionPathOptions::
150 SyntheticChildrenTraversal::None),
154 auto __i_(valobj_sp->GetChildMemberWithName(g___i_, true));
156 m_pair_ptr = nullptr;
159 CompilerType pair_type(__i_->GetCompilerType().GetTypeTemplateArgument(0));
160 std::string name; uint64_t bit_offset_ptr; uint32_t bitfield_bit_size_ptr; bool is_bitfield_ptr;
161 pair_type = pair_type.GetFieldAtIndex(0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
163 m_pair_ptr = nullptr;
167 auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS));
168 m_pair_ptr = nullptr;
169 if (addr && addr!=LLDB_INVALID_ADDRESS) {
170 ClangASTContext *ast_ctx = llvm::dyn_cast_or_null<ClangASTContext>(pair_type.GetTypeSystem());
173 CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(ConstString(), {
174 {"ptr0",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
175 {"ptr1",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
176 {"ptr2",ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
177 {"cw",ast_ctx->GetBasicType(lldb::eBasicTypeBool)},
178 {"payload",pair_type}
180 DataBufferSP buffer_sp(new DataBufferHeap(tree_node_type.GetByteSize(nullptr),0));
181 ProcessSP process_sp(target_sp->GetProcessSP());
183 process_sp->ReadMemory(addr, buffer_sp->GetBytes(), buffer_sp->GetByteSize(), error);
186 DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
187 auto pair_sp = CreateValueObjectFromData("pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type);
189 m_pair_sp = pair_sp->GetChildAtIndex(4,true);
197 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
198 CalculateNumChildren() {
203 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::GetChildAtIndex(
206 return m_pair_ptr->GetChildAtIndex(idx, true);
208 return m_pair_sp->GetChildAtIndex(idx, true);
209 return lldb::ValueObjectSP();
212 bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
213 MightHaveChildren() {
217 size_t lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
218 GetIndexOfChildWithName(const ConstString &name) {
219 if (name == ConstString("first"))
221 if (name == ConstString("second"))
226 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::
227 ~LibCxxMapIteratorSyntheticFrontEnd() {
228 // this will be deleted when its parent dies (since it's a child object)
229 // delete m_pair_ptr;
232 SyntheticChildrenFrontEnd *
233 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator(
234 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
235 return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp)
240 (lldb) fr var ibeg --raw --ptr-depth 1 -T
241 (std::__1::__wrap_iter<int *>) ibeg = {
242 (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 {
248 SyntheticChildrenFrontEnd *
249 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator(
250 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
251 static ConstString g_item_name;
253 g_item_name.SetCString("__i");
255 ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name)
259 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
260 LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
261 : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr), m_count_sp(),
262 m_weak_count_sp(), m_ptr_size(0), m_byte_order(lldb::eByteOrderInvalid) {
267 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
268 CalculateNumChildren() {
269 return (m_cntrl ? 1 : 0);
273 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex(
276 return lldb::ValueObjectSP();
278 ValueObjectSP valobj_sp = m_backend.GetSP();
280 return lldb::ValueObjectSP();
283 return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true);
286 return lldb::ValueObjectSP();
290 ValueObjectSP shared_owners_sp(m_cntrl->GetChildMemberWithName(
291 ConstString("__shared_owners_"), true));
292 if (!shared_owners_sp)
293 return lldb::ValueObjectSP();
294 uint64_t count = 1 + shared_owners_sp->GetValueAsUnsigned(0);
295 DataExtractor data(&count, 8, m_byte_order, m_ptr_size);
296 m_count_sp = CreateValueObjectFromData(
297 "count", data, valobj_sp->GetExecutionContextRef(),
298 shared_owners_sp->GetCompilerType());
301 } else /* if (idx == 2) */
303 if (!m_weak_count_sp) {
304 ValueObjectSP shared_weak_owners_sp(m_cntrl->GetChildMemberWithName(
305 ConstString("__shared_weak_owners_"), true));
306 if (!shared_weak_owners_sp)
307 return lldb::ValueObjectSP();
308 uint64_t count = 1 + shared_weak_owners_sp->GetValueAsUnsigned(0);
309 DataExtractor data(&count, 8, m_byte_order, m_ptr_size);
310 m_weak_count_sp = CreateValueObjectFromData(
311 "count", data, valobj_sp->GetExecutionContextRef(),
312 shared_weak_owners_sp->GetCompilerType());
314 return m_weak_count_sp;
318 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() {
320 m_weak_count_sp.reset();
323 ValueObjectSP valobj_sp = m_backend.GetSP();
327 TargetSP target_sp(valobj_sp->GetTargetSP());
331 m_byte_order = target_sp->GetArchitecture().GetByteOrder();
332 m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize();
334 lldb::ValueObjectSP cntrl_sp(
335 valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true));
337 m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular
342 bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
343 MightHaveChildren() {
347 size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
348 GetIndexOfChildWithName(const ConstString &name) {
349 if (name == ConstString("__ptr_"))
351 if (name == ConstString("count"))
353 if (name == ConstString("weak_count"))
358 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::
359 ~LibcxxSharedPtrSyntheticFrontEnd() = default;
361 SyntheticChildrenFrontEnd *
362 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator(
363 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
364 return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp)
368 bool lldb_private::formatters::LibcxxContainerSummaryProvider(
369 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
370 if (valobj.IsPointerType()) {
371 uint64_t value = valobj.GetValueAsUnsigned(0);
374 stream.Printf("0x%016" PRIx64 " ", value);
376 return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr,
377 nullptr, nullptr, &valobj, false, false);
380 // the field layout in a libc++ string (cap, side, data or data, size, cap)
381 enum LibcxxStringLayoutMode {
382 eLibcxxStringLayoutModeCSD = 0,
383 eLibcxxStringLayoutModeDSC = 1,
384 eLibcxxStringLayoutModeInvalid = 0xffff
387 // this function abstracts away the layout and mode details of a libc++ string
388 // and returns the address of the data and the size ready for callers to
390 static bool ExtractLibcxxStringInfo(ValueObject &valobj,
391 ValueObjectSP &location_sp,
393 ValueObjectSP D(valobj.GetChildAtIndexPath({0, 0, 0, 0}));
397 ValueObjectSP layout_decider(
398 D->GetChildAtIndexPath(llvm::ArrayRef<size_t>({0, 0})));
400 // this child should exist
404 ConstString g_data_name("__data_");
405 ConstString g_size_name("__size_");
406 bool short_mode = false; // this means the string is in short-mode and the
407 // data is stored inline
408 LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name)
409 ? eLibcxxStringLayoutModeDSC
410 : eLibcxxStringLayoutModeCSD;
411 uint64_t size_mode_value = 0;
413 if (layout == eLibcxxStringLayoutModeDSC) {
414 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 1, 0}));
418 if (size_mode->GetName() != g_size_name) {
419 // we are hitting the padding structure, move along
420 size_mode = D->GetChildAtIndexPath({1, 1, 1});
425 size_mode_value = (size_mode->GetValueAsUnsigned(0));
426 short_mode = ((size_mode_value & 0x80) == 0);
428 ValueObjectSP size_mode(D->GetChildAtIndexPath({1, 0, 0}));
432 size_mode_value = (size_mode->GetValueAsUnsigned(0));
433 short_mode = ((size_mode_value & 1) == 0);
437 ValueObjectSP s(D->GetChildAtIndex(1, true));
440 location_sp = s->GetChildAtIndex(
441 (layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true);
442 size = (layout == eLibcxxStringLayoutModeDSC)
444 : ((size_mode_value >> 1) % 256);
445 return (location_sp.get() != nullptr);
447 ValueObjectSP l(D->GetChildAtIndex(0, true));
450 // we can use the layout_decider object as the data pointer
451 location_sp = (layout == eLibcxxStringLayoutModeDSC)
453 : l->GetChildAtIndex(2, true);
454 ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
455 if (!size_vo || !location_sp)
457 size = size_vo->GetValueAsUnsigned(0);
462 bool lldb_private::formatters::LibcxxWStringSummaryProvider(
463 ValueObject &valobj, Stream &stream,
464 const TypeSummaryOptions &summary_options) {
466 ValueObjectSP location_sp;
467 if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
470 stream.Printf("L\"\"");
476 DataExtractor extractor;
478 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
480 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
481 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
482 if (size > max_size) {
484 options.SetIsTruncated(true);
487 location_sp->GetPointeeData(extractor, 0, size);
489 // std::wstring::size() is measured in 'characters', not bytes
490 auto wchar_t_size = valobj.GetTargetSP()
491 ->GetScratchClangASTContext()
492 ->GetBasicType(lldb::eBasicTypeWChar)
493 .GetByteSize(nullptr);
495 options.SetData(extractor);
496 options.SetStream(&stream);
497 options.SetPrefixToken("L");
498 options.SetQuote('"');
499 options.SetSourceSize(size);
500 options.SetBinaryZeroIsTerminator(false);
502 switch (wchar_t_size) {
504 StringPrinter::ReadBufferAndDumpToStream<
505 lldb_private::formatters::StringPrinter::StringElementType::UTF8>(
510 lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream<
511 lldb_private::formatters::StringPrinter::StringElementType::UTF16>(
516 lldb_private::formatters::StringPrinter::ReadBufferAndDumpToStream<
517 lldb_private::formatters::StringPrinter::StringElementType::UTF32>(
522 stream.Printf("size for wchar_t is not valid");
529 bool lldb_private::formatters::LibcxxStringSummaryProvider(
530 ValueObject &valobj, Stream &stream,
531 const TypeSummaryOptions &summary_options) {
533 ValueObjectSP location_sp;
535 if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
539 stream.Printf("\"\"");
546 StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);
548 DataExtractor extractor;
549 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
550 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
551 if (size > max_size) {
553 options.SetIsTruncated(true);
556 location_sp->GetPointeeData(extractor, 0, size);
558 options.SetData(extractor);
559 options.SetStream(&stream);
560 options.SetPrefixToken(nullptr);
561 options.SetQuote('"');
562 options.SetSourceSize(size);
563 options.SetBinaryZeroIsTerminator(false);
564 StringPrinter::ReadBufferAndDumpToStream<
565 StringPrinter::StringElementType::ASCII>(options);
570 class LibcxxFunctionFrontEnd : public SyntheticValueProviderFrontEnd {
572 LibcxxFunctionFrontEnd(ValueObject &backend)
573 : SyntheticValueProviderFrontEnd(backend) {}
575 lldb::ValueObjectSP GetSyntheticValue() override {
576 static ConstString g___f_("__f_");
577 return m_backend.GetChildMemberWithName(g___f_, true);
581 SyntheticChildrenFrontEnd *
582 lldb_private::formatters::LibcxxFunctionFrontEndCreator(
583 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
585 return new LibcxxFunctionFrontEnd(*valobj_sp);