xref: /freebsd/contrib/llvm-project/lldb/source/Target/Language.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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