1 //===-- FormatManager.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/FormatManager.h" 11 12 #include "llvm/ADT/STLExtras.h" 13 14 // C Includes 15 // C++ Includes 16 // Other libraries and framework includes 17 // Project includes 18 19 #include "lldb/Core/Debugger.h" 20 #include "lldb/Core/Log.h" 21 #include "lldb/DataFormatters/FormattersHelpers.h" 22 #include "lldb/DataFormatters/LanguageCategory.h" 23 #include "lldb/Target/ExecutionContext.h" 24 #include "lldb/Target/Language.h" 25 26 using namespace lldb; 27 using namespace lldb_private; 28 using namespace lldb_private::formatters; 29 30 struct FormatInfo 31 { 32 Format format; 33 const char format_char; // One or more format characters that can be used for this format. 34 const char *format_name; // Long format name that can be used to specify the current format 35 }; 36 37 static FormatInfo 38 g_format_infos[] = 39 { 40 { eFormatDefault , '\0' , "default" }, 41 { eFormatBoolean , 'B' , "boolean" }, 42 { eFormatBinary , 'b' , "binary" }, 43 { eFormatBytes , 'y' , "bytes" }, 44 { eFormatBytesWithASCII , 'Y' , "bytes with ASCII" }, 45 { eFormatChar , 'c' , "character" }, 46 { eFormatCharPrintable , 'C' , "printable character" }, 47 { eFormatComplexFloat , 'F' , "complex float" }, 48 { eFormatCString , 's' , "c-string" }, 49 { eFormatDecimal , 'd' , "decimal" }, 50 { eFormatEnum , 'E' , "enumeration" }, 51 { eFormatHex , 'x' , "hex" }, 52 { eFormatHexUppercase , 'X' , "uppercase hex" }, 53 { eFormatFloat , 'f' , "float" }, 54 { eFormatOctal , 'o' , "octal" }, 55 { eFormatOSType , 'O' , "OSType" }, 56 { eFormatUnicode16 , 'U' , "unicode16" }, 57 { eFormatUnicode32 , '\0' , "unicode32" }, 58 { eFormatUnsigned , 'u' , "unsigned decimal" }, 59 { eFormatPointer , 'p' , "pointer" }, 60 { eFormatVectorOfChar , '\0' , "char[]" }, 61 { eFormatVectorOfSInt8 , '\0' , "int8_t[]" }, 62 { eFormatVectorOfUInt8 , '\0' , "uint8_t[]" }, 63 { eFormatVectorOfSInt16 , '\0' , "int16_t[]" }, 64 { eFormatVectorOfUInt16 , '\0' , "uint16_t[]" }, 65 { eFormatVectorOfSInt32 , '\0' , "int32_t[]" }, 66 { eFormatVectorOfUInt32 , '\0' , "uint32_t[]" }, 67 { eFormatVectorOfSInt64 , '\0' , "int64_t[]" }, 68 { eFormatVectorOfUInt64 , '\0' , "uint64_t[]" }, 69 { eFormatVectorOfFloat16, '\0' , "float16[]" }, 70 { eFormatVectorOfFloat32, '\0' , "float32[]" }, 71 { eFormatVectorOfFloat64, '\0' , "float64[]" }, 72 { eFormatVectorOfUInt128, '\0' , "uint128_t[]" }, 73 { eFormatComplexInteger , 'I' , "complex integer" }, 74 { eFormatCharArray , 'a' , "character array" }, 75 { eFormatAddressInfo , 'A' , "address" }, 76 { eFormatHexFloat , '\0' , "hex float" }, 77 { eFormatInstruction , 'i' , "instruction" }, 78 { eFormatVoid , 'v' , "void" } 79 }; 80 81 static uint32_t g_num_format_infos = llvm::array_lengthof(g_format_infos); 82 83 static bool 84 GetFormatFromFormatChar (char format_char, Format &format) 85 { 86 for (uint32_t i=0; i<g_num_format_infos; ++i) 87 { 88 if (g_format_infos[i].format_char == format_char) 89 { 90 format = g_format_infos[i].format; 91 return true; 92 } 93 } 94 format = eFormatInvalid; 95 return false; 96 } 97 98 static bool 99 GetFormatFromFormatName (const char *format_name, bool partial_match_ok, Format &format) 100 { 101 uint32_t i; 102 for (i=0; i<g_num_format_infos; ++i) 103 { 104 if (strcasecmp (g_format_infos[i].format_name, format_name) == 0) 105 { 106 format = g_format_infos[i].format; 107 return true; 108 } 109 } 110 111 if (partial_match_ok) 112 { 113 for (i=0; i<g_num_format_infos; ++i) 114 { 115 if (strcasestr (g_format_infos[i].format_name, format_name) == g_format_infos[i].format_name) 116 { 117 format = g_format_infos[i].format; 118 return true; 119 } 120 } 121 } 122 format = eFormatInvalid; 123 return false; 124 } 125 126 void 127 FormatManager::Changed () 128 { 129 ++m_last_revision; 130 m_format_cache.Clear (); 131 Mutex::Locker lang_locker(m_language_categories_mutex); 132 for (auto& iter : m_language_categories_map) 133 { 134 if (iter.second) 135 iter.second->GetFormatCache().Clear(); 136 } 137 } 138 139 bool 140 FormatManager::GetFormatFromCString (const char *format_cstr, 141 bool partial_match_ok, 142 lldb::Format &format) 143 { 144 bool success = false; 145 if (format_cstr && format_cstr[0]) 146 { 147 if (format_cstr[1] == '\0') 148 { 149 success = GetFormatFromFormatChar (format_cstr[0], format); 150 if (success) 151 return true; 152 } 153 154 success = GetFormatFromFormatName (format_cstr, partial_match_ok, format); 155 } 156 if (!success) 157 format = eFormatInvalid; 158 return success; 159 } 160 161 char 162 FormatManager::GetFormatAsFormatChar (lldb::Format format) 163 { 164 for (uint32_t i=0; i<g_num_format_infos; ++i) 165 { 166 if (g_format_infos[i].format == format) 167 return g_format_infos[i].format_char; 168 } 169 return '\0'; 170 } 171 172 const char * 173 FormatManager::GetFormatAsCString (Format format) 174 { 175 if (format >= eFormatDefault && format < kNumFormats) 176 return g_format_infos[format].format_name; 177 return NULL; 178 } 179 180 void 181 FormatManager::EnableAllCategories () 182 { 183 m_categories_map.EnableAllCategories (); 184 Mutex::Locker lang_locker(m_language_categories_mutex); 185 for (auto& iter : m_language_categories_map) 186 { 187 if (iter.second) 188 iter.second->Enable(); 189 } 190 } 191 192 void 193 FormatManager::DisableAllCategories () 194 { 195 m_categories_map.DisableAllCategories (); 196 Mutex::Locker lang_locker(m_language_categories_mutex); 197 for (auto& iter : m_language_categories_map) 198 { 199 if (iter.second) 200 iter.second->Disable(); 201 } 202 } 203 204 void 205 FormatManager::GetPossibleMatches (ValueObject& valobj, 206 CompilerType compiler_type, 207 uint32_t reason, 208 lldb::DynamicValueType use_dynamic, 209 FormattersMatchVector& entries, 210 bool did_strip_ptr, 211 bool did_strip_ref, 212 bool did_strip_typedef, 213 bool root_level) 214 { 215 compiler_type = compiler_type.GetTypeForFormatters(); 216 ConstString type_name(compiler_type.GetConstTypeName()); 217 if (valobj.GetBitfieldBitSize() > 0) 218 { 219 StreamString sstring; 220 sstring.Printf("%s:%d",type_name.AsCString(),valobj.GetBitfieldBitSize()); 221 ConstString bitfieldname = ConstString(sstring.GetData()); 222 entries.push_back({bitfieldname,0,did_strip_ptr,did_strip_ref,did_strip_typedef}); 223 reason |= lldb_private::eFormatterChoiceCriterionStrippedBitField; 224 } 225 226 if (!compiler_type.IsMeaninglessWithoutDynamicResolution()) 227 { 228 entries.push_back({type_name,reason,did_strip_ptr,did_strip_ref,did_strip_typedef}); 229 230 ConstString display_type_name(compiler_type.GetDisplayTypeName()); 231 if (display_type_name != type_name) 232 entries.push_back({display_type_name,reason,did_strip_ptr,did_strip_ref,did_strip_typedef}); 233 } 234 235 for (bool is_rvalue_ref = true, j = true; j && compiler_type.IsReferenceType(nullptr, &is_rvalue_ref); j = false) 236 { 237 CompilerType non_ref_type = compiler_type.GetNonReferenceType(); 238 GetPossibleMatches(valobj, 239 non_ref_type, 240 reason | lldb_private::eFormatterChoiceCriterionStrippedPointerReference, 241 use_dynamic, 242 entries, 243 did_strip_ptr, 244 true, 245 did_strip_typedef); 246 if (non_ref_type.IsTypedefType()) 247 { 248 CompilerType deffed_referenced_type = non_ref_type.GetTypedefedType(); 249 deffed_referenced_type = is_rvalue_ref ? deffed_referenced_type.GetRValueReferenceType() : deffed_referenced_type.GetLValueReferenceType(); 250 GetPossibleMatches(valobj, 251 deffed_referenced_type, 252 reason | lldb_private::eFormatterChoiceCriterionNavigatedTypedefs, 253 use_dynamic, 254 entries, 255 did_strip_ptr, 256 did_strip_ref, 257 true); // this is not exactly the usual meaning of stripping typedefs 258 } 259 } 260 261 if (compiler_type.IsPointerType()) 262 { 263 CompilerType non_ptr_type = compiler_type.GetPointeeType(); 264 GetPossibleMatches(valobj, 265 non_ptr_type, 266 reason | lldb_private::eFormatterChoiceCriterionStrippedPointerReference, 267 use_dynamic, 268 entries, 269 true, 270 did_strip_ref, 271 did_strip_typedef); 272 if (non_ptr_type.IsTypedefType()) 273 { 274 CompilerType deffed_pointed_type = non_ptr_type.GetTypedefedType().GetPointerType(); 275 GetPossibleMatches(valobj, 276 deffed_pointed_type, 277 reason | lldb_private::eFormatterChoiceCriterionNavigatedTypedefs, 278 use_dynamic, 279 entries, 280 did_strip_ptr, 281 did_strip_ref, 282 true); // this is not exactly the usual meaning of stripping typedefs 283 } 284 } 285 286 for (lldb::LanguageType language_type : GetCandidateLanguages(valobj)) 287 { 288 if (Language* language = Language::FindPlugin(language_type)) 289 { 290 for (ConstString candidate : language->GetPossibleFormattersMatches(valobj, use_dynamic)) 291 { 292 entries.push_back({candidate, 293 reason | lldb_private::eFormatterChoiceCriterionLanguagePlugin, 294 did_strip_ptr, 295 did_strip_ref, 296 did_strip_typedef}); 297 } 298 } 299 } 300 301 // try to strip typedef chains 302 if (compiler_type.IsTypedefType()) 303 { 304 CompilerType deffed_type = compiler_type.GetTypedefedType(); 305 GetPossibleMatches(valobj, 306 deffed_type, 307 reason | lldb_private::eFormatterChoiceCriterionNavigatedTypedefs, 308 use_dynamic, 309 entries, 310 did_strip_ptr, 311 did_strip_ref, 312 true); 313 } 314 315 if (root_level) 316 { 317 do { 318 if (!compiler_type.IsValid()) 319 break; 320 321 CompilerType unqual_compiler_ast_type = compiler_type.GetFullyUnqualifiedType(); 322 if (!unqual_compiler_ast_type.IsValid()) 323 break; 324 if (unqual_compiler_ast_type.GetOpaqueQualType() != compiler_type.GetOpaqueQualType()) 325 GetPossibleMatches (valobj, 326 unqual_compiler_ast_type, 327 reason, 328 use_dynamic, 329 entries, 330 did_strip_ptr, 331 did_strip_ref, 332 did_strip_typedef); 333 } while(false); 334 335 336 // if all else fails, go to static type 337 if (valobj.IsDynamic()) 338 { 339 lldb::ValueObjectSP static_value_sp(valobj.GetStaticValue()); 340 if (static_value_sp) 341 GetPossibleMatches(*static_value_sp.get(), 342 static_value_sp->GetCompilerType(), 343 reason | lldb_private::eFormatterChoiceCriterionWentToStaticValue, 344 use_dynamic, 345 entries, 346 did_strip_ptr, 347 did_strip_ref, 348 did_strip_typedef, 349 true); 350 } 351 } 352 } 353 354 lldb::TypeFormatImplSP 355 FormatManager::GetFormatForType (lldb::TypeNameSpecifierImplSP type_sp) 356 { 357 if (!type_sp) 358 return lldb::TypeFormatImplSP(); 359 lldb::TypeFormatImplSP format_chosen_sp; 360 uint32_t num_categories = m_categories_map.GetCount(); 361 lldb::TypeCategoryImplSP category_sp; 362 uint32_t prio_category = UINT32_MAX; 363 for (uint32_t category_id = 0; 364 category_id < num_categories; 365 category_id++) 366 { 367 category_sp = GetCategoryAtIndex(category_id); 368 if (category_sp->IsEnabled() == false) 369 continue; 370 lldb::TypeFormatImplSP format_current_sp = category_sp->GetFormatForType(type_sp); 371 if (format_current_sp && (format_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition()))) 372 { 373 prio_category = category_sp->GetEnabledPosition(); 374 format_chosen_sp = format_current_sp; 375 } 376 } 377 return format_chosen_sp; 378 } 379 380 lldb::TypeSummaryImplSP 381 FormatManager::GetSummaryForType (lldb::TypeNameSpecifierImplSP type_sp) 382 { 383 if (!type_sp) 384 return lldb::TypeSummaryImplSP(); 385 lldb::TypeSummaryImplSP summary_chosen_sp; 386 uint32_t num_categories = m_categories_map.GetCount(); 387 lldb::TypeCategoryImplSP category_sp; 388 uint32_t prio_category = UINT32_MAX; 389 for (uint32_t category_id = 0; 390 category_id < num_categories; 391 category_id++) 392 { 393 category_sp = GetCategoryAtIndex(category_id); 394 if (category_sp->IsEnabled() == false) 395 continue; 396 lldb::TypeSummaryImplSP summary_current_sp = category_sp->GetSummaryForType(type_sp); 397 if (summary_current_sp && (summary_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition()))) 398 { 399 prio_category = category_sp->GetEnabledPosition(); 400 summary_chosen_sp = summary_current_sp; 401 } 402 } 403 return summary_chosen_sp; 404 } 405 406 lldb::TypeFilterImplSP 407 FormatManager::GetFilterForType (lldb::TypeNameSpecifierImplSP type_sp) 408 { 409 if (!type_sp) 410 return lldb::TypeFilterImplSP(); 411 lldb::TypeFilterImplSP filter_chosen_sp; 412 uint32_t num_categories = m_categories_map.GetCount(); 413 lldb::TypeCategoryImplSP category_sp; 414 uint32_t prio_category = UINT32_MAX; 415 for (uint32_t category_id = 0; 416 category_id < num_categories; 417 category_id++) 418 { 419 category_sp = GetCategoryAtIndex(category_id); 420 if (category_sp->IsEnabled() == false) 421 continue; 422 lldb::TypeFilterImplSP filter_current_sp((TypeFilterImpl*)category_sp->GetFilterForType(type_sp).get()); 423 if (filter_current_sp && (filter_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition()))) 424 { 425 prio_category = category_sp->GetEnabledPosition(); 426 filter_chosen_sp = filter_current_sp; 427 } 428 } 429 return filter_chosen_sp; 430 } 431 432 #ifndef LLDB_DISABLE_PYTHON 433 lldb::ScriptedSyntheticChildrenSP 434 FormatManager::GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp) 435 { 436 if (!type_sp) 437 return lldb::ScriptedSyntheticChildrenSP(); 438 lldb::ScriptedSyntheticChildrenSP synth_chosen_sp; 439 uint32_t num_categories = m_categories_map.GetCount(); 440 lldb::TypeCategoryImplSP category_sp; 441 uint32_t prio_category = UINT32_MAX; 442 for (uint32_t category_id = 0; 443 category_id < num_categories; 444 category_id++) 445 { 446 category_sp = GetCategoryAtIndex(category_id); 447 if (category_sp->IsEnabled() == false) 448 continue; 449 lldb::ScriptedSyntheticChildrenSP synth_current_sp((ScriptedSyntheticChildren*)category_sp->GetSyntheticForType(type_sp).get()); 450 if (synth_current_sp && (synth_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition()))) 451 { 452 prio_category = category_sp->GetEnabledPosition(); 453 synth_chosen_sp = synth_current_sp; 454 } 455 } 456 return synth_chosen_sp; 457 } 458 #endif 459 460 #ifndef LLDB_DISABLE_PYTHON 461 lldb::SyntheticChildrenSP 462 FormatManager::GetSyntheticChildrenForType (lldb::TypeNameSpecifierImplSP type_sp) 463 { 464 if (!type_sp) 465 return lldb::SyntheticChildrenSP(); 466 lldb::TypeFilterImplSP filter_sp = GetFilterForType(type_sp); 467 lldb::ScriptedSyntheticChildrenSP synth_sp = GetSyntheticForType(type_sp); 468 if (filter_sp->GetRevision() > synth_sp->GetRevision()) 469 return lldb::SyntheticChildrenSP(filter_sp.get()); 470 else 471 return lldb::SyntheticChildrenSP(synth_sp.get()); 472 } 473 #endif 474 475 lldb::TypeValidatorImplSP 476 FormatManager::GetValidatorForType (lldb::TypeNameSpecifierImplSP type_sp) 477 { 478 if (!type_sp) 479 return lldb::TypeValidatorImplSP(); 480 lldb::TypeValidatorImplSP validator_chosen_sp; 481 uint32_t num_categories = m_categories_map.GetCount(); 482 lldb::TypeCategoryImplSP category_sp; 483 uint32_t prio_category = UINT32_MAX; 484 for (uint32_t category_id = 0; 485 category_id < num_categories; 486 category_id++) 487 { 488 category_sp = GetCategoryAtIndex(category_id); 489 if (category_sp->IsEnabled() == false) 490 continue; 491 lldb::TypeValidatorImplSP validator_current_sp(category_sp->GetValidatorForType(type_sp).get()); 492 if (validator_current_sp && (validator_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition()))) 493 { 494 prio_category = category_sp->GetEnabledPosition(); 495 validator_chosen_sp = validator_current_sp; 496 } 497 } 498 return validator_chosen_sp; 499 } 500 501 void 502 FormatManager::ForEachCategory(TypeCategoryMap::ForEachCallback callback) 503 { 504 m_categories_map.ForEach(callback); 505 Mutex::Locker locker(m_language_categories_mutex); 506 for (const auto& entry : m_language_categories_map) 507 { 508 if (auto category_sp = entry.second->GetCategory()) 509 { 510 if (!callback(category_sp)) 511 break; 512 } 513 } 514 } 515 516 lldb::TypeCategoryImplSP 517 FormatManager::GetCategory (const ConstString& category_name, 518 bool can_create) 519 { 520 if (!category_name) 521 return GetCategory(m_default_category_name); 522 lldb::TypeCategoryImplSP category; 523 if (m_categories_map.Get(category_name, category)) 524 return category; 525 526 if (!can_create) 527 return lldb::TypeCategoryImplSP(); 528 529 m_categories_map.Add(category_name,lldb::TypeCategoryImplSP(new TypeCategoryImpl(this, category_name))); 530 return GetCategory(category_name); 531 } 532 533 lldb::Format 534 FormatManager::GetSingleItemFormat(lldb::Format vector_format) 535 { 536 switch(vector_format) 537 { 538 case eFormatVectorOfChar: 539 return eFormatCharArray; 540 541 case eFormatVectorOfSInt8: 542 case eFormatVectorOfSInt16: 543 case eFormatVectorOfSInt32: 544 case eFormatVectorOfSInt64: 545 return eFormatDecimal; 546 547 case eFormatVectorOfUInt8: 548 case eFormatVectorOfUInt16: 549 case eFormatVectorOfUInt32: 550 case eFormatVectorOfUInt64: 551 case eFormatVectorOfUInt128: 552 return eFormatHex; 553 554 case eFormatVectorOfFloat16: 555 case eFormatVectorOfFloat32: 556 case eFormatVectorOfFloat64: 557 return eFormatFloat; 558 559 default: 560 return lldb::eFormatInvalid; 561 } 562 } 563 564 bool 565 FormatManager::ShouldPrintAsOneLiner (ValueObject& valobj) 566 { 567 // if settings say no oneline whatsoever 568 if (valobj.GetTargetSP().get() && valobj.GetTargetSP()->GetDebugger().GetAutoOneLineSummaries() == false) 569 return false; // then don't oneline 570 571 // if this object has a summary, then ask the summary 572 if (valobj.GetSummaryFormat().get() != nullptr) 573 return valobj.GetSummaryFormat()->IsOneLiner(); 574 575 // no children, no party 576 if (valobj.GetNumChildren() == 0) 577 return false; 578 579 // ask the type if it has any opinion about this 580 // eLazyBoolCalculate == no opinion; other values should be self explanatory 581 CompilerType compiler_type(valobj.GetCompilerType()); 582 if (compiler_type.IsValid()) 583 { 584 switch (compiler_type.ShouldPrintAsOneLiner(&valobj)) 585 { 586 case eLazyBoolNo: 587 return false; 588 case eLazyBoolYes: 589 return true; 590 case eLazyBoolCalculate: 591 break; 592 } 593 } 594 595 size_t total_children_name_len = 0; 596 597 for (size_t idx = 0; 598 idx < valobj.GetNumChildren(); 599 idx++) 600 { 601 bool is_synth_val = false; 602 ValueObjectSP child_sp(valobj.GetChildAtIndex(idx, true)); 603 // something is wrong here - bail out 604 if (!child_sp) 605 return false; 606 607 // also ask the child's type if it has any opinion 608 CompilerType child_compiler_type(child_sp->GetCompilerType()); 609 if (child_compiler_type.IsValid()) 610 { 611 switch (child_compiler_type.ShouldPrintAsOneLiner(child_sp.get())) 612 { 613 case eLazyBoolYes: 614 // an opinion of yes is only binding for the child, so keep going 615 case eLazyBoolCalculate: 616 break; 617 case eLazyBoolNo: 618 // but if the child says no, then it's a veto on the whole thing 619 return false; 620 } 621 } 622 623 // if we decided to define synthetic children for a type, we probably care enough 624 // to show them, but avoid nesting children in children 625 if (child_sp->GetSyntheticChildren().get() != nullptr) 626 { 627 ValueObjectSP synth_sp(child_sp->GetSyntheticValue()); 628 // wait.. wat? just get out of here.. 629 if (!synth_sp) 630 return false; 631 // but if we only have them to provide a value, keep going 632 if (synth_sp->MightHaveChildren() == false && synth_sp->DoesProvideSyntheticValue()) 633 is_synth_val = true; 634 else 635 return false; 636 } 637 638 total_children_name_len += child_sp->GetName().GetLength(); 639 640 // 50 itself is a "randomly" chosen number - the idea is that 641 // overly long structs should not get this treatment 642 // FIXME: maybe make this a user-tweakable setting? 643 if (total_children_name_len > 50) 644 return false; 645 646 // if a summary is there.. 647 if (child_sp->GetSummaryFormat()) 648 { 649 // and it wants children, then bail out 650 if (child_sp->GetSummaryFormat()->DoesPrintChildren(child_sp.get())) 651 return false; 652 } 653 654 // if this child has children.. 655 if (child_sp->GetNumChildren()) 656 { 657 // ...and no summary... 658 // (if it had a summary and the summary wanted children, we would have bailed out anyway 659 // so this only makes us bail out if this has no summary and we would then print children) 660 if (!child_sp->GetSummaryFormat() && !is_synth_val) // but again only do that if not a synthetic valued child 661 return false; // then bail out 662 } 663 } 664 return true; 665 } 666 667 ConstString 668 FormatManager::GetValidTypeName (const ConstString& type) 669 { 670 return ::GetValidTypeName_Impl(type); 671 } 672 673 ConstString 674 FormatManager::GetTypeForCache (ValueObject& valobj, 675 lldb::DynamicValueType use_dynamic) 676 { 677 ValueObjectSP valobj_sp = valobj.GetQualifiedRepresentationIfAvailable(use_dynamic, valobj.IsSynthetic()); 678 if (valobj_sp && valobj_sp->GetCompilerType().IsValid()) 679 { 680 if (!valobj_sp->GetCompilerType().IsMeaninglessWithoutDynamicResolution()) 681 return valobj_sp->GetQualifiedTypeName(); 682 } 683 return ConstString(); 684 } 685 686 std::vector<lldb::LanguageType> 687 FormatManager::GetCandidateLanguages (ValueObject& valobj) 688 { 689 lldb::LanguageType lang_type = valobj.GetObjectRuntimeLanguage(); 690 return GetCandidateLanguages(lang_type); 691 } 692 693 std::vector<lldb::LanguageType> 694 FormatManager::GetCandidateLanguages (lldb::LanguageType lang_type) 695 { 696 switch (lang_type) 697 { 698 case lldb::eLanguageTypeC: 699 case lldb::eLanguageTypeC89: 700 case lldb::eLanguageTypeC99: 701 case lldb::eLanguageTypeC11: 702 case lldb::eLanguageTypeC_plus_plus: 703 case lldb::eLanguageTypeC_plus_plus_03: 704 case lldb::eLanguageTypeC_plus_plus_11: 705 case lldb::eLanguageTypeC_plus_plus_14: 706 return {lldb::eLanguageTypeC_plus_plus, lldb::eLanguageTypeObjC}; 707 default: 708 return {lang_type}; 709 } 710 } 711 712 LanguageCategory* 713 FormatManager::GetCategoryForLanguage (lldb::LanguageType lang_type) 714 { 715 Mutex::Locker locker(m_language_categories_mutex); 716 auto iter = m_language_categories_map.find(lang_type), end = m_language_categories_map.end(); 717 if (iter != end) 718 return iter->second.get(); 719 LanguageCategory* lang_category = new LanguageCategory(lang_type); 720 m_language_categories_map[lang_type] = LanguageCategory::UniquePointer(lang_category); 721 return lang_category; 722 } 723 724 lldb::TypeFormatImplSP 725 FormatManager::GetHardcodedFormat (FormattersMatchData& match_data) 726 { 727 TypeFormatImplSP retval_sp; 728 729 for (lldb::LanguageType lang_type : match_data.GetCandidateLanguages()) 730 { 731 if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type)) 732 { 733 if (lang_category->GetHardcoded(*this, match_data, retval_sp)) 734 break; 735 } 736 } 737 738 return retval_sp; 739 } 740 741 lldb::TypeFormatImplSP 742 FormatManager::GetFormat (ValueObject& valobj, 743 lldb::DynamicValueType use_dynamic) 744 { 745 FormattersMatchData match_data(valobj, use_dynamic); 746 747 TypeFormatImplSP retval; 748 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_DATAFORMATTERS)); 749 if (match_data.GetTypeForCache()) 750 { 751 if (log) 752 log->Printf("\n\n[FormatManager::GetFormat] Looking into cache for type %s", match_data.GetTypeForCache().AsCString("<invalid>")); 753 if (m_format_cache.GetFormat(match_data.GetTypeForCache(),retval)) 754 { 755 if (log) 756 { 757 log->Printf("[FormatManager::GetFormat] Cache search success. Returning."); 758 if (log->GetDebug()) 759 log->Printf("[FormatManager::GetFormat] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses()); 760 } 761 return retval; 762 } 763 if (log) 764 log->Printf("[FormatManager::GetFormat] Cache search failed. Going normal route"); 765 } 766 767 retval = m_categories_map.GetFormat(match_data); 768 if (!retval) 769 { 770 if (log) 771 log->Printf("[FormatManager::GetFormat] Search failed. Giving language a chance."); 772 for (lldb::LanguageType lang_type : match_data.GetCandidateLanguages()) 773 { 774 if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type)) 775 { 776 if (lang_category->Get(match_data, retval)) 777 break; 778 } 779 } 780 if (retval) 781 { 782 if (log) 783 log->Printf("[FormatManager::GetFormat] Language search success. Returning."); 784 return retval; 785 } 786 } 787 if (!retval) 788 { 789 if (log) 790 log->Printf("[FormatManager::GetFormat] Search failed. Giving hardcoded a chance."); 791 retval = GetHardcodedFormat(match_data); 792 } 793 794 if (match_data.GetTypeForCache() && (!retval || !retval->NonCacheable())) 795 { 796 if (log) 797 log->Printf("[FormatManager::GetFormat] Caching %p for type %s", 798 static_cast<void*>(retval.get()), 799 match_data.GetTypeForCache().AsCString("<invalid>")); 800 m_format_cache.SetFormat(match_data.GetTypeForCache(),retval); 801 } 802 if (log && log->GetDebug()) 803 log->Printf("[FormatManager::GetFormat] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses()); 804 return retval; 805 } 806 807 lldb::TypeSummaryImplSP 808 FormatManager::GetHardcodedSummaryFormat (FormattersMatchData& match_data) 809 { 810 TypeSummaryImplSP retval_sp; 811 812 for (lldb::LanguageType lang_type : match_data.GetCandidateLanguages()) 813 { 814 if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type)) 815 { 816 if (lang_category->GetHardcoded(*this, match_data, retval_sp)) 817 break; 818 } 819 } 820 821 return retval_sp; 822 } 823 824 lldb::TypeSummaryImplSP 825 FormatManager::GetSummaryFormat (ValueObject& valobj, 826 lldb::DynamicValueType use_dynamic) 827 { 828 FormattersMatchData match_data(valobj, use_dynamic); 829 830 TypeSummaryImplSP retval; 831 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_DATAFORMATTERS)); 832 if (match_data.GetTypeForCache()) 833 { 834 if (log) 835 log->Printf("\n\n[FormatManager::GetSummaryFormat] Looking into cache for type %s", match_data.GetTypeForCache().AsCString("<invalid>")); 836 if (m_format_cache.GetSummary(match_data.GetTypeForCache(),retval)) 837 { 838 if (log) 839 { 840 log->Printf("[FormatManager::GetSummaryFormat] Cache search success. Returning."); 841 if (log->GetDebug()) 842 log->Printf("[FormatManager::GetSummaryFormat] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses()); 843 } 844 return retval; 845 } 846 if (log) 847 log->Printf("[FormatManager::GetSummaryFormat] Cache search failed. Going normal route"); 848 } 849 850 retval = m_categories_map.GetSummaryFormat(match_data); 851 if (!retval) 852 { 853 if (log) 854 log->Printf("[FormatManager::GetSummaryFormat] Search failed. Giving language a chance."); 855 for (lldb::LanguageType lang_type : match_data.GetCandidateLanguages()) 856 { 857 if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type)) 858 { 859 if (lang_category->Get(match_data, retval)) 860 break; 861 } 862 } 863 if (retval) 864 { 865 if (log) 866 log->Printf("[FormatManager::GetSummaryFormat] Language search success. Returning."); 867 return retval; 868 } 869 } 870 if (!retval) 871 { 872 if (log) 873 log->Printf("[FormatManager::GetSummaryFormat] Search failed. Giving hardcoded a chance."); 874 retval = GetHardcodedSummaryFormat(match_data); 875 } 876 877 if (match_data.GetTypeForCache() && (!retval || !retval->NonCacheable())) 878 { 879 if (log) 880 log->Printf("[FormatManager::GetSummaryFormat] Caching %p for type %s", 881 static_cast<void*>(retval.get()), 882 match_data.GetTypeForCache().AsCString("<invalid>")); 883 m_format_cache.SetSummary(match_data.GetTypeForCache(),retval); 884 } 885 if (log && log->GetDebug()) 886 log->Printf("[FormatManager::GetSummaryFormat] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses()); 887 return retval; 888 } 889 890 #ifndef LLDB_DISABLE_PYTHON 891 lldb::SyntheticChildrenSP 892 FormatManager::GetHardcodedSyntheticChildren (FormattersMatchData& match_data) 893 { 894 SyntheticChildrenSP retval_sp; 895 896 for (lldb::LanguageType lang_type : match_data.GetCandidateLanguages()) 897 { 898 if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type)) 899 { 900 if (lang_category->GetHardcoded(*this, match_data, retval_sp)) 901 break; 902 } 903 } 904 905 return retval_sp; 906 } 907 908 lldb::SyntheticChildrenSP 909 FormatManager::GetSyntheticChildren (ValueObject& valobj, 910 lldb::DynamicValueType use_dynamic) 911 { 912 FormattersMatchData match_data(valobj, use_dynamic); 913 914 SyntheticChildrenSP retval; 915 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_DATAFORMATTERS)); 916 if (match_data.GetTypeForCache()) 917 { 918 if (log) 919 log->Printf("\n\n[FormatManager::GetSyntheticChildren] Looking into cache for type %s", match_data.GetTypeForCache().AsCString("<invalid>")); 920 if (m_format_cache.GetSynthetic(match_data.GetTypeForCache(),retval)) 921 { 922 if (log) 923 { 924 log->Printf("[FormatManager::GetSyntheticChildren] Cache search success. Returning."); 925 if (log->GetDebug()) 926 log->Printf("[FormatManager::GetSyntheticChildren] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses()); 927 } 928 return retval; 929 } 930 if (log) 931 log->Printf("[FormatManager::GetSyntheticChildren] Cache search failed. Going normal route"); 932 } 933 934 retval = m_categories_map.GetSyntheticChildren(match_data); 935 if (!retval) 936 { 937 if (log) 938 log->Printf("[FormatManager::GetSyntheticChildren] Search failed. Giving language a chance."); 939 for (lldb::LanguageType lang_type : match_data.GetCandidateLanguages()) 940 { 941 if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type)) 942 { 943 if (lang_category->Get(match_data, retval)) 944 break; 945 } 946 } 947 if (retval) 948 { 949 if (log) 950 log->Printf("[FormatManager::GetSyntheticChildren] Language search success. Returning."); 951 return retval; 952 } 953 } 954 if (!retval) 955 { 956 if (log) 957 log->Printf("[FormatManager::GetSyntheticChildren] Search failed. Giving hardcoded a chance."); 958 retval = GetHardcodedSyntheticChildren(match_data); 959 } 960 961 if (match_data.GetTypeForCache() && (!retval || !retval->NonCacheable())) 962 { 963 if (log) 964 log->Printf("[FormatManager::GetSyntheticChildren] Caching %p for type %s", 965 static_cast<void*>(retval.get()), 966 match_data.GetTypeForCache().AsCString("<invalid>")); 967 m_format_cache.SetSynthetic(match_data.GetTypeForCache(),retval); 968 } 969 if (log && log->GetDebug()) 970 log->Printf("[FormatManager::GetSyntheticChildren] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses()); 971 return retval; 972 } 973 #endif 974 975 lldb::TypeValidatorImplSP 976 FormatManager::GetValidator (ValueObject& valobj, 977 lldb::DynamicValueType use_dynamic) 978 { 979 FormattersMatchData match_data(valobj, use_dynamic); 980 981 TypeValidatorImplSP retval; 982 Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_DATAFORMATTERS)); 983 if (match_data.GetTypeForCache()) 984 { 985 if (log) 986 log->Printf("\n\n[FormatManager::GetValidator] Looking into cache for type %s", match_data.GetTypeForCache().AsCString("<invalid>")); 987 if (m_format_cache.GetValidator(match_data.GetTypeForCache(),retval)) 988 { 989 if (log) 990 { 991 log->Printf("[FormatManager::GetValidator] Cache search success. Returning."); 992 if (log->GetDebug()) 993 log->Printf("[FormatManager::GetValidator] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses()); 994 } 995 return retval; 996 } 997 if (log) 998 log->Printf("[FormatManager::GetValidator] Cache search failed. Going normal route"); 999 } 1000 1001 retval = m_categories_map.GetValidator(match_data); 1002 if (!retval) 1003 { 1004 if (log) 1005 log->Printf("[FormatManager::GetValidator] Search failed. Giving language a chance."); 1006 for (lldb::LanguageType lang_type : match_data.GetCandidateLanguages()) 1007 { 1008 if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type)) 1009 { 1010 if (lang_category->Get(match_data, retval)) 1011 break; 1012 } 1013 } 1014 if (retval) 1015 { 1016 if (log) 1017 log->Printf("[FormatManager::GetValidator] Language search success. Returning."); 1018 return retval; 1019 } 1020 } 1021 if (!retval) 1022 { 1023 if (log) 1024 log->Printf("[FormatManager::GetValidator] Search failed. Giving hardcoded a chance."); 1025 retval = GetHardcodedValidator(match_data); 1026 } 1027 1028 if (match_data.GetTypeForCache() && (!retval || !retval->NonCacheable())) 1029 { 1030 if (log) 1031 log->Printf("[FormatManager::GetValidator] Caching %p for type %s", 1032 static_cast<void*>(retval.get()), 1033 match_data.GetTypeForCache().AsCString("<invalid>")); 1034 m_format_cache.SetValidator(match_data.GetTypeForCache(),retval); 1035 } 1036 if (log && log->GetDebug()) 1037 log->Printf("[FormatManager::GetValidator] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses()); 1038 return retval; 1039 } 1040 1041 lldb::TypeValidatorImplSP 1042 FormatManager::GetHardcodedValidator (FormattersMatchData& match_data) 1043 { 1044 TypeValidatorImplSP retval_sp; 1045 1046 for (lldb::LanguageType lang_type : match_data.GetCandidateLanguages()) 1047 { 1048 if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type)) 1049 { 1050 if (lang_category->GetHardcoded(*this, match_data, retval_sp)) 1051 break; 1052 } 1053 } 1054 1055 return retval_sp; 1056 } 1057 1058 FormatManager::FormatManager() : 1059 m_last_revision(0), 1060 m_format_cache(), 1061 m_language_categories_mutex(Mutex::eMutexTypeRecursive), 1062 m_language_categories_map(), 1063 m_named_summaries_map(this), 1064 m_categories_map(this), 1065 m_default_category_name(ConstString("default")), 1066 m_system_category_name(ConstString("system")), 1067 m_vectortypes_category_name(ConstString("VectorTypes")) 1068 { 1069 LoadSystemFormatters(); 1070 LoadVectorFormatters(); 1071 1072 EnableCategory(m_vectortypes_category_name,TypeCategoryMap::Last, lldb::eLanguageTypeObjC_plus_plus); 1073 EnableCategory(m_system_category_name,TypeCategoryMap::Last, lldb::eLanguageTypeObjC_plus_plus); 1074 } 1075 1076 void 1077 FormatManager::LoadSystemFormatters() 1078 { 1079 TypeSummaryImpl::Flags string_flags; 1080 string_flags.SetCascades(true) 1081 .SetSkipPointers(true) 1082 .SetSkipReferences(false) 1083 .SetDontShowChildren(true) 1084 .SetDontShowValue(false) 1085 .SetShowMembersOneLiner(false) 1086 .SetHideItemNames(false); 1087 1088 TypeSummaryImpl::Flags string_array_flags; 1089 string_array_flags.SetCascades(true) 1090 .SetSkipPointers(true) 1091 .SetSkipReferences(false) 1092 .SetDontShowChildren(true) 1093 .SetDontShowValue(true) 1094 .SetShowMembersOneLiner(false) 1095 .SetHideItemNames(false); 1096 1097 lldb::TypeSummaryImplSP string_format(new StringSummaryFormat(string_flags, "${var%s}")); 1098 1099 1100 lldb::TypeSummaryImplSP string_array_format(new StringSummaryFormat(string_array_flags, 1101 "${var%s}")); 1102 1103 lldb::RegularExpressionSP any_size_char_arr(new RegularExpression("char \\[[0-9]+\\]")); 1104 lldb::RegularExpressionSP any_size_wchar_arr(new RegularExpression("wchar_t \\[[0-9]+\\]")); 1105 1106 TypeCategoryImpl::SharedPointer sys_category_sp = GetCategory(m_system_category_name); 1107 1108 sys_category_sp->GetTypeSummariesContainer()->Add(ConstString("char *"), string_format); 1109 sys_category_sp->GetTypeSummariesContainer()->Add(ConstString("unsigned char *"), string_format); 1110 sys_category_sp->GetRegexTypeSummariesContainer()->Add(any_size_char_arr, string_array_format); 1111 1112 lldb::TypeSummaryImplSP ostype_summary(new StringSummaryFormat(TypeSummaryImpl::Flags().SetCascades(false) 1113 .SetSkipPointers(true) 1114 .SetSkipReferences(true) 1115 .SetDontShowChildren(true) 1116 .SetDontShowValue(false) 1117 .SetShowMembersOneLiner(false) 1118 .SetHideItemNames(false), 1119 "${var%O}")); 1120 1121 sys_category_sp->GetTypeSummariesContainer()->Add(ConstString("OSType"), ostype_summary); 1122 1123 #ifndef LLDB_DISABLE_PYTHON 1124 TypeFormatImpl::Flags fourchar_flags; 1125 fourchar_flags.SetCascades(true).SetSkipPointers(true).SetSkipReferences(true); 1126 1127 AddFormat(sys_category_sp, lldb::eFormatOSType, ConstString("FourCharCode"), fourchar_flags); 1128 #endif 1129 } 1130 1131 void 1132 FormatManager::LoadVectorFormatters() 1133 { 1134 TypeCategoryImpl::SharedPointer vectors_category_sp = GetCategory(m_vectortypes_category_name); 1135 1136 TypeSummaryImpl::Flags vector_flags; 1137 vector_flags.SetCascades(true) 1138 .SetSkipPointers(true) 1139 .SetSkipReferences(false) 1140 .SetDontShowChildren(true) 1141 .SetDontShowValue(false) 1142 .SetShowMembersOneLiner(true) 1143 .SetHideItemNames(true); 1144 1145 AddStringSummary(vectors_category_sp, 1146 "${var.uint128}", 1147 ConstString("builtin_type_vec128"), 1148 vector_flags); 1149 1150 AddStringSummary(vectors_category_sp, 1151 "", 1152 ConstString("float [4]"), 1153 vector_flags); 1154 AddStringSummary(vectors_category_sp, 1155 "", 1156 ConstString("int32_t [4]"), 1157 vector_flags); 1158 AddStringSummary(vectors_category_sp, 1159 "", 1160 ConstString("int16_t [8]"), 1161 vector_flags); 1162 AddStringSummary(vectors_category_sp, 1163 "", 1164 ConstString("vDouble"), 1165 vector_flags); 1166 AddStringSummary(vectors_category_sp, 1167 "", 1168 ConstString("vFloat"), 1169 vector_flags); 1170 AddStringSummary(vectors_category_sp, 1171 "", 1172 ConstString("vSInt8"), 1173 vector_flags); 1174 AddStringSummary(vectors_category_sp, 1175 "", 1176 ConstString("vSInt16"), 1177 vector_flags); 1178 AddStringSummary(vectors_category_sp, 1179 "", 1180 ConstString("vSInt32"), 1181 vector_flags); 1182 AddStringSummary(vectors_category_sp, 1183 "", 1184 ConstString("vUInt16"), 1185 vector_flags); 1186 AddStringSummary(vectors_category_sp, 1187 "", 1188 ConstString("vUInt8"), 1189 vector_flags); 1190 AddStringSummary(vectors_category_sp, 1191 "", 1192 ConstString("vUInt16"), 1193 vector_flags); 1194 AddStringSummary(vectors_category_sp, 1195 "", 1196 ConstString("vUInt32"), 1197 vector_flags); 1198 AddStringSummary(vectors_category_sp, 1199 "", 1200 ConstString("vBool32"), 1201 vector_flags); 1202 } 1203