ValueObjectPrinter.cpp revision 344779
1219019Sgabor//===-- ValueObjectPrinter.cpp -----------------------------------*- C++-*-===// 2264497Stijl// 3219019Sgabor// The LLVM Compiler Infrastructure 4219019Sgabor// 5219019Sgabor// This file is distributed under the University of Illinois Open Source 6219019Sgabor// License. See LICENSE.TXT for details. 7219019Sgabor// 8219019Sgabor//===----------------------------------------------------------------------===// 9219019Sgabor 10219019Sgabor#include "lldb/DataFormatters/ValueObjectPrinter.h" 11219019Sgabor 12219019Sgabor#include "lldb/Core/ValueObject.h" 13219019Sgabor#include "lldb/DataFormatters/DataVisualization.h" 14219019Sgabor#include "lldb/Interpreter/CommandInterpreter.h" 15219019Sgabor#include "lldb/Target/Language.h" 16219019Sgabor#include "lldb/Target/Target.h" 17219019Sgabor#include "lldb/Utility/Stream.h" 18219019Sgabor 19219019Sgaborusing namespace lldb; 20219019Sgaborusing namespace lldb_private; 21219019Sgabor 22219019SgaborValueObjectPrinter::ValueObjectPrinter(ValueObject *valobj, Stream *s) { 23219019Sgabor if (valobj) { 24219019Sgabor DumpValueObjectOptions options(*valobj); 25219019Sgabor Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); 26219019Sgabor } else { 27219019Sgabor DumpValueObjectOptions options; 28219019Sgabor Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); 29219019Sgabor } 30219019Sgabor} 31219019Sgabor 32219019SgaborValueObjectPrinter::ValueObjectPrinter(ValueObject *valobj, Stream *s, 33219019Sgabor const DumpValueObjectOptions &options) { 34219019Sgabor Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); 35219019Sgabor} 36219019Sgabor 37219019SgaborValueObjectPrinter::ValueObjectPrinter( 38219019Sgabor ValueObject *valobj, Stream *s, const DumpValueObjectOptions &options, 39219019Sgabor const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth, 40219019Sgabor InstancePointersSetSP printed_instance_pointers) { 41219019Sgabor Init(valobj, s, options, ptr_depth, curr_depth, printed_instance_pointers); 42219019Sgabor} 43219019Sgabor 44219019Sgaborvoid ValueObjectPrinter::Init( 45219019Sgabor ValueObject *valobj, Stream *s, const DumpValueObjectOptions &options, 46219019Sgabor const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth, 47219019Sgabor InstancePointersSetSP printed_instance_pointers) { 48219019Sgabor m_orig_valobj = valobj; 49219019Sgabor m_valobj = nullptr; 50219019Sgabor m_stream = s; 51219019Sgabor m_options = options; 52219019Sgabor m_ptr_depth = ptr_depth; 53219019Sgabor m_curr_depth = curr_depth; 54219019Sgabor assert(m_orig_valobj && "cannot print a NULL ValueObject"); 55219019Sgabor assert(m_stream && "cannot print to a NULL Stream"); 56219019Sgabor m_should_print = eLazyBoolCalculate; 57219019Sgabor m_is_nil = eLazyBoolCalculate; 58252584Speter m_is_uninit = eLazyBoolCalculate; 59252584Speter m_is_ptr = eLazyBoolCalculate; 60219019Sgabor m_is_ref = eLazyBoolCalculate; 61219019Sgabor m_is_aggregate = eLazyBoolCalculate; 62219019Sgabor m_is_instance_ptr = eLazyBoolCalculate; 63219019Sgabor m_summary_formatter = {nullptr, false}; 64219019Sgabor m_value.assign(""); 65219019Sgabor m_summary.assign(""); 66219019Sgabor m_error.assign(""); 67219019Sgabor m_val_summary_ok = false; 68219019Sgabor m_printed_instance_pointers = 69219019Sgabor printed_instance_pointers 70219019Sgabor ? printed_instance_pointers 71219019Sgabor : InstancePointersSetSP(new InstancePointersSet()); 72219019Sgabor} 73219019Sgabor 74219019Sgaborbool ValueObjectPrinter::PrintValueObject() { 75219019Sgabor if (!GetMostSpecializedValue() || m_valobj == nullptr) 76219019Sgabor return false; 77219019Sgabor 78219019Sgabor if (ShouldPrintValueObject()) { 79219019Sgabor PrintValidationMarkerIfNeeded(); 80252584Speter 81219019Sgabor PrintLocationIfNeeded(); 82219019Sgabor m_stream->Indent(); 83219019Sgabor 84219019Sgabor PrintDecl(); 85219019Sgabor } 86219019Sgabor 87219019Sgabor bool value_printed = false; 88219019Sgabor bool summary_printed = false; 89219019Sgabor 90219019Sgabor m_val_summary_ok = 91219019Sgabor PrintValueAndSummaryIfNeeded(value_printed, summary_printed); 92219019Sgabor 93219019Sgabor if (m_val_summary_ok) 94219019Sgabor PrintChildrenIfNeeded(value_printed, summary_printed); 95219019Sgabor else 96219019Sgabor m_stream->EOL(); 97219019Sgabor 98219019Sgabor PrintValidationErrorIfNeeded(); 99219019Sgabor 100219019Sgabor return true; 101252464Speter} 102219019Sgabor 103219019Sgaborbool ValueObjectPrinter::GetMostSpecializedValue() { 104219019Sgabor if (m_valobj) 105219019Sgabor return true; 106219019Sgabor bool update_success = m_orig_valobj->UpdateValueIfNeeded(true); 107219019Sgabor if (!update_success) { 108219019Sgabor m_valobj = m_orig_valobj; 109252584Speter } else { 110219019Sgabor if (m_orig_valobj->IsDynamic()) { 111219019Sgabor if (m_options.m_use_dynamic == eNoDynamicValues) { 112219019Sgabor ValueObject *static_value = m_orig_valobj->GetStaticValue().get(); 113219019Sgabor if (static_value) 114219019Sgabor m_valobj = static_value; 115219019Sgabor else 116219019Sgabor m_valobj = m_orig_valobj; 117219019Sgabor } else 118219019Sgabor m_valobj = m_orig_valobj; 119219019Sgabor } else { 120219019Sgabor if (m_options.m_use_dynamic != eNoDynamicValues) { 121219019Sgabor ValueObject *dynamic_value = 122219019Sgabor m_orig_valobj->GetDynamicValue(m_options.m_use_dynamic).get(); 123219019Sgabor if (dynamic_value) 124219019Sgabor m_valobj = dynamic_value; 125219019Sgabor else 126219019Sgabor m_valobj = m_orig_valobj; 127219019Sgabor } else 128219019Sgabor m_valobj = m_orig_valobj; 129219019Sgabor } 130219019Sgabor 131219019Sgabor if (m_valobj->IsSynthetic()) { 132219019Sgabor if (!m_options.m_use_synthetic) { 133219019Sgabor ValueObject *non_synthetic = m_valobj->GetNonSyntheticValue().get(); 134219019Sgabor if (non_synthetic) 135219019Sgabor m_valobj = non_synthetic; 136219019Sgabor } 137219019Sgabor } else { 138219019Sgabor if (m_options.m_use_synthetic) { 139219019Sgabor ValueObject *synthetic = m_valobj->GetSyntheticValue().get(); 140219019Sgabor if (synthetic) 141219019Sgabor m_valobj = synthetic; 142219019Sgabor } 143219019Sgabor } 144219019Sgabor } 145219019Sgabor m_compiler_type = m_valobj->GetCompilerType(); 146219019Sgabor m_type_flags = m_compiler_type.GetTypeInfo(); 147219019Sgabor return true; 148219019Sgabor} 149219019Sgabor 150219019Sgaborconst char *ValueObjectPrinter::GetDescriptionForDisplay() { 151219019Sgabor const char *str = m_valobj->GetObjectDescription(); 152219019Sgabor if (!str) 153219019Sgabor str = m_valobj->GetSummaryAsCString(); 154219019Sgabor if (!str) 155219019Sgabor str = m_valobj->GetValueAsCString(); 156219019Sgabor return str; 157219019Sgabor} 158219019Sgabor 159219019Sgaborconst char *ValueObjectPrinter::GetRootNameForDisplay(const char *if_fail) { 160219019Sgabor const char *root_valobj_name = m_options.m_root_valobj_name.empty() 161219019Sgabor ? m_valobj->GetName().AsCString() 162219019Sgabor : m_options.m_root_valobj_name.c_str(); 163219019Sgabor return root_valobj_name ? root_valobj_name : if_fail; 164219019Sgabor} 165219019Sgabor 166219019Sgaborbool ValueObjectPrinter::ShouldPrintValueObject() { 167219019Sgabor if (m_should_print == eLazyBoolCalculate) 168219019Sgabor m_should_print = 169219019Sgabor (!m_options.m_flat_output || m_type_flags.Test(eTypeHasValue)) 170219019Sgabor ? eLazyBoolYes 171219019Sgabor : eLazyBoolNo; 172219019Sgabor return m_should_print == eLazyBoolYes; 173219019Sgabor} 174219019Sgabor 175219019Sgaborbool ValueObjectPrinter::IsNil() { 176219019Sgabor if (m_is_nil == eLazyBoolCalculate) 177219019Sgabor m_is_nil = m_valobj->IsNilReference() ? eLazyBoolYes : eLazyBoolNo; 178219019Sgabor return m_is_nil == eLazyBoolYes; 179219019Sgabor} 180219019Sgabor 181219019Sgaborbool ValueObjectPrinter::IsUninitialized() { 182219019Sgabor if (m_is_uninit == eLazyBoolCalculate) 183219019Sgabor m_is_uninit = 184219019Sgabor m_valobj->IsUninitializedReference() ? eLazyBoolYes : eLazyBoolNo; 185219019Sgabor return m_is_uninit == eLazyBoolYes; 186219019Sgabor} 187219019Sgabor 188219019Sgaborbool ValueObjectPrinter::IsPtr() { 189219019Sgabor if (m_is_ptr == eLazyBoolCalculate) 190219019Sgabor m_is_ptr = m_type_flags.Test(eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo; 191219019Sgabor return m_is_ptr == eLazyBoolYes; 192219019Sgabor} 193219019Sgabor 194219019Sgaborbool ValueObjectPrinter::IsRef() { 195219019Sgabor if (m_is_ref == eLazyBoolCalculate) 196219019Sgabor m_is_ref = m_type_flags.Test(eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo; 197219019Sgabor return m_is_ref == eLazyBoolYes; 198219019Sgabor} 199219019Sgabor 200219019Sgaborbool ValueObjectPrinter::IsAggregate() { 201219019Sgabor if (m_is_aggregate == eLazyBoolCalculate) 202219019Sgabor m_is_aggregate = 203219019Sgabor m_type_flags.Test(eTypeHasChildren) ? eLazyBoolYes : eLazyBoolNo; 204219019Sgabor return m_is_aggregate == eLazyBoolYes; 205219019Sgabor} 206219019Sgabor 207219019Sgaborbool ValueObjectPrinter::IsInstancePointer() { 208219019Sgabor // you need to do this check on the value's clang type 209219019Sgabor if (m_is_instance_ptr == eLazyBoolCalculate) 210219019Sgabor m_is_instance_ptr = (m_valobj->GetValue().GetCompilerType().GetTypeInfo() & 211219019Sgabor eTypeInstanceIsPointer) != 0 212219019Sgabor ? eLazyBoolYes 213219019Sgabor : eLazyBoolNo; 214219019Sgabor if ((eLazyBoolYes == m_is_instance_ptr) && m_valobj->IsBaseClass()) 215219019Sgabor m_is_instance_ptr = eLazyBoolNo; 216219019Sgabor return m_is_instance_ptr == eLazyBoolYes; 217219019Sgabor} 218219019Sgabor 219219019Sgaborbool ValueObjectPrinter::PrintLocationIfNeeded() { 220219019Sgabor if (m_options.m_show_location) { 221219019Sgabor m_stream->Printf("%s: ", m_valobj->GetLocationAsCString()); 222219019Sgabor return true; 223219019Sgabor } 224219019Sgabor return false; 225219019Sgabor} 226219019Sgabor 227219019Sgaborvoid ValueObjectPrinter::PrintDecl() { 228219019Sgabor bool show_type = true; 229219019Sgabor // if we are at the root-level and been asked to hide the root's type, then 230219019Sgabor // hide it 231219019Sgabor if (m_curr_depth == 0 && m_options.m_hide_root_type) 232219019Sgabor show_type = false; 233219019Sgabor else 234219019Sgabor // otherwise decide according to the usual rules (asked to show types - 235219019Sgabor // always at the root level) 236219019Sgabor show_type = m_options.m_show_types || 237219019Sgabor (m_curr_depth == 0 && !m_options.m_flat_output); 238219019Sgabor 239219019Sgabor StreamString typeName; 240219019Sgabor 241219019Sgabor // always show the type at the root level if it is invalid 242219019Sgabor if (show_type) { 243219019Sgabor // Some ValueObjects don't have types (like registers sets). Only print the 244219019Sgabor // type if there is one to print 245219019Sgabor ConstString type_name; 246219019Sgabor if (m_compiler_type.IsValid()) { 247264497Stijl if (m_options.m_use_type_display_name) 248264497Stijl type_name = m_valobj->GetDisplayTypeName(); 249219019Sgabor else 250264497Stijl type_name = m_valobj->GetQualifiedTypeName(); 251219019Sgabor } else { 252219019Sgabor // only show an invalid type name if the user explicitly triggered 253219019Sgabor // show_type 254219019Sgabor if (m_options.m_show_types) 255219019Sgabor type_name = ConstString("<invalid type>"); 256219019Sgabor else 257219019Sgabor type_name.Clear(); 258219019Sgabor } 259219019Sgabor 260219019Sgabor if (type_name) { 261219019Sgabor std::string type_name_str(type_name.GetCString()); 262219019Sgabor if (m_options.m_hide_pointer_value) { 263219019Sgabor for (auto iter = type_name_str.find(" *"); iter != std::string::npos; 264219019Sgabor iter = type_name_str.find(" *")) { 265219019Sgabor type_name_str.erase(iter, 2); 266219019Sgabor } 267219019Sgabor } 268219019Sgabor typeName.Printf("%s", type_name_str.c_str()); 269219019Sgabor } 270219019Sgabor } 271219019Sgabor 272219019Sgabor StreamString varName; 273219019Sgabor 274219019Sgabor if (m_options.m_flat_output) { 275219019Sgabor // If we are showing types, also qualify the C++ base classes 276219019Sgabor const bool qualify_cxx_base_classes = show_type; 277219019Sgabor if (!m_options.m_hide_name) { 278219019Sgabor m_valobj->GetExpressionPath(varName, qualify_cxx_base_classes); 279219019Sgabor } 280219019Sgabor } else if (!m_options.m_hide_name) { 281219019Sgabor const char *name_cstr = GetRootNameForDisplay(""); 282219019Sgabor varName.Printf("%s", name_cstr); 283219019Sgabor } 284219019Sgabor 285219019Sgabor bool decl_printed = false; 286219019Sgabor if (!m_options.m_decl_printing_helper) { 287219019Sgabor // if the user didn't give us a custom helper, pick one based upon the 288219019Sgabor // language, either the one that this printer is bound to, or the preferred 289219019Sgabor // one for the ValueObject 290219019Sgabor lldb::LanguageType lang_type = 291219019Sgabor (m_options.m_varformat_language == lldb::eLanguageTypeUnknown) 292219019Sgabor ? m_valobj->GetPreferredDisplayLanguage() 293219019Sgabor : m_options.m_varformat_language; 294219019Sgabor if (Language *lang_plugin = Language::FindPlugin(lang_type)) { 295219019Sgabor m_options.m_decl_printing_helper = lang_plugin->GetDeclPrintingHelper(); 296219019Sgabor } 297219019Sgabor } 298219019Sgabor 299219019Sgabor if (m_options.m_decl_printing_helper) { 300219019Sgabor ConstString type_name_cstr(typeName.GetString()); 301219019Sgabor ConstString var_name_cstr(varName.GetString()); 302219019Sgabor 303219019Sgabor StreamString dest_stream; 304219019Sgabor if (m_options.m_decl_printing_helper(type_name_cstr, var_name_cstr, 305219019Sgabor m_options, dest_stream)) { 306219019Sgabor decl_printed = true; 307219019Sgabor m_stream->PutCString(dest_stream.GetString()); 308219019Sgabor } 309219019Sgabor } 310219019Sgabor 311219019Sgabor // if the helper failed, or there is none, do a default thing 312219019Sgabor if (!decl_printed) { 313219019Sgabor if (!typeName.Empty()) 314219019Sgabor m_stream->Printf("(%s) ", typeName.GetData()); 315219019Sgabor if (!varName.Empty()) 316219019Sgabor m_stream->Printf("%s =", varName.GetData()); 317219019Sgabor else if (!m_options.m_hide_name) 318219019Sgabor m_stream->Printf(" ="); 319219019Sgabor } 320219019Sgabor} 321219019Sgabor 322219019Sgaborbool ValueObjectPrinter::CheckScopeIfNeeded() { 323252584Speter if (m_options.m_scope_already_checked) 324219019Sgabor return true; 325219019Sgabor return m_valobj->IsInScope(); 326219019Sgabor} 327219019Sgabor 328219019SgaborTypeSummaryImpl *ValueObjectPrinter::GetSummaryFormatter(bool null_if_omitted) { 329219019Sgabor if (!m_summary_formatter.second) { 330219019Sgabor TypeSummaryImpl *entry = m_options.m_summary_sp 331219019Sgabor ? m_options.m_summary_sp.get() 332219019Sgabor : m_valobj->GetSummaryFormat().get(); 333219019Sgabor 334219019Sgabor if (m_options.m_omit_summary_depth > 0) 335219019Sgabor entry = NULL; 336219019Sgabor m_summary_formatter.first = entry; 337219019Sgabor m_summary_formatter.second = true; 338219019Sgabor } 339219019Sgabor if (m_options.m_omit_summary_depth > 0 && null_if_omitted) 340219019Sgabor return nullptr; 341219019Sgabor return m_summary_formatter.first; 342219019Sgabor} 343219019Sgabor 344252584Speterstatic bool IsPointerValue(const CompilerType &type) { 345219019Sgabor Flags type_flags(type.GetTypeInfo()); 346252584Speter if (type_flags.AnySet(eTypeInstanceIsPointer | eTypeIsPointer)) 347219019Sgabor return type_flags.AllClear(eTypeIsBuiltIn); 348219019Sgabor return false; 349219019Sgabor} 350219019Sgabor 351219019Sgaborvoid ValueObjectPrinter::GetValueSummaryError(std::string &value, 352219019Sgabor std::string &summary, 353219019Sgabor std::string &error) { 354219019Sgabor lldb::Format format = m_options.m_format; 355219019Sgabor // if I am printing synthetized elements, apply the format to those elements 356219019Sgabor // only 357219019Sgabor if (m_options.m_pointer_as_array) 358219019Sgabor m_valobj->GetValueAsCString(lldb::eFormatDefault, value); 359219019Sgabor else if (format != eFormatDefault && format != m_valobj->GetFormat()) 360219019Sgabor m_valobj->GetValueAsCString(format, value); 361219019Sgabor else { 362219019Sgabor const char *val_cstr = m_valobj->GetValueAsCString(); 363252584Speter if (val_cstr) 364219019Sgabor value.assign(val_cstr); 365219019Sgabor } 366219019Sgabor const char *err_cstr = m_valobj->GetError().AsCString(); 367219019Sgabor if (err_cstr) 368219019Sgabor error.assign(err_cstr); 369219019Sgabor 370219019Sgabor if (ShouldPrintValueObject()) { 371219019Sgabor if (IsNil()) 372219019Sgabor summary.assign("nil"); 373219019Sgabor else if (IsUninitialized()) 374219019Sgabor summary.assign("<uninitialized>"); 375219019Sgabor else if (m_options.m_omit_summary_depth == 0) { 376219019Sgabor TypeSummaryImpl *entry = GetSummaryFormatter(); 377252584Speter if (entry) 378219019Sgabor m_valobj->GetSummaryAsCString(entry, summary, 379219019Sgabor m_options.m_varformat_language); 380219019Sgabor else { 381219019Sgabor const char *sum_cstr = 382219019Sgabor m_valobj->GetSummaryAsCString(m_options.m_varformat_language); 383219019Sgabor if (sum_cstr) 384219019Sgabor summary.assign(sum_cstr); 385219019Sgabor } 386257039Sdelphij } 387219019Sgabor } 388257039Sdelphij} 389219019Sgabor 390252584Speterbool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed, 391219019Sgabor bool &summary_printed) { 392219019Sgabor bool error_printed = false; 393219019Sgabor if (ShouldPrintValueObject()) { 394219019Sgabor if (!CheckScopeIfNeeded()) 395219019Sgabor m_error.assign("out of scope"); 396219019Sgabor if (m_error.empty()) { 397219019Sgabor GetValueSummaryError(m_value, m_summary, m_error); 398219019Sgabor } 399219019Sgabor if (m_error.size()) { 400219019Sgabor // we need to support scenarios in which it is actually fine for a value 401219019Sgabor // to have no type but - on the other hand - if we get an error *AND* 402252584Speter // have no type, we try to get out gracefully, since most often that 403219019Sgabor // combination means "could not resolve a type" and the default failure 404252584Speter // mode is quite ugly 405219019Sgabor if (!m_compiler_type.IsValid()) { 406 m_stream->Printf(" <could not resolve type>"); 407 return false; 408 } 409 410 error_printed = true; 411 m_stream->Printf(" <%s>\n", m_error.c_str()); 412 } else { 413 // Make sure we have a value and make sure the summary didn't specify 414 // that the value should not be printed - and do not print the value if 415 // this thing is nil (but show the value if the user passes a format 416 // explicitly) 417 TypeSummaryImpl *entry = GetSummaryFormatter(); 418 if (!IsNil() && !IsUninitialized() && !m_value.empty() && 419 (entry == NULL || (entry->DoesPrintValue(m_valobj) || 420 m_options.m_format != eFormatDefault) || 421 m_summary.empty()) && 422 !m_options.m_hide_value) { 423 if (m_options.m_hide_pointer_value && 424 IsPointerValue(m_valobj->GetCompilerType())) { 425 } else { 426 m_stream->Printf(" %s", m_value.c_str()); 427 value_printed = true; 428 } 429 } 430 431 if (m_summary.size()) { 432 m_stream->Printf(" %s", m_summary.c_str()); 433 summary_printed = true; 434 } 435 } 436 } 437 return !error_printed; 438} 439 440bool ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed, 441 bool summary_printed) { 442 if (ShouldPrintValueObject()) { 443 // let's avoid the overly verbose no description error for a nil thing 444 if (m_options.m_use_objc && !IsNil() && !IsUninitialized() && 445 (!m_options.m_pointer_as_array)) { 446 if (!m_options.m_hide_value || !m_options.m_hide_name) 447 m_stream->Printf(" "); 448 const char *object_desc = nullptr; 449 if (value_printed || summary_printed) 450 object_desc = m_valobj->GetObjectDescription(); 451 else 452 object_desc = GetDescriptionForDisplay(); 453 if (object_desc && *object_desc) { 454 // If the description already ends with a \n don't add another one. 455 size_t object_end = strlen(object_desc) - 1; 456 if (object_desc[object_end] == '\n') 457 m_stream->Printf("%s", object_desc); 458 else 459 m_stream->Printf("%s\n", object_desc); 460 return true; 461 } else if (!value_printed && !summary_printed) 462 return true; 463 else 464 return false; 465 } 466 } 467 return true; 468} 469 470bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion() const { 471 switch (m_mode) { 472 case Mode::Always: 473 case Mode::Default: 474 return m_count > 0; 475 case Mode::Never: 476 return false; 477 } 478 return false; 479} 480 481bool ValueObjectPrinter::ShouldPrintChildren( 482 bool is_failed_description, 483 DumpValueObjectOptions::PointerDepth &curr_ptr_depth) { 484 const bool is_ref = IsRef(); 485 const bool is_ptr = IsPtr(); 486 const bool is_uninit = IsUninitialized(); 487 488 if (is_uninit) 489 return false; 490 491 // if the user has specified an element count, always print children as it is 492 // explicit user demand being honored 493 if (m_options.m_pointer_as_array) 494 return true; 495 496 TypeSummaryImpl *entry = GetSummaryFormatter(); 497 498 if (m_options.m_use_objc) 499 return false; 500 501 if (is_failed_description || m_curr_depth < m_options.m_max_depth) { 502 // We will show children for all concrete types. We won't show pointer 503 // contents unless a pointer depth has been specified. We won't reference 504 // contents unless the reference is the root object (depth of zero). 505 506 // Use a new temporary pointer depth in case we override the current 507 // pointer depth below... 508 509 if (is_ptr || is_ref) { 510 // We have a pointer or reference whose value is an address. Make sure 511 // that address is not NULL 512 AddressType ptr_address_type; 513 if (m_valobj->GetPointerValue(&ptr_address_type) == 0) 514 return false; 515 516 const bool is_root_level = m_curr_depth == 0; 517 518 if (is_ref && is_root_level) { 519 // If this is the root object (depth is zero) that we are showing and 520 // it is a reference, and no pointer depth has been supplied print out 521 // what it references. Don't do this at deeper depths otherwise we can 522 // end up with infinite recursion... 523 return true; 524 } 525 526 return curr_ptr_depth.CanAllowExpansion(); 527 } 528 529 return (!entry || entry->DoesPrintChildren(m_valobj) || m_summary.empty()); 530 } 531 return false; 532} 533 534bool ValueObjectPrinter::ShouldExpandEmptyAggregates() { 535 TypeSummaryImpl *entry = GetSummaryFormatter(); 536 537 if (!entry) 538 return true; 539 540 return entry->DoesPrintEmptyAggregates(); 541} 542 543ValueObject *ValueObjectPrinter::GetValueObjectForChildrenGeneration() { 544 return m_valobj; 545} 546 547void ValueObjectPrinter::PrintChildrenPreamble() { 548 if (m_options.m_flat_output) { 549 if (ShouldPrintValueObject()) 550 m_stream->EOL(); 551 } else { 552 if (ShouldPrintValueObject()) 553 m_stream->PutCString(IsRef() ? ": {\n" : " {\n"); 554 m_stream->IndentMore(); 555 } 556} 557 558void ValueObjectPrinter::PrintChild( 559 ValueObjectSP child_sp, 560 const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) { 561 const uint32_t consumed_depth = (!m_options.m_pointer_as_array) ? 1 : 0; 562 const bool does_consume_ptr_depth = 563 ((IsPtr() && !m_options.m_pointer_as_array) || IsRef()); 564 565 DumpValueObjectOptions child_options(m_options); 566 child_options.SetFormat(m_options.m_format) 567 .SetSummary() 568 .SetRootValueObjectName(); 569 child_options.SetScopeChecked(true) 570 .SetHideName(m_options.m_hide_name) 571 .SetHideValue(m_options.m_hide_value) 572 .SetOmitSummaryDepth(child_options.m_omit_summary_depth > 1 573 ? child_options.m_omit_summary_depth - 574 consumed_depth 575 : 0) 576 .SetElementCount(0); 577 578 if (child_sp.get()) { 579 ValueObjectPrinter child_printer( 580 child_sp.get(), m_stream, child_options, 581 does_consume_ptr_depth ? --curr_ptr_depth : curr_ptr_depth, 582 m_curr_depth + consumed_depth, m_printed_instance_pointers); 583 child_printer.PrintValueObject(); 584 } 585} 586 587uint32_t ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot) { 588 ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); 589 590 if (m_options.m_pointer_as_array) 591 return m_options.m_pointer_as_array.m_element_count; 592 593 size_t num_children = synth_m_valobj->GetNumChildren(); 594 print_dotdotdot = false; 595 if (num_children) { 596 const size_t max_num_children = 597 m_valobj->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay(); 598 599 if (num_children > max_num_children && !m_options.m_ignore_cap) { 600 print_dotdotdot = true; 601 return max_num_children; 602 } 603 } 604 return num_children; 605} 606 607void ValueObjectPrinter::PrintChildrenPostamble(bool print_dotdotdot) { 608 if (!m_options.m_flat_output) { 609 if (print_dotdotdot) { 610 m_valobj->GetTargetSP() 611 ->GetDebugger() 612 .GetCommandInterpreter() 613 .ChildrenTruncated(); 614 m_stream->Indent("...\n"); 615 } 616 m_stream->IndentLess(); 617 m_stream->Indent("}\n"); 618 } 619} 620 621bool ValueObjectPrinter::ShouldPrintEmptyBrackets(bool value_printed, 622 bool summary_printed) { 623 ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); 624 625 if (!IsAggregate()) 626 return false; 627 628 if (!m_options.m_reveal_empty_aggregates) { 629 if (value_printed || summary_printed) 630 return false; 631 } 632 633 if (synth_m_valobj->MightHaveChildren()) 634 return true; 635 636 if (m_val_summary_ok) 637 return false; 638 639 return true; 640} 641 642static constexpr size_t PhysicalIndexForLogicalIndex(size_t base, size_t stride, 643 size_t logical) { 644 return base + logical * stride; 645} 646 647ValueObjectSP ValueObjectPrinter::GenerateChild(ValueObject *synth_valobj, 648 size_t idx) { 649 if (m_options.m_pointer_as_array) { 650 // if generating pointer-as-array children, use GetSyntheticArrayMember 651 return synth_valobj->GetSyntheticArrayMember( 652 PhysicalIndexForLogicalIndex( 653 m_options.m_pointer_as_array.m_base_element, 654 m_options.m_pointer_as_array.m_stride, idx), 655 true); 656 } else { 657 // otherwise, do the usual thing 658 return synth_valobj->GetChildAtIndex(idx, true); 659 } 660} 661 662void ValueObjectPrinter::PrintChildren( 663 bool value_printed, bool summary_printed, 664 const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) { 665 ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); 666 667 bool print_dotdotdot = false; 668 size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot); 669 if (num_children) { 670 bool any_children_printed = false; 671 672 for (size_t idx = 0; idx < num_children; ++idx) { 673 if (ValueObjectSP child_sp = GenerateChild(synth_m_valobj, idx)) { 674 if (!any_children_printed) { 675 PrintChildrenPreamble(); 676 any_children_printed = true; 677 } 678 PrintChild(child_sp, curr_ptr_depth); 679 } 680 } 681 682 if (any_children_printed) 683 PrintChildrenPostamble(print_dotdotdot); 684 else { 685 if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) { 686 if (ShouldPrintValueObject()) 687 m_stream->PutCString(" {}\n"); 688 else 689 m_stream->EOL(); 690 } else 691 m_stream->EOL(); 692 } 693 } else if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) { 694 // Aggregate, no children... 695 if (ShouldPrintValueObject()) { 696 // if it has a synthetic value, then don't print {}, the synthetic 697 // children are probably only being used to vend a value 698 if (m_valobj->DoesProvideSyntheticValue() || 699 !ShouldExpandEmptyAggregates()) 700 m_stream->PutCString("\n"); 701 else 702 m_stream->PutCString(" {}\n"); 703 } 704 } else { 705 if (ShouldPrintValueObject()) 706 m_stream->EOL(); 707 } 708} 709 710bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) { 711 if (!GetMostSpecializedValue() || m_valobj == nullptr) 712 return false; 713 714 ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); 715 716 bool print_dotdotdot = false; 717 size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot); 718 719 if (num_children) { 720 m_stream->PutChar('('); 721 722 for (uint32_t idx = 0; idx < num_children; ++idx) { 723 lldb::ValueObjectSP child_sp(synth_m_valobj->GetChildAtIndex(idx, true)); 724 if (child_sp) 725 child_sp = child_sp->GetQualifiedRepresentationIfAvailable( 726 m_options.m_use_dynamic, m_options.m_use_synthetic); 727 if (child_sp) { 728 if (idx) 729 m_stream->PutCString(", "); 730 if (!hide_names) { 731 const char *name = child_sp.get()->GetName().AsCString(); 732 if (name && *name) { 733 m_stream->PutCString(name); 734 m_stream->PutCString(" = "); 735 } 736 } 737 child_sp->DumpPrintableRepresentation( 738 *m_stream, ValueObject::eValueObjectRepresentationStyleSummary, 739 m_options.m_format, 740 ValueObject::PrintableRepresentationSpecialCases::eDisable); 741 } 742 } 743 744 if (print_dotdotdot) 745 m_stream->PutCString(", ...)"); 746 else 747 m_stream->PutChar(')'); 748 } 749 return true; 750} 751 752void ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed, 753 bool summary_printed) { 754 // this flag controls whether we tried to display a description for this 755 // object and failed if that happens, we want to display the children, if any 756 bool is_failed_description = 757 !PrintObjectDescriptionIfNeeded(value_printed, summary_printed); 758 759 auto curr_ptr_depth = m_ptr_depth; 760 bool print_children = 761 ShouldPrintChildren(is_failed_description, curr_ptr_depth); 762 bool print_oneline = 763 (curr_ptr_depth.CanAllowExpansion() || m_options.m_show_types || 764 !m_options.m_allow_oneliner_mode || m_options.m_flat_output || 765 (m_options.m_pointer_as_array) || m_options.m_show_location) 766 ? false 767 : DataVisualization::ShouldPrintAsOneLiner(*m_valobj); 768 bool is_instance_ptr = IsInstancePointer(); 769 uint64_t instance_ptr_value = LLDB_INVALID_ADDRESS; 770 771 if (print_children && is_instance_ptr) { 772 instance_ptr_value = m_valobj->GetValueAsUnsigned(0); 773 if (m_printed_instance_pointers->count(instance_ptr_value)) { 774 // we already printed this instance-is-pointer thing, so don't expand it 775 m_stream->PutCString(" {...}\n"); 776 777 // we're done here - get out fast 778 return; 779 } else 780 m_printed_instance_pointers->emplace( 781 instance_ptr_value); // remember this guy for future reference 782 } 783 784 if (print_children) { 785 if (print_oneline) { 786 m_stream->PutChar(' '); 787 PrintChildrenOneLiner(false); 788 m_stream->EOL(); 789 } else 790 PrintChildren(value_printed, summary_printed, curr_ptr_depth); 791 } else if (m_curr_depth >= m_options.m_max_depth && IsAggregate() && 792 ShouldPrintValueObject()) { 793 m_stream->PutCString("{...}\n"); 794 } else 795 m_stream->EOL(); 796} 797 798bool ValueObjectPrinter::ShouldPrintValidation() { 799 return m_options.m_run_validator; 800} 801 802bool ValueObjectPrinter::PrintValidationMarkerIfNeeded() { 803 if (!ShouldPrintValidation()) 804 return false; 805 806 m_validation = m_valobj->GetValidationStatus(); 807 808 if (TypeValidatorResult::Failure == m_validation.first) { 809 m_stream->Printf("! "); 810 return true; 811 } 812 813 return false; 814} 815 816bool ValueObjectPrinter::PrintValidationErrorIfNeeded() { 817 if (!ShouldPrintValidation()) 818 return false; 819 820 if (TypeValidatorResult::Success == m_validation.first) 821 return false; 822 823 if (m_validation.second.empty()) 824 m_validation.second.assign("unknown error"); 825 826 m_stream->Printf(" ! validation error: %s", m_validation.second.c_str()); 827 m_stream->EOL(); 828 829 return true; 830} 831