1 //===-- Language.cpp ------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include <functional> 10 #include <map> 11 #include <mutex> 12 13 #include "lldb/Target/Language.h" 14 15 #include "lldb/Core/PluginManager.h" 16 #include "lldb/Interpreter/OptionValueProperties.h" 17 #include "lldb/Symbol/SymbolFile.h" 18 #include "lldb/Symbol/TypeList.h" 19 #include "lldb/Target/Target.h" 20 #include "lldb/Utility/Stream.h" 21 22 #include "llvm/BinaryFormat/Dwarf.h" 23 #include "llvm/Support/Threading.h" 24 25 using namespace lldb; 26 using namespace lldb_private; 27 using namespace lldb_private::formatters; 28 29 typedef std::unique_ptr<Language> LanguageUP; 30 typedef std::map<lldb::LanguageType, LanguageUP> LanguagesMap; 31 32 #define LLDB_PROPERTIES_language 33 #include "TargetProperties.inc" 34 35 enum { 36 #define LLDB_PROPERTIES_language 37 #include "TargetPropertiesEnum.inc" 38 }; 39 40 LanguageProperties &Language::GetGlobalLanguageProperties() { 41 static LanguageProperties g_settings; 42 return g_settings; 43 } 44 45 llvm::StringRef LanguageProperties::GetSettingName() { 46 static constexpr llvm::StringLiteral g_setting_name("language"); 47 return g_setting_name; 48 } 49 50 LanguageProperties::LanguageProperties() { 51 m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName()); 52 m_collection_sp->Initialize(g_language_properties); 53 } 54 55 bool LanguageProperties::GetEnableFilterForLineBreakpoints() const { 56 const uint32_t idx = ePropertyEnableFilterForLineBreakpoints; 57 return GetPropertyAtIndexAs<bool>( 58 idx, g_language_properties[idx].default_uint_value != 0); 59 } 60 61 static LanguagesMap &GetLanguagesMap() { 62 static LanguagesMap *g_map = nullptr; 63 static llvm::once_flag g_initialize; 64 65 llvm::call_once(g_initialize, [] { 66 g_map = new LanguagesMap(); // NOTE: INTENTIONAL LEAK due to global 67 // destructor chain 68 }); 69 70 return *g_map; 71 } 72 static std::mutex &GetLanguagesMutex() { 73 static std::mutex *g_mutex = nullptr; 74 static llvm::once_flag g_initialize; 75 76 llvm::call_once(g_initialize, [] { 77 g_mutex = new std::mutex(); // NOTE: INTENTIONAL LEAK due to global 78 // destructor chain 79 }); 80 81 return *g_mutex; 82 } 83 84 Language *Language::FindPlugin(lldb::LanguageType language) { 85 std::lock_guard<std::mutex> guard(GetLanguagesMutex()); 86 LanguagesMap &map(GetLanguagesMap()); 87 auto iter = map.find(language), end = map.end(); 88 if (iter != end) 89 return iter->second.get(); 90 91 Language *language_ptr = nullptr; 92 LanguageCreateInstance create_callback; 93 94 for (uint32_t idx = 0; 95 (create_callback = 96 PluginManager::GetLanguageCreateCallbackAtIndex(idx)) != nullptr; 97 ++idx) { 98 language_ptr = create_callback(language); 99 100 if (language_ptr) { 101 map[language] = std::unique_ptr<Language>(language_ptr); 102 return language_ptr; 103 } 104 } 105 106 return nullptr; 107 } 108 109 Language *Language::FindPlugin(llvm::StringRef file_path) { 110 Language *result = nullptr; 111 ForEach([&result, file_path](Language *language) { 112 if (language->IsSourceFile(file_path)) { 113 result = language; 114 return false; 115 } 116 return true; 117 }); 118 return result; 119 } 120 121 Language *Language::FindPlugin(LanguageType language, 122 llvm::StringRef file_path) { 123 Language *result = FindPlugin(language); 124 // Finding a language by file path is slower, we so we use this as the 125 // fallback. 126 if (!result) 127 result = FindPlugin(file_path); 128 return result; 129 } 130 131 void Language::ForEach(std::function<bool(Language *)> callback) { 132 // If we want to iterate over all languages, we first have to complete the 133 // LanguagesMap. 134 static llvm::once_flag g_initialize; 135 llvm::call_once(g_initialize, [] { 136 for (unsigned lang = eLanguageTypeUnknown; lang < eNumLanguageTypes; 137 ++lang) { 138 FindPlugin(static_cast<lldb::LanguageType>(lang)); 139 } 140 }); 141 142 // callback may call a method in Language that attempts to acquire the same 143 // lock (such as Language::ForEach or Language::FindPlugin). To avoid a 144 // deadlock, we do not use callback while holding the lock. 145 std::vector<Language *> loaded_plugins; 146 { 147 std::lock_guard<std::mutex> guard(GetLanguagesMutex()); 148 LanguagesMap &map(GetLanguagesMap()); 149 for (const auto &entry : map) { 150 if (entry.second) 151 loaded_plugins.push_back(entry.second.get()); 152 } 153 } 154 155 for (auto *lang : loaded_plugins) { 156 if (!callback(lang)) 157 break; 158 } 159 } 160 161 bool Language::IsTopLevelFunction(Function &function) { return false; } 162 163 lldb::TypeCategoryImplSP Language::GetFormatters() { return nullptr; } 164 165 HardcodedFormatters::HardcodedFormatFinder Language::GetHardcodedFormats() { 166 return {}; 167 } 168 169 HardcodedFormatters::HardcodedSummaryFinder Language::GetHardcodedSummaries() { 170 return {}; 171 } 172 173 HardcodedFormatters::HardcodedSyntheticFinder 174 Language::GetHardcodedSynthetics() { 175 return {}; 176 } 177 178 std::vector<FormattersMatchCandidate> 179 Language::GetPossibleFormattersMatches(ValueObject &valobj, 180 lldb::DynamicValueType use_dynamic) { 181 return {}; 182 } 183 184 struct language_name_pair { 185 const char *name; 186 LanguageType type; 187 }; 188 189 struct language_name_pair language_names[] = { 190 // To allow GetNameForLanguageType to be a simple array lookup, the first 191 // part of this array must follow enum LanguageType exactly. 192 {"unknown", eLanguageTypeUnknown}, 193 {"c89", eLanguageTypeC89}, 194 {"c", eLanguageTypeC}, 195 {"ada83", eLanguageTypeAda83}, 196 {"c++", eLanguageTypeC_plus_plus}, 197 {"cobol74", eLanguageTypeCobol74}, 198 {"cobol85", eLanguageTypeCobol85}, 199 {"fortran77", eLanguageTypeFortran77}, 200 {"fortran90", eLanguageTypeFortran90}, 201 {"pascal83", eLanguageTypePascal83}, 202 {"modula2", eLanguageTypeModula2}, 203 {"java", eLanguageTypeJava}, 204 {"c99", eLanguageTypeC99}, 205 {"ada95", eLanguageTypeAda95}, 206 {"fortran95", eLanguageTypeFortran95}, 207 {"pli", eLanguageTypePLI}, 208 {"objective-c", eLanguageTypeObjC}, 209 {"objective-c++", eLanguageTypeObjC_plus_plus}, 210 {"upc", eLanguageTypeUPC}, 211 {"d", eLanguageTypeD}, 212 {"python", eLanguageTypePython}, 213 {"opencl", eLanguageTypeOpenCL}, 214 {"go", eLanguageTypeGo}, 215 {"modula3", eLanguageTypeModula3}, 216 {"haskell", eLanguageTypeHaskell}, 217 {"c++03", eLanguageTypeC_plus_plus_03}, 218 {"c++11", eLanguageTypeC_plus_plus_11}, 219 {"ocaml", eLanguageTypeOCaml}, 220 {"rust", eLanguageTypeRust}, 221 {"c11", eLanguageTypeC11}, 222 {"swift", eLanguageTypeSwift}, 223 {"julia", eLanguageTypeJulia}, 224 {"dylan", eLanguageTypeDylan}, 225 {"c++14", eLanguageTypeC_plus_plus_14}, 226 {"fortran03", eLanguageTypeFortran03}, 227 {"fortran08", eLanguageTypeFortran08}, 228 {"renderscript", eLanguageTypeRenderScript}, 229 {"bliss", eLanguageTypeBLISS}, 230 {"kotlin", eLanguageTypeKotlin}, 231 {"zig", eLanguageTypeZig}, 232 {"crystal", eLanguageTypeCrystal}, 233 {"<invalid language>", 234 static_cast<LanguageType>( 235 0x0029)}, // Not yet taken by any language in the DWARF spec 236 // and thus has no entry in LanguageType 237 {"c++17", eLanguageTypeC_plus_plus_17}, 238 {"c++20", eLanguageTypeC_plus_plus_20}, 239 {"c17", eLanguageTypeC17}, 240 {"fortran18", eLanguageTypeFortran18}, 241 {"ada2005", eLanguageTypeAda2005}, 242 {"ada2012", eLanguageTypeAda2012}, 243 {"HIP", eLanguageTypeHIP}, 244 {"assembly", eLanguageTypeAssembly}, 245 {"c-sharp", eLanguageTypeC_sharp}, 246 {"mojo", eLanguageTypeMojo}, 247 // Vendor Extensions 248 {"assembler", eLanguageTypeMipsAssembler}, 249 // Now synonyms, in arbitrary order 250 {"objc", eLanguageTypeObjC}, 251 {"objc++", eLanguageTypeObjC_plus_plus}, 252 {"pascal", eLanguageTypePascal83}}; 253 254 static uint32_t num_languages = 255 sizeof(language_names) / sizeof(struct language_name_pair); 256 257 LanguageType Language::GetLanguageTypeFromString(llvm::StringRef string) { 258 for (const auto &L : language_names) { 259 if (string.equals_insensitive(L.name)) 260 return static_cast<LanguageType>(L.type); 261 } 262 263 return eLanguageTypeUnknown; 264 } 265 266 const char *Language::GetNameForLanguageType(LanguageType language) { 267 if (language < num_languages) 268 return language_names[language].name; 269 else 270 return language_names[eLanguageTypeUnknown].name; 271 } 272 273 void Language::PrintSupportedLanguagesForExpressions(Stream &s, 274 llvm::StringRef prefix, 275 llvm::StringRef suffix) { 276 auto supported = Language::GetLanguagesSupportingTypeSystemsForExpressions(); 277 for (size_t idx = 0; idx < num_languages; ++idx) { 278 auto const &lang = language_names[idx]; 279 if (supported[lang.type]) 280 s << prefix << lang.name << suffix; 281 } 282 } 283 284 void Language::PrintAllLanguages(Stream &s, const char *prefix, 285 const char *suffix) { 286 for (uint32_t i = 1; i < num_languages; i++) { 287 s.Printf("%s%s%s", prefix, language_names[i].name, suffix); 288 } 289 } 290 291 void Language::ForAllLanguages( 292 std::function<bool(lldb::LanguageType)> callback) { 293 for (uint32_t i = 1; i < num_languages; i++) { 294 if (!callback(language_names[i].type)) 295 break; 296 } 297 } 298 299 bool Language::LanguageIsCPlusPlus(LanguageType language) { 300 switch (language) { 301 case eLanguageTypeC_plus_plus: 302 case eLanguageTypeC_plus_plus_03: 303 case eLanguageTypeC_plus_plus_11: 304 case eLanguageTypeC_plus_plus_14: 305 case eLanguageTypeC_plus_plus_17: 306 case eLanguageTypeC_plus_plus_20: 307 case eLanguageTypeObjC_plus_plus: 308 return true; 309 default: 310 return false; 311 } 312 } 313 314 bool Language::LanguageIsObjC(LanguageType language) { 315 switch (language) { 316 case eLanguageTypeObjC: 317 case eLanguageTypeObjC_plus_plus: 318 return true; 319 default: 320 return false; 321 } 322 } 323 324 bool Language::LanguageIsC(LanguageType language) { 325 switch (language) { 326 case eLanguageTypeC: 327 case eLanguageTypeC89: 328 case eLanguageTypeC99: 329 case eLanguageTypeC11: 330 return true; 331 default: 332 return false; 333 } 334 } 335 336 bool Language::LanguageIsCFamily(LanguageType language) { 337 switch (language) { 338 case eLanguageTypeC: 339 case eLanguageTypeC89: 340 case eLanguageTypeC99: 341 case eLanguageTypeC11: 342 case eLanguageTypeC_plus_plus: 343 case eLanguageTypeC_plus_plus_03: 344 case eLanguageTypeC_plus_plus_11: 345 case eLanguageTypeC_plus_plus_14: 346 case eLanguageTypeC_plus_plus_17: 347 case eLanguageTypeC_plus_plus_20: 348 case eLanguageTypeObjC_plus_plus: 349 case eLanguageTypeObjC: 350 return true; 351 default: 352 return false; 353 } 354 } 355 356 bool Language::LanguageIsPascal(LanguageType language) { 357 switch (language) { 358 case eLanguageTypePascal83: 359 return true; 360 default: 361 return false; 362 } 363 } 364 365 LanguageType Language::GetPrimaryLanguage(LanguageType language) { 366 switch (language) { 367 case eLanguageTypeC_plus_plus: 368 case eLanguageTypeC_plus_plus_03: 369 case eLanguageTypeC_plus_plus_11: 370 case eLanguageTypeC_plus_plus_14: 371 case eLanguageTypeC_plus_plus_17: 372 case eLanguageTypeC_plus_plus_20: 373 return eLanguageTypeC_plus_plus; 374 case eLanguageTypeC: 375 case eLanguageTypeC89: 376 case eLanguageTypeC99: 377 case eLanguageTypeC11: 378 return eLanguageTypeC; 379 case eLanguageTypeObjC: 380 case eLanguageTypeObjC_plus_plus: 381 return eLanguageTypeObjC; 382 case eLanguageTypePascal83: 383 case eLanguageTypeCobol74: 384 case eLanguageTypeCobol85: 385 case eLanguageTypeFortran77: 386 case eLanguageTypeFortran90: 387 case eLanguageTypeFortran95: 388 case eLanguageTypeFortran03: 389 case eLanguageTypeFortran08: 390 case eLanguageTypeAda83: 391 case eLanguageTypeAda95: 392 case eLanguageTypeModula2: 393 case eLanguageTypeJava: 394 case eLanguageTypePLI: 395 case eLanguageTypeUPC: 396 case eLanguageTypeD: 397 case eLanguageTypePython: 398 case eLanguageTypeOpenCL: 399 case eLanguageTypeGo: 400 case eLanguageTypeModula3: 401 case eLanguageTypeHaskell: 402 case eLanguageTypeOCaml: 403 case eLanguageTypeRust: 404 case eLanguageTypeSwift: 405 case eLanguageTypeJulia: 406 case eLanguageTypeDylan: 407 case eLanguageTypeMipsAssembler: 408 case eLanguageTypeMojo: 409 case eLanguageTypeUnknown: 410 default: 411 return language; 412 } 413 } 414 415 std::set<lldb::LanguageType> Language::GetSupportedLanguages() { 416 std::set<lldb::LanguageType> supported_languages; 417 ForEach([&](Language *lang) { 418 supported_languages.emplace(lang->GetLanguageType()); 419 return true; 420 }); 421 return supported_languages; 422 } 423 424 LanguageSet Language::GetLanguagesSupportingTypeSystems() { 425 return PluginManager::GetAllTypeSystemSupportedLanguagesForTypes(); 426 } 427 428 LanguageSet Language::GetLanguagesSupportingTypeSystemsForExpressions() { 429 return PluginManager::GetAllTypeSystemSupportedLanguagesForExpressions(); 430 } 431 432 LanguageSet Language::GetLanguagesSupportingREPLs() { 433 return PluginManager::GetREPLAllTypeSystemSupportedLanguages(); 434 } 435 436 std::unique_ptr<Language::TypeScavenger> Language::GetTypeScavenger() { 437 return nullptr; 438 } 439 440 const char *Language::GetLanguageSpecificTypeLookupHelp() { return nullptr; } 441 442 size_t Language::TypeScavenger::Find(ExecutionContextScope *exe_scope, 443 const char *key, ResultSet &results, 444 bool append) { 445 if (!exe_scope || !exe_scope->CalculateTarget().get()) 446 return false; 447 448 if (!key || !key[0]) 449 return false; 450 451 if (!append) 452 results.clear(); 453 454 size_t old_size = results.size(); 455 456 if (this->Find_Impl(exe_scope, key, results)) 457 return results.size() - old_size; 458 return 0; 459 } 460 461 bool Language::ImageListTypeScavenger::Find_Impl( 462 ExecutionContextScope *exe_scope, const char *key, ResultSet &results) { 463 bool result = false; 464 465 Target *target = exe_scope->CalculateTarget().get(); 466 if (target) { 467 const auto &images(target->GetImages()); 468 TypeQuery query(key); 469 TypeResults type_results; 470 images.FindTypes(nullptr, query, type_results); 471 for (const auto &match : type_results.GetTypeMap().Types()) { 472 if (match) { 473 CompilerType compiler_type(match->GetFullCompilerType()); 474 compiler_type = AdjustForInclusion(compiler_type); 475 if (!compiler_type) 476 continue; 477 std::unique_ptr<Language::TypeScavenger::Result> scavengeresult( 478 new Result(compiler_type)); 479 results.insert(std::move(scavengeresult)); 480 result = true; 481 } 482 } 483 } 484 485 return result; 486 } 487 488 std::pair<llvm::StringRef, llvm::StringRef> 489 Language::GetFormatterPrefixSuffix(llvm::StringRef type_hint) { 490 return std::pair<llvm::StringRef, llvm::StringRef>(); 491 } 492 493 bool Language::DemangledNameContainsPath(llvm::StringRef path, 494 ConstString demangled) const { 495 // The base implementation does a simple contains comparision: 496 if (path.empty()) 497 return false; 498 return demangled.GetStringRef().contains(path); 499 } 500 501 DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() { 502 return nullptr; 503 } 504 505 LazyBool Language::IsLogicalTrue(ValueObject &valobj, Status &error) { 506 return eLazyBoolCalculate; 507 } 508 509 bool Language::IsNilReference(ValueObject &valobj) { return false; } 510 511 bool Language::IsUninitializedReference(ValueObject &valobj) { return false; } 512 513 bool Language::GetFunctionDisplayName(const SymbolContext *sc, 514 const ExecutionContext *exe_ctx, 515 FunctionNameRepresentation representation, 516 Stream &s) { 517 return false; 518 } 519 520 void Language::GetExceptionResolverDescription(bool catch_on, bool throw_on, 521 Stream &s) { 522 GetDefaultExceptionResolverDescription(catch_on, throw_on, s); 523 } 524 525 void Language::GetDefaultExceptionResolverDescription(bool catch_on, 526 bool throw_on, 527 Stream &s) { 528 s.Printf("Exception breakpoint (catch: %s throw: %s)", 529 catch_on ? "on" : "off", throw_on ? "on" : "off"); 530 } 531 532 std::optional<bool> Language::GetBooleanFromString(llvm::StringRef str) const { 533 return llvm::StringSwitch<std::optional<bool>>(str) 534 .Case("true", {true}) 535 .Case("false", {false}) 536 .Default({}); 537 } 538 539 // Constructor 540 Language::Language() = default; 541 542 // Destructor 543 Language::~Language() = default; 544 545 SourceLanguage::SourceLanguage(lldb::LanguageType language_type) { 546 auto lname = 547 llvm::dwarf::toDW_LNAME((llvm::dwarf::SourceLanguage)language_type); 548 if (!lname) 549 return; 550 name = lname->first; 551 version = lname->second; 552 } 553 554 lldb::LanguageType SourceLanguage::AsLanguageType() const { 555 if (auto lang = llvm::dwarf::toDW_LANG((llvm::dwarf::SourceLanguageName)name, 556 version)) 557 return (lldb::LanguageType)*lang; 558 return lldb::eLanguageTypeUnknown; 559 } 560 561 llvm::StringRef SourceLanguage::GetDescription() const { 562 LanguageType type = AsLanguageType(); 563 if (type) 564 return Language::GetNameForLanguageType(type); 565 return llvm::dwarf::LanguageDescription( 566 (llvm::dwarf::SourceLanguageName)name); 567 } 568 bool SourceLanguage::IsC() const { return name == llvm::dwarf::DW_LNAME_C; } 569 570 bool SourceLanguage::IsObjC() const { 571 return name == llvm::dwarf::DW_LNAME_ObjC; 572 } 573 574 bool SourceLanguage::IsCPlusPlus() const { 575 return name == llvm::dwarf::DW_LNAME_C_plus_plus; 576 } 577