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