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