920 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "LibCxx.h"10 11#include "lldb/Core/Debugger.h"12#include "lldb/Core/FormatEntity.h"13#include "lldb/DataFormatters/FormattersHelpers.h"14#include "lldb/DataFormatters/StringPrinter.h"15#include "lldb/DataFormatters/TypeSummary.h"16#include "lldb/DataFormatters/VectorIterator.h"17#include "lldb/Target/SectionLoadList.h"18#include "lldb/Target/Target.h"19#include "lldb/Utility/ConstString.h"20#include "lldb/Utility/DataBufferHeap.h"21#include "lldb/Utility/Endian.h"22#include "lldb/Utility/Status.h"23#include "lldb/Utility/Stream.h"24#include "lldb/ValueObject/ValueObject.h"25#include "lldb/ValueObject/ValueObjectConstResult.h"26 27#include "Plugins/Language/CPlusPlus/CxxStringTypes.h"28#include "Plugins/Language/CPlusPlus/Generic.h"29#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"30#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"31#include "lldb/lldb-enumerations.h"32#include "lldb/lldb-forward.h"33#include <optional>34#include <tuple>35 36using namespace lldb;37using namespace lldb_private;38using namespace lldb_private::formatters;39 40static void consumeInlineNamespace(llvm::StringRef &name) {41 // Delete past an inline namespace, if any: __[a-zA-Z0-9_]+::42 auto scratch = name;43 if (scratch.consume_front("__") &&44 std::isalnum(static_cast<unsigned char>(scratch[0]))) {45 scratch = scratch.drop_while(46 [](char c) { return std::isalnum(static_cast<unsigned char>(c)); });47 if (scratch.consume_front("::")) {48 // Successfully consumed a namespace.49 name = scratch;50 }51 }52}53 54bool lldb_private::formatters::isStdTemplate(ConstString type_name,55 llvm::StringRef type) {56 llvm::StringRef name = type_name.GetStringRef();57 // The type name may be prefixed with `std::__<inline-namespace>::`.58 if (name.consume_front("std::"))59 consumeInlineNamespace(name);60 return name.consume_front(type) && name.starts_with("<");61}62 63lldb::ValueObjectSP lldb_private::formatters::GetChildMemberWithName(64 ValueObject &obj, llvm::ArrayRef<ConstString> alternative_names) {65 for (ConstString name : alternative_names) {66 lldb::ValueObjectSP child_sp = obj.GetChildMemberWithName(name);67 68 if (child_sp)69 return child_sp;70 }71 return {};72}73 74lldb::ValueObjectSP75lldb_private::formatters::GetFirstValueOfLibCXXCompressedPair(76 ValueObject &pair) {77 ValueObjectSP value;78 ValueObjectSP first_child = pair.GetChildAtIndex(0);79 if (first_child)80 value = first_child->GetChildMemberWithName("__value_");81 if (!value) {82 // pre-c88580c member name83 value = pair.GetChildMemberWithName("__first_");84 }85 return value;86}87 88lldb::ValueObjectSP89lldb_private::formatters::GetSecondValueOfLibCXXCompressedPair(90 ValueObject &pair) {91 ValueObjectSP value;92 if (pair.GetNumChildrenIgnoringErrors() > 1) {93 ValueObjectSP second_child = pair.GetChildAtIndex(1);94 if (second_child) {95 value = second_child->GetChildMemberWithName("__value_");96 }97 }98 if (!value) {99 // pre-c88580c member name100 value = pair.GetChildMemberWithName("__second_");101 }102 return value;103}104 105std::pair<lldb::ValueObjectSP, bool>106lldb_private::formatters::GetValueOrOldCompressedPair(107 ValueObject &obj, size_t anon_struct_idx, llvm::StringRef child_name,108 llvm::StringRef compressed_pair_name) {109 auto is_old_compressed_pair = [](ValueObject &pair_obj) -> bool {110 return isStdTemplate(pair_obj.GetTypeName(), "__compressed_pair");111 };112 113 // Try searching the child member in an anonymous structure first.114 if (auto unwrapped = obj.GetChildAtIndex(anon_struct_idx)) {115 ValueObjectSP node_sp(obj.GetChildMemberWithName(child_name));116 if (node_sp)117 return {node_sp, is_old_compressed_pair(*node_sp)};118 }119 120 // Older versions of libc++ don't wrap the children in anonymous structures.121 // Try that instead.122 ValueObjectSP node_sp(obj.GetChildMemberWithName(child_name));123 if (node_sp)124 return {node_sp, is_old_compressed_pair(*node_sp)};125 126 // Try the even older __compressed_pair layout.127 128 assert(!compressed_pair_name.empty());129 130 node_sp = obj.GetChildMemberWithName(compressed_pair_name);131 132 // Unrecognized layout (possibly older than LLDB supports).133 if (!node_sp)134 return {nullptr, false};135 136 // Expected old compressed_pair layout, but got something else.137 if (!is_old_compressed_pair(*node_sp))138 return {nullptr, false};139 140 return {node_sp, true};141}142 143bool lldb_private::formatters::LibcxxFunctionSummaryProvider(144 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {145 146 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());147 148 if (!valobj_sp)149 return false;150 151 ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef());152 Process *process = exe_ctx.GetProcessPtr();153 154 if (process == nullptr)155 return false;156 157 CPPLanguageRuntime *cpp_runtime = CPPLanguageRuntime::Get(*process);158 159 if (!cpp_runtime)160 return false;161 162 CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info =163 cpp_runtime->FindLibCppStdFunctionCallableInfo(valobj_sp);164 165 switch (callable_info.callable_case) {166 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Invalid:167 stream.Printf(" __f_ = %" PRIu64, callable_info.member_f_pointer_value);168 return false;169 break;170 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Lambda:171 stream.Printf(172 " Lambda in File %s at Line %u",173 callable_info.callable_line_entry.GetFile().GetFilename().GetCString(),174 callable_info.callable_line_entry.line);175 break;176 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::CallableObject:177 stream.Printf(178 " Function in File %s at Line %u",179 callable_info.callable_line_entry.GetFile().GetFilename().GetCString(),180 callable_info.callable_line_entry.line);181 break;182 case CPPLanguageRuntime::LibCppStdFunctionCallableCase::FreeOrMemberFunction:183 stream.Printf(" Function = %s ",184 callable_info.callable_symbol.GetName().GetCString());185 break;186 }187 188 return true;189}190 191bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider(192 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {193 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());194 if (!valobj_sp)195 return false;196 197 ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));198 ValueObjectSP ctrl_sp(valobj_sp->GetChildMemberWithName("__cntrl_"));199 if (!ctrl_sp || !ptr_sp)200 return false;201 202 DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options);203 204 bool success;205 uint64_t ctrl_addr = ctrl_sp->GetValueAsUnsigned(0, &success);206 // Empty control field. We're done.207 if (!success || ctrl_addr == 0)208 return true;209 210 if (auto count_sp = ctrl_sp->GetChildMemberWithName("__shared_owners_")) {211 bool success;212 uint64_t count = count_sp->GetValueAsUnsigned(0, &success);213 if (!success)214 return false;215 216 // std::shared_ptr releases the underlying resource when the217 // __shared_owners_ count hits -1. So `__shared_owners_ == 0` indicates 1218 // owner. Hence add +1 here.219 stream.Printf(" strong=%" PRIu64, count + 1);220 }221 222 if (auto weak_count_sp =223 ctrl_sp->GetChildMemberWithName("__shared_weak_owners_")) {224 bool success;225 uint64_t count = weak_count_sp->GetValueAsUnsigned(0, &success);226 if (!success)227 return false;228 229 // Unlike __shared_owners_, __shared_weak_owners_ indicates the exact230 // std::weak_ptr reference count.231 stream.Printf(" weak=%" PRIu64, count);232 }233 234 return true;235}236 237bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(238 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {239 ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());240 if (!valobj_sp)241 return false;242 243 auto [ptr_sp, is_compressed_pair] = GetValueOrOldCompressedPair(244 *valobj_sp, /*anon_struct_idx=*/0, "__ptr_", "__ptr_");245 if (!ptr_sp)246 return false;247 248 if (is_compressed_pair)249 ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);250 251 if (!ptr_sp)252 return false;253 254 DumpCxxSmartPtrPointerSummary(stream, *ptr_sp, options);255 256 return true;257}258 259/*260 (lldb) fr var ibeg --raw --ptr-depth 1 -T261 (std::__1::__wrap_iter<int *>) ibeg = {262 (std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 {263 (int) *__i = 1264 }265 }266*/267 268SyntheticChildrenFrontEnd *269lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator(270 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {271 return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(272 valobj_sp, {ConstString("__i_"), ConstString("__i")})273 : nullptr);274}275 276lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::277 LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)278 : SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr),279 m_ptr_obj(nullptr) {280 if (valobj_sp)281 Update();282}283 284llvm::Expected<uint32_t> lldb_private::formatters::285 LibcxxSharedPtrSyntheticFrontEnd::CalculateNumChildren() {286 return (m_cntrl ? 1 : 0);287}288 289lldb::ValueObjectSP290lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex(291 uint32_t idx) {292 if (!m_cntrl || !m_ptr_obj)293 return lldb::ValueObjectSP();294 295 ValueObjectSP valobj_sp = m_backend.GetSP();296 if (!valobj_sp)297 return lldb::ValueObjectSP();298 299 if (idx == 0)300 return m_ptr_obj->GetSP();301 302 if (idx == 1) {303 Status status;304 ValueObjectSP value_sp = m_ptr_obj->Dereference(status);305 if (status.Success())306 return value_sp;307 }308 309 return lldb::ValueObjectSP();310}311 312lldb::ChildCacheState313lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() {314 m_cntrl = nullptr;315 m_ptr_obj = nullptr;316 317 ValueObjectSP valobj_sp = m_backend.GetSP();318 if (!valobj_sp)319 return lldb::ChildCacheState::eRefetch;320 321 TargetSP target_sp(valobj_sp->GetTargetSP());322 if (!target_sp)323 return lldb::ChildCacheState::eRefetch;324 325 auto ptr_obj_sp = valobj_sp->GetChildMemberWithName("__ptr_");326 if (!ptr_obj_sp)327 return lldb::ChildCacheState::eRefetch;328 329 auto cast_ptr_sp = GetDesugaredSmartPointerValue(*ptr_obj_sp, *valobj_sp);330 if (!cast_ptr_sp)331 return lldb::ChildCacheState::eRefetch;332 333 m_ptr_obj = cast_ptr_sp->Clone(ConstString("pointer")).get();334 335 lldb::ValueObjectSP cntrl_sp(valobj_sp->GetChildMemberWithName("__cntrl_"));336 337 m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular338 // dependency339 return lldb::ChildCacheState::eRefetch;340}341 342llvm::Expected<size_t>343lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::344 GetIndexOfChildWithName(ConstString name) {345 if (name == "pointer")346 return 0;347 348 if (name == "object" || name == "$$dereference$$")349 return 1;350 351 return llvm::createStringError("Type has no child named '%s'",352 name.AsCString());353}354 355lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::356 ~LibcxxSharedPtrSyntheticFrontEnd() = default;357 358SyntheticChildrenFrontEnd *359lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator(360 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {361 return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp)362 : nullptr);363}364 365lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::366 LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)367 : SyntheticChildrenFrontEnd(*valobj_sp) {368 if (valobj_sp)369 Update();370}371 372lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::373 ~LibcxxUniquePtrSyntheticFrontEnd() = default;374 375SyntheticChildrenFrontEnd *376lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator(377 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {378 return (valobj_sp ? new LibcxxUniquePtrSyntheticFrontEnd(valobj_sp)379 : nullptr);380}381 382llvm::Expected<uint32_t> lldb_private::formatters::383 LibcxxUniquePtrSyntheticFrontEnd::CalculateNumChildren() {384 if (m_value_ptr_sp)385 return m_deleter_sp ? 2 : 1;386 return 0;387}388 389lldb::ValueObjectSP390lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex(391 uint32_t idx) {392 if (!m_value_ptr_sp)393 return lldb::ValueObjectSP();394 395 if (idx == 0)396 return m_value_ptr_sp;397 398 if (idx == 1)399 return m_deleter_sp;400 401 if (idx == 2) {402 Status status;403 auto value_sp = m_value_ptr_sp->Dereference(status);404 if (status.Success()) {405 return value_sp;406 }407 }408 409 return lldb::ValueObjectSP();410}411 412lldb::ChildCacheState413lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {414 ValueObjectSP valobj_sp = m_backend.GetSP();415 if (!valobj_sp)416 return lldb::ChildCacheState::eRefetch;417 418 auto [ptr_sp, is_compressed_pair] = GetValueOrOldCompressedPair(419 *valobj_sp, /*anon_struct_idx=*/0, "__ptr_", "__ptr_");420 if (!ptr_sp)421 return lldb::ChildCacheState::eRefetch;422 423 // Retrieve the actual pointer and the deleter, and clone them to give them424 // user-friendly names.425 if (is_compressed_pair) {426 if (ValueObjectSP value_pointer_sp =427 GetFirstValueOfLibCXXCompressedPair(*ptr_sp))428 m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));429 430 if (ValueObjectSP deleter_sp =431 GetSecondValueOfLibCXXCompressedPair(*ptr_sp))432 m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));433 } else {434 m_value_ptr_sp = ptr_sp->Clone(ConstString("pointer"));435 436 if (ValueObjectSP deleter_sp =437 valobj_sp->GetChildMemberWithName("__deleter_"))438 if (deleter_sp->GetNumChildrenIgnoringErrors() > 0)439 m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));440 }441 442 return lldb::ChildCacheState::eRefetch;443}444 445llvm::Expected<size_t>446lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::447 GetIndexOfChildWithName(ConstString name) {448 if (name == "pointer")449 return 0;450 if (name == "deleter")451 return 1;452 if (name == "obj" || name == "object" || name == "$$dereference$$")453 return 2;454 return llvm::createStringError("Type has no child named '%s'",455 name.AsCString());456}457 458/// The field layout in a libc++ string (cap, side, data or data, size, cap).459namespace {460enum class StringLayout { CSD, DSC };461}462 463static ValueObjectSP ExtractLibCxxStringData(ValueObject &valobj) {464 auto [valobj_r_sp, is_compressed_pair] = GetValueOrOldCompressedPair(465 valobj, /*anon_struct_idx=*/0, "__rep_", "__r_");466 if (!valobj_r_sp)467 return nullptr;468 469 if (is_compressed_pair)470 return GetFirstValueOfLibCXXCompressedPair(*valobj_r_sp);471 472 return valobj_r_sp;473}474 475/// Determine the size in bytes of \p valobj (a libc++ std::string object) and476/// extract its data payload. Return the size + payload pair.477// TODO: Support big-endian architectures.478static std::optional<std::pair<uint64_t, ValueObjectSP>>479ExtractLibcxxStringInfo(ValueObject &valobj) {480 ValueObjectSP valobj_rep_sp = ExtractLibCxxStringData(valobj);481 if (!valobj_rep_sp || !valobj_rep_sp->GetError().Success())482 return {};483 484 ValueObjectSP l = valobj_rep_sp->GetChildMemberWithName("__l");485 if (!l)486 return {};487 488 auto index_or_err = l->GetIndexOfChildWithName("__data_");489 if (!index_or_err) {490 LLDB_LOG_ERROR(GetLog(LLDBLog::DataFormatters), index_or_err.takeError(),491 "{0}");492 return {};493 }494 495 StringLayout layout =496 *index_or_err == 0 ? StringLayout::DSC : StringLayout::CSD;497 498 bool short_mode = false; // this means the string is in short-mode and the499 // data is stored inline500 bool using_bitmasks = true; // Whether the class uses bitmasks for the mode501 // flag (pre-D123580).502 uint64_t size;503 uint64_t size_mode_value = 0;504 505 ValueObjectSP short_sp = valobj_rep_sp->GetChildMemberWithName("__s");506 if (!short_sp)507 return {};508 509 ValueObjectSP is_long = short_sp->GetChildMemberWithName("__is_long_");510 ValueObjectSP size_sp = short_sp->GetChildMemberWithName("__size_");511 if (!size_sp)512 return {};513 514 if (is_long) {515 using_bitmasks = false;516 short_mode = !is_long->GetValueAsUnsigned(/*fail_value=*/0);517 size = size_sp->GetValueAsUnsigned(/*fail_value=*/0);518 } else {519 // The string mode is encoded in the size field.520 size_mode_value = size_sp->GetValueAsUnsigned(0);521 uint8_t mode_mask = layout == StringLayout::DSC ? 0x80 : 1;522 short_mode = (size_mode_value & mode_mask) == 0;523 }524 525 if (short_mode) {526 ValueObjectSP location_sp = short_sp->GetChildMemberWithName("__data_");527 if (using_bitmasks)528 size = (layout == StringLayout::DSC) ? size_mode_value529 : ((size_mode_value >> 1) % 256);530 531 if (!location_sp)532 return {};533 534 // When the small-string optimization takes place, the data must fit in the535 // inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's536 // likely that the string isn't initialized and we're reading garbage.537 ExecutionContext exe_ctx(location_sp->GetExecutionContextRef());538 const std::optional<uint64_t> max_bytes =539 llvm::expectedToOptional(location_sp->GetCompilerType().GetByteSize(540 exe_ctx.GetBestExecutionContextScope()));541 if (!max_bytes || size > *max_bytes)542 return {};543 544 return std::make_pair(size, location_sp);545 }546 547 // we can use the layout_decider object as the data pointer548 ValueObjectSP location_sp = l->GetChildMemberWithName("__data_");549 ValueObjectSP size_vo = l->GetChildMemberWithName("__size_");550 ValueObjectSP capacity_vo = l->GetChildMemberWithName("__cap_");551 if (!size_vo || !location_sp || !capacity_vo)552 return {};553 size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);554 uint64_t capacity = capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);555 if (!using_bitmasks && layout == StringLayout::CSD)556 capacity *= 2;557 if (size == LLDB_INVALID_OFFSET || capacity == LLDB_INVALID_OFFSET ||558 capacity < size)559 return {};560 return std::make_pair(size, location_sp);561}562 563bool lldb_private::formatters::LibcxxWStringSummaryProvider(564 ValueObject &valobj, Stream &stream,565 const TypeSummaryOptions &summary_options) {566 auto string_info = ExtractLibcxxStringInfo(valobj);567 if (!string_info)568 return false;569 uint64_t size;570 ValueObjectSP location_sp;571 std::tie(size, location_sp) = *string_info;572 573 auto wchar_t_size = GetWCharByteSize(valobj);574 if (!wchar_t_size)575 return false;576 577 switch (*wchar_t_size) {578 case 1:579 return StringBufferSummaryProvider<StringPrinter::StringElementType::UTF8>(580 stream, summary_options, location_sp, size, "L");581 case 2:582 return StringBufferSummaryProvider<StringPrinter::StringElementType::UTF16>(583 stream, summary_options, location_sp, size, "L");584 case 4:585 return StringBufferSummaryProvider<StringPrinter::StringElementType::UTF32>(586 stream, summary_options, location_sp, size, "L");587 }588 return false;589}590 591template <StringPrinter::StringElementType element_type>592static bool593LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream,594 const TypeSummaryOptions &summary_options,595 std::string prefix_token) {596 auto string_info = ExtractLibcxxStringInfo(valobj);597 if (!string_info)598 return false;599 uint64_t size;600 ValueObjectSP location_sp;601 std::tie(size, location_sp) = *string_info;602 603 return StringBufferSummaryProvider<element_type>(604 stream, summary_options, location_sp, size, prefix_token);605}606template <StringPrinter::StringElementType element_type>607static bool formatStringImpl(ValueObject &valobj, Stream &stream,608 const TypeSummaryOptions &summary_options,609 std::string prefix_token) {610 StreamString scratch_stream;611 const bool success = LibcxxStringSummaryProvider<element_type>(612 valobj, scratch_stream, summary_options, prefix_token);613 if (success)614 stream << scratch_stream.GetData();615 else616 stream << "Summary Unavailable";617 return true;618}619 620bool lldb_private::formatters::LibcxxStringSummaryProviderASCII(621 ValueObject &valobj, Stream &stream,622 const TypeSummaryOptions &summary_options) {623 return formatStringImpl<StringPrinter::StringElementType::ASCII>(624 valobj, stream, summary_options, "");625}626 627bool lldb_private::formatters::LibcxxStringSummaryProviderUTF16(628 ValueObject &valobj, Stream &stream,629 const TypeSummaryOptions &summary_options) {630 return formatStringImpl<StringPrinter::StringElementType::UTF16>(631 valobj, stream, summary_options, "u");632}633 634bool lldb_private::formatters::LibcxxStringSummaryProviderUTF32(635 ValueObject &valobj, Stream &stream,636 const TypeSummaryOptions &summary_options) {637 return formatStringImpl<StringPrinter::StringElementType::UTF32>(638 valobj, stream, summary_options, "U");639}640 641static std::tuple<bool, ValueObjectSP, size_t>642LibcxxExtractStringViewData(ValueObject& valobj) {643 auto dataobj = GetChildMemberWithName(644 valobj, {ConstString("__data_"), ConstString("__data")});645 auto sizeobj = GetChildMemberWithName(646 valobj, {ConstString("__size_"), ConstString("__size")});647 if (!dataobj || !sizeobj)648 return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});649 650 if (!dataobj->GetError().Success() || !sizeobj->GetError().Success())651 return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});652 653 bool success{false};654 uint64_t size = sizeobj->GetValueAsUnsigned(0, &success);655 if (!success)656 return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});657 658 return std::make_tuple(true,dataobj,size);659}660 661template <StringPrinter::StringElementType element_type>662static bool formatStringViewImpl(ValueObject &valobj, Stream &stream,663 const TypeSummaryOptions &summary_options,664 std::string prefix_token) {665 666 bool success;667 ValueObjectSP dataobj;668 size_t size;669 std::tie(success, dataobj, size) = LibcxxExtractStringViewData(valobj);670 671 if (!success) {672 stream << "Summary Unavailable";673 return true;674 }675 676 return StringBufferSummaryProvider<element_type>(stream, summary_options,677 dataobj, size, prefix_token);678}679 680bool lldb_private::formatters::LibcxxStringViewSummaryProviderASCII(681 ValueObject &valobj, Stream &stream,682 const TypeSummaryOptions &summary_options) {683 return formatStringViewImpl<StringPrinter::StringElementType::ASCII>(684 valobj, stream, summary_options, "");685}686 687bool lldb_private::formatters::LibcxxStringViewSummaryProviderUTF16(688 ValueObject &valobj, Stream &stream,689 const TypeSummaryOptions &summary_options) {690 return formatStringViewImpl<StringPrinter::StringElementType::UTF16>(691 valobj, stream, summary_options, "u");692}693 694bool lldb_private::formatters::LibcxxStringViewSummaryProviderUTF32(695 ValueObject &valobj, Stream &stream,696 const TypeSummaryOptions &summary_options) {697 return formatStringViewImpl<StringPrinter::StringElementType::UTF32>(698 valobj, stream, summary_options, "U");699}700 701bool lldb_private::formatters::LibcxxWStringViewSummaryProvider(702 ValueObject &valobj, Stream &stream,703 const TypeSummaryOptions &summary_options) {704 705 bool success;706 ValueObjectSP dataobj;707 size_t size;708 std::tie(success, dataobj, size) = LibcxxExtractStringViewData(valobj);709 710 if (!success) {711 stream << "Summary Unavailable";712 return true;713 }714 715 auto wchar_t_size = GetWCharByteSize(valobj);716 if (!wchar_t_size)717 return false;718 719 switch (*wchar_t_size) {720 case 1:721 return StringBufferSummaryProvider<StringPrinter::StringElementType::UTF8>(722 stream, summary_options, dataobj, size, "L");723 case 2:724 return StringBufferSummaryProvider<StringPrinter::StringElementType::UTF16>(725 stream, summary_options, dataobj, size, "L");726 case 4:727 return StringBufferSummaryProvider<StringPrinter::StringElementType::UTF32>(728 stream, summary_options, dataobj, size, "L");729 }730 return false;731}732 733static bool734LibcxxChronoTimePointSecondsSummaryProvider(ValueObject &valobj, Stream &stream,735 const TypeSummaryOptions &options,736 const char *fmt) {737 ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__d_");738 if (!ptr_sp)739 return false;740 ptr_sp = ptr_sp->GetChildMemberWithName("__rep_");741 if (!ptr_sp)742 return false;743 744#ifndef _WIN32745 // The date time in the chrono library is valid in the range746 // [-32767-01-01T00:00:00Z, 32767-12-31T23:59:59Z]. A 64-bit time_t has a747 // larger range, the function strftime is not able to format the entire range748 // of time_t. The exact point has not been investigated; it's limited to749 // chrono's range.750 const std::time_t chrono_timestamp_min =751 -1'096'193'779'200; // -32767-01-01T00:00:00Z752 const std::time_t chrono_timestamp_max =753 971'890'963'199; // 32767-12-31T23:59:59Z754#else755 const std::time_t chrono_timestamp_min = -43'200; // 1969-12-31T12:00:00Z756 const std::time_t chrono_timestamp_max =757 32'536'850'399; // 3001-01-19T21:59:59758#endif759 760 const std::time_t seconds = ptr_sp->GetValueAsSigned(0);761 if (seconds < chrono_timestamp_min || seconds > chrono_timestamp_max)762 stream.Printf("timestamp=%" PRId64 " s", static_cast<int64_t>(seconds));763 else {764 std::array<char, 128> str;765 std::size_t size =766 std::strftime(str.data(), str.size(), fmt, gmtime(&seconds));767 if (size == 0)768 return false;769 770 stream.Printf("date/time=%s timestamp=%" PRId64 " s", str.data(),771 static_cast<int64_t>(seconds));772 }773 774 return true;775}776 777bool lldb_private::formatters::LibcxxChronoSysSecondsSummaryProvider(778 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {779 return LibcxxChronoTimePointSecondsSummaryProvider(valobj, stream, options,780 "%FT%H:%M:%SZ");781}782 783bool lldb_private::formatters::LibcxxChronoLocalSecondsSummaryProvider(784 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {785 return LibcxxChronoTimePointSecondsSummaryProvider(valobj, stream, options,786 "%FT%H:%M:%S");787}788 789static bool790LibcxxChronoTimepointDaysSummaryProvider(ValueObject &valobj, Stream &stream,791 const TypeSummaryOptions &options,792 const char *fmt) {793 ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__d_");794 if (!ptr_sp)795 return false;796 ptr_sp = ptr_sp->GetChildMemberWithName("__rep_");797 if (!ptr_sp)798 return false;799 800#ifndef _WIN32801 // The date time in the chrono library is valid in the range802 // [-32767-01-01Z, 32767-12-31Z]. A 32-bit time_t has a larger range, the803 // function strftime is not able to format the entire range of time_t. The804 // exact point has not been investigated; it's limited to chrono's range.805 const int chrono_timestamp_min = -12'687'428; // -32767-01-01Z806 const int chrono_timestamp_max = 11'248'737; // 32767-12-31Z807#else808 const int chrono_timestamp_min = 0; // 1970-01-01Z809 const int chrono_timestamp_max = 376'583; // 3001-01-19Z810#endif811 812 const int days = ptr_sp->GetValueAsSigned(0);813 if (days < chrono_timestamp_min || days > chrono_timestamp_max)814 stream.Printf("timestamp=%d days", days);815 816 else {817 const std::time_t seconds = std::time_t(86400) * days;818 819 std::array<char, 128> str;820 std::size_t size =821 std::strftime(str.data(), str.size(), fmt, gmtime(&seconds));822 if (size == 0)823 return false;824 825 stream.Printf("date=%s timestamp=%d days", str.data(), days);826 }827 828 return true;829}830 831bool lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider(832 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {833 return LibcxxChronoTimepointDaysSummaryProvider(valobj, stream, options,834 "%FZ");835}836 837bool lldb_private::formatters::LibcxxChronoLocalDaysSummaryProvider(838 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {839 return LibcxxChronoTimepointDaysSummaryProvider(valobj, stream, options,840 "%F");841}842 843bool lldb_private::formatters::LibcxxChronoMonthSummaryProvider(844 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {845 // FIXME: These are the names used in the C++20 ostream operator. Since LLVM846 // uses C++17 it's not possible to use the ostream operator directly.847 static const std::array<std::string_view, 12> months = {848 "January", "February", "March", "April", "May", "June",849 "July", "August", "September", "October", "November", "December"};850 851 ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__m_");852 if (!ptr_sp)853 return false;854 855 const unsigned month = ptr_sp->GetValueAsUnsigned(0);856 if (month >= 1 && month <= 12)857 stream << "month=" << months[month - 1];858 else859 stream.Printf("month=%u", month);860 861 return true;862}863 864bool lldb_private::formatters::LibcxxChronoWeekdaySummaryProvider(865 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {866 // FIXME: These are the names used in the C++20 ostream operator. Since LLVM867 // uses C++17 it's not possible to use the ostream operator directly.868 static const std::array<std::string_view, 7> weekdays = {869 "Sunday", "Monday", "Tuesday", "Wednesday",870 "Thursday", "Friday", "Saturday"};871 872 ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__wd_");873 if (!ptr_sp)874 return false;875 876 const unsigned weekday = ptr_sp->GetValueAsUnsigned(0);877 if (weekday < 7)878 stream << "weekday=" << weekdays[weekday];879 else880 stream.Printf("weekday=%u", weekday);881 882 return true;883}884 885bool lldb_private::formatters::LibcxxChronoYearMonthDaySummaryProvider(886 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {887 ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__y_");888 if (!ptr_sp)889 return false;890 ptr_sp = ptr_sp->GetChildMemberWithName("__y_");891 if (!ptr_sp)892 return false;893 int year = ptr_sp->GetValueAsSigned(0);894 895 ptr_sp = valobj.GetChildMemberWithName("__m_");896 if (!ptr_sp)897 return false;898 ptr_sp = ptr_sp->GetChildMemberWithName("__m_");899 if (!ptr_sp)900 return false;901 const unsigned month = ptr_sp->GetValueAsUnsigned(0);902 903 ptr_sp = valobj.GetChildMemberWithName("__d_");904 if (!ptr_sp)905 return false;906 ptr_sp = ptr_sp->GetChildMemberWithName("__d_");907 if (!ptr_sp)908 return false;909 const unsigned day = ptr_sp->GetValueAsUnsigned(0);910 911 stream << "date=";912 if (year < 0) {913 stream << '-';914 year = -year;915 }916 stream.Printf("%04d-%02u-%02u", year, month, day);917 918 return true;919}920