1 //===-- FormatNavigator.h ----------------------------------------*- 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 #ifndef lldb_FormatNavigator_h_
11 #define lldb_FormatNavigator_h_
12 
13 // C Includes
14 // C++ Includes
15 
16 // Other libraries and framework includes
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/Type.h"
19 #include "clang/AST/DeclObjC.h"
20 
21 // Project includes
22 #include "lldb/lldb-public.h"
23 
24 #include "lldb/Core/Log.h"
25 #include "lldb/Core/RegularExpression.h"
26 #include "lldb/Core/ValueObject.h"
27 
28 #include "lldb/DataFormatters/FormatClasses.h"
29 
30 #include "lldb/Symbol/ClangASTContext.h"
31 #include "lldb/Symbol/ClangASTType.h"
32 
33 #include "lldb/Target/ObjCLanguageRuntime.h"
34 #include "lldb/Target/Process.h"
35 #include "lldb/Target/StackFrame.h"
36 #include "lldb/Target/TargetList.h"
37 
38 namespace lldb_private {
39 
40 // this file (and its. cpp) contain the low-level implementation of LLDB Data Visualization
41 // class DataVisualization is the high-level front-end of this feature
42 // clients should refer to that class as the entry-point into the data formatters
43 // unless they have a good reason to bypass it and prefer to use this file's objects directly
44 class IFormatChangeListener
45 {
46 public:
47     virtual void
48     Changed () = 0;
49 
50     virtual
~IFormatChangeListener()51     ~IFormatChangeListener () {}
52 
53     virtual uint32_t
54     GetCurrentRevision () = 0;
55 
56 };
57 
58 static inline bool
IsWhitespace(char c)59 IsWhitespace (char c)
60 {
61     return ( (c == ' ') || (c == '\t') || (c == '\v') || (c == '\f') );
62 }
63 
64 static inline bool
HasPrefix(const char * str1,const char * str2)65 HasPrefix (const char* str1, const char* str2)
66 {
67     return ( ::strstr(str1, str2) == str1 );
68 }
69 
70 // if the user tries to add formatters for, say, "struct Foo"
71 // those will not match any type because of the way we strip qualifiers from typenames
72 // this method looks for the case where the user is adding a "class","struct","enum" or "union" Foo
73 // and strips the unnecessary qualifier
74 static inline ConstString
GetValidTypeName_Impl(const ConstString & type)75 GetValidTypeName_Impl (const ConstString& type)
76 {
77     int strip_len = 0;
78 
79     if (type == false)
80         return type;
81 
82     const char* type_cstr = type.AsCString();
83 
84     if ( HasPrefix(type_cstr, "class ") )
85         strip_len = 6;
86     else if ( HasPrefix(type_cstr, "enum ") )
87         strip_len = 5;
88     else if ( HasPrefix(type_cstr, "struct ") )
89         strip_len = 7;
90     else if ( HasPrefix(type_cstr, "union ") )
91         strip_len = 6;
92 
93     if (strip_len == 0)
94         return type;
95 
96     type_cstr += strip_len;
97     while (IsWhitespace(*type_cstr) && ++type_cstr)
98         ;
99 
100     return ConstString(type_cstr);
101 }
102 
103 template<typename KeyType, typename ValueType>
104 class FormatNavigator;
105 
106 template<typename KeyType, typename ValueType>
107 class FormatMap
108 {
109 public:
110 
111     typedef typename ValueType::SharedPointer ValueSP;
112     typedef std::map<KeyType, ValueSP> MapType;
113     typedef typename MapType::iterator MapIterator;
114     typedef bool(*CallbackType)(void*, KeyType, const ValueSP&);
115 
FormatMap(IFormatChangeListener * lst)116     FormatMap(IFormatChangeListener* lst) :
117     m_map(),
118     m_map_mutex(Mutex::eMutexTypeRecursive),
119     listener(lst)
120     {
121     }
122 
123     void
Add(KeyType name,const ValueSP & entry)124     Add(KeyType name,
125         const ValueSP& entry)
126     {
127         if (listener)
128             entry->GetRevision() = listener->GetCurrentRevision();
129         else
130             entry->GetRevision() = 0;
131 
132         Mutex::Locker locker(m_map_mutex);
133         m_map[name] = entry;
134         if (listener)
135             listener->Changed();
136     }
137 
138     bool
Delete(KeyType name)139     Delete (KeyType name)
140     {
141         Mutex::Locker locker(m_map_mutex);
142         MapIterator iter = m_map.find(name);
143         if (iter == m_map.end())
144             return false;
145         m_map.erase(name);
146         if (listener)
147             listener->Changed();
148         return true;
149     }
150 
151     void
Clear()152     Clear ()
153     {
154         Mutex::Locker locker(m_map_mutex);
155         m_map.clear();
156         if (listener)
157             listener->Changed();
158     }
159 
160     bool
Get(KeyType name,ValueSP & entry)161     Get(KeyType name,
162         ValueSP& entry)
163     {
164         Mutex::Locker locker(m_map_mutex);
165         MapIterator iter = m_map.find(name);
166         if (iter == m_map.end())
167             return false;
168         entry = iter->second;
169         return true;
170     }
171 
172     void
LoopThrough(CallbackType callback,void * param)173     LoopThrough (CallbackType callback, void* param)
174     {
175         if (callback)
176         {
177             Mutex::Locker locker(m_map_mutex);
178             MapIterator pos, end = m_map.end();
179             for (pos = m_map.begin(); pos != end; pos++)
180             {
181                 KeyType type = pos->first;
182                 if (!callback(param, type, pos->second))
183                     break;
184             }
185         }
186     }
187 
188     uint32_t
GetCount()189     GetCount ()
190     {
191         return m_map.size();
192     }
193 
194     ValueSP
GetValueAtIndex(size_t index)195     GetValueAtIndex (size_t index)
196     {
197         Mutex::Locker locker(m_map_mutex);
198         MapIterator iter = m_map.begin();
199         MapIterator end = m_map.end();
200         while (index > 0)
201         {
202             iter++;
203             index--;
204             if (end == iter)
205                 return ValueSP();
206         }
207         return iter->second;
208     }
209 
210     KeyType
GetKeyAtIndex(size_t index)211     GetKeyAtIndex (size_t index)
212     {
213         Mutex::Locker locker(m_map_mutex);
214         MapIterator iter = m_map.begin();
215         MapIterator end = m_map.end();
216         while (index > 0)
217         {
218             iter++;
219             index--;
220             if (end == iter)
221                 return KeyType();
222         }
223         return iter->first;
224     }
225 
226 protected:
227     MapType m_map;
228     Mutex m_map_mutex;
229     IFormatChangeListener* listener;
230 
231     MapType&
map()232     map ()
233     {
234         return m_map;
235     }
236 
237     Mutex&
mutex()238     mutex ()
239     {
240         return m_map_mutex;
241     }
242 
243     friend class FormatNavigator<KeyType, ValueType>;
244     friend class FormatManager;
245 
246 };
247 
248 template<typename KeyType, typename ValueType>
249 class FormatNavigator
250 {
251 protected:
252     typedef FormatMap<KeyType,ValueType> BackEndType;
253 
254 public:
255     typedef typename BackEndType::MapType MapType;
256     typedef typename MapType::iterator MapIterator;
257     typedef typename MapType::key_type MapKeyType;
258     typedef typename MapType::mapped_type MapValueType;
259     typedef typename BackEndType::CallbackType CallbackType;
260     typedef typename std::shared_ptr<FormatNavigator<KeyType, ValueType> > SharedPointer;
261 
262     friend class TypeCategoryImpl;
263 
FormatNavigator(std::string name,IFormatChangeListener * lst)264     FormatNavigator(std::string name,
265                     IFormatChangeListener* lst) :
266     m_format_map(lst),
267     m_name(name),
268     m_id_cs(ConstString("id"))
269     {
270     }
271 
272     void
Add(const MapKeyType & type,const MapValueType & entry)273     Add (const MapKeyType &type, const MapValueType& entry)
274     {
275         Add_Impl(type, entry, (KeyType*)NULL);
276     }
277 
278     bool
Delete(ConstString type)279     Delete (ConstString type)
280     {
281         return Delete_Impl(type, (KeyType*)NULL);
282     }
283 
284     bool
285     Get(ValueObject& valobj,
286         MapValueType& entry,
287         lldb::DynamicValueType use_dynamic,
288         uint32_t* why = NULL)
289     {
290         uint32_t value = lldb_private::eFormatterChoiceCriterionDirectChoice;
291         ClangASTType ast_type(valobj.GetClangType());
292         bool ret = Get(valobj, ast_type, entry, use_dynamic, value);
293         if (ret)
294             entry = MapValueType(entry);
295         else
296             entry = MapValueType();
297         if (why)
298             *why = value;
299         return ret;
300     }
301 
302     bool
Get(ConstString type,MapValueType & entry)303     Get (ConstString type, MapValueType& entry)
304     {
305         return Get_Impl(type, entry, (KeyType*)NULL);
306     }
307 
308     bool
GetExact(ConstString type,MapValueType & entry)309     GetExact (ConstString type, MapValueType& entry)
310     {
311         return GetExact_Impl(type, entry, (KeyType*)NULL);
312     }
313 
314     MapValueType
GetAtIndex(size_t index)315     GetAtIndex (size_t index)
316     {
317         return m_format_map.GetValueAtIndex(index);
318     }
319 
320     lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierAtIndex(size_t index)321     GetTypeNameSpecifierAtIndex (size_t index)
322     {
323         return GetTypeNameSpecifierAtIndex_Impl(index, (KeyType*)NULL);
324     }
325 
326     void
Clear()327     Clear ()
328     {
329         m_format_map.Clear();
330     }
331 
332     void
LoopThrough(CallbackType callback,void * param)333     LoopThrough (CallbackType callback, void* param)
334     {
335         m_format_map.LoopThrough(callback,param);
336     }
337 
338     uint32_t
GetCount()339     GetCount ()
340     {
341         return m_format_map.GetCount();
342     }
343 
344 protected:
345 
346     BackEndType m_format_map;
347 
348     std::string m_name;
349 
350     DISALLOW_COPY_AND_ASSIGN(FormatNavigator);
351 
352     ConstString m_id_cs;
353 
354     void
Add_Impl(const MapKeyType & type,const MapValueType & entry,lldb::RegularExpressionSP * dummy)355     Add_Impl (const MapKeyType &type, const MapValueType& entry, lldb::RegularExpressionSP *dummy)
356     {
357        m_format_map.Add(type,entry);
358     }
359 
Add_Impl(const ConstString & type,const MapValueType & entry,ConstString * dummy)360     void Add_Impl (const ConstString &type, const MapValueType& entry, ConstString *dummy)
361     {
362        m_format_map.Add(GetValidTypeName_Impl(type), entry);
363     }
364 
365     bool
Delete_Impl(ConstString type,ConstString * dummy)366     Delete_Impl (ConstString type, ConstString *dummy)
367     {
368        return m_format_map.Delete(type);
369     }
370 
371     bool
Delete_Impl(ConstString type,lldb::RegularExpressionSP * dummy)372     Delete_Impl (ConstString type, lldb::RegularExpressionSP *dummy)
373     {
374        Mutex& x_mutex = m_format_map.mutex();
375         lldb_private::Mutex::Locker locker(x_mutex);
376        MapIterator pos, end = m_format_map.map().end();
377        for (pos = m_format_map.map().begin(); pos != end; pos++)
378        {
379            lldb::RegularExpressionSP regex = pos->first;
380            if ( ::strcmp(type.AsCString(),regex->GetText()) == 0)
381            {
382                m_format_map.map().erase(pos);
383                if (m_format_map.listener)
384                    m_format_map.listener->Changed();
385                return true;
386            }
387        }
388        return false;
389     }
390 
391     bool
Get_Impl(ConstString type,MapValueType & entry,ConstString * dummy)392     Get_Impl (ConstString type, MapValueType& entry, ConstString *dummy)
393     {
394        return m_format_map.Get(type, entry);
395     }
396 
397     bool
GetExact_Impl(ConstString type,MapValueType & entry,ConstString * dummy)398     GetExact_Impl (ConstString type, MapValueType& entry, ConstString *dummy)
399     {
400         return Get_Impl(type,entry, (KeyType*)0);
401     }
402 
403     lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierAtIndex_Impl(size_t index,ConstString * dummy)404     GetTypeNameSpecifierAtIndex_Impl (size_t index, ConstString *dummy)
405     {
406         ConstString key = m_format_map.GetKeyAtIndex(index);
407         if (key)
408             return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(key.AsCString(),
409                                                                            false));
410         else
411             return lldb::TypeNameSpecifierImplSP();
412     }
413 
414     lldb::TypeNameSpecifierImplSP
GetTypeNameSpecifierAtIndex_Impl(size_t index,lldb::RegularExpressionSP * dummy)415     GetTypeNameSpecifierAtIndex_Impl (size_t index, lldb::RegularExpressionSP *dummy)
416     {
417         lldb::RegularExpressionSP regex = m_format_map.GetKeyAtIndex(index);
418         if (regex.get() == NULL)
419             return lldb::TypeNameSpecifierImplSP();
420         return lldb::TypeNameSpecifierImplSP(new TypeNameSpecifierImpl(regex->GetText(),
421                                                                        true));
422     }
423 
424     bool
Get_Impl(ConstString key,MapValueType & value,lldb::RegularExpressionSP * dummy)425     Get_Impl (ConstString key, MapValueType& value, lldb::RegularExpressionSP *dummy)
426     {
427        const char* key_cstr = key.AsCString();
428        if (!key_cstr)
429            return false;
430        Mutex& x_mutex = m_format_map.mutex();
431        lldb_private::Mutex::Locker locker(x_mutex);
432        MapIterator pos, end = m_format_map.map().end();
433        for (pos = m_format_map.map().begin(); pos != end; pos++)
434        {
435            lldb::RegularExpressionSP regex = pos->first;
436            if (regex->Execute(key_cstr))
437            {
438                value = pos->second;
439                return true;
440            }
441        }
442        return false;
443     }
444 
445     bool
GetExact_Impl(ConstString key,MapValueType & value,lldb::RegularExpressionSP * dummy)446     GetExact_Impl (ConstString key, MapValueType& value, lldb::RegularExpressionSP *dummy)
447     {
448         Mutex& x_mutex = m_format_map.mutex();
449         lldb_private::Mutex::Locker locker(x_mutex);
450         MapIterator pos, end = m_format_map.map().end();
451         for (pos = m_format_map.map().begin(); pos != end; pos++)
452         {
453             lldb::RegularExpressionSP regex = pos->first;
454             if (strcmp(regex->GetText(),key.AsCString()) == 0)
455             {
456                 value = pos->second;
457                 return true;
458             }
459         }
460         return false;
461     }
462 
463     bool
Get_BitfieldMatch(ValueObject & valobj,ConstString typeName,MapValueType & entry,uint32_t & reason)464     Get_BitfieldMatch (ValueObject& valobj,
465                        ConstString typeName,
466                        MapValueType& entry,
467                        uint32_t& reason)
468     {
469         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
470         // for bitfields, append size to the typename so one can custom format them
471         StreamString sstring;
472         sstring.Printf("%s:%d",typeName.AsCString(),valobj.GetBitfieldBitSize());
473         ConstString bitfieldname = ConstString(sstring.GetData());
474         if (log)
475             log->Printf("[Get_BitfieldMatch] appended bitfield info, final result is %s", bitfieldname.GetCString());
476         if (Get(bitfieldname, entry))
477         {
478             if (log)
479                 log->Printf("[Get_BitfieldMatch] bitfield direct match found, returning");
480             return true;
481         }
482         else
483         {
484             reason |= lldb_private::eFormatterChoiceCriterionStrippedBitField;
485             if (log)
486                 log->Printf("[Get_BitfieldMatch] no bitfield direct match");
487             return false;
488         }
489     }
490 
Get_ObjC(ValueObject & valobj,MapValueType & entry)491     bool Get_ObjC (ValueObject& valobj,
492                    MapValueType& entry)
493     {
494         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
495         lldb::ProcessSP process_sp = valobj.GetProcessSP();
496         ObjCLanguageRuntime* runtime = process_sp->GetObjCLanguageRuntime();
497         if (runtime == NULL)
498         {
499             if (log)
500                 log->Printf("[Get_ObjC] no valid ObjC runtime, skipping dynamic");
501             return false;
502         }
503         ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (runtime->GetClassDescriptor(valobj));
504         if (!objc_class_sp)
505         {
506             if (log)
507                 log->Printf("[Get_ObjC] invalid ISA, skipping dynamic");
508             return false;
509         }
510         ConstString name (objc_class_sp->GetClassName());
511         if (log)
512             log->Printf("[Get_ObjC] dynamic type inferred is %s - looking for direct dynamic match", name.GetCString());
513         if (Get(name, entry))
514         {
515             if (log)
516                 log->Printf("[Get_ObjC] direct dynamic match found, returning");
517             return true;
518         }
519         if (log)
520             log->Printf("[Get_ObjC] no dynamic match");
521         return false;
522     }
523 
524     bool
Get_Impl(ValueObject & valobj,ClangASTType clang_type,MapValueType & entry,lldb::DynamicValueType use_dynamic,uint32_t & reason)525     Get_Impl (ValueObject& valobj,
526               ClangASTType clang_type,
527               MapValueType& entry,
528               lldb::DynamicValueType use_dynamic,
529               uint32_t& reason)
530     {
531         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
532 
533         if (!clang_type.IsValid())
534         {
535             if (log)
536                 log->Printf("[Get_Impl] type is invalid, returning");
537             return false;
538         }
539 
540         clang_type = clang_type.RemoveFastQualifiers();
541 
542         ConstString typeName(clang_type.GetConstTypeName());
543 
544         if (valobj.GetBitfieldBitSize() > 0)
545         {
546             if (Get_BitfieldMatch(valobj, typeName, entry, reason))
547                 return true;
548         }
549 
550         if (log)
551             log->Printf("[Get_Impl] trying to get %s for VO name %s of type %s",
552                         m_name.c_str(),
553                         valobj.GetName().AsCString(),
554                         typeName.AsCString());
555 
556         if (Get(typeName, entry))
557         {
558             if (log)
559                 log->Printf("[Get] direct match found, returning");
560             return true;
561         }
562         if (log)
563             log->Printf("[Get_Impl] no direct match");
564 
565         // strip pointers and references and see if that helps
566         if (clang_type.IsReferenceType())
567         {
568             if (log)
569                 log->Printf("[Get_Impl] stripping reference");
570             if (Get_Impl(valobj, clang_type.GetNonReferenceType(), entry, use_dynamic, reason) && !entry->SkipsReferences())
571             {
572                 reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
573                 return true;
574             }
575         }
576         else if (clang_type.IsPointerType())
577         {
578             if (log)
579                 log->Printf("[Get_Impl] stripping pointer");
580             if (Get_Impl(valobj, clang_type.GetPointeeType(), entry, use_dynamic, reason) && !entry->SkipsPointers())
581             {
582                 reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
583                 return true;
584             }
585         }
586 
587         bool canBeObjCDynamic = valobj.GetClangType().IsPossibleDynamicType (NULL,
588                                                                              false, // no C++
589                                                                              true); // yes ObjC
590 
591         if (canBeObjCDynamic)
592         {
593             if (use_dynamic != lldb::eNoDynamicValues)
594             {
595                 if (log)
596                     log->Printf("[Get_Impl] allowed to figure out dynamic ObjC type");
597                 if (Get_ObjC(valobj,entry))
598                 {
599                     reason |= lldb_private::eFormatterChoiceCriterionDynamicObjCDiscovery;
600                     return true;
601                 }
602             }
603             if (log)
604                 log->Printf("[Get_Impl] dynamic disabled or failed - stripping ObjC pointer");
605             if (Get_Impl(valobj, clang_type.GetPointeeType(), entry, use_dynamic, reason) && !entry->SkipsPointers())
606             {
607                 reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
608                 return true;
609             }
610         }
611 
612         // try to strip typedef chains
613         if (clang_type.IsTypedefType())
614         {
615             if (log)
616                 log->Printf("[Get_Impl] stripping typedef");
617             if ((Get_Impl(valobj, clang_type.GetTypedefedType(), entry, use_dynamic, reason)) && entry->Cascades())
618             {
619                 reason |= lldb_private::eFormatterChoiceCriterionNavigatedTypedefs;
620                 return true;
621             }
622         }
623 
624         // out of luck here
625         return false;
626     }
627 
628     // we are separately passing in valobj and type because the valobj is fixed (and is used for ObjC discovery and bitfield size)
629     // but the type can change (e.g. stripping pointers, ...)
Get(ValueObject & valobj,ClangASTType clang_type,MapValueType & entry,lldb::DynamicValueType use_dynamic,uint32_t & reason)630     bool Get (ValueObject& valobj,
631               ClangASTType clang_type,
632               MapValueType& entry,
633               lldb::DynamicValueType use_dynamic,
634               uint32_t& reason)
635     {
636         Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
637 
638         if (Get_Impl (valobj, clang_type, entry, use_dynamic, reason))
639             return true;
640 
641         // try going to the unqualified type
642         do {
643             if (log)
644                 log->Printf("[Get] trying the unqualified type");
645             if (!clang_type.IsValid())
646                 break;
647 
648             ClangASTType unqual_clang_ast_type = clang_type.GetFullyUnqualifiedType();
649             if (!unqual_clang_ast_type.IsValid())
650             {
651                 if (log)
652                     log->Printf("[Get] could not get the unqual_clang_ast_type");
653                 break;
654             }
655             if (unqual_clang_ast_type.GetOpaqueQualType() != clang_type.GetOpaqueQualType())
656             {
657                 if (log)
658                     log->Printf("[Get] unqualified type is there and is not the same, let's try");
659                 if (Get_Impl (valobj, unqual_clang_ast_type,entry, use_dynamic, reason))
660                     return true;
661             }
662             else if (log)
663                 log->Printf("[Get] unqualified type same as original type");
664         } while(false);
665 
666         // if all else fails, go to static type
667         if (valobj.IsDynamic())
668         {
669             if (log)
670                 log->Printf("[Get] going to static value");
671             lldb::ValueObjectSP static_value_sp(valobj.GetStaticValue());
672             if (static_value_sp)
673             {
674                 if (log)
675                     log->Printf("[Get] has a static value - actually use it");
676                 if (Get(*static_value_sp.get(), static_value_sp->GetClangType(), entry, use_dynamic, reason))
677                 {
678                     reason |= lldb_private::eFormatterChoiceCriterionWentToStaticValue;
679                     return true;
680                 }
681             }
682         }
683 
684         return false;
685     }
686 };
687 
688 } // namespace lldb_private
689 
690 #endif	// lldb_FormatNavigator_h_
691