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