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