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