871 lines · cpp
1//===-- ValueObjectPrinter.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 "lldb/DataFormatters/ValueObjectPrinter.h"10 11#include "lldb/DataFormatters/DataVisualization.h"12#include "lldb/Interpreter/CommandInterpreter.h"13#include "lldb/Target/Language.h"14#include "lldb/Target/Target.h"15#include "lldb/Utility/Stream.h"16#include "lldb/ValueObject/ValueObject.h"17#include "llvm/Support/Error.h"18#include "llvm/Support/MathExtras.h"19#include <cstdint>20#include <memory>21#include <optional>22 23using namespace lldb;24using namespace lldb_private;25 26ValueObjectPrinter::ValueObjectPrinter(ValueObject &valobj, Stream *s)27 : m_orig_valobj(valobj) {28 DumpValueObjectOptions options(valobj);29 Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr);30}31 32ValueObjectPrinter::ValueObjectPrinter(ValueObject &valobj, Stream *s,33 const DumpValueObjectOptions &options)34 : m_orig_valobj(valobj) {35 Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr);36}37 38ValueObjectPrinter::ValueObjectPrinter(39 ValueObject &valobj, Stream *s, const DumpValueObjectOptions &options,40 const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth,41 InstancePointersSetSP printed_instance_pointers)42 : m_orig_valobj(valobj) {43 Init(valobj, s, options, ptr_depth, curr_depth, printed_instance_pointers);44}45 46void ValueObjectPrinter::Init(47 ValueObject &valobj, Stream *s, const DumpValueObjectOptions &options,48 const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth,49 InstancePointersSetSP printed_instance_pointers) {50 m_cached_valobj = nullptr;51 m_stream = s;52 m_options = options;53 m_ptr_depth = ptr_depth;54 m_curr_depth = curr_depth;55 assert(m_stream && "cannot print to a NULL Stream");56 m_should_print = eLazyBoolCalculate;57 m_is_nil = eLazyBoolCalculate;58 m_is_uninit = eLazyBoolCalculate;59 m_is_ptr = eLazyBoolCalculate;60 m_is_ref = eLazyBoolCalculate;61 m_is_aggregate = eLazyBoolCalculate;62 m_is_instance_ptr = eLazyBoolCalculate;63 m_summary_formatter = {nullptr, false};64 m_value.assign("");65 m_summary.assign("");66 m_error.assign("");67 m_val_summary_ok = false;68 m_printed_instance_pointers = printed_instance_pointers69 ? printed_instance_pointers70 : std::make_shared<InstancePointersSet>();71 SetupMostSpecializedValue();72}73 74static const char *maybeNewline(const std::string &s) {75 // If the string already ends with a \n don't add another one.76 if (s.empty() || s.back() != '\n')77 return "\n";78 return "";79}80 81bool ValueObjectPrinter::ShouldPrintObjectDescription() {82 return ShouldPrintValueObject() && m_options.m_use_object_desc && !IsNil() &&83 !IsUninitialized() && !m_options.m_pointer_as_array;84}85 86llvm::Error ValueObjectPrinter::PrintValueObject() {87 // If the incoming ValueObject is in an error state, the best we're going to 88 // get out of it is its type. But if we don't even have that, just print89 // the error and exit early.90 if (m_orig_valobj.GetError().Fail() &&91 !m_orig_valobj.GetCompilerType().IsValid())92 return m_orig_valobj.GetError().ToError();93 94 std::optional<std::string> object_desc;95 if (ShouldPrintObjectDescription()) {96 // The object description is invoked now, but not printed until after97 // value/summary. Calling GetObjectDescription at the outset of printing98 // allows for early discovery of errors. In the case of an error, the value99 // object is printed normally.100 llvm::Expected<std::string> object_desc_or_err =101 GetMostSpecializedValue().GetObjectDescription();102 if (!object_desc_or_err) {103 auto error_msg = toString(object_desc_or_err.takeError());104 *m_stream << "error: " << error_msg << maybeNewline(error_msg);105 106 // Print the value object directly.107 m_options.DisableObjectDescription();108 } else {109 object_desc = *object_desc_or_err;110 }111 }112 113 if (ShouldPrintValueObject()) {114 PrintLocationIfNeeded();115 m_stream->Indent();116 117 PrintDecl();118 }119 120 bool value_printed = false;121 bool summary_printed = false;122 123 m_val_summary_ok =124 PrintValueAndSummaryIfNeeded(value_printed, summary_printed);125 126 if (m_val_summary_ok) {127 PrintObjectDescriptionIfNeeded(object_desc);128 return PrintChildrenIfNeeded(value_printed, summary_printed);129 }130 m_stream->EOL();131 132 return llvm::Error::success();133}134 135ValueObject &ValueObjectPrinter::GetMostSpecializedValue() {136 assert(m_cached_valobj && "ValueObjectPrinter must have a valid ValueObject");137 return *m_cached_valobj;138}139 140void ValueObjectPrinter::SetupMostSpecializedValue() {141 bool update_success = m_orig_valobj.UpdateValueIfNeeded(true);142 // If we can't find anything better, we'll fall back on the original143 // ValueObject.144 m_cached_valobj = &m_orig_valobj;145 if (update_success) {146 if (m_orig_valobj.IsDynamic()) {147 if (m_options.m_use_dynamic == eNoDynamicValues) {148 ValueObject *static_value = m_orig_valobj.GetStaticValue().get();149 if (static_value)150 m_cached_valobj = static_value;151 }152 } else {153 if (m_options.m_use_dynamic != eNoDynamicValues) {154 ValueObject *dynamic_value =155 m_orig_valobj.GetDynamicValue(m_options.m_use_dynamic).get();156 if (dynamic_value)157 m_cached_valobj = dynamic_value;158 }159 }160 161 if (m_cached_valobj->IsSynthetic()) {162 if (!m_options.m_use_synthetic) {163 ValueObject *non_synthetic =164 m_cached_valobj->GetNonSyntheticValue().get();165 if (non_synthetic)166 m_cached_valobj = non_synthetic;167 }168 } else {169 if (m_options.m_use_synthetic) {170 ValueObject *synthetic = m_cached_valobj->GetSyntheticValue().get();171 if (synthetic)172 m_cached_valobj = synthetic;173 }174 }175 }176 m_compiler_type = m_cached_valobj->GetCompilerType();177 m_type_flags = m_compiler_type.GetTypeInfo();178 assert(m_cached_valobj &&179 "SetupMostSpecialized value must compute a valid ValueObject");180}181 182const char *ValueObjectPrinter::GetRootNameForDisplay() {183 const char *root_valobj_name =184 m_options.m_root_valobj_name.empty()185 ? GetMostSpecializedValue().GetName().AsCString()186 : m_options.m_root_valobj_name.c_str();187 return root_valobj_name ? root_valobj_name : "";188}189 190bool ValueObjectPrinter::ShouldPrintValueObject() {191 if (m_should_print == eLazyBoolCalculate)192 m_should_print =193 (!m_options.m_flat_output || m_type_flags.Test(eTypeHasValue))194 ? eLazyBoolYes195 : eLazyBoolNo;196 return m_should_print == eLazyBoolYes;197}198 199bool ValueObjectPrinter::IsNil() {200 if (m_is_nil == eLazyBoolCalculate)201 m_is_nil =202 GetMostSpecializedValue().IsNilReference() ? eLazyBoolYes : eLazyBoolNo;203 return m_is_nil == eLazyBoolYes;204}205 206bool ValueObjectPrinter::IsUninitialized() {207 if (m_is_uninit == eLazyBoolCalculate)208 m_is_uninit = GetMostSpecializedValue().IsUninitializedReference()209 ? eLazyBoolYes210 : eLazyBoolNo;211 return m_is_uninit == eLazyBoolYes;212}213 214bool ValueObjectPrinter::IsPtr() {215 if (m_is_ptr == eLazyBoolCalculate)216 m_is_ptr = m_type_flags.Test(eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo;217 return m_is_ptr == eLazyBoolYes;218}219 220bool ValueObjectPrinter::IsRef() {221 if (m_is_ref == eLazyBoolCalculate)222 m_is_ref = m_type_flags.Test(eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo;223 return m_is_ref == eLazyBoolYes;224}225 226bool ValueObjectPrinter::IsAggregate() {227 if (m_is_aggregate == eLazyBoolCalculate)228 m_is_aggregate =229 m_type_flags.Test(eTypeHasChildren) ? eLazyBoolYes : eLazyBoolNo;230 return m_is_aggregate == eLazyBoolYes;231}232 233bool ValueObjectPrinter::IsInstancePointer() {234 // you need to do this check on the value's clang type235 ValueObject &valobj = GetMostSpecializedValue();236 if (m_is_instance_ptr == eLazyBoolCalculate)237 m_is_instance_ptr = (valobj.GetValue().GetCompilerType().GetTypeInfo() &238 eTypeInstanceIsPointer) != 0239 ? eLazyBoolYes240 : eLazyBoolNo;241 if ((eLazyBoolYes == m_is_instance_ptr) && valobj.IsBaseClass())242 m_is_instance_ptr = eLazyBoolNo;243 return m_is_instance_ptr == eLazyBoolYes;244}245 246bool ValueObjectPrinter::PrintLocationIfNeeded() {247 if (m_options.m_show_location) {248 m_stream->Printf("%s: ", GetMostSpecializedValue().GetLocationAsCString());249 return true;250 }251 return false;252}253 254void ValueObjectPrinter::PrintDecl() {255 bool show_type = true;256 // if we are at the root-level and been asked to hide the root's type, then257 // hide it258 if (m_curr_depth == 0 && m_options.m_hide_root_type)259 show_type = false;260 else261 // otherwise decide according to the usual rules (asked to show types -262 // always at the root level)263 show_type = m_options.m_show_types ||264 (m_curr_depth == 0 && !m_options.m_flat_output);265 266 StreamString typeName;267 // Figure out which ValueObject we're acting on268 ValueObject &valobj = GetMostSpecializedValue();269 270 // always show the type at the root level if it is invalid271 if (show_type) {272 // Some ValueObjects don't have types (like registers sets). Only print the273 // type if there is one to print274 ConstString type_name;275 if (m_compiler_type.IsValid()) {276 type_name = m_options.m_use_type_display_name277 ? valobj.GetDisplayTypeName()278 : valobj.GetQualifiedTypeName();279 } else {280 // only show an invalid type name if the user explicitly triggered281 // show_type282 if (m_options.m_show_types)283 type_name = ConstString("<invalid type>");284 }285 286 if (type_name) {287 std::string type_name_str(type_name.GetCString());288 if (m_options.m_hide_pointer_value) {289 for (auto iter = type_name_str.find(" *"); iter != std::string::npos;290 iter = type_name_str.find(" *")) {291 type_name_str.erase(iter, 2);292 }293 }294 typeName << type_name_str.c_str();295 }296 }297 298 StreamString varName;299 300 if (ShouldShowName()) {301 if (m_options.m_flat_output)302 valobj.GetExpressionPath(varName);303 else304 varName << GetRootNameForDisplay();305 }306 307 bool decl_printed = false;308 if (!m_options.m_decl_printing_helper) {309 // if the user didn't give us a custom helper, pick one based upon the310 // language, either the one that this printer is bound to, or the preferred311 // one for the ValueObject312 lldb::LanguageType lang_type =313 (m_options.m_varformat_language == lldb::eLanguageTypeUnknown)314 ? valobj.GetPreferredDisplayLanguage()315 : m_options.m_varformat_language;316 if (Language *lang_plugin = Language::FindPlugin(lang_type)) {317 m_options.m_decl_printing_helper = lang_plugin->GetDeclPrintingHelper();318 }319 }320 321 if (m_options.m_decl_printing_helper) {322 ConstString type_name_cstr(typeName.GetString());323 ConstString var_name_cstr(varName.GetString());324 325 DumpValueObjectOptions decl_print_options = m_options;326 // Pass printing helpers an option object that indicates whether the name327 // should be shown or hidden.328 decl_print_options.SetHideName(!ShouldShowName());329 330 StreamString dest_stream;331 if (m_options.m_decl_printing_helper(type_name_cstr, var_name_cstr,332 decl_print_options, dest_stream)) {333 decl_printed = true;334 m_stream->PutCString(dest_stream.GetString());335 }336 }337 338 // if the helper failed, or there is none, do a default thing339 if (!decl_printed) {340 if (!typeName.Empty())341 m_stream->Printf("(%s) ", typeName.GetData());342 if (!varName.Empty())343 m_stream->Printf("%s =", varName.GetData());344 else if (ShouldShowName())345 m_stream->Printf(" =");346 }347}348 349bool ValueObjectPrinter::CheckScopeIfNeeded() {350 if (m_options.m_scope_already_checked)351 return true;352 return GetMostSpecializedValue().IsInScope();353}354 355TypeSummaryImpl *ValueObjectPrinter::GetSummaryFormatter(bool null_if_omitted) {356 if (!m_summary_formatter.second) {357 TypeSummaryImpl *entry =358 m_options.m_summary_sp359 ? m_options.m_summary_sp.get()360 : GetMostSpecializedValue().GetSummaryFormat().get();361 362 if (m_options.m_omit_summary_depth > 0)363 entry = nullptr;364 m_summary_formatter.first = entry;365 m_summary_formatter.second = true;366 }367 if (m_options.m_omit_summary_depth > 0 && null_if_omitted)368 return nullptr;369 return m_summary_formatter.first;370}371 372static bool IsPointerValue(const CompilerType &type) {373 Flags type_flags(type.GetTypeInfo());374 if (type_flags.AnySet(eTypeInstanceIsPointer | eTypeIsPointer))375 return type_flags.AllClear(eTypeIsBuiltIn);376 return false;377}378 379void ValueObjectPrinter::GetValueSummaryError(std::string &value,380 std::string &summary,381 std::string &error) {382 lldb::Format format = m_options.m_format;383 ValueObject &valobj = GetMostSpecializedValue();384 // if I am printing synthetized elements, apply the format to those elements385 // only386 if (m_options.m_pointer_as_array)387 valobj.GetValueAsCString(lldb::eFormatDefault, value);388 else if (format != eFormatDefault && format != valobj.GetFormat())389 valobj.GetValueAsCString(format, value);390 else {391 const char *val_cstr = valobj.GetValueAsCString();392 if (val_cstr)393 value.assign(val_cstr);394 }395 const char *err_cstr = valobj.GetError().AsCString();396 if (err_cstr)397 error.assign(err_cstr);398 399 if (!ShouldPrintValueObject())400 return;401 402 if (IsNil()) {403 lldb::LanguageType lang_type =404 (m_options.m_varformat_language == lldb::eLanguageTypeUnknown)405 ? valobj.GetPreferredDisplayLanguage()406 : m_options.m_varformat_language;407 if (Language *lang_plugin = Language::FindPlugin(lang_type)) {408 summary.assign(lang_plugin->GetNilReferenceSummaryString().str());409 } else {410 // We treat C as the fallback language rather than as a separate Language411 // plugin.412 summary.assign("NULL");413 }414 } else if (IsUninitialized()) {415 summary.assign("<uninitialized>");416 } else if (m_options.m_omit_summary_depth == 0) {417 TypeSummaryImpl *entry = GetSummaryFormatter();418 if (entry) {419 valobj.GetSummaryAsCString(entry, summary,420 m_options.m_varformat_language);421 } else {422 const char *sum_cstr =423 valobj.GetSummaryAsCString(m_options.m_varformat_language);424 if (sum_cstr)425 summary.assign(sum_cstr);426 }427 }428}429 430bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed,431 bool &summary_printed) {432 bool error_printed = false;433 if (ShouldPrintValueObject()) {434 if (!CheckScopeIfNeeded())435 m_error.assign("out of scope");436 if (m_error.empty()) {437 GetValueSummaryError(m_value, m_summary, m_error);438 }439 if (m_error.size()) {440 // we need to support scenarios in which it is actually fine for a value441 // to have no type but - on the other hand - if we get an error *AND*442 // have no type, we try to get out gracefully, since most often that443 // combination means "could not resolve a type" and the default failure444 // mode is quite ugly445 if (!m_compiler_type.IsValid()) {446 m_stream->Printf(" <could not resolve type>");447 return false;448 }449 450 error_printed = true;451 m_stream->Printf(" <%s>\n", m_error.c_str());452 } else {453 // Make sure we have a value and make sure the summary didn't specify454 // that the value should not be printed - and do not print the value if455 // this thing is nil (but show the value if the user passes a format456 // explicitly)457 TypeSummaryImpl *entry = GetSummaryFormatter();458 ValueObject &valobj = GetMostSpecializedValue();459 const bool has_nil_or_uninitialized_summary =460 (IsNil() || IsUninitialized()) && !m_summary.empty();461 if (!has_nil_or_uninitialized_summary && !m_value.empty() &&462 (entry == nullptr ||463 (entry->DoesPrintValue(&valobj) ||464 m_options.m_format != eFormatDefault) ||465 m_summary.empty()) &&466 !m_options.m_hide_value) {467 if (m_options.m_hide_pointer_value &&468 IsPointerValue(valobj.GetCompilerType())) {469 } else {470 if (ShouldShowName())471 m_stream->PutChar(' ');472 m_stream->PutCString(m_value);473 value_printed = true;474 }475 }476 477 if (m_summary.size()) {478 if (ShouldShowName() || value_printed)479 m_stream->PutChar(' ');480 m_stream->PutCString(m_summary);481 summary_printed = true;482 }483 }484 }485 return !error_printed;486}487 488void ValueObjectPrinter::PrintObjectDescriptionIfNeeded(489 std::optional<std::string> object_desc) {490 if (!object_desc)491 return;492 493 if (!m_options.m_hide_value || ShouldShowName())494 *m_stream << ' ';495 *m_stream << *object_desc << maybeNewline(*object_desc);496}497 498bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion() const {499 return m_count > 0;500}501 502bool ValueObjectPrinter::ShouldPrintChildren(503 DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {504 const bool is_ref = IsRef();505 const bool is_ptr = IsPtr();506 const bool is_uninit = IsUninitialized();507 508 if (is_uninit)509 return false;510 511 // If we have reached the maximum depth we shouldn't print any more children.512 if (HasReachedMaximumDepth())513 return false;514 515 // if the user has specified an element count, always print children as it is516 // explicit user demand being honored517 if (m_options.m_pointer_as_array)518 return true;519 520 if (m_options.m_use_object_desc)521 return false;522 523 bool print_children = true;524 ValueObject &valobj = GetMostSpecializedValue();525 if (TypeSummaryImpl *type_summary = GetSummaryFormatter())526 print_children = type_summary->DoesPrintChildren(&valobj);527 528 // We will show children for all concrete types. We won't show pointer529 // contents unless a pointer depth has been specified. We won't reference530 // contents unless the reference is the root object (depth of zero).531 532 // Use a new temporary pointer depth in case we override the current533 // pointer depth below...534 535 if (is_ptr || is_ref) {536 // We have a pointer or reference whose value is an address. Make sure537 // that address is not NULL538 if (valobj.GetPointerValue().address == 0)539 return false;540 541 const bool is_root_level = m_curr_depth == 0;542 const bool is_expanded_ptr =543 is_ptr && m_type_flags.Test(m_options.m_expand_ptr_type_flags);544 545 if ((is_ref || is_expanded_ptr) && is_root_level && print_children) {546 // If this is the root object (depth is zero) that we are showing and it547 // is either a reference or a preferred type of pointer, then print it.548 // Don't do this at deeper depths otherwise we can end up with infinite549 // recursion...550 return true;551 }552 553 return curr_ptr_depth.CanAllowExpansion();554 }555 556 return print_children || m_summary.empty();557}558 559bool ValueObjectPrinter::ShouldExpandEmptyAggregates() {560 TypeSummaryImpl *entry = GetSummaryFormatter();561 562 if (!entry)563 return true;564 565 return entry->DoesPrintEmptyAggregates();566}567 568ValueObject &ValueObjectPrinter::GetValueObjectForChildrenGeneration() {569 return GetMostSpecializedValue();570}571 572void ValueObjectPrinter::PrintChildrenPreamble(bool value_printed,573 bool summary_printed) {574 if (m_options.m_flat_output) {575 if (ShouldPrintValueObject())576 m_stream->EOL();577 } else {578 if (ShouldPrintValueObject()) {579 if (IsRef()) {580 m_stream->PutCString(": ");581 } else if (value_printed || summary_printed || ShouldShowName()) {582 m_stream->PutChar(' ');583 }584 m_stream->PutCString("{\n");585 }586 m_stream->IndentMore();587 }588}589 590void ValueObjectPrinter::PrintChild(591 ValueObjectSP child_sp,592 const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {593 const uint32_t consumed_summary_depth = m_options.m_pointer_as_array ? 0 : 1;594 const bool does_consume_ptr_depth =595 ((IsPtr() && !m_options.m_pointer_as_array) || IsRef());596 597 DumpValueObjectOptions child_options(m_options);598 child_options.SetFormat(m_options.m_format)599 .SetSummary()600 .SetRootValueObjectName();601 child_options.SetScopeChecked(true)602 .SetHideName(m_options.m_hide_name)603 .SetHideValue(m_options.m_hide_value)604 .SetOmitSummaryDepth(child_options.m_omit_summary_depth > 1605 ? child_options.m_omit_summary_depth -606 consumed_summary_depth607 : 0)608 .SetElementCount(0);609 610 if (child_sp.get()) {611 auto ptr_depth = curr_ptr_depth;612 if (does_consume_ptr_depth)613 ptr_depth = curr_ptr_depth.Decremented();614 615 ValueObjectPrinter child_printer(*(child_sp.get()), m_stream, child_options,616 ptr_depth, m_curr_depth + 1,617 m_printed_instance_pointers);618 llvm::Error error = child_printer.PrintValueObject();619 if (error) {620 if (m_stream)621 *m_stream << "error: " << toString(std::move(error));622 else623 llvm::consumeError(std::move(error));624 }625 }626}627 628llvm::Expected<uint32_t>629ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot) {630 ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();631 632 if (m_options.m_pointer_as_array)633 return m_options.m_pointer_as_array.m_element_count;634 635 const uint32_t max_num_children =636 m_options.m_ignore_cap ? UINT32_MAX637 : GetMostSpecializedValue()638 .GetTargetSP()639 ->GetMaximumNumberOfChildrenToDisplay();640 // Ask for one more child than the maximum to see if we should print "...".641 auto num_children_or_err = synth_valobj.GetNumChildren(642 llvm::SaturatingAdd(max_num_children, uint32_t(1)));643 if (!num_children_or_err)644 return num_children_or_err;645 if (*num_children_or_err > max_num_children) {646 print_dotdotdot = true;647 return max_num_children;648 }649 return num_children_or_err;650}651 652void ValueObjectPrinter::PrintChildrenPostamble(bool print_dotdotdot) {653 if (!m_options.m_flat_output) {654 if (print_dotdotdot) {655 GetMostSpecializedValue()656 .GetTargetSP()657 ->GetDebugger()658 .GetCommandInterpreter()659 .ChildrenTruncated();660 m_stream->Indent("...\n");661 }662 m_stream->IndentLess();663 m_stream->Indent("}\n");664 }665}666 667bool ValueObjectPrinter::ShouldPrintEmptyBrackets(bool value_printed,668 bool summary_printed) {669 ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();670 671 if (!IsAggregate())672 return false;673 674 if (!m_options.m_reveal_empty_aggregates) {675 if (value_printed || summary_printed)676 return false;677 }678 679 if (synth_valobj.MightHaveChildren())680 return true;681 682 if (m_val_summary_ok)683 return false;684 685 return true;686}687 688static constexpr size_t PhysicalIndexForLogicalIndex(size_t base, size_t stride,689 size_t logical) {690 return base + logical * stride;691}692 693ValueObjectSP ValueObjectPrinter::GenerateChild(ValueObject &synth_valobj,694 size_t idx) {695 if (m_options.m_pointer_as_array) {696 // if generating pointer-as-array children, use GetSyntheticArrayMember697 return synth_valobj.GetSyntheticArrayMember(698 PhysicalIndexForLogicalIndex(699 m_options.m_pointer_as_array.m_base_element,700 m_options.m_pointer_as_array.m_stride, idx),701 true);702 } else {703 // otherwise, do the usual thing704 return synth_valobj.GetChildAtIndex(idx);705 }706}707 708void ValueObjectPrinter::PrintChildren(709 bool value_printed, bool summary_printed,710 const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) {711 ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();712 713 bool print_dotdotdot = false;714 auto num_children_or_err = GetMaxNumChildrenToPrint(print_dotdotdot);715 if (!num_children_or_err) {716 *m_stream << " <" << llvm::toString(num_children_or_err.takeError()) << '>';717 return;718 }719 uint32_t num_children = *num_children_or_err;720 if (num_children) {721 bool any_children_printed = false;722 723 for (size_t idx = 0; idx < num_children; ++idx) {724 if (ValueObjectSP child_sp = GenerateChild(synth_valobj, idx)) {725 if (m_options.m_child_printing_decider &&726 !m_options.m_child_printing_decider(child_sp->GetName()))727 continue;728 if (!any_children_printed) {729 PrintChildrenPreamble(value_printed, summary_printed);730 any_children_printed = true;731 }732 PrintChild(child_sp, curr_ptr_depth);733 }734 }735 736 if (any_children_printed)737 PrintChildrenPostamble(print_dotdotdot);738 else {739 if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) {740 if (ShouldPrintValueObject())741 m_stream->PutCString(" {}\n");742 else743 m_stream->EOL();744 } else745 m_stream->EOL();746 }747 } else if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) {748 // Aggregate, no children...749 if (ShouldPrintValueObject()) {750 // if it has a synthetic value, then don't print {}, the synthetic751 // children are probably only being used to vend a value752 if (GetMostSpecializedValue().DoesProvideSyntheticValue() ||753 !ShouldExpandEmptyAggregates())754 m_stream->PutCString("\n");755 else756 m_stream->PutCString(" {}\n");757 }758 } else {759 if (ShouldPrintValueObject())760 m_stream->EOL();761 }762}763 764bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) {765 ValueObject &synth_valobj = GetValueObjectForChildrenGeneration();766 767 bool print_dotdotdot = false;768 auto num_children_or_err = GetMaxNumChildrenToPrint(print_dotdotdot);769 if (!num_children_or_err) {770 *m_stream << '<' << llvm::toString(num_children_or_err.takeError()) << '>';771 return true;772 }773 uint32_t num_children = *num_children_or_err;774 775 if (num_children) {776 m_stream->PutChar('(');777 778 bool did_print_children = false;779 for (uint32_t idx = 0; idx < num_children; ++idx) {780 lldb::ValueObjectSP child_sp(synth_valobj.GetChildAtIndex(idx));781 if (child_sp)782 child_sp = child_sp->GetQualifiedRepresentationIfAvailable(783 m_options.m_use_dynamic, m_options.m_use_synthetic);784 if (child_sp) {785 if (m_options.m_child_printing_decider &&786 !m_options.m_child_printing_decider(child_sp->GetName()))787 continue;788 if (idx && did_print_children)789 m_stream->PutCString(", ");790 did_print_children = true;791 if (!hide_names) {792 const char *name = child_sp.get()->GetName().AsCString();793 if (name && *name) {794 m_stream->PutCString(name);795 m_stream->PutCString(" = ");796 }797 }798 child_sp->DumpPrintableRepresentation(799 *m_stream, ValueObject::eValueObjectRepresentationStyleSummary,800 m_options.m_format,801 ValueObject::PrintableRepresentationSpecialCases::eDisable);802 }803 }804 805 if (print_dotdotdot)806 m_stream->PutCString(", ...)");807 else808 m_stream->PutChar(')');809 }810 return true;811}812 813llvm::Error ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed,814 bool summary_printed) {815 816 ValueObject &valobj = GetMostSpecializedValue();817 818 DumpValueObjectOptions::PointerDepth curr_ptr_depth = m_ptr_depth;819 const bool print_children = ShouldPrintChildren(curr_ptr_depth);820 const bool print_oneline =821 (curr_ptr_depth.CanAllowExpansion() || m_options.m_show_types ||822 !m_options.m_allow_oneliner_mode || m_options.m_flat_output ||823 (m_options.m_pointer_as_array) || m_options.m_show_location)824 ? false825 : DataVisualization::ShouldPrintAsOneLiner(valobj);826 if (print_children && IsInstancePointer()) {827 uint64_t instance_ptr_value = valobj.GetValueAsUnsigned(0);828 if (m_printed_instance_pointers->count(instance_ptr_value)) {829 // We already printed this instance-is-pointer thing, so don't expand it.830 m_stream->PutCString(" {...}\n");831 return llvm::Error::success();832 } else {833 // Remember this guy for future reference.834 m_printed_instance_pointers->emplace(instance_ptr_value);835 }836 }837 838 if (print_children) {839 if (print_oneline) {840 m_stream->PutChar(' ');841 PrintChildrenOneLiner(false);842 m_stream->EOL();843 } else844 PrintChildren(value_printed, summary_printed, curr_ptr_depth);845 } else if (HasReachedMaximumDepth() && IsAggregate() &&846 ShouldPrintValueObject()) {847 m_stream->PutCString(" {...}\n");848 // The maximum child depth has been reached. If `m_max_depth` is the default849 // (i.e. the user has _not_ customized it), then lldb presents a warning to850 // the user. The warning tells the user that the limit has been reached, but851 // more importantly tells them how to expand the limit if desired.852 if (m_options.m_max_depth_is_default)853 valobj.GetTargetSP()854 ->GetDebugger()855 .GetCommandInterpreter()856 .SetReachedMaximumDepth();857 } else858 m_stream->EOL();859 return llvm::Error::success();860}861 862bool ValueObjectPrinter::HasReachedMaximumDepth() {863 return m_curr_depth >= m_options.m_max_depth;864}865 866bool ValueObjectPrinter::ShouldShowName() const {867 if (m_curr_depth == 0)868 return !m_options.m_hide_root_name && !m_options.m_hide_name;869 return !m_options.m_hide_name;870}871