Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
39644 views
//===-- LibCxx.cpp --------------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "LibCxx.h"910#include "lldb/Core/Debugger.h"11#include "lldb/Core/FormatEntity.h"12#include "lldb/Core/ValueObject.h"13#include "lldb/Core/ValueObjectConstResult.h"14#include "lldb/DataFormatters/FormattersHelpers.h"15#include "lldb/DataFormatters/StringPrinter.h"16#include "lldb/DataFormatters/TypeSummary.h"17#include "lldb/DataFormatters/VectorIterator.h"18#include "lldb/Target/SectionLoadList.h"19#include "lldb/Target/Target.h"20#include "lldb/Utility/ConstString.h"21#include "lldb/Utility/DataBufferHeap.h"22#include "lldb/Utility/Endian.h"23#include "lldb/Utility/Status.h"24#include "lldb/Utility/Stream.h"2526#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"27#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"28#include "lldb/lldb-enumerations.h"29#include <optional>30#include <tuple>3132using namespace lldb;33using namespace lldb_private;34using namespace lldb_private::formatters;3536lldb::ValueObjectSP lldb_private::formatters::GetChildMemberWithName(37ValueObject &obj, llvm::ArrayRef<ConstString> alternative_names) {38for (ConstString name : alternative_names) {39lldb::ValueObjectSP child_sp = obj.GetChildMemberWithName(name);4041if (child_sp)42return child_sp;43}44return {};45}4647lldb::ValueObjectSP48lldb_private::formatters::GetFirstValueOfLibCXXCompressedPair(49ValueObject &pair) {50ValueObjectSP value;51ValueObjectSP first_child = pair.GetChildAtIndex(0);52if (first_child)53value = first_child->GetChildMemberWithName("__value_");54if (!value) {55// pre-r300140 member name56value = pair.GetChildMemberWithName("__first_");57}58return value;59}6061lldb::ValueObjectSP62lldb_private::formatters::GetSecondValueOfLibCXXCompressedPair(63ValueObject &pair) {64ValueObjectSP value;65if (pair.GetNumChildrenIgnoringErrors() > 1) {66ValueObjectSP second_child = pair.GetChildAtIndex(1);67if (second_child) {68value = second_child->GetChildMemberWithName("__value_");69}70}71if (!value) {72// pre-r300140 member name73value = pair.GetChildMemberWithName("__second_");74}75return value;76}7778bool lldb_private::formatters::LibcxxFunctionSummaryProvider(79ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {8081ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());8283if (!valobj_sp)84return false;8586ExecutionContext exe_ctx(valobj_sp->GetExecutionContextRef());87Process *process = exe_ctx.GetProcessPtr();8889if (process == nullptr)90return false;9192CPPLanguageRuntime *cpp_runtime = CPPLanguageRuntime::Get(*process);9394if (!cpp_runtime)95return false;9697CPPLanguageRuntime::LibCppStdFunctionCallableInfo callable_info =98cpp_runtime->FindLibCppStdFunctionCallableInfo(valobj_sp);99100switch (callable_info.callable_case) {101case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Invalid:102stream.Printf(" __f_ = %" PRIu64, callable_info.member_f_pointer_value);103return false;104break;105case CPPLanguageRuntime::LibCppStdFunctionCallableCase::Lambda:106stream.Printf(107" Lambda in File %s at Line %u",108callable_info.callable_line_entry.GetFile().GetFilename().GetCString(),109callable_info.callable_line_entry.line);110break;111case CPPLanguageRuntime::LibCppStdFunctionCallableCase::CallableObject:112stream.Printf(113" Function in File %s at Line %u",114callable_info.callable_line_entry.GetFile().GetFilename().GetCString(),115callable_info.callable_line_entry.line);116break;117case CPPLanguageRuntime::LibCppStdFunctionCallableCase::FreeOrMemberFunction:118stream.Printf(" Function = %s ",119callable_info.callable_symbol.GetName().GetCString());120break;121}122123return true;124}125126bool lldb_private::formatters::LibcxxSmartPointerSummaryProvider(127ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {128ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());129if (!valobj_sp)130return false;131ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));132ValueObjectSP count_sp(133valobj_sp->GetChildAtNamePath({"__cntrl_", "__shared_owners_"}));134ValueObjectSP weakcount_sp(135valobj_sp->GetChildAtNamePath({"__cntrl_", "__shared_weak_owners_"}));136137if (!ptr_sp)138return false;139140if (ptr_sp->GetValueAsUnsigned(0) == 0) {141stream.Printf("nullptr");142return true;143} else {144bool print_pointee = false;145Status error;146ValueObjectSP pointee_sp = ptr_sp->Dereference(error);147if (pointee_sp && error.Success()) {148if (pointee_sp->DumpPrintableRepresentation(149stream, ValueObject::eValueObjectRepresentationStyleSummary,150lldb::eFormatInvalid,151ValueObject::PrintableRepresentationSpecialCases::eDisable,152false))153print_pointee = true;154}155if (!print_pointee)156stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));157}158159if (count_sp)160stream.Printf(" strong=%" PRIu64, 1 + count_sp->GetValueAsUnsigned(0));161162if (weakcount_sp)163stream.Printf(" weak=%" PRIu64, 1 + weakcount_sp->GetValueAsUnsigned(0));164165return true;166}167168bool lldb_private::formatters::LibcxxUniquePointerSummaryProvider(169ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {170ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());171if (!valobj_sp)172return false;173174ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));175if (!ptr_sp)176return false;177178ptr_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);179if (!ptr_sp)180return false;181182if (ptr_sp->GetValueAsUnsigned(0) == 0) {183stream.Printf("nullptr");184return true;185} else {186bool print_pointee = false;187Status error;188ValueObjectSP pointee_sp = ptr_sp->Dereference(error);189if (pointee_sp && error.Success()) {190if (pointee_sp->DumpPrintableRepresentation(191stream, ValueObject::eValueObjectRepresentationStyleSummary,192lldb::eFormatInvalid,193ValueObject::PrintableRepresentationSpecialCases::eDisable,194false))195print_pointee = true;196}197if (!print_pointee)198stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));199}200201return true;202}203204/*205(lldb) fr var ibeg --raw --ptr-depth 1 -T206(std::__1::__wrap_iter<int *>) ibeg = {207(std::__1::__wrap_iter<int *>::iterator_type) __i = 0x00000001001037a0 {208(int) *__i = 1209}210}211*/212213SyntheticChildrenFrontEnd *214lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator(215CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {216return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(217valobj_sp, {ConstString("__i_"), ConstString("__i")})218: nullptr);219}220221lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::222LibcxxSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)223: SyntheticChildrenFrontEnd(*valobj_sp), m_cntrl(nullptr) {224if (valobj_sp)225Update();226}227228llvm::Expected<uint32_t> lldb_private::formatters::229LibcxxSharedPtrSyntheticFrontEnd::CalculateNumChildren() {230return (m_cntrl ? 1 : 0);231}232233lldb::ValueObjectSP234lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::GetChildAtIndex(235uint32_t idx) {236if (!m_cntrl)237return lldb::ValueObjectSP();238239ValueObjectSP valobj_sp = m_backend.GetSP();240if (!valobj_sp)241return lldb::ValueObjectSP();242243if (idx == 0)244return valobj_sp->GetChildMemberWithName("__ptr_");245246if (idx == 1) {247if (auto ptr_sp = valobj_sp->GetChildMemberWithName("__ptr_")) {248Status status;249auto value_type_sp =250valobj_sp->GetCompilerType()251.GetTypeTemplateArgument(0).GetPointerType();252ValueObjectSP cast_ptr_sp = ptr_sp->Cast(value_type_sp);253ValueObjectSP value_sp = cast_ptr_sp->Dereference(status);254if (status.Success()) {255return value_sp;256}257}258}259260return lldb::ValueObjectSP();261}262263lldb::ChildCacheState264lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::Update() {265m_cntrl = nullptr;266267ValueObjectSP valobj_sp = m_backend.GetSP();268if (!valobj_sp)269return lldb::ChildCacheState::eRefetch;270271TargetSP target_sp(valobj_sp->GetTargetSP());272if (!target_sp)273return lldb::ChildCacheState::eRefetch;274275lldb::ValueObjectSP cntrl_sp(valobj_sp->GetChildMemberWithName("__cntrl_"));276277m_cntrl = cntrl_sp.get(); // need to store the raw pointer to avoid a circular278// dependency279return lldb::ChildCacheState::eRefetch;280}281282bool lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::283MightHaveChildren() {284return true;285}286287size_t lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::288GetIndexOfChildWithName(ConstString name) {289if (name == "__ptr_")290return 0;291if (name == "$$dereference$$")292return 1;293return UINT32_MAX;294}295296lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEnd::297~LibcxxSharedPtrSyntheticFrontEnd() = default;298299SyntheticChildrenFrontEnd *300lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator(301CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {302return (valobj_sp ? new LibcxxSharedPtrSyntheticFrontEnd(valobj_sp)303: nullptr);304}305306lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::307LibcxxUniquePtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)308: SyntheticChildrenFrontEnd(*valobj_sp) {309if (valobj_sp)310Update();311}312313lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::314~LibcxxUniquePtrSyntheticFrontEnd() = default;315316SyntheticChildrenFrontEnd *317lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEndCreator(318CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {319return (valobj_sp ? new LibcxxUniquePtrSyntheticFrontEnd(valobj_sp)320: nullptr);321}322323llvm::Expected<uint32_t> lldb_private::formatters::324LibcxxUniquePtrSyntheticFrontEnd::CalculateNumChildren() {325if (m_value_ptr_sp)326return m_deleter_sp ? 2 : 1;327return 0;328}329330lldb::ValueObjectSP331lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::GetChildAtIndex(332uint32_t idx) {333if (!m_value_ptr_sp)334return lldb::ValueObjectSP();335336if (idx == 0)337return m_value_ptr_sp;338339if (idx == 1)340return m_deleter_sp;341342if (idx == 2) {343Status status;344auto value_sp = m_value_ptr_sp->Dereference(status);345if (status.Success()) {346return value_sp;347}348}349350return lldb::ValueObjectSP();351}352353lldb::ChildCacheState354lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::Update() {355ValueObjectSP valobj_sp = m_backend.GetSP();356if (!valobj_sp)357return lldb::ChildCacheState::eRefetch;358359ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName("__ptr_"));360if (!ptr_sp)361return lldb::ChildCacheState::eRefetch;362363// Retrieve the actual pointer and the deleter, and clone them to give them364// user-friendly names.365ValueObjectSP value_pointer_sp = GetFirstValueOfLibCXXCompressedPair(*ptr_sp);366if (value_pointer_sp)367m_value_ptr_sp = value_pointer_sp->Clone(ConstString("pointer"));368369ValueObjectSP deleter_sp = GetSecondValueOfLibCXXCompressedPair(*ptr_sp);370if (deleter_sp)371m_deleter_sp = deleter_sp->Clone(ConstString("deleter"));372373return lldb::ChildCacheState::eRefetch;374}375376bool lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::377MightHaveChildren() {378return true;379}380381size_t lldb_private::formatters::LibcxxUniquePtrSyntheticFrontEnd::382GetIndexOfChildWithName(ConstString name) {383if (name == "pointer")384return 0;385if (name == "deleter")386return 1;387if (name == "$$dereference$$")388return 2;389return UINT32_MAX;390}391392bool lldb_private::formatters::LibcxxContainerSummaryProvider(393ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {394if (valobj.IsPointerType()) {395uint64_t value = valobj.GetValueAsUnsigned(0);396if (!value)397return false;398stream.Printf("0x%016" PRIx64 " ", value);399}400return FormatEntity::FormatStringRef("size=${svar%#}", stream, nullptr,401nullptr, nullptr, &valobj, false, false);402}403404/// The field layout in a libc++ string (cap, side, data or data, size, cap).405namespace {406enum class StringLayout { CSD, DSC };407}408409/// Determine the size in bytes of \p valobj (a libc++ std::string object) and410/// extract its data payload. Return the size + payload pair.411// TODO: Support big-endian architectures.412static std::optional<std::pair<uint64_t, ValueObjectSP>>413ExtractLibcxxStringInfo(ValueObject &valobj) {414ValueObjectSP valobj_r_sp = valobj.GetChildMemberWithName("__r_");415if (!valobj_r_sp || !valobj_r_sp->GetError().Success())416return {};417418// __r_ is a compressed_pair of the actual data and the allocator. The data we419// want is in the first base class.420ValueObjectSP valobj_r_base_sp = valobj_r_sp->GetChildAtIndex(0);421if (!valobj_r_base_sp)422return {};423424ValueObjectSP valobj_rep_sp =425valobj_r_base_sp->GetChildMemberWithName("__value_");426if (!valobj_rep_sp)427return {};428429ValueObjectSP l = valobj_rep_sp->GetChildMemberWithName("__l");430if (!l)431return {};432433StringLayout layout = l->GetIndexOfChildWithName("__data_") == 0434? StringLayout::DSC435: StringLayout::CSD;436437bool short_mode = false; // this means the string is in short-mode and the438// data is stored inline439bool using_bitmasks = true; // Whether the class uses bitmasks for the mode440// flag (pre-D123580).441uint64_t size;442uint64_t size_mode_value = 0;443444ValueObjectSP short_sp = valobj_rep_sp->GetChildMemberWithName("__s");445if (!short_sp)446return {};447448ValueObjectSP is_long = short_sp->GetChildMemberWithName("__is_long_");449ValueObjectSP size_sp = short_sp->GetChildMemberWithName("__size_");450if (!size_sp)451return {};452453if (is_long) {454using_bitmasks = false;455short_mode = !is_long->GetValueAsUnsigned(/*fail_value=*/0);456size = size_sp->GetValueAsUnsigned(/*fail_value=*/0);457} else {458// The string mode is encoded in the size field.459size_mode_value = size_sp->GetValueAsUnsigned(0);460uint8_t mode_mask = layout == StringLayout::DSC ? 0x80 : 1;461short_mode = (size_mode_value & mode_mask) == 0;462}463464if (short_mode) {465ValueObjectSP location_sp = short_sp->GetChildMemberWithName("__data_");466if (using_bitmasks)467size = (layout == StringLayout::DSC) ? size_mode_value468: ((size_mode_value >> 1) % 256);469470if (!location_sp)471return {};472473// When the small-string optimization takes place, the data must fit in the474// inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's475// likely that the string isn't initialized and we're reading garbage.476ExecutionContext exe_ctx(location_sp->GetExecutionContextRef());477const std::optional<uint64_t> max_bytes =478location_sp->GetCompilerType().GetByteSize(479exe_ctx.GetBestExecutionContextScope());480if (!max_bytes || size > *max_bytes)481return {};482483return std::make_pair(size, location_sp);484}485486// we can use the layout_decider object as the data pointer487ValueObjectSP location_sp = l->GetChildMemberWithName("__data_");488ValueObjectSP size_vo = l->GetChildMemberWithName("__size_");489ValueObjectSP capacity_vo = l->GetChildMemberWithName("__cap_");490if (!size_vo || !location_sp || !capacity_vo)491return {};492size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);493uint64_t capacity = capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);494if (!using_bitmasks && layout == StringLayout::CSD)495capacity *= 2;496if (size == LLDB_INVALID_OFFSET || capacity == LLDB_INVALID_OFFSET ||497capacity < size)498return {};499return std::make_pair(size, location_sp);500}501502static bool503LibcxxWStringSummaryProvider(ValueObject &valobj, Stream &stream,504const TypeSummaryOptions &summary_options,505ValueObjectSP location_sp, size_t size) {506if (size == 0) {507stream.Printf("L\"\"");508return true;509}510if (!location_sp)511return false;512513StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);514if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {515const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();516if (size > max_size) {517size = max_size;518options.SetIsTruncated(true);519}520}521522DataExtractor extractor;523const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);524if (bytes_read < size)525return false;526527// std::wstring::size() is measured in 'characters', not bytes528TypeSystemClangSP scratch_ts_sp =529ScratchTypeSystemClang::GetForTarget(*valobj.GetTargetSP());530if (!scratch_ts_sp)531return false;532533auto wchar_t_size =534scratch_ts_sp->GetBasicType(lldb::eBasicTypeWChar).GetByteSize(nullptr);535if (!wchar_t_size)536return false;537538options.SetData(std::move(extractor));539options.SetStream(&stream);540options.SetPrefixToken("L");541options.SetQuote('"');542options.SetSourceSize(size);543options.SetBinaryZeroIsTerminator(false);544545switch (*wchar_t_size) {546case 1:547return StringPrinter::ReadBufferAndDumpToStream<548lldb_private::formatters::StringPrinter::StringElementType::UTF8>(549options);550break;551552case 2:553return StringPrinter::ReadBufferAndDumpToStream<554lldb_private::formatters::StringPrinter::StringElementType::UTF16>(555options);556break;557558case 4:559return StringPrinter::ReadBufferAndDumpToStream<560lldb_private::formatters::StringPrinter::StringElementType::UTF32>(561options);562}563return false;564}565566bool lldb_private::formatters::LibcxxWStringSummaryProvider(567ValueObject &valobj, Stream &stream,568const TypeSummaryOptions &summary_options) {569auto string_info = ExtractLibcxxStringInfo(valobj);570if (!string_info)571return false;572uint64_t size;573ValueObjectSP location_sp;574std::tie(size, location_sp) = *string_info;575576return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,577location_sp, size);578}579580template <StringPrinter::StringElementType element_type>581static bool582LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream,583const TypeSummaryOptions &summary_options,584std::string prefix_token, ValueObjectSP location_sp,585uint64_t size) {586587if (size == 0) {588stream.Printf("\"\"");589return true;590}591592if (!location_sp)593return false;594595StringPrinter::ReadBufferAndDumpToStreamOptions options(valobj);596597if (summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryCapped) {598const auto max_size = valobj.GetTargetSP()->GetMaximumSizeOfStringSummary();599if (size > max_size) {600size = max_size;601options.SetIsTruncated(true);602}603}604605{606DataExtractor extractor;607const size_t bytes_read = location_sp->GetPointeeData(extractor, 0, size);608if (bytes_read < size)609return false;610611options.SetData(std::move(extractor));612}613options.SetStream(&stream);614if (prefix_token.empty())615options.SetPrefixToken(nullptr);616else617options.SetPrefixToken(prefix_token);618options.SetQuote('"');619options.SetSourceSize(size);620options.SetBinaryZeroIsTerminator(false);621return StringPrinter::ReadBufferAndDumpToStream<element_type>(options);622}623624template <StringPrinter::StringElementType element_type>625static bool626LibcxxStringSummaryProvider(ValueObject &valobj, Stream &stream,627const TypeSummaryOptions &summary_options,628std::string prefix_token) {629auto string_info = ExtractLibcxxStringInfo(valobj);630if (!string_info)631return false;632uint64_t size;633ValueObjectSP location_sp;634std::tie(size, location_sp) = *string_info;635636return LibcxxStringSummaryProvider<element_type>(637valobj, stream, summary_options, prefix_token, location_sp, size);638}639template <StringPrinter::StringElementType element_type>640static bool formatStringImpl(ValueObject &valobj, Stream &stream,641const TypeSummaryOptions &summary_options,642std::string prefix_token) {643StreamString scratch_stream;644const bool success = LibcxxStringSummaryProvider<element_type>(645valobj, scratch_stream, summary_options, prefix_token);646if (success)647stream << scratch_stream.GetData();648else649stream << "Summary Unavailable";650return true;651}652653bool lldb_private::formatters::LibcxxStringSummaryProviderASCII(654ValueObject &valobj, Stream &stream,655const TypeSummaryOptions &summary_options) {656return formatStringImpl<StringPrinter::StringElementType::ASCII>(657valobj, stream, summary_options, "");658}659660bool lldb_private::formatters::LibcxxStringSummaryProviderUTF16(661ValueObject &valobj, Stream &stream,662const TypeSummaryOptions &summary_options) {663return formatStringImpl<StringPrinter::StringElementType::UTF16>(664valobj, stream, summary_options, "u");665}666667bool lldb_private::formatters::LibcxxStringSummaryProviderUTF32(668ValueObject &valobj, Stream &stream,669const TypeSummaryOptions &summary_options) {670return formatStringImpl<StringPrinter::StringElementType::UTF32>(671valobj, stream, summary_options, "U");672}673674static std::tuple<bool, ValueObjectSP, size_t>675LibcxxExtractStringViewData(ValueObject& valobj) {676auto dataobj = GetChildMemberWithName(677valobj, {ConstString("__data_"), ConstString("__data")});678auto sizeobj = GetChildMemberWithName(679valobj, {ConstString("__size_"), ConstString("__size")});680if (!dataobj || !sizeobj)681return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});682683if (!dataobj->GetError().Success() || !sizeobj->GetError().Success())684return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});685686bool success{false};687uint64_t size = sizeobj->GetValueAsUnsigned(0, &success);688if (!success)689return std::make_tuple<bool,ValueObjectSP,size_t>(false, {}, {});690691return std::make_tuple(true,dataobj,size);692}693694template <StringPrinter::StringElementType element_type>695static bool formatStringViewImpl(ValueObject &valobj, Stream &stream,696const TypeSummaryOptions &summary_options,697std::string prefix_token) {698699bool success;700ValueObjectSP dataobj;701size_t size;702std::tie(success, dataobj, size) = LibcxxExtractStringViewData(valobj);703704if (!success) {705stream << "Summary Unavailable";706return true;707}708709return LibcxxStringSummaryProvider<element_type>(710valobj, stream, summary_options, prefix_token, dataobj, size);711}712713bool lldb_private::formatters::LibcxxStringViewSummaryProviderASCII(714ValueObject &valobj, Stream &stream,715const TypeSummaryOptions &summary_options) {716return formatStringViewImpl<StringPrinter::StringElementType::ASCII>(717valobj, stream, summary_options, "");718}719720bool lldb_private::formatters::LibcxxStringViewSummaryProviderUTF16(721ValueObject &valobj, Stream &stream,722const TypeSummaryOptions &summary_options) {723return formatStringViewImpl<StringPrinter::StringElementType::UTF16>(724valobj, stream, summary_options, "u");725}726727bool lldb_private::formatters::LibcxxStringViewSummaryProviderUTF32(728ValueObject &valobj, Stream &stream,729const TypeSummaryOptions &summary_options) {730return formatStringViewImpl<StringPrinter::StringElementType::UTF32>(731valobj, stream, summary_options, "U");732}733734bool lldb_private::formatters::LibcxxWStringViewSummaryProvider(735ValueObject &valobj, Stream &stream,736const TypeSummaryOptions &summary_options) {737738bool success;739ValueObjectSP dataobj;740size_t size;741std::tie(success, dataobj, size) = LibcxxExtractStringViewData(valobj);742743if (!success) {744stream << "Summary Unavailable";745return true;746}747748return ::LibcxxWStringSummaryProvider(valobj, stream, summary_options,749dataobj, size);750}751752static bool753LibcxxChronoTimePointSecondsSummaryProvider(ValueObject &valobj, Stream &stream,754const TypeSummaryOptions &options,755const char *fmt) {756ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__d_");757if (!ptr_sp)758return false;759ptr_sp = ptr_sp->GetChildMemberWithName("__rep_");760if (!ptr_sp)761return false;762763#ifndef _WIN32764// The date time in the chrono library is valid in the range765// [-32767-01-01T00:00:00Z, 32767-12-31T23:59:59Z]. A 64-bit time_t has a766// larger range, the function strftime is not able to format the entire range767// of time_t. The exact point has not been investigated; it's limited to768// chrono's range.769const std::time_t chrono_timestamp_min =770-1'096'193'779'200; // -32767-01-01T00:00:00Z771const std::time_t chrono_timestamp_max =772971'890'963'199; // 32767-12-31T23:59:59Z773#else774const std::time_t chrono_timestamp_min = -43'200; // 1969-12-31T12:00:00Z775const std::time_t chrono_timestamp_max =77632'536'850'399; // 3001-01-19T21:59:59777#endif778779const std::time_t seconds = ptr_sp->GetValueAsSigned(0);780if (seconds < chrono_timestamp_min || seconds > chrono_timestamp_max)781stream.Printf("timestamp=%" PRId64 " s", static_cast<int64_t>(seconds));782else {783std::array<char, 128> str;784std::size_t size =785std::strftime(str.data(), str.size(), fmt, gmtime(&seconds));786if (size == 0)787return false;788789stream.Printf("date/time=%s timestamp=%" PRId64 " s", str.data(),790static_cast<int64_t>(seconds));791}792793return true;794}795796bool lldb_private::formatters::LibcxxChronoSysSecondsSummaryProvider(797ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {798return LibcxxChronoTimePointSecondsSummaryProvider(valobj, stream, options,799"%FT%H:%M:%SZ");800}801802bool lldb_private::formatters::LibcxxChronoLocalSecondsSummaryProvider(803ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {804return LibcxxChronoTimePointSecondsSummaryProvider(valobj, stream, options,805"%FT%H:%M:%S");806}807808static bool809LibcxxChronoTimepointDaysSummaryProvider(ValueObject &valobj, Stream &stream,810const TypeSummaryOptions &options,811const char *fmt) {812ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__d_");813if (!ptr_sp)814return false;815ptr_sp = ptr_sp->GetChildMemberWithName("__rep_");816if (!ptr_sp)817return false;818819#ifndef _WIN32820// The date time in the chrono library is valid in the range821// [-32767-01-01Z, 32767-12-31Z]. A 32-bit time_t has a larger range, the822// function strftime is not able to format the entire range of time_t. The823// exact point has not been investigated; it's limited to chrono's range.824const int chrono_timestamp_min = -12'687'428; // -32767-01-01Z825const int chrono_timestamp_max = 11'248'737; // 32767-12-31Z826#else827const int chrono_timestamp_min = 0; // 1970-01-01Z828const int chrono_timestamp_max = 376'583; // 3001-01-19Z829#endif830831const int days = ptr_sp->GetValueAsSigned(0);832if (days < chrono_timestamp_min || days > chrono_timestamp_max)833stream.Printf("timestamp=%d days", days);834835else {836const std::time_t seconds = std::time_t(86400) * days;837838std::array<char, 128> str;839std::size_t size =840std::strftime(str.data(), str.size(), fmt, gmtime(&seconds));841if (size == 0)842return false;843844stream.Printf("date=%s timestamp=%d days", str.data(), days);845}846847return true;848}849850bool lldb_private::formatters::LibcxxChronoSysDaysSummaryProvider(851ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {852return LibcxxChronoTimepointDaysSummaryProvider(valobj, stream, options,853"%FZ");854}855856bool lldb_private::formatters::LibcxxChronoLocalDaysSummaryProvider(857ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {858return LibcxxChronoTimepointDaysSummaryProvider(valobj, stream, options,859"%F");860}861862bool lldb_private::formatters::LibcxxChronoMonthSummaryProvider(863ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {864// FIXME: These are the names used in the C++20 ostream operator. Since LLVM865// uses C++17 it's not possible to use the ostream operator directly.866static const std::array<std::string_view, 12> months = {867"January", "February", "March", "April", "May", "June",868"July", "August", "September", "October", "November", "December"};869870ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__m_");871if (!ptr_sp)872return false;873874const unsigned month = ptr_sp->GetValueAsUnsigned(0);875if (month >= 1 && month <= 12)876stream << "month=" << months[month - 1];877else878stream.Printf("month=%u", month);879880return true;881}882883bool lldb_private::formatters::LibcxxChronoWeekdaySummaryProvider(884ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {885// FIXME: These are the names used in the C++20 ostream operator. Since LLVM886// uses C++17 it's not possible to use the ostream operator directly.887static const std::array<std::string_view, 7> weekdays = {888"Sunday", "Monday", "Tuesday", "Wednesday",889"Thursday", "Friday", "Saturday"};890891ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__wd_");892if (!ptr_sp)893return false;894895const unsigned weekday = ptr_sp->GetValueAsUnsigned(0);896if (weekday < 7)897stream << "weekday=" << weekdays[weekday];898else899stream.Printf("weekday=%u", weekday);900901return true;902}903904bool lldb_private::formatters::LibcxxChronoYearMonthDaySummaryProvider(905ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {906ValueObjectSP ptr_sp = valobj.GetChildMemberWithName("__y_");907if (!ptr_sp)908return false;909ptr_sp = ptr_sp->GetChildMemberWithName("__y_");910if (!ptr_sp)911return false;912int year = ptr_sp->GetValueAsSigned(0);913914ptr_sp = valobj.GetChildMemberWithName("__m_");915if (!ptr_sp)916return false;917ptr_sp = ptr_sp->GetChildMemberWithName("__m_");918if (!ptr_sp)919return false;920const unsigned month = ptr_sp->GetValueAsUnsigned(0);921922ptr_sp = valobj.GetChildMemberWithName("__d_");923if (!ptr_sp)924return false;925ptr_sp = ptr_sp->GetChildMemberWithName("__d_");926if (!ptr_sp)927return false;928const unsigned day = ptr_sp->GetValueAsUnsigned(0);929930stream << "date=";931if (year < 0) {932stream << '-';933year = -year;934}935stream.Printf("%04d-%02u-%02u", year, month, day);936937return true;938}939940941