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