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/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 #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 switch (m_mode) { 507 case Mode::Always: 508 case Mode::Default: 509 return m_count > 0; 510 case Mode::Never: 511 return false; 512 } 513 return false; 514 } 515 516 bool ValueObjectPrinter::ShouldPrintChildren( 517 DumpValueObjectOptions::PointerDepth &curr_ptr_depth) { 518 const bool is_ref = IsRef(); 519 const bool is_ptr = IsPtr(); 520 const bool is_uninit = IsUninitialized(); 521 522 if (is_uninit) 523 return false; 524 525 // If we have reached the maximum depth we shouldn't print any more children. 526 if (HasReachedMaximumDepth()) 527 return false; 528 529 // if the user has specified an element count, always print children as it is 530 // explicit user demand being honored 531 if (m_options.m_pointer_as_array) 532 return true; 533 534 if (m_options.m_use_objc) 535 return false; 536 537 bool print_children = true; 538 ValueObject &valobj = GetMostSpecializedValue(); 539 if (TypeSummaryImpl *type_summary = GetSummaryFormatter()) 540 print_children = type_summary->DoesPrintChildren(&valobj); 541 542 // We will show children for all concrete types. We won't show pointer 543 // contents unless a pointer depth has been specified. We won't reference 544 // contents unless the reference is the root object (depth of zero). 545 546 // Use a new temporary pointer depth in case we override the current 547 // pointer depth below... 548 549 if (is_ptr || is_ref) { 550 // We have a pointer or reference whose value is an address. Make sure 551 // that address is not NULL 552 AddressType ptr_address_type; 553 if (valobj.GetPointerValue(&ptr_address_type) == 0) 554 return false; 555 556 const bool is_root_level = m_curr_depth == 0; 557 558 if (is_ref && is_root_level && print_children) { 559 // If this is the root object (depth is zero) that we are showing and 560 // it is a reference, and no pointer depth has been supplied print out 561 // what it references. Don't do this at deeper depths otherwise we can 562 // end up with infinite recursion... 563 return true; 564 } 565 566 return curr_ptr_depth.CanAllowExpansion(); 567 } 568 569 return print_children || m_summary.empty(); 570 } 571 572 bool ValueObjectPrinter::ShouldExpandEmptyAggregates() { 573 TypeSummaryImpl *entry = GetSummaryFormatter(); 574 575 if (!entry) 576 return true; 577 578 return entry->DoesPrintEmptyAggregates(); 579 } 580 581 ValueObject &ValueObjectPrinter::GetValueObjectForChildrenGeneration() { 582 return GetMostSpecializedValue(); 583 } 584 585 void ValueObjectPrinter::PrintChildrenPreamble(bool value_printed, 586 bool summary_printed) { 587 if (m_options.m_flat_output) { 588 if (ShouldPrintValueObject()) 589 m_stream->EOL(); 590 } else { 591 if (ShouldPrintValueObject()) { 592 if (IsRef()) { 593 m_stream->PutCString(": "); 594 } else if (value_printed || summary_printed || ShouldShowName()) { 595 m_stream->PutChar(' '); 596 } 597 m_stream->PutCString("{\n"); 598 } 599 m_stream->IndentMore(); 600 } 601 } 602 603 void ValueObjectPrinter::PrintChild( 604 ValueObjectSP child_sp, 605 const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) { 606 const uint32_t consumed_summary_depth = m_options.m_pointer_as_array ? 0 : 1; 607 const bool does_consume_ptr_depth = 608 ((IsPtr() && !m_options.m_pointer_as_array) || IsRef()); 609 610 DumpValueObjectOptions child_options(m_options); 611 child_options.SetFormat(m_options.m_format) 612 .SetSummary() 613 .SetRootValueObjectName(); 614 child_options.SetScopeChecked(true) 615 .SetHideName(m_options.m_hide_name) 616 .SetHideValue(m_options.m_hide_value) 617 .SetOmitSummaryDepth(child_options.m_omit_summary_depth > 1 618 ? child_options.m_omit_summary_depth - 619 consumed_summary_depth 620 : 0) 621 .SetElementCount(0); 622 623 if (child_sp.get()) { 624 auto ptr_depth = curr_ptr_depth; 625 if (does_consume_ptr_depth) 626 ptr_depth = curr_ptr_depth.Decremented(); 627 628 ValueObjectPrinter child_printer(*(child_sp.get()), m_stream, child_options, 629 ptr_depth, m_curr_depth + 1, 630 m_printed_instance_pointers); 631 llvm::Error error = child_printer.PrintValueObject(); 632 if (error) { 633 if (m_stream) 634 *m_stream << "error: " << toString(std::move(error)); 635 else 636 llvm::consumeError(std::move(error)); 637 } 638 } 639 } 640 641 llvm::Expected<uint32_t> 642 ValueObjectPrinter::GetMaxNumChildrenToPrint(bool &print_dotdotdot) { 643 ValueObject &synth_valobj = GetValueObjectForChildrenGeneration(); 644 645 if (m_options.m_pointer_as_array) 646 return m_options.m_pointer_as_array.m_element_count; 647 648 const uint32_t max_num_children = 649 m_options.m_ignore_cap ? UINT32_MAX 650 : GetMostSpecializedValue() 651 .GetTargetSP() 652 ->GetMaximumNumberOfChildrenToDisplay(); 653 // Ask for one more child than the maximum to see if we should print "...". 654 auto num_children_or_err = synth_valobj.GetNumChildren( 655 llvm::SaturatingAdd(max_num_children, uint32_t(1))); 656 if (!num_children_or_err) 657 return num_children_or_err; 658 if (*num_children_or_err > max_num_children) { 659 print_dotdotdot = true; 660 return max_num_children; 661 } 662 return num_children_or_err; 663 } 664 665 void ValueObjectPrinter::PrintChildrenPostamble(bool print_dotdotdot) { 666 if (!m_options.m_flat_output) { 667 if (print_dotdotdot) { 668 GetMostSpecializedValue() 669 .GetTargetSP() 670 ->GetDebugger() 671 .GetCommandInterpreter() 672 .ChildrenTruncated(); 673 m_stream->Indent("...\n"); 674 } 675 m_stream->IndentLess(); 676 m_stream->Indent("}\n"); 677 } 678 } 679 680 bool ValueObjectPrinter::ShouldPrintEmptyBrackets(bool value_printed, 681 bool summary_printed) { 682 ValueObject &synth_valobj = GetValueObjectForChildrenGeneration(); 683 684 if (!IsAggregate()) 685 return false; 686 687 if (!m_options.m_reveal_empty_aggregates) { 688 if (value_printed || summary_printed) 689 return false; 690 } 691 692 if (synth_valobj.MightHaveChildren()) 693 return true; 694 695 if (m_val_summary_ok) 696 return false; 697 698 return true; 699 } 700 701 static constexpr size_t PhysicalIndexForLogicalIndex(size_t base, size_t stride, 702 size_t logical) { 703 return base + logical * stride; 704 } 705 706 ValueObjectSP ValueObjectPrinter::GenerateChild(ValueObject &synth_valobj, 707 size_t idx) { 708 if (m_options.m_pointer_as_array) { 709 // if generating pointer-as-array children, use GetSyntheticArrayMember 710 return synth_valobj.GetSyntheticArrayMember( 711 PhysicalIndexForLogicalIndex( 712 m_options.m_pointer_as_array.m_base_element, 713 m_options.m_pointer_as_array.m_stride, idx), 714 true); 715 } else { 716 // otherwise, do the usual thing 717 return synth_valobj.GetChildAtIndex(idx); 718 } 719 } 720 721 void ValueObjectPrinter::PrintChildren( 722 bool value_printed, bool summary_printed, 723 const DumpValueObjectOptions::PointerDepth &curr_ptr_depth) { 724 ValueObject &synth_valobj = GetValueObjectForChildrenGeneration(); 725 726 bool print_dotdotdot = false; 727 auto num_children_or_err = GetMaxNumChildrenToPrint(print_dotdotdot); 728 if (!num_children_or_err) { 729 *m_stream << " <" << llvm::toString(num_children_or_err.takeError()) << '>'; 730 return; 731 } 732 uint32_t num_children = *num_children_or_err; 733 if (num_children) { 734 bool any_children_printed = false; 735 736 for (size_t idx = 0; idx < num_children; ++idx) { 737 if (ValueObjectSP child_sp = GenerateChild(synth_valobj, idx)) { 738 if (m_options.m_child_printing_decider && 739 !m_options.m_child_printing_decider(child_sp->GetName())) 740 continue; 741 if (!any_children_printed) { 742 PrintChildrenPreamble(value_printed, summary_printed); 743 any_children_printed = true; 744 } 745 PrintChild(child_sp, curr_ptr_depth); 746 } 747 } 748 749 if (any_children_printed) 750 PrintChildrenPostamble(print_dotdotdot); 751 else { 752 if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) { 753 if (ShouldPrintValueObject()) 754 m_stream->PutCString(" {}\n"); 755 else 756 m_stream->EOL(); 757 } else 758 m_stream->EOL(); 759 } 760 } else if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) { 761 // Aggregate, no children... 762 if (ShouldPrintValueObject()) { 763 // if it has a synthetic value, then don't print {}, the synthetic 764 // children are probably only being used to vend a value 765 if (GetMostSpecializedValue().DoesProvideSyntheticValue() || 766 !ShouldExpandEmptyAggregates()) 767 m_stream->PutCString("\n"); 768 else 769 m_stream->PutCString(" {}\n"); 770 } 771 } else { 772 if (ShouldPrintValueObject()) 773 m_stream->EOL(); 774 } 775 } 776 777 bool ValueObjectPrinter::PrintChildrenOneLiner(bool hide_names) { 778 ValueObject &synth_valobj = GetValueObjectForChildrenGeneration(); 779 780 bool print_dotdotdot = false; 781 auto num_children_or_err = GetMaxNumChildrenToPrint(print_dotdotdot); 782 if (!num_children_or_err) { 783 *m_stream << '<' << llvm::toString(num_children_or_err.takeError()) << '>'; 784 return true; 785 } 786 uint32_t num_children = *num_children_or_err; 787 788 if (num_children) { 789 m_stream->PutChar('('); 790 791 bool did_print_children = false; 792 for (uint32_t idx = 0; idx < num_children; ++idx) { 793 lldb::ValueObjectSP child_sp(synth_valobj.GetChildAtIndex(idx)); 794 if (child_sp) 795 child_sp = child_sp->GetQualifiedRepresentationIfAvailable( 796 m_options.m_use_dynamic, m_options.m_use_synthetic); 797 if (child_sp) { 798 if (m_options.m_child_printing_decider && 799 !m_options.m_child_printing_decider(child_sp->GetName())) 800 continue; 801 if (idx && did_print_children) 802 m_stream->PutCString(", "); 803 did_print_children = true; 804 if (!hide_names) { 805 const char *name = child_sp.get()->GetName().AsCString(); 806 if (name && *name) { 807 m_stream->PutCString(name); 808 m_stream->PutCString(" = "); 809 } 810 } 811 child_sp->DumpPrintableRepresentation( 812 *m_stream, ValueObject::eValueObjectRepresentationStyleSummary, 813 m_options.m_format, 814 ValueObject::PrintableRepresentationSpecialCases::eDisable); 815 } 816 } 817 818 if (print_dotdotdot) 819 m_stream->PutCString(", ...)"); 820 else 821 m_stream->PutChar(')'); 822 } 823 return true; 824 } 825 826 llvm::Error ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed, 827 bool summary_printed) { 828 auto error = PrintObjectDescriptionIfNeeded(value_printed, summary_printed); 829 if (error) 830 return error; 831 832 ValueObject &valobj = GetMostSpecializedValue(); 833 834 DumpValueObjectOptions::PointerDepth curr_ptr_depth = m_ptr_depth; 835 const bool print_children = ShouldPrintChildren(curr_ptr_depth); 836 const bool print_oneline = 837 (curr_ptr_depth.CanAllowExpansion() || m_options.m_show_types || 838 !m_options.m_allow_oneliner_mode || m_options.m_flat_output || 839 (m_options.m_pointer_as_array) || m_options.m_show_location) 840 ? false 841 : DataVisualization::ShouldPrintAsOneLiner(valobj); 842 if (print_children && IsInstancePointer()) { 843 uint64_t instance_ptr_value = valobj.GetValueAsUnsigned(0); 844 if (m_printed_instance_pointers->count(instance_ptr_value)) { 845 // We already printed this instance-is-pointer thing, so don't expand it. 846 m_stream->PutCString(" {...}\n"); 847 return llvm::Error::success(); 848 } else { 849 // Remember this guy for future reference. 850 m_printed_instance_pointers->emplace(instance_ptr_value); 851 } 852 } 853 854 if (print_children) { 855 if (print_oneline) { 856 m_stream->PutChar(' '); 857 PrintChildrenOneLiner(false); 858 m_stream->EOL(); 859 } else 860 PrintChildren(value_printed, summary_printed, curr_ptr_depth); 861 } else if (HasReachedMaximumDepth() && IsAggregate() && 862 ShouldPrintValueObject()) { 863 m_stream->PutCString("{...}\n"); 864 // The maximum child depth has been reached. If `m_max_depth` is the default 865 // (i.e. the user has _not_ customized it), then lldb presents a warning to 866 // the user. The warning tells the user that the limit has been reached, but 867 // more importantly tells them how to expand the limit if desired. 868 if (m_options.m_max_depth_is_default) 869 valobj.GetTargetSP() 870 ->GetDebugger() 871 .GetCommandInterpreter() 872 .SetReachedMaximumDepth(); 873 } else 874 m_stream->EOL(); 875 return llvm::Error::success(); 876 } 877 878 bool ValueObjectPrinter::HasReachedMaximumDepth() { 879 return m_curr_depth >= m_options.m_max_depth; 880 } 881 882 bool ValueObjectPrinter::ShouldShowName() const { 883 if (m_curr_depth == 0) 884 return !m_options.m_hide_root_name && !m_options.m_hide_name; 885 return !m_options.m_hide_name; 886 } 887