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, lldb_private::formatters::LibcxxStringSummaryProvider, 409 "std::string summary provider")); 410 lldb::TypeSummaryImplSP std_wstring_summary_sp(new CXXFunctionSummaryFormat( 411 stl_summary_flags, lldb_private::formatters::LibcxxWStringSummaryProvider, 412 "std::wstring summary provider")); 413 414 cpp_category_sp->GetTypeSummariesContainer()->Add( 415 ConstString("std::__1::string"), std_string_summary_sp); 416 cpp_category_sp->GetTypeSummariesContainer()->Add( 417 ConstString("std::__ndk1::string"), std_string_summary_sp); 418 cpp_category_sp->GetTypeSummariesContainer()->Add( 419 ConstString("std::__1::basic_string<char, std::__1::char_traits<char>, " 420 "std::__1::allocator<char> >"), 421 std_string_summary_sp); 422 cpp_category_sp->GetTypeSummariesContainer()->Add( 423 ConstString("std::__ndk1::basic_string<char, " 424 "std::__ndk1::char_traits<char>, " 425 "std::__ndk1::allocator<char> >"), 426 std_string_summary_sp); 427 428 cpp_category_sp->GetTypeSummariesContainer()->Add( 429 ConstString("std::__1::wstring"), std_wstring_summary_sp); 430 cpp_category_sp->GetTypeSummariesContainer()->Add( 431 ConstString("std::__ndk1::wstring"), std_wstring_summary_sp); 432 cpp_category_sp->GetTypeSummariesContainer()->Add( 433 ConstString("std::__1::basic_string<wchar_t, " 434 "std::__1::char_traits<wchar_t>, " 435 "std::__1::allocator<wchar_t> >"), 436 std_wstring_summary_sp); 437 cpp_category_sp->GetTypeSummariesContainer()->Add( 438 ConstString("std::__ndk1::basic_string<wchar_t, " 439 "std::__ndk1::char_traits<wchar_t>, " 440 "std::__ndk1::allocator<wchar_t> >"), 441 std_wstring_summary_sp); 442 443 SyntheticChildren::Flags stl_synth_flags; 444 stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences( 445 false); 446 SyntheticChildren::Flags stl_deref_flags = stl_synth_flags; 447 stl_deref_flags.SetFrontEndWantsDereference(); 448 449 AddCXXSynthetic( 450 cpp_category_sp, 451 lldb_private::formatters::LibcxxBitsetSyntheticFrontEndCreator, 452 "libc++ std::bitset synthetic children", 453 ConstString("^std::__(ndk)?1::bitset<.+>(( )?&)?$"), stl_deref_flags, 454 true); 455 AddCXXSynthetic( 456 cpp_category_sp, 457 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator, 458 "libc++ std::vector synthetic children", 459 ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"), stl_deref_flags, 460 true); 461 AddCXXSynthetic( 462 cpp_category_sp, 463 lldb_private::formatters::LibcxxStdForwardListSyntheticFrontEndCreator, 464 "libc++ std::forward_list synthetic children", 465 ConstString("^std::__(ndk)?1::forward_list<.+>(( )?&)?$"), 466 stl_synth_flags, true); 467 AddCXXSynthetic( 468 cpp_category_sp, 469 lldb_private::formatters::LibcxxStdListSyntheticFrontEndCreator, 470 "libc++ std::list synthetic children", 471 ConstString("^std::__(ndk)?1::list<.+>(( )?&)?$"), stl_synth_flags, true); 472 AddCXXSynthetic( 473 cpp_category_sp, 474 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, 475 "libc++ std::map synthetic children", 476 ConstString("^std::__(ndk)?1::map<.+> >(( )?&)?$"), stl_synth_flags, 477 true); 478 AddCXXSynthetic( 479 cpp_category_sp, 480 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, 481 "libc++ std::set synthetic children", 482 ConstString("^std::__(ndk)?1::set<.+> >(( )?&)?$"), stl_deref_flags, 483 true); 484 AddCXXSynthetic( 485 cpp_category_sp, 486 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, 487 "libc++ std::multiset synthetic children", 488 ConstString("^std::__(ndk)?1::multiset<.+> >(( )?&)?$"), stl_deref_flags, 489 true); 490 AddCXXSynthetic( 491 cpp_category_sp, 492 lldb_private::formatters::LibcxxStdMapSyntheticFrontEndCreator, 493 "libc++ std::multimap synthetic children", 494 ConstString("^std::__(ndk)?1::multimap<.+> >(( )?&)?$"), stl_synth_flags, 495 true); 496 AddCXXSynthetic( 497 cpp_category_sp, 498 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator, 499 "libc++ std::unordered containers synthetic children", 500 ConstString("^(std::__(ndk)?1::)unordered_(multi)?(map|set)<.+> >$"), 501 stl_synth_flags, true); 502 AddCXXSynthetic( 503 cpp_category_sp, 504 lldb_private::formatters::LibcxxInitializerListSyntheticFrontEndCreator, 505 "libc++ std::initializer_list synthetic children", 506 ConstString("^std::initializer_list<.+>(( )?&)?$"), stl_synth_flags, 507 true); 508 AddCXXSynthetic(cpp_category_sp, LibcxxQueueFrontEndCreator, 509 "libc++ std::queue synthetic children", 510 ConstString("^std::__(ndk)?1::queue<.+>(( )?&)?$"), 511 stl_synth_flags, true); 512 AddCXXSynthetic(cpp_category_sp, LibcxxTupleFrontEndCreator, 513 "libc++ std::tuple synthetic children", 514 ConstString("^std::__(ndk)?1::tuple<.*>(( )?&)?$"), stl_synth_flags, 515 true); 516 AddCXXSynthetic(cpp_category_sp, LibcxxOptionalFrontEndCreator, 517 "libc++ std::optional synthetic children", 518 ConstString("^std::__(ndk)?1::optional<.+>(( )?&)?$"), 519 stl_synth_flags, true); 520 AddCXXSynthetic(cpp_category_sp, LibcxxVariantFrontEndCreator, 521 "libc++ std::variant synthetic children", 522 ConstString("^std::__(ndk)?1::variant<.+>(( )?&)?$"), 523 stl_synth_flags, true); 524 AddCXXSynthetic( 525 cpp_category_sp, 526 lldb_private::formatters::LibcxxAtomicSyntheticFrontEndCreator, 527 "libc++ std::atomic synthetic children", 528 ConstString("^std::__(ndk)?1::atomic<.+>$"), stl_synth_flags, true); 529 530 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( 531 RegularExpressionSP(new RegularExpression( 532 llvm::StringRef("^(std::__(ndk)?1::)deque<.+>(( )?&)?$"))), 533 SyntheticChildrenSP(new ScriptedSyntheticChildren( 534 stl_synth_flags, 535 "lldb.formatters.cpp.libcxx.stddeque_SynthProvider"))); 536 537 AddCXXSynthetic( 538 cpp_category_sp, 539 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, 540 "shared_ptr synthetic children", 541 ConstString("^(std::__(ndk)?1::)shared_ptr<.+>(( )?&)?$"), 542 stl_synth_flags, true); 543 AddCXXSynthetic( 544 cpp_category_sp, 545 lldb_private::formatters::LibcxxSharedPtrSyntheticFrontEndCreator, 546 "weak_ptr synthetic children", 547 ConstString("^(std::__(ndk)?1::)weak_ptr<.+>(( )?&)?$"), stl_synth_flags, 548 true); 549 550 AddCXXSummary( 551 cpp_category_sp, lldb_private::formatters::LibcxxFunctionSummaryProvider, 552 "libc++ std::function summary provider", 553 ConstString("^std::__(ndk)?1::function<.+>$"), stl_summary_flags, true); 554 555 stl_summary_flags.SetDontShowChildren(false); 556 stl_summary_flags.SetSkipPointers(false); 557 AddCXXSummary(cpp_category_sp, 558 lldb_private::formatters::LibcxxContainerSummaryProvider, 559 "libc++ std::bitset summary provider", 560 ConstString("^std::__(ndk)?1::bitset<.+>(( )?&)?$"), 561 stl_summary_flags, true); 562 AddCXXSummary(cpp_category_sp, 563 lldb_private::formatters::LibcxxContainerSummaryProvider, 564 "libc++ std::vector summary provider", 565 ConstString("^std::__(ndk)?1::vector<.+>(( )?&)?$"), 566 stl_summary_flags, true); 567 AddCXXSummary(cpp_category_sp, 568 lldb_private::formatters::LibcxxContainerSummaryProvider, 569 "libc++ std::list summary provider", 570 ConstString("^std::__(ndk)?1::forward_list<.+>(( )?&)?$"), 571 stl_summary_flags, true); 572 AddCXXSummary(cpp_category_sp, 573 lldb_private::formatters::LibcxxContainerSummaryProvider, 574 "libc++ std::list summary provider", 575 ConstString("^std::__(ndk)?1::list<.+>(( )?&)?$"), 576 stl_summary_flags, true); 577 AddCXXSummary(cpp_category_sp, 578 lldb_private::formatters::LibcxxContainerSummaryProvider, 579 "libc++ std::map summary provider", 580 ConstString("^std::__(ndk)?1::map<.+>(( )?&)?$"), 581 stl_summary_flags, true); 582 AddCXXSummary(cpp_category_sp, 583 lldb_private::formatters::LibcxxContainerSummaryProvider, 584 "libc++ std::deque summary provider", 585 ConstString("^std::__(ndk)?1::deque<.+>(( )?&)?$"), 586 stl_summary_flags, true); 587 AddCXXSummary(cpp_category_sp, 588 lldb_private::formatters::LibcxxContainerSummaryProvider, 589 "libc++ std::queue summary provider", 590 ConstString("^std::__(ndk)?1::queue<.+>(( )?&)?$"), 591 stl_summary_flags, true); 592 AddCXXSummary(cpp_category_sp, 593 lldb_private::formatters::LibcxxContainerSummaryProvider, 594 "libc++ std::set summary provider", 595 ConstString("^std::__(ndk)?1::set<.+>(( )?&)?$"), 596 stl_summary_flags, true); 597 AddCXXSummary(cpp_category_sp, 598 lldb_private::formatters::LibcxxContainerSummaryProvider, 599 "libc++ std::multiset summary provider", 600 ConstString("^std::__(ndk)?1::multiset<.+>(( )?&)?$"), 601 stl_summary_flags, true); 602 AddCXXSummary(cpp_category_sp, 603 lldb_private::formatters::LibcxxContainerSummaryProvider, 604 "libc++ std::multimap summary provider", 605 ConstString("^std::__(ndk)?1::multimap<.+>(( )?&)?$"), 606 stl_summary_flags, true); 607 AddCXXSummary( 608 cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, 609 "libc++ std::unordered containers summary provider", 610 ConstString("^(std::__(ndk)?1::)unordered_(multi)?(map|set)<.+> >$"), 611 stl_summary_flags, true); 612 AddCXXSummary(cpp_category_sp, LibcxxContainerSummaryProvider, 613 "libc++ std::tuple summary provider", 614 ConstString("^std::__(ndk)?1::tuple<.*>(( )?&)?$"), stl_summary_flags, 615 true); 616 AddCXXSummary( 617 cpp_category_sp, lldb_private::formatters::LibCxxAtomicSummaryProvider, 618 "libc++ std::atomic summary provider", 619 ConstString("^std::__(ndk)?1::atomic<.+>$"), stl_summary_flags, true); 620 AddCXXSummary(cpp_category_sp, 621 lldb_private::formatters::LibcxxOptionalSummaryProvider, 622 "libc++ std::optional summary provider", 623 ConstString("^std::__(ndk)?1::optional<.+>(( )?&)?$"), 624 stl_summary_flags, true); 625 AddCXXSummary(cpp_category_sp, 626 lldb_private::formatters::LibcxxVariantSummaryProvider, 627 "libc++ std::variant summary provider", 628 ConstString("^std::__(ndk)?1::variant<.+>(( )?&)?$"), 629 stl_summary_flags, true); 630 631 stl_summary_flags.SetSkipPointers(true); 632 633 AddCXXSummary(cpp_category_sp, 634 lldb_private::formatters::LibcxxSmartPointerSummaryProvider, 635 "libc++ std::shared_ptr summary provider", 636 ConstString("^std::__(ndk)?1::shared_ptr<.+>(( )?&)?$"), 637 stl_summary_flags, true); 638 AddCXXSummary(cpp_category_sp, 639 lldb_private::formatters::LibcxxSmartPointerSummaryProvider, 640 "libc++ std::weak_ptr summary provider", 641 ConstString("^std::__(ndk)?1::weak_ptr<.+>(( )?&)?$"), 642 stl_summary_flags, true); 643 644 AddCXXSynthetic( 645 cpp_category_sp, 646 lldb_private::formatters::LibCxxVectorIteratorSyntheticFrontEndCreator, 647 "std::vector iterator synthetic children", 648 ConstString("^std::__(ndk)?1::__wrap_iter<.+>$"), stl_synth_flags, true); 649 650 AddCXXSynthetic( 651 cpp_category_sp, 652 lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator, 653 "std::map iterator synthetic children", 654 ConstString("^std::__(ndk)?1::__map_iterator<.+>$"), stl_synth_flags, 655 true); 656 #endif 657 } 658 659 static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { 660 if (!cpp_category_sp) 661 return; 662 663 TypeSummaryImpl::Flags stl_summary_flags; 664 stl_summary_flags.SetCascades(true) 665 .SetSkipPointers(false) 666 .SetSkipReferences(false) 667 .SetDontShowChildren(true) 668 .SetDontShowValue(true) 669 .SetShowMembersOneLiner(false) 670 .SetHideItemNames(false); 671 672 lldb::TypeSummaryImplSP std_string_summary_sp( 673 new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p}")); 674 675 lldb::TypeSummaryImplSP cxx11_string_summary_sp(new CXXFunctionSummaryFormat( 676 stl_summary_flags, LibStdcppStringSummaryProvider, 677 "libstdc++ c++11 std::string summary provider")); 678 lldb::TypeSummaryImplSP cxx11_wstring_summary_sp(new CXXFunctionSummaryFormat( 679 stl_summary_flags, LibStdcppWStringSummaryProvider, 680 "libstdc++ c++11 std::wstring summary provider")); 681 682 cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::string"), 683 std_string_summary_sp); 684 cpp_category_sp->GetTypeSummariesContainer()->Add( 685 ConstString("std::basic_string<char>"), std_string_summary_sp); 686 cpp_category_sp->GetTypeSummariesContainer()->Add( 687 ConstString("std::basic_string<char,std::char_traits<char>,std::" 688 "allocator<char> >"), 689 std_string_summary_sp); 690 cpp_category_sp->GetTypeSummariesContainer()->Add( 691 ConstString("std::basic_string<char, std::char_traits<char>, " 692 "std::allocator<char> >"), 693 std_string_summary_sp); 694 695 cpp_category_sp->GetTypeSummariesContainer()->Add( 696 ConstString("std::__cxx11::string"), cxx11_string_summary_sp); 697 cpp_category_sp->GetTypeSummariesContainer()->Add( 698 ConstString("std::__cxx11::basic_string<char, std::char_traits<char>, " 699 "std::allocator<char> >"), 700 cxx11_string_summary_sp); 701 702 // making sure we force-pick the summary for printing wstring (_M_p is a 703 // wchar_t*) 704 lldb::TypeSummaryImplSP std_wstring_summary_sp( 705 new StringSummaryFormat(stl_summary_flags, "${var._M_dataplus._M_p%S}")); 706 707 cpp_category_sp->GetTypeSummariesContainer()->Add(ConstString("std::wstring"), 708 std_wstring_summary_sp); 709 cpp_category_sp->GetTypeSummariesContainer()->Add( 710 ConstString("std::basic_string<wchar_t>"), std_wstring_summary_sp); 711 cpp_category_sp->GetTypeSummariesContainer()->Add( 712 ConstString("std::basic_string<wchar_t,std::char_traits<wchar_t>,std::" 713 "allocator<wchar_t> >"), 714 std_wstring_summary_sp); 715 cpp_category_sp->GetTypeSummariesContainer()->Add( 716 ConstString("std::basic_string<wchar_t, std::char_traits<wchar_t>, " 717 "std::allocator<wchar_t> >"), 718 std_wstring_summary_sp); 719 720 cpp_category_sp->GetTypeSummariesContainer()->Add( 721 ConstString("std::__cxx11::wstring"), cxx11_wstring_summary_sp); 722 cpp_category_sp->GetTypeSummariesContainer()->Add( 723 ConstString("std::__cxx11::basic_string<wchar_t, " 724 "std::char_traits<wchar_t>, std::allocator<wchar_t> >"), 725 cxx11_wstring_summary_sp); 726 727 #ifndef LLDB_DISABLE_PYTHON 728 729 SyntheticChildren::Flags stl_synth_flags; 730 stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences( 731 false); 732 733 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( 734 RegularExpressionSP( 735 new RegularExpression(llvm::StringRef("^std::vector<.+>(( )?&)?$"))), 736 SyntheticChildrenSP(new ScriptedSyntheticChildren( 737 stl_synth_flags, 738 "lldb.formatters.cpp.gnu_libstdcpp.StdVectorSynthProvider"))); 739 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( 740 RegularExpressionSP( 741 new RegularExpression(llvm::StringRef("^std::map<.+> >(( )?&)?$"))), 742 SyntheticChildrenSP(new ScriptedSyntheticChildren( 743 stl_synth_flags, 744 "lldb.formatters.cpp.gnu_libstdcpp.StdMapSynthProvider"))); 745 cpp_category_sp->GetRegexTypeSyntheticsContainer()->Add( 746 RegularExpressionSP(new RegularExpression( 747 llvm::StringRef("^std::(__cxx11::)?list<.+>(( )?&)?$"))), 748 SyntheticChildrenSP(new ScriptedSyntheticChildren( 749 stl_synth_flags, 750 "lldb.formatters.cpp.gnu_libstdcpp.StdListSynthProvider"))); 751 stl_summary_flags.SetDontShowChildren(false); 752 stl_summary_flags.SetSkipPointers(true); 753 cpp_category_sp->GetRegexTypeSummariesContainer()->Add( 754 RegularExpressionSP( 755 new RegularExpression(llvm::StringRef("^std::vector<.+>(( )?&)?$"))), 756 TypeSummaryImplSP( 757 new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); 758 cpp_category_sp->GetRegexTypeSummariesContainer()->Add( 759 RegularExpressionSP( 760 new RegularExpression(llvm::StringRef("^std::map<.+> >(( )?&)?$"))), 761 TypeSummaryImplSP( 762 new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); 763 cpp_category_sp->GetRegexTypeSummariesContainer()->Add( 764 RegularExpressionSP(new RegularExpression( 765 llvm::StringRef("^std::(__cxx11::)?list<.+>(( )?&)?$"))), 766 TypeSummaryImplSP( 767 new StringSummaryFormat(stl_summary_flags, "size=${svar%#}"))); 768 769 AddCXXSynthetic( 770 cpp_category_sp, 771 lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator, 772 "std::vector iterator synthetic children", 773 ConstString("^__gnu_cxx::__normal_iterator<.+>$"), stl_synth_flags, true); 774 775 AddCXXSynthetic( 776 cpp_category_sp, 777 lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator, 778 "std::map iterator synthetic children", 779 ConstString("^std::_Rb_tree_iterator<.+>$"), stl_synth_flags, true); 780 781 AddCXXSynthetic( 782 cpp_category_sp, 783 lldb_private::formatters::LibStdcppUniquePtrSyntheticFrontEndCreator, 784 "std::unique_ptr synthetic children", 785 ConstString("^std::unique_ptr<.+>(( )?&)?$"), stl_synth_flags, true); 786 AddCXXSynthetic( 787 cpp_category_sp, 788 lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator, 789 "std::shared_ptr synthetic children", 790 ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_synth_flags, true); 791 AddCXXSynthetic( 792 cpp_category_sp, 793 lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator, 794 "std::weak_ptr synthetic children", 795 ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true); 796 AddCXXSynthetic( 797 cpp_category_sp, 798 lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator, 799 "std::tuple synthetic children", ConstString("^std::tuple<.+>(( )?&)?$"), 800 stl_synth_flags, true); 801 802 AddCXXSummary(cpp_category_sp, 803 lldb_private::formatters::LibStdcppUniquePointerSummaryProvider, 804 "libstdc++ std::unique_ptr summary provider", 805 ConstString("^std::unique_ptr<.+>(( )?&)?$"), stl_summary_flags, 806 true); 807 AddCXXSummary(cpp_category_sp, 808 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider, 809 "libstdc++ std::shared_ptr summary provider", 810 ConstString("^std::shared_ptr<.+>(( )?&)?$"), stl_summary_flags, 811 true); 812 AddCXXSummary(cpp_category_sp, 813 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider, 814 "libstdc++ std::weak_ptr summary provider", 815 ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_summary_flags, 816 true); 817 #endif 818 } 819 820 static void LoadSystemFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { 821 if (!cpp_category_sp) 822 return; 823 824 TypeSummaryImpl::Flags string_flags; 825 string_flags.SetCascades(true) 826 .SetSkipPointers(true) 827 .SetSkipReferences(false) 828 .SetDontShowChildren(true) 829 .SetDontShowValue(false) 830 .SetShowMembersOneLiner(false) 831 .SetHideItemNames(false); 832 833 TypeSummaryImpl::Flags string_array_flags; 834 string_array_flags.SetCascades(true) 835 .SetSkipPointers(true) 836 .SetSkipReferences(false) 837 .SetDontShowChildren(true) 838 .SetDontShowValue(true) 839 .SetShowMembersOneLiner(false) 840 .SetHideItemNames(false); 841 842 #ifndef LLDB_DISABLE_PYTHON 843 // FIXME because of a bug in the FormattersContainer we need to add a summary 844 // for both X* and const X* (<rdar://problem/12717717>) 845 AddCXXSummary( 846 cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider, 847 "char16_t * summary provider", ConstString("char16_t *"), string_flags); 848 AddCXXSummary(cpp_category_sp, 849 lldb_private::formatters::Char16StringSummaryProvider, 850 "char16_t [] summary provider", 851 ConstString("char16_t \\[[0-9]+\\]"), string_array_flags, true); 852 853 AddCXXSummary( 854 cpp_category_sp, lldb_private::formatters::Char32StringSummaryProvider, 855 "char32_t * summary provider", ConstString("char32_t *"), string_flags); 856 AddCXXSummary(cpp_category_sp, 857 lldb_private::formatters::Char32StringSummaryProvider, 858 "char32_t [] summary provider", 859 ConstString("char32_t \\[[0-9]+\\]"), string_array_flags, true); 860 861 AddCXXSummary( 862 cpp_category_sp, lldb_private::formatters::WCharStringSummaryProvider, 863 "wchar_t * summary provider", ConstString("wchar_t *"), string_flags); 864 AddCXXSummary(cpp_category_sp, 865 lldb_private::formatters::WCharStringSummaryProvider, 866 "wchar_t * summary provider", 867 ConstString("wchar_t \\[[0-9]+\\]"), string_array_flags, true); 868 869 AddCXXSummary( 870 cpp_category_sp, lldb_private::formatters::Char16StringSummaryProvider, 871 "unichar * summary provider", ConstString("unichar *"), string_flags); 872 873 TypeSummaryImpl::Flags widechar_flags; 874 widechar_flags.SetDontShowValue(true) 875 .SetSkipPointers(true) 876 .SetSkipReferences(false) 877 .SetCascades(true) 878 .SetDontShowChildren(true) 879 .SetHideItemNames(true) 880 .SetShowMembersOneLiner(false); 881 882 AddCXXSummary( 883 cpp_category_sp, lldb_private::formatters::Char16SummaryProvider, 884 "char16_t summary provider", ConstString("char16_t"), widechar_flags); 885 AddCXXSummary( 886 cpp_category_sp, lldb_private::formatters::Char32SummaryProvider, 887 "char32_t summary provider", ConstString("char32_t"), widechar_flags); 888 AddCXXSummary(cpp_category_sp, lldb_private::formatters::WCharSummaryProvider, 889 "wchar_t summary provider", ConstString("wchar_t"), 890 widechar_flags); 891 892 AddCXXSummary( 893 cpp_category_sp, lldb_private::formatters::Char16SummaryProvider, 894 "unichar summary provider", ConstString("unichar"), widechar_flags); 895 #endif 896 } 897 898 std::unique_ptr<Language::TypeScavenger> CPlusPlusLanguage::GetTypeScavenger() { 899 class CPlusPlusTypeScavenger : public Language::ImageListTypeScavenger { 900 public: 901 virtual CompilerType AdjustForInclusion(CompilerType &candidate) override { 902 LanguageType lang_type(candidate.GetMinimumLanguage()); 903 if (!Language::LanguageIsC(lang_type) && 904 !Language::LanguageIsCPlusPlus(lang_type)) 905 return CompilerType(); 906 if (candidate.IsTypedefType()) 907 return candidate.GetTypedefedType(); 908 return candidate; 909 } 910 }; 911 912 return std::unique_ptr<TypeScavenger>(new CPlusPlusTypeScavenger()); 913 } 914 915 lldb::TypeCategoryImplSP CPlusPlusLanguage::GetFormatters() { 916 static llvm::once_flag g_initialize; 917 static TypeCategoryImplSP g_category; 918 919 llvm::call_once(g_initialize, [this]() -> void { 920 DataVisualization::Categories::GetCategory(GetPluginName(), g_category); 921 if (g_category) { 922 LoadLibCxxFormatters(g_category); 923 LoadLibStdcppFormatters(g_category); 924 LoadSystemFormatters(g_category); 925 } 926 }); 927 return g_category; 928 } 929 930 HardcodedFormatters::HardcodedSummaryFinder 931 CPlusPlusLanguage::GetHardcodedSummaries() { 932 static llvm::once_flag g_initialize; 933 static ConstString g_vectortypes("VectorTypes"); 934 static HardcodedFormatters::HardcodedSummaryFinder g_formatters; 935 936 llvm::call_once(g_initialize, []() -> void { 937 g_formatters.push_back( 938 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, 939 FormatManager &) -> TypeSummaryImpl::SharedPointer { 940 static CXXFunctionSummaryFormat::SharedPointer formatter_sp( 941 new CXXFunctionSummaryFormat( 942 TypeSummaryImpl::Flags(), 943 lldb_private::formatters::CXXFunctionPointerSummaryProvider, 944 "Function pointer summary provider")); 945 if (valobj.GetCompilerType().IsFunctionPointerType()) { 946 return formatter_sp; 947 } 948 return nullptr; 949 }); 950 g_formatters.push_back( 951 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, 952 FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer { 953 static CXXFunctionSummaryFormat::SharedPointer formatter_sp( 954 new CXXFunctionSummaryFormat( 955 TypeSummaryImpl::Flags() 956 .SetCascades(true) 957 .SetDontShowChildren(true) 958 .SetHideItemNames(true) 959 .SetShowMembersOneLiner(true) 960 .SetSkipPointers(true) 961 .SetSkipReferences(false), 962 lldb_private::formatters::VectorTypeSummaryProvider, 963 "vector_type pointer summary provider")); 964 if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr)) { 965 if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled()) 966 return formatter_sp; 967 } 968 return nullptr; 969 }); 970 g_formatters.push_back( 971 [](lldb_private::ValueObject &valobj, lldb::DynamicValueType, 972 FormatManager &fmt_mgr) -> TypeSummaryImpl::SharedPointer { 973 static CXXFunctionSummaryFormat::SharedPointer formatter_sp( 974 new CXXFunctionSummaryFormat( 975 TypeSummaryImpl::Flags() 976 .SetCascades(true) 977 .SetDontShowChildren(true) 978 .SetHideItemNames(true) 979 .SetShowMembersOneLiner(true) 980 .SetSkipPointers(true) 981 .SetSkipReferences(false), 982 lldb_private::formatters::BlockPointerSummaryProvider, 983 "block pointer summary provider")); 984 if (valobj.GetCompilerType().IsBlockPointerType(nullptr)) { 985 return formatter_sp; 986 } 987 return nullptr; 988 }); 989 }); 990 991 return g_formatters; 992 } 993 994 HardcodedFormatters::HardcodedSyntheticFinder 995 CPlusPlusLanguage::GetHardcodedSynthetics() { 996 static llvm::once_flag g_initialize; 997 static ConstString g_vectortypes("VectorTypes"); 998 static HardcodedFormatters::HardcodedSyntheticFinder g_formatters; 999 1000 llvm::call_once(g_initialize, []() -> void { 1001 g_formatters.push_back([](lldb_private::ValueObject &valobj, 1002 lldb::DynamicValueType, 1003 FormatManager & 1004 fmt_mgr) -> SyntheticChildren::SharedPointer { 1005 static CXXSyntheticChildren::SharedPointer formatter_sp( 1006 new CXXSyntheticChildren( 1007 SyntheticChildren::Flags() 1008 .SetCascades(true) 1009 .SetSkipPointers(true) 1010 .SetSkipReferences(true) 1011 .SetNonCacheable(true), 1012 "vector_type synthetic children", 1013 lldb_private::formatters::VectorTypeSyntheticFrontEndCreator)); 1014 if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr)) { 1015 if (fmt_mgr.GetCategory(g_vectortypes)->IsEnabled()) 1016 return formatter_sp; 1017 } 1018 return nullptr; 1019 }); 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 "block pointer synthetic children", 1032 lldb_private::formatters::BlockPointerSyntheticFrontEndCreator)); 1033 if (valobj.GetCompilerType().IsBlockPointerType(nullptr)) { 1034 return formatter_sp; 1035 } 1036 return nullptr; 1037 }); 1038 1039 }); 1040 1041 return g_formatters; 1042 } 1043 1044 bool CPlusPlusLanguage::IsSourceFile(llvm::StringRef file_path) const { 1045 const auto suffixes = {".cpp", ".cxx", ".c++", ".cc", ".c", 1046 ".h", ".hh", ".hpp", ".hxx", ".h++"}; 1047 for (auto suffix : suffixes) { 1048 if (file_path.endswith_lower(suffix)) 1049 return true; 1050 } 1051 1052 // Check if we're in a STL path (where the files usually have no extension 1053 // that we could check for. 1054 return file_path.contains("/usr/include/c++/"); 1055 } 1056