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