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