LLDB mainline
LibCxx.cpp
Go to the documentation of this file.
1//===-- LibCxx.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 "LibCxx.h"
10
11#include "lldb/Core/Debugger.h"
21#include "lldb/Target/Target.h"
24#include "lldb/Utility/Endian.h"
25#include "lldb/Utility/Status.h"
26#include "lldb/Utility/Stream.h"
27
31#include <optional>
32#include <tuple>
33
34using namespace lldb;
35using namespace lldb_private;
36using namespace lldb_private::formatters;
37
39 ValueObject &obj, llvm::ArrayRef<ConstString> alternative_names) {
40 for (ConstString name : alternative_names) {
41 lldb::ValueObjectSP child_sp = obj.GetChildMemberWithName(name, true);
42
43 if (child_sp)
44 return child_sp;
45 }
46 return {};
47}
48
50 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
51 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
52 if (!valobj_sp)
53 return false;
54
55 // An optional either contains a value or not, the member __engaged_ is
56 // a bool flag, it is true if the optional has a value and false otherwise.
57 ValueObjectSP engaged_sp(
58 valobj_sp->GetChildMemberWithName(ConstString("__engaged_"), true));
59
60 if (!engaged_sp)
61 return false;
62
63 llvm::StringRef engaged_as_cstring(
64 engaged_sp->GetValueAsUnsigned(0) == 1 ? "true" : "false");
65
66 stream.Printf(" Has Value=%s ", engaged_as_cstring.data());
67
68 return true;
69}
70
72 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
73
74 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
75
76 if (!valobj_sp)
77 return false;
78
79 ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef());
80 Process *process = exe_ctx.GetProcessPtr();
81
82 if (process == nullptr)
83 return false;
84
85 CPPLanguageRuntime *cpp_runtime = CPPLanguageRuntime::Get(*process);
86
87 if (!cpp_runtime)
88 return false;
89
91 cpp_runtime->FindLibCppStdFunctionCallableInfo(valobj_sp);
92
93 switch (callable_info.callable_case) {
94 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Invalid:
95 stream.Printf(" __f_ = %" PRIu64, callable_info.member_f_pointer_value);
96 return false;
97 break;
98 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Lambda:
99 stream.Printf(
100 " Lambda in File %s at Line %u",
102 callable_info.callable_line_entry.line);
103 break;
104 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::CallableObject:
105 stream.Printf(
106 " Function in File %s at Line %u",
108 callable_info.callable_line_entry.line);
109 break;
110 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::FreeOrMemberFunction:
111 stream.Printf(" Function = %s ",
112 callable_info.callable_symbol.GetName().GetCString());
113 break;
114 }
115
116 return true;
117}
118
120 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
121 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
122 if (!valobj_sp)
123 return false;
124 ValueObjectSP ptr_sp(
125 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true));
126 ValueObjectSP count_sp(valobj_sp->GetChildAtNamePath(
127 {ConstString("__cntrl_"), ConstString("__shared_owners_")}));
128 ValueObjectSP weakcount_sp(valobj_sp->GetChildAtNamePath(
129 {ConstString("__cntrl_"), ConstString("__shared_weak_owners_")}));
130
131 if (!ptr_sp)
132 return false;
133
134 if (ptr_sp->GetValueAsUnsigned(0) == 0) {
135 stream.Printf("nullptr");
136 return true;
137 } else {
138 bool print_pointee = false;
140 ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
141 if (pointee_sp && error.Success()) {
142 if (pointee_sp->DumpPrintableRepresentation(
145 ValueObject::PrintableRepresentationSpecialCases::eDisable,
146 false))
147 print_pointee = true;
148 }
149 if (!print_pointee)
150 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
151 }
152
153 if (count_sp)
154 stream.Printf(" strong=%" PRIu64, 1 + count_sp->GetValueAsUnsigned(0));
155
156 if (weakcount_sp)
157 stream.Printf(" weak=%" PRIu64, 1 + weakcount_sp->GetValueAsUnsigned(0));
158
159 return true;
160}
161
163 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
164 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
165 if (!valobj_sp)
166 return false;
167
168 ValueObjectSP ptr_sp(
169 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true));
170 if (!ptr_sp)
171 return false;
172
173 ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp);
174 if (!ptr_sp)
175 return false;
176
177 if (ptr_sp->GetValueAsUnsigned(0) == 0) {
178 stream.Printf("nullptr");
179 return true;
180 } else {
181 bool print_pointee = false;
183 ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
184 if (pointee_sp && error.Success()) {
185 if (pointee_sp->DumpPrintableRepresentation(
188 ValueObject::PrintableRepresentationSpecialCases::eDisable,
189 false))
190 print_pointee = true;
191 }
192 if (!print_pointee)
193 stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
194 }
195
196 return true;
197}
198
199/*
200 (lldb) fr var ibeg --raw --ptr-depth 1
201 (std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::pair<int,
202 std::__1::basic_string<char, std::__1::char_traits<char>,
203 std::__1::allocator<char> > >, std::__1::__tree_node<std::__1::pair<int,
204 std::__1::basic_string<char, std::__1::char_traits<char>,
205 std::__1::allocator<char> > >, void *> *, long> >) ibeg = {
206 __i_ = {
207 __ptr_ = 0x0000000100103870 {
208 std::__1::__tree_node_base<void *> = {
209 std::__1::__tree_end_node<std::__1::__tree_node_base<void *> *> = {
210 __left_ = 0x0000000000000000
211 }
212 __right_ = 0x0000000000000000
213 __parent_ = 0x00000001001038b0
214 __is_black_ = true
215 }
216 __value_ = {
217 first = 0
218 second = { std::string }
219 */
220
222 LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
223 : SyntheticChildrenFrontEnd(*valobj_sp), m_pair_ptr(), m_pair_sp() {
224 if (valobj_sp)
225 Update();
226}
227
229 m_pair_sp.reset();
230 m_pair_ptr = nullptr;
231
232 ValueObjectSP valobj_sp = m_backend.GetSP();
233 if (!valobj_sp)
234 return false;
235
236 TargetSP target_sp(valobj_sp->GetTargetSP());
237
238 if (!target_sp)
239 return false;
240
241 if (!valobj_sp)
242 return false;
243
244 static ConstString g_i_("__i_");
245
246 // this must be a ValueObject* because it is a child of the ValueObject we
247 // are producing children for it if were a ValueObjectSP, we would end up
248 // with a loop (iterator -> synthetic -> child -> parent == iterator) and
249 // that would in turn leak memory by never allowing the ValueObjects to die
250 // and free their memory
251 m_pair_ptr = valobj_sp
252 ->GetValueForExpressionPath(
253 ".__i_.__ptr_->__value_", nullptr, nullptr,
255 .DontCheckDotVsArrowSyntax()
256 .SetSyntheticChildrenTraversal(
258 SyntheticChildrenTraversal::None),
259 nullptr)
260 .get();
261
262 if (!m_pair_ptr) {
263 m_pair_ptr = valobj_sp
264 ->GetValueForExpressionPath(
265 ".__i_.__ptr_", nullptr, nullptr,
267 .DontCheckDotVsArrowSyntax()
268 .SetSyntheticChildrenTraversal(
270 SyntheticChildrenTraversal::None),
271 nullptr)
272 .get();
273 if (m_pair_ptr) {
274 auto __i_(valobj_sp->GetChildMemberWithName(g_i_, true));
275 if (!__i_) {
276 m_pair_ptr = nullptr;
277 return false;
278 }
279 CompilerType pair_type(
280 __i_->GetCompilerType().GetTypeTemplateArgument(0));
281 std::string name;
282 uint64_t bit_offset_ptr;
283 uint32_t bitfield_bit_size_ptr;
284 bool is_bitfield_ptr;
285 pair_type = pair_type.GetFieldAtIndex(
286 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
287 if (!pair_type) {
288 m_pair_ptr = nullptr;
289 return false;
290 }
291
292 auto addr(m_pair_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS));
293 m_pair_ptr = nullptr;
294 if (addr && addr != LLDB_INVALID_ADDRESS) {
295 auto ts = pair_type.GetTypeSystem();
296 auto ast_ctx = ts.dyn_cast_or_null<TypeSystemClang>();
297 if (!ast_ctx)
298 return false;
299
300 // Mimick layout of std::__tree_iterator::__ptr_ and read it in
301 // from process memory.
302 //
303 // The following shows the contiguous block of memory:
304 //
305 // +-----------------------------+ class __tree_end_node
306 // __ptr_ | pointer __left_; |
307 // +-----------------------------+ class __tree_node_base
308 // | pointer __right_; |
309 // | __parent_pointer __parent_; |
310 // | bool __is_black_; |
311 // +-----------------------------+ class __tree_node
312 // | __node_value_type __value_; | <<< our key/value pair
313 // +-----------------------------+
314 //
315 CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(
316 ConstString(),
317 {{"ptr0",
318 ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
319 {"ptr1",
320 ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
321 {"ptr2",
322 ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
323 {"cw", ast_ctx->GetBasicType(lldb::eBasicTypeBool)},
324 {"payload", pair_type}});
325 std::optional<uint64_t> size = tree_node_type.GetByteSize(nullptr);
326 if (!size)
327 return false;
328 WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
329 ProcessSP process_sp(target_sp->GetProcessSP());
331 process_sp->ReadMemory(addr, buffer_sp->GetBytes(),
332 buffer_sp->GetByteSize(), error);
333 if (error.Fail())
334 return false;
335 DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(),
336 process_sp->GetAddressByteSize());
337 auto pair_sp = CreateValueObjectFromData(
338 "pair", extractor, valobj_sp->GetExecutionContextRef(),
339 tree_node_type);
340 if (pair_sp)
341 m_pair_sp = pair_sp->GetChildAtIndex(4, true);
342 }
343 }
344 }
345
346 return false;
347}
348
351 return 2;
352}
353
354lldb::ValueObjectSP
356 size_t idx) {
357 if (m_pair_ptr)
358 return m_pair_ptr->GetChildAtIndex(idx, true);
359 if (m_pair_sp)
360 return m_pair_sp->GetChildAtIndex(idx, true);
361 return lldb::ValueObjectSP();
362}
363
366 return true;
367}
368
371 if (name == "first")
372 return 0;
373 if (name == "second")
374 return 1;
375 return UINT32_MAX;
376}
377
380 // this will be deleted when its parent dies (since it's a child object)
381 // delete m_pair_ptr;
382}
383
386 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
387 return (valobj_sp ? new LibCxxMapIteratorSyntheticFrontEnd(valobj_sp)
388 : nullptr);
389}
390
392 LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
393 : SyntheticChildrenFrontEnd(*valobj_sp) {
394 if (valobj_sp)
395 Update();
396}
397
399 Update() {
400 m_pair_sp.reset();
401 m_iter_ptr = nullptr;
402
403 ValueObjectSP valobj_sp = m_backend.GetSP();
404 if (!valobj_sp)
405 return false;
406
407 TargetSP target_sp(valobj_sp->GetTargetSP());
408
409 if (!target_sp)
410 return false;
411
412 if (!valobj_sp)
413 return false;
414
415 auto exprPathOptions = ValueObject::GetValueForExpressionPathOptions()
419 SyntheticChildrenTraversal::None);
420
421 // This must be a ValueObject* because it is a child of the ValueObject we
422 // are producing children for it if were a ValueObjectSP, we would end up
423 // with a loop (iterator -> synthetic -> child -> parent == iterator) and
424 // that would in turn leak memory by never allowing the ValueObjects to die
425 // and free their memory.
426 m_iter_ptr =
427 valobj_sp
428 ->GetValueForExpressionPath(".__i_.__node_", nullptr, nullptr,
429 exprPathOptions, nullptr)
430 .get();
431
432 if (m_iter_ptr) {
433 auto iter_child(
434 valobj_sp->GetChildMemberWithName(ConstString("__i_"), true));
435 if (!iter_child) {
436 m_iter_ptr = nullptr;
437 return false;
438 }
439
440 CompilerType node_type(iter_child->GetCompilerType()
441 .GetTypeTemplateArgument(0)
442 .GetPointeeType());
443
444 CompilerType pair_type(node_type.GetTypeTemplateArgument(0));
445
446 std::string name;
447 uint64_t bit_offset_ptr;
448 uint32_t bitfield_bit_size_ptr;
449 bool is_bitfield_ptr;
450
451 pair_type = pair_type.GetFieldAtIndex(
452 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
453 if (!pair_type) {
454 m_iter_ptr = nullptr;
455 return false;
456 }
457
458 uint64_t addr = m_iter_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
459 m_iter_ptr = nullptr;
460
461 if (addr == 0 || addr == LLDB_INVALID_ADDRESS)
462 return false;
463
464 auto ts = pair_type.GetTypeSystem();
465 auto ast_ctx = ts.dyn_cast_or_null<TypeSystemClang>();
466 if (!ast_ctx)
467 return false;
468
469 // Mimick layout of std::__hash_iterator::__node_ and read it in
470 // from process memory.
471 //
472 // The following shows the contiguous block of memory:
473 //
474 // +-----------------------------+ class __hash_node_base
475 // __node_ | __next_pointer __next_; |
476 // +-----------------------------+ class __hash_node
477 // | size_t __hash_; |
478 // | __node_value_type __value_; | <<< our key/value pair
479 // +-----------------------------+
480 //
481 CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(
482 ConstString(),
483 {{"__next_",
484 ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
485 {"__hash_", ast_ctx->GetBasicType(lldb::eBasicTypeUnsignedLongLong)},
486 {"__value_", pair_type}});
487 std::optional<uint64_t> size = tree_node_type.GetByteSize(nullptr);
488 if (!size)
489 return false;
490 WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
491 ProcessSP process_sp(target_sp->GetProcessSP());
493 process_sp->ReadMemory(addr, buffer_sp->GetBytes(),
494 buffer_sp->GetByteSize(), error);
495 if (error.Fail())
496 return false;
497 DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(),
498 process_sp->GetAddressByteSize());
499 auto pair_sp = CreateValueObjectFromData(
500 "pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type);
501 if (pair_sp)
502 m_pair_sp = pair_sp->GetChildAtIndex(2, true);
503 }
504
505 return false;
506}
507
510 return 2;
511}
512
513lldb::ValueObjectSP lldb_private::formatters::
515 if (m_pair_sp)
516 return m_pair_sp->GetChildAtIndex(idx, true);
517 return lldb::ValueObjectSP();
518}
519
522 return true;
523}
524
527 if (name == "first")
528 return 0;
529 if (name == "second")
530 return 1;
531 return UINT32_MAX;
532}
533
536 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
537 return (valobj_sp ? new LibCxxUnorderedMapIteratorSyntheticFrontEnd(valobj_sp)
538 : nullptr);
539}
540
541/*
542 (lldb) fr var ibeg --raw --ptr-depth 1 -T
543 (std::__1::__wrap_iter<int *>) ibeg = {
544 (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 {
545 (int) *__i = 1
546 }
547 }
548*/
549
552 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
553 return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(
554 valobj_sp, {ConstString("__i_"), ConstString("__i")})
555 : nullptr);
556}
557
559 LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
560 : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr) {
561 if (valobj_sp)
562 Update();
563}
564
567 return (m_cntrl ? 1 : 0);
568}
569
570lldb::ValueObjectSP
572 size_t idx) {
573 if (!m_cntrl)
574 return lldb::ValueObjectSP();
575
576 ValueObjectSP valobj_sp = m_backend.GetSP();
577 if (!valobj_sp)
578 return lldb::ValueObjectSP();
579
580 if (idx == 0)
581 return valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true);
582
583 if (idx == 1) {
584 if (auto ptr_sp =
585 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true)) {
586 Status status;
587 auto value_sp = ptr_sp->Dereference(status);
588 if (status.Success()) {
589 auto value_type_sp =
590 valobj_sp->GetCompilerType().GetTypeTemplateArgument(0);
591 return value_sp->Cast(value_type_sp);
592 }
593 }
594 }
595
596 return lldb::ValueObjectSP();
597}
598
600 m_cntrl = nullptr;
601
602 ValueObjectSP valobj_sp = m_backend.GetSP();
603 if (!valobj_sp)
604 return false;
605
606 TargetSP target_sp(valobj_sp->GetTargetSP());
607 if (!target_sp)
608 return false;
609
610 lldb::ValueObjectSP cntrl_sp(
611 valobj_sp->GetChildMemberWithName(ConstString("__cntrl_"), true));
612
613 m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular
614 // dependency
615 return false;
616}
617
620 return true;
621}
622
625 if (name == "__ptr_")
626 return 0;
627 if (name == "$$dereference$$")
628 return 1;
629 return UINT32_MAX;
630}
631
634
637 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
638 return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp)
639 : nullptr);
640}
641
643 LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
644 : SyntheticChildrenFrontEnd(*valobj_sp) {
645 if (valobj_sp)
646 Update();
647}
648
651
654 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
655 return (valobj_sp ? new LibcxxUniquePtrSyntheticFrontEnd(valobj_sp)
656 : nullptr);
657}
658
661 return (m_value_ptr_sp ? 1 : 0);
662}
663
664lldb::ValueObjectSP
666 size_t idx) {
667 if (!m_value_ptr_sp)
668 return lldb::ValueObjectSP();
669
670 if (idx == 0)
671 return m_value_ptr_sp;
672
673 if (idx == 1) {
674 Status status;
675 auto value_sp = m_value_ptr_sp->Dereference(status);
676 if (status.Success()) {
677 return value_sp;
678 }
679 }
680
681 return lldb::ValueObjectSP();
682}
683
685 ValueObjectSP valobj_sp = m_backend.GetSP();
686 if (!valobj_sp)
687 return false;
688
689 ValueObjectSP ptr_sp(
690 valobj_sp->GetChildMemberWithName(ConstString("__ptr_"), true));
691 if (!ptr_sp)
692 return false;
693
694 m_value_ptr_sp = GetValueOfLibCXXCompressedPair(*ptr_sp);
695
696 return false;
697}
698
701 return true;
702}
703
706 if (name == "__value_")
707 return 0;
708 if (name == "$$dereference$$")
709 return 1;
710 return UINT32_MAX;
711}
712
714 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
715 if (valobj.IsPointerType()) {
716 uint64_t value = valobj.GetValueAsUnsigned(0);
717 if (!value)
718 return false;
719 stream.Printf("0x%016" PRIx64 " ", value);
720 }
721 return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr,
722 nullptr, nullptr, &valobj, false, false);
723}
724
725/// The field layout in a libc++ string (cap, side, data or data, size, cap).
726namespace {
727enum class StringLayout { CSD, DSC };
728}
729
730/// Determine the size in bytes of \p valobj (a libc++ std::string object) and
731/// extract its data payload. Return the size + payload pair.
732// TODO: Support big-endian architectures.
733static std::optional<std::pair<uint64_t, ValueObjectSP>>
735 ValueObjectSP valobj_r_sp =
736 valobj.GetChildMemberWithName(ConstString("__r_"), /*can_create=*/true);
737 if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
738 return {};
739
740 // __r_ is a compressed_pair of the actual data and the allocator. The data we
741 // want is in the first base class.
742 ValueObjectSP valobj_r_base_sp =
743 valobj_r_sp->GetChildAtIndex(0, /*can_create=*/true);
744 if (!valobj_r_base_sp)
745 return {};
746
747 ValueObjectSP valobj_rep_sp = valobj_r_base_sp->GetChildMemberWithName(
748 ConstString("__value_"), /*can_create=*/true);
749 if (!valobj_rep_sp)
750 return {};
751
752 ValueObjectSP l = valobj_rep_sp->GetChildMemberWithName(ConstString("__l"),
753 /*can_create=*/true);
754 if (!l)
755 return {};
756
757 StringLayout layout = l->GetIndexOfChildWithName(ConstString("__data_")) == 0
758 ? StringLayout::DSC
759 : StringLayout::CSD;
760
761 bool short_mode = false; // this means the string is in short-mode and the
762 // data is stored inline
763 bool using_bitmasks = true; // Whether the class uses bitmasks for the mode
764 // flag (pre-D123580).
765 uint64_t size;
766 uint64_t size_mode_value = 0;
767
768 ValueObjectSP short_sp = valobj_rep_sp->GetChildMemberWithName(
769 ConstString("__s"), /*can_create=*/true);
770 if (!short_sp)
771 return {};
772
773 ValueObjectSP is_long =
774 short_sp->GetChildMemberWithName(ConstString("__is_long_"), true);
775 ValueObjectSP size_sp =
776 short_sp->GetChildAtNamePath({ConstString("__size_")});
777 if (!size_sp)
778 return {};
779
780 if (is_long) {
781 using_bitmasks = false;
782 short_mode = !is_long->GetValueAsUnsigned(/*fail_value=*/0);
783 size = size_sp->GetValueAsUnsigned(/*fail_value=*/0);
784 } else {
785 // The string mode is encoded in the size field.
786 size_mode_value = size_sp->GetValueAsUnsigned(0);
787 uint8_t mode_mask = layout == StringLayout::DSC ? 0x80 : 1;
788 short_mode = (size_mode_value & mode_mask) == 0;
789 }
790
791 if (short_mode) {
792 ValueObjectSP location_sp =
793 short_sp->GetChildMemberWithName(ConstString("__data_"), true);
794 if (using_bitmasks)
795 size = (layout == StringLayout::DSC) ? size_mode_value
796 : ((size_mode_value >> 1) % 256);
797
798 // When the small-string optimization takes place, the data must fit in the
799 // inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's
800 // likely that the string isn't initialized and we're reading garbage.
801 ExecutionContext exe_ctx(location_sp->GetExecutionContextRef());
802 const std::optional<uint64_t> max_bytes =
803 location_sp->GetCompilerType().GetByteSize(
805 if (!max_bytes || size > *max_bytes || !location_sp)
806 return {};
807
808 return std::make_pair(size, location_sp);
809 }
810
811 // we can use the layout_decider object as the data pointer
812 ValueObjectSP location_sp =
813 l->GetChildMemberWithName(ConstString("__data_"), /*can_create=*/true);
814 ValueObjectSP size_vo =
815 l->GetChildMemberWithName(ConstString("__size_"), /*can_create=*/true);
816 ValueObjectSP capacity_vo =
817 l->GetChildMemberWithName(ConstString("__cap_"), /*can_create=*/true);
818 if (!size_vo || !location_sp || !capacity_vo)
819 return {};
820 size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);
821 uint64_t capacity = capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);
822 if (!using_bitmasks && layout == StringLayout::CSD)
823 capacity *= 2;
824 if (size == LLDB_INVALID_OFFSET || capacity == LLDB_INVALID_OFFSET ||
825 capacity < size)
826 return {};
827 return std::make_pair(size, location_sp);
828}
829
830static bool
832 const TypeSummaryOptions &summary_options,
833 ValueObjectSP location_sp, size_t size) {
834 if (size == 0) {
835 stream.Printf("L\"\"");
836 return true;
837 }
838 if (!location_sp)
839 return false;
840
842 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
843 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
844 if (size > max_size) {
845 size = max_size;
846 options.SetIsTruncated(true);
847 }
848 }
849
850 DataExtractor extractor;
851 const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
852 if (bytes_read < size)
853 return false;
854
855 // std::wstring::size() is measured in 'characters', not bytes
856 TypeSystemClangSP scratch_ts_sp =
858 if (!scratch_ts_sp)
859 return false;
860
861 auto wchar_t_size =
862 scratch_ts_sp->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr);
863 if (!wchar_t_size)
864 return false;
865
866 options.SetData(std::move(extractor));
867 options.SetStream(&stream);
868 options.SetPrefixToken("L");
869 options.SetQuote('"');
870 options.SetSourceSize(size);
871 options.SetBinaryZeroIsTerminator(false);
872
873 switch (*wchar_t_size) {
874 case 1:
876 lldb_private::formatters::StringPrinter::StringElementType::UTF8>(
877 options);
878 break;
879
880 case 2:
882 lldb_private::formatters::StringPrinter::StringElementType::UTF16>(
883 options);
884 break;
885
886 case 4:
888 lldb_private::formatters::StringPrinter::StringElementType::UTF32>(
889 options);
890 }
891 return false;
892}
893
895 ValueObject &valobj, Stream &stream,
896 const TypeSummaryOptions &summary_options) {
897 auto string_info = ExtractLibcxxStringInfo(valobj);
898 if (!string_info)
899 return false;
900 uint64_t size;
901 ValueObjectSP location_sp;
902 std::tie(size, location_sp) = *string_info;
903
904 return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,
905 location_sp, size);
906}
907
908template <StringPrinter::StringElementType element_type>
909static bool
911 const TypeSummaryOptions &summary_options,
912 std::string prefix_token, ValueObjectSP location_sp,
913 uint64_t size) {
914
915 if (size == 0) {
916 stream.Printf("\"\"");
917 return true;
918 }
919
920 if (!location_sp)
921 return false;
922
924
925 if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {
926 const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();
927 if (size > max_size) {
928 size = max_size;
929 options.SetIsTruncated(true);
930 }
931 }
932
933 {
934 DataExtractor extractor;
935 const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);
936 if (bytes_read < size)
937 return false;
938
939 options.SetData(std::move(extractor));
940 }
941 options.SetStream(&stream);
942 if (prefix_token.empty())
943 options.SetPrefixToken(nullptr);
944 else
945 options.SetPrefixToken(prefix_token);
946 options.SetQuote('"');
947 options.SetSourceSize(size);
948 options.SetBinaryZeroIsTerminator(false);
949 return StringPrinter::ReadBufferAndDumpToStream<element_type>(options);
950}
951
952template <StringPrinter::StringElementType element_type>
953static bool
955 const TypeSummaryOptions &summary_options,
956 std::string prefix_token) {
957 auto string_info = ExtractLibcxxStringInfo(valobj);
958 if (!string_info)
959 return false;
960 uint64_t size;
961 ValueObjectSP location_sp;
962 std::tie(size, location_sp) = *string_info;
963
964 return LibcxxStringSummaryProvider<element_type>(
965 valobj, stream, summary_options, prefix_token, location_sp, size);
966}
967template <StringPrinter::StringElementType element_type>
968static bool formatStringImpl(ValueObject &valobj, Stream &stream,
969 const TypeSummaryOptions &summary_options,
970 std::string prefix_token) {
971 StreamString scratch_stream;
972 const bool success = LibcxxStringSummaryProvider<element_type>(
973 valobj, scratch_stream, summary_options, prefix_token);
974 if (success)
975 stream << scratch_stream.GetData();
976 else
977 stream << "Summary Unavailable";
978 return true;
979}
980
982 ValueObject &valobj, Stream &stream,
983 const TypeSummaryOptions &summary_options) {
984 return formatStringImpl<StringPrinter::StringElementType::ASCII>(
985 valobj, stream, summary_options, "");
986}
987
989 ValueObject &valobj, Stream &stream,
990 const TypeSummaryOptions &summary_options) {
991 return formatStringImpl<StringPrinter::StringElementType::UTF16>(
992 valobj, stream, summary_options, "u");
993}
994
996 ValueObject &valobj, Stream &stream,
997 const TypeSummaryOptions &summary_options) {
998 return formatStringImpl<StringPrinter::StringElementType::UTF32>(
999 valobj, stream, summary_options, "U");
1000}
1001
1002static std::tuple<bool, ValueObjectSP, size_t>
1004 auto dataobj = GetChildMemberWithName(
1005 valobj, {ConstString("__data_"), ConstString("__data")});
1006 auto sizeobj = GetChildMemberWithName(
1007 valobj, {ConstString("__size_"), ConstString("__size")});
1008 if (!dataobj || !sizeobj)
1009 return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});
1010
1011 if (!dataobj->GetError().Success() || !sizeobj->GetError().Success())
1012 return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});
1013
1014 bool success{false};
1015 uint64_t size = sizeobj->GetValueAsUnsigned(0, &success);
1016 if (!success)
1017 return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});
1018
1019 return std::make_tuple(true,dataobj,size);
1020}
1021
1022template <StringPrinter::StringElementType element_type>
1023static bool formatStringViewImpl(ValueObject &valobj, Stream &stream,
1024 const TypeSummaryOptions &summary_options,
1025 std::string prefix_token) {
1026
1027 bool success;
1028 ValueObjectSP dataobj;
1029 size_t size;
1030 std::tie(success, dataobj, size) = LibcxxExtractStringViewData(valobj);
1031
1032 if (!success) {
1033 stream << "Summary Unavailable";
1034 return true;
1035 }
1036
1037 return LibcxxStringSummaryProvider<element_type>(
1038 valobj, stream, summary_options, prefix_token, dataobj, size);
1039}
1040
1042 ValueObject &valobj, Stream &stream,
1043 const TypeSummaryOptions &summary_options) {
1044 return formatStringViewImpl<StringPrinter::StringElementType::ASCII>(
1045 valobj, stream, summary_options, "");
1046}
1047
1049 ValueObject &valobj, Stream &stream,
1050 const TypeSummaryOptions &summary_options) {
1051 return formatStringViewImpl<StringPrinter::StringElementType::UTF16>(
1052 valobj, stream, summary_options, "u");
1053}
1054
1056 ValueObject &valobj, Stream &stream,
1057 const TypeSummaryOptions &summary_options) {
1058 return formatStringViewImpl<StringPrinter::StringElementType::UTF32>(
1059 valobj, stream, summary_options, "U");
1060}
1061
1063 ValueObject &valobj, Stream &stream,
1064 const TypeSummaryOptions &summary_options) {
1065
1066 bool success;
1067 ValueObjectSP dataobj;
1068 size_t size;
1069 std::tie( success, dataobj, size ) = LibcxxExtractStringViewData(valobj);
1070
1071 if (!success) {
1072 stream << "Summary Unavailable";
1073 return true;
1074 }
1075
1076
1077 return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,
1078 dataobj, size);
1079}
static llvm::raw_ostream & error(Stream &strm)
static bool formatStringImpl(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options, std::string prefix_token)
Definition: LibCxx.cpp:968
static std::optional< std::pair< uint64_t, ValueObjectSP > > ExtractLibcxxStringInfo(ValueObject &valobj)
Determine the size in bytes of valobj (a libc++ std::string object) and extract its data payload.
Definition: LibCxx.cpp:734
static bool formatStringViewImpl(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options, std::string prefix_token)
Definition: LibCxx.cpp:1023
static bool LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options, std::string prefix_token, ValueObjectSP location_sp, uint64_t size)
Definition: LibCxx.cpp:910
static std::tuple< bool, ValueObjectSP, size_t > LibcxxExtractStringViewData(ValueObject &valobj)
Definition: LibCxx.cpp:1003
LibCppStdFunctionCallableInfo FindLibCppStdFunctionCallableInfo(lldb::ValueObjectSP &valobj_sp)
static CPPLanguageRuntime * Get(Process &process)
std::shared_ptr< TypeSystemType > dyn_cast_or_null()
Return a shared_ptr<TypeSystemType> if dyn_cast succeeds.
Definition: CompilerType.h:68
Generic representation of a type in a programming language.
Definition: CompilerType.h:36
CompilerType GetTypeTemplateArgument(size_t idx, bool expand_pack=false) const
TypeSystemSPWrapper GetTypeSystem() const
Accessors.
std::optional< uint64_t > GetByteSize(ExecutionContextScope *exe_scope) const
Return the size of the type in bytes.
CompilerType GetFieldAtIndex(size_t idx, std::string &name, uint64_t *bit_offset_ptr, uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) const
A uniqued constant string class.
Definition: ConstString.h:39
const char * GetCString() const
Get the string value as a C string.
Definition: ConstString.h:215
A subclass of DataBuffer that stores a data buffer on the heap.
An data extractor class.
Definition: DataExtractor.h:48
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
ExecutionContextScope * GetBestExecutionContextScope() const
Process * GetProcessPtr() const
Returns a pointer to the process object.
const ConstString & GetFilename() const
Filename string const get accessor.
Definition: FileSpec.h:240
static bool FormatStringRef(const llvm::StringRef &format, Stream &s, const SymbolContext *sc, const ExecutionContext *exe_ctx, const Address *addr, ValueObject *valobj, bool function_changed, bool initial_function)
A plug-in interface definition class for debugging a process.
Definition: Process.h:342
static lldb::TypeSystemClangSP GetForTarget(Target &target, std::optional< IsolatedASTKind > ast_kind=DefaultAST, bool create_on_demand=true)
Returns the scratch TypeSystemClang for the given target.
An error handling class.
Definition: Status.h:44
bool Success() const
Test for success condition.
Definition: Status.cpp:287
const char * GetData() const
Definition: StreamString.h:43
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:107
ConstString GetName() const
Definition: Symbol.cpp:500
lldb::TypeSummaryCapping GetCapping() const
Definition: TypeSummary.cpp:33
A TypeSystem implementation based on Clang.
virtual uint64_t GetValueAsUnsigned(uint64_t fail_value, bool *success=nullptr)
lldb::TargetSP GetTargetSP() const
Definition: ValueObject.h:334
virtual bool IsPointerType()
Definition: ValueObject.h:382
virtual lldb::ValueObjectSP GetChildMemberWithName(ConstString name, bool can_create)
virtual lldb::ValueObjectSP GetNonSyntheticValue()
Definition: ValueObject.h:592
size_t GetIndexOfChildWithName(ConstString name) override
Definition: LibCxx.cpp:370
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
Definition: LibCxx.cpp:355
LibCxxMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
Definition: LibCxx.cpp:222
Formats libcxx's std::unordered_map iterators.
Definition: LibCxx.h:132
LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
Definition: LibCxx.cpp:392
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
Definition: LibCxx.cpp:514
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
Definition: LibCxx.cpp:571
LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
Definition: LibCxx.cpp:559
size_t GetIndexOfChildWithName(ConstString name) override
Definition: LibCxx.cpp:624
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
Definition: LibCxx.cpp:665
size_t GetIndexOfChildWithName(ConstString name) override
Definition: LibCxx.cpp:705
LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
Definition: LibCxx.cpp:643
static bool ReadBufferAndDumpToStream(const ReadBufferAndDumpToStreamOptions &options)
#define LLDB_INVALID_ADDRESS
Definition: lldb-defines.h:74
#define LLDB_INVALID_OFFSET
Definition: lldb-defines.h:85
#define UINT32_MAX
Definition: lldb-defines.h:19
SyntheticChildrenFrontEnd * LibCxxUnorderedMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
Definition: LibCxx.cpp:535
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:38
SyntheticChildrenFrontEnd * LibcxxUniquePtrSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
Definition: LibCxx.cpp:653
bool LibcxxUniquePointerSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: LibCxx.cpp:162
bool LibcxxOptionalSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: LibCxx.cpp:49
bool LibcxxSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: LibCxx.cpp:119
bool LibcxxStringViewSummaryProviderASCII(ValueObject &valueObj, Stream &stream, const TypeSummaryOptions &summary_options)
Definition: LibCxx.cpp:1041
bool LibcxxStringViewSummaryProviderUTF16(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options)
Definition: LibCxx.cpp:1048
SyntheticChildrenFrontEnd * LibCxxVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
Definition: LibCxx.cpp:551
bool LibcxxStringViewSummaryProviderUTF32(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options)
Definition: LibCxx.cpp:1055
bool LibcxxWStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: LibCxx.cpp:894
bool LibcxxStringSummaryProviderASCII(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options)
Definition: LibCxx.cpp:981
bool LibcxxWStringViewSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: LibCxx.cpp:1062
bool LibcxxStringSummaryProviderUTF16(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options)
Definition: LibCxx.cpp:988
bool LibcxxFunctionSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: LibCxx.cpp:71
bool LibcxxStringSummaryProviderUTF32(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &summary_options)
Definition: LibCxx.cpp:995
lldb::ValueObjectSP GetValueOfLibCXXCompressedPair(ValueObject &pair)
bool LibcxxContainerSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: LibCxx.cpp:713
SyntheticChildrenFrontEnd * LibcxxSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
Definition: LibCxx.cpp:636
SyntheticChildrenFrontEnd * LibCxxMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
Definition: LibCxx.cpp:385
A class that represents a running process on the host machine.
Definition: SBAddress.h:15
@ eBasicTypeUnsignedLongLong
FileSpec file
The source file, possibly mapped by the target.source-map setting.
Definition: LineEntry.h:140
uint32_t line
The source line number, or zero if there is no line number information.
Definition: LineEntry.h:143
GetValueForExpressionPathOptions & SetSyntheticChildrenTraversal(SyntheticChildrenTraversal traverse)
Definition: ValueObject.h:248
GetValueForExpressionPathOptions & DontCheckDotVsArrowSyntax()
Definition: ValueObject.h:222