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