brintos

brintos / llvm-project-archived public Read only

0
0
Text · 30.3 KiB · 141c5c9 Raw
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