1 //===-- FormatManager.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/FormatManager.h" 10 11 #include "lldb/Core/Debugger.h" 12 #include "lldb/DataFormatters/FormattersHelpers.h" 13 #include "lldb/DataFormatters/LanguageCategory.h" 14 #include "lldb/Target/ExecutionContext.h" 15 #include "lldb/Target/Language.h" 16 #include "lldb/Utility/LLDBLog.h" 17 #include "lldb/Utility/Log.h" 18 #include "llvm/ADT/STLExtras.h" 19 20 using namespace lldb; 21 using namespace lldb_private; 22 using namespace lldb_private::formatters; 23 24 struct FormatInfo { 25 Format format; 26 const char format_char; // One or more format characters that can be used for 27 // this format. 28 const char *format_name; // Long format name that can be used to specify the 29 // current format 30 }; 31 32 static constexpr FormatInfo g_format_infos[] = { 33 {eFormatDefault, '\0', "default"}, 34 {eFormatBoolean, 'B', "boolean"}, 35 {eFormatBinary, 'b', "binary"}, 36 {eFormatBytes, 'y', "bytes"}, 37 {eFormatBytesWithASCII, 'Y', "bytes with ASCII"}, 38 {eFormatChar, 'c', "character"}, 39 {eFormatCharPrintable, 'C', "printable character"}, 40 {eFormatComplexFloat, 'F', "complex float"}, 41 {eFormatCString, 's', "c-string"}, 42 {eFormatDecimal, 'd', "decimal"}, 43 {eFormatEnum, 'E', "enumeration"}, 44 {eFormatHex, 'x', "hex"}, 45 {eFormatHexUppercase, 'X', "uppercase hex"}, 46 {eFormatFloat, 'f', "float"}, 47 {eFormatOctal, 'o', "octal"}, 48 {eFormatOSType, 'O', "OSType"}, 49 {eFormatUnicode16, 'U', "unicode16"}, 50 {eFormatUnicode32, '\0', "unicode32"}, 51 {eFormatUnsigned, 'u', "unsigned decimal"}, 52 {eFormatPointer, 'p', "pointer"}, 53 {eFormatVectorOfChar, '\0', "char[]"}, 54 {eFormatVectorOfSInt8, '\0', "int8_t[]"}, 55 {eFormatVectorOfUInt8, '\0', "uint8_t[]"}, 56 {eFormatVectorOfSInt16, '\0', "int16_t[]"}, 57 {eFormatVectorOfUInt16, '\0', "uint16_t[]"}, 58 {eFormatVectorOfSInt32, '\0', "int32_t[]"}, 59 {eFormatVectorOfUInt32, '\0', "uint32_t[]"}, 60 {eFormatVectorOfSInt64, '\0', "int64_t[]"}, 61 {eFormatVectorOfUInt64, '\0', "uint64_t[]"}, 62 {eFormatVectorOfFloat16, '\0', "float16[]"}, 63 {eFormatVectorOfFloat32, '\0', "float32[]"}, 64 {eFormatVectorOfFloat64, '\0', "float64[]"}, 65 {eFormatVectorOfUInt128, '\0', "uint128_t[]"}, 66 {eFormatComplexInteger, 'I', "complex integer"}, 67 {eFormatCharArray, 'a', "character array"}, 68 {eFormatAddressInfo, 'A', "address"}, 69 {eFormatHexFloat, '\0', "hex float"}, 70 {eFormatInstruction, 'i', "instruction"}, 71 {eFormatVoid, 'v', "void"}, 72 {eFormatUnicode8, 'u', "unicode8"}, 73 }; 74 75 static_assert((sizeof(g_format_infos) / sizeof(g_format_infos[0])) == 76 kNumFormats, 77 "All formats must have a corresponding info entry."); 78 79 static uint32_t g_num_format_infos = llvm::array_lengthof(g_format_infos); 80 81 static bool GetFormatFromFormatChar(char format_char, Format &format) { 82 for (uint32_t i = 0; i < g_num_format_infos; ++i) { 83 if (g_format_infos[i].format_char == format_char) { 84 format = g_format_infos[i].format; 85 return true; 86 } 87 } 88 format = eFormatInvalid; 89 return false; 90 } 91 92 static bool GetFormatFromFormatName(llvm::StringRef format_name, 93 bool partial_match_ok, Format &format) { 94 uint32_t i; 95 for (i = 0; i < g_num_format_infos; ++i) { 96 if (format_name.equals_insensitive(g_format_infos[i].format_name)) { 97 format = g_format_infos[i].format; 98 return true; 99 } 100 } 101 102 if (partial_match_ok) { 103 for (i = 0; i < g_num_format_infos; ++i) { 104 if (llvm::StringRef(g_format_infos[i].format_name) 105 .startswith_insensitive(format_name)) { 106 format = g_format_infos[i].format; 107 return true; 108 } 109 } 110 } 111 format = eFormatInvalid; 112 return false; 113 } 114 115 void FormatManager::Changed() { 116 ++m_last_revision; 117 m_format_cache.Clear(); 118 std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex); 119 for (auto &iter : m_language_categories_map) { 120 if (iter.second) 121 iter.second->GetFormatCache().Clear(); 122 } 123 } 124 125 bool FormatManager::GetFormatFromCString(const char *format_cstr, 126 bool partial_match_ok, 127 lldb::Format &format) { 128 bool success = false; 129 if (format_cstr && format_cstr[0]) { 130 if (format_cstr[1] == '\0') { 131 success = GetFormatFromFormatChar(format_cstr[0], format); 132 if (success) 133 return true; 134 } 135 136 success = GetFormatFromFormatName(format_cstr, partial_match_ok, format); 137 } 138 if (!success) 139 format = eFormatInvalid; 140 return success; 141 } 142 143 char FormatManager::GetFormatAsFormatChar(lldb::Format format) { 144 for (uint32_t i = 0; i < g_num_format_infos; ++i) { 145 if (g_format_infos[i].format == format) 146 return g_format_infos[i].format_char; 147 } 148 return '\0'; 149 } 150 151 const char *FormatManager::GetFormatAsCString(Format format) { 152 if (format >= eFormatDefault && format < kNumFormats) 153 return g_format_infos[format].format_name; 154 return nullptr; 155 } 156 157 void FormatManager::EnableAllCategories() { 158 m_categories_map.EnableAllCategories(); 159 std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex); 160 for (auto &iter : m_language_categories_map) { 161 if (iter.second) 162 iter.second->Enable(); 163 } 164 } 165 166 void FormatManager::DisableAllCategories() { 167 m_categories_map.DisableAllCategories(); 168 std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex); 169 for (auto &iter : m_language_categories_map) { 170 if (iter.second) 171 iter.second->Disable(); 172 } 173 } 174 175 void FormatManager::GetPossibleMatches( 176 ValueObject &valobj, CompilerType compiler_type, 177 lldb::DynamicValueType use_dynamic, FormattersMatchVector &entries, 178 bool did_strip_ptr, bool did_strip_ref, bool did_strip_typedef, 179 bool root_level) { 180 compiler_type = compiler_type.GetTypeForFormatters(); 181 ConstString type_name(compiler_type.GetTypeName()); 182 if (valobj.GetBitfieldBitSize() > 0) { 183 StreamString sstring; 184 sstring.Printf("%s:%d", type_name.AsCString(), valobj.GetBitfieldBitSize()); 185 ConstString bitfieldname(sstring.GetString()); 186 entries.push_back( 187 {bitfieldname, did_strip_ptr, did_strip_ref, did_strip_typedef}); 188 } 189 190 if (!compiler_type.IsMeaninglessWithoutDynamicResolution()) { 191 entries.push_back( 192 {type_name, did_strip_ptr, did_strip_ref, did_strip_typedef}); 193 194 ConstString display_type_name(compiler_type.GetTypeName()); 195 if (display_type_name != type_name) 196 entries.push_back({display_type_name, did_strip_ptr, 197 did_strip_ref, did_strip_typedef}); 198 } 199 200 for (bool is_rvalue_ref = true, j = true; 201 j && compiler_type.IsReferenceType(nullptr, &is_rvalue_ref); j = false) { 202 CompilerType non_ref_type = compiler_type.GetNonReferenceType(); 203 GetPossibleMatches( 204 valobj, non_ref_type, 205 use_dynamic, entries, did_strip_ptr, true, did_strip_typedef); 206 if (non_ref_type.IsTypedefType()) { 207 CompilerType deffed_referenced_type = non_ref_type.GetTypedefedType(); 208 deffed_referenced_type = 209 is_rvalue_ref ? deffed_referenced_type.GetRValueReferenceType() 210 : deffed_referenced_type.GetLValueReferenceType(); 211 GetPossibleMatches( 212 valobj, deffed_referenced_type, 213 use_dynamic, entries, did_strip_ptr, did_strip_ref, 214 true); // this is not exactly the usual meaning of stripping typedefs 215 } 216 } 217 218 if (compiler_type.IsPointerType()) { 219 CompilerType non_ptr_type = compiler_type.GetPointeeType(); 220 GetPossibleMatches( 221 valobj, non_ptr_type, 222 use_dynamic, entries, true, did_strip_ref, did_strip_typedef); 223 if (non_ptr_type.IsTypedefType()) { 224 CompilerType deffed_pointed_type = 225 non_ptr_type.GetTypedefedType().GetPointerType(); 226 const bool stripped_typedef = true; 227 GetPossibleMatches( 228 valobj, deffed_pointed_type, 229 use_dynamic, entries, did_strip_ptr, did_strip_ref, 230 stripped_typedef); // this is not exactly the usual meaning of 231 // stripping typedefs 232 } 233 } 234 235 // For arrays with typedef-ed elements, we add a candidate with the typedef 236 // stripped. 237 uint64_t array_size; 238 if (compiler_type.IsArrayType(nullptr, &array_size, nullptr)) { 239 ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); 240 CompilerType element_type = compiler_type.GetArrayElementType( 241 exe_ctx.GetBestExecutionContextScope()); 242 if (element_type.IsTypedefType()) { 243 // Get the stripped element type and compute the stripped array type 244 // from it. 245 CompilerType deffed_array_type = 246 element_type.GetTypedefedType().GetArrayType(array_size); 247 const bool stripped_typedef = true; 248 GetPossibleMatches( 249 valobj, deffed_array_type, 250 use_dynamic, entries, did_strip_ptr, did_strip_ref, 251 stripped_typedef); // this is not exactly the usual meaning of 252 // stripping typedefs 253 } 254 } 255 256 for (lldb::LanguageType language_type : 257 GetCandidateLanguages(valobj.GetObjectRuntimeLanguage())) { 258 if (Language *language = Language::FindPlugin(language_type)) { 259 for (ConstString candidate : 260 language->GetPossibleFormattersMatches(valobj, use_dynamic)) { 261 entries.push_back( 262 {candidate, 263 did_strip_ptr, did_strip_ref, did_strip_typedef}); 264 } 265 } 266 } 267 268 // try to strip typedef chains 269 if (compiler_type.IsTypedefType()) { 270 CompilerType deffed_type = compiler_type.GetTypedefedType(); 271 GetPossibleMatches( 272 valobj, deffed_type, 273 use_dynamic, entries, did_strip_ptr, did_strip_ref, true); 274 } 275 276 if (root_level) { 277 do { 278 if (!compiler_type.IsValid()) 279 break; 280 281 CompilerType unqual_compiler_ast_type = 282 compiler_type.GetFullyUnqualifiedType(); 283 if (!unqual_compiler_ast_type.IsValid()) 284 break; 285 if (unqual_compiler_ast_type.GetOpaqueQualType() != 286 compiler_type.GetOpaqueQualType()) 287 GetPossibleMatches(valobj, unqual_compiler_ast_type, 288 use_dynamic, entries, did_strip_ptr, did_strip_ref, 289 did_strip_typedef); 290 } while (false); 291 292 // if all else fails, go to static type 293 if (valobj.IsDynamic()) { 294 lldb::ValueObjectSP static_value_sp(valobj.GetStaticValue()); 295 if (static_value_sp) 296 GetPossibleMatches( 297 *static_value_sp.get(), static_value_sp->GetCompilerType(), 298 use_dynamic, entries, did_strip_ptr, did_strip_ref, 299 did_strip_typedef, true); 300 } 301 } 302 } 303 304 lldb::TypeFormatImplSP 305 FormatManager::GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp) { 306 if (!type_sp) 307 return lldb::TypeFormatImplSP(); 308 lldb::TypeFormatImplSP format_chosen_sp; 309 uint32_t num_categories = m_categories_map.GetCount(); 310 lldb::TypeCategoryImplSP category_sp; 311 uint32_t prio_category = UINT32_MAX; 312 for (uint32_t category_id = 0; category_id < num_categories; category_id++) { 313 category_sp = GetCategoryAtIndex(category_id); 314 if (!category_sp->IsEnabled()) 315 continue; 316 lldb::TypeFormatImplSP format_current_sp = 317 category_sp->GetFormatForType(type_sp); 318 if (format_current_sp && 319 (format_chosen_sp.get() == nullptr || 320 (prio_category > category_sp->GetEnabledPosition()))) { 321 prio_category = category_sp->GetEnabledPosition(); 322 format_chosen_sp = format_current_sp; 323 } 324 } 325 return format_chosen_sp; 326 } 327 328 lldb::TypeSummaryImplSP 329 FormatManager::GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp) { 330 if (!type_sp) 331 return lldb::TypeSummaryImplSP(); 332 lldb::TypeSummaryImplSP summary_chosen_sp; 333 uint32_t num_categories = m_categories_map.GetCount(); 334 lldb::TypeCategoryImplSP category_sp; 335 uint32_t prio_category = UINT32_MAX; 336 for (uint32_t category_id = 0; category_id < num_categories; category_id++) { 337 category_sp = GetCategoryAtIndex(category_id); 338 if (!category_sp->IsEnabled()) 339 continue; 340 lldb::TypeSummaryImplSP summary_current_sp = 341 category_sp->GetSummaryForType(type_sp); 342 if (summary_current_sp && 343 (summary_chosen_sp.get() == nullptr || 344 (prio_category > category_sp->GetEnabledPosition()))) { 345 prio_category = category_sp->GetEnabledPosition(); 346 summary_chosen_sp = summary_current_sp; 347 } 348 } 349 return summary_chosen_sp; 350 } 351 352 lldb::TypeFilterImplSP 353 FormatManager::GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp) { 354 if (!type_sp) 355 return lldb::TypeFilterImplSP(); 356 lldb::TypeFilterImplSP filter_chosen_sp; 357 uint32_t num_categories = m_categories_map.GetCount(); 358 lldb::TypeCategoryImplSP category_sp; 359 uint32_t prio_category = UINT32_MAX; 360 for (uint32_t category_id = 0; category_id < num_categories; category_id++) { 361 category_sp = GetCategoryAtIndex(category_id); 362 if (!category_sp->IsEnabled()) 363 continue; 364 lldb::TypeFilterImplSP filter_current_sp( 365 (TypeFilterImpl *)category_sp->GetFilterForType(type_sp).get()); 366 if (filter_current_sp && 367 (filter_chosen_sp.get() == nullptr || 368 (prio_category > category_sp->GetEnabledPosition()))) { 369 prio_category = category_sp->GetEnabledPosition(); 370 filter_chosen_sp = filter_current_sp; 371 } 372 } 373 return filter_chosen_sp; 374 } 375 376 lldb::ScriptedSyntheticChildrenSP 377 FormatManager::GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp) { 378 if (!type_sp) 379 return lldb::ScriptedSyntheticChildrenSP(); 380 lldb::ScriptedSyntheticChildrenSP synth_chosen_sp; 381 uint32_t num_categories = m_categories_map.GetCount(); 382 lldb::TypeCategoryImplSP category_sp; 383 uint32_t prio_category = UINT32_MAX; 384 for (uint32_t category_id = 0; category_id < num_categories; category_id++) { 385 category_sp = GetCategoryAtIndex(category_id); 386 if (!category_sp->IsEnabled()) 387 continue; 388 lldb::ScriptedSyntheticChildrenSP synth_current_sp( 389 (ScriptedSyntheticChildren *)category_sp->GetSyntheticForType(type_sp) 390 .get()); 391 if (synth_current_sp && 392 (synth_chosen_sp.get() == nullptr || 393 (prio_category > category_sp->GetEnabledPosition()))) { 394 prio_category = category_sp->GetEnabledPosition(); 395 synth_chosen_sp = synth_current_sp; 396 } 397 } 398 return synth_chosen_sp; 399 } 400 401 void FormatManager::ForEachCategory(TypeCategoryMap::ForEachCallback callback) { 402 m_categories_map.ForEach(callback); 403 std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex); 404 for (const auto &entry : m_language_categories_map) { 405 if (auto category_sp = entry.second->GetCategory()) { 406 if (!callback(category_sp)) 407 break; 408 } 409 } 410 } 411 412 lldb::TypeCategoryImplSP 413 FormatManager::GetCategory(ConstString category_name, bool can_create) { 414 if (!category_name) 415 return GetCategory(m_default_category_name); 416 lldb::TypeCategoryImplSP category; 417 if (m_categories_map.Get(category_name, category)) 418 return category; 419 420 if (!can_create) 421 return lldb::TypeCategoryImplSP(); 422 423 m_categories_map.Add( 424 category_name, 425 lldb::TypeCategoryImplSP(new TypeCategoryImpl(this, category_name))); 426 return GetCategory(category_name); 427 } 428 429 lldb::Format FormatManager::GetSingleItemFormat(lldb::Format vector_format) { 430 switch (vector_format) { 431 case eFormatVectorOfChar: 432 return eFormatCharArray; 433 434 case eFormatVectorOfSInt8: 435 case eFormatVectorOfSInt16: 436 case eFormatVectorOfSInt32: 437 case eFormatVectorOfSInt64: 438 return eFormatDecimal; 439 440 case eFormatVectorOfUInt8: 441 case eFormatVectorOfUInt16: 442 case eFormatVectorOfUInt32: 443 case eFormatVectorOfUInt64: 444 case eFormatVectorOfUInt128: 445 return eFormatHex; 446 447 case eFormatVectorOfFloat16: 448 case eFormatVectorOfFloat32: 449 case eFormatVectorOfFloat64: 450 return eFormatFloat; 451 452 default: 453 return lldb::eFormatInvalid; 454 } 455 } 456 457 bool FormatManager::ShouldPrintAsOneLiner(ValueObject &valobj) { 458 // if settings say no oneline whatsoever 459 if (valobj.GetTargetSP().get() && 460 !valobj.GetTargetSP()->GetDebugger().GetAutoOneLineSummaries()) 461 return false; // then don't oneline 462 463 // if this object has a summary, then ask the summary 464 if (valobj.GetSummaryFormat().get() != nullptr) 465 return valobj.GetSummaryFormat()->IsOneLiner(); 466 467 // no children, no party 468 if (valobj.GetNumChildren() == 0) 469 return false; 470 471 // ask the type if it has any opinion about this eLazyBoolCalculate == no 472 // opinion; other values should be self explanatory 473 CompilerType compiler_type(valobj.GetCompilerType()); 474 if (compiler_type.IsValid()) { 475 switch (compiler_type.ShouldPrintAsOneLiner(&valobj)) { 476 case eLazyBoolNo: 477 return false; 478 case eLazyBoolYes: 479 return true; 480 case eLazyBoolCalculate: 481 break; 482 } 483 } 484 485 size_t total_children_name_len = 0; 486 487 for (size_t idx = 0; idx < valobj.GetNumChildren(); idx++) { 488 bool is_synth_val = false; 489 ValueObjectSP child_sp(valobj.GetChildAtIndex(idx, true)); 490 // something is wrong here - bail out 491 if (!child_sp) 492 return false; 493 494 // also ask the child's type if it has any opinion 495 CompilerType child_compiler_type(child_sp->GetCompilerType()); 496 if (child_compiler_type.IsValid()) { 497 switch (child_compiler_type.ShouldPrintAsOneLiner(child_sp.get())) { 498 case eLazyBoolYes: 499 // an opinion of yes is only binding for the child, so keep going 500 case eLazyBoolCalculate: 501 break; 502 case eLazyBoolNo: 503 // but if the child says no, then it's a veto on the whole thing 504 return false; 505 } 506 } 507 508 // if we decided to define synthetic children for a type, we probably care 509 // enough to show them, but avoid nesting children in children 510 if (child_sp->GetSyntheticChildren().get() != nullptr) { 511 ValueObjectSP synth_sp(child_sp->GetSyntheticValue()); 512 // wait.. wat? just get out of here.. 513 if (!synth_sp) 514 return false; 515 // but if we only have them to provide a value, keep going 516 if (!synth_sp->MightHaveChildren() && 517 synth_sp->DoesProvideSyntheticValue()) 518 is_synth_val = true; 519 else 520 return false; 521 } 522 523 total_children_name_len += child_sp->GetName().GetLength(); 524 525 // 50 itself is a "randomly" chosen number - the idea is that 526 // overly long structs should not get this treatment 527 // FIXME: maybe make this a user-tweakable setting? 528 if (total_children_name_len > 50) 529 return false; 530 531 // if a summary is there.. 532 if (child_sp->GetSummaryFormat()) { 533 // and it wants children, then bail out 534 if (child_sp->GetSummaryFormat()->DoesPrintChildren(child_sp.get())) 535 return false; 536 } 537 538 // if this child has children.. 539 if (child_sp->GetNumChildren()) { 540 // ...and no summary... 541 // (if it had a summary and the summary wanted children, we would have 542 // bailed out anyway 543 // so this only makes us bail out if this has no summary and we would 544 // then print children) 545 if (!child_sp->GetSummaryFormat() && !is_synth_val) // but again only do 546 // that if not a 547 // synthetic valued 548 // child 549 return false; // then bail out 550 } 551 } 552 return true; 553 } 554 555 ConstString FormatManager::GetTypeForCache(ValueObject &valobj, 556 lldb::DynamicValueType use_dynamic) { 557 ValueObjectSP valobj_sp = valobj.GetQualifiedRepresentationIfAvailable( 558 use_dynamic, valobj.IsSynthetic()); 559 if (valobj_sp && valobj_sp->GetCompilerType().IsValid()) { 560 if (!valobj_sp->GetCompilerType().IsMeaninglessWithoutDynamicResolution()) 561 return valobj_sp->GetQualifiedTypeName(); 562 } 563 return ConstString(); 564 } 565 566 std::vector<lldb::LanguageType> 567 FormatManager::GetCandidateLanguages(lldb::LanguageType lang_type) { 568 switch (lang_type) { 569 case lldb::eLanguageTypeC: 570 case lldb::eLanguageTypeC89: 571 case lldb::eLanguageTypeC99: 572 case lldb::eLanguageTypeC11: 573 case lldb::eLanguageTypeC_plus_plus: 574 case lldb::eLanguageTypeC_plus_plus_03: 575 case lldb::eLanguageTypeC_plus_plus_11: 576 case lldb::eLanguageTypeC_plus_plus_14: 577 return {lldb::eLanguageTypeC_plus_plus, lldb::eLanguageTypeObjC}; 578 default: 579 return {lang_type}; 580 } 581 llvm_unreachable("Fully covered switch"); 582 } 583 584 LanguageCategory * 585 FormatManager::GetCategoryForLanguage(lldb::LanguageType lang_type) { 586 std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex); 587 auto iter = m_language_categories_map.find(lang_type), 588 end = m_language_categories_map.end(); 589 if (iter != end) 590 return iter->second.get(); 591 LanguageCategory *lang_category = new LanguageCategory(lang_type); 592 m_language_categories_map[lang_type] = 593 LanguageCategory::UniquePointer(lang_category); 594 return lang_category; 595 } 596 597 template <typename ImplSP> 598 ImplSP FormatManager::GetHardcoded(FormattersMatchData &match_data) { 599 ImplSP retval_sp; 600 for (lldb::LanguageType lang_type : match_data.GetCandidateLanguages()) { 601 if (LanguageCategory *lang_category = GetCategoryForLanguage(lang_type)) { 602 if (lang_category->GetHardcoded(*this, match_data, retval_sp)) 603 return retval_sp; 604 } 605 } 606 return retval_sp; 607 } 608 609 template <typename ImplSP> 610 ImplSP FormatManager::Get(ValueObject &valobj, 611 lldb::DynamicValueType use_dynamic) { 612 FormattersMatchData match_data(valobj, use_dynamic); 613 if (ImplSP retval_sp = GetCached<ImplSP>(match_data)) 614 return retval_sp; 615 616 Log *log = GetLog(LLDBLog::DataFormatters); 617 618 LLDB_LOGF(log, "[%s] Search failed. Giving language a chance.", __FUNCTION__); 619 for (lldb::LanguageType lang_type : match_data.GetCandidateLanguages()) { 620 if (LanguageCategory *lang_category = GetCategoryForLanguage(lang_type)) { 621 ImplSP retval_sp; 622 if (lang_category->Get(match_data, retval_sp)) 623 if (retval_sp) { 624 LLDB_LOGF(log, "[%s] Language search success. Returning.", 625 __FUNCTION__); 626 return retval_sp; 627 } 628 } 629 } 630 631 LLDB_LOGF(log, "[%s] Search failed. Giving hardcoded a chance.", 632 __FUNCTION__); 633 return GetHardcoded<ImplSP>(match_data); 634 } 635 636 template <typename ImplSP> 637 ImplSP FormatManager::GetCached(FormattersMatchData &match_data) { 638 ImplSP retval_sp; 639 Log *log = GetLog(LLDBLog::DataFormatters); 640 if (match_data.GetTypeForCache()) { 641 LLDB_LOGF(log, "\n\n[%s] Looking into cache for type %s", __FUNCTION__, 642 match_data.GetTypeForCache().AsCString("<invalid>")); 643 if (m_format_cache.Get(match_data.GetTypeForCache(), retval_sp)) { 644 if (log) { 645 LLDB_LOGF(log, "[%s] Cache search success. Returning.", __FUNCTION__); 646 LLDB_LOGV(log, "Cache hits: {0} - Cache Misses: {1}", 647 m_format_cache.GetCacheHits(), 648 m_format_cache.GetCacheMisses()); 649 } 650 return retval_sp; 651 } 652 LLDB_LOGF(log, "[%s] Cache search failed. Going normal route", 653 __FUNCTION__); 654 } 655 656 m_categories_map.Get(match_data, retval_sp); 657 if (match_data.GetTypeForCache() && (!retval_sp || !retval_sp->NonCacheable())) { 658 LLDB_LOGF(log, "[%s] Caching %p for type %s", __FUNCTION__, 659 static_cast<void *>(retval_sp.get()), 660 match_data.GetTypeForCache().AsCString("<invalid>")); 661 m_format_cache.Set(match_data.GetTypeForCache(), retval_sp); 662 } 663 LLDB_LOGV(log, "Cache hits: {0} - Cache Misses: {1}", 664 m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses()); 665 return retval_sp; 666 } 667 668 lldb::TypeFormatImplSP 669 FormatManager::GetFormat(ValueObject &valobj, 670 lldb::DynamicValueType use_dynamic) { 671 return Get<lldb::TypeFormatImplSP>(valobj, use_dynamic); 672 } 673 674 lldb::TypeSummaryImplSP 675 FormatManager::GetSummaryFormat(ValueObject &valobj, 676 lldb::DynamicValueType use_dynamic) { 677 return Get<lldb::TypeSummaryImplSP>(valobj, use_dynamic); 678 } 679 680 lldb::SyntheticChildrenSP 681 FormatManager::GetSyntheticChildren(ValueObject &valobj, 682 lldb::DynamicValueType use_dynamic) { 683 return Get<lldb::SyntheticChildrenSP>(valobj, use_dynamic); 684 } 685 686 FormatManager::FormatManager() 687 : m_last_revision(0), m_format_cache(), m_language_categories_mutex(), 688 m_language_categories_map(), m_named_summaries_map(this), 689 m_categories_map(this), m_default_category_name(ConstString("default")), 690 m_system_category_name(ConstString("system")), 691 m_vectortypes_category_name(ConstString("VectorTypes")) { 692 LoadSystemFormatters(); 693 LoadVectorFormatters(); 694 695 EnableCategory(m_vectortypes_category_name, TypeCategoryMap::Last, 696 lldb::eLanguageTypeObjC_plus_plus); 697 EnableCategory(m_system_category_name, TypeCategoryMap::Last, 698 lldb::eLanguageTypeObjC_plus_plus); 699 } 700 701 void FormatManager::LoadSystemFormatters() { 702 TypeSummaryImpl::Flags string_flags; 703 string_flags.SetCascades(true) 704 .SetSkipPointers(true) 705 .SetSkipReferences(false) 706 .SetDontShowChildren(true) 707 .SetDontShowValue(false) 708 .SetShowMembersOneLiner(false) 709 .SetHideItemNames(false); 710 711 TypeSummaryImpl::Flags string_array_flags; 712 string_array_flags.SetCascades(true) 713 .SetSkipPointers(true) 714 .SetSkipReferences(false) 715 .SetDontShowChildren(true) 716 .SetDontShowValue(true) 717 .SetShowMembersOneLiner(false) 718 .SetHideItemNames(false); 719 720 lldb::TypeSummaryImplSP string_format( 721 new StringSummaryFormat(string_flags, "${var%s}")); 722 723 lldb::TypeSummaryImplSP string_array_format( 724 new StringSummaryFormat(string_array_flags, "${var%char[]}")); 725 726 RegularExpression any_size_char_arr(R"(^((un)?signed )?char ?\[[0-9]+\]$)"); 727 728 TypeCategoryImpl::SharedPointer sys_category_sp = 729 GetCategory(m_system_category_name); 730 731 sys_category_sp->GetRegexTypeSummariesContainer()->Add( 732 RegularExpression(R"(^(unsigned )?char ?(\*|\[\])$)"), string_format); 733 734 sys_category_sp->GetRegexTypeSummariesContainer()->Add( 735 std::move(any_size_char_arr), string_array_format); 736 737 lldb::TypeSummaryImplSP ostype_summary( 738 new StringSummaryFormat(TypeSummaryImpl::Flags() 739 .SetCascades(false) 740 .SetSkipPointers(true) 741 .SetSkipReferences(true) 742 .SetDontShowChildren(true) 743 .SetDontShowValue(false) 744 .SetShowMembersOneLiner(false) 745 .SetHideItemNames(false), 746 "${var%O}")); 747 748 sys_category_sp->GetTypeSummariesContainer()->Add(ConstString("OSType"), 749 ostype_summary); 750 751 TypeFormatImpl::Flags fourchar_flags; 752 fourchar_flags.SetCascades(true).SetSkipPointers(true).SetSkipReferences( 753 true); 754 755 AddFormat(sys_category_sp, lldb::eFormatOSType, ConstString("FourCharCode"), 756 fourchar_flags); 757 } 758 759 void FormatManager::LoadVectorFormatters() { 760 TypeCategoryImpl::SharedPointer vectors_category_sp = 761 GetCategory(m_vectortypes_category_name); 762 763 TypeSummaryImpl::Flags vector_flags; 764 vector_flags.SetCascades(true) 765 .SetSkipPointers(true) 766 .SetSkipReferences(false) 767 .SetDontShowChildren(true) 768 .SetDontShowValue(false) 769 .SetShowMembersOneLiner(true) 770 .SetHideItemNames(true); 771 772 AddStringSummary(vectors_category_sp, "${var.uint128}", 773 ConstString("builtin_type_vec128"), vector_flags); 774 AddStringSummary(vectors_category_sp, "", ConstString("float[4]"), 775 vector_flags); 776 AddStringSummary(vectors_category_sp, "", ConstString("int32_t[4]"), 777 vector_flags); 778 AddStringSummary(vectors_category_sp, "", ConstString("int16_t[8]"), 779 vector_flags); 780 AddStringSummary(vectors_category_sp, "", ConstString("vDouble"), 781 vector_flags); 782 AddStringSummary(vectors_category_sp, "", ConstString("vFloat"), 783 vector_flags); 784 AddStringSummary(vectors_category_sp, "", ConstString("vSInt8"), 785 vector_flags); 786 AddStringSummary(vectors_category_sp, "", ConstString("vSInt16"), 787 vector_flags); 788 AddStringSummary(vectors_category_sp, "", ConstString("vSInt32"), 789 vector_flags); 790 AddStringSummary(vectors_category_sp, "", ConstString("vUInt16"), 791 vector_flags); 792 AddStringSummary(vectors_category_sp, "", ConstString("vUInt8"), 793 vector_flags); 794 AddStringSummary(vectors_category_sp, "", ConstString("vUInt16"), 795 vector_flags); 796 AddStringSummary(vectors_category_sp, "", ConstString("vUInt32"), 797 vector_flags); 798 AddStringSummary(vectors_category_sp, "", ConstString("vBool32"), 799 vector_flags); 800 } 801