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