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 HardcodedFormatters::HardcodedValidatorFinder 138 Language::GetHardcodedValidators() { 139 return {}; 140 } 141 142 std::vector<ConstString> 143 Language::GetPossibleFormattersMatches(ValueObject &valobj, 144 lldb::DynamicValueType use_dynamic) { 145 return {}; 146 } 147 148 lldb_private::formatters::StringPrinter::EscapingHelper 149 Language::GetStringPrinterEscapingHelper( 150 lldb_private::formatters::StringPrinter::GetPrintableElementType 151 elem_type) { 152 return StringPrinter::GetDefaultEscapingHelper(elem_type); 153 } 154 155 struct language_name_pair { 156 const char *name; 157 LanguageType type; 158 }; 159 160 struct language_name_pair language_names[] = { 161 // To allow GetNameForLanguageType to be a simple array lookup, the first 162 // part of this array must follow enum LanguageType exactly. 163 {"unknown", eLanguageTypeUnknown}, 164 {"c89", eLanguageTypeC89}, 165 {"c", eLanguageTypeC}, 166 {"ada83", eLanguageTypeAda83}, 167 {"c++", eLanguageTypeC_plus_plus}, 168 {"cobol74", eLanguageTypeCobol74}, 169 {"cobol85", eLanguageTypeCobol85}, 170 {"fortran77", eLanguageTypeFortran77}, 171 {"fortran90", eLanguageTypeFortran90}, 172 {"pascal83", eLanguageTypePascal83}, 173 {"modula2", eLanguageTypeModula2}, 174 {"java", eLanguageTypeJava}, 175 {"c99", eLanguageTypeC99}, 176 {"ada95", eLanguageTypeAda95}, 177 {"fortran95", eLanguageTypeFortran95}, 178 {"pli", eLanguageTypePLI}, 179 {"objective-c", eLanguageTypeObjC}, 180 {"objective-c++", eLanguageTypeObjC_plus_plus}, 181 {"upc", eLanguageTypeUPC}, 182 {"d", eLanguageTypeD}, 183 {"python", eLanguageTypePython}, 184 {"opencl", eLanguageTypeOpenCL}, 185 {"go", eLanguageTypeGo}, 186 {"modula3", eLanguageTypeModula3}, 187 {"haskell", eLanguageTypeHaskell}, 188 {"c++03", eLanguageTypeC_plus_plus_03}, 189 {"c++11", eLanguageTypeC_plus_plus_11}, 190 {"ocaml", eLanguageTypeOCaml}, 191 {"rust", eLanguageTypeRust}, 192 {"c11", eLanguageTypeC11}, 193 {"swift", eLanguageTypeSwift}, 194 {"julia", eLanguageTypeJulia}, 195 {"dylan", eLanguageTypeDylan}, 196 {"c++14", eLanguageTypeC_plus_plus_14}, 197 {"fortran03", eLanguageTypeFortran03}, 198 {"fortran08", eLanguageTypeFortran08}, 199 // Vendor Extensions 200 {"mipsassem", eLanguageTypeMipsAssembler}, 201 {"renderscript", eLanguageTypeExtRenderScript}, 202 // Now synonyms, in arbitrary order 203 {"objc", eLanguageTypeObjC}, 204 {"objc++", eLanguageTypeObjC_plus_plus}, 205 {"pascal", eLanguageTypePascal83}}; 206 207 static uint32_t num_languages = 208 sizeof(language_names) / sizeof(struct language_name_pair); 209 210 LanguageType Language::GetLanguageTypeFromString(llvm::StringRef string) { 211 for (const auto &L : language_names) { 212 if (string.equals_lower(L.name)) 213 return static_cast<LanguageType>(L.type); 214 } 215 216 return eLanguageTypeUnknown; 217 } 218 219 const char *Language::GetNameForLanguageType(LanguageType language) { 220 if (language < num_languages) 221 return language_names[language].name; 222 else 223 return language_names[eLanguageTypeUnknown].name; 224 } 225 226 void Language::PrintAllLanguages(Stream &s, const char *prefix, 227 const char *suffix) { 228 for (uint32_t i = 1; i < num_languages; i++) { 229 s.Printf("%s%s%s", prefix, language_names[i].name, suffix); 230 } 231 } 232 233 void Language::ForAllLanguages( 234 std::function<bool(lldb::LanguageType)> callback) { 235 for (uint32_t i = 1; i < num_languages; i++) { 236 if (!callback(language_names[i].type)) 237 break; 238 } 239 } 240 241 bool Language::LanguageIsCPlusPlus(LanguageType language) { 242 switch (language) { 243 case eLanguageTypeC_plus_plus: 244 case eLanguageTypeC_plus_plus_03: 245 case eLanguageTypeC_plus_plus_11: 246 case eLanguageTypeC_plus_plus_14: 247 case eLanguageTypeObjC_plus_plus: 248 return true; 249 default: 250 return false; 251 } 252 } 253 254 bool Language::LanguageIsObjC(LanguageType language) { 255 switch (language) { 256 case eLanguageTypeObjC: 257 case eLanguageTypeObjC_plus_plus: 258 return true; 259 default: 260 return false; 261 } 262 } 263 264 bool Language::LanguageIsC(LanguageType language) { 265 switch (language) { 266 case eLanguageTypeC: 267 case eLanguageTypeC89: 268 case eLanguageTypeC99: 269 case eLanguageTypeC11: 270 return true; 271 default: 272 return false; 273 } 274 } 275 276 bool Language::LanguageIsCFamily(LanguageType language) { 277 switch (language) { 278 case eLanguageTypeC: 279 case eLanguageTypeC89: 280 case eLanguageTypeC99: 281 case eLanguageTypeC11: 282 case eLanguageTypeC_plus_plus: 283 case eLanguageTypeC_plus_plus_03: 284 case eLanguageTypeC_plus_plus_11: 285 case eLanguageTypeC_plus_plus_14: 286 case eLanguageTypeObjC_plus_plus: 287 case eLanguageTypeObjC: 288 return true; 289 default: 290 return false; 291 } 292 } 293 294 bool Language::LanguageIsPascal(LanguageType language) { 295 switch (language) { 296 case eLanguageTypePascal83: 297 return true; 298 default: 299 return false; 300 } 301 } 302 303 LanguageType Language::GetPrimaryLanguage(LanguageType language) { 304 switch (language) { 305 case eLanguageTypeC_plus_plus: 306 case eLanguageTypeC_plus_plus_03: 307 case eLanguageTypeC_plus_plus_11: 308 case eLanguageTypeC_plus_plus_14: 309 return eLanguageTypeC_plus_plus; 310 case eLanguageTypeC: 311 case eLanguageTypeC89: 312 case eLanguageTypeC99: 313 case eLanguageTypeC11: 314 return eLanguageTypeC; 315 case eLanguageTypeObjC: 316 case eLanguageTypeObjC_plus_plus: 317 return eLanguageTypeObjC; 318 case eLanguageTypePascal83: 319 case eLanguageTypeCobol74: 320 case eLanguageTypeCobol85: 321 case eLanguageTypeFortran77: 322 case eLanguageTypeFortran90: 323 case eLanguageTypeFortran95: 324 case eLanguageTypeFortran03: 325 case eLanguageTypeFortran08: 326 case eLanguageTypeAda83: 327 case eLanguageTypeAda95: 328 case eLanguageTypeModula2: 329 case eLanguageTypeJava: 330 case eLanguageTypePLI: 331 case eLanguageTypeUPC: 332 case eLanguageTypeD: 333 case eLanguageTypePython: 334 case eLanguageTypeOpenCL: 335 case eLanguageTypeGo: 336 case eLanguageTypeModula3: 337 case eLanguageTypeHaskell: 338 case eLanguageTypeOCaml: 339 case eLanguageTypeRust: 340 case eLanguageTypeSwift: 341 case eLanguageTypeJulia: 342 case eLanguageTypeDylan: 343 case eLanguageTypeMipsAssembler: 344 case eLanguageTypeExtRenderScript: 345 case eLanguageTypeUnknown: 346 default: 347 return language; 348 } 349 } 350 351 void Language::GetLanguagesSupportingTypeSystems( 352 std::set<lldb::LanguageType> &languages, 353 std::set<lldb::LanguageType> &languages_for_expressions) { 354 uint32_t idx = 0; 355 356 while (TypeSystemEnumerateSupportedLanguages enumerate = PluginManager:: 357 GetTypeSystemEnumerateSupportedLanguagesCallbackAtIndex(idx++)) { 358 (*enumerate)(languages, languages_for_expressions); 359 } 360 } 361 362 void Language::GetLanguagesSupportingREPLs( 363 std::set<lldb::LanguageType> &languages) { 364 uint32_t idx = 0; 365 366 while (REPLEnumerateSupportedLanguages enumerate = 367 PluginManager::GetREPLEnumerateSupportedLanguagesCallbackAtIndex( 368 idx++)) { 369 (*enumerate)(languages); 370 } 371 } 372 373 std::unique_ptr<Language::TypeScavenger> Language::GetTypeScavenger() { 374 return nullptr; 375 } 376 377 const char *Language::GetLanguageSpecificTypeLookupHelp() { return nullptr; } 378 379 size_t Language::TypeScavenger::Find(ExecutionContextScope *exe_scope, 380 const char *key, ResultSet &results, 381 bool append) { 382 if (!exe_scope || !exe_scope->CalculateTarget().get()) 383 return false; 384 385 if (!key || !key[0]) 386 return false; 387 388 if (!append) 389 results.clear(); 390 391 size_t old_size = results.size(); 392 393 if (this->Find_Impl(exe_scope, key, results)) 394 return results.size() - old_size; 395 return 0; 396 } 397 398 bool Language::ImageListTypeScavenger::Find_Impl( 399 ExecutionContextScope *exe_scope, const char *key, ResultSet &results) { 400 bool result = false; 401 402 Target *target = exe_scope->CalculateTarget().get(); 403 if (target) { 404 const auto &images(target->GetImages()); 405 ConstString cs_key(key); 406 llvm::DenseSet<SymbolFile *> searched_sym_files; 407 TypeList matches; 408 images.FindTypes(nullptr, cs_key, false, UINT32_MAX, searched_sym_files, 409 matches); 410 for (const auto &match : matches.Types()) { 411 if (match) { 412 CompilerType compiler_type(match->GetFullCompilerType()); 413 compiler_type = AdjustForInclusion(compiler_type); 414 if (!compiler_type) 415 continue; 416 std::unique_ptr<Language::TypeScavenger::Result> scavengeresult( 417 new Result(compiler_type)); 418 results.insert(std::move(scavengeresult)); 419 result = true; 420 } 421 } 422 } 423 424 return result; 425 } 426 427 bool Language::GetFormatterPrefixSuffix(ValueObject &valobj, 428 ConstString type_hint, 429 std::string &prefix, 430 std::string &suffix) { 431 return false; 432 } 433 434 DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() { 435 return nullptr; 436 } 437 438 LazyBool Language::IsLogicalTrue(ValueObject &valobj, Status &error) { 439 return eLazyBoolCalculate; 440 } 441 442 bool Language::IsNilReference(ValueObject &valobj) { return false; } 443 444 bool Language::IsUninitializedReference(ValueObject &valobj) { return false; } 445 446 bool Language::GetFunctionDisplayName(const SymbolContext *sc, 447 const ExecutionContext *exe_ctx, 448 FunctionNameRepresentation representation, 449 Stream &s) { 450 return false; 451 } 452 453 void Language::GetExceptionResolverDescription(bool catch_on, bool throw_on, 454 Stream &s) { 455 GetDefaultExceptionResolverDescription(catch_on, throw_on, s); 456 } 457 458 void Language::GetDefaultExceptionResolverDescription(bool catch_on, 459 bool throw_on, 460 Stream &s) { 461 s.Printf("Exception breakpoint (catch: %s throw: %s)", 462 catch_on ? "on" : "off", throw_on ? "on" : "off"); 463 } 464 // Constructor 465 Language::Language() {} 466 467 // Destructor 468 Language::~Language() {} 469