1 //===-- CPlusPlusLanguage.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 "CPlusPlusLanguage.h" 11 12 // C Includes 13 #include <cctype> 14 #include <cstring> 15 16 // C++ Includes 17 #include <functional> 18 #include <memory> 19 #include <mutex> 20 #include <set> 21 22 // Other libraries and framework includes 23 #include "llvm/ADT/StringRef.h" 24 25 // Project includes 26 #include "lldb/Core/PluginManager.h" 27 #include "lldb/Core/UniqueCStringMap.h" 28 #include "lldb/DataFormatters/CXXFunctionPointer.h" 29 #include "lldb/DataFormatters/DataVisualization.h" 30 #include "lldb/DataFormatters/FormattersHelpers.h" 31 #include "lldb/DataFormatters/VectorType.h" 32 #include "lldb/Utility/ConstString.h" 33 #include "lldb/Utility/FastDemangle.h" 34 #include "lldb/Utility/Log.h" 35 #include "lldb/Utility/RegularExpression.h" 36 37 #include "BlockPointer.h" 38 #include "CPlusPlusNameParser.h" 39 #include "CxxStringTypes.h" 40 #include "LibCxx.h" 41 #include "LibCxxAtomic.h" 42 #include "LibStdcpp.h" 43 44 using namespace lldb; 45 using namespace lldb_private; 46 using namespace lldb_private::formatters; 47 48 void CPlusPlusLanguage::Initialize() { 49 PluginManager::RegisterPlugin(GetPluginNameStatic(), "C++ Language", 50 CreateInstance); 51 } 52 53 void CPlusPlusLanguage::Terminate() { 54 PluginManager::UnregisterPlugin(CreateInstance); 55 } 56 57 lldb_private::ConstString CPlusPlusLanguage::GetPluginNameStatic() { 58 static ConstString g_name("cplusplus"); 59 return g_name; 60 } 61 62 //------------------------------------------------------------------ 63 // PluginInterface protocol 64 //------------------------------------------------------------------ 65 66 lldb_private::ConstString CPlusPlusLanguage::GetPluginName() { 67 return GetPluginNameStatic(); 68 } 69 70 uint32_t CPlusPlusLanguage::GetPluginVersion() { return 1; } 71 72 //------------------------------------------------------------------ 73 // Static Functions 74 //------------------------------------------------------------------ 75 76 Language *CPlusPlusLanguage::CreateInstance(lldb::LanguageType language) { 77 if (Language::LanguageIsCPlusPlus(language)) 78 return new CPlusPlusLanguage(); 79 return nullptr; 80 } 81 82 void CPlusPlusLanguage::MethodName::Clear() { 83 m_full.Clear(); 84 m_basename = llvm::StringRef(); 85 m_context = llvm::StringRef(); 86 m_arguments = llvm::StringRef(); 87 m_qualifiers = llvm::StringRef(); 88 m_parsed = false; 89 m_parse_error = false; 90 } 91 92 static bool ReverseFindMatchingChars(const llvm::StringRef &s, 93 const llvm::StringRef &left_right_chars, 94 size_t &left_pos, size_t &right_pos, 95 size_t pos = llvm::StringRef::npos) { 96 assert(left_right_chars.size() == 2); 97 left_pos = llvm::StringRef::npos; 98 const char left_char = left_right_chars[0]; 99 const char right_char = left_right_chars[1]; 100 pos = s.find_last_of(left_right_chars, pos); 101 if (pos == llvm::StringRef::npos || s[pos] == left_char) 102 return false; 103 right_pos = pos; 104 uint32_t depth = 1; 105 while (pos > 0 && depth > 0) { 106 pos = s.find_last_of(left_right_chars, pos); 107 if (pos == llvm::StringRef::npos) 108 return false; 109 if (s[pos] == left_char) { 110 if (--depth == 0) { 111 left_pos = pos; 112 return left_pos < right_pos; 113 } 114 } else if (s[pos] == right_char) { 115 ++depth; 116 } 117 } 118 return false; 119 } 120 121 static bool IsTrivialBasename(const llvm::StringRef &basename) { 122 // Check that the basename matches with the following regular expression 123 // "^~?([A-Za-z_][A-Za-z_0-9]*)$" 124 // We are using a hand written implementation because it is significantly more 125 // efficient then 126 // using the general purpose regular expression library. 127 size_t idx = 0; 128 if (basename.size() > 0 && basename[0] == '~') 129 idx = 1; 130 131 if (basename.size() <= idx) 132 return false; // Empty string or "~" 133 134 if (!std::isalpha(basename[idx]) && basename[idx] != '_') 135 return false; // First charater (after removing the possible '~'') isn't in 136 // [A-Za-z_] 137 138 // Read all characters matching [A-Za-z_0-9] 139 ++idx; 140 while (idx < basename.size()) { 141 if (!std::isalnum(basename[idx]) && basename[idx] != '_') 142 break; 143 ++idx; 144 } 145 146 // We processed all characters. It is a vaild basename. 147 if (idx == basename.size()) 148 return true; 149 150 return false; 151 } 152 153 bool CPlusPlusLanguage::MethodName::TrySimplifiedParse() { 154 // This method tries to parse simple method definitions 155 // which are presumably most comman in user programs. 156 // Definitions that can be parsed by this function don't have return types 157 // and templates in the name. 158 // A::B::C::fun(std::vector<T> &) const 159 size_t arg_start, arg_end; 160 llvm::StringRef full(m_full.GetCString()); 161 llvm::StringRef parens("()", 2); 162 if (ReverseFindMatchingChars(full, parens, arg_start, arg_end)) { 163 m_arguments = full.substr(arg_start, arg_end - arg_start + 1); 164 if (arg_end + 1 < full.size()) 165 m_qualifiers = full.substr(arg_end + 1).ltrim(); 166 167 if (arg_start == 0) 168 return false; 169 size_t basename_end = arg_start; 170 size_t context_start = 0; 171 size_t context_end = full.rfind(':', basename_end); 172 if (context_end == llvm::StringRef::npos) 173 m_basename = full.substr(0, basename_end); 174 else { 175 if (context_start < context_end) 176 m_context = full.substr(context_start, context_end - 1 - context_start); 177 const size_t basename_begin = context_end + 1; 178 m_basename = full.substr(basename_begin, basename_end - basename_begin); 179 } 180 181 if (IsTrivialBasename(m_basename)) { 182 return true; 183 } else { 184 // The C++ basename doesn't match our regular expressions so this can't 185 // be a valid C++ method, clear everything out and indicate an error 186 m_context = llvm::StringRef(); 187 m_basename = llvm::StringRef(); 188 m_arguments = llvm::StringRef(); 189 m_qualifiers = llvm::StringRef(); 190 return false; 191 } 192 } 193 return false; 194 } 195 196 void CPlusPlusLanguage::MethodName::Parse() { 197 if (!m_parsed && m_full) { 198 if (TrySimplifiedParse()) { 199 m_parse_error = false; 200 } else { 201 CPlusPlusNameParser parser(m_full.GetStringRef()); 202 if (auto function = parser.ParseAsFunctionDefinition()) { 203 m_basename = function.getValue().name.basename; 204 m_context = function.getValue().name.context; 205 m_arguments = function.getValue().arguments; 206 m_qualifiers = function.getValue().qualifiers; 207 m_parse_error = false; 208 } else { 209 m_parse_error = true; 210 } 211 } 212 m_parsed = true; 213 } 214 } 215 216 llvm::StringRef CPlusPlusLanguage::MethodName::GetBasename() { 217 if (!m_parsed) 218 Parse(); 219 return m_basename; 220 } 221 222 llvm::StringRef CPlusPlusLanguage::MethodName::GetContext() { 223 if (!m_parsed) 224 Parse(); 225 return m_context; 226 } 227 228 llvm::StringRef CPlusPlusLanguage::MethodName::GetArguments() { 229 if (!m_parsed) 230 Parse(); 231 return m_arguments; 232 } 233 234 llvm::StringRef CPlusPlusLanguage::MethodName::GetQualifiers() { 235 if (!m_parsed) 236 Parse(); 237 return m_qualifiers; 238 } 239 240 std::string CPlusPlusLanguage::MethodName::GetScopeQualifiedName() { 241 if (!m_parsed) 242 Parse(); 243 if (m_context.empty()) 244 return m_basename; 245 246 std::string res; 247 res += m_context; 248 res += "::"; 249 res += m_basename; 250 return res; 251 } 252 253 bool CPlusPlusLanguage::IsCPPMangledName(const char *name) { 254 // FIXME, we should really run through all the known C++ Language plugins and 255 // ask each one if 256 // this is a C++ mangled name, but we can put that off till there is actually 257 // more than one 258 // we care about. 259 260 return (name != nullptr && name[0] == '_' && name[1] == 'Z'); 261 } 262 263 bool CPlusPlusLanguage::ExtractContextAndIdentifier( 264 const char *name, llvm::StringRef &context, llvm::StringRef &identifier) { 265 CPlusPlusNameParser parser(name); 266 if (auto full_name = parser.ParseAsFullName()) { 267 identifier = full_name.getValue().basename; 268 context = full_name.getValue().context; 269 return true; 270 } 271 return false; 272 } 273 274 class CPPRuntimeEquivalents { 275 public: 276 CPPRuntimeEquivalents() { 277 m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, " 278 "std::allocator<char> >") 279 .GetStringRef(), 280 ConstString("basic_string<char>")); 281 282 // these two (with a prefixed std::) occur when c++stdlib string class 283 // occurs as a template argument in some STL container 284 m_impl.Append(ConstString("std::basic_string<char, std::char_traits<char>, " 285 "std::allocator<char> >") 286 .GetStringRef(), 287 ConstString("std::basic_string<char>")); 288 289 m_impl.Sort(); 290 } 291 292 void Add(ConstString &type_name, ConstString &type_equivalent) { 293 m_impl.Insert(type_name.GetStringRef(), type_equivalent); 294 } 295 296 uint32_t FindExactMatches(ConstString &type_name, 297 std::vector<ConstString> &equivalents) { 298 uint32_t count = 0; 299 300 for (ImplData match = 301 m_impl.FindFirstValueForName(type_name.GetStringRef()); 302 match != nullptr; match = m_impl.FindNextValueForName(match)) { 303 equivalents.push_back(match->value); 304 count++; 305 } 306 307 return count; 308 } 309 310 // partial matches can occur when a name with equivalents is a template 311 // argument. 312 // e.g. we may have "class Foo" be a match for "struct Bar". if we have a 313 // typename 314 // such as "class Templatized<class Foo, Anything>" we want this to be 315 // replaced with 316 // "class Templatized<struct Bar, Anything>". Since partial matching is time 317 // consuming 318 // once we get a partial match, we add it to the exact matches list for faster 319 // retrieval 320 uint32_t FindPartialMatches(ConstString &type_name, 321 std::vector<ConstString> &equivalents) { 322 uint32_t count = 0; 323 324 llvm::StringRef type_name_cstr = type_name.GetStringRef(); 325 326 size_t items_count = m_impl.GetSize(); 327 328 for (size_t item = 0; item < items_count; item++) { 329 llvm::StringRef key_cstr = m_impl.GetCStringAtIndex(item); 330 if (type_name_cstr.contains(key_cstr)) { 331 count += AppendReplacements(type_name_cstr, key_cstr, equivalents); 332 } 333 } 334 335 return count; 336 } 337 338 private: 339 std::string &replace(std::string &target, std::string &pattern, 340 std::string &with) { 341 size_t pos; 342 size_t pattern_len = pattern.size(); 343 344 while ((pos = target.find(pattern)) != std::string::npos) 345 target.replace(pos, pattern_len, with); 346 347 return target; 348 } 349 350 uint32_t AppendReplacements(llvm::StringRef original, 351 llvm::StringRef matching_key, 352 std::vector<ConstString> &equivalents) { 353 std::string matching_key_str(matching_key); 354 ConstString original_const(original); 355 356 uint32_t count = 0; 357 358 for (ImplData match = m_impl.FindFirstValueForName(matching_key); 359 match != nullptr; match = m_impl.FindNextValueForName(match)) { 360 std::string target(original); 361 std::string equiv_class(match->value.AsCString()); 362 363 replace(target, matching_key_str, equiv_class); 364 365 ConstString target_const(target.c_str()); 366 367 // you will most probably want to leave this off since it might make this map 368 // grow indefinitely 369 #ifdef ENABLE_CPP_EQUIVALENTS_MAP_TO_GROW 370 Add(original_const, target_const); 371 #endif 372 equivalents.push_back(target_const); 373 374 count++; 375 } 376 377 return count; 378 } 379 380 typedef UniqueCStringMap<ConstString> Impl; 381 typedef const Impl::Entry *ImplData; 382 Impl m_impl; 383 }; 384 385 static CPPRuntimeEquivalents &GetEquivalentsMap() { 386 static CPPRuntimeEquivalents g_equivalents_map; 387 return g_equivalents_map; 388 } 389 390 uint32_t 391 CPlusPlusLanguage::FindEquivalentNames(ConstString type_name, 392 std::vector<ConstString> &equivalents) { 393 uint32_t count = GetEquivalentsMap().FindExactMatches(type_name, equivalents); 394 395 bool might_have_partials = 396 (count == 0) // if we have a full name match just use it 397 && (strchr(type_name.AsCString(), '<') != 398 nullptr // we should only have partial matches when templates are 399 // involved, check that we have 400 && strchr(type_name.AsCString(), '>') != nullptr); // angle brackets 401 // in the type_name 402 // before trying to 403 // scan for partial 404 // matches 405 406 if (might_have_partials) 407 count = GetEquivalentsMap().FindPartialMatches(type_name, equivalents); 408 409 return count; 410 } 411 412 /// Given a mangled function `mangled`, replace all the primitive function type 413 /// arguments of `search` with type `replace`. 414 static ConstString SubsPrimitiveParmItanium(llvm::StringRef mangled, 415 llvm::StringRef search, 416 llvm::StringRef replace) { 417 Log *log = GetLogIfAllCategoriesSet(LIBLLDB_LOG_LANGUAGE); 418 419 const size_t max_len = 420 mangled.size() + mangled.count(search) * replace.size() + 1; 421 422 // Make a temporary buffer to fix up the mangled parameter types and copy the 423 // original there 424 std::string output_buf; 425 output_buf.reserve(max_len); 426 output_buf.insert(0, mangled.str()); 427 ptrdiff_t replaced_offset = 0; 428 429 auto swap_parms_hook = [&](const char *parsee) { 430 if (!parsee || !*parsee) 431 return; 432 433 // Check whether we've found a substitutee 434 llvm::StringRef s(parsee); 435 if (s.startswith(search)) { 436 // account for the case where a replacement is of a different length to 437 // the original 438 replaced_offset += replace.size() - search.size(); 439 440 ptrdiff_t replace_idx = (mangled.size() - s.size()) + replaced_offset; 441 output_buf.erase(replace_idx, search.size()); 442 output_buf.insert(replace_idx, replace.str()); 443 } 444 }; 445 446 // FastDemangle will call our hook for each instance of a primitive type, 447 // allowing us to perform substitution 448 const char *const demangled = 449 FastDemangle(mangled.str().c_str(), mangled.size(), swap_parms_hook); 450 451 if (log) 452 log->Printf("substituted mangling for %s:{%s} %s:{%s}\n", 453 mangled.str().c_str(), demangled, output_buf.c_str(), 454 FastDemangle(output_buf.c_str())); 455 456 return output_buf == mangled ? ConstString() : ConstString(output_buf); 457 } 458 459 uint32_t CPlusPlusLanguage::FindAlternateFunctionManglings( 460 const ConstString mangled_name, std::set<ConstString> &alternates) { 461 const auto start_size = alternates.size(); 462 /// Get a basic set of alternative manglings for the given symbol `name`, by 463 /// making a few basic possible substitutions on basic types, storage duration 464 /// and `const`ness for the given symbol. The output parameter `alternates` 465 /// is filled with a best-guess, non-exhaustive set of different manglings 466 /// for the given name. 467 468 // Maybe we're looking for a const symbol but the debug info told us it was 469 // non-const... 470 if (!strncmp(mangled_name.GetCString(), "_ZN", 3) && 471 strncmp(mangled_name.GetCString(), "_ZNK", 4)) { 472 std::string fixed_scratch("_ZNK"); 473 fixed_scratch.append(mangled_name.GetCString() + 3); 474 alternates.insert(ConstString(fixed_scratch)); 475 } 476 477 // Maybe we're looking for a static symbol but we thought it was global... 478 if (!strncmp(mangled_name.GetCString(), "_Z", 2) && 479 strncmp(mangled_name.GetCString(), "_ZL", 3)) { 480 std::string fixed_scratch("_ZL"); 481 fixed_scratch.append(mangled_name.GetCString() + 2); 482 alternates.insert(ConstString(fixed_scratch)); 483 } 484 485 // `char` is implementation defined as either `signed` or `unsigned`. As a 486 // result a char parameter has 3 possible manglings: 'c'-char, 'a'-signed 487 // char, 'h'-unsigned char. If we're looking for symbols with a signed char 488 // parameter, try finding matches which have the general case 'c'. 489 if (ConstString char_fixup = 490 SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "a", "c")) 491 alternates.insert(char_fixup); 492 493 // long long parameter mangling 'x', may actually just be a long 'l' argument 494 if (ConstString long_fixup = 495 SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "x", "l")) 496 alternates.insert(long_fixup); 497 498 // unsigned long long parameter mangling 'y', may actually just be unsigned 499 // long 'm' argument 500 if (ConstString ulong_fixup = 501 SubsPrimitiveParmItanium(mangled_name.GetStringRef(), "y", "m")) 502 alternates.insert(ulong_fixup); 503 504 return alternates.size() - start_size; 505 } 506 507 static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { 508 if (!cpp_category_sp) 509 return; 510 511 TypeSummaryImpl::Flags stl_summary_flags; 512 stl_summary_flags.SetCascades(true) 513 .SetSkipPointers(false) 514 .SetSkipReferences(false) 515 .SetDontShowChildren(true) 516 .SetDontShowValue(true) 517 .SetShowMembersOneLiner(false) 518 .SetHideItemNames(false); 519 520 #ifndef LLDB_DISABLE_PYTHON 521 lldb::TypeSummaryImplSP std_string_summary_sp(new CXXFunctionSummaryFormat( 522 stl_summary_flags, lldb_private::formatters::LibcxxStringSummaryProvider, 523 "std::string summary provider")); 524 lldb::TypeSummaryImplSP std_wstring_summary_sp(new CXXFunctionSummaryFormat( 525 stl_summary_flags, lldb_private::formatters::LibcxxWStringSummaryProvider, 526 "std::wstring summary provider")); 527 528 cpp_category_sp->GetTypeSummariesContainer()->Add( 529 ConstString("std::__1::string"), std_string_summary_sp); 530 cpp_category_sp->GetTypeSummariesContainer()->Add( 531 ConstString("std::__ndk1::string"), std_string_summary_sp); 532 cpp_category_sp->GetTypeSummariesContainer()->Add( 533 ConstString("std::__1::basic_string<char, std::__1::char_traits<char>, " 534 "std::__1::allocator<char> >"), 535 std_string_summary_sp); 536 cpp_category_sp->GetTypeSummariesContainer()->Add( 537 ConstString("std::__ndk1::basic_string<char, " 538 "std::__ndk1::char_traits<char>, " 539 "std::__ndk1::allocator<char> >"), 540 std_string_summary_sp); 541 542 cpp_category_sp->GetTypeSummariesContainer()->Add( 543 ConstString("std::__1::wstring"), std_wstring_summary_sp); 544 cpp_category_sp->GetTypeSummariesContainer()->Add( 545 ConstString("std::__ndk1::wstring"), std_wstring_summary_sp); 546 cpp_category_sp->GetTypeSummariesContainer()->Add( 547 ConstString("std::__1::basic_string<wchar_t, " 548 "std::__1::char_traits<wchar_t>, " 549 "std::__1::allocator<wchar_t> >"), 550 std_wstring_summary_sp); 551 cpp_category_sp->GetTypeSummariesContainer()->Add( 552 ConstString("std::__ndk1::basic_string<wchar_t, " 553 "std::__ndk1::char_traits<wchar_t>, " 554 "std::__ndk1::allocator<wchar_t> >"), 555 std_wstring_summary_sp); 556 557 SyntheticChildren::Flags stl_synth_flags; 558 stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences( 559 false); 560 561 AddCXXSynthetic( 562 cpp_category_sp, 563 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator, 564 "libc++ std::vector synthetic children", 565 ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"), stl_synth_flags, 566 true); 567 AddCXXSynthetic( 568 cpp_category_sp, 569 lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator, 570 "libc++ std::list synthetic children", 571 ConstString("^std::__(ndk)?1::list<.+>(( )?&)?$"), stl_synth_flags, true); 572 AddCXXSynthetic( 573 cpp_category_sp, 574 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, 575 "libc++ std::map synthetic children", 576 ConstString("^std::__(ndk)?1::map<.+> >(( )?&)?$"), stl_synth_flags, 577 true); 578 AddCXXSynthetic( 579 cpp_category_sp, 580 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, 581 "libc++ std::set synthetic children", 582 ConstString("^std::__(ndk)?1::set<.+> >(( )?&)?$"), stl_synth_flags, 583 true); 584 AddCXXSynthetic( 585 cpp_category_sp, 586 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, 587 "libc++ std::multiset synthetic children", 588 ConstString("^std::__(ndk)?1::multiset<.+> >(( )?&)?$"), stl_synth_flags, 589 true); 590 AddCXXSynthetic( 591 cpp_category_sp, 592 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, 593 "libc++ std::multimap synthetic children", 594 ConstString("^std::__(ndk)?1::multimap<.+> >(( )?&)?$"), stl_synth_flags, 595 true); 596 AddCXXSynthetic( 597 cpp_category_sp, 598 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator, 599 "libc++ std::unordered containers synthetic children", 600 ConstString("^(std::__(ndk)?1::)unordered_(multi)?(map|set)<.+> >$"), 601 stl_synth_flags, true); 602 AddCXXSynthetic( 603 cpp_category_sp, 604 lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator, 605 "libc++ std::initializer_list synthetic children", 606 ConstString("^std::initializer_list<.+>(( )?&)?$"), stl_synth_flags, 607 true); 608 AddCXXSynthetic( 609 cpp_category_sp, 610 lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator, 611 "libc++ std::atomic synthetic children", 612 ConstString("^std::__(ndk)?1::atomic<.+>$"), stl_synth_flags, true); 613 614 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( 615 RegularExpressionSP(new RegularExpression( 616 llvm::StringRef("^(std::__(ndk)?1::)deque<.+>(( )?&)?$"))), 617 SyntheticChildrenSP(new ScriptedSyntheticChildren( 618 stl_synth_flags, 619 "lldb.formatters.cpp.libcxx.stddeque_SynthProvider"))); 620 621 AddCXXSynthetic( 622 cpp_category_sp, 623 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, 624 "shared_ptr synthetic children", 625 ConstString("^(std::__(ndk)?1::)shared_ptr<.+>(( )?&)?$"), 626 stl_synth_flags, true); 627 AddCXXSynthetic( 628 cpp_category_sp, 629 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, 630 "weak_ptr synthetic children", 631 ConstString("^(std::__(ndk)?1::)weak_ptr<.+>(( )?&)?$"), stl_synth_flags, 632 true); 633 634 stl_summary_flags.SetDontShowChildren(false); 635 stl_summary_flags.SetSkipPointers(false); 636 AddCXXSummary(cpp_category_sp, 637 lldb_private::formatters::LibcxxContainerSummaryProvider, 638 "libc++ std::vector summary provider", 639 ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"), 640 stl_summary_flags, true); 641 AddCXXSummary(cpp_category_sp, 642 lldb_private::formatters::LibcxxContainerSummaryProvider, 643 "libc++ std::list summary provider", 644 ConstString("^std::__(ndk)?1::list<.+>(( )?&)?$"), 645 stl_summary_flags, true); 646 AddCXXSummary(cpp_category_sp, 647 lldb_private::formatters::LibcxxContainerSummaryProvider, 648 "libc++ std::map summary provider", 649 ConstString("^std::__(ndk)?1::map<.+>(( )?&)?$"), 650 stl_summary_flags, true); 651 AddCXXSummary(cpp_category_sp, 652 lldb_private::formatters::LibcxxContainerSummaryProvider, 653 "libc++ std::deque summary provider", 654 ConstString("^std::__(ndk)?1::deque<.+>(( )?&)?$"), 655 stl_summary_flags, true); 656 AddCXXSummary(cpp_category_sp, 657 lldb_private::formatters::LibcxxContainerSummaryProvider, 658 "libc++ std::set summary provider", 659 ConstString("^std::__(ndk)?1::set<.+>(( )?&)?$"), 660 stl_summary_flags, true); 661 AddCXXSummary(cpp_category_sp, 662 lldb_private::formatters::LibcxxContainerSummaryProvider, 663 "libc++ std::multiset summary provider", 664 ConstString("^std::__(ndk)?1::multiset<.+>(( )?&)?$"), 665 stl_summary_flags, true); 666 AddCXXSummary(cpp_category_sp, 667 lldb_private::formatters::LibcxxContainerSummaryProvider, 668 "libc++ std::multimap summary provider", 669 ConstString("^std::__(ndk)?1::multimap<.+>(( )?&)?$"), 670 stl_summary_flags, true); 671 AddCXXSummary( 672 cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, 673 "libc++ std::unordered containers summary provider", 674 ConstString("^(std::__(ndk)?1::)unordered_(multi)?(map|set)<.+> >$"), 675 stl_summary_flags, true); 676 AddCXXSummary( 677 cpp_category_sp, lldb_private::formatters::LibCxxAtomicSummaryProvider, 678 "libc++ std::atomic summary provider", 679 ConstString("^std::__(ndk)?1::atomic<.+>$"), stl_summary_flags, true); 680 681 stl_summary_flags.SetSkipPointers(true); 682 683 AddCXXSummary(cpp_category_sp, 684 lldb_private::formatters::LibcxxSmartPointerSummaryProvider, 685 "libc++ std::shared_ptr summary provider", 686 ConstString("^std::__(ndk)?1::shared_ptr<.+>(( )?&)?$"), 687 stl_summary_flags, true); 688 AddCXXSummary(cpp_category_sp, 689 lldb_private::formatters::LibcxxSmartPointerSummaryProvider, 690 "libc++ std::weak_ptr summary provider", 691 ConstString("^std::__(ndk)?1::weak_ptr<.+>(( )?&)?$"), 692 stl_summary_flags, true); 693 694 AddCXXSynthetic( 695 cpp_category_sp, 696 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator, 697 "std::vector iterator synthetic children", 698 ConstString("^std::__(ndk)?1::__wrap_iter<.+>$"), stl_synth_flags, true); 699 700 AddCXXSynthetic( 701 cpp_category_sp, 702 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator, 703 "std::map iterator synthetic children", 704 ConstString("^std::__(ndk)?1::__map_iterator<.+>$"), stl_synth_flags, 705 true); 706 707 AddCXXSynthetic( 708 cpp_category_sp, lldb_private::formatters::LibcxxFunctionFrontEndCreator, 709 "std::function synthetic value provider", 710 ConstString("^std::__1::function<.+>$"), stl_synth_flags, true); 711 #endif 712 } 713 714 static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { 715 if (!cpp_category_sp) 716 return; 717 718 TypeSummaryImpl::Flags stl_summary_flags; 719 stl_summary_flags.SetCascades(true) 720 .SetSkipPointers(false) 721 .SetSkipReferences(false) 722 .SetDontShowChildren(true) 723 .SetDontShowValue(true) 724 .SetShowMembersOneLiner(false) 725 .SetHideItemNames(false); 726 727 lldb::TypeSummaryImplSP std_string_summary_sp( 728 new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p}")); 729 730 lldb::TypeSummaryImplSP cxx11_string_summary_sp(new CXXFunctionSummaryFormat( 731 stl_summary_flags, LibStdcppStringSummaryProvider, 732 "libstdc++ c++11 std::string summary provider")); 733 lldb::TypeSummaryImplSP cxx11_wstring_summary_sp(new CXXFunctionSummaryFormat( 734 stl_summary_flags, LibStdcppWStringSummaryProvider, 735 "libstdc++ c++11 std::wstring summary provider")); 736 737 cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::string"), 738 std_string_summary_sp); 739 cpp_category_sp->GetTypeSummariesContainer()->Add( 740 ConstString("std::basic_string<char>"), std_string_summary_sp); 741 cpp_category_sp->GetTypeSummariesContainer()->Add( 742 ConstString("std::basic_string<char,std::char_traits<char>,std::" 743 "allocator<char> >"), 744 std_string_summary_sp); 745 cpp_category_sp->GetTypeSummariesContainer()->Add( 746 ConstString("std::basic_string<char, std::char_traits<char>, " 747 "std::allocator<char> >"), 748 std_string_summary_sp); 749 750 cpp_category_sp->GetTypeSummariesContainer()->Add( 751 ConstString("std::__cxx11::string"), cxx11_string_summary_sp); 752 cpp_category_sp->GetTypeSummariesContainer()->Add( 753 ConstString("std::__cxx11::basic_string<char, std::char_traits<char>, " 754 "std::allocator<char> >"), 755 cxx11_string_summary_sp); 756 757 // making sure we force-pick the summary for printing wstring (_M_p is a 758 // wchar_t*) 759 lldb::TypeSummaryImplSP std_wstring_summary_sp( 760 new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p%S}")); 761 762 cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::wstring"), 763 std_wstring_summary_sp); 764 cpp_category_sp->GetTypeSummariesContainer()->Add( 765 ConstString("std::basic_string<wchar_t>"), std_wstring_summary_sp); 766 cpp_category_sp->GetTypeSummariesContainer()->Add( 767 ConstString("std::basic_string<wchar_t,std::char_traits<wchar_t>,std::" 768 "allocator<wchar_t> >"), 769 std_wstring_summary_sp); 770 cpp_category_sp->GetTypeSummariesContainer()->Add( 771 ConstString("std::basic_string<wchar_t, std::char_traits<wchar_t>, " 772 "std::allocator<wchar_t> >"), 773 std_wstring_summary_sp); 774 775 cpp_category_sp->GetTypeSummariesContainer()->Add( 776 ConstString("std::__cxx11::wstring"), cxx11_wstring_summary_sp); 777 cpp_category_sp->GetTypeSummariesContainer()->Add( 778 ConstString("std::__cxx11::basic_string<wchar_t, " 779 "std::char_traits<wchar_t>, std::allocator<wchar_t> >"), 780 cxx11_wstring_summary_sp); 781 782 #ifndef LLDB_DISABLE_PYTHON 783 784 SyntheticChildren::Flags stl_synth_flags; 785 stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences( 786 false); 787 788 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( 789 RegularExpressionSP( 790 new RegularExpression(llvm::StringRef("^std::vector<.+>(( )?&)?$"))), 791 SyntheticChildrenSP(new ScriptedSyntheticChildren( 792 stl_synth_flags, 793 "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider"))); 794 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( 795 RegularExpressionSP( 796 new RegularExpression(llvm::StringRef("^std::map<.+> >(( )?&)?$"))), 797 SyntheticChildrenSP(new ScriptedSyntheticChildren( 798 stl_synth_flags, 799 "lldb.formatters.cpp.gnu_libstdcpp.StdMapSynthProvider"))); 800 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( 801 RegularExpressionSP(new RegularExpression( 802 llvm::StringRef("^std::(__cxx11::)?list<.+>(( )?&)?$"))), 803 SyntheticChildrenSP(new ScriptedSyntheticChildren( 804 stl_synth_flags, 805 "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider"))); 806 stl_summary_flags.SetDontShowChildren(false); 807 stl_summary_flags.SetSkipPointers(true); 808 cpp_category_sp->GetRegexTypeSummariesContainer()->Add( 809 RegularExpressionSP( 810 new RegularExpression(llvm::StringRef("^std::vector<.+>(( )?&)?$"))), 811 TypeSummaryImplSP( 812 new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); 813 cpp_category_sp->GetRegexTypeSummariesContainer()->Add( 814 RegularExpressionSP( 815 new RegularExpression(llvm::StringRef("^std::map<.+> >(( )?&)?$"))), 816 TypeSummaryImplSP( 817 new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); 818 cpp_category_sp->GetRegexTypeSummariesContainer()->Add( 819 RegularExpressionSP(new RegularExpression( 820 llvm::StringRef("^std::(__cxx11::)?list<.+>(( )?&)?$"))), 821 TypeSummaryImplSP( 822 new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); 823 824 AddCXXSynthetic( 825 cpp_category_sp, 826 lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator, 827 "std::vector iterator synthetic children", 828 ConstString("^__gnu_cxx::__normal_iterator<.+>$"), stl_synth_flags, true); 829 830 AddCXXSynthetic( 831 cpp_category_sp, 832 lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator, 833 "std::map iterator synthetic children", 834 ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true); 835 836 AddCXXSynthetic( 837 cpp_category_sp, 838 lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator, 839 "std::unique_ptr synthetic children", 840 ConstString("^std::unique_ptr<.+>(( )?&)?$"), stl_synth_flags, true); 841 AddCXXSynthetic( 842 cpp_category_sp, 843 lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator, 844 "std::shared_ptr synthetic children", 845 ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true); 846 AddCXXSynthetic( 847 cpp_category_sp, 848 lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator, 849 "std::weak_ptr synthetic children", 850 ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true); 851 AddCXXSynthetic( 852 cpp_category_sp, 853 lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator, 854 "std::tuple synthetic children", ConstString("^std::tuple<.+>(( )?&)?$"), 855 stl_synth_flags, true); 856 857 AddCXXSummary(cpp_category_sp, 858 lldb_private::formatters::LibStdcppUniquePointerSummaryProvider, 859 "libstdc++ std::unique_ptr summary provider", 860 ConstString("^std::unique_ptr<.+>(( )?&)?$"), stl_summary_flags, 861 true); 862 AddCXXSummary(cpp_category_sp, 863 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider, 864 "libstdc++ std::shared_ptr summary provider", 865 ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_summary_flags, 866 true); 867 AddCXXSummary(cpp_category_sp, 868 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider, 869 "libstdc++ std::weak_ptr summary provider", 870 ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, 871 true); 872 #endif 873 } 874 875 static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { 876 if (!cpp_category_sp) 877 return; 878 879 TypeSummaryImpl::Flags string_flags; 880 string_flags.SetCascades(true) 881 .SetSkipPointers(true) 882 .SetSkipReferences(false) 883 .SetDontShowChildren(true) 884 .SetDontShowValue(false) 885 .SetShowMembersOneLiner(false) 886 .SetHideItemNames(false); 887 888 TypeSummaryImpl::Flags string_array_flags; 889 string_array_flags.SetCascades(true) 890 .SetSkipPointers(true) 891 .SetSkipReferences(false) 892 .SetDontShowChildren(true) 893 .SetDontShowValue(true) 894 .SetShowMembersOneLiner(false) 895 .SetHideItemNames(false); 896 897 #ifndef LLDB_DISABLE_PYTHON 898 // FIXME because of a bug in the FormattersContainer we need to add a summary 899 // for both X* and const X* (<rdar://problem/12717717>) 900 AddCXXSummary( 901 cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider, 902 "char16_t * summary provider", ConstString("char16_t *"), string_flags); 903 AddCXXSummary(cpp_category_sp, 904 lldb_private::formatters::Char16StringSummaryProvider, 905 "char16_t [] summary provider", 906 ConstString("char16_t \\[[0-9]+\\]"), string_array_flags, true); 907 908 AddCXXSummary( 909 cpp_category_sp, lldb_private::formatters::Char32StringSummaryProvider, 910 "char32_t * summary provider", ConstString("char32_t *"), string_flags); 911 AddCXXSummary(cpp_category_sp, 912 lldb_private::formatters::Char32StringSummaryProvider, 913 "char32_t [] summary provider", 914 ConstString("char32_t \\[[0-9]+\\]"), string_array_flags, true); 915 916 AddCXXSummary( 917 cpp_category_sp, lldb_private::formatters::WCharStringSummaryProvider, 918 "wchar_t * summary provider", ConstString("wchar_t *"), string_flags); 919 AddCXXSummary(cpp_category_sp, 920 lldb_private::formatters::WCharStringSummaryProvider, 921 "wchar_t * summary provider", 922 ConstString("wchar_t \\[[0-9]+\\]"), string_array_flags, true); 923 924 AddCXXSummary( 925 cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider, 926 "unichar * summary provider", ConstString("unichar *"), string_flags); 927 928 TypeSummaryImpl::Flags widechar_flags; 929 widechar_flags.SetDontShowValue(true) 930 .SetSkipPointers(true) 931 .SetSkipReferences(false) 932 .SetCascades(true) 933 .SetDontShowChildren(true) 934 .SetHideItemNames(true) 935 .SetShowMembersOneLiner(false); 936 937 AddCXXSummary( 938 cpp_category_sp, lldb_private::formatters::Char16SummaryProvider, 939 "char16_t summary provider", ConstString("char16_t"), widechar_flags); 940 AddCXXSummary( 941 cpp_category_sp, lldb_private::formatters::Char32SummaryProvider, 942 "char32_t summary provider", ConstString("char32_t"), widechar_flags); 943 AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharSummaryProvider, 944 "wchar_t summary provider", ConstString("wchar_t"), 945 widechar_flags); 946 947 AddCXXSummary( 948 cpp_category_sp, lldb_private::formatters::Char16SummaryProvider, 949 "unichar summary provider", ConstString("unichar"), widechar_flags); 950 #endif 951 } 952 953 std::unique_ptr<Language::TypeScavenger> CPlusPlusLanguage::GetTypeScavenger() { 954 class CPlusPlusTypeScavenger : public Language::ImageListTypeScavenger { 955 public: 956 virtual CompilerType AdjustForInclusion(CompilerType &candidate) override { 957 LanguageType lang_type(candidate.GetMinimumLanguage()); 958 if (!Language::LanguageIsC(lang_type) && 959 !Language::LanguageIsCPlusPlus(lang_type)) 960 return CompilerType(); 961 if (candidate.IsTypedefType()) 962 return candidate.GetTypedefedType(); 963 return candidate; 964 } 965 }; 966 967 return std::unique_ptr<TypeScavenger>(new CPlusPlusTypeScavenger()); 968 } 969 970 lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() { 971 static llvm::once_flag g_initialize; 972 static TypeCategoryImplSP g_category; 973 974 llvm::call_once(g_initialize, [this]() -> void { 975 DataVisualization::Categories::GetCategory(GetPluginName(), g_category); 976 if (g_category) { 977 LoadLibCxxFormatters(g_category); 978 LoadLibStdcppFormatters(g_category); 979 LoadSystemFormatters(g_category); 980 } 981 }); 982 return g_category; 983 } 984 985 HardcodedFormatters::HardcodedSummaryFinder 986 CPlusPlusLanguage::GetHardcodedSummaries() { 987 static llvm::once_flag g_initialize; 988 static ConstString g_vectortypes("VectorTypes"); 989 static HardcodedFormatters::HardcodedSummaryFinder g_formatters; 990 991 llvm::call_once(g_initialize, []() -> void { 992 g_formatters.push_back( 993 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, 994 FormatManager &) -> TypeSummaryImpl::SharedPointer { 995 static CXXFunctionSummaryFormat::SharedPointer formatter_sp( 996 new CXXFunctionSummaryFormat( 997 TypeSummaryImpl::Flags(), 998 lldb_private::formatters::CXXFunctionPointerSummaryProvider, 999 "Function pointer summary provider")); 1000 if (valobj.GetCompilerType().IsFunctionPointerType()) { 1001 return formatter_sp; 1002 } 1003 return nullptr; 1004 }); 1005 g_formatters.push_back( 1006 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, 1007 FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer { 1008 static CXXFunctionSummaryFormat::SharedPointer formatter_sp( 1009 new CXXFunctionSummaryFormat( 1010 TypeSummaryImpl::Flags() 1011 .SetCascades(true) 1012 .SetDontShowChildren(true) 1013 .SetHideItemNames(true) 1014 .SetShowMembersOneLiner(true) 1015 .SetSkipPointers(true) 1016 .SetSkipReferences(false), 1017 lldb_private::formatters::VectorTypeSummaryProvider, 1018 "vector_type pointer summary provider")); 1019 if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr)) { 1020 if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled()) 1021 return formatter_sp; 1022 } 1023 return nullptr; 1024 }); 1025 g_formatters.push_back( 1026 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, 1027 FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer { 1028 static CXXFunctionSummaryFormat::SharedPointer formatter_sp( 1029 new CXXFunctionSummaryFormat( 1030 TypeSummaryImpl::Flags() 1031 .SetCascades(true) 1032 .SetDontShowChildren(true) 1033 .SetHideItemNames(true) 1034 .SetShowMembersOneLiner(true) 1035 .SetSkipPointers(true) 1036 .SetSkipReferences(false), 1037 lldb_private::formatters::BlockPointerSummaryProvider, 1038 "block pointer summary provider")); 1039 if (valobj.GetCompilerType().IsBlockPointerType(nullptr)) { 1040 return formatter_sp; 1041 } 1042 return nullptr; 1043 }); 1044 }); 1045 1046 return g_formatters; 1047 } 1048 1049 HardcodedFormatters::HardcodedSyntheticFinder 1050 CPlusPlusLanguage::GetHardcodedSynthetics() { 1051 static llvm::once_flag g_initialize; 1052 static ConstString g_vectortypes("VectorTypes"); 1053 static HardcodedFormatters::HardcodedSyntheticFinder g_formatters; 1054 1055 llvm::call_once(g_initialize, []() -> void { 1056 g_formatters.push_back([](lldb_private::ValueObject &valobj, 1057 lldb::DynamicValueType, 1058 FormatManager & 1059 fmt_mgr) -> SyntheticChildren::SharedPointer { 1060 static CXXSyntheticChildren::SharedPointer formatter_sp( 1061 new CXXSyntheticChildren( 1062 SyntheticChildren::Flags() 1063 .SetCascades(true) 1064 .SetSkipPointers(true) 1065 .SetSkipReferences(true) 1066 .SetNonCacheable(true), 1067 "vector_type synthetic children", 1068 lldb_private::formatters::VectorTypeSyntheticFrontEndCreator)); 1069 if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr)) { 1070 if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled()) 1071 return formatter_sp; 1072 } 1073 return nullptr; 1074 }); 1075 g_formatters.push_back([](lldb_private::ValueObject &valobj, 1076 lldb::DynamicValueType, 1077 FormatManager & 1078 fmt_mgr) -> SyntheticChildren::SharedPointer { 1079 static CXXSyntheticChildren::SharedPointer formatter_sp( 1080 new CXXSyntheticChildren( 1081 SyntheticChildren::Flags() 1082 .SetCascades(true) 1083 .SetSkipPointers(true) 1084 .SetSkipReferences(true) 1085 .SetNonCacheable(true), 1086 "block pointer synthetic children", 1087 lldb_private::formatters::BlockPointerSyntheticFrontEndCreator)); 1088 if (valobj.GetCompilerType().IsBlockPointerType(nullptr)) { 1089 return formatter_sp; 1090 } 1091 return nullptr; 1092 }); 1093 1094 }); 1095 1096 return g_formatters; 1097 } 1098