FormatNavigator.h revision b6a4c565732b3a7b546ba2aa0e7aec3a4bb359a4
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
38namespace 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
44class IFormatChangeListener
45{
46public:
47    virtual void
48    Changed () = 0;
49
50    virtual
51    ~IFormatChangeListener () {}
52
53    virtual uint32_t
54    GetCurrentRevision () = 0;
55
56};
57
58static inline bool
59IsWhitespace (char c)
60{
61    return ( (c == ' ') || (c == '\t') || (c == '\v') || (c == '\f') );
62}
63
64static inline bool
65HasPrefix (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
74static ConstString
75GetValidTypeName_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
103template<typename KeyType, typename ValueType>
104class FormatNavigator;
105
106template<typename KeyType, typename ValueType>
107class FormatMap
108{
109public:
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
116    FormatMap(IFormatChangeListener* lst) :
117    m_map(),
118    m_map_mutex(Mutex::eMutexTypeRecursive),
119    listener(lst)
120    {
121    }
122
123    void
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
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
152    Clear ()
153    {
154        Mutex::Locker locker(m_map_mutex);
155        m_map.clear();
156        if (listener)
157            listener->Changed();
158    }
159
160    bool
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
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
189    GetCount ()
190    {
191        return m_map.size();
192    }
193
194    ValueSP
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
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
226protected:
227    MapType m_map;
228    Mutex m_map_mutex;
229    IFormatChangeListener* listener;
230
231    MapType&
232    map ()
233    {
234        return m_map;
235    }
236
237    Mutex&
238    mutex ()
239    {
240        return m_map_mutex;
241    }
242
243    friend class FormatNavigator<KeyType, ValueType>;
244    friend class FormatManager;
245
246};
247
248template<typename KeyType, typename ValueType>
249class FormatNavigator
250{
251protected:
252    typedef FormatMap<KeyType,ValueType> BackEndType;
253
254public:
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
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
273    Add (const MapKeyType &type, const MapValueType& entry)
274    {
275        Add_Impl(type, entry, (KeyType*)NULL);
276    }
277
278    bool
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        clang::QualType type = clang::QualType::getFromOpaquePtr(valobj.GetClangType());
292        bool ret = Get(valobj, 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
303    Get (ConstString type, MapValueType& entry)
304    {
305        return Get_Impl(type, entry, (KeyType*)NULL);
306    }
307
308    bool
309    GetExact (ConstString type, MapValueType& entry)
310    {
311        return GetExact_Impl(type, entry, (KeyType*)NULL);
312    }
313
314    MapValueType
315    GetAtIndex (size_t index)
316    {
317        return m_format_map.GetValueAtIndex(index);
318    }
319
320    lldb::TypeNameSpecifierImplSP
321    GetTypeNameSpecifierAtIndex (size_t index)
322    {
323        return GetTypeNameSpecifierAtIndex_Impl(index, (KeyType*)NULL);
324    }
325
326    void
327    Clear ()
328    {
329        m_format_map.Clear();
330    }
331
332    void
333    LoopThrough (CallbackType callback, void* param)
334    {
335        m_format_map.LoopThrough(callback,param);
336    }
337
338    uint32_t
339    GetCount ()
340    {
341        return m_format_map.GetCount();
342    }
343
344protected:
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
355    Add_Impl (const MapKeyType &type, const MapValueType& entry, lldb::RegularExpressionSP *dummy)
356    {
357       m_format_map.Add(type,entry);
358    }
359
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
366    Delete_Impl (ConstString type, ConstString *dummy)
367    {
368       return m_format_map.Delete(type);
369    }
370
371    bool
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
392    Get_Impl (ConstString type, MapValueType& entry, ConstString *dummy)
393    {
394       return m_format_map.Get(type, entry);
395    }
396
397    bool
398    GetExact_Impl (ConstString type, MapValueType& entry, ConstString *dummy)
399    {
400        return Get_Impl(type,entry, (KeyType*)0);
401    }
402
403    lldb::TypeNameSpecifierImplSP
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
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
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
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
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
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
525    Get_Impl (ValueObject& valobj,
526              clang::QualType 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 (type.isNull())
534        {
535            if (log)
536                log->Printf("[Get_Impl] type is NULL, returning");
537            return false;
538        }
539
540        type.removeLocalConst(); type.removeLocalVolatile(); type.removeLocalRestrict();
541        const clang::Type* typePtr = type.getTypePtrOrNull();
542        if (!typePtr)
543        {
544            if (log)
545                log->Printf("[Get_Impl] type is NULL, returning");
546            return false;
547        }
548        ConstString typeName(ClangASTType::GetTypeNameForQualType(valobj.GetClangAST(), type).c_str());
549
550        if (valobj.GetBitfieldBitSize() > 0)
551        {
552            if (Get_BitfieldMatch(valobj, typeName, entry, reason))
553                return true;
554        }
555
556        if (log)
557            log->Printf("[Get_Impl] trying to get %s for VO name %s of type %s",
558                        m_name.c_str(),
559                        valobj.GetName().AsCString(),
560                        typeName.AsCString());
561
562        if (Get(typeName, entry))
563        {
564            if (log)
565                log->Printf("[Get] direct match found, returning");
566            return true;
567        }
568        if (log)
569            log->Printf("[Get_Impl] no direct match");
570
571        // strip pointers and references and see if that helps
572        if (typePtr->isReferenceType())
573        {
574            if (log)
575                log->Printf("[Get_Impl] stripping reference");
576            if (Get_Impl(valobj,type.getNonReferenceType(),entry, use_dynamic, reason) && !entry->SkipsReferences())
577            {
578                reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
579                return true;
580            }
581        }
582        else if (typePtr->isPointerType())
583        {
584            if (log)
585                log->Printf("[Get_Impl] stripping pointer");
586            clang::QualType pointee = typePtr->getPointeeType();
587            if (Get_Impl(valobj, pointee, entry, use_dynamic, reason) && !entry->SkipsPointers())
588            {
589                reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
590                return true;
591            }
592        }
593
594        bool canBeObjCDynamic = ClangASTContext::IsPossibleDynamicType (valobj.GetClangAST(),
595                                                                        type.getAsOpaquePtr(),
596                                                                        NULL,
597                                                                        false, // no C++
598                                                                        true); // yes ObjC
599
600        if (canBeObjCDynamic)
601        {
602            if (use_dynamic != lldb::eNoDynamicValues)
603            {
604                if (log)
605                    log->Printf("[Get_Impl] allowed to figure out dynamic ObjC type");
606                if (Get_ObjC(valobj,entry))
607                {
608                    reason |= lldb_private::eFormatterChoiceCriterionDynamicObjCDiscovery;
609                    return true;
610                }
611            }
612            if (log)
613                log->Printf("[Get_Impl] dynamic disabled or failed - stripping ObjC pointer");
614            clang::QualType pointee = typePtr->getPointeeType();
615            if (Get_Impl(valobj, pointee, entry, use_dynamic, reason) && !entry->SkipsPointers())
616            {
617                reason |= lldb_private::eFormatterChoiceCriterionStrippedPointerReference;
618                return true;
619            }
620        }
621
622        // try to strip typedef chains
623        const clang::TypedefType* type_tdef = type->getAs<clang::TypedefType>();
624        if (type_tdef)
625        {
626            if (log)
627                log->Printf("[Get_Impl] stripping typedef");
628            if ((Get_Impl(valobj, type_tdef->getDecl()->getUnderlyingType(), entry, use_dynamic, reason)) && entry->Cascades())
629            {
630                reason |= lldb_private::eFormatterChoiceCriterionNavigatedTypedefs;
631                return true;
632            }
633        }
634
635        // out of luck here
636        return false;
637    }
638
639    // we are separately passing in valobj and type because the valobj is fixed (and is used for ObjC discovery and bitfield size)
640    // but the type can change (e.g. stripping pointers, ...)
641    bool Get (ValueObject& valobj,
642              clang::QualType type,
643              MapValueType& entry,
644              lldb::DynamicValueType use_dynamic,
645              uint32_t& reason)
646    {
647        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
648
649        if (Get_Impl (valobj,type,entry,use_dynamic,reason))
650            return true;
651
652        // try going to the unqualified type
653        do {
654            if (log)
655                log->Printf("[Get] trying the unqualified type");
656            lldb::clang_type_t opaque_type = type.getAsOpaquePtr();
657            if (!opaque_type)
658            {
659                if (log)
660                    log->Printf("[Get] could not get the opaque_type");
661                break;
662            }
663            ClangASTType unqual_clang_ast_type = ClangASTType::GetFullyUnqualifiedType(valobj.GetClangAST(),opaque_type);
664            if (!unqual_clang_ast_type.IsValid())
665            {
666                if (log)
667                    log->Printf("[Get] could not get the unqual_clang_ast_type");
668                break;
669            }
670            clang::QualType unqualified_qual_type = clang::QualType::getFromOpaquePtr(unqual_clang_ast_type.GetOpaqueQualType());
671            if (unqualified_qual_type.getTypePtrOrNull() != type.getTypePtrOrNull())
672            {
673                if (log)
674                    log->Printf("[Get] unqualified type is there and is not the same, let's try");
675                if (Get_Impl (valobj,unqualified_qual_type,entry,use_dynamic,reason))
676                    return true;
677            }
678            else if (log)
679                log->Printf("[Get] unqualified type same as original type");
680        } while(false);
681
682        // if all else fails, go to static type
683        if (valobj.IsDynamic())
684        {
685            if (log)
686                log->Printf("[Get] going to static value");
687            lldb::ValueObjectSP static_value_sp(valobj.GetStaticValue());
688            if (static_value_sp)
689            {
690                if (log)
691                    log->Printf("[Get] has a static value - actually use it");
692                if (Get(*static_value_sp.get(), clang::QualType::getFromOpaquePtr(static_value_sp->GetClangType()) , entry, use_dynamic, reason))
693                {
694                    reason |= lldb_private::eFormatterChoiceCriterionWentToStaticValue;
695                    return true;
696                }
697            }
698        }
699
700        return false;
701    }
702};
703
704} // namespace lldb_private
705
706#endif	// lldb_FormatNavigator_h_
707