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