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