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