1 //===-- Language.cpp -------------------------------------------------*- C++
2 //-*-===//
3 //
4 //                     The LLVM Compiler Infrastructure
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10 
11 #include <functional>
12 #include <map>
13 #include <mutex>
14 
15 #include "lldb/Target/Language.h"
16 
17 #include "lldb/Core/PluginManager.h"
18 #include "lldb/Symbol/SymbolFile.h"
19 #include "lldb/Symbol/TypeList.h"
20 #include "lldb/Target/Target.h"
21 #include "lldb/Utility/Stream.h"
22 
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 
GetLanguagesMap()32 static LanguagesMap &GetLanguagesMap() {
33   static LanguagesMap *g_map = nullptr;
34   static llvm::once_flag g_initialize;
35 
36   llvm::call_once(g_initialize, [] {
37     g_map = new LanguagesMap(); // NOTE: INTENTIONAL LEAK due to global
38                                 // destructor chain
39   });
40 
41   return *g_map;
42 }
GetLanguagesMutex()43 static std::mutex &GetLanguagesMutex() {
44   static std::mutex *g_mutex = nullptr;
45   static llvm::once_flag g_initialize;
46 
47   llvm::call_once(g_initialize, [] {
48     g_mutex = new std::mutex(); // NOTE: INTENTIONAL LEAK due to global
49                                 // destructor chain
50   });
51 
52   return *g_mutex;
53 }
54 
FindPlugin(lldb::LanguageType language)55 Language *Language::FindPlugin(lldb::LanguageType language) {
56   std::lock_guard<std::mutex> guard(GetLanguagesMutex());
57   LanguagesMap &map(GetLanguagesMap());
58   auto iter = map.find(language), end = map.end();
59   if (iter != end)
60     return iter->second.get();
61 
62   Language *language_ptr = nullptr;
63   LanguageCreateInstance create_callback;
64 
65   for (uint32_t idx = 0;
66        (create_callback =
67             PluginManager::GetLanguageCreateCallbackAtIndex(idx)) != nullptr;
68        ++idx) {
69     language_ptr = create_callback(language);
70 
71     if (language_ptr) {
72       map[language] = std::unique_ptr<Language>(language_ptr);
73       return language_ptr;
74     }
75   }
76 
77   return nullptr;
78 }
79 
FindPlugin(llvm::StringRef file_path)80 Language *Language::FindPlugin(llvm::StringRef file_path) {
81   Language *result = nullptr;
82   ForEach([&result, file_path](Language *language) {
83     if (language->IsSourceFile(file_path)) {
84       result = language;
85       return false;
86     }
87     return true;
88   });
89   return result;
90 }
91 
FindPlugin(LanguageType language,llvm::StringRef file_path)92 Language *Language::FindPlugin(LanguageType language,
93                                llvm::StringRef file_path) {
94   Language *result = FindPlugin(language);
95   // Finding a language by file path is slower, we so we use this as the
96   // fallback.
97   if (!result)
98     result = FindPlugin(file_path);
99   return result;
100 }
101 
ForEach(std::function<bool (Language *)> callback)102 void Language::ForEach(std::function<bool(Language *)> callback) {
103   // If we want to iterate over all languages, we first have to complete the
104   // LanguagesMap.
105   static llvm::once_flag g_initialize;
106   llvm::call_once(g_initialize, [] {
107     for (unsigned lang = eLanguageTypeUnknown; lang < eNumLanguageTypes;
108          ++lang) {
109       FindPlugin(static_cast<lldb::LanguageType>(lang));
110     }
111   });
112 
113   std::lock_guard<std::mutex> guard(GetLanguagesMutex());
114   LanguagesMap &map(GetLanguagesMap());
115   for (const auto &entry : map) {
116     if (!callback(entry.second.get()))
117       break;
118   }
119 }
120 
IsTopLevelFunction(Function & function)121 bool Language::IsTopLevelFunction(Function &function) { return false; }
122 
GetFormatters()123 lldb::TypeCategoryImplSP Language::GetFormatters() { return nullptr; }
124 
GetHardcodedFormats()125 HardcodedFormatters::HardcodedFormatFinder Language::GetHardcodedFormats() {
126   return {};
127 }
128 
GetHardcodedSummaries()129 HardcodedFormatters::HardcodedSummaryFinder Language::GetHardcodedSummaries() {
130   return {};
131 }
132 
133 HardcodedFormatters::HardcodedSyntheticFinder
GetHardcodedSynthetics()134 Language::GetHardcodedSynthetics() {
135   return {};
136 }
137 
138 HardcodedFormatters::HardcodedValidatorFinder
GetHardcodedValidators()139 Language::GetHardcodedValidators() {
140   return {};
141 }
142 
143 std::vector<ConstString>
GetPossibleFormattersMatches(ValueObject & valobj,lldb::DynamicValueType use_dynamic)144 Language::GetPossibleFormattersMatches(ValueObject &valobj,
145                                        lldb::DynamicValueType use_dynamic) {
146   return {};
147 }
148 
149 lldb_private::formatters::StringPrinter::EscapingHelper
GetStringPrinterEscapingHelper(lldb_private::formatters::StringPrinter::GetPrintableElementType elem_type)150 Language::GetStringPrinterEscapingHelper(
151     lldb_private::formatters::StringPrinter::GetPrintableElementType
152         elem_type) {
153   return StringPrinter::GetDefaultEscapingHelper(elem_type);
154 }
155 
156 struct language_name_pair {
157   const char *name;
158   LanguageType type;
159 };
160 
161 struct language_name_pair language_names[] = {
162     // To allow GetNameForLanguageType to be a simple array lookup, the first
163     // part of this array must follow enum LanguageType exactly.
164     {"unknown", eLanguageTypeUnknown},
165     {"c89", eLanguageTypeC89},
166     {"c", eLanguageTypeC},
167     {"ada83", eLanguageTypeAda83},
168     {"c++", eLanguageTypeC_plus_plus},
169     {"cobol74", eLanguageTypeCobol74},
170     {"cobol85", eLanguageTypeCobol85},
171     {"fortran77", eLanguageTypeFortran77},
172     {"fortran90", eLanguageTypeFortran90},
173     {"pascal83", eLanguageTypePascal83},
174     {"modula2", eLanguageTypeModula2},
175     {"java", eLanguageTypeJava},
176     {"c99", eLanguageTypeC99},
177     {"ada95", eLanguageTypeAda95},
178     {"fortran95", eLanguageTypeFortran95},
179     {"pli", eLanguageTypePLI},
180     {"objective-c", eLanguageTypeObjC},
181     {"objective-c++", eLanguageTypeObjC_plus_plus},
182     {"upc", eLanguageTypeUPC},
183     {"d", eLanguageTypeD},
184     {"python", eLanguageTypePython},
185     {"opencl", eLanguageTypeOpenCL},
186     {"go", eLanguageTypeGo},
187     {"modula3", eLanguageTypeModula3},
188     {"haskell", eLanguageTypeHaskell},
189     {"c++03", eLanguageTypeC_plus_plus_03},
190     {"c++11", eLanguageTypeC_plus_plus_11},
191     {"ocaml", eLanguageTypeOCaml},
192     {"rust", eLanguageTypeRust},
193     {"c11", eLanguageTypeC11},
194     {"swift", eLanguageTypeSwift},
195     {"julia", eLanguageTypeJulia},
196     {"dylan", eLanguageTypeDylan},
197     {"c++14", eLanguageTypeC_plus_plus_14},
198     {"fortran03", eLanguageTypeFortran03},
199     {"fortran08", eLanguageTypeFortran08},
200     // Vendor Extensions
201     {"mipsassem", eLanguageTypeMipsAssembler},
202     {"renderscript", eLanguageTypeExtRenderScript},
203     // Now synonyms, in arbitrary order
204     {"objc", eLanguageTypeObjC},
205     {"objc++", eLanguageTypeObjC_plus_plus},
206     {"pascal", eLanguageTypePascal83}};
207 
208 static uint32_t num_languages =
209     sizeof(language_names) / sizeof(struct language_name_pair);
210 
GetLanguageTypeFromString(llvm::StringRef string)211 LanguageType Language::GetLanguageTypeFromString(llvm::StringRef string) {
212   for (const auto &L : language_names) {
213     if (string.equals_lower(L.name))
214       return static_cast<LanguageType>(L.type);
215   }
216 
217   return eLanguageTypeUnknown;
218 }
219 
GetNameForLanguageType(LanguageType language)220 const char *Language::GetNameForLanguageType(LanguageType language) {
221   if (language < num_languages)
222     return language_names[language].name;
223   else
224     return language_names[eLanguageTypeUnknown].name;
225 }
226 
PrintAllLanguages(Stream & s,const char * prefix,const char * suffix)227 void Language::PrintAllLanguages(Stream &s, const char *prefix,
228                                  const char *suffix) {
229   for (uint32_t i = 1; i < num_languages; i++) {
230     s.Printf("%s%s%s", prefix, language_names[i].name, suffix);
231   }
232 }
233 
ForAllLanguages(std::function<bool (lldb::LanguageType)> callback)234 void Language::ForAllLanguages(
235     std::function<bool(lldb::LanguageType)> callback) {
236   for (uint32_t i = 1; i < num_languages; i++) {
237     if (!callback(language_names[i].type))
238       break;
239   }
240 }
241 
LanguageIsCPlusPlus(LanguageType language)242 bool Language::LanguageIsCPlusPlus(LanguageType language) {
243   switch (language) {
244   case eLanguageTypeC_plus_plus:
245   case eLanguageTypeC_plus_plus_03:
246   case eLanguageTypeC_plus_plus_11:
247   case eLanguageTypeC_plus_plus_14:
248   case eLanguageTypeObjC_plus_plus:
249     return true;
250   default:
251     return false;
252   }
253 }
254 
LanguageIsObjC(LanguageType language)255 bool Language::LanguageIsObjC(LanguageType language) {
256   switch (language) {
257   case eLanguageTypeObjC:
258   case eLanguageTypeObjC_plus_plus:
259     return true;
260   default:
261     return false;
262   }
263 }
264 
LanguageIsC(LanguageType language)265 bool Language::LanguageIsC(LanguageType language) {
266   switch (language) {
267   case eLanguageTypeC:
268   case eLanguageTypeC89:
269   case eLanguageTypeC99:
270   case eLanguageTypeC11:
271     return true;
272   default:
273     return false;
274   }
275 }
276 
LanguageIsPascal(LanguageType language)277 bool Language::LanguageIsPascal(LanguageType language) {
278   switch (language) {
279   case eLanguageTypePascal83:
280     return true;
281   default:
282     return false;
283   }
284 }
285 
GetPrimaryLanguage(LanguageType language)286 LanguageType Language::GetPrimaryLanguage(LanguageType language) {
287   switch (language) {
288   case eLanguageTypeC_plus_plus:
289   case eLanguageTypeC_plus_plus_03:
290   case eLanguageTypeC_plus_plus_11:
291   case eLanguageTypeC_plus_plus_14:
292     return eLanguageTypeC_plus_plus;
293   case eLanguageTypeC:
294   case eLanguageTypeC89:
295   case eLanguageTypeC99:
296   case eLanguageTypeC11:
297     return eLanguageTypeC;
298   case eLanguageTypeObjC:
299   case eLanguageTypeObjC_plus_plus:
300     return eLanguageTypeObjC;
301   case eLanguageTypePascal83:
302   case eLanguageTypeCobol74:
303   case eLanguageTypeCobol85:
304   case eLanguageTypeFortran77:
305   case eLanguageTypeFortran90:
306   case eLanguageTypeFortran95:
307   case eLanguageTypeFortran03:
308   case eLanguageTypeFortran08:
309   case eLanguageTypeAda83:
310   case eLanguageTypeAda95:
311   case eLanguageTypeModula2:
312   case eLanguageTypeJava:
313   case eLanguageTypePLI:
314   case eLanguageTypeUPC:
315   case eLanguageTypeD:
316   case eLanguageTypePython:
317   case eLanguageTypeOpenCL:
318   case eLanguageTypeGo:
319   case eLanguageTypeModula3:
320   case eLanguageTypeHaskell:
321   case eLanguageTypeOCaml:
322   case eLanguageTypeRust:
323   case eLanguageTypeSwift:
324   case eLanguageTypeJulia:
325   case eLanguageTypeDylan:
326   case eLanguageTypeMipsAssembler:
327   case eLanguageTypeExtRenderScript:
328   case eLanguageTypeUnknown:
329   default:
330     return language;
331   }
332 }
333 
GetLanguagesSupportingTypeSystems(std::set<lldb::LanguageType> & languages,std::set<lldb::LanguageType> & languages_for_expressions)334 void Language::GetLanguagesSupportingTypeSystems(
335     std::set<lldb::LanguageType> &languages,
336     std::set<lldb::LanguageType> &languages_for_expressions) {
337   uint32_t idx = 0;
338 
339   while (TypeSystemEnumerateSupportedLanguages enumerate = PluginManager::
340              GetTypeSystemEnumerateSupportedLanguagesCallbackAtIndex(idx++)) {
341     (*enumerate)(languages, languages_for_expressions);
342   }
343 }
344 
GetLanguagesSupportingREPLs(std::set<lldb::LanguageType> & languages)345 void Language::GetLanguagesSupportingREPLs(
346     std::set<lldb::LanguageType> &languages) {
347   uint32_t idx = 0;
348 
349   while (REPLEnumerateSupportedLanguages enumerate =
350              PluginManager::GetREPLEnumerateSupportedLanguagesCallbackAtIndex(
351                  idx++)) {
352     (*enumerate)(languages);
353   }
354 }
355 
GetTypeScavenger()356 std::unique_ptr<Language::TypeScavenger> Language::GetTypeScavenger() {
357   return nullptr;
358 }
359 
GetLanguageSpecificTypeLookupHelp()360 const char *Language::GetLanguageSpecificTypeLookupHelp() { return nullptr; }
361 
Find(ExecutionContextScope * exe_scope,const char * key,ResultSet & results,bool append)362 size_t Language::TypeScavenger::Find(ExecutionContextScope *exe_scope,
363                                      const char *key, ResultSet &results,
364                                      bool append) {
365   if (!exe_scope || !exe_scope->CalculateTarget().get())
366     return false;
367 
368   if (!key || !key[0])
369     return false;
370 
371   if (!append)
372     results.clear();
373 
374   size_t old_size = results.size();
375 
376   if (this->Find_Impl(exe_scope, key, results))
377     return results.size() - old_size;
378   return 0;
379 }
380 
Find_Impl(ExecutionContextScope * exe_scope,const char * key,ResultSet & results)381 bool Language::ImageListTypeScavenger::Find_Impl(
382     ExecutionContextScope *exe_scope, const char *key, ResultSet &results) {
383   bool result = false;
384 
385   Target *target = exe_scope->CalculateTarget().get();
386   if (target) {
387     const auto &images(target->GetImages());
388     ConstString cs_key(key);
389     llvm::DenseSet<SymbolFile *> searched_sym_files;
390     TypeList matches;
391     images.FindTypes(nullptr, cs_key, false, UINT32_MAX, searched_sym_files,
392                      matches);
393     for (const auto &match : matches.Types()) {
394       if (match.get()) {
395         CompilerType compiler_type(match->GetFullCompilerType());
396         compiler_type = AdjustForInclusion(compiler_type);
397         if (!compiler_type)
398           continue;
399         std::unique_ptr<Language::TypeScavenger::Result> scavengeresult(
400             new Result(compiler_type));
401         results.insert(std::move(scavengeresult));
402         result = true;
403       }
404     }
405   }
406 
407   return result;
408 }
409 
GetFormatterPrefixSuffix(ValueObject & valobj,ConstString type_hint,std::string & prefix,std::string & suffix)410 bool Language::GetFormatterPrefixSuffix(ValueObject &valobj,
411                                         ConstString type_hint,
412                                         std::string &prefix,
413                                         std::string &suffix) {
414   return false;
415 }
416 
GetDeclPrintingHelper()417 DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() {
418   return nullptr;
419 }
420 
IsLogicalTrue(ValueObject & valobj,Status & error)421 LazyBool Language::IsLogicalTrue(ValueObject &valobj, Status &error) {
422   return eLazyBoolCalculate;
423 }
424 
IsNilReference(ValueObject & valobj)425 bool Language::IsNilReference(ValueObject &valobj) { return false; }
426 
IsUninitializedReference(ValueObject & valobj)427 bool Language::IsUninitializedReference(ValueObject &valobj) { return false; }
428 
GetFunctionDisplayName(const SymbolContext * sc,const ExecutionContext * exe_ctx,FunctionNameRepresentation representation,Stream & s)429 bool Language::GetFunctionDisplayName(const SymbolContext *sc,
430                                       const ExecutionContext *exe_ctx,
431                                       FunctionNameRepresentation representation,
432                                       Stream &s) {
433   return false;
434 }
435 
GetExceptionResolverDescription(bool catch_on,bool throw_on,Stream & s)436 void Language::GetExceptionResolverDescription(bool catch_on, bool throw_on,
437                                                Stream &s) {
438   GetDefaultExceptionResolverDescription(catch_on, throw_on, s);
439 }
440 
GetDefaultExceptionResolverDescription(bool catch_on,bool throw_on,Stream & s)441 void Language::GetDefaultExceptionResolverDescription(bool catch_on,
442                                                       bool throw_on,
443                                                       Stream &s) {
444   s.Printf("Exception breakpoint (catch: %s throw: %s)",
445            catch_on ? "on" : "off", throw_on ? "on" : "off");
446 }
447 //----------------------------------------------------------------------
448 // Constructor
449 //----------------------------------------------------------------------
Language()450 Language::Language() {}
451 
452 //----------------------------------------------------------------------
453 // Destructor
454 //----------------------------------------------------------------------
~Language()455 Language::~Language() {}
456