Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/DataFormatters/FormatManager.cpp
39587 views
1
//===-- FormatManager.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 "lldb/DataFormatters/FormatManager.h"
10
11
#include "lldb/Core/Debugger.h"
12
#include "lldb/Core/ValueObject.h"
13
#include "lldb/DataFormatters/FormattersHelpers.h"
14
#include "lldb/DataFormatters/LanguageCategory.h"
15
#include "lldb/Interpreter/ScriptInterpreter.h"
16
#include "lldb/Target/ExecutionContext.h"
17
#include "lldb/Target/Language.h"
18
#include "lldb/Utility/LLDBLog.h"
19
#include "lldb/Utility/Log.h"
20
#include "llvm/ADT/STLExtras.h"
21
22
using namespace lldb;
23
using namespace lldb_private;
24
using namespace lldb_private::formatters;
25
26
struct FormatInfo {
27
Format format;
28
const char format_char; // One or more format characters that can be used for
29
// this format.
30
const char *format_name; // Long format name that can be used to specify the
31
// current format
32
};
33
34
static constexpr FormatInfo g_format_infos[] = {
35
{eFormatDefault, '\0', "default"},
36
{eFormatBoolean, 'B', "boolean"},
37
{eFormatBinary, 'b', "binary"},
38
{eFormatBytes, 'y', "bytes"},
39
{eFormatBytesWithASCII, 'Y', "bytes with ASCII"},
40
{eFormatChar, 'c', "character"},
41
{eFormatCharPrintable, 'C', "printable character"},
42
{eFormatComplexFloat, 'F', "complex float"},
43
{eFormatCString, 's', "c-string"},
44
{eFormatDecimal, 'd', "decimal"},
45
{eFormatEnum, 'E', "enumeration"},
46
{eFormatHex, 'x', "hex"},
47
{eFormatHexUppercase, 'X', "uppercase hex"},
48
{eFormatFloat, 'f', "float"},
49
{eFormatOctal, 'o', "octal"},
50
{eFormatOSType, 'O', "OSType"},
51
{eFormatUnicode16, 'U', "unicode16"},
52
{eFormatUnicode32, '\0', "unicode32"},
53
{eFormatUnsigned, 'u', "unsigned decimal"},
54
{eFormatPointer, 'p', "pointer"},
55
{eFormatVectorOfChar, '\0', "char[]"},
56
{eFormatVectorOfSInt8, '\0', "int8_t[]"},
57
{eFormatVectorOfUInt8, '\0', "uint8_t[]"},
58
{eFormatVectorOfSInt16, '\0', "int16_t[]"},
59
{eFormatVectorOfUInt16, '\0', "uint16_t[]"},
60
{eFormatVectorOfSInt32, '\0', "int32_t[]"},
61
{eFormatVectorOfUInt32, '\0', "uint32_t[]"},
62
{eFormatVectorOfSInt64, '\0', "int64_t[]"},
63
{eFormatVectorOfUInt64, '\0', "uint64_t[]"},
64
{eFormatVectorOfFloat16, '\0', "float16[]"},
65
{eFormatVectorOfFloat32, '\0', "float32[]"},
66
{eFormatVectorOfFloat64, '\0', "float64[]"},
67
{eFormatVectorOfUInt128, '\0', "uint128_t[]"},
68
{eFormatComplexInteger, 'I', "complex integer"},
69
{eFormatCharArray, 'a', "character array"},
70
{eFormatAddressInfo, 'A', "address"},
71
{eFormatHexFloat, '\0', "hex float"},
72
{eFormatInstruction, 'i', "instruction"},
73
{eFormatVoid, 'v', "void"},
74
{eFormatUnicode8, 'u', "unicode8"},
75
};
76
77
static_assert((sizeof(g_format_infos) / sizeof(g_format_infos[0])) ==
78
kNumFormats,
79
"All formats must have a corresponding info entry.");
80
81
static uint32_t g_num_format_infos = std::size(g_format_infos);
82
83
static bool GetFormatFromFormatChar(char format_char, Format &format) {
84
for (uint32_t i = 0; i < g_num_format_infos; ++i) {
85
if (g_format_infos[i].format_char == format_char) {
86
format = g_format_infos[i].format;
87
return true;
88
}
89
}
90
format = eFormatInvalid;
91
return false;
92
}
93
94
static bool GetFormatFromFormatName(llvm::StringRef format_name,
95
Format &format) {
96
uint32_t i;
97
for (i = 0; i < g_num_format_infos; ++i) {
98
if (format_name.equals_insensitive(g_format_infos[i].format_name)) {
99
format = g_format_infos[i].format;
100
return true;
101
}
102
}
103
104
for (i = 0; i < g_num_format_infos; ++i) {
105
if (llvm::StringRef(g_format_infos[i].format_name)
106
.starts_with_insensitive(format_name)) {
107
format = g_format_infos[i].format;
108
return true;
109
}
110
}
111
format = eFormatInvalid;
112
return false;
113
}
114
115
void FormatManager::Changed() {
116
++m_last_revision;
117
m_format_cache.Clear();
118
std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex);
119
for (auto &iter : m_language_categories_map) {
120
if (iter.second)
121
iter.second->GetFormatCache().Clear();
122
}
123
}
124
125
bool FormatManager::GetFormatFromCString(const char *format_cstr,
126
lldb::Format &format) {
127
bool success = false;
128
if (format_cstr && format_cstr[0]) {
129
if (format_cstr[1] == '\0') {
130
success = GetFormatFromFormatChar(format_cstr[0], format);
131
if (success)
132
return true;
133
}
134
135
success = GetFormatFromFormatName(format_cstr, format);
136
}
137
if (!success)
138
format = eFormatInvalid;
139
return success;
140
}
141
142
char FormatManager::GetFormatAsFormatChar(lldb::Format format) {
143
for (uint32_t i = 0; i < g_num_format_infos; ++i) {
144
if (g_format_infos[i].format == format)
145
return g_format_infos[i].format_char;
146
}
147
return '\0';
148
}
149
150
const char *FormatManager::GetFormatAsCString(Format format) {
151
if (format >= eFormatDefault && format < kNumFormats)
152
return g_format_infos[format].format_name;
153
return nullptr;
154
}
155
156
void FormatManager::EnableAllCategories() {
157
m_categories_map.EnableAllCategories();
158
std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex);
159
for (auto &iter : m_language_categories_map) {
160
if (iter.second)
161
iter.second->Enable();
162
}
163
}
164
165
void FormatManager::DisableAllCategories() {
166
m_categories_map.DisableAllCategories();
167
std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex);
168
for (auto &iter : m_language_categories_map) {
169
if (iter.second)
170
iter.second->Disable();
171
}
172
}
173
174
void FormatManager::GetPossibleMatches(
175
ValueObject &valobj, CompilerType compiler_type,
176
lldb::DynamicValueType use_dynamic, FormattersMatchVector &entries,
177
FormattersMatchCandidate::Flags current_flags, bool root_level) {
178
compiler_type = compiler_type.GetTypeForFormatters();
179
ConstString type_name(compiler_type.GetTypeName());
180
// A ValueObject that couldn't be made correctly won't necessarily have a
181
// target. We aren't going to find a formatter in this case anyway, so we
182
// should just exit.
183
TargetSP target_sp = valobj.GetTargetSP();
184
if (!target_sp)
185
return;
186
ScriptInterpreter *script_interpreter =
187
target_sp->GetDebugger().GetScriptInterpreter();
188
if (valobj.GetBitfieldBitSize() > 0) {
189
StreamString sstring;
190
sstring.Printf("%s:%d", type_name.AsCString(), valobj.GetBitfieldBitSize());
191
ConstString bitfieldname(sstring.GetString());
192
entries.push_back({bitfieldname, script_interpreter,
193
TypeImpl(compiler_type), current_flags});
194
}
195
196
if (!compiler_type.IsMeaninglessWithoutDynamicResolution()) {
197
entries.push_back({type_name, script_interpreter, TypeImpl(compiler_type),
198
current_flags});
199
200
ConstString display_type_name(compiler_type.GetTypeName());
201
if (display_type_name != type_name)
202
entries.push_back({display_type_name, script_interpreter,
203
TypeImpl(compiler_type), current_flags});
204
}
205
206
for (bool is_rvalue_ref = true, j = true;
207
j && compiler_type.IsReferenceType(nullptr, &is_rvalue_ref); j = false) {
208
CompilerType non_ref_type = compiler_type.GetNonReferenceType();
209
GetPossibleMatches(valobj, non_ref_type, use_dynamic, entries,
210
current_flags.WithStrippedReference());
211
if (non_ref_type.IsTypedefType()) {
212
CompilerType deffed_referenced_type = non_ref_type.GetTypedefedType();
213
deffed_referenced_type =
214
is_rvalue_ref ? deffed_referenced_type.GetRValueReferenceType()
215
: deffed_referenced_type.GetLValueReferenceType();
216
// this is not exactly the usual meaning of stripping typedefs
217
GetPossibleMatches(
218
valobj, deffed_referenced_type,
219
use_dynamic, entries, current_flags.WithStrippedTypedef());
220
}
221
}
222
223
if (compiler_type.IsPointerType()) {
224
CompilerType non_ptr_type = compiler_type.GetPointeeType();
225
GetPossibleMatches(valobj, non_ptr_type, use_dynamic, entries,
226
current_flags.WithStrippedPointer());
227
if (non_ptr_type.IsTypedefType()) {
228
CompilerType deffed_pointed_type =
229
non_ptr_type.GetTypedefedType().GetPointerType();
230
// this is not exactly the usual meaning of stripping typedefs
231
GetPossibleMatches(valobj, deffed_pointed_type, use_dynamic, entries,
232
current_flags.WithStrippedTypedef());
233
}
234
}
235
236
// For arrays with typedef-ed elements, we add a candidate with the typedef
237
// stripped.
238
uint64_t array_size;
239
if (compiler_type.IsArrayType(nullptr, &array_size, nullptr)) {
240
ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
241
CompilerType element_type = compiler_type.GetArrayElementType(
242
exe_ctx.GetBestExecutionContextScope());
243
if (element_type.IsTypedefType()) {
244
// Get the stripped element type and compute the stripped array type
245
// from it.
246
CompilerType deffed_array_type =
247
element_type.GetTypedefedType().GetArrayType(array_size);
248
// this is not exactly the usual meaning of stripping typedefs
249
GetPossibleMatches(
250
valobj, deffed_array_type,
251
use_dynamic, entries, current_flags.WithStrippedTypedef());
252
}
253
}
254
255
for (lldb::LanguageType language_type :
256
GetCandidateLanguages(valobj.GetObjectRuntimeLanguage())) {
257
if (Language *language = Language::FindPlugin(language_type)) {
258
for (const FormattersMatchCandidate& candidate :
259
language->GetPossibleFormattersMatches(valobj, use_dynamic)) {
260
entries.push_back(candidate);
261
}
262
}
263
}
264
265
// try to strip typedef chains
266
if (compiler_type.IsTypedefType()) {
267
CompilerType deffed_type = compiler_type.GetTypedefedType();
268
GetPossibleMatches(valobj, deffed_type, use_dynamic, entries,
269
current_flags.WithStrippedTypedef());
270
}
271
272
if (root_level) {
273
do {
274
if (!compiler_type.IsValid())
275
break;
276
277
CompilerType unqual_compiler_ast_type =
278
compiler_type.GetFullyUnqualifiedType();
279
if (!unqual_compiler_ast_type.IsValid())
280
break;
281
if (unqual_compiler_ast_type.GetOpaqueQualType() !=
282
compiler_type.GetOpaqueQualType())
283
GetPossibleMatches(valobj, unqual_compiler_ast_type, use_dynamic,
284
entries, current_flags);
285
} while (false);
286
287
// if all else fails, go to static type
288
if (valobj.IsDynamic()) {
289
lldb::ValueObjectSP static_value_sp(valobj.GetStaticValue());
290
if (static_value_sp)
291
GetPossibleMatches(*static_value_sp.get(),
292
static_value_sp->GetCompilerType(), use_dynamic,
293
entries, current_flags, true);
294
}
295
}
296
}
297
298
lldb::TypeFormatImplSP
299
FormatManager::GetFormatForType(lldb::TypeNameSpecifierImplSP type_sp) {
300
if (!type_sp)
301
return lldb::TypeFormatImplSP();
302
lldb::TypeFormatImplSP format_chosen_sp;
303
uint32_t num_categories = m_categories_map.GetCount();
304
lldb::TypeCategoryImplSP category_sp;
305
uint32_t prio_category = UINT32_MAX;
306
for (uint32_t category_id = 0; category_id < num_categories; category_id++) {
307
category_sp = GetCategoryAtIndex(category_id);
308
if (!category_sp->IsEnabled())
309
continue;
310
lldb::TypeFormatImplSP format_current_sp =
311
category_sp->GetFormatForType(type_sp);
312
if (format_current_sp &&
313
(format_chosen_sp.get() == nullptr ||
314
(prio_category > category_sp->GetEnabledPosition()))) {
315
prio_category = category_sp->GetEnabledPosition();
316
format_chosen_sp = format_current_sp;
317
}
318
}
319
return format_chosen_sp;
320
}
321
322
lldb::TypeSummaryImplSP
323
FormatManager::GetSummaryForType(lldb::TypeNameSpecifierImplSP type_sp) {
324
if (!type_sp)
325
return lldb::TypeSummaryImplSP();
326
lldb::TypeSummaryImplSP summary_chosen_sp;
327
uint32_t num_categories = m_categories_map.GetCount();
328
lldb::TypeCategoryImplSP category_sp;
329
uint32_t prio_category = UINT32_MAX;
330
for (uint32_t category_id = 0; category_id < num_categories; category_id++) {
331
category_sp = GetCategoryAtIndex(category_id);
332
if (!category_sp->IsEnabled())
333
continue;
334
lldb::TypeSummaryImplSP summary_current_sp =
335
category_sp->GetSummaryForType(type_sp);
336
if (summary_current_sp &&
337
(summary_chosen_sp.get() == nullptr ||
338
(prio_category > category_sp->GetEnabledPosition()))) {
339
prio_category = category_sp->GetEnabledPosition();
340
summary_chosen_sp = summary_current_sp;
341
}
342
}
343
return summary_chosen_sp;
344
}
345
346
lldb::TypeFilterImplSP
347
FormatManager::GetFilterForType(lldb::TypeNameSpecifierImplSP type_sp) {
348
if (!type_sp)
349
return lldb::TypeFilterImplSP();
350
lldb::TypeFilterImplSP filter_chosen_sp;
351
uint32_t num_categories = m_categories_map.GetCount();
352
lldb::TypeCategoryImplSP category_sp;
353
uint32_t prio_category = UINT32_MAX;
354
for (uint32_t category_id = 0; category_id < num_categories; category_id++) {
355
category_sp = GetCategoryAtIndex(category_id);
356
if (!category_sp->IsEnabled())
357
continue;
358
lldb::TypeFilterImplSP filter_current_sp(
359
(TypeFilterImpl *)category_sp->GetFilterForType(type_sp).get());
360
if (filter_current_sp &&
361
(filter_chosen_sp.get() == nullptr ||
362
(prio_category > category_sp->GetEnabledPosition()))) {
363
prio_category = category_sp->GetEnabledPosition();
364
filter_chosen_sp = filter_current_sp;
365
}
366
}
367
return filter_chosen_sp;
368
}
369
370
lldb::ScriptedSyntheticChildrenSP
371
FormatManager::GetSyntheticForType(lldb::TypeNameSpecifierImplSP type_sp) {
372
if (!type_sp)
373
return lldb::ScriptedSyntheticChildrenSP();
374
lldb::ScriptedSyntheticChildrenSP synth_chosen_sp;
375
uint32_t num_categories = m_categories_map.GetCount();
376
lldb::TypeCategoryImplSP category_sp;
377
uint32_t prio_category = UINT32_MAX;
378
for (uint32_t category_id = 0; category_id < num_categories; category_id++) {
379
category_sp = GetCategoryAtIndex(category_id);
380
if (!category_sp->IsEnabled())
381
continue;
382
lldb::ScriptedSyntheticChildrenSP synth_current_sp(
383
(ScriptedSyntheticChildren *)category_sp->GetSyntheticForType(type_sp)
384
.get());
385
if (synth_current_sp &&
386
(synth_chosen_sp.get() == nullptr ||
387
(prio_category > category_sp->GetEnabledPosition()))) {
388
prio_category = category_sp->GetEnabledPosition();
389
synth_chosen_sp = synth_current_sp;
390
}
391
}
392
return synth_chosen_sp;
393
}
394
395
void FormatManager::ForEachCategory(TypeCategoryMap::ForEachCallback callback) {
396
m_categories_map.ForEach(callback);
397
std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex);
398
for (const auto &entry : m_language_categories_map) {
399
if (auto category_sp = entry.second->GetCategory()) {
400
if (!callback(category_sp))
401
break;
402
}
403
}
404
}
405
406
lldb::TypeCategoryImplSP
407
FormatManager::GetCategory(ConstString category_name, bool can_create) {
408
if (!category_name)
409
return GetCategory(m_default_category_name);
410
lldb::TypeCategoryImplSP category;
411
if (m_categories_map.Get(category_name, category))
412
return category;
413
414
if (!can_create)
415
return lldb::TypeCategoryImplSP();
416
417
m_categories_map.Add(
418
category_name,
419
lldb::TypeCategoryImplSP(new TypeCategoryImpl(this, category_name)));
420
return GetCategory(category_name);
421
}
422
423
lldb::Format FormatManager::GetSingleItemFormat(lldb::Format vector_format) {
424
switch (vector_format) {
425
case eFormatVectorOfChar:
426
return eFormatCharArray;
427
428
case eFormatVectorOfSInt8:
429
case eFormatVectorOfSInt16:
430
case eFormatVectorOfSInt32:
431
case eFormatVectorOfSInt64:
432
return eFormatDecimal;
433
434
case eFormatVectorOfUInt8:
435
case eFormatVectorOfUInt16:
436
case eFormatVectorOfUInt32:
437
case eFormatVectorOfUInt64:
438
case eFormatVectorOfUInt128:
439
return eFormatHex;
440
441
case eFormatVectorOfFloat16:
442
case eFormatVectorOfFloat32:
443
case eFormatVectorOfFloat64:
444
return eFormatFloat;
445
446
default:
447
return lldb::eFormatInvalid;
448
}
449
}
450
451
bool FormatManager::ShouldPrintAsOneLiner(ValueObject &valobj) {
452
TargetSP target_sp = valobj.GetTargetSP();
453
// if settings say no oneline whatsoever
454
if (target_sp && !target_sp->GetDebugger().GetAutoOneLineSummaries())
455
return false; // then don't oneline
456
457
// if this object has a summary, then ask the summary
458
if (valobj.GetSummaryFormat().get() != nullptr)
459
return valobj.GetSummaryFormat()->IsOneLiner();
460
461
const size_t max_num_children =
462
(target_sp ? *target_sp : Target::GetGlobalProperties())
463
.GetMaximumNumberOfChildrenToDisplay();
464
auto num_children = valobj.GetNumChildren(max_num_children);
465
if (!num_children) {
466
llvm::consumeError(num_children.takeError());
467
return true;
468
}
469
// no children, no party
470
if (*num_children == 0)
471
return false;
472
473
// ask the type if it has any opinion about this eLazyBoolCalculate == no
474
// opinion; other values should be self explanatory
475
CompilerType compiler_type(valobj.GetCompilerType());
476
if (compiler_type.IsValid()) {
477
switch (compiler_type.ShouldPrintAsOneLiner(&valobj)) {
478
case eLazyBoolNo:
479
return false;
480
case eLazyBoolYes:
481
return true;
482
case eLazyBoolCalculate:
483
break;
484
}
485
}
486
487
size_t total_children_name_len = 0;
488
489
for (size_t idx = 0; idx < *num_children; idx++) {
490
bool is_synth_val = false;
491
ValueObjectSP child_sp(valobj.GetChildAtIndex(idx));
492
// something is wrong here - bail out
493
if (!child_sp)
494
return false;
495
496
// also ask the child's type if it has any opinion
497
CompilerType child_compiler_type(child_sp->GetCompilerType());
498
if (child_compiler_type.IsValid()) {
499
switch (child_compiler_type.ShouldPrintAsOneLiner(child_sp.get())) {
500
case eLazyBoolYes:
501
// an opinion of yes is only binding for the child, so keep going
502
case eLazyBoolCalculate:
503
break;
504
case eLazyBoolNo:
505
// but if the child says no, then it's a veto on the whole thing
506
return false;
507
}
508
}
509
510
// if we decided to define synthetic children for a type, we probably care
511
// enough to show them, but avoid nesting children in children
512
if (child_sp->GetSyntheticChildren().get() != nullptr) {
513
ValueObjectSP synth_sp(child_sp->GetSyntheticValue());
514
// wait.. wat? just get out of here..
515
if (!synth_sp)
516
return false;
517
// but if we only have them to provide a value, keep going
518
if (!synth_sp->MightHaveChildren() &&
519
synth_sp->DoesProvideSyntheticValue())
520
is_synth_val = true;
521
else
522
return false;
523
}
524
525
total_children_name_len += child_sp->GetName().GetLength();
526
527
// 50 itself is a "randomly" chosen number - the idea is that
528
// overly long structs should not get this treatment
529
// FIXME: maybe make this a user-tweakable setting?
530
if (total_children_name_len > 50)
531
return false;
532
533
// if a summary is there..
534
if (child_sp->GetSummaryFormat()) {
535
// and it wants children, then bail out
536
if (child_sp->GetSummaryFormat()->DoesPrintChildren(child_sp.get()))
537
return false;
538
}
539
540
// if this child has children..
541
if (child_sp->HasChildren()) {
542
// ...and no summary...
543
// (if it had a summary and the summary wanted children, we would have
544
// bailed out anyway
545
// so this only makes us bail out if this has no summary and we would
546
// then print children)
547
if (!child_sp->GetSummaryFormat() && !is_synth_val) // but again only do
548
// that if not a
549
// synthetic valued
550
// child
551
return false; // then bail out
552
}
553
}
554
return true;
555
}
556
557
ConstString FormatManager::GetTypeForCache(ValueObject &valobj,
558
lldb::DynamicValueType use_dynamic) {
559
ValueObjectSP valobj_sp = valobj.GetQualifiedRepresentationIfAvailable(
560
use_dynamic, valobj.IsSynthetic());
561
if (valobj_sp && valobj_sp->GetCompilerType().IsValid()) {
562
if (!valobj_sp->GetCompilerType().IsMeaninglessWithoutDynamicResolution())
563
return valobj_sp->GetQualifiedTypeName();
564
}
565
return ConstString();
566
}
567
568
std::vector<lldb::LanguageType>
569
FormatManager::GetCandidateLanguages(lldb::LanguageType lang_type) {
570
switch (lang_type) {
571
case lldb::eLanguageTypeC:
572
case lldb::eLanguageTypeC89:
573
case lldb::eLanguageTypeC99:
574
case lldb::eLanguageTypeC11:
575
case lldb::eLanguageTypeC_plus_plus:
576
case lldb::eLanguageTypeC_plus_plus_03:
577
case lldb::eLanguageTypeC_plus_plus_11:
578
case lldb::eLanguageTypeC_plus_plus_14:
579
return {lldb::eLanguageTypeC_plus_plus, lldb::eLanguageTypeObjC};
580
default:
581
return {lang_type};
582
}
583
llvm_unreachable("Fully covered switch");
584
}
585
586
LanguageCategory *
587
FormatManager::GetCategoryForLanguage(lldb::LanguageType lang_type) {
588
std::lock_guard<std::recursive_mutex> guard(m_language_categories_mutex);
589
auto iter = m_language_categories_map.find(lang_type),
590
end = m_language_categories_map.end();
591
if (iter != end)
592
return iter->second.get();
593
LanguageCategory *lang_category = new LanguageCategory(lang_type);
594
m_language_categories_map[lang_type] =
595
LanguageCategory::UniquePointer(lang_category);
596
return lang_category;
597
}
598
599
template <typename ImplSP>
600
ImplSP FormatManager::GetHardcoded(FormattersMatchData &match_data) {
601
ImplSP retval_sp;
602
for (lldb::LanguageType lang_type : match_data.GetCandidateLanguages()) {
603
if (LanguageCategory *lang_category = GetCategoryForLanguage(lang_type)) {
604
if (lang_category->GetHardcoded(*this, match_data, retval_sp))
605
return retval_sp;
606
}
607
}
608
return retval_sp;
609
}
610
611
namespace {
612
template <typename ImplSP> const char *FormatterKind;
613
template <> const char *FormatterKind<lldb::TypeFormatImplSP> = "format";
614
template <> const char *FormatterKind<lldb::TypeSummaryImplSP> = "summary";
615
template <> const char *FormatterKind<lldb::SyntheticChildrenSP> = "synthetic";
616
} // namespace
617
618
#define FORMAT_LOG(Message) "[%s] " Message, FormatterKind<ImplSP>
619
620
template <typename ImplSP>
621
ImplSP FormatManager::Get(ValueObject &valobj,
622
lldb::DynamicValueType use_dynamic) {
623
FormattersMatchData match_data(valobj, use_dynamic);
624
if (ImplSP retval_sp = GetCached<ImplSP>(match_data))
625
return retval_sp;
626
627
Log *log = GetLog(LLDBLog::DataFormatters);
628
629
LLDB_LOGF(log, FORMAT_LOG("Search failed. Giving language a chance."));
630
for (lldb::LanguageType lang_type : match_data.GetCandidateLanguages()) {
631
if (LanguageCategory *lang_category = GetCategoryForLanguage(lang_type)) {
632
ImplSP retval_sp;
633
if (lang_category->Get(match_data, retval_sp))
634
if (retval_sp) {
635
LLDB_LOGF(log, FORMAT_LOG("Language search success. Returning."));
636
return retval_sp;
637
}
638
}
639
}
640
641
LLDB_LOGF(log, FORMAT_LOG("Search failed. Giving hardcoded a chance."));
642
return GetHardcoded<ImplSP>(match_data);
643
}
644
645
template <typename ImplSP>
646
ImplSP FormatManager::GetCached(FormattersMatchData &match_data) {
647
ImplSP retval_sp;
648
Log *log = GetLog(LLDBLog::DataFormatters);
649
if (match_data.GetTypeForCache()) {
650
LLDB_LOGF(log, "\n\n" FORMAT_LOG("Looking into cache for type %s"),
651
match_data.GetTypeForCache().AsCString("<invalid>"));
652
if (m_format_cache.Get(match_data.GetTypeForCache(), retval_sp)) {
653
if (log) {
654
LLDB_LOGF(log, FORMAT_LOG("Cache search success. Returning."));
655
LLDB_LOGV(log, "Cache hits: {0} - Cache Misses: {1}",
656
m_format_cache.GetCacheHits(),
657
m_format_cache.GetCacheMisses());
658
}
659
return retval_sp;
660
}
661
LLDB_LOGF(log, FORMAT_LOG("Cache search failed. Going normal route"));
662
}
663
664
m_categories_map.Get(match_data, retval_sp);
665
if (match_data.GetTypeForCache() && (!retval_sp || !retval_sp->NonCacheable())) {
666
LLDB_LOGF(log, FORMAT_LOG("Caching %p for type %s"),
667
static_cast<void *>(retval_sp.get()),
668
match_data.GetTypeForCache().AsCString("<invalid>"));
669
m_format_cache.Set(match_data.GetTypeForCache(), retval_sp);
670
}
671
LLDB_LOGV(log, "Cache hits: {0} - Cache Misses: {1}",
672
m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
673
return retval_sp;
674
}
675
676
#undef FORMAT_LOG
677
678
lldb::TypeFormatImplSP
679
FormatManager::GetFormat(ValueObject &valobj,
680
lldb::DynamicValueType use_dynamic) {
681
return Get<lldb::TypeFormatImplSP>(valobj, use_dynamic);
682
}
683
684
lldb::TypeSummaryImplSP
685
FormatManager::GetSummaryFormat(ValueObject &valobj,
686
lldb::DynamicValueType use_dynamic) {
687
return Get<lldb::TypeSummaryImplSP>(valobj, use_dynamic);
688
}
689
690
lldb::SyntheticChildrenSP
691
FormatManager::GetSyntheticChildren(ValueObject &valobj,
692
lldb::DynamicValueType use_dynamic) {
693
return Get<lldb::SyntheticChildrenSP>(valobj, use_dynamic);
694
}
695
696
FormatManager::FormatManager()
697
: m_last_revision(0), m_format_cache(), m_language_categories_mutex(),
698
m_language_categories_map(), m_named_summaries_map(this),
699
m_categories_map(this), m_default_category_name(ConstString("default")),
700
m_system_category_name(ConstString("system")),
701
m_vectortypes_category_name(ConstString("VectorTypes")) {
702
LoadSystemFormatters();
703
LoadVectorFormatters();
704
705
EnableCategory(m_vectortypes_category_name, TypeCategoryMap::Last,
706
lldb::eLanguageTypeObjC_plus_plus);
707
EnableCategory(m_system_category_name, TypeCategoryMap::Last,
708
lldb::eLanguageTypeObjC_plus_plus);
709
}
710
711
void FormatManager::LoadSystemFormatters() {
712
TypeSummaryImpl::Flags string_flags;
713
string_flags.SetCascades(true)
714
.SetSkipPointers(true)
715
.SetSkipReferences(false)
716
.SetDontShowChildren(true)
717
.SetDontShowValue(false)
718
.SetShowMembersOneLiner(false)
719
.SetHideItemNames(false);
720
721
TypeSummaryImpl::Flags string_array_flags;
722
string_array_flags.SetCascades(true)
723
.SetSkipPointers(true)
724
.SetSkipReferences(false)
725
.SetDontShowChildren(true)
726
.SetDontShowValue(true)
727
.SetShowMembersOneLiner(false)
728
.SetHideItemNames(false);
729
730
lldb::TypeSummaryImplSP string_format(
731
new StringSummaryFormat(string_flags, "${var%s}"));
732
733
lldb::TypeSummaryImplSP string_array_format(
734
new StringSummaryFormat(string_array_flags, "${var%char[]}"));
735
736
TypeCategoryImpl::SharedPointer sys_category_sp =
737
GetCategory(m_system_category_name);
738
739
sys_category_sp->AddTypeSummary(R"(^(unsigned )?char ?(\*|\[\])$)",
740
eFormatterMatchRegex, string_format);
741
742
sys_category_sp->AddTypeSummary(R"(^((un)?signed )?char ?\[[0-9]+\]$)",
743
eFormatterMatchRegex, string_array_format);
744
745
lldb::TypeSummaryImplSP ostype_summary(
746
new StringSummaryFormat(TypeSummaryImpl::Flags()
747
.SetCascades(false)
748
.SetSkipPointers(true)
749
.SetSkipReferences(true)
750
.SetDontShowChildren(true)
751
.SetDontShowValue(false)
752
.SetShowMembersOneLiner(false)
753
.SetHideItemNames(false),
754
"${var%O}"));
755
756
sys_category_sp->AddTypeSummary("OSType", eFormatterMatchExact,
757
ostype_summary);
758
759
TypeFormatImpl::Flags fourchar_flags;
760
fourchar_flags.SetCascades(true).SetSkipPointers(true).SetSkipReferences(
761
true);
762
763
AddFormat(sys_category_sp, lldb::eFormatOSType, "FourCharCode",
764
fourchar_flags);
765
}
766
767
void FormatManager::LoadVectorFormatters() {
768
TypeCategoryImpl::SharedPointer vectors_category_sp =
769
GetCategory(m_vectortypes_category_name);
770
771
TypeSummaryImpl::Flags vector_flags;
772
vector_flags.SetCascades(true)
773
.SetSkipPointers(true)
774
.SetSkipReferences(false)
775
.SetDontShowChildren(true)
776
.SetDontShowValue(false)
777
.SetShowMembersOneLiner(true)
778
.SetHideItemNames(true);
779
780
AddStringSummary(vectors_category_sp, "${var.uint128}", "builtin_type_vec128",
781
vector_flags);
782
AddStringSummary(vectors_category_sp, "", "float[4]", vector_flags);
783
AddStringSummary(vectors_category_sp, "", "int32_t[4]", vector_flags);
784
AddStringSummary(vectors_category_sp, "", "int16_t[8]", vector_flags);
785
AddStringSummary(vectors_category_sp, "", "vDouble", vector_flags);
786
AddStringSummary(vectors_category_sp, "", "vFloat", vector_flags);
787
AddStringSummary(vectors_category_sp, "", "vSInt8", vector_flags);
788
AddStringSummary(vectors_category_sp, "", "vSInt16", vector_flags);
789
AddStringSummary(vectors_category_sp, "", "vSInt32", vector_flags);
790
AddStringSummary(vectors_category_sp, "", "vUInt16", vector_flags);
791
AddStringSummary(vectors_category_sp, "", "vUInt8", vector_flags);
792
AddStringSummary(vectors_category_sp, "", "vUInt16", vector_flags);
793
AddStringSummary(vectors_category_sp, "", "vUInt32", vector_flags);
794
AddStringSummary(vectors_category_sp, "", "vBool32", vector_flags);
795
}
796
797