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