1 //===-- ValueObjectPrinter.cpp -----------------------------------*- C++-*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "lldb/DataFormatters/ValueObjectPrinter.h" 11 12 #include "lldb/Core/ValueObject.h" 13 #include "lldb/DataFormatters/DataVisualization.h" 14 #include "lldb/Interpreter/CommandInterpreter.h" 15 #include "lldb/Target/Language.h" 16 #include "lldb/Target/Target.h" 17 #include "lldb/Utility/Stream.h" 18 19 using namespace lldb; 20 using namespace lldb_private; 21 22 ValueObjectPrinter::ValueObjectPrinter(ValueObject *valobj, Stream *s) { 23 if (valobj) { 24 DumpValueObjectOptions options(*valobj); 25 Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); 26 } else { 27 DumpValueObjectOptions options; 28 Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); 29 } 30 } 31 32 ValueObjectPrinter::ValueObjectPrinter(ValueObject *valobj, Stream *s, 33 const DumpValueObjectOptions &options) { 34 Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); 35 } 36 37 ValueObjectPrinter::ValueObjectPrinter( 38 ValueObject *valobj, Stream *s, const DumpValueObjectOptions &options, 39 const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth, 40 InstancePointersSetSP printed_instance_pointers) { 41 Init(valobj, s, options, ptr_depth, curr_depth, printed_instance_pointers); 42 } 43 44 void ValueObjectPrinter::Init( 45 ValueObject *valobj, Stream *s, const DumpValueObjectOptions &options, 46 const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth, 47 InstancePointersSetSP printed_instance_pointers) { 48 m_orig_valobj = valobj; 49 m_valobj = nullptr; 50 m_stream = s; 51 m_options = options; 52 m_ptr_depth = ptr_depth; 53 m_curr_depth = curr_depth; 54 assert(m_orig_valobj && "cannot print a NULL ValueObject"); 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 = 69 printed_instance_pointers 70 ? printed_instance_pointers 71 : InstancePointersSetSP(new InstancePointersSet()); 72 } 73 74 bool ValueObjectPrinter::PrintValueObject() { 75 if (!GetMostSpecializedValue() || m_valobj == nullptr) 76 return false; 77 78 if (ShouldPrintValueObject()) { 79 PrintValidationMarkerIfNeeded(); 80 81 PrintLocationIfNeeded(); 82 m_stream->Indent(); 83 84 PrintDecl(); 85 } 86 87 bool value_printed = false; 88 bool summary_printed = false; 89 90 m_val_summary_ok = 91 PrintValueAndSummaryIfNeeded(value_printed, summary_printed); 92 93 if (m_val_summary_ok) 94 PrintChildrenIfNeeded(value_printed, summary_printed); 95 else 96 m_stream->EOL(); 97 98 PrintValidationErrorIfNeeded(); 99 100 return true; 101 } 102 103 bool ValueObjectPrinter::GetMostSpecializedValue() { 104 if (m_valobj) 105 return true; 106 bool update_success = m_orig_valobj->UpdateValueIfNeeded(true); 107 if (!update_success) { 108 m_valobj = m_orig_valobj; 109 } else { 110 if (m_orig_valobj->IsDynamic()) { 111 if (m_options.m_use_dynamic == eNoDynamicValues) { 112 ValueObject *static_value = m_orig_valobj->GetStaticValue().get(); 113 if (static_value) 114 m_valobj = static_value; 115 else 116 m_valobj = m_orig_valobj; 117 } else 118 m_valobj = m_orig_valobj; 119 } else { 120 if (m_options.m_use_dynamic != eNoDynamicValues) { 121 ValueObject *dynamic_value = 122 m_orig_valobj->GetDynamicValue(m_options.m_use_dynamic).get(); 123 if (dynamic_value) 124 m_valobj = dynamic_value; 125 else 126 m_valobj = m_orig_valobj; 127 } else 128 m_valobj = m_orig_valobj; 129 } 130 131 if (m_valobj->IsSynthetic()) { 132 if (m_options.m_use_synthetic == false) { 133 ValueObject *non_synthetic = m_valobj->GetNonSyntheticValue().get(); 134 if (non_synthetic) 135 m_valobj = non_synthetic; 136 } 137 } else { 138 if (m_options.m_use_synthetic == true) { 139 ValueObject *synthetic = m_valobj->GetSyntheticValue().get(); 140 if (synthetic) 141 m_valobj = synthetic; 142 } 143 } 144 } 145 m_compiler_type = m_valobj->GetCompilerType(); 146 m_type_flags = m_compiler_type.GetTypeInfo(); 147 return true; 148 } 149 150 const char *ValueObjectPrinter::GetDescriptionForDisplay() { 151 const char *str = m_valobj->GetObjectDescription(); 152 if (!str) 153 str = m_valobj->GetSummaryAsCString(); 154 if (!str) 155 str = m_valobj->GetValueAsCString(); 156 return str; 157 } 158 159 const char *ValueObjectPrinter::GetRootNameForDisplay(const char *if_fail) { 160 const char *root_valobj_name = m_options.m_root_valobj_name.empty() 161 ? m_valobj->GetName().AsCString() 162 : m_options.m_root_valobj_name.c_str(); 163 return root_valobj_name ? root_valobj_name : if_fail; 164 } 165 166 bool ValueObjectPrinter::ShouldPrintValueObject() { 167 if (m_should_print == eLazyBoolCalculate) 168 m_should_print = 169 (m_options.m_flat_output == false || m_type_flags.Test(eTypeHasValue)) 170 ? eLazyBoolYes 171 : eLazyBoolNo; 172 return m_should_print == eLazyBoolYes; 173 } 174 175 bool ValueObjectPrinter::IsNil() { 176 if (m_is_nil == eLazyBoolCalculate) 177 m_is_nil = m_valobj->IsNilReference() ? eLazyBoolYes : eLazyBoolNo; 178 return m_is_nil == eLazyBoolYes; 179 } 180 181 bool ValueObjectPrinter::IsUninitialized() { 182 if (m_is_uninit == eLazyBoolCalculate) 183 m_is_uninit = 184 m_valobj->IsUninitializedReference() ? eLazyBoolYes : eLazyBoolNo; 185 return m_is_uninit == eLazyBoolYes; 186 } 187 188 bool ValueObjectPrinter::IsPtr() { 189 if (m_is_ptr == eLazyBoolCalculate) 190 m_is_ptr = m_type_flags.Test(eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo; 191 return m_is_ptr == eLazyBoolYes; 192 } 193 194 bool ValueObjectPrinter::IsRef() { 195 if (m_is_ref == eLazyBoolCalculate) 196 m_is_ref = m_type_flags.Test(eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo; 197 return m_is_ref == eLazyBoolYes; 198 } 199 200 bool ValueObjectPrinter::IsAggregate() { 201 if (m_is_aggregate == eLazyBoolCalculate) 202 m_is_aggregate = 203 m_type_flags.Test(eTypeHasChildren) ? eLazyBoolYes : eLazyBoolNo; 204 return m_is_aggregate == eLazyBoolYes; 205 } 206 207 bool ValueObjectPrinter::IsInstancePointer() { 208 // you need to do this check on the value's clang type 209 if (m_is_instance_ptr == eLazyBoolCalculate) 210 m_is_instance_ptr = (m_valobj->GetValue().GetCompilerType().GetTypeInfo() & 211 eTypeInstanceIsPointer) != 0 212 ? eLazyBoolYes 213 : eLazyBoolNo; 214 if ((eLazyBoolYes == m_is_instance_ptr) && m_valobj->IsBaseClass()) 215 m_is_instance_ptr = eLazyBoolNo; 216 return m_is_instance_ptr == eLazyBoolYes; 217 } 218 219 bool ValueObjectPrinter::PrintLocationIfNeeded() { 220 if (m_options.m_show_location) { 221 m_stream->Printf("%s: ", m_valobj->GetLocationAsCString()); 222 return true; 223 } 224 return false; 225 } 226 227 void ValueObjectPrinter::PrintDecl() { 228 bool show_type = true; 229 // if we are at the root-level and been asked to hide the root's type, then 230 // hide it 231 if (m_curr_depth == 0 && m_options.m_hide_root_type) 232 show_type = false; 233 else 234 // otherwise decide according to the usual rules (asked to show types - 235 // always at the root level) 236 show_type = m_options.m_show_types || 237 (m_curr_depth == 0 && !m_options.m_flat_output); 238 239 StreamString typeName; 240 241 // always show the type at the root level if it is invalid 242 if (show_type) { 243 // Some ValueObjects don't have types (like registers sets). Only print the 244 // type if there is one to print 245 ConstString type_name; 246 if (m_compiler_type.IsValid()) { 247 if (m_options.m_use_type_display_name) 248 type_name = m_valobj->GetDisplayTypeName(); 249 else 250 type_name = m_valobj->GetQualifiedTypeName(); 251 } else { 252 // only show an invalid type name if the user explicitly triggered 253 // show_type 254 if (m_options.m_show_types) 255 type_name = ConstString("<invalid type>"); 256 else 257 type_name.Clear(); 258 } 259 260 if (type_name) { 261 std::string type_name_str(type_name.GetCString()); 262 if (m_options.m_hide_pointer_value) { 263 for (auto iter = type_name_str.find(" *"); iter != std::string::npos; 264 iter = type_name_str.find(" *")) { 265 type_name_str.erase(iter, 2); 266 } 267 } 268 typeName.Printf("%s", type_name_str.c_str()); 269 } 270 } 271 272 StreamString varName; 273 274 if (m_options.m_flat_output) { 275 // If we are showing types, also qualify the C++ base classes 276 const bool qualify_cxx_base_classes = show_type; 277 if (!m_options.m_hide_name) { 278 m_valobj->GetExpressionPath(varName, qualify_cxx_base_classes); 279 } 280 } else if (!m_options.m_hide_name) { 281 const char *name_cstr = GetRootNameForDisplay(""); 282 varName.Printf("%s", name_cstr); 283 } 284 285 bool decl_printed = false; 286 if (!m_options.m_decl_printing_helper) { 287 // if the user didn't give us a custom helper, pick one based upon the 288 // language, either the one that this printer is bound to, or the preferred 289 // one for the ValueObject 290 lldb::LanguageType lang_type = 291 (m_options.m_varformat_language == lldb::eLanguageTypeUnknown) 292 ? m_valobj->GetPreferredDisplayLanguage() 293 : m_options.m_varformat_language; 294 if (Language *lang_plugin = Language::FindPlugin(lang_type)) { 295 m_options.m_decl_printing_helper = lang_plugin->GetDeclPrintingHelper(); 296 } 297 } 298 299 if (m_options.m_decl_printing_helper) { 300 ConstString type_name_cstr(typeName.GetString()); 301 ConstString var_name_cstr(varName.GetString()); 302 303 StreamString dest_stream; 304 if (m_options.m_decl_printing_helper(type_name_cstr, var_name_cstr, 305 m_options, dest_stream)) { 306 decl_printed = true; 307 m_stream->PutCString(dest_stream.GetString()); 308 } 309 } 310 311 // if the helper failed, or there is none, do a default thing 312 if (!decl_printed) { 313 if (!typeName.Empty()) 314 m_stream->Printf("(%s) ", typeName.GetData()); 315 if (!varName.Empty()) 316 m_stream->Printf("%s =", varName.GetData()); 317 else if (!m_options.m_hide_name) 318 m_stream->Printf(" ="); 319 } 320 } 321 322 bool ValueObjectPrinter::CheckScopeIfNeeded() { 323 if (m_options.m_scope_already_checked) 324 return true; 325 return m_valobj->IsInScope(); 326 } 327 328 TypeSummaryImpl *ValueObjectPrinter::GetSummaryFormatter(bool null_if_omitted) { 329 if (m_summary_formatter.second == false) { 330 TypeSummaryImpl *entry = m_options.m_summary_sp 331 ? m_options.m_summary_sp.get() 332 : m_valobj->GetSummaryFormat().get(); 333 334 if (m_options.m_omit_summary_depth > 0) 335 entry = NULL; 336 m_summary_formatter.first = entry; 337 m_summary_formatter.second = true; 338 } 339 if (m_options.m_omit_summary_depth > 0 && null_if_omitted) 340 return nullptr; 341 return m_summary_formatter.first; 342 } 343 344 static bool IsPointerValue(const CompilerType &type) { 345 Flags type_flags(type.GetTypeInfo()); 346 if (type_flags.AnySet(eTypeInstanceIsPointer | eTypeIsPointer)) 347 return type_flags.AllClear(eTypeIsBuiltIn); 348 return false; 349 } 350 351 void ValueObjectPrinter::GetValueSummaryError(std::string &value, 352 std::string &summary, 353 std::string &error) { 354 lldb::Format format = m_options.m_format; 355 // if I am printing synthetized elements, apply the format to those elements 356 // only 357 if (m_options.m_pointer_as_array) 358 m_valobj->GetValueAsCString(lldb::eFormatDefault, value); 359 else if (format != eFormatDefault && format != m_valobj->GetFormat()) 360 m_valobj->GetValueAsCString(format, value); 361 else { 362 const char *val_cstr = m_valobj->GetValueAsCString(); 363 if (val_cstr) 364 value.assign(val_cstr); 365 } 366 const char *err_cstr = m_valobj->GetError().AsCString(); 367 if (err_cstr) 368 error.assign(err_cstr); 369 370 if (ShouldPrintValueObject()) { 371 if (IsNil()) 372 summary.assign("nil"); 373 else if (IsUninitialized()) 374 summary.assign("<uninitialized>"); 375 else if (m_options.m_omit_summary_depth == 0) { 376 TypeSummaryImpl *entry = GetSummaryFormatter(); 377 if (entry) 378 m_valobj->GetSummaryAsCString(entry, summary, 379 m_options.m_varformat_language); 380 else { 381 const char *sum_cstr = 382 m_valobj->GetSummaryAsCString(m_options.m_varformat_language); 383 if (sum_cstr) 384 summary.assign(sum_cstr); 385 } 386 } 387 } 388 } 389 390 bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed, 391 bool &summary_printed) { 392 bool error_printed = false; 393 if (ShouldPrintValueObject()) { 394 if (!CheckScopeIfNeeded()) 395 m_error.assign("out of scope"); 396 if (m_error.empty()) { 397 GetValueSummaryError(m_value, m_summary, m_error); 398 } 399 if (m_error.size()) { 400 // we need to support scenarios in which it is actually fine for a value 401 // to have no type but - on the other hand - if we get an error *AND* 402 // have no type, we try to get out gracefully, since most often that 403 // combination means "could not resolve a type" and the default failure 404 // mode is quite ugly 405 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 440 bool 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 == false && summary_printed == false) 462 return true; 463 else 464 return false; 465 } 466 } 467 return true; 468 } 469 470 bool 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 481 bool 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 534 bool ValueObjectPrinter::ShouldExpandEmptyAggregates() { 535 TypeSummaryImpl *entry = GetSummaryFormatter(); 536 537 if (!entry) 538 return true; 539 540 return entry->DoesPrintEmptyAggregates(); 541 } 542 543 ValueObject *ValueObjectPrinter::GetValueObjectForChildrenGeneration() { 544 return m_valobj; 545 } 546 547 void 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 558 void 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 587 uint32_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 607 void 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 621 bool 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 == false) { 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 642 static constexpr size_t PhysicalIndexForLogicalIndex(size_t base, size_t stride, 643 size_t logical) { 644 return base + logical * stride; 645 } 646 647 ValueObjectSP 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 662 void 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 710 bool 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 752 void 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 798 bool ValueObjectPrinter::ShouldPrintValidation() { 799 return m_options.m_run_validator; 800 } 801 802 bool 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 816 bool 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