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
GetGlobalLanguageProperties()40 LanguageProperties &Language::GetGlobalLanguageProperties() {
41 static LanguageProperties g_settings;
42 return g_settings;
43 }
44
GetSettingName()45 llvm::StringRef LanguageProperties::GetSettingName() {
46 static constexpr llvm::StringLiteral g_setting_name("language");
47 return g_setting_name;
48 }
49
LanguageProperties()50 LanguageProperties::LanguageProperties() {
51 m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
52 m_collection_sp->Initialize(g_language_properties);
53 }
54
GetEnableFilterForLineBreakpoints() const55 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
GetLanguagesMap()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 }
GetLanguagesMutex()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
FindPlugin(lldb::LanguageType language)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
FindPlugin(llvm::StringRef file_path)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
FindPlugin(LanguageType language,llvm::StringRef file_path)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
ForEach(std::function<bool (Language *)> callback)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
IsTopLevelFunction(Function & function)161 bool Language::IsTopLevelFunction(Function &function) { return false; }
162
GetFormatters()163 lldb::TypeCategoryImplSP Language::GetFormatters() { return nullptr; }
164
GetHardcodedFormats()165 HardcodedFormatters::HardcodedFormatFinder Language::GetHardcodedFormats() {
166 return {};
167 }
168
GetHardcodedSummaries()169 HardcodedFormatters::HardcodedSummaryFinder Language::GetHardcodedSummaries() {
170 return {};
171 }
172
173 HardcodedFormatters::HardcodedSyntheticFinder
GetHardcodedSynthetics()174 Language::GetHardcodedSynthetics() {
175 return {};
176 }
177
178 std::vector<FormattersMatchCandidate>
GetPossibleFormattersMatches(ValueObject & valobj,lldb::DynamicValueType use_dynamic)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
GetLanguageTypeFromString(llvm::StringRef string)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
GetNameForLanguageType(LanguageType language)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
PrintSupportedLanguagesForExpressions(Stream & s,llvm::StringRef prefix,llvm::StringRef suffix)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
PrintAllLanguages(Stream & s,const char * prefix,const char * suffix)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
ForAllLanguages(std::function<bool (lldb::LanguageType)> callback)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
LanguageIsCPlusPlus(LanguageType language)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
LanguageIsObjC(LanguageType language)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
LanguageIsC(LanguageType language)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
LanguageIsCFamily(LanguageType language)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
LanguageIsPascal(LanguageType language)356 bool Language::LanguageIsPascal(LanguageType language) {
357 switch (language) {
358 case eLanguageTypePascal83:
359 return true;
360 default:
361 return false;
362 }
363 }
364
GetPrimaryLanguage(LanguageType language)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
GetSupportedLanguages()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
GetLanguagesSupportingTypeSystems()424 LanguageSet Language::GetLanguagesSupportingTypeSystems() {
425 return PluginManager::GetAllTypeSystemSupportedLanguagesForTypes();
426 }
427
GetLanguagesSupportingTypeSystemsForExpressions()428 LanguageSet Language::GetLanguagesSupportingTypeSystemsForExpressions() {
429 return PluginManager::GetAllTypeSystemSupportedLanguagesForExpressions();
430 }
431
GetLanguagesSupportingREPLs()432 LanguageSet Language::GetLanguagesSupportingREPLs() {
433 return PluginManager::GetREPLAllTypeSystemSupportedLanguages();
434 }
435
GetTypeScavenger()436 std::unique_ptr<Language::TypeScavenger> Language::GetTypeScavenger() {
437 return nullptr;
438 }
439
GetLanguageSpecificTypeLookupHelp()440 const char *Language::GetLanguageSpecificTypeLookupHelp() { return nullptr; }
441
Find(ExecutionContextScope * exe_scope,const char * key,ResultSet & results,bool append)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
Find_Impl(ExecutionContextScope * exe_scope,const char * key,ResultSet & results)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>
GetFormatterPrefixSuffix(llvm::StringRef type_hint)489 Language::GetFormatterPrefixSuffix(llvm::StringRef type_hint) {
490 return std::pair<llvm::StringRef, llvm::StringRef>();
491 }
492
DemangledNameContainsPath(llvm::StringRef path,ConstString demangled) const493 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
GetDeclPrintingHelper()501 DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() {
502 return nullptr;
503 }
504
IsLogicalTrue(ValueObject & valobj,Status & error)505 LazyBool Language::IsLogicalTrue(ValueObject &valobj, Status &error) {
506 return eLazyBoolCalculate;
507 }
508
IsNilReference(ValueObject & valobj)509 bool Language::IsNilReference(ValueObject &valobj) { return false; }
510
IsUninitializedReference(ValueObject & valobj)511 bool Language::IsUninitializedReference(ValueObject &valobj) { return false; }
512
GetFunctionDisplayName(const SymbolContext * sc,const ExecutionContext * exe_ctx,FunctionNameRepresentation representation,Stream & s)513 bool Language::GetFunctionDisplayName(const SymbolContext *sc,
514 const ExecutionContext *exe_ctx,
515 FunctionNameRepresentation representation,
516 Stream &s) {
517 return false;
518 }
519
GetExceptionResolverDescription(bool catch_on,bool throw_on,Stream & s)520 void Language::GetExceptionResolverDescription(bool catch_on, bool throw_on,
521 Stream &s) {
522 GetDefaultExceptionResolverDescription(catch_on, throw_on, s);
523 }
524
GetDefaultExceptionResolverDescription(bool catch_on,bool throw_on,Stream & s)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 // Constructor
532 Language::Language() = default;
533
534 // Destructor
535 Language::~Language() = default;
536
SourceLanguage(lldb::LanguageType language_type)537 SourceLanguage::SourceLanguage(lldb::LanguageType language_type) {
538 auto lname =
539 llvm::dwarf::toDW_LNAME((llvm::dwarf::SourceLanguage)language_type);
540 if (!lname)
541 return;
542 name = lname->first;
543 version = lname->second;
544 }
545
AsLanguageType() const546 lldb::LanguageType SourceLanguage::AsLanguageType() const {
547 if (auto lang = llvm::dwarf::toDW_LANG((llvm::dwarf::SourceLanguageName)name,
548 version))
549 return (lldb::LanguageType)*lang;
550 return lldb::eLanguageTypeUnknown;
551 }
552
GetDescription() const553 llvm::StringRef SourceLanguage::GetDescription() const {
554 LanguageType type = AsLanguageType();
555 if (type)
556 return Language::GetNameForLanguageType(type);
557 return llvm::dwarf::LanguageDescription(
558 (llvm::dwarf::SourceLanguageName)name);
559 }
IsC() const560 bool SourceLanguage::IsC() const { return name == llvm::dwarf::DW_LNAME_C; }
561
IsObjC() const562 bool SourceLanguage::IsObjC() const {
563 return name == llvm::dwarf::DW_LNAME_ObjC;
564 }
565
IsCPlusPlus() const566 bool SourceLanguage::IsCPlusPlus() const {
567 return name == llvm::dwarf::DW_LNAME_C_plus_plus;
568 }
569