150
|
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
|
|
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 }
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
236
|
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))
|
150
|
126 break;
|
|
127 }
|
|
128 }
|
|
129
|
|
130 bool Language::IsTopLevelFunction(Function &function) { return false; }
|
|
131
|
|
132 lldb::TypeCategoryImplSP Language::GetFormatters() { return nullptr; }
|
|
133
|
|
134 HardcodedFormatters::HardcodedFormatFinder Language::GetHardcodedFormats() {
|
|
135 return {};
|
|
136 }
|
|
137
|
|
138 HardcodedFormatters::HardcodedSummaryFinder Language::GetHardcodedSummaries() {
|
|
139 return {};
|
|
140 }
|
|
141
|
|
142 HardcodedFormatters::HardcodedSyntheticFinder
|
|
143 Language::GetHardcodedSynthetics() {
|
|
144 return {};
|
|
145 }
|
|
146
|
236
|
147 std::vector<FormattersMatchCandidate>
|
150
|
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},
|
252
|
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},
|
150
|
216 // Vendor Extensions
|
221
|
217 {"assembler", eLanguageTypeMipsAssembler},
|
150
|
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
|
|
226 LanguageType Language::GetLanguageTypeFromString(llvm::StringRef string) {
|
|
227 for (const auto &L : language_names) {
|
223
|
228 if (string.equals_insensitive(L.name))
|
150
|
229 return static_cast<LanguageType>(L.type);
|
|
230 }
|
|
231
|
|
232 return eLanguageTypeUnknown;
|
|
233 }
|
|
234
|
|
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
|
252
|
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
|
150
|
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
|
|
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
|
|
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:
|
252
|
274 case eLanguageTypeC_plus_plus_17:
|
|
275 case eLanguageTypeC_plus_plus_20:
|
150
|
276 case eLanguageTypeObjC_plus_plus:
|
|
277 return true;
|
|
278 default:
|
|
279 return false;
|
|
280 }
|
|
281 }
|
|
282
|
|
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
|
|
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
|
|
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:
|
252
|
315 case eLanguageTypeC_plus_plus_17:
|
|
316 case eLanguageTypeC_plus_plus_20:
|
150
|
317 case eLanguageTypeObjC_plus_plus:
|
|
318 case eLanguageTypeObjC:
|
|
319 return true;
|
|
320 default:
|
|
321 return false;
|
|
322 }
|
|
323 }
|
|
324
|
|
325 bool Language::LanguageIsPascal(LanguageType language) {
|
|
326 switch (language) {
|
|
327 case eLanguageTypePascal83:
|
|
328 return true;
|
|
329 default:
|
|
330 return false;
|
|
331 }
|
|
332 }
|
|
333
|
|
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:
|
252
|
340 case eLanguageTypeC_plus_plus_17:
|
|
341 case eLanguageTypeC_plus_plus_20:
|
150
|
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 eLanguageTypeUnknown:
|
|
378 default:
|
|
379 return language;
|
|
380 }
|
|
381 }
|
|
382
|
|
383 std::set<lldb::LanguageType> Language::GetSupportedLanguages() {
|
|
384 std::set<lldb::LanguageType> supported_languages;
|
|
385 ForEach([&](Language *lang) {
|
|
386 supported_languages.emplace(lang->GetLanguageType());
|
|
387 return true;
|
|
388 });
|
|
389 return supported_languages;
|
|
390 }
|
|
391
|
|
392 LanguageSet Language::GetLanguagesSupportingTypeSystems() {
|
|
393 return PluginManager::GetAllTypeSystemSupportedLanguagesForTypes();
|
|
394 }
|
|
395
|
|
396 LanguageSet Language::GetLanguagesSupportingTypeSystemsForExpressions() {
|
|
397 return PluginManager::GetAllTypeSystemSupportedLanguagesForExpressions();
|
|
398 }
|
|
399
|
|
400 LanguageSet Language::GetLanguagesSupportingREPLs() {
|
|
401 return PluginManager::GetREPLAllTypeSystemSupportedLanguages();
|
|
402 }
|
|
403
|
|
404 std::unique_ptr<Language::TypeScavenger> Language::GetTypeScavenger() {
|
|
405 return nullptr;
|
|
406 }
|
|
407
|
|
408 const char *Language::GetLanguageSpecificTypeLookupHelp() { return nullptr; }
|
|
409
|
|
410 size_t Language::TypeScavenger::Find(ExecutionContextScope *exe_scope,
|
|
411 const char *key, ResultSet &results,
|
|
412 bool append) {
|
|
413 if (!exe_scope || !exe_scope->CalculateTarget().get())
|
|
414 return false;
|
|
415
|
|
416 if (!key || !key[0])
|
|
417 return false;
|
|
418
|
|
419 if (!append)
|
|
420 results.clear();
|
|
421
|
|
422 size_t old_size = results.size();
|
|
423
|
|
424 if (this->Find_Impl(exe_scope, key, results))
|
|
425 return results.size() - old_size;
|
|
426 return 0;
|
|
427 }
|
|
428
|
|
429 bool Language::ImageListTypeScavenger::Find_Impl(
|
|
430 ExecutionContextScope *exe_scope, const char *key, ResultSet &results) {
|
|
431 bool result = false;
|
|
432
|
|
433 Target *target = exe_scope->CalculateTarget().get();
|
|
434 if (target) {
|
|
435 const auto &images(target->GetImages());
|
|
436 ConstString cs_key(key);
|
|
437 llvm::DenseSet<SymbolFile *> searched_sym_files;
|
|
438 TypeList matches;
|
|
439 images.FindTypes(nullptr, cs_key, false, UINT32_MAX, searched_sym_files,
|
|
440 matches);
|
|
441 for (const auto &match : matches.Types()) {
|
|
442 if (match) {
|
|
443 CompilerType compiler_type(match->GetFullCompilerType());
|
|
444 compiler_type = AdjustForInclusion(compiler_type);
|
|
445 if (!compiler_type)
|
|
446 continue;
|
|
447 std::unique_ptr<Language::TypeScavenger::Result> scavengeresult(
|
|
448 new Result(compiler_type));
|
|
449 results.insert(std::move(scavengeresult));
|
|
450 result = true;
|
|
451 }
|
|
452 }
|
|
453 }
|
|
454
|
|
455 return result;
|
|
456 }
|
|
457
|
252
|
458 std::pair<llvm::StringRef, llvm::StringRef>
|
|
459 Language::GetFormatterPrefixSuffix(llvm::StringRef type_hint) {
|
|
460 return std::pair<llvm::StringRef, llvm::StringRef>();
|
150
|
461 }
|
|
462
|
252
|
463 bool Language::DemangledNameContainsPath(llvm::StringRef path,
|
236
|
464 ConstString demangled) const {
|
|
465 // The base implementation does a simple contains comparision:
|
|
466 if (path.empty())
|
|
467 return false;
|
252
|
468 return demangled.GetStringRef().contains(path);
|
236
|
469 }
|
|
470
|
150
|
471 DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() {
|
|
472 return nullptr;
|
|
473 }
|
|
474
|
|
475 LazyBool Language::IsLogicalTrue(ValueObject &valobj, Status &error) {
|
|
476 return eLazyBoolCalculate;
|
|
477 }
|
|
478
|
|
479 bool Language::IsNilReference(ValueObject &valobj) { return false; }
|
|
480
|
|
481 bool Language::IsUninitializedReference(ValueObject &valobj) { return false; }
|
|
482
|
|
483 bool Language::GetFunctionDisplayName(const SymbolContext *sc,
|
|
484 const ExecutionContext *exe_ctx,
|
|
485 FunctionNameRepresentation representation,
|
|
486 Stream &s) {
|
|
487 return false;
|
|
488 }
|
|
489
|
|
490 void Language::GetExceptionResolverDescription(bool catch_on, bool throw_on,
|
|
491 Stream &s) {
|
|
492 GetDefaultExceptionResolverDescription(catch_on, throw_on, s);
|
|
493 }
|
|
494
|
|
495 void Language::GetDefaultExceptionResolverDescription(bool catch_on,
|
|
496 bool throw_on,
|
|
497 Stream &s) {
|
|
498 s.Printf("Exception breakpoint (catch: %s throw: %s)",
|
|
499 catch_on ? "on" : "off", throw_on ? "on" : "off");
|
|
500 }
|
|
501 // Constructor
|
223
|
502 Language::Language() = default;
|
150
|
503
|
|
504 // Destructor
|
223
|
505 Language::~Language() = default;
|