1 //===-- ValueObjectPrinter.cpp -----------------------------------*- C++-*-===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/DataFormatters/ValueObjectPrinter.h" 10 11 #include "lldb/Core/ValueObject.h" 12 #include "lldb/DataFormatters/DataVisualization.h" 13 #include "lldb/Interpreter/CommandInterpreter.h" 14 #include "lldb/Target/Language.h" 15 #include "lldb/Target/Target.h" 16 #include "lldb/Utility/Stream.h" 17 18 using namespace lldb; 19 using namespace lldb_private; 20 21 ValueObjectPrinter::ValueObjectPrinter(ValueObject *valobj, Stream *s) { 22 if (valobj) { 23 DumpValueObjectOptions options(*valobj); 24 Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); 25 } else { 26 DumpValueObjectOptions options; 27 Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); 28 } 29 } 30 31 ValueObjectPrinter::ValueObjectPrinter(ValueObject *valobj, Stream *s, 32 const DumpValueObjectOptions &options) { 33 Init(valobj, s, options, m_options.m_max_ptr_depth, 0, nullptr); 34 } 35 36 ValueObjectPrinter::ValueObjectPrinter( 37 ValueObject *valobj, Stream *s, const DumpValueObjectOptions &options, 38 const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth, 39 InstancePointersSetSP printed_instance_pointers) { 40 Init(valobj, s, options, ptr_depth, curr_depth, printed_instance_pointers); 41 } 42 43 void ValueObjectPrinter::Init( 44 ValueObject *valobj, Stream *s, const DumpValueObjectOptions &options, 45 const DumpValueObjectOptions::PointerDepth &ptr_depth, uint32_t curr_depth, 46 InstancePointersSetSP printed_instance_pointers) { 47 m_orig_valobj = valobj; 48 m_valobj = nullptr; 49 m_stream = s; 50 m_options = options; 51 m_ptr_depth = ptr_depth; 52 m_curr_depth = curr_depth; 53 assert(m_orig_valobj && "cannot print a NULL ValueObject"); 54 assert(m_stream && "cannot print to a NULL Stream"); 55 m_should_print = eLazyBoolCalculate; 56 m_is_nil = eLazyBoolCalculate; 57 m_is_uninit = eLazyBoolCalculate; 58 m_is_ptr = eLazyBoolCalculate; 59 m_is_ref = eLazyBoolCalculate; 60 m_is_aggregate = eLazyBoolCalculate; 61 m_is_instance_ptr = eLazyBoolCalculate; 62 m_summary_formatter = {nullptr, false}; 63 m_value.assign(""); 64 m_summary.assign(""); 65 m_error.assign(""); 66 m_val_summary_ok = false; 67 m_printed_instance_pointers = 68 printed_instance_pointers 69 ? printed_instance_pointers 70 : InstancePointersSetSP(new InstancePointersSet()); 71 } 72 73 bool ValueObjectPrinter::PrintValueObject() { 74 if (!GetMostSpecializedValue() || m_valobj == nullptr) 75 return false; 76 77 if (ShouldPrintValueObject()) { 78 PrintValidationMarkerIfNeeded(); 79 80 PrintLocationIfNeeded(); 81 m_stream->Indent(); 82 83 PrintDecl(); 84 } 85 86 bool value_printed = false; 87 bool summary_printed = false; 88 89 m_val_summary_ok = 90 PrintValueAndSummaryIfNeeded(value_printed, summary_printed); 91 92 if (m_val_summary_ok) 93 PrintChildrenIfNeeded(value_printed, summary_printed); 94 else 95 m_stream->EOL(); 96 97 PrintValidationErrorIfNeeded(); 98 99 return true; 100 } 101 102 bool ValueObjectPrinter::GetMostSpecializedValue() { 103 if (m_valobj) 104 return true; 105 bool update_success = m_orig_valobj->UpdateValueIfNeeded(true); 106 if (!update_success) { 107 m_valobj = m_orig_valobj; 108 } else { 109 if (m_orig_valobj->IsDynamic()) { 110 if (m_options.m_use_dynamic == eNoDynamicValues) { 111 ValueObject *static_value = m_orig_valobj->GetStaticValue().get(); 112 if (static_value) 113 m_valobj = static_value; 114 else 115 m_valobj = m_orig_valobj; 116 } else 117 m_valobj = m_orig_valobj; 118 } else { 119 if (m_options.m_use_dynamic != eNoDynamicValues) { 120 ValueObject *dynamic_value = 121 m_orig_valobj->GetDynamicValue(m_options.m_use_dynamic).get(); 122 if (dynamic_value) 123 m_valobj = dynamic_value; 124 else 125 m_valobj = m_orig_valobj; 126 } else 127 m_valobj = m_orig_valobj; 128 } 129 130 if (m_valobj->IsSynthetic()) { 131 if (!m_options.m_use_synthetic) { 132 ValueObject *non_synthetic = m_valobj->GetNonSyntheticValue().get(); 133 if (non_synthetic) 134 m_valobj = non_synthetic; 135 } 136 } else { 137 if (m_options.m_use_synthetic) { 138 ValueObject *synthetic = m_valobj->GetSyntheticValue().get(); 139 if (synthetic) 140 m_valobj = synthetic; 141 } 142 } 143 } 144 m_compiler_type = m_valobj->GetCompilerType(); 145 m_type_flags = m_compiler_type.GetTypeInfo(); 146 return true; 147 } 148 149 const char *ValueObjectPrinter::GetDescriptionForDisplay() { 150 const char *str = m_valobj->GetObjectDescription(); 151 if (!str) 152 str = m_valobj->GetSummaryAsCString(); 153 if (!str) 154 str = m_valobj->GetValueAsCString(); 155 return str; 156 } 157 158 const char *ValueObjectPrinter::GetRootNameForDisplay(const char *if_fail) { 159 const char *root_valobj_name = m_options.m_root_valobj_name.empty() 160 ? m_valobj->GetName().AsCString() 161 : m_options.m_root_valobj_name.c_str(); 162 return root_valobj_name ? root_valobj_name : if_fail; 163 } 164 165 bool ValueObjectPrinter::ShouldPrintValueObject() { 166 if (m_should_print == eLazyBoolCalculate) 167 m_should_print = 168 (!m_options.m_flat_output || m_type_flags.Test(eTypeHasValue)) 169 ? eLazyBoolYes 170 : eLazyBoolNo; 171 return m_should_print == eLazyBoolYes; 172 } 173 174 bool ValueObjectPrinter::IsNil() { 175 if (m_is_nil == eLazyBoolCalculate) 176 m_is_nil = m_valobj->IsNilReference() ? eLazyBoolYes : eLazyBoolNo; 177 return m_is_nil == eLazyBoolYes; 178 } 179 180 bool ValueObjectPrinter::IsUninitialized() { 181 if (m_is_uninit == eLazyBoolCalculate) 182 m_is_uninit = 183 m_valobj->IsUninitializedReference() ? eLazyBoolYes : eLazyBoolNo; 184 return m_is_uninit == eLazyBoolYes; 185 } 186 187 bool ValueObjectPrinter::IsPtr() { 188 if (m_is_ptr == eLazyBoolCalculate) 189 m_is_ptr = m_type_flags.Test(eTypeIsPointer) ? eLazyBoolYes : eLazyBoolNo; 190 return m_is_ptr == eLazyBoolYes; 191 } 192 193 bool ValueObjectPrinter::IsRef() { 194 if (m_is_ref == eLazyBoolCalculate) 195 m_is_ref = m_type_flags.Test(eTypeIsReference) ? eLazyBoolYes : eLazyBoolNo; 196 return m_is_ref == eLazyBoolYes; 197 } 198 199 bool ValueObjectPrinter::IsAggregate() { 200 if (m_is_aggregate == eLazyBoolCalculate) 201 m_is_aggregate = 202 m_type_flags.Test(eTypeHasChildren) ? eLazyBoolYes : eLazyBoolNo; 203 return m_is_aggregate == eLazyBoolYes; 204 } 205 206 bool ValueObjectPrinter::IsInstancePointer() { 207 // you need to do this check on the value's clang type 208 if (m_is_instance_ptr == eLazyBoolCalculate) 209 m_is_instance_ptr = (m_valobj->GetValue().GetCompilerType().GetTypeInfo() & 210 eTypeInstanceIsPointer) != 0 211 ? eLazyBoolYes 212 : eLazyBoolNo; 213 if ((eLazyBoolYes == m_is_instance_ptr) && m_valobj->IsBaseClass()) 214 m_is_instance_ptr = eLazyBoolNo; 215 return m_is_instance_ptr == eLazyBoolYes; 216 } 217 218 bool ValueObjectPrinter::PrintLocationIfNeeded() { 219 if (m_options.m_show_location) { 220 m_stream->Printf("%s: ", m_valobj->GetLocationAsCString()); 221 return true; 222 } 223 return false; 224 } 225 226 void ValueObjectPrinter::PrintDecl() { 227 bool show_type = true; 228 // if we are at the root-level and been asked to hide the root's type, then 229 // hide it 230 if (m_curr_depth == 0 && m_options.m_hide_root_type) 231 show_type = false; 232 else 233 // otherwise decide according to the usual rules (asked to show types - 234 // always at the root level) 235 show_type = m_options.m_show_types || 236 (m_curr_depth == 0 && !m_options.m_flat_output); 237 238 StreamString typeName; 239 240 // always show the type at the root level if it is invalid 241 if (show_type) { 242 // Some ValueObjects don't have types (like registers sets). Only print the 243 // type if there is one to print 244 ConstString type_name; 245 if (m_compiler_type.IsValid()) { 246 if (m_options.m_use_type_display_name) 247 type_name = m_valobj->GetDisplayTypeName(); 248 else 249 type_name = m_valobj->GetQualifiedTypeName(); 250 } else { 251 // only show an invalid type name if the user explicitly triggered 252 // show_type 253 if (m_options.m_show_types) 254 type_name = ConstString("<invalid type>"); 255 else 256 type_name.Clear(); 257 } 258 259 if (type_name) { 260 std::string type_name_str(type_name.GetCString()); 261 if (m_options.m_hide_pointer_value) { 262 for (auto iter = type_name_str.find(" *"); iter != std::string::npos; 263 iter = type_name_str.find(" *")) { 264 type_name_str.erase(iter, 2); 265 } 266 } 267 typeName.Printf("%s", type_name_str.c_str()); 268 } 269 } 270 271 StreamString varName; 272 273 if (m_options.m_flat_output) { 274 // If we are showing types, also qualify the C++ base classes 275 const bool qualify_cxx_base_classes = show_type; 276 if (!m_options.m_hide_name) { 277 m_valobj->GetExpressionPath(varName, qualify_cxx_base_classes); 278 } 279 } else if (!m_options.m_hide_name) { 280 const char *name_cstr = GetRootNameForDisplay(""); 281 varName.Printf("%s", name_cstr); 282 } 283 284 bool decl_printed = false; 285 if (!m_options.m_decl_printing_helper) { 286 // if the user didn't give us a custom helper, pick one based upon the 287 // language, either the one that this printer is bound to, or the preferred 288 // one for the ValueObject 289 lldb::LanguageType lang_type = 290 (m_options.m_varformat_language == lldb::eLanguageTypeUnknown) 291 ? m_valobj->GetPreferredDisplayLanguage() 292 : m_options.m_varformat_language; 293 if (Language *lang_plugin = Language::FindPlugin(lang_type)) { 294 m_options.m_decl_printing_helper = lang_plugin->GetDeclPrintingHelper(); 295 } 296 } 297 298 if (m_options.m_decl_printing_helper) { 299 ConstString type_name_cstr(typeName.GetString()); 300 ConstString var_name_cstr(varName.GetString()); 301 302 StreamString dest_stream; 303 if (m_options.m_decl_printing_helper(type_name_cstr, var_name_cstr, 304 m_options, dest_stream)) { 305 decl_printed = true; 306 m_stream->PutCString(dest_stream.GetString()); 307 } 308 } 309 310 // if the helper failed, or there is none, do a default thing 311 if (!decl_printed) { 312 if (!typeName.Empty()) 313 m_stream->Printf("(%s) ", typeName.GetData()); 314 if (!varName.Empty()) 315 m_stream->Printf("%s =", varName.GetData()); 316 else if (!m_options.m_hide_name) 317 m_stream->Printf(" ="); 318 } 319 } 320 321 bool ValueObjectPrinter::CheckScopeIfNeeded() { 322 if (m_options.m_scope_already_checked) 323 return true; 324 return m_valobj->IsInScope(); 325 } 326 327 TypeSummaryImpl *ValueObjectPrinter::GetSummaryFormatter(bool null_if_omitted) { 328 if (!m_summary_formatter.second) { 329 TypeSummaryImpl *entry = m_options.m_summary_sp 330 ? m_options.m_summary_sp.get() 331 : m_valobj->GetSummaryFormat().get(); 332 333 if (m_options.m_omit_summary_depth > 0) 334 entry = NULL; 335 m_summary_formatter.first = entry; 336 m_summary_formatter.second = true; 337 } 338 if (m_options.m_omit_summary_depth > 0 && null_if_omitted) 339 return nullptr; 340 return m_summary_formatter.first; 341 } 342 343 static bool IsPointerValue(const CompilerType &type) { 344 Flags type_flags(type.GetTypeInfo()); 345 if (type_flags.AnySet(eTypeInstanceIsPointer | eTypeIsPointer)) 346 return type_flags.AllClear(eTypeIsBuiltIn); 347 return false; 348 } 349 350 void ValueObjectPrinter::GetValueSummaryError(std::string &value, 351 std::string &summary, 352 std::string &error) { 353 lldb::Format format = m_options.m_format; 354 // if I am printing synthetized elements, apply the format to those elements 355 // only 356 if (m_options.m_pointer_as_array) 357 m_valobj->GetValueAsCString(lldb::eFormatDefault, value); 358 else if (format != eFormatDefault && format != m_valobj->GetFormat()) 359 m_valobj->GetValueAsCString(format, value); 360 else { 361 const char *val_cstr = m_valobj->GetValueAsCString(); 362 if (val_cstr) 363 value.assign(val_cstr); 364 } 365 const char *err_cstr = m_valobj->GetError().AsCString(); 366 if (err_cstr) 367 error.assign(err_cstr); 368 369 if (ShouldPrintValueObject()) { 370 if (IsNil()) 371 summary.assign("nil"); 372 else if (IsUninitialized()) 373 summary.assign("<uninitialized>"); 374 else if (m_options.m_omit_summary_depth == 0) { 375 TypeSummaryImpl *entry = GetSummaryFormatter(); 376 if (entry) 377 m_valobj->GetSummaryAsCString(entry, summary, 378 m_options.m_varformat_language); 379 else { 380 const char *sum_cstr = 381 m_valobj->GetSummaryAsCString(m_options.m_varformat_language); 382 if (sum_cstr) 383 summary.assign(sum_cstr); 384 } 385 } 386 } 387 } 388 389 bool ValueObjectPrinter::PrintValueAndSummaryIfNeeded(bool &value_printed, 390 bool &summary_printed) { 391 bool error_printed = false; 392 if (ShouldPrintValueObject()) { 393 if (!CheckScopeIfNeeded()) 394 m_error.assign("out of scope"); 395 if (m_error.empty()) { 396 GetValueSummaryError(m_value, m_summary, m_error); 397 } 398 if (m_error.size()) { 399 // we need to support scenarios in which it is actually fine for a value 400 // to have no type but - on the other hand - if we get an error *AND* 401 // have no type, we try to get out gracefully, since most often that 402 // combination means "could not resolve a type" and the default failure 403 // mode is quite ugly 404 if (!m_compiler_type.IsValid()) { 405 m_stream->Printf(" <could not resolve type>"); 406 return false; 407 } 408 409 error_printed = true; 410 m_stream->Printf(" <%s>\n", m_error.c_str()); 411 } else { 412 // Make sure we have a value and make sure the summary didn't specify 413 // that the value should not be printed - and do not print the value if 414 // this thing is nil (but show the value if the user passes a format 415 // explicitly) 416 TypeSummaryImpl *entry = GetSummaryFormatter(); 417 if (!IsNil() && !IsUninitialized() && !m_value.empty() && 418 (entry == NULL || (entry->DoesPrintValue(m_valobj) || 419 m_options.m_format != eFormatDefault) || 420 m_summary.empty()) && 421 !m_options.m_hide_value) { 422 if (m_options.m_hide_pointer_value && 423 IsPointerValue(m_valobj->GetCompilerType())) { 424 } else { 425 m_stream->Printf(" %s", m_value.c_str()); 426 value_printed = true; 427 } 428 } 429 430 if (m_summary.size()) { 431 m_stream->Printf(" %s", m_summary.c_str()); 432 summary_printed = true; 433 } 434 } 435 } 436 return !error_printed; 437 } 438 439 bool ValueObjectPrinter::PrintObjectDescriptionIfNeeded(bool value_printed, 440 bool summary_printed) { 441 if (ShouldPrintValueObject()) { 442 // let's avoid the overly verbose no description error for a nil thing 443 if (m_options.m_use_objc && !IsNil() && !IsUninitialized() && 444 (!m_options.m_pointer_as_array)) { 445 if (!m_options.m_hide_value || !m_options.m_hide_name) 446 m_stream->Printf(" "); 447 const char *object_desc = nullptr; 448 if (value_printed || summary_printed) 449 object_desc = m_valobj->GetObjectDescription(); 450 else 451 object_desc = GetDescriptionForDisplay(); 452 if (object_desc && *object_desc) { 453 // If the description already ends with a \n don't add another one. 454 size_t object_end = strlen(object_desc) - 1; 455 if (object_desc[object_end] == '\n') 456 m_stream->Printf("%s", object_desc); 457 else 458 m_stream->Printf("%s\n", object_desc); 459 return true; 460 } else if (!value_printed && !summary_printed) 461 return true; 462 else 463 return false; 464 } 465 } 466 return true; 467 } 468 469 bool DumpValueObjectOptions::PointerDepth::CanAllowExpansion() const { 470 switch (m_mode) { 471 case Mode::Always: 472 case Mode::Default: 473 return m_count > 0; 474 case Mode::Never: 475 return false; 476 } 477 return false; 478 } 479 480 bool ValueObjectPrinter::ShouldPrintChildren( 481 bool is_failed_description, 482 DumpValueObjectOptions::PointerDepth &curr_ptr_depth) { 483 const bool is_ref = IsRef(); 484 const bool is_ptr = IsPtr(); 485 const bool is_uninit = IsUninitialized(); 486 487 if (is_uninit) 488 return false; 489 490 // if the user has specified an element count, always print children as it is 491 // explicit user demand being honored 492 if (m_options.m_pointer_as_array) 493 return true; 494 495 TypeSummaryImpl *entry = GetSummaryFormatter(); 496 497 if (m_options.m_use_objc) 498 return false; 499 500 if (is_failed_description || m_curr_depth < m_options.m_max_depth) { 501 // We will show children for all concrete types. We won't show pointer 502 // contents unless a pointer depth has been specified. We won't reference 503 // contents unless the reference is the root object (depth of zero). 504 505 // Use a new temporary pointer depth in case we override the current 506 // pointer depth below... 507 508 if (is_ptr || is_ref) { 509 // We have a pointer or reference whose value is an address. Make sure 510 // that address is not NULL 511 AddressType ptr_address_type; 512 if (m_valobj->GetPointerValue(&ptr_address_type) == 0) 513 return false; 514 515 const bool is_root_level = m_curr_depth == 0; 516 517 if (is_ref && is_root_level) { 518 // If this is the root object (depth is zero) that we are showing and 519 // it is a reference, and no pointer depth has been supplied print out 520 // what it references. Don't do this at deeper depths otherwise we can 521 // end up with infinite recursion... 522 return true; 523 } 524 525 return curr_ptr_depth.CanAllowExpansion(); 526 } 527 528 return (!entry || entry->DoesPrintChildren(m_valobj) || m_summary.empty()); 529 } 530 return false; 531 } 532 533 bool ValueObjectPrinter::ShouldExpandEmptyAggregates() { 534 TypeSummaryImpl *entry = GetSummaryFormatter(); 535 536 if (!entry) 537 return true; 538 539 return entry->DoesPrintEmptyAggregates(); 540 } 541 542 ValueObject *ValueObjectPrinter::GetValueObjectForChildrenGeneration() { 543 return m_valobj; 544 } 545 546 void ValueObjectPrinter::PrintChildrenPreamble() { 547 if (m_options.m_flat_output) { 548 if (ShouldPrintValueObject()) 549 m_stream->EOL(); 550 } else { 551 if (ShouldPrintValueObject()) 552 m_stream->PutCString(IsRef() ? ": {\n" : " {\n"); 553 m_stream->IndentMore(); 554 } 555 } 556 557 void ValueObjectPrinter::PrintChild( 558 ValueObjectSP child_sp, 559 const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) { 560 const uint32_t consumed_depth = (!m_options.m_pointer_as_array) ? 1 : 0; 561 const bool does_consume_ptr_depth = 562 ((IsPtr() && !m_options.m_pointer_as_array) || IsRef()); 563 564 DumpValueObjectOptions child_options(m_options); 565 child_options.SetFormat(m_options.m_format) 566 .SetSummary() 567 .SetRootValueObjectName(); 568 child_options.SetScopeChecked(true) 569 .SetHideName(m_options.m_hide_name) 570 .SetHideValue(m_options.m_hide_value) 571 .SetOmitSummaryDepth(child_options.m_omit_summary_depth > 1 572 ? child_options.m_omit_summary_depth - 573 consumed_depth 574 : 0) 575 .SetElementCount(0); 576 577 if (child_sp.get()) { 578 ValueObjectPrinter child_printer( 579 child_sp.get(), m_stream, child_options, 580 does_consume_ptr_depth ? --curr_ptr_depth : curr_ptr_depth, 581 m_curr_depth + consumed_depth, m_printed_instance_pointers); 582 child_printer.PrintValueObject(); 583 } 584 } 585 586 uint32_t ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot) { 587 ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); 588 589 if (m_options.m_pointer_as_array) 590 return m_options.m_pointer_as_array.m_element_count; 591 592 size_t num_children = synth_m_valobj->GetNumChildren(); 593 print_dotdotdot = false; 594 if (num_children) { 595 const size_t max_num_children = 596 m_valobj->GetTargetSP()->GetMaximumNumberOfChildrenToDisplay(); 597 598 if (num_children > max_num_children && !m_options.m_ignore_cap) { 599 print_dotdotdot = true; 600 return max_num_children; 601 } 602 } 603 return num_children; 604 } 605 606 void ValueObjectPrinter::PrintChildrenPostamble(bool print_dotdotdot) { 607 if (!m_options.m_flat_output) { 608 if (print_dotdotdot) { 609 m_valobj->GetTargetSP() 610 ->GetDebugger() 611 .GetCommandInterpreter() 612 .ChildrenTruncated(); 613 m_stream->Indent("...\n"); 614 } 615 m_stream->IndentLess(); 616 m_stream->Indent("}\n"); 617 } 618 } 619 620 bool ValueObjectPrinter::ShouldPrintEmptyBrackets(bool value_printed, 621 bool summary_printed) { 622 ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); 623 624 if (!IsAggregate()) 625 return false; 626 627 if (!m_options.m_reveal_empty_aggregates) { 628 if (value_printed || summary_printed) 629 return false; 630 } 631 632 if (synth_m_valobj->MightHaveChildren()) 633 return true; 634 635 if (m_val_summary_ok) 636 return false; 637 638 return true; 639 } 640 641 static constexpr size_t PhysicalIndexForLogicalIndex(size_t base, size_t stride, 642 size_t logical) { 643 return base + logical * stride; 644 } 645 646 ValueObjectSP ValueObjectPrinter::GenerateChild(ValueObject *synth_valobj, 647 size_t idx) { 648 if (m_options.m_pointer_as_array) { 649 // if generating pointer-as-array children, use GetSyntheticArrayMember 650 return synth_valobj->GetSyntheticArrayMember( 651 PhysicalIndexForLogicalIndex( 652 m_options.m_pointer_as_array.m_base_element, 653 m_options.m_pointer_as_array.m_stride, idx), 654 true); 655 } else { 656 // otherwise, do the usual thing 657 return synth_valobj->GetChildAtIndex(idx, true); 658 } 659 } 660 661 void ValueObjectPrinter::PrintChildren( 662 bool value_printed, bool summary_printed, 663 const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) { 664 ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); 665 666 bool print_dotdotdot = false; 667 size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot); 668 if (num_children) { 669 bool any_children_printed = false; 670 671 for (size_t idx = 0; idx < num_children; ++idx) { 672 if (ValueObjectSP child_sp = GenerateChild(synth_m_valobj, idx)) { 673 if (!any_children_printed) { 674 PrintChildrenPreamble(); 675 any_children_printed = true; 676 } 677 PrintChild(child_sp, curr_ptr_depth); 678 } 679 } 680 681 if (any_children_printed) 682 PrintChildrenPostamble(print_dotdotdot); 683 else { 684 if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) { 685 if (ShouldPrintValueObject()) 686 m_stream->PutCString(" {}\n"); 687 else 688 m_stream->EOL(); 689 } else 690 m_stream->EOL(); 691 } 692 } else if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) { 693 // Aggregate, no children... 694 if (ShouldPrintValueObject()) { 695 // if it has a synthetic value, then don't print {}, the synthetic 696 // children are probably only being used to vend a value 697 if (m_valobj->DoesProvideSyntheticValue() || 698 !ShouldExpandEmptyAggregates()) 699 m_stream->PutCString("\n"); 700 else 701 m_stream->PutCString(" {}\n"); 702 } 703 } else { 704 if (ShouldPrintValueObject()) 705 m_stream->EOL(); 706 } 707 } 708 709 bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) { 710 if (!GetMostSpecializedValue() || m_valobj == nullptr) 711 return false; 712 713 ValueObject *synth_m_valobj = GetValueObjectForChildrenGeneration(); 714 715 bool print_dotdotdot = false; 716 size_t num_children = GetMaxNumChildrenToPrint(print_dotdotdot); 717 718 if (num_children) { 719 m_stream->PutChar('('); 720 721 for (uint32_t idx = 0; idx < num_children; ++idx) { 722 lldb::ValueObjectSP child_sp(synth_m_valobj->GetChildAtIndex(idx, true)); 723 if (child_sp) 724 child_sp = child_sp->GetQualifiedRepresentationIfAvailable( 725 m_options.m_use_dynamic, m_options.m_use_synthetic); 726 if (child_sp) { 727 if (idx) 728 m_stream->PutCString(", "); 729 if (!hide_names) { 730 const char *name = child_sp.get()->GetName().AsCString(); 731 if (name && *name) { 732 m_stream->PutCString(name); 733 m_stream->PutCString(" = "); 734 } 735 } 736 child_sp->DumpPrintableRepresentation( 737 *m_stream, ValueObject::eValueObjectRepresentationStyleSummary, 738 m_options.m_format, 739 ValueObject::PrintableRepresentationSpecialCases::eDisable); 740 } 741 } 742 743 if (print_dotdotdot) 744 m_stream->PutCString(", ...)"); 745 else 746 m_stream->PutChar(')'); 747 } 748 return true; 749 } 750 751 void ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed, 752 bool summary_printed) { 753 // this flag controls whether we tried to display a description for this 754 // object and failed if that happens, we want to display the children, if any 755 bool is_failed_description = 756 !PrintObjectDescriptionIfNeeded(value_printed, summary_printed); 757 758 auto curr_ptr_depth = m_ptr_depth; 759 bool print_children = 760 ShouldPrintChildren(is_failed_description, curr_ptr_depth); 761 bool print_oneline = 762 (curr_ptr_depth.CanAllowExpansion() || m_options.m_show_types || 763 !m_options.m_allow_oneliner_mode || m_options.m_flat_output || 764 (m_options.m_pointer_as_array) || m_options.m_show_location) 765 ? false 766 : DataVisualization::ShouldPrintAsOneLiner(*m_valobj); 767 bool is_instance_ptr = IsInstancePointer(); 768 uint64_t instance_ptr_value = LLDB_INVALID_ADDRESS; 769 770 if (print_children && is_instance_ptr) { 771 instance_ptr_value = m_valobj->GetValueAsUnsigned(0); 772 if (m_printed_instance_pointers->count(instance_ptr_value)) { 773 // we already printed this instance-is-pointer thing, so don't expand it 774 m_stream->PutCString(" {...}\n"); 775 776 // we're done here - get out fast 777 return; 778 } else 779 m_printed_instance_pointers->emplace( 780 instance_ptr_value); // remember this guy for future reference 781 } 782 783 if (print_children) { 784 if (print_oneline) { 785 m_stream->PutChar(' '); 786 PrintChildrenOneLiner(false); 787 m_stream->EOL(); 788 } else 789 PrintChildren(value_printed, summary_printed, curr_ptr_depth); 790 } else if (m_curr_depth >= m_options.m_max_depth && IsAggregate() && 791 ShouldPrintValueObject()) { 792 m_stream->PutCString("{...}\n"); 793 } else 794 m_stream->EOL(); 795 } 796 797 bool ValueObjectPrinter::ShouldPrintValidation() { 798 return m_options.m_run_validator; 799 } 800 801 bool ValueObjectPrinter::PrintValidationMarkerIfNeeded() { 802 if (!ShouldPrintValidation()) 803 return false; 804 805 m_validation = m_valobj->GetValidationStatus(); 806 807 if (TypeValidatorResult::Failure == m_validation.first) { 808 m_stream->Printf("! "); 809 return true; 810 } 811 812 return false; 813 } 814 815 bool ValueObjectPrinter::PrintValidationErrorIfNeeded() { 816 if (!ShouldPrintValidation()) 817 return false; 818 819 if (TypeValidatorResult::Success == m_validation.first) 820 return false; 821 822 if (m_validation.second.empty()) 823 m_validation.second.assign("unknown error"); 824 825 m_stream->Printf(" ! validation error: %s", m_validation.second.c_str()); 826 m_stream->EOL(); 827 828 return true; 829 } 830