xref: /llvm-project/lldb/source/DataFormatters/FormatManager.cpp (revision 170c395e7004732b10d6ff7762f420fff1cfc40c)
1 //===-- FormatManager.cpp -------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "lldb/DataFormatters/FormatManager.h"
11 
12 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 
17 #include "lldb/Core/Debugger.h"
18 #include "lldb/DataFormatters/CXXFunctionPointer.h"
19 #include "lldb/DataFormatters/VectorType.h"
20 #include "lldb/DataFormatters/FormattersHelpers.h"
21 #include "lldb/DataFormatters/LanguageCategory.h"
22 #include "lldb/Target/ExecutionContext.h"
23 #include "lldb/Target/Language.h"
24 #include "lldb/Target/Platform.h"
25 #include "llvm/ADT/STLExtras.h"
26 
27 #include <initializer_list>
28 
29 using namespace lldb;
30 using namespace lldb_private;
31 using namespace lldb_private::formatters;
32 
33 struct FormatInfo
34 {
35     Format format;
36     const char format_char; // One or more format characters that can be used for this format.
37     const char *format_name;    // Long format name that can be used to specify the current format
38 };
39 
40 static FormatInfo
41 g_format_infos[] =
42 {
43     { eFormatDefault        , '\0'  , "default"             },
44     { eFormatBoolean        , 'B'   , "boolean"             },
45     { eFormatBinary         , 'b'   , "binary"              },
46     { eFormatBytes          , 'y'   , "bytes"               },
47     { eFormatBytesWithASCII , 'Y'   , "bytes with ASCII"    },
48     { eFormatChar           , 'c'   , "character"           },
49     { eFormatCharPrintable  , 'C'   , "printable character" },
50     { eFormatComplexFloat   , 'F'   , "complex float"       },
51     { eFormatCString        , 's'   , "c-string"            },
52     { eFormatDecimal        , 'd'   , "decimal"             },
53     { eFormatEnum           , 'E'   , "enumeration"         },
54     { eFormatHex            , 'x'   , "hex"                 },
55     { eFormatHexUppercase   , 'X'   , "uppercase hex"       },
56     { eFormatFloat          , 'f'   , "float"               },
57     { eFormatOctal          , 'o'   , "octal"               },
58     { eFormatOSType         , 'O'   , "OSType"              },
59     { eFormatUnicode16      , 'U'   , "unicode16"           },
60     { eFormatUnicode32      , '\0'  , "unicode32"           },
61     { eFormatUnsigned       , 'u'   , "unsigned decimal"    },
62     { eFormatPointer        , 'p'   , "pointer"             },
63     { eFormatVectorOfChar   , '\0'  , "char[]"              },
64     { eFormatVectorOfSInt8  , '\0'  , "int8_t[]"            },
65     { eFormatVectorOfUInt8  , '\0'  , "uint8_t[]"           },
66     { eFormatVectorOfSInt16 , '\0'  , "int16_t[]"           },
67     { eFormatVectorOfUInt16 , '\0'  , "uint16_t[]"          },
68     { eFormatVectorOfSInt32 , '\0'  , "int32_t[]"           },
69     { eFormatVectorOfUInt32 , '\0'  , "uint32_t[]"          },
70     { eFormatVectorOfSInt64 , '\0'  , "int64_t[]"           },
71     { eFormatVectorOfUInt64 , '\0'  , "uint64_t[]"          },
72     { eFormatVectorOfFloat32, '\0'  , "float32[]"           },
73     { eFormatVectorOfFloat64, '\0'  , "float64[]"           },
74     { eFormatVectorOfUInt128, '\0'  , "uint128_t[]"         },
75     { eFormatComplexInteger , 'I'   , "complex integer"     },
76     { eFormatCharArray      , 'a'   , "character array"     },
77     { eFormatAddressInfo    , 'A'   , "address"             },
78     { eFormatHexFloat       , '\0'  , "hex float"           },
79     { eFormatInstruction    , 'i'   , "instruction"         },
80     { eFormatVoid           , 'v'   , "void"                }
81 };
82 
83 static uint32_t g_num_format_infos = llvm::array_lengthof(g_format_infos);
84 
85 static bool
86 GetFormatFromFormatChar (char format_char, Format &format)
87 {
88     for (uint32_t i=0; i<g_num_format_infos; ++i)
89     {
90         if (g_format_infos[i].format_char == format_char)
91         {
92             format = g_format_infos[i].format;
93             return true;
94         }
95     }
96     format = eFormatInvalid;
97     return false;
98 }
99 
100 static bool
101 GetFormatFromFormatName (const char *format_name, bool partial_match_ok, Format &format)
102 {
103     uint32_t i;
104     for (i=0; i<g_num_format_infos; ++i)
105     {
106         if (strcasecmp (g_format_infos[i].format_name, format_name) == 0)
107         {
108             format = g_format_infos[i].format;
109             return true;
110         }
111     }
112 
113     if (partial_match_ok)
114     {
115         for (i=0; i<g_num_format_infos; ++i)
116         {
117             if (strcasestr (g_format_infos[i].format_name, format_name) == g_format_infos[i].format_name)
118             {
119                 format = g_format_infos[i].format;
120                 return true;
121             }
122         }
123     }
124     format = eFormatInvalid;
125     return false;
126 }
127 
128 bool
129 FormatManager::GetFormatFromCString (const char *format_cstr,
130                                      bool partial_match_ok,
131                                      lldb::Format &format)
132 {
133     bool success = false;
134     if (format_cstr && format_cstr[0])
135     {
136         if (format_cstr[1] == '\0')
137         {
138             success = GetFormatFromFormatChar (format_cstr[0], format);
139             if (success)
140                 return true;
141         }
142 
143         success = GetFormatFromFormatName (format_cstr, partial_match_ok, format);
144     }
145     if (!success)
146         format = eFormatInvalid;
147     return success;
148 }
149 
150 char
151 FormatManager::GetFormatAsFormatChar (lldb::Format format)
152 {
153     for (uint32_t i=0; i<g_num_format_infos; ++i)
154     {
155         if (g_format_infos[i].format == format)
156             return g_format_infos[i].format_char;
157     }
158     return '\0';
159 }
160 
161 const char *
162 FormatManager::GetFormatAsCString (Format format)
163 {
164     if (format >= eFormatDefault && format < kNumFormats)
165         return g_format_infos[format].format_name;
166     return NULL;
167 }
168 
169 void
170 FormatManager::EnableAllCategories ()
171 {
172     m_categories_map.EnableAllCategories ();
173     Mutex::Locker lang_locker(m_language_categories_mutex);
174     for (auto& iter : m_language_categories_map)
175     {
176         if (iter.second)
177             iter.second->Enable();
178     }
179 }
180 
181 void
182 FormatManager::DisableAllCategories ()
183 {
184     m_categories_map.DisableAllCategories ();
185     Mutex::Locker lang_locker(m_language_categories_mutex);
186     for (auto& iter : m_language_categories_map)
187     {
188         if (iter.second)
189             iter.second->Disable();
190     }
191 }
192 
193 void
194 FormatManager::GetPossibleMatches (ValueObject& valobj,
195                                    CompilerType clang_type,
196                                    uint32_t reason,
197                                    lldb::DynamicValueType use_dynamic,
198                                    FormattersMatchVector& entries,
199                                    bool did_strip_ptr,
200                                    bool did_strip_ref,
201                                    bool did_strip_typedef,
202                                    bool root_level)
203 {
204     clang_type = ClangASTContext::RemoveFastQualifiers(clang_type);
205     ConstString type_name(clang_type.GetConstTypeName());
206     if (valobj.GetBitfieldBitSize() > 0)
207     {
208         StreamString sstring;
209         sstring.Printf("%s:%d",type_name.AsCString(),valobj.GetBitfieldBitSize());
210         ConstString bitfieldname = ConstString(sstring.GetData());
211         entries.push_back({bitfieldname,0,did_strip_ptr,did_strip_ref,did_strip_typedef});
212         reason |= lldb_private::eFormatterChoiceCriterionStrippedBitField;
213     }
214     entries.push_back({type_name,reason,did_strip_ptr,did_strip_ref,did_strip_typedef});
215 
216     ConstString display_type_name(clang_type.GetDisplayTypeName());
217     if (display_type_name != type_name)
218         entries.push_back({display_type_name,reason,did_strip_ptr,did_strip_ref,did_strip_typedef});
219 
220     for (bool is_rvalue_ref = true, j = true; j && clang_type.IsReferenceType(nullptr, &is_rvalue_ref); j = false)
221     {
222         CompilerType non_ref_type = clang_type.GetNonReferenceType();
223         GetPossibleMatches(valobj,
224                            non_ref_type,
225                            reason | lldb_private::eFormatterChoiceCriterionStrippedPointerReference,
226                            use_dynamic,
227                            entries,
228                            did_strip_ptr,
229                            true,
230                            did_strip_typedef);
231         if (non_ref_type.IsTypedefType())
232         {
233             CompilerType deffed_referenced_type = non_ref_type.GetTypedefedType();
234             deffed_referenced_type = is_rvalue_ref ? ClangASTContext::GetRValueReferenceType(deffed_referenced_type) : ClangASTContext::GetLValueReferenceType(deffed_referenced_type);
235             GetPossibleMatches(valobj,
236                                deffed_referenced_type,
237                                reason | lldb_private::eFormatterChoiceCriterionNavigatedTypedefs,
238                                use_dynamic,
239                                entries,
240                                did_strip_ptr,
241                                did_strip_ref,
242                                true); // this is not exactly the usual meaning of stripping typedefs
243         }
244     }
245 
246     if (clang_type.IsPointerType())
247     {
248         CompilerType non_ptr_type = clang_type.GetPointeeType();
249         GetPossibleMatches(valobj,
250                            non_ptr_type,
251                            reason | lldb_private::eFormatterChoiceCriterionStrippedPointerReference,
252                            use_dynamic,
253                            entries,
254                            true,
255                            did_strip_ref,
256                            did_strip_typedef);
257         if (non_ptr_type.IsTypedefType())
258         {
259             CompilerType deffed_pointed_type = non_ptr_type.GetTypedefedType().GetPointerType();
260             GetPossibleMatches(valobj,
261                                deffed_pointed_type,
262                                reason | lldb_private::eFormatterChoiceCriterionNavigatedTypedefs,
263                                use_dynamic,
264                                entries,
265                                did_strip_ptr,
266                                did_strip_ref,
267                                true); // this is not exactly the usual meaning of stripping typedefs
268         }
269     }
270 
271     for (lldb::LanguageType language_type : GetCandidateLanguages(valobj))
272     {
273         if (Language* language = Language::FindPlugin(language_type))
274         {
275             for (ConstString candidate : language->GetPossibleFormattersMatches(valobj, use_dynamic))
276             {
277                 entries.push_back({candidate,
278                                    reason | lldb_private::eFormatterChoiceCriterionLanguagePlugin,
279                                    did_strip_ptr,
280                                    did_strip_ref,
281                                    did_strip_typedef});
282             }
283         }
284     }
285 
286     // try to strip typedef chains
287     if (clang_type.IsTypedefType())
288     {
289         CompilerType deffed_type = clang_type.GetTypedefedType();
290         GetPossibleMatches(valobj,
291                            deffed_type,
292                            reason | lldb_private::eFormatterChoiceCriterionNavigatedTypedefs,
293                            use_dynamic,
294                            entries,
295                            did_strip_ptr,
296                            did_strip_ref,
297                            true);
298     }
299 
300     if (root_level)
301     {
302         do {
303             if (!clang_type.IsValid())
304                 break;
305 
306             CompilerType unqual_clang_ast_type = clang_type.GetFullyUnqualifiedType();
307             if (!unqual_clang_ast_type.IsValid())
308                 break;
309             if (unqual_clang_ast_type.GetOpaqueQualType() != clang_type.GetOpaqueQualType())
310                 GetPossibleMatches (valobj,
311                                     unqual_clang_ast_type,
312                                     reason,
313                                     use_dynamic,
314                                     entries,
315                                     did_strip_ptr,
316                                     did_strip_ref,
317                                     did_strip_typedef);
318         } while(false);
319 
320 
321         // if all else fails, go to static type
322         if (valobj.IsDynamic())
323         {
324             lldb::ValueObjectSP static_value_sp(valobj.GetStaticValue());
325             if (static_value_sp)
326                 GetPossibleMatches(*static_value_sp.get(),
327                                    static_value_sp->GetCompilerType(),
328                                    reason | lldb_private::eFormatterChoiceCriterionWentToStaticValue,
329                                    use_dynamic,
330                                    entries,
331                                    did_strip_ptr,
332                                    did_strip_ref,
333                                    did_strip_typedef,
334                                    true);
335         }
336     }
337 }
338 
339 lldb::TypeFormatImplSP
340 FormatManager::GetFormatForType (lldb::TypeNameSpecifierImplSP type_sp)
341 {
342     if (!type_sp)
343         return lldb::TypeFormatImplSP();
344     lldb::TypeFormatImplSP format_chosen_sp;
345     uint32_t num_categories = m_categories_map.GetCount();
346     lldb::TypeCategoryImplSP category_sp;
347     uint32_t prio_category = UINT32_MAX;
348     for (uint32_t category_id = 0;
349          category_id < num_categories;
350          category_id++)
351     {
352         category_sp = GetCategoryAtIndex(category_id);
353         if (category_sp->IsEnabled() == false)
354             continue;
355         lldb::TypeFormatImplSP format_current_sp = category_sp->GetFormatForType(type_sp);
356         if (format_current_sp && (format_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition())))
357         {
358             prio_category = category_sp->GetEnabledPosition();
359             format_chosen_sp = format_current_sp;
360         }
361     }
362     return format_chosen_sp;
363 }
364 
365 lldb::TypeSummaryImplSP
366 FormatManager::GetSummaryForType (lldb::TypeNameSpecifierImplSP type_sp)
367 {
368     if (!type_sp)
369         return lldb::TypeSummaryImplSP();
370     lldb::TypeSummaryImplSP summary_chosen_sp;
371     uint32_t num_categories = m_categories_map.GetCount();
372     lldb::TypeCategoryImplSP category_sp;
373     uint32_t prio_category = UINT32_MAX;
374     for (uint32_t category_id = 0;
375          category_id < num_categories;
376          category_id++)
377     {
378         category_sp = GetCategoryAtIndex(category_id);
379         if (category_sp->IsEnabled() == false)
380             continue;
381         lldb::TypeSummaryImplSP summary_current_sp = category_sp->GetSummaryForType(type_sp);
382         if (summary_current_sp && (summary_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition())))
383         {
384             prio_category = category_sp->GetEnabledPosition();
385             summary_chosen_sp = summary_current_sp;
386         }
387     }
388     return summary_chosen_sp;
389 }
390 
391 lldb::TypeFilterImplSP
392 FormatManager::GetFilterForType (lldb::TypeNameSpecifierImplSP type_sp)
393 {
394     if (!type_sp)
395         return lldb::TypeFilterImplSP();
396     lldb::TypeFilterImplSP filter_chosen_sp;
397     uint32_t num_categories = m_categories_map.GetCount();
398     lldb::TypeCategoryImplSP category_sp;
399     uint32_t prio_category = UINT32_MAX;
400     for (uint32_t category_id = 0;
401          category_id < num_categories;
402          category_id++)
403     {
404         category_sp = GetCategoryAtIndex(category_id);
405         if (category_sp->IsEnabled() == false)
406             continue;
407         lldb::TypeFilterImplSP filter_current_sp((TypeFilterImpl*)category_sp->GetFilterForType(type_sp).get());
408         if (filter_current_sp && (filter_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition())))
409         {
410             prio_category = category_sp->GetEnabledPosition();
411             filter_chosen_sp = filter_current_sp;
412         }
413     }
414     return filter_chosen_sp;
415 }
416 
417 #ifndef LLDB_DISABLE_PYTHON
418 lldb::ScriptedSyntheticChildrenSP
419 FormatManager::GetSyntheticForType (lldb::TypeNameSpecifierImplSP type_sp)
420 {
421     if (!type_sp)
422         return lldb::ScriptedSyntheticChildrenSP();
423     lldb::ScriptedSyntheticChildrenSP synth_chosen_sp;
424     uint32_t num_categories = m_categories_map.GetCount();
425     lldb::TypeCategoryImplSP category_sp;
426     uint32_t prio_category = UINT32_MAX;
427     for (uint32_t category_id = 0;
428          category_id < num_categories;
429          category_id++)
430     {
431         category_sp = GetCategoryAtIndex(category_id);
432         if (category_sp->IsEnabled() == false)
433             continue;
434         lldb::ScriptedSyntheticChildrenSP synth_current_sp((ScriptedSyntheticChildren*)category_sp->GetSyntheticForType(type_sp).get());
435         if (synth_current_sp && (synth_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition())))
436         {
437             prio_category = category_sp->GetEnabledPosition();
438             synth_chosen_sp = synth_current_sp;
439         }
440     }
441     return synth_chosen_sp;
442 }
443 #endif
444 
445 #ifndef LLDB_DISABLE_PYTHON
446 lldb::SyntheticChildrenSP
447 FormatManager::GetSyntheticChildrenForType (lldb::TypeNameSpecifierImplSP type_sp)
448 {
449     if (!type_sp)
450         return lldb::SyntheticChildrenSP();
451     lldb::TypeFilterImplSP filter_sp = GetFilterForType(type_sp);
452     lldb::ScriptedSyntheticChildrenSP synth_sp = GetSyntheticForType(type_sp);
453     if (filter_sp->GetRevision() > synth_sp->GetRevision())
454         return lldb::SyntheticChildrenSP(filter_sp.get());
455     else
456         return lldb::SyntheticChildrenSP(synth_sp.get());
457 }
458 #endif
459 
460 lldb::TypeValidatorImplSP
461 FormatManager::GetValidatorForType (lldb::TypeNameSpecifierImplSP type_sp)
462 {
463     if (!type_sp)
464         return lldb::TypeValidatorImplSP();
465     lldb::TypeValidatorImplSP validator_chosen_sp;
466     uint32_t num_categories = m_categories_map.GetCount();
467     lldb::TypeCategoryImplSP category_sp;
468     uint32_t prio_category = UINT32_MAX;
469     for (uint32_t category_id = 0;
470          category_id < num_categories;
471          category_id++)
472     {
473         category_sp = GetCategoryAtIndex(category_id);
474         if (category_sp->IsEnabled() == false)
475             continue;
476         lldb::TypeValidatorImplSP validator_current_sp(category_sp->GetValidatorForType(type_sp).get());
477         if (validator_current_sp && (validator_chosen_sp.get() == NULL || (prio_category > category_sp->GetEnabledPosition())))
478         {
479             prio_category = category_sp->GetEnabledPosition();
480             validator_chosen_sp = validator_current_sp;
481         }
482     }
483     return validator_chosen_sp;
484 }
485 
486 void
487 FormatManager::LoopThroughCategories (CategoryCallback callback, void* param)
488 {
489     m_categories_map.LoopThrough(callback, param);
490     Mutex::Locker locker(m_language_categories_mutex);
491     for (const auto& entry : m_language_categories_map)
492     {
493         if (auto category_sp = entry.second->GetCategory())
494         {
495             if (!callback(param, category_sp))
496                 break;
497         }
498     }
499 }
500 
501 lldb::TypeCategoryImplSP
502 FormatManager::GetCategory (const ConstString& category_name,
503                             bool can_create)
504 {
505     if (!category_name)
506         return GetCategory(m_default_category_name);
507     lldb::TypeCategoryImplSP category;
508     if (m_categories_map.Get(category_name, category))
509         return category;
510 
511     if (!can_create)
512         return lldb::TypeCategoryImplSP();
513 
514     m_categories_map.Add(category_name,lldb::TypeCategoryImplSP(new TypeCategoryImpl(this, category_name)));
515     return GetCategory(category_name);
516 }
517 
518 lldb::Format
519 FormatManager::GetSingleItemFormat(lldb::Format vector_format)
520 {
521     switch(vector_format)
522     {
523         case eFormatVectorOfChar:
524             return eFormatCharArray;
525 
526         case eFormatVectorOfSInt8:
527         case eFormatVectorOfSInt16:
528         case eFormatVectorOfSInt32:
529         case eFormatVectorOfSInt64:
530             return eFormatDecimal;
531 
532         case eFormatVectorOfUInt8:
533         case eFormatVectorOfUInt16:
534         case eFormatVectorOfUInt32:
535         case eFormatVectorOfUInt64:
536         case eFormatVectorOfUInt128:
537             return eFormatHex;
538 
539         case eFormatVectorOfFloat32:
540         case eFormatVectorOfFloat64:
541             return eFormatFloat;
542 
543         default:
544             return lldb::eFormatInvalid;
545     }
546 }
547 
548 bool
549 FormatManager::ShouldPrintAsOneLiner (ValueObject& valobj)
550 {
551     // if settings say no oneline whatsoever
552     if (valobj.GetTargetSP().get() && valobj.GetTargetSP()->GetDebugger().GetAutoOneLineSummaries() == false)
553         return false; // then don't oneline
554 
555     // if this object has a summary, then ask the summary
556     if (valobj.GetSummaryFormat().get() != nullptr)
557         return valobj.GetSummaryFormat()->IsOneLiner();
558 
559     // no children, no party
560     if (valobj.GetNumChildren() == 0)
561         return false;
562 
563     size_t total_children_name_len = 0;
564 
565     for (size_t idx = 0;
566          idx < valobj.GetNumChildren();
567          idx++)
568     {
569         bool is_synth_val = false;
570         ValueObjectSP child_sp(valobj.GetChildAtIndex(idx, true));
571         // something is wrong here - bail out
572         if (!child_sp)
573             return false;
574         // if we decided to define synthetic children for a type, we probably care enough
575         // to show them, but avoid nesting children in children
576         if (child_sp->GetSyntheticChildren().get() != nullptr)
577         {
578             ValueObjectSP synth_sp(child_sp->GetSyntheticValue());
579             // wait.. wat? just get out of here..
580             if (!synth_sp)
581                 return false;
582             // but if we only have them to provide a value, keep going
583             if (synth_sp->MightHaveChildren() == false && synth_sp->DoesProvideSyntheticValue())
584                 is_synth_val = true;
585             else
586                 return false;
587         }
588 
589         total_children_name_len += child_sp->GetName().GetLength();
590 
591         // 50 itself is a "randomly" chosen number - the idea is that
592         // overly long structs should not get this treatment
593         // FIXME: maybe make this a user-tweakable setting?
594         if (total_children_name_len > 50)
595             return false;
596 
597         // if a summary is there..
598         if (child_sp->GetSummaryFormat())
599         {
600             // and it wants children, then bail out
601             if (child_sp->GetSummaryFormat()->DoesPrintChildren(child_sp.get()))
602                 return false;
603         }
604 
605         // if this child has children..
606         if (child_sp->GetNumChildren())
607         {
608             // ...and no summary...
609             // (if it had a summary and the summary wanted children, we would have bailed out anyway
610             //  so this only makes us bail out if this has no summary and we would then print children)
611             if (!child_sp->GetSummaryFormat() && !is_synth_val) // but again only do that if not a synthetic valued child
612                 return false; // then bail out
613         }
614     }
615     return true;
616 }
617 
618 ConstString
619 FormatManager::GetValidTypeName (const ConstString& type)
620 {
621     return ::GetValidTypeName_Impl(type);
622 }
623 
624 ConstString
625 FormatManager::GetTypeForCache (ValueObject& valobj,
626                                 lldb::DynamicValueType use_dynamic)
627 {
628     if (use_dynamic == lldb::eNoDynamicValues)
629     {
630         if (valobj.IsDynamic())
631         {
632             if (valobj.GetStaticValue())
633                 return valobj.GetStaticValue()->GetQualifiedTypeName();
634             else
635                 return ConstString();
636         }
637         else
638             return valobj.GetQualifiedTypeName();
639     }
640     if (valobj.IsDynamic())
641         return valobj.GetQualifiedTypeName();
642     if (valobj.GetDynamicValue(use_dynamic))
643         return valobj.GetDynamicValue(use_dynamic)->GetQualifiedTypeName();
644     return ConstString();
645 }
646 
647 std::vector<lldb::LanguageType>
648 FormatManager::GetCandidateLanguages (ValueObject& valobj)
649 {
650     lldb::LanguageType lang_type = valobj.GetObjectRuntimeLanguage();
651     return GetCandidateLanguages(lang_type);
652 }
653 
654 std::vector<lldb::LanguageType>
655 FormatManager::GetCandidateLanguages (lldb::LanguageType lang_type)
656 {
657     switch (lang_type)
658     {
659         case lldb::eLanguageTypeC:
660         case lldb::eLanguageTypeC89:
661         case lldb::eLanguageTypeC99:
662         case lldb::eLanguageTypeC11:
663         case lldb::eLanguageTypeC_plus_plus:
664         case lldb::eLanguageTypeC_plus_plus_03:
665         case lldb::eLanguageTypeC_plus_plus_11:
666         case lldb::eLanguageTypeC_plus_plus_14:
667             return {lldb::eLanguageTypeC_plus_plus, lldb::eLanguageTypeObjC};
668         default:
669             return {lang_type};
670     }
671 }
672 
673 LanguageCategory*
674 FormatManager::GetCategoryForLanguage (lldb::LanguageType lang_type)
675 {
676     Mutex::Locker locker(m_language_categories_mutex);
677     auto iter = m_language_categories_map.find(lang_type), end = m_language_categories_map.end();
678     if (iter != end)
679         return iter->second.get();
680     LanguageCategory* lang_category = new LanguageCategory(lang_type);
681     m_language_categories_map[lang_type] = LanguageCategory::UniquePointer(lang_category);
682     return lang_category;
683 }
684 
685 lldb::TypeFormatImplSP
686 FormatManager::GetHardcodedFormat (ValueObject& valobj,
687                                    lldb::DynamicValueType use_dynamic)
688 {
689     for (const auto& candidate: m_hardcoded_formats)
690     {
691         auto result = candidate(valobj,use_dynamic,*this);
692         if (result)
693             return result;
694     }
695     return nullptr;
696 }
697 
698 lldb::TypeFormatImplSP
699 FormatManager::GetFormat (ValueObject& valobj,
700                           lldb::DynamicValueType use_dynamic)
701 {
702     TypeFormatImplSP retval;
703     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
704     ConstString valobj_type(GetTypeForCache(valobj, use_dynamic));
705     if (valobj_type)
706     {
707         if (log)
708             log->Printf("\n\n[FormatManager::GetFormat] Looking into cache for type %s", valobj_type.AsCString("<invalid>"));
709         if (m_format_cache.GetFormat(valobj_type,retval))
710         {
711             if (log)
712             {
713                 log->Printf("[FormatManager::GetFormat] Cache search success. Returning.");
714                 if (log->GetDebug())
715                     log->Printf("[FormatManager::GetFormat] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
716             }
717             return retval;
718         }
719         if (log)
720             log->Printf("[FormatManager::GetFormat] Cache search failed. Going normal route");
721     }
722 
723     FormattersMatchVector matches = GetPossibleMatches(valobj, use_dynamic);
724 
725     retval = m_categories_map.GetFormat(valobj, use_dynamic, matches);
726     if (!retval)
727     {
728         if (log)
729             log->Printf("[FormatManager::GetFormat] Search failed. Giving language a chance.");
730         for (lldb::LanguageType lang_type : GetCandidateLanguages(valobj))
731         {
732             if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type))
733             {
734                 if (lang_category->Get(valobj, use_dynamic, matches, retval))
735                     break;
736             }
737         }
738         if (retval)
739         {
740             if (log)
741                 log->Printf("[FormatManager::GetFormat] Language search success. Returning.");
742             return retval;
743         }
744     }
745     if (!retval)
746     {
747         if (log)
748             log->Printf("[FormatManager::GetFormat] Search failed. Giving hardcoded a chance.");
749         retval = GetHardcodedFormat(valobj, use_dynamic);
750     }
751 
752     if (valobj_type && (!retval || !retval->NonCacheable()))
753     {
754         if (log)
755             log->Printf("[FormatManager::GetFormat] Caching %p for type %s",
756                         static_cast<void*>(retval.get()),
757                         valobj_type.AsCString("<invalid>"));
758         m_format_cache.SetFormat(valobj_type,retval);
759     }
760     if (log && log->GetDebug())
761         log->Printf("[FormatManager::GetFormat] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
762     return retval;
763 }
764 
765 lldb::TypeSummaryImplSP
766 FormatManager::GetHardcodedSummaryFormat (ValueObject& valobj,
767                                           lldb::DynamicValueType use_dynamic)
768 {
769     for (const auto& candidate: m_hardcoded_summaries)
770     {
771         auto result = candidate(valobj,use_dynamic,*this);
772         if (result)
773             return result;
774     }
775     return nullptr;
776 }
777 
778 lldb::TypeSummaryImplSP
779 FormatManager::GetSummaryFormat (ValueObject& valobj,
780                                  lldb::DynamicValueType use_dynamic)
781 {
782     TypeSummaryImplSP retval;
783     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
784     ConstString valobj_type(GetTypeForCache(valobj, use_dynamic));
785     if (valobj_type)
786     {
787         if (log)
788             log->Printf("\n\n[FormatManager::GetSummaryFormat] Looking into cache for type %s", valobj_type.AsCString("<invalid>"));
789         if (m_format_cache.GetSummary(valobj_type,retval))
790         {
791             if (log)
792             {
793                 log->Printf("[FormatManager::GetSummaryFormat] Cache search success. Returning.");
794                 if (log->GetDebug())
795                     log->Printf("[FormatManager::GetSummaryFormat] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
796             }
797             return retval;
798         }
799         if (log)
800             log->Printf("[FormatManager::GetSummaryFormat] Cache search failed. Going normal route");
801     }
802 
803     FormattersMatchVector matches = GetPossibleMatches(valobj, use_dynamic);
804 
805     retval = m_categories_map.GetSummaryFormat(valobj, use_dynamic, matches);
806     if (!retval)
807     {
808         if (log)
809             log->Printf("[FormatManager::GetSummaryFormat] Search failed. Giving language a chance.");
810         for (lldb::LanguageType lang_type : GetCandidateLanguages(valobj))
811         {
812             if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type))
813             {
814                 if (lang_category->Get(valobj, use_dynamic, matches, retval))
815                     break;
816             }
817         }
818         if (retval)
819         {
820             if (log)
821                 log->Printf("[FormatManager::GetSummaryFormat] Language search success. Returning.");
822             return retval;
823         }
824     }
825     if (!retval)
826     {
827         if (log)
828             log->Printf("[FormatManager::GetSummaryFormat] Search failed. Giving hardcoded a chance.");
829         retval = GetHardcodedSummaryFormat(valobj, use_dynamic);
830     }
831 
832     if (valobj_type && (!retval || !retval->NonCacheable()))
833     {
834         if (log)
835             log->Printf("[FormatManager::GetSummaryFormat] Caching %p for type %s",
836                         static_cast<void*>(retval.get()),
837                         valobj_type.AsCString("<invalid>"));
838         m_format_cache.SetSummary(valobj_type,retval);
839     }
840     if (log && log->GetDebug())
841         log->Printf("[FormatManager::GetSummaryFormat] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
842     return retval;
843 }
844 
845 #ifndef LLDB_DISABLE_PYTHON
846 lldb::SyntheticChildrenSP
847 FormatManager::GetHardcodedSyntheticChildren (ValueObject& valobj,
848                                               lldb::DynamicValueType use_dynamic)
849 {
850     for (const auto& candidate: m_hardcoded_synthetics)
851     {
852         auto result = candidate(valobj,use_dynamic,*this);
853         if (result)
854             return result;
855     }
856     return nullptr;
857 }
858 
859 lldb::SyntheticChildrenSP
860 FormatManager::GetSyntheticChildren (ValueObject& valobj,
861                                      lldb::DynamicValueType use_dynamic)
862 {
863     SyntheticChildrenSP retval;
864     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
865     ConstString valobj_type(GetTypeForCache(valobj, use_dynamic));
866     if (valobj_type)
867     {
868         if (log)
869             log->Printf("\n\n[FormatManager::GetSyntheticChildren] Looking into cache for type %s", valobj_type.AsCString("<invalid>"));
870         if (m_format_cache.GetSynthetic(valobj_type,retval))
871         {
872             if (log)
873             {
874                 log->Printf("[FormatManager::GetSyntheticChildren] Cache search success. Returning.");
875                 if (log->GetDebug())
876                     log->Printf("[FormatManager::GetSyntheticChildren] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
877             }
878             return retval;
879         }
880         if (log)
881             log->Printf("[FormatManager::GetSyntheticChildren] Cache search failed. Going normal route");
882     }
883 
884     FormattersMatchVector matches = GetPossibleMatches(valobj, use_dynamic);
885 
886     retval = m_categories_map.GetSyntheticChildren(valobj, use_dynamic, matches);
887     if (!retval)
888     {
889         if (log)
890             log->Printf("[FormatManager::GetSyntheticChildren] Search failed. Giving language a chance.");
891         for (lldb::LanguageType lang_type : GetCandidateLanguages(valobj))
892         {
893             if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type))
894             {
895                 if (lang_category->Get(valobj, use_dynamic, matches, retval))
896                     break;
897             }
898         }
899         if (retval)
900         {
901             if (log)
902                 log->Printf("[FormatManager::GetSyntheticChildren] Language search success. Returning.");
903             return retval;
904         }
905     }
906     if (!retval)
907     {
908         if (log)
909             log->Printf("[FormatManager::GetSyntheticChildren] Search failed. Giving hardcoded a chance.");
910         retval = GetHardcodedSyntheticChildren(valobj, use_dynamic);
911     }
912 
913     if (valobj_type && (!retval || !retval->NonCacheable()))
914     {
915         if (log)
916             log->Printf("[FormatManager::GetSyntheticChildren] Caching %p for type %s",
917                         static_cast<void*>(retval.get()),
918                         valobj_type.AsCString("<invalid>"));
919         m_format_cache.SetSynthetic(valobj_type,retval);
920     }
921     if (log && log->GetDebug())
922         log->Printf("[FormatManager::GetSyntheticChildren] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
923     return retval;
924 }
925 #endif
926 
927 lldb::TypeValidatorImplSP
928 FormatManager::GetValidator (ValueObject& valobj,
929                              lldb::DynamicValueType use_dynamic)
930 {
931     TypeValidatorImplSP retval;
932     Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
933     ConstString valobj_type(GetTypeForCache(valobj, use_dynamic));
934     if (valobj_type)
935     {
936         if (log)
937             log->Printf("\n\n[FormatManager::GetValidator] Looking into cache for type %s", valobj_type.AsCString("<invalid>"));
938         if (m_format_cache.GetValidator(valobj_type,retval))
939         {
940             if (log)
941             {
942                 log->Printf("[FormatManager::GetValidator] Cache search success. Returning.");
943                 if (log->GetDebug())
944                     log->Printf("[FormatManager::GetValidator] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
945             }
946             return retval;
947         }
948         if (log)
949             log->Printf("[FormatManager::GetValidator] Cache search failed. Going normal route");
950     }
951 
952     FormattersMatchVector matches = GetPossibleMatches(valobj, use_dynamic);
953 
954     retval = m_categories_map.GetValidator(valobj, use_dynamic, matches);
955     if (!retval)
956     {
957         if (log)
958             log->Printf("[FormatManager::GetValidator] Search failed. Giving language a chance.");
959         for (lldb::LanguageType lang_type : GetCandidateLanguages(valobj))
960         {
961             if (LanguageCategory* lang_category = GetCategoryForLanguage(lang_type))
962             {
963                 if (lang_category->Get(valobj, use_dynamic, matches, retval))
964                     break;
965             }
966         }
967         if (retval)
968         {
969             if (log)
970                 log->Printf("[FormatManager::GetValidator] Language search success. Returning.");
971             return retval;
972         }
973     }
974     if (!retval)
975     {
976         if (log)
977             log->Printf("[FormatManager::GetValidator] Search failed. Giving hardcoded a chance.");
978         retval = GetHardcodedValidator(valobj, use_dynamic);
979     }
980 
981     if (valobj_type && (!retval || !retval->NonCacheable()))
982     {
983         if (log)
984             log->Printf("[FormatManager::GetValidator] Caching %p for type %s",
985                         static_cast<void*>(retval.get()),
986                         valobj_type.AsCString("<invalid>"));
987         m_format_cache.SetValidator(valobj_type,retval);
988     }
989     if (log && log->GetDebug())
990         log->Printf("[FormatManager::GetValidator] Cache hits: %" PRIu64 " - Cache Misses: %" PRIu64, m_format_cache.GetCacheHits(), m_format_cache.GetCacheMisses());
991     return retval;
992 }
993 
994 lldb::TypeValidatorImplSP
995 FormatManager::GetHardcodedValidator (ValueObject& valobj,
996                                       lldb::DynamicValueType use_dynamic)
997 {
998     for (const auto& candidate: m_hardcoded_validators)
999     {
1000         auto result = candidate(valobj,use_dynamic,*this);
1001         if (result)
1002             return result;
1003     }
1004     return nullptr;
1005 }
1006 
1007 FormatManager::FormatManager() :
1008     m_format_cache(),
1009     m_named_summaries_map(this),
1010     m_last_revision(0),
1011     m_categories_map(this),
1012     m_language_categories_map(),
1013     m_language_categories_mutex(Mutex::eMutexTypeRecursive),
1014     m_default_category_name(ConstString("default")),
1015     m_system_category_name(ConstString("system")),
1016     m_vectortypes_category_name(ConstString("VectorTypes")),
1017     m_hardcoded_formats(),
1018     m_hardcoded_summaries(),
1019     m_hardcoded_synthetics(),
1020     m_hardcoded_validators()
1021 
1022 {
1023     LoadSystemFormatters();
1024     LoadVectorFormatters();
1025     LoadHardcodedFormatters();
1026 
1027     EnableCategory(m_vectortypes_category_name,TypeCategoryMap::Last);
1028     EnableCategory(m_system_category_name,TypeCategoryMap::Last);
1029 }
1030 
1031 void
1032 FormatManager::LoadSystemFormatters()
1033 {
1034 
1035     TypeSummaryImpl::Flags string_flags;
1036     string_flags.SetCascades(true)
1037     .SetSkipPointers(true)
1038     .SetSkipReferences(false)
1039     .SetDontShowChildren(true)
1040     .SetDontShowValue(false)
1041     .SetShowMembersOneLiner(false)
1042     .SetHideItemNames(false);
1043 
1044     TypeSummaryImpl::Flags string_array_flags;
1045     string_array_flags.SetCascades(true)
1046     .SetSkipPointers(true)
1047     .SetSkipReferences(false)
1048     .SetDontShowChildren(true)
1049     .SetDontShowValue(true)
1050     .SetShowMembersOneLiner(false)
1051     .SetHideItemNames(false);
1052 
1053     lldb::TypeSummaryImplSP string_format(new StringSummaryFormat(string_flags, "${var%s}"));
1054 
1055 
1056     lldb::TypeSummaryImplSP string_array_format(new StringSummaryFormat(string_array_flags,
1057                                                                         "${var%s}"));
1058 
1059     lldb::RegularExpressionSP any_size_char_arr(new RegularExpression("char \\[[0-9]+\\]"));
1060     lldb::RegularExpressionSP any_size_wchar_arr(new RegularExpression("wchar_t \\[[0-9]+\\]"));
1061 
1062     TypeCategoryImpl::SharedPointer sys_category_sp = GetCategory(m_system_category_name);
1063 
1064     sys_category_sp->GetTypeSummariesContainer()->Add(ConstString("char *"), string_format);
1065     sys_category_sp->GetTypeSummariesContainer()->Add(ConstString("unsigned char *"), string_format);
1066     sys_category_sp->GetRegexTypeSummariesContainer()->Add(any_size_char_arr, string_array_format);
1067 
1068     lldb::TypeSummaryImplSP ostype_summary(new StringSummaryFormat(TypeSummaryImpl::Flags().SetCascades(false)
1069                                                                    .SetSkipPointers(true)
1070                                                                    .SetSkipReferences(true)
1071                                                                    .SetDontShowChildren(true)
1072                                                                    .SetDontShowValue(false)
1073                                                                    .SetShowMembersOneLiner(false)
1074                                                                    .SetHideItemNames(false),
1075                                                                    "${var%O}"));
1076 
1077     sys_category_sp->GetTypeSummariesContainer()->Add(ConstString("OSType"), ostype_summary);
1078 
1079 #ifndef LLDB_DISABLE_PYTHON
1080     TypeFormatImpl::Flags fourchar_flags;
1081     fourchar_flags.SetCascades(true).SetSkipPointers(true).SetSkipReferences(true);
1082 
1083     AddFormat(sys_category_sp, lldb::eFormatOSType, ConstString("FourCharCode"), fourchar_flags);
1084 #endif
1085 }
1086 
1087 void
1088 FormatManager::LoadVectorFormatters()
1089 {
1090     TypeCategoryImpl::SharedPointer vectors_category_sp = GetCategory(m_vectortypes_category_name);
1091 
1092     TypeSummaryImpl::Flags vector_flags;
1093     vector_flags.SetCascades(true)
1094     .SetSkipPointers(true)
1095     .SetSkipReferences(false)
1096     .SetDontShowChildren(true)
1097     .SetDontShowValue(false)
1098     .SetShowMembersOneLiner(true)
1099     .SetHideItemNames(true);
1100 
1101     AddStringSummary(vectors_category_sp,
1102                      "${var.uint128}",
1103                      ConstString("builtin_type_vec128"),
1104                      vector_flags);
1105 
1106     AddStringSummary(vectors_category_sp,
1107                      "",
1108                      ConstString("float [4]"),
1109                      vector_flags);
1110     AddStringSummary(vectors_category_sp,
1111                      "",
1112                      ConstString("int32_t [4]"),
1113                      vector_flags);
1114     AddStringSummary(vectors_category_sp,
1115                      "",
1116                      ConstString("int16_t [8]"),
1117                      vector_flags);
1118     AddStringSummary(vectors_category_sp,
1119                      "",
1120                      ConstString("vDouble"),
1121                      vector_flags);
1122     AddStringSummary(vectors_category_sp,
1123                      "",
1124                      ConstString("vFloat"),
1125                      vector_flags);
1126     AddStringSummary(vectors_category_sp,
1127                      "",
1128                      ConstString("vSInt8"),
1129                      vector_flags);
1130     AddStringSummary(vectors_category_sp,
1131                      "",
1132                      ConstString("vSInt16"),
1133                      vector_flags);
1134     AddStringSummary(vectors_category_sp,
1135                      "",
1136                      ConstString("vSInt32"),
1137                      vector_flags);
1138     AddStringSummary(vectors_category_sp,
1139                      "",
1140                      ConstString("vUInt16"),
1141                      vector_flags);
1142     AddStringSummary(vectors_category_sp,
1143                      "",
1144                      ConstString("vUInt8"),
1145                      vector_flags);
1146     AddStringSummary(vectors_category_sp,
1147                      "",
1148                      ConstString("vUInt16"),
1149                      vector_flags);
1150     AddStringSummary(vectors_category_sp,
1151                      "",
1152                      ConstString("vUInt32"),
1153                      vector_flags);
1154     AddStringSummary(vectors_category_sp,
1155                      "",
1156                      ConstString("vBool32"),
1157                      vector_flags);
1158 }
1159 
1160 void
1161 FormatManager::LoadHardcodedFormatters()
1162 {
1163     {
1164         // insert code to load formats here
1165     }
1166     {
1167         // insert code to load summaries here
1168         m_hardcoded_summaries.push_back(
1169                                         [](lldb_private::ValueObject& valobj,
1170                                             lldb::DynamicValueType,
1171                                             FormatManager&) -> TypeSummaryImpl::SharedPointer {
1172                                             static CXXFunctionSummaryFormat::SharedPointer formatter_sp(new CXXFunctionSummaryFormat(TypeSummaryImpl::Flags(), lldb_private::formatters::CXXFunctionPointerSummaryProvider, "Function pointer summary provider"));
1173                                             if (valobj.GetCompilerType().IsFunctionPointerType())
1174                                             {
1175                                                 return formatter_sp;
1176                                             }
1177                                             return nullptr;
1178                                         });
1179         m_hardcoded_summaries.push_back(
1180                                          [](lldb_private::ValueObject& valobj,
1181                                             lldb::DynamicValueType,
1182                                             FormatManager& fmt_mgr) -> TypeSummaryImpl::SharedPointer {
1183                                              static CXXFunctionSummaryFormat::SharedPointer formatter_sp(new CXXFunctionSummaryFormat(TypeSummaryImpl::Flags()
1184                                                                                                                                       .SetCascades(true)
1185                                                                                                                                       .SetDontShowChildren(true)
1186                                                                                                                                       .SetHideItemNames(true)
1187                                                                                                                                       .SetShowMembersOneLiner(true)
1188                                                                                                                                       .SetSkipPointers(true)
1189                                                                                                                                       .SetSkipReferences(false),
1190                                                                                                                                       lldb_private::formatters::VectorTypeSummaryProvider,
1191                                                                                                                                       "vector_type pointer summary provider"));
1192                                              if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr))
1193                                              {
1194                                                  if (fmt_mgr.GetCategory(fmt_mgr.m_vectortypes_category_name)->IsEnabled())
1195                                                      return formatter_sp;
1196                                              }
1197                                              return nullptr;
1198                                          });
1199     }
1200     {
1201         // insert code to load synthetics here
1202         m_hardcoded_synthetics.push_back(
1203                                          [](lldb_private::ValueObject& valobj,
1204                                             lldb::DynamicValueType,
1205                                             FormatManager& fmt_mgr) -> SyntheticChildren::SharedPointer {
1206                                              static CXXSyntheticChildren::SharedPointer formatter_sp(new CXXSyntheticChildren(SyntheticChildren::Flags().SetCascades(true).SetSkipPointers(true).SetSkipReferences(true).SetNonCacheable(true),
1207                                                                                                                               "vector_type synthetic children",
1208                                                                                                                               lldb_private::formatters::VectorTypeSyntheticFrontEndCreator));
1209                                              if (valobj.GetCompilerType().IsVectorType(nullptr, nullptr))
1210                                              {
1211                                                  if (fmt_mgr.GetCategory(fmt_mgr.m_vectortypes_category_name)->IsEnabled())
1212                                                      return formatter_sp;
1213                                              }
1214                                              return nullptr;
1215                                          });
1216     }
1217     {
1218         // insert code to load validators here
1219     }
1220 }
1221