1//===-- ObjCLanguageRuntime.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 liblldb_ObjCLanguageRuntime_h_
11#define liblldb_ObjCLanguageRuntime_h_
12
13// C Includes
14// C++ Includes
15#include <functional>
16#include <map>
17#include <memory>
18#include <unordered_set>
19
20// Other libraries and framework includes
21#include "llvm/Support/Casting.h"
22
23// Project includes
24#include "lldb/lldb-private.h"
25#include "lldb/Core/PluginInterface.h"
26#include "lldb/Core/ThreadSafeDenseMap.h"
27#include "lldb/Symbol/CompilerType.h"
28#include "lldb/Symbol/DeclVendor.h"
29#include "lldb/Symbol/Type.h"
30#include "lldb/Target/LanguageRuntime.h"
31
32class CommandObjectObjC_ClassTable_Dump;
33
34namespace lldb_private {
35
36class UtilityFunction;
37
38class ObjCLanguageRuntime :
39    public LanguageRuntime
40{
41public:
42    enum class ObjCRuntimeVersions
43    {
44        eObjC_VersionUnknown = 0,
45        eAppleObjC_V1 = 1,
46        eAppleObjC_V2 = 2
47    };
48
49    typedef lldb::addr_t ObjCISA;
50
51    class ClassDescriptor;
52    typedef std::shared_ptr<ClassDescriptor> ClassDescriptorSP;
53
54    // the information that we want to support retrieving from an ObjC class
55    // this needs to be pure virtual since there are at least 2 different implementations
56    // of the runtime, and more might come
57    class ClassDescriptor
58    {
59    public:
60        ClassDescriptor() :
61            m_is_kvo (eLazyBoolCalculate),
62            m_is_cf (eLazyBoolCalculate),
63            m_type_wp ()
64        {
65        }
66
67        virtual
68        ~ClassDescriptor() = default;
69
70        virtual ConstString
71        GetClassName () = 0;
72
73        virtual ClassDescriptorSP
74        GetSuperclass () = 0;
75
76        virtual ClassDescriptorSP
77        GetMetaclass () const = 0;
78
79        // virtual if any implementation has some other version-specific rules
80        // but for the known v1/v2 this is all that needs to be done
81        virtual bool
82        IsKVO ()
83        {
84            if (m_is_kvo == eLazyBoolCalculate)
85            {
86                const char* class_name = GetClassName().AsCString();
87                if (class_name && *class_name)
88                    m_is_kvo = (LazyBool)(strstr(class_name,"NSKVONotifying_") == class_name);
89            }
90            return (m_is_kvo == eLazyBoolYes);
91        }
92
93        // virtual if any implementation has some other version-specific rules
94        // but for the known v1/v2 this is all that needs to be done
95        virtual bool
96        IsCFType ()
97        {
98            if (m_is_cf == eLazyBoolCalculate)
99            {
100                const char* class_name = GetClassName().AsCString();
101                if (class_name && *class_name)
102                    m_is_cf = (LazyBool)(strcmp(class_name,"__NSCFType") == 0 ||
103                                         strcmp(class_name,"NSCFType") == 0);
104            }
105            return (m_is_cf == eLazyBoolYes);
106        }
107
108        virtual bool
109        IsValid () = 0;
110
111        virtual bool
112        GetTaggedPointerInfo(uint64_t* info_bits = nullptr,
113                             uint64_t* value_bits = nullptr,
114                             uint64_t* payload = nullptr) = 0;
115
116        virtual uint64_t
117        GetInstanceSize () = 0;
118
119        // use to implement version-specific additional constraints on pointers
120        virtual bool
121        CheckPointer (lldb::addr_t value,
122                      uint32_t ptr_size) const
123        {
124            return true;
125        }
126
127        virtual ObjCISA
128        GetISA () = 0;
129
130        // This should return true iff the interface could be completed
131        virtual bool
132        Describe (std::function <void (ObjCISA)> const &superclass_func,
133                  std::function <bool (const char*, const char*)> const &instance_method_func,
134                  std::function <bool (const char*, const char*)> const &class_method_func,
135                  std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func) const
136        {
137            return false;
138        }
139
140        lldb::TypeSP
141        GetType ()
142        {
143            return m_type_wp.lock();
144        }
145
146        void
147        SetType (const lldb::TypeSP &type_sp)
148        {
149            m_type_wp = type_sp;
150        }
151
152        struct iVarDescriptor {
153            ConstString m_name;
154            CompilerType m_type;
155            uint64_t m_size;
156            int32_t m_offset;
157        };
158
159        virtual size_t
160        GetNumIVars ()
161        {
162            return 0;
163        }
164
165        virtual iVarDescriptor
166        GetIVarAtIndex (size_t idx)
167        {
168            return iVarDescriptor();
169        }
170
171    protected:
172        bool
173        IsPointerValid (lldb::addr_t value,
174                        uint32_t ptr_size,
175                        bool allow_NULLs = false,
176                        bool allow_tagged = false,
177                        bool check_version_specific = false) const;
178
179    private:
180        LazyBool m_is_kvo;
181        LazyBool m_is_cf;
182        lldb::TypeWP m_type_wp;
183    };
184
185    class EncodingToType
186    {
187    public:
188        virtual ~EncodingToType();
189
190        virtual CompilerType RealizeType (ClangASTContext& ast_ctx, const char* name, bool for_expression);
191        virtual CompilerType RealizeType (const char* name, bool for_expression);
192
193        virtual CompilerType RealizeType (clang::ASTContext& ast_ctx, const char* name, bool for_expression) = 0;
194
195    protected:
196        std::unique_ptr<ClangASTContext> m_scratch_ast_ctx_ap;
197    };
198
199    class ObjCExceptionPrecondition : public Breakpoint::BreakpointPrecondition
200    {
201    public:
202        ObjCExceptionPrecondition();
203
204        ~ObjCExceptionPrecondition() override = default;
205
206        bool EvaluatePrecondition(StoppointCallbackContext &context) override;
207        void GetDescription(Stream &stream, lldb::DescriptionLevel level) override;
208        Error ConfigurePrecondition(Args &args) override;
209
210    protected:
211        void AddClassName(const char *class_name);
212
213    private:
214        std::unordered_set<std::string> m_class_names;
215    };
216
217    class TaggedPointerVendor
218    {
219    public:
220        virtual
221        ~TaggedPointerVendor() = default;
222
223        virtual bool
224        IsPossibleTaggedPointer (lldb::addr_t ptr) = 0;
225
226        virtual ObjCLanguageRuntime::ClassDescriptorSP
227        GetClassDescriptor (lldb::addr_t ptr) = 0;
228
229    protected:
230        TaggedPointerVendor() = default;
231
232    private:
233        DISALLOW_COPY_AND_ASSIGN(TaggedPointerVendor);
234    };
235
236    ~ObjCLanguageRuntime() override;
237
238    virtual TaggedPointerVendor*
239    GetTaggedPointerVendor ()
240    {
241        return nullptr;
242    }
243
244    typedef std::shared_ptr<EncodingToType> EncodingToTypeSP;
245
246    virtual EncodingToTypeSP
247    GetEncodingToType ();
248
249    virtual ClassDescriptorSP
250    GetClassDescriptor (ValueObject& in_value);
251
252    ClassDescriptorSP
253    GetNonKVOClassDescriptor (ValueObject& in_value);
254
255    virtual ClassDescriptorSP
256    GetClassDescriptorFromClassName (const ConstString &class_name);
257
258    virtual ClassDescriptorSP
259    GetClassDescriptorFromISA (ObjCISA isa);
260
261    ClassDescriptorSP
262    GetNonKVOClassDescriptor (ObjCISA isa);
263
264    lldb::LanguageType
265    GetLanguageType () const override
266    {
267        return lldb::eLanguageTypeObjC;
268    }
269
270    virtual bool
271    IsModuleObjCLibrary (const lldb::ModuleSP &module_sp) = 0;
272
273    virtual bool
274    ReadObjCLibrary (const lldb::ModuleSP &module_sp) = 0;
275
276    virtual bool
277    HasReadObjCLibrary () = 0;
278
279    virtual lldb::ThreadPlanSP
280    GetStepThroughTrampolinePlan (Thread &thread, bool stop_others) = 0;
281
282    lldb::addr_t
283    LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t sel);
284
285    void
286    AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t sel, lldb::addr_t impl_addr);
287
288    TypeAndOrName
289    LookupInClassNameCache (lldb::addr_t class_addr);
290
291    void
292    AddToClassNameCache (lldb::addr_t class_addr, const char *name, lldb::TypeSP type_sp);
293
294    void
295    AddToClassNameCache (lldb::addr_t class_addr, const TypeAndOrName &class_or_type_name);
296
297    lldb::TypeSP
298    LookupInCompleteClassCache (ConstString &name);
299
300    virtual UtilityFunction *
301    CreateObjectChecker (const char *) = 0;
302
303    virtual ObjCRuntimeVersions
304    GetRuntimeVersion () const
305    {
306        return ObjCRuntimeVersions::eObjC_VersionUnknown;
307    }
308
309    bool
310    IsValidISA(ObjCISA isa)
311    {
312        UpdateISAToDescriptorMap();
313        return m_isa_to_descriptor.count(isa) > 0;
314    }
315
316    virtual void
317    UpdateISAToDescriptorMapIfNeeded() = 0;
318
319    void
320    UpdateISAToDescriptorMap()
321    {
322        if (m_process && m_process->GetStopID() != m_isa_to_descriptor_stop_id)
323        {
324            UpdateISAToDescriptorMapIfNeeded ();
325        }
326    }
327
328    virtual ObjCISA
329    GetISA(const ConstString &name);
330
331    virtual ConstString
332    GetActualTypeName(ObjCISA isa);
333
334    virtual ObjCISA
335    GetParentClass(ObjCISA isa);
336
337    virtual DeclVendor *
338    GetDeclVendor()
339    {
340        return nullptr;
341    }
342
343    // Finds the byte offset of the child_type ivar in parent_type.  If it can't find the
344    // offset, returns LLDB_INVALID_IVAR_OFFSET.
345
346    virtual size_t
347    GetByteOffsetForIvar (CompilerType &parent_qual_type, const char *ivar_name);
348
349    // Given the name of an Objective-C runtime symbol (e.g., ivar offset symbol),
350    // try to determine from the runtime what the value of that symbol would be.
351    // Useful when the underlying binary is stripped.
352    virtual lldb::addr_t
353    LookupRuntimeSymbol (const ConstString &name)
354    {
355        return LLDB_INVALID_ADDRESS;
356    }
357
358    bool
359    HasNewLiteralsAndIndexing ()
360    {
361        if (m_has_new_literals_and_indexing == eLazyBoolCalculate)
362        {
363            if (CalculateHasNewLiteralsAndIndexing())
364                m_has_new_literals_and_indexing = eLazyBoolYes;
365            else
366                m_has_new_literals_and_indexing = eLazyBoolNo;
367        }
368
369        return (m_has_new_literals_and_indexing == eLazyBoolYes);
370    }
371
372    virtual void
373    SymbolsDidLoad (const ModuleList& module_list)
374    {
375        m_negative_complete_class_cache.clear();
376    }
377
378    bool
379    GetTypeBitSize (const CompilerType& compiler_type,
380                    uint64_t &size) override;
381
382protected:
383    //------------------------------------------------------------------
384    // Classes that inherit from ObjCLanguageRuntime can see and modify these
385    //------------------------------------------------------------------
386    ObjCLanguageRuntime(Process *process);
387
388    virtual bool CalculateHasNewLiteralsAndIndexing()
389    {
390        return false;
391    }
392
393    bool
394    ISAIsCached (ObjCISA isa) const
395    {
396        return m_isa_to_descriptor.find(isa) != m_isa_to_descriptor.end();
397    }
398
399    bool
400    AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp)
401    {
402        if (isa != 0)
403        {
404            m_isa_to_descriptor[isa] = descriptor_sp;
405            return true;
406        }
407        return false;
408    }
409
410    bool
411    AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name);
412
413    bool
414    AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, uint32_t class_name_hash)
415    {
416        if (isa != 0)
417        {
418            m_isa_to_descriptor[isa] = descriptor_sp;
419            m_hash_to_isa_map.insert(std::make_pair(class_name_hash, isa));
420            return true;
421        }
422        return false;
423    }
424
425private:
426    // We keep a map of <Class,Selector>->Implementation so we don't have to call the resolver
427    // function over and over.
428
429    // FIXME: We need to watch for the loading of Protocols, and flush the cache for any
430    // class that we see so changed.
431
432    struct ClassAndSel
433    {
434        ClassAndSel()
435        {
436            sel_addr = LLDB_INVALID_ADDRESS;
437            class_addr = LLDB_INVALID_ADDRESS;
438        }
439
440        ClassAndSel (lldb::addr_t in_sel_addr, lldb::addr_t in_class_addr) :
441            class_addr (in_class_addr),
442            sel_addr(in_sel_addr)
443        {
444        }
445
446        bool operator== (const ClassAndSel &rhs)
447        {
448            if (class_addr == rhs.class_addr
449                && sel_addr == rhs.sel_addr)
450                return true;
451            else
452                return false;
453        }
454
455        bool operator< (const ClassAndSel &rhs) const
456        {
457            if (class_addr < rhs.class_addr)
458                return true;
459            else if (class_addr > rhs.class_addr)
460                return false;
461            else
462            {
463                if (sel_addr < rhs.sel_addr)
464                    return true;
465                else
466                    return false;
467            }
468        }
469
470        lldb::addr_t class_addr;
471        lldb::addr_t sel_addr;
472    };
473
474    typedef std::map<ClassAndSel,lldb::addr_t> MsgImplMap;
475    typedef std::map<ObjCISA, ClassDescriptorSP> ISAToDescriptorMap;
476    typedef std::multimap<uint32_t, ObjCISA> HashToISAMap;
477    typedef ISAToDescriptorMap::iterator ISAToDescriptorIterator;
478    typedef HashToISAMap::iterator HashToISAIterator;
479    typedef ThreadSafeDenseMap<void*, uint64_t> TypeSizeCache;
480
481    MsgImplMap m_impl_cache;
482    LazyBool m_has_new_literals_and_indexing;
483    ISAToDescriptorMap m_isa_to_descriptor;
484    HashToISAMap m_hash_to_isa_map;
485    TypeSizeCache m_type_size_cache;
486
487protected:
488    uint32_t m_isa_to_descriptor_stop_id;
489
490    typedef std::map<ConstString, lldb::TypeWP> CompleteClassMap;
491    CompleteClassMap m_complete_class_cache;
492
493    struct ConstStringSetHelpers {
494        size_t operator () (const ConstString& arg) const // for hashing
495        {
496            return (size_t)arg.GetCString();
497        }
498        bool operator () (const ConstString& arg1, const ConstString& arg2) const // for equality
499        {
500            return arg1.operator==(arg2);
501        }
502    };
503    typedef std::unordered_set<ConstString, ConstStringSetHelpers, ConstStringSetHelpers> CompleteClassSet;
504    CompleteClassSet m_negative_complete_class_cache;
505
506    ISAToDescriptorIterator
507    GetDescriptorIterator (const ConstString &name);
508
509    friend class ::CommandObjectObjC_ClassTable_Dump;
510
511    std::pair<ISAToDescriptorIterator,ISAToDescriptorIterator>
512    GetDescriptorIteratorPair (bool update_if_needed = true);
513
514    void
515    ReadObjCLibraryIfNeeded (const ModuleList &module_list);
516
517    DISALLOW_COPY_AND_ASSIGN (ObjCLanguageRuntime);
518};
519
520} // namespace lldb_private
521
522#endif // liblldb_ObjCLanguageRuntime_h_
523