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