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