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<ConstString>
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 // Vendor Extensions
198 {"assembler", eLanguageTypeMipsAssembler},
199 {"renderscript", eLanguageTypeExtRenderScript},
200 // Now synonyms, in arbitrary order
201 {"objc", eLanguageTypeObjC},
202 {"objc++", eLanguageTypeObjC_plus_plus},
203 {"pascal", eLanguageTypePascal83}};
204
205 static uint32_t num_languages =
206 sizeof(language_names) / sizeof(struct language_name_pair);
207
GetLanguageTypeFromString(llvm::StringRef string)208 LanguageType Language::GetLanguageTypeFromString(llvm::StringRef string) {
209 for (const auto &L : language_names) {
210 if (string.equals_insensitive(L.name))
211 return static_cast<LanguageType>(L.type);
212 }
213
214 return eLanguageTypeUnknown;
215 }
216
GetNameForLanguageType(LanguageType language)217 const char *Language::GetNameForLanguageType(LanguageType language) {
218 if (language < num_languages)
219 return language_names[language].name;
220 else
221 return language_names[eLanguageTypeUnknown].name;
222 }
223
PrintAllLanguages(Stream & s,const char * prefix,const char * suffix)224 void Language::PrintAllLanguages(Stream &s, const char *prefix,
225 const char *suffix) {
226 for (uint32_t i = 1; i < num_languages; i++) {
227 s.Printf("%s%s%s", prefix, language_names[i].name, suffix);
228 }
229 }
230
ForAllLanguages(std::function<bool (lldb::LanguageType)> callback)231 void Language::ForAllLanguages(
232 std::function<bool(lldb::LanguageType)> callback) {
233 for (uint32_t i = 1; i < num_languages; i++) {
234 if (!callback(language_names[i].type))
235 break;
236 }
237 }
238
LanguageIsCPlusPlus(LanguageType language)239 bool Language::LanguageIsCPlusPlus(LanguageType language) {
240 switch (language) {
241 case eLanguageTypeC_plus_plus:
242 case eLanguageTypeC_plus_plus_03:
243 case eLanguageTypeC_plus_plus_11:
244 case eLanguageTypeC_plus_plus_14:
245 case eLanguageTypeObjC_plus_plus:
246 return true;
247 default:
248 return false;
249 }
250 }
251
LanguageIsObjC(LanguageType language)252 bool Language::LanguageIsObjC(LanguageType language) {
253 switch (language) {
254 case eLanguageTypeObjC:
255 case eLanguageTypeObjC_plus_plus:
256 return true;
257 default:
258 return false;
259 }
260 }
261
LanguageIsC(LanguageType language)262 bool Language::LanguageIsC(LanguageType language) {
263 switch (language) {
264 case eLanguageTypeC:
265 case eLanguageTypeC89:
266 case eLanguageTypeC99:
267 case eLanguageTypeC11:
268 return true;
269 default:
270 return false;
271 }
272 }
273
LanguageIsCFamily(LanguageType language)274 bool Language::LanguageIsCFamily(LanguageType language) {
275 switch (language) {
276 case eLanguageTypeC:
277 case eLanguageTypeC89:
278 case eLanguageTypeC99:
279 case eLanguageTypeC11:
280 case eLanguageTypeC_plus_plus:
281 case eLanguageTypeC_plus_plus_03:
282 case eLanguageTypeC_plus_plus_11:
283 case eLanguageTypeC_plus_plus_14:
284 case eLanguageTypeObjC_plus_plus:
285 case eLanguageTypeObjC:
286 return true;
287 default:
288 return false;
289 }
290 }
291
LanguageIsPascal(LanguageType language)292 bool Language::LanguageIsPascal(LanguageType language) {
293 switch (language) {
294 case eLanguageTypePascal83:
295 return true;
296 default:
297 return false;
298 }
299 }
300
GetPrimaryLanguage(LanguageType language)301 LanguageType Language::GetPrimaryLanguage(LanguageType language) {
302 switch (language) {
303 case eLanguageTypeC_plus_plus:
304 case eLanguageTypeC_plus_plus_03:
305 case eLanguageTypeC_plus_plus_11:
306 case eLanguageTypeC_plus_plus_14:
307 return eLanguageTypeC_plus_plus;
308 case eLanguageTypeC:
309 case eLanguageTypeC89:
310 case eLanguageTypeC99:
311 case eLanguageTypeC11:
312 return eLanguageTypeC;
313 case eLanguageTypeObjC:
314 case eLanguageTypeObjC_plus_plus:
315 return eLanguageTypeObjC;
316 case eLanguageTypePascal83:
317 case eLanguageTypeCobol74:
318 case eLanguageTypeCobol85:
319 case eLanguageTypeFortran77:
320 case eLanguageTypeFortran90:
321 case eLanguageTypeFortran95:
322 case eLanguageTypeFortran03:
323 case eLanguageTypeFortran08:
324 case eLanguageTypeAda83:
325 case eLanguageTypeAda95:
326 case eLanguageTypeModula2:
327 case eLanguageTypeJava:
328 case eLanguageTypePLI:
329 case eLanguageTypeUPC:
330 case eLanguageTypeD:
331 case eLanguageTypePython:
332 case eLanguageTypeOpenCL:
333 case eLanguageTypeGo:
334 case eLanguageTypeModula3:
335 case eLanguageTypeHaskell:
336 case eLanguageTypeOCaml:
337 case eLanguageTypeRust:
338 case eLanguageTypeSwift:
339 case eLanguageTypeJulia:
340 case eLanguageTypeDylan:
341 case eLanguageTypeMipsAssembler:
342 case eLanguageTypeExtRenderScript:
343 case eLanguageTypeUnknown:
344 default:
345 return language;
346 }
347 }
348
GetSupportedLanguages()349 std::set<lldb::LanguageType> Language::GetSupportedLanguages() {
350 std::set<lldb::LanguageType> supported_languages;
351 ForEach([&](Language *lang) {
352 supported_languages.emplace(lang->GetLanguageType());
353 return true;
354 });
355 return supported_languages;
356 }
357
GetLanguagesSupportingTypeSystems()358 LanguageSet Language::GetLanguagesSupportingTypeSystems() {
359 return PluginManager::GetAllTypeSystemSupportedLanguagesForTypes();
360 }
361
GetLanguagesSupportingTypeSystemsForExpressions()362 LanguageSet Language::GetLanguagesSupportingTypeSystemsForExpressions() {
363 return PluginManager::GetAllTypeSystemSupportedLanguagesForExpressions();
364 }
365
GetLanguagesSupportingREPLs()366 LanguageSet Language::GetLanguagesSupportingREPLs() {
367 return PluginManager::GetREPLAllTypeSystemSupportedLanguages();
368 }
369
GetTypeScavenger()370 std::unique_ptr<Language::TypeScavenger> Language::GetTypeScavenger() {
371 return nullptr;
372 }
373
GetLanguageSpecificTypeLookupHelp()374 const char *Language::GetLanguageSpecificTypeLookupHelp() { return nullptr; }
375
Find(ExecutionContextScope * exe_scope,const char * key,ResultSet & results,bool append)376 size_t Language::TypeScavenger::Find(ExecutionContextScope *exe_scope,
377 const char *key, ResultSet &results,
378 bool append) {
379 if (!exe_scope || !exe_scope->CalculateTarget().get())
380 return false;
381
382 if (!key || !key[0])
383 return false;
384
385 if (!append)
386 results.clear();
387
388 size_t old_size = results.size();
389
390 if (this->Find_Impl(exe_scope, key, results))
391 return results.size() - old_size;
392 return 0;
393 }
394
Find_Impl(ExecutionContextScope * exe_scope,const char * key,ResultSet & results)395 bool Language::ImageListTypeScavenger::Find_Impl(
396 ExecutionContextScope *exe_scope, const char *key, ResultSet &results) {
397 bool result = false;
398
399 Target *target = exe_scope->CalculateTarget().get();
400 if (target) {
401 const auto &images(target->GetImages());
402 ConstString cs_key(key);
403 llvm::DenseSet<SymbolFile *> searched_sym_files;
404 TypeList matches;
405 images.FindTypes(nullptr, cs_key, false, UINT32_MAX, searched_sym_files,
406 matches);
407 for (const auto &match : matches.Types()) {
408 if (match) {
409 CompilerType compiler_type(match->GetFullCompilerType());
410 compiler_type = AdjustForInclusion(compiler_type);
411 if (!compiler_type)
412 continue;
413 std::unique_ptr<Language::TypeScavenger::Result> scavengeresult(
414 new Result(compiler_type));
415 results.insert(std::move(scavengeresult));
416 result = true;
417 }
418 }
419 }
420
421 return result;
422 }
423
GetFormatterPrefixSuffix(ValueObject & valobj,ConstString type_hint,std::string & prefix,std::string & suffix)424 bool Language::GetFormatterPrefixSuffix(ValueObject &valobj,
425 ConstString type_hint,
426 std::string &prefix,
427 std::string &suffix) {
428 return false;
429 }
430
GetDeclPrintingHelper()431 DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() {
432 return nullptr;
433 }
434
IsLogicalTrue(ValueObject & valobj,Status & error)435 LazyBool Language::IsLogicalTrue(ValueObject &valobj, Status &error) {
436 return eLazyBoolCalculate;
437 }
438
IsNilReference(ValueObject & valobj)439 bool Language::IsNilReference(ValueObject &valobj) { return false; }
440
IsUninitializedReference(ValueObject & valobj)441 bool Language::IsUninitializedReference(ValueObject &valobj) { return false; }
442
GetFunctionDisplayName(const SymbolContext * sc,const ExecutionContext * exe_ctx,FunctionNameRepresentation representation,Stream & s)443 bool Language::GetFunctionDisplayName(const SymbolContext *sc,
444 const ExecutionContext *exe_ctx,
445 FunctionNameRepresentation representation,
446 Stream &s) {
447 return false;
448 }
449
GetExceptionResolverDescription(bool catch_on,bool throw_on,Stream & s)450 void Language::GetExceptionResolverDescription(bool catch_on, bool throw_on,
451 Stream &s) {
452 GetDefaultExceptionResolverDescription(catch_on, throw_on, s);
453 }
454
GetDefaultExceptionResolverDescription(bool catch_on,bool throw_on,Stream & s)455 void Language::GetDefaultExceptionResolverDescription(bool catch_on,
456 bool throw_on,
457 Stream &s) {
458 s.Printf("Exception breakpoint (catch: %s throw: %s)",
459 catch_on ? "on" : "off", throw_on ? "on" : "off");
460 }
461 // Constructor
462 Language::Language() = default;
463
464 // Destructor
465 Language::~Language() = default;
466