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/Interpreter/OptionValueProperties.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/BinaryFormat/Dwarf.h"
23#include "llvm/Support/Threading.h"
24
25using namespace lldb;
26using namespace lldb_private;
27using namespace lldb_private::formatters;
28
29typedef std::unique_ptr<Language> LanguageUP;
30typedef std::map<lldb::LanguageType, LanguageUP> LanguagesMap;
31
32#define LLDB_PROPERTIES_language
33#include "TargetProperties.inc"
34
35enum {
36#define LLDB_PROPERTIES_language
37#include "TargetPropertiesEnum.inc"
38};
39
40LanguageProperties &Language::GetGlobalLanguageProperties() {
41 static LanguageProperties g_settings;
42 return g_settings;
43}
44
45llvm::StringRef LanguageProperties::GetSettingName() {
46 static constexpr llvm::StringLiteral g_setting_name("language");
47 return g_setting_name;
48}
49
50LanguageProperties::LanguageProperties() {
51 m_collection_sp = std::make_shared<OptionValueProperties>(args: GetSettingName());
52 m_collection_sp->Initialize(setting_definitions: g_language_properties);
53}
54
55bool LanguageProperties::GetEnableFilterForLineBreakpoints() const {
56 const uint32_t idx = ePropertyEnableFilterForLineBreakpoints;
57 return GetPropertyAtIndexAs<bool>(
58 idx, g_language_properties[idx].default_uint_value != 0);
59}
60
61static LanguagesMap &GetLanguagesMap() {
62 static LanguagesMap *g_map = nullptr;
63 static llvm::once_flag g_initialize;
64
65 llvm::call_once(flag&: g_initialize, F: [] {
66 g_map = new LanguagesMap(); // NOTE: INTENTIONAL LEAK due to global
67 // destructor chain
68 });
69
70 return *g_map;
71}
72static std::mutex &GetLanguagesMutex() {
73 static std::mutex *g_mutex = nullptr;
74 static llvm::once_flag g_initialize;
75
76 llvm::call_once(flag&: g_initialize, F: [] {
77 g_mutex = new std::mutex(); // NOTE: INTENTIONAL LEAK due to global
78 // destructor chain
79 });
80
81 return *g_mutex;
82}
83
84Language *Language::FindPlugin(lldb::LanguageType language) {
85 std::lock_guard<std::mutex> guard(GetLanguagesMutex());
86 LanguagesMap &map(GetLanguagesMap());
87 auto iter = map.find(x: language), end = map.end();
88 if (iter != end)
89 return iter->second.get();
90
91 Language *language_ptr = nullptr;
92 LanguageCreateInstance create_callback;
93
94 for (uint32_t idx = 0;
95 (create_callback =
96 PluginManager::GetLanguageCreateCallbackAtIndex(idx)) != nullptr;
97 ++idx) {
98 language_ptr = create_callback(language);
99
100 if (language_ptr) {
101 map[language] = std::unique_ptr<Language>(language_ptr);
102 return language_ptr;
103 }
104 }
105
106 return nullptr;
107}
108
109Language *Language::FindPlugin(llvm::StringRef file_path) {
110 Language *result = nullptr;
111 ForEach(callback: [&result, file_path](Language *language) {
112 if (language->IsSourceFile(file_path)) {
113 result = language;
114 return false;
115 }
116 return true;
117 });
118 return result;
119}
120
121Language *Language::FindPlugin(LanguageType language,
122 llvm::StringRef file_path) {
123 Language *result = FindPlugin(language);
124 // Finding a language by file path is slower, we so we use this as the
125 // fallback.
126 if (!result)
127 result = FindPlugin(file_path);
128 return result;
129}
130
131void Language::ForEach(std::function<bool(Language *)> callback) {
132 // If we want to iterate over all languages, we first have to complete the
133 // LanguagesMap.
134 static llvm::once_flag g_initialize;
135 llvm::call_once(flag&: g_initialize, F: [] {
136 for (unsigned lang = eLanguageTypeUnknown; lang < eNumLanguageTypes;
137 ++lang) {
138 FindPlugin(language: static_cast<lldb::LanguageType>(lang));
139 }
140 });
141
142 // callback may call a method in Language that attempts to acquire the same
143 // lock (such as Language::ForEach or Language::FindPlugin). To avoid a
144 // deadlock, we do not use callback while holding the lock.
145 std::vector<Language *> loaded_plugins;
146 {
147 std::lock_guard<std::mutex> guard(GetLanguagesMutex());
148 LanguagesMap &map(GetLanguagesMap());
149 for (const auto &entry : map) {
150 if (entry.second)
151 loaded_plugins.push_back(x: entry.second.get());
152 }
153 }
154
155 for (auto *lang : loaded_plugins) {
156 if (!callback(lang))
157 break;
158 }
159}
160
161bool Language::IsTopLevelFunction(Function &function) { return false; }
162
163lldb::TypeCategoryImplSP Language::GetFormatters() { return nullptr; }
164
165HardcodedFormatters::HardcodedFormatFinder Language::GetHardcodedFormats() {
166 return {};
167}
168
169HardcodedFormatters::HardcodedSummaryFinder Language::GetHardcodedSummaries() {
170 return {};
171}
172
173HardcodedFormatters::HardcodedSyntheticFinder
174Language::GetHardcodedSynthetics() {
175 return {};
176}
177
178std::vector<FormattersMatchCandidate>
179Language::GetPossibleFormattersMatches(ValueObject &valobj,
180 lldb::DynamicValueType use_dynamic) {
181 return {};
182}
183
184struct language_name_pair {
185 const char *name;
186 LanguageType type;
187};
188
189struct language_name_pair language_names[] = {
190 // To allow GetNameForLanguageType to be a simple array lookup, the first
191 // part of this array must follow enum LanguageType exactly.
192 {.name: "unknown", .type: eLanguageTypeUnknown},
193 {.name: "c89", .type: eLanguageTypeC89},
194 {.name: "c", .type: eLanguageTypeC},
195 {.name: "ada83", .type: eLanguageTypeAda83},
196 {.name: "c++", .type: eLanguageTypeC_plus_plus},
197 {.name: "cobol74", .type: eLanguageTypeCobol74},
198 {.name: "cobol85", .type: eLanguageTypeCobol85},
199 {.name: "fortran77", .type: eLanguageTypeFortran77},
200 {.name: "fortran90", .type: eLanguageTypeFortran90},
201 {.name: "pascal83", .type: eLanguageTypePascal83},
202 {.name: "modula2", .type: eLanguageTypeModula2},
203 {.name: "java", .type: eLanguageTypeJava},
204 {.name: "c99", .type: eLanguageTypeC99},
205 {.name: "ada95", .type: eLanguageTypeAda95},
206 {.name: "fortran95", .type: eLanguageTypeFortran95},
207 {.name: "pli", .type: eLanguageTypePLI},
208 {.name: "objective-c", .type: eLanguageTypeObjC},
209 {.name: "objective-c++", .type: eLanguageTypeObjC_plus_plus},
210 {.name: "upc", .type: eLanguageTypeUPC},
211 {.name: "d", .type: eLanguageTypeD},
212 {.name: "python", .type: eLanguageTypePython},
213 {.name: "opencl", .type: eLanguageTypeOpenCL},
214 {.name: "go", .type: eLanguageTypeGo},
215 {.name: "modula3", .type: eLanguageTypeModula3},
216 {.name: "haskell", .type: eLanguageTypeHaskell},
217 {.name: "c++03", .type: eLanguageTypeC_plus_plus_03},
218 {.name: "c++11", .type: eLanguageTypeC_plus_plus_11},
219 {.name: "ocaml", .type: eLanguageTypeOCaml},
220 {.name: "rust", .type: eLanguageTypeRust},
221 {.name: "c11", .type: eLanguageTypeC11},
222 {.name: "swift", .type: eLanguageTypeSwift},
223 {.name: "julia", .type: eLanguageTypeJulia},
224 {.name: "dylan", .type: eLanguageTypeDylan},
225 {.name: "c++14", .type: eLanguageTypeC_plus_plus_14},
226 {.name: "fortran03", .type: eLanguageTypeFortran03},
227 {.name: "fortran08", .type: eLanguageTypeFortran08},
228 {.name: "renderscript", .type: eLanguageTypeRenderScript},
229 {.name: "bliss", .type: eLanguageTypeBLISS},
230 {.name: "kotlin", .type: eLanguageTypeKotlin},
231 {.name: "zig", .type: eLanguageTypeZig},
232 {.name: "crystal", .type: eLanguageTypeCrystal},
233 {.name: "<invalid language>",
234 .type: static_cast<LanguageType>(
235 0x0029)}, // Not yet taken by any language in the DWARF spec
236 // and thus has no entry in LanguageType
237 {.name: "c++17", .type: eLanguageTypeC_plus_plus_17},
238 {.name: "c++20", .type: eLanguageTypeC_plus_plus_20},
239 {.name: "c17", .type: eLanguageTypeC17},
240 {.name: "fortran18", .type: eLanguageTypeFortran18},
241 {.name: "ada2005", .type: eLanguageTypeAda2005},
242 {.name: "ada2012", .type: eLanguageTypeAda2012},
243 {.name: "HIP", .type: eLanguageTypeHIP},
244 {.name: "assembly", .type: eLanguageTypeAssembly},
245 {.name: "c-sharp", .type: eLanguageTypeC_sharp},
246 {.name: "mojo", .type: eLanguageTypeMojo},
247 // Vendor Extensions
248 {.name: "assembler", .type: eLanguageTypeMipsAssembler},
249 // Now synonyms, in arbitrary order
250 {.name: "objc", .type: eLanguageTypeObjC},
251 {.name: "objc++", .type: eLanguageTypeObjC_plus_plus},
252 {.name: "pascal", .type: eLanguageTypePascal83}};
253
254static uint32_t num_languages =
255 sizeof(language_names) / sizeof(struct language_name_pair);
256
257LanguageType Language::GetLanguageTypeFromString(llvm::StringRef string) {
258 for (const auto &L : language_names) {
259 if (string.equals_insensitive(RHS: L.name))
260 return static_cast<LanguageType>(L.type);
261 }
262
263 return eLanguageTypeUnknown;
264}
265
266const char *Language::GetNameForLanguageType(LanguageType language) {
267 if (language < num_languages)
268 return language_names[language].name;
269 else
270 return language_names[eLanguageTypeUnknown].name;
271}
272
273void Language::PrintSupportedLanguagesForExpressions(Stream &s,
274 llvm::StringRef prefix,
275 llvm::StringRef suffix) {
276 auto supported = Language::GetLanguagesSupportingTypeSystemsForExpressions();
277 for (size_t idx = 0; idx < num_languages; ++idx) {
278 auto const &lang = language_names[idx];
279 if (supported[lang.type])
280 s << prefix << lang.name << suffix;
281 }
282}
283
284void Language::PrintAllLanguages(Stream &s, const char *prefix,
285 const char *suffix) {
286 for (uint32_t i = 1; i < num_languages; i++) {
287 s.Printf(format: "%s%s%s", prefix, language_names[i].name, suffix);
288 }
289}
290
291void Language::ForAllLanguages(
292 std::function<bool(lldb::LanguageType)> callback) {
293 for (uint32_t i = 1; i < num_languages; i++) {
294 if (!callback(language_names[i].type))
295 break;
296 }
297}
298
299bool Language::LanguageIsCPlusPlus(LanguageType language) {
300 switch (language) {
301 case eLanguageTypeC_plus_plus:
302 case eLanguageTypeC_plus_plus_03:
303 case eLanguageTypeC_plus_plus_11:
304 case eLanguageTypeC_plus_plus_14:
305 case eLanguageTypeC_plus_plus_17:
306 case eLanguageTypeC_plus_plus_20:
307 case eLanguageTypeObjC_plus_plus:
308 return true;
309 default:
310 return false;
311 }
312}
313
314bool Language::LanguageIsObjC(LanguageType language) {
315 switch (language) {
316 case eLanguageTypeObjC:
317 case eLanguageTypeObjC_plus_plus:
318 return true;
319 default:
320 return false;
321 }
322}
323
324bool Language::LanguageIsC(LanguageType language) {
325 switch (language) {
326 case eLanguageTypeC:
327 case eLanguageTypeC89:
328 case eLanguageTypeC99:
329 case eLanguageTypeC11:
330 return true;
331 default:
332 return false;
333 }
334}
335
336bool Language::LanguageIsCFamily(LanguageType language) {
337 switch (language) {
338 case eLanguageTypeC:
339 case eLanguageTypeC89:
340 case eLanguageTypeC99:
341 case eLanguageTypeC11:
342 case eLanguageTypeC_plus_plus:
343 case eLanguageTypeC_plus_plus_03:
344 case eLanguageTypeC_plus_plus_11:
345 case eLanguageTypeC_plus_plus_14:
346 case eLanguageTypeC_plus_plus_17:
347 case eLanguageTypeC_plus_plus_20:
348 case eLanguageTypeObjC_plus_plus:
349 case eLanguageTypeObjC:
350 return true;
351 default:
352 return false;
353 }
354}
355
356bool Language::LanguageIsPascal(LanguageType language) {
357 switch (language) {
358 case eLanguageTypePascal83:
359 return true;
360 default:
361 return false;
362 }
363}
364
365LanguageType Language::GetPrimaryLanguage(LanguageType language) {
366 switch (language) {
367 case eLanguageTypeC_plus_plus:
368 case eLanguageTypeC_plus_plus_03:
369 case eLanguageTypeC_plus_plus_11:
370 case eLanguageTypeC_plus_plus_14:
371 case eLanguageTypeC_plus_plus_17:
372 case eLanguageTypeC_plus_plus_20:
373 return eLanguageTypeC_plus_plus;
374 case eLanguageTypeC:
375 case eLanguageTypeC89:
376 case eLanguageTypeC99:
377 case eLanguageTypeC11:
378 return eLanguageTypeC;
379 case eLanguageTypeObjC:
380 case eLanguageTypeObjC_plus_plus:
381 return eLanguageTypeObjC;
382 case eLanguageTypePascal83:
383 case eLanguageTypeCobol74:
384 case eLanguageTypeCobol85:
385 case eLanguageTypeFortran77:
386 case eLanguageTypeFortran90:
387 case eLanguageTypeFortran95:
388 case eLanguageTypeFortran03:
389 case eLanguageTypeFortran08:
390 case eLanguageTypeAda83:
391 case eLanguageTypeAda95:
392 case eLanguageTypeModula2:
393 case eLanguageTypeJava:
394 case eLanguageTypePLI:
395 case eLanguageTypeUPC:
396 case eLanguageTypeD:
397 case eLanguageTypePython:
398 case eLanguageTypeOpenCL:
399 case eLanguageTypeGo:
400 case eLanguageTypeModula3:
401 case eLanguageTypeHaskell:
402 case eLanguageTypeOCaml:
403 case eLanguageTypeRust:
404 case eLanguageTypeSwift:
405 case eLanguageTypeJulia:
406 case eLanguageTypeDylan:
407 case eLanguageTypeMipsAssembler:
408 case eLanguageTypeMojo:
409 case eLanguageTypeUnknown:
410 default:
411 return language;
412 }
413}
414
415std::set<lldb::LanguageType> Language::GetSupportedLanguages() {
416 std::set<lldb::LanguageType> supported_languages;
417 ForEach(callback: [&](Language *lang) {
418 supported_languages.emplace(args: lang->GetLanguageType());
419 return true;
420 });
421 return supported_languages;
422}
423
424LanguageSet Language::GetLanguagesSupportingTypeSystems() {
425 return PluginManager::GetAllTypeSystemSupportedLanguagesForTypes();
426}
427
428LanguageSet Language::GetLanguagesSupportingTypeSystemsForExpressions() {
429 return PluginManager::GetAllTypeSystemSupportedLanguagesForExpressions();
430}
431
432LanguageSet Language::GetLanguagesSupportingREPLs() {
433 return PluginManager::GetREPLAllTypeSystemSupportedLanguages();
434}
435
436std::unique_ptr<Language::TypeScavenger> Language::GetTypeScavenger() {
437 return nullptr;
438}
439
440const char *Language::GetLanguageSpecificTypeLookupHelp() { return nullptr; }
441
442size_t Language::TypeScavenger::Find(ExecutionContextScope *exe_scope,
443 const char *key, ResultSet &results,
444 bool append) {
445 if (!exe_scope || !exe_scope->CalculateTarget().get())
446 return false;
447
448 if (!key || !key[0])
449 return false;
450
451 if (!append)
452 results.clear();
453
454 size_t old_size = results.size();
455
456 if (this->Find_Impl(exe_scope, key, results))
457 return results.size() - old_size;
458 return 0;
459}
460
461bool Language::ImageListTypeScavenger::Find_Impl(
462 ExecutionContextScope *exe_scope, const char *key, ResultSet &results) {
463 bool result = false;
464
465 Target *target = exe_scope->CalculateTarget().get();
466 if (target) {
467 const auto &images(target->GetImages());
468 TypeQuery query(key);
469 TypeResults type_results;
470 images.FindTypes(search_first: nullptr, query, results&: type_results);
471 for (const auto &match : type_results.GetTypeMap().Types()) {
472 if (match) {
473 CompilerType compiler_type(match->GetFullCompilerType());
474 compiler_type = AdjustForInclusion(candidate&: compiler_type);
475 if (!compiler_type)
476 continue;
477 std::unique_ptr<Language::TypeScavenger::Result> scavengeresult(
478 new Result(compiler_type));
479 results.insert(x: std::move(scavengeresult));
480 result = true;
481 }
482 }
483 }
484
485 return result;
486}
487
488std::pair<llvm::StringRef, llvm::StringRef>
489Language::GetFormatterPrefixSuffix(llvm::StringRef type_hint) {
490 return std::pair<llvm::StringRef, llvm::StringRef>();
491}
492
493bool Language::DemangledNameContainsPath(llvm::StringRef path,
494 ConstString demangled) const {
495 // The base implementation does a simple contains comparision:
496 if (path.empty())
497 return false;
498 return demangled.GetStringRef().contains(Other: path);
499}
500
501DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() {
502 return nullptr;
503}
504
505LazyBool Language::IsLogicalTrue(ValueObject &valobj, Status &error) {
506 return eLazyBoolCalculate;
507}
508
509bool Language::IsNilReference(ValueObject &valobj) { return false; }
510
511bool Language::IsUninitializedReference(ValueObject &valobj) { return false; }
512
513bool Language::GetFunctionDisplayName(const SymbolContext &sc,
514 const ExecutionContext *exe_ctx,
515 FunctionNameRepresentation representation,
516 Stream &s) {
517 return false;
518}
519
520void Language::GetExceptionResolverDescription(bool catch_on, bool throw_on,
521 Stream &s) {
522 GetDefaultExceptionResolverDescription(catch_on, throw_on, s);
523}
524
525void Language::GetDefaultExceptionResolverDescription(bool catch_on,
526 bool throw_on,
527 Stream &s) {
528 s.Printf(format: "Exception breakpoint (catch: %s throw: %s)",
529 catch_on ? "on" : "off", throw_on ? "on" : "off");
530}
531
532std::optional<bool> Language::GetBooleanFromString(llvm::StringRef str) const {
533 return llvm::StringSwitch<std::optional<bool>>(str)
534 .Case(S: "true", Value: {true})
535 .Case(S: "false", Value: {false})
536 .Default(Value: {});
537}
538
539// Constructor
540Language::Language() = default;
541
542// Destructor
543Language::~Language() = default;
544
545SourceLanguage::SourceLanguage(lldb::LanguageType language_type) {
546 auto lname =
547 llvm::dwarf::toDW_LNAME(language: (llvm::dwarf::SourceLanguage)language_type);
548 if (!lname)
549 return;
550 name = lname->first;
551 version = lname->second;
552}
553
554lldb::LanguageType SourceLanguage::AsLanguageType() const {
555 if (auto lang = llvm::dwarf::toDW_LANG(name: (llvm::dwarf::SourceLanguageName)name,
556 version))
557 return (lldb::LanguageType)*lang;
558 return lldb::eLanguageTypeUnknown;
559}
560
561llvm::StringRef SourceLanguage::GetDescription() const {
562 LanguageType type = AsLanguageType();
563 if (type)
564 return Language::GetNameForLanguageType(language: type);
565 return llvm::dwarf::LanguageDescription(
566 name: (llvm::dwarf::SourceLanguageName)name);
567}
568bool SourceLanguage::IsC() const { return name == llvm::dwarf::DW_LNAME_C; }
569
570bool SourceLanguage::IsObjC() const {
571 return name == llvm::dwarf::DW_LNAME_ObjC;
572}
573
574bool SourceLanguage::IsCPlusPlus() const {
575 return name == llvm::dwarf::DW_LNAME_C_plus_plus;
576}
577

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of lldb/source/Target/Language.cpp