AppleObjCRuntimeV2.cpp revision 309124
1//===-- AppleObjCRuntimeV2.cpp ----------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10// C Includes
11#include <stdint.h>
12
13// C++ Includes
14#include <string>
15#include <vector>
16
17// Other libraries and framework includes
18#include "clang/AST/ASTContext.h"
19#include "clang/AST/DeclObjC.h"
20
21// Project includes
22#include "lldb/lldb-enumerations.h"
23#include "lldb/Core/ClangForward.h"
24#include "lldb/Symbol/CompilerType.h"
25
26#include "lldb/Core/ClangForward.h"
27#include "lldb/Core/ConstString.h"
28#include "lldb/Core/Debugger.h"
29#include "lldb/Core/Error.h"
30#include "lldb/Core/Log.h"
31#include "lldb/Core/Module.h"
32#include "lldb/Core/PluginManager.h"
33#include "lldb/Core/Scalar.h"
34#include "lldb/Core/Section.h"
35#include "lldb/Core/Stream.h"
36#include "lldb/Core/StreamString.h"
37#include "lldb/Core/Timer.h"
38#include "lldb/Core/ValueObjectVariable.h"
39#include "lldb/Expression/DiagnosticManager.h"
40#include "lldb/Expression/FunctionCaller.h"
41#include "lldb/Expression/UtilityFunction.h"
42#include "lldb/Host/StringConvert.h"
43#include "lldb/Interpreter/CommandObject.h"
44#include "lldb/Interpreter/CommandObjectMultiword.h"
45#include "lldb/Interpreter/CommandReturnObject.h"
46#include "lldb/Interpreter/OptionValueBoolean.h"
47#include "lldb/Symbol/ClangASTContext.h"
48#include "lldb/Symbol/ObjectFile.h"
49#include "lldb/Symbol/Symbol.h"
50#include "lldb/Symbol/TypeList.h"
51#include "lldb/Symbol/VariableList.h"
52#include "lldb/Target/ExecutionContext.h"
53#include "lldb/Target/Platform.h"
54#include "lldb/Target/Process.h"
55#include "lldb/Target/RegisterContext.h"
56#include "lldb/Target/Target.h"
57#include "lldb/Target/Thread.h"
58
59#include "AppleObjCRuntimeV2.h"
60#include "AppleObjCClassDescriptorV2.h"
61#include "AppleObjCTypeEncodingParser.h"
62#include "AppleObjCDeclVendor.h"
63#include "AppleObjCTrampolineHandler.h"
64
65
66using namespace lldb;
67using namespace lldb_private;
68
69// 2 second timeout when running utility functions
70#define UTILITY_FUNCTION_TIMEOUT_USEC 2*1000*1000
71
72static const char *g_get_dynamic_class_info_name = "__lldb_apple_objc_v2_get_dynamic_class_info";
73// Testing using the new C++11 raw string literals. If this breaks GCC then we will
74// need to revert to the code above...
75static const char *g_get_dynamic_class_info_body = R"(
76
77extern "C"
78{
79    size_t strlen(const char *);
80    char *strncpy (char * s1, const char * s2, size_t n);
81    int printf(const char * format, ...);
82}
83#define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)
84
85typedef struct _NXMapTable {
86    void *prototype;
87    unsigned num_classes;
88    unsigned num_buckets_minus_one;
89    void *buckets;
90} NXMapTable;
91
92#define NX_MAPNOTAKEY   ((void *)(-1))
93
94typedef struct BucketInfo
95{
96    const char *name_ptr;
97    Class isa;
98} BucketInfo;
99
100struct ClassInfo
101{
102    Class isa;
103    uint32_t hash;
104} __attribute__((__packed__));
105
106uint32_t
107__lldb_apple_objc_v2_get_dynamic_class_info (void *gdb_objc_realized_classes_ptr,
108                                             void *class_infos_ptr,
109                                             uint32_t class_infos_byte_size,
110                                             uint32_t should_log)
111{
112    DEBUG_PRINTF ("gdb_objc_realized_classes_ptr = %p\n", gdb_objc_realized_classes_ptr);
113    DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
114    DEBUG_PRINTF ("class_infos_byte_size = %u\n", class_infos_byte_size);
115    const NXMapTable *grc = (const NXMapTable *)gdb_objc_realized_classes_ptr;
116    if (grc)
117    {
118        const unsigned num_classes = grc->num_classes;
119        if (class_infos_ptr)
120        {
121            const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
122            ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
123            BucketInfo *buckets = (BucketInfo *)grc->buckets;
124
125            uint32_t idx = 0;
126            for (unsigned i=0; i<=grc->num_buckets_minus_one; ++i)
127            {
128                if (buckets[i].name_ptr != NX_MAPNOTAKEY)
129                {
130                    if (idx < max_class_infos)
131                    {
132                        const char *s = buckets[i].name_ptr;
133                        uint32_t h = 5381;
134                        for (unsigned char c = *s; c; c = *++s)
135                            h = ((h << 5) + h) + c;
136                        class_infos[idx].hash = h;
137                        class_infos[idx].isa = buckets[i].isa;
138                    }
139                    ++idx;
140                }
141            }
142            if (idx < max_class_infos)
143            {
144                class_infos[idx].isa = NULL;
145                class_infos[idx].hash = 0;
146            }
147        }
148        return num_classes;
149    }
150    return 0;
151}
152
153)";
154
155static const char *g_get_shared_cache_class_info_name = "__lldb_apple_objc_v2_get_shared_cache_class_info";
156// Testing using the new C++11 raw string literals. If this breaks GCC then we will
157// need to revert to the code above...
158static const char *g_get_shared_cache_class_info_body = R"(
159
160extern "C"
161{
162    const char *class_getName(void *objc_class);
163    size_t strlen(const char *);
164    char *strncpy (char * s1, const char * s2, size_t n);
165    int printf(const char * format, ...);
166}
167
168#define DEBUG_PRINTF(fmt, ...) if (should_log) printf(fmt, ## __VA_ARGS__)
169
170
171struct objc_classheader_t {
172    int32_t clsOffset;
173    int32_t hiOffset;
174};
175
176struct objc_clsopt_t {
177    uint32_t capacity;
178    uint32_t occupied;
179    uint32_t shift;
180    uint32_t mask;
181    uint32_t zero;
182    uint32_t unused;
183    uint64_t salt;
184    uint32_t scramble[256];
185    uint8_t tab[0]; // tab[mask+1]
186    //  uint8_t checkbytes[capacity];
187    //  int32_t offset[capacity];
188    //  objc_classheader_t clsOffsets[capacity];
189    //  uint32_t duplicateCount;
190    //  objc_classheader_t duplicateOffsets[duplicateCount];
191};
192
193struct objc_opt_t {
194    uint32_t version;
195    int32_t selopt_offset;
196    int32_t headeropt_offset;
197    int32_t clsopt_offset;
198};
199
200struct objc_opt_v14_t {
201    uint32_t version;
202    uint32_t flags;
203    int32_t selopt_offset;
204    int32_t headeropt_offset;
205    int32_t clsopt_offset;
206};
207
208struct ClassInfo
209{
210    Class isa;
211    uint32_t hash;
212}  __attribute__((__packed__));
213
214uint32_t
215__lldb_apple_objc_v2_get_shared_cache_class_info (void *objc_opt_ro_ptr,
216                                                  void *class_infos_ptr,
217                                                  uint32_t class_infos_byte_size,
218                                                  uint32_t should_log)
219{
220    uint32_t idx = 0;
221    DEBUG_PRINTF ("objc_opt_ro_ptr = %p\n", objc_opt_ro_ptr);
222    DEBUG_PRINTF ("class_infos_ptr = %p\n", class_infos_ptr);
223    DEBUG_PRINTF ("class_infos_byte_size = %u (%llu class infos)\n", class_infos_byte_size, (uint64_t)(class_infos_byte_size/sizeof(ClassInfo)));
224    if (objc_opt_ro_ptr)
225    {
226        const objc_opt_t *objc_opt = (objc_opt_t *)objc_opt_ro_ptr;
227        const objc_opt_v14_t* objc_opt_v14 = (objc_opt_v14_t*)objc_opt_ro_ptr;
228        const bool is_v14_format = objc_opt->version >= 14;
229        if (is_v14_format)
230        {
231            DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt_v14->version);
232            DEBUG_PRINTF ("objc_opt->flags = %u\n", objc_opt_v14->flags);
233            DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt_v14->selopt_offset);
234            DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt_v14->headeropt_offset);
235            DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt_v14->clsopt_offset);
236        }
237        else
238        {
239            DEBUG_PRINTF ("objc_opt->version = %u\n", objc_opt->version);
240            DEBUG_PRINTF ("objc_opt->selopt_offset = %d\n", objc_opt->selopt_offset);
241            DEBUG_PRINTF ("objc_opt->headeropt_offset = %d\n", objc_opt->headeropt_offset);
242            DEBUG_PRINTF ("objc_opt->clsopt_offset = %d\n", objc_opt->clsopt_offset);
243        }
244        if (objc_opt->version == 12 || objc_opt->version == 13 || objc_opt->version == 14 || objc_opt->version == 15)
245        {
246            const objc_clsopt_t* clsopt = NULL;
247            if (is_v14_format)
248                clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt_v14 + objc_opt_v14->clsopt_offset);
249            else
250                clsopt = (const objc_clsopt_t*)((uint8_t *)objc_opt + objc_opt->clsopt_offset);
251            const size_t max_class_infos = class_infos_byte_size/sizeof(ClassInfo);
252            DEBUG_PRINTF("max_class_infos = %llu\n", (uint64_t)max_class_infos);
253            ClassInfo *class_infos = (ClassInfo *)class_infos_ptr;
254            int32_t invalidEntryOffset = 0;
255            // this is safe to do because the version field order is invariant
256            if (objc_opt->version == 12)
257                invalidEntryOffset = 16;
258            const uint8_t *checkbytes = &clsopt->tab[clsopt->mask+1];
259            const int32_t *offsets = (const int32_t *)(checkbytes + clsopt->capacity);
260            const objc_classheader_t *classOffsets = (const objc_classheader_t *)(offsets + clsopt->capacity);
261            DEBUG_PRINTF ("clsopt->capacity = %u\n", clsopt->capacity);
262            DEBUG_PRINTF ("clsopt->mask = 0x%8.8x\n", clsopt->mask);
263            DEBUG_PRINTF ("classOffsets = %p\n", classOffsets);
264            DEBUG_PRINTF("invalidEntryOffset = %d\n", invalidEntryOffset);
265            for (uint32_t i=0; i<clsopt->capacity; ++i)
266            {
267                const int32_t clsOffset = classOffsets[i].clsOffset;
268                DEBUG_PRINTF("clsOffset[%u] = %u\n", i, clsOffset);
269                if (clsOffset & 1)
270                {
271                    DEBUG_PRINTF("clsOffset & 1\n");
272                    continue; // duplicate
273                }
274                else if (clsOffset == invalidEntryOffset)
275                {
276                    DEBUG_PRINTF("clsOffset == invalidEntryOffset\n");
277                    continue; // invalid offset
278                }
279
280                if (class_infos && idx < max_class_infos)
281                {
282                    class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
283                    const char *name = class_getName (class_infos[idx].isa);
284                    DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
285                    // Hash the class name so we don't have to read it
286                    const char *s = name;
287                    uint32_t h = 5381;
288                    for (unsigned char c = *s; c; c = *++s)
289                        h = ((h << 5) + h) + c;
290                    class_infos[idx].hash = h;
291                }
292                else
293                {
294                    DEBUG_PRINTF("not(class_infos && idx < max_class_infos)\n");
295                }
296                ++idx;
297            }
298
299            const uint32_t *duplicate_count_ptr = (uint32_t *)&classOffsets[clsopt->capacity];
300            const uint32_t duplicate_count = *duplicate_count_ptr;
301            const objc_classheader_t *duplicateClassOffsets = (const objc_classheader_t *)(&duplicate_count_ptr[1]);
302            DEBUG_PRINTF ("duplicate_count = %u\n", duplicate_count);
303            DEBUG_PRINTF ("duplicateClassOffsets = %p\n", duplicateClassOffsets);
304            for (uint32_t i=0; i<duplicate_count; ++i)
305            {
306                const int32_t clsOffset = duplicateClassOffsets[i].clsOffset;
307                if (clsOffset & 1)
308                    continue; // duplicate
309                else if (clsOffset == invalidEntryOffset)
310                    continue; // invalid offset
311
312                if (class_infos && idx < max_class_infos)
313                {
314                    class_infos[idx].isa = (Class)((uint8_t *)clsopt + clsOffset);
315                    const char *name = class_getName (class_infos[idx].isa);
316                    DEBUG_PRINTF ("[%u] isa = %8p %s\n", idx, class_infos[idx].isa, name);
317                    // Hash the class name so we don't have to read it
318                    const char *s = name;
319                    uint32_t h = 5381;
320                    for (unsigned char c = *s; c; c = *++s)
321                        h = ((h << 5) + h) + c;
322                    class_infos[idx].hash = h;
323                }
324                ++idx;
325            }
326        }
327        DEBUG_PRINTF ("%u class_infos\n", idx);
328        DEBUG_PRINTF ("done\n");
329    }
330    return idx;
331}
332
333
334)";
335
336static uint64_t
337ExtractRuntimeGlobalSymbol (Process* process,
338                            ConstString name,
339                            const ModuleSP &module_sp,
340                            Error& error,
341                            bool read_value = true,
342                            uint8_t byte_size = 0,
343                            uint64_t default_value = LLDB_INVALID_ADDRESS,
344                            SymbolType sym_type = lldb::eSymbolTypeData)
345{
346    if (!process)
347    {
348        error.SetErrorString("no process");
349        return default_value;
350    }
351    if (!module_sp)
352    {
353        error.SetErrorString("no module");
354        return default_value;
355    }
356    if (!byte_size)
357        byte_size = process->GetAddressByteSize();
358    const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType(name, lldb::eSymbolTypeData);
359    if (symbol && symbol->ValueIsAddress())
360    {
361        lldb::addr_t symbol_load_addr = symbol->GetAddressRef().GetLoadAddress(&process->GetTarget());
362        if (symbol_load_addr != LLDB_INVALID_ADDRESS)
363        {
364            if (read_value)
365                return process->ReadUnsignedIntegerFromMemory(symbol_load_addr, byte_size, default_value, error);
366            else
367                return symbol_load_addr;
368        }
369        else
370        {
371            error.SetErrorString("symbol address invalid");
372            return default_value;
373        }
374    }
375    else
376    {
377        error.SetErrorString("no symbol");
378        return default_value;
379    }
380}
381
382AppleObjCRuntimeV2::AppleObjCRuntimeV2(Process *process, const ModuleSP &objc_module_sp)
383    : AppleObjCRuntime(process),
384      m_get_class_info_code(),
385      m_get_class_info_args(LLDB_INVALID_ADDRESS),
386      m_get_class_info_args_mutex(),
387      m_get_shared_cache_class_info_code(),
388      m_get_shared_cache_class_info_args(LLDB_INVALID_ADDRESS),
389      m_get_shared_cache_class_info_args_mutex(),
390      m_decl_vendor_ap(),
391      m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS),
392      m_hash_signature(),
393      m_has_object_getClass(false),
394      m_loaded_objc_opt(false),
395      m_non_pointer_isa_cache_ap(NonPointerISACache::CreateInstance(*this, objc_module_sp)),
396      m_tagged_pointer_vendor_ap(TaggedPointerVendorV2::CreateInstance(*this, objc_module_sp)),
397      m_encoding_to_type_sp(),
398      m_noclasses_warning_emitted(false)
399{
400    static const ConstString g_gdb_object_getClass("gdb_object_getClass");
401    m_has_object_getClass =
402        (objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_object_getClass, eSymbolTypeCode) != NULL);
403}
404
405bool
406AppleObjCRuntimeV2::GetDynamicTypeAndAddress (ValueObject &in_value,
407                                              DynamicValueType use_dynamic,
408                                              TypeAndOrName &class_type_or_name,
409                                              Address &address,
410                                              Value::ValueType &value_type)
411{
412    // We should never get here with a null process...
413    assert (m_process != NULL);
414
415    // The Runtime is attached to a particular process, you shouldn't pass in a value from another process.
416    // Note, however, the process might be NULL (e.g. if the value was made with SBTarget::EvaluateExpression...)
417    // in which case it is sufficient if the target's match:
418
419    Process *process = in_value.GetProcessSP().get();
420    if (process)
421        assert (process == m_process);
422    else
423        assert (in_value.GetTargetSP().get() == m_process->CalculateTarget().get());
424
425    class_type_or_name.Clear();
426    value_type = Value::ValueType::eValueTypeScalar;
427
428    // Make sure we can have a dynamic value before starting...
429    if (CouldHaveDynamicValue (in_value))
430    {
431        // First job, pull out the address at 0 offset from the object  That will be the ISA pointer.
432        ClassDescriptorSP objc_class_sp (GetNonKVOClassDescriptor (in_value));
433        if (objc_class_sp)
434        {
435            const addr_t object_ptr = in_value.GetPointerValue();
436            address.SetRawAddress(object_ptr);
437
438            ConstString class_name (objc_class_sp->GetClassName());
439            class_type_or_name.SetName(class_name);
440            TypeSP type_sp (objc_class_sp->GetType());
441            if (type_sp)
442                class_type_or_name.SetTypeSP (type_sp);
443            else
444            {
445                type_sp = LookupInCompleteClassCache (class_name);
446                if (type_sp)
447                {
448                    objc_class_sp->SetType (type_sp);
449                    class_type_or_name.SetTypeSP (type_sp);
450                }
451                else
452                {
453                    // try to go for a CompilerType at least
454                    DeclVendor* vendor = GetDeclVendor();
455                    if (vendor)
456                    {
457                        std::vector<clang::NamedDecl*> decls;
458                        if (vendor->FindDecls(class_name, false, 1, decls) && decls.size())
459                            class_type_or_name.SetCompilerType(ClangASTContext::GetTypeForDecl(decls[0]));
460                    }
461                }
462            }
463        }
464    }
465    return class_type_or_name.IsEmpty() == false;
466}
467
468//------------------------------------------------------------------
469// Static Functions
470//------------------------------------------------------------------
471LanguageRuntime *
472AppleObjCRuntimeV2::CreateInstance (Process *process, LanguageType language)
473{
474    // FIXME: This should be a MacOS or iOS process, and we need to look for the OBJC section to make
475    // sure we aren't using the V1 runtime.
476    if (language == eLanguageTypeObjC)
477    {
478        ModuleSP objc_module_sp;
479
480        if (AppleObjCRuntime::GetObjCVersion (process, objc_module_sp) == ObjCRuntimeVersions::eAppleObjC_V2)
481            return new AppleObjCRuntimeV2 (process, objc_module_sp);
482        else
483            return NULL;
484    }
485    else
486        return NULL;
487}
488
489class CommandObjectObjC_ClassTable_Dump : public CommandObjectParsed
490{
491public:
492    class CommandOptions : public Options
493    {
494    public:
495        CommandOptions (CommandInterpreter &interpreter) :
496        Options(interpreter),
497        m_verbose(false,false)
498        {}
499
500        ~CommandOptions() override = default;
501
502        Error
503        SetOptionValue(uint32_t option_idx, const char *option_arg) override
504        {
505            Error error;
506            const int short_option = m_getopt_table[option_idx].val;
507            switch (short_option)
508            {
509                case 'v':
510                    m_verbose.SetCurrentValue(true);
511                    m_verbose.SetOptionWasSet();
512                    break;
513
514                default:
515                    error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
516                    break;
517            }
518
519            return error;
520        }
521
522        void
523        OptionParsingStarting() override
524        {
525            m_verbose.Clear();
526        }
527
528        const OptionDefinition*
529        GetDefinitions() override
530        {
531            return g_option_table;
532        }
533
534        OptionValueBoolean m_verbose;
535        static OptionDefinition g_option_table[];
536    };
537
538    CommandObjectObjC_ClassTable_Dump (CommandInterpreter &interpreter) :
539    CommandObjectParsed (interpreter,
540                         "dump",
541                         "Dump information on Objective-C classes known to the current process.",
542                         "language objc class-table dump",
543                         eCommandRequiresProcess       |
544                         eCommandProcessMustBeLaunched |
545                         eCommandProcessMustBePaused   ),
546    m_options(interpreter)
547    {
548        CommandArgumentEntry arg;
549        CommandArgumentData index_arg;
550
551        // Define the first (and only) variant of this arg.
552        index_arg.arg_type = eArgTypeRegularExpression;
553        index_arg.arg_repetition = eArgRepeatOptional;
554
555        // There is only one variant this argument could be; put it into the argument entry.
556        arg.push_back (index_arg);
557
558        // Push the data for the first argument into the m_arguments vector.
559        m_arguments.push_back (arg);
560    }
561
562    ~CommandObjectObjC_ClassTable_Dump() override = default;
563
564    Options *
565    GetOptions() override
566    {
567        return &m_options;
568    }
569
570protected:
571    bool
572    DoExecute(Args& command, CommandReturnObject &result) override
573    {
574        std::unique_ptr<RegularExpression> regex_up;
575        switch(command.GetArgumentCount())
576        {
577            case 0:
578                break;
579            case 1:
580            {
581                regex_up.reset(new RegularExpression());
582                if (!regex_up->Compile(command.GetArgumentAtIndex(0)))
583                {
584                    result.AppendError("invalid argument - please provide a valid regular expression");
585                    result.SetStatus(lldb::eReturnStatusFailed);
586                    return false;
587                }
588                break;
589            }
590            default:
591            {
592                result.AppendError("please provide 0 or 1 arguments");
593                result.SetStatus(lldb::eReturnStatusFailed);
594                return false;
595            }
596        }
597
598        Process *process = m_exe_ctx.GetProcessPtr();
599        ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime();
600        if (objc_runtime)
601        {
602            auto iterators_pair = objc_runtime->GetDescriptorIteratorPair();
603            auto iterator = iterators_pair.first;
604            auto &std_out = result.GetOutputStream();
605            for(; iterator != iterators_pair.second; iterator++)
606            {
607                if (iterator->second)
608                {
609                    const char* class_name = iterator->second->GetClassName().AsCString("<unknown>");
610                    if (regex_up && class_name && !regex_up->Execute(class_name))
611                        continue;
612                    std_out.Printf("isa = 0x%" PRIx64, iterator->first);
613                    std_out.Printf(" name = %s", class_name);
614                    std_out.Printf(" instance size = %" PRIu64, iterator->second->GetInstanceSize());
615                    std_out.Printf(" num ivars = %" PRIuPTR, (uintptr_t)iterator->second->GetNumIVars());
616                    if (auto superclass = iterator->second->GetSuperclass())
617                    {
618                        std_out.Printf(" superclass = %s", superclass->GetClassName().AsCString("<unknown>"));
619                    }
620                    std_out.Printf("\n");
621                    if (m_options.m_verbose)
622                    {
623                        for(size_t i = 0;
624                            i < iterator->second->GetNumIVars();
625                            i++)
626                        {
627                            auto ivar = iterator->second->GetIVarAtIndex(i);
628                            std_out.Printf("  ivar name = %s type = %s size = %" PRIu64 " offset = %" PRId32 "\n",
629                                                            ivar.m_name.AsCString("<unknown>"),
630                                                            ivar.m_type.GetDisplayTypeName().AsCString("<unknown>"),
631                                                            ivar.m_size,
632                                                            ivar.m_offset);
633                        }
634                        iterator->second->Describe(nullptr,
635                                                   [objc_runtime, &std_out] (const char* name, const char* type) -> bool {
636                                                       std_out.Printf("  instance method name = %s type = %s\n",
637                                                                      name,
638                                                                      type);
639                                                       return false;
640                                                   },
641                                                   [objc_runtime, &std_out] (const char* name, const char* type) -> bool {
642                                                       std_out.Printf("  class method name = %s type = %s\n",
643                                                                      name,
644                                                                      type);
645                                                       return false;
646                                                   },
647                                                   nullptr);
648                    }
649                }
650                else
651                {
652                    if (regex_up && !regex_up->Execute(""))
653                        continue;
654                    std_out.Printf("isa = 0x%" PRIx64 " has no associated class.\n", iterator->first);
655                }
656            }
657            result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
658            return true;
659        }
660        else
661        {
662            result.AppendError("current process has no Objective-C runtime loaded");
663            result.SetStatus(lldb::eReturnStatusFailed);
664            return false;
665        }
666    }
667
668    CommandOptions m_options;
669};
670
671OptionDefinition
672CommandObjectObjC_ClassTable_Dump::CommandOptions::g_option_table[] =
673{
674    { LLDB_OPT_SET_ALL, false, "verbose"        , 'v', OptionParser::eNoArgument        , nullptr, nullptr, 0, eArgTypeNone,        "Print ivar and method information in detail"},
675    { 0               , false, nullptr           ,   0, 0                  , nullptr, nullptr, 0, eArgTypeNone,        nullptr }
676};
677
678class CommandObjectMultiwordObjC_TaggedPointer_Info : public CommandObjectParsed
679{
680public:
681    CommandObjectMultiwordObjC_TaggedPointer_Info (CommandInterpreter &interpreter) :
682    CommandObjectParsed (interpreter,
683                         "info",
684                         "Dump information on a tagged pointer.",
685                         "language objc tagged-pointer info",
686                         eCommandRequiresProcess       |
687                         eCommandProcessMustBeLaunched |
688                         eCommandProcessMustBePaused   )
689    {
690        CommandArgumentEntry arg;
691        CommandArgumentData index_arg;
692
693        // Define the first (and only) variant of this arg.
694        index_arg.arg_type = eArgTypeAddress;
695        index_arg.arg_repetition = eArgRepeatPlus;
696
697        // There is only one variant this argument could be; put it into the argument entry.
698        arg.push_back (index_arg);
699
700        // Push the data for the first argument into the m_arguments vector.
701        m_arguments.push_back (arg);
702    }
703
704    ~CommandObjectMultiwordObjC_TaggedPointer_Info() override = default;
705
706protected:
707    bool
708    DoExecute(Args& command, CommandReturnObject &result) override
709    {
710        if (command.GetArgumentCount() == 0)
711        {
712            result.AppendError("this command requires arguments");
713            result.SetStatus(lldb::eReturnStatusFailed);
714            return false;
715        }
716
717        Process *process = m_exe_ctx.GetProcessPtr();
718        ExecutionContext exe_ctx(process);
719        ObjCLanguageRuntime *objc_runtime = process->GetObjCLanguageRuntime();
720        if (objc_runtime)
721        {
722            ObjCLanguageRuntime::TaggedPointerVendor *tagged_ptr_vendor = objc_runtime->GetTaggedPointerVendor();
723            if (tagged_ptr_vendor)
724            {
725                for (size_t i = 0;
726                     i < command.GetArgumentCount();
727                     i++)
728                {
729                    const char *arg_str = command.GetArgumentAtIndex(i);
730                    if (!arg_str)
731                        continue;
732                    Error error;
733                    lldb::addr_t arg_addr = Args::StringToAddress(&exe_ctx, arg_str, LLDB_INVALID_ADDRESS, &error);
734                    if (arg_addr == 0 || arg_addr == LLDB_INVALID_ADDRESS || error.Fail())
735                        continue;
736                    auto descriptor_sp = tagged_ptr_vendor->GetClassDescriptor(arg_addr);
737                    if (!descriptor_sp)
738                        continue;
739                    uint64_t info_bits = 0;
740                    uint64_t value_bits = 0;
741                    uint64_t payload = 0;
742                    if (descriptor_sp->GetTaggedPointerInfo(&info_bits, &value_bits, &payload))
743                    {
744                        result.GetOutputStream().Printf("0x%" PRIx64 " is tagged.\n\tpayload = 0x%" PRIx64 "\n\tvalue = 0x%" PRIx64 "\n\tinfo bits = 0x%" PRIx64 "\n\tclass = %s\n",
745                                                        (uint64_t)arg_addr,
746                                                        payload,
747                                                        value_bits,
748                                                        info_bits,
749                                                        descriptor_sp->GetClassName().AsCString("<unknown>"));
750                    }
751                    else
752                    {
753                        result.GetOutputStream().Printf("0x%" PRIx64 " is not tagged.\n", (uint64_t)arg_addr);
754                    }
755                }
756            }
757            else
758            {
759                result.AppendError("current process has no tagged pointer support");
760                result.SetStatus(lldb::eReturnStatusFailed);
761                return false;
762            }
763            result.SetStatus(lldb::eReturnStatusSuccessFinishResult);
764            return true;
765        }
766        else
767        {
768            result.AppendError("current process has no Objective-C runtime loaded");
769            result.SetStatus(lldb::eReturnStatusFailed);
770            return false;
771        }
772    }
773};
774
775class CommandObjectMultiwordObjC_ClassTable : public CommandObjectMultiword
776{
777public:
778    CommandObjectMultiwordObjC_ClassTable(CommandInterpreter &interpreter)
779        : CommandObjectMultiword(interpreter, "class-table", "Commands for operating on the Objective-C class table.",
780                                 "class-table <subcommand> [<subcommand-options>]")
781    {
782        LoadSubCommand ("dump",   CommandObjectSP (new CommandObjectObjC_ClassTable_Dump (interpreter)));
783    }
784
785    ~CommandObjectMultiwordObjC_ClassTable() override = default;
786};
787
788class CommandObjectMultiwordObjC_TaggedPointer : public CommandObjectMultiword
789{
790public:
791    CommandObjectMultiwordObjC_TaggedPointer(CommandInterpreter &interpreter)
792        : CommandObjectMultiword(interpreter, "tagged-pointer",
793                                 "Commands for operating on Objective-C tagged pointers.",
794                                 "class-table <subcommand> [<subcommand-options>]")
795    {
796        LoadSubCommand ("info",   CommandObjectSP (new CommandObjectMultiwordObjC_TaggedPointer_Info (interpreter)));
797    }
798
799    ~CommandObjectMultiwordObjC_TaggedPointer() override = default;
800};
801
802class CommandObjectMultiwordObjC : public CommandObjectMultiword
803{
804public:
805    CommandObjectMultiwordObjC(CommandInterpreter &interpreter)
806        : CommandObjectMultiword(interpreter, "objc", "Commands for operating on the Objective-C language runtime.",
807                                 "objc <subcommand> [<subcommand-options>]")
808    {
809        LoadSubCommand ("class-table",   CommandObjectSP (new CommandObjectMultiwordObjC_ClassTable (interpreter)));
810        LoadSubCommand ("tagged-pointer",   CommandObjectSP (new CommandObjectMultiwordObjC_TaggedPointer (interpreter)));
811    }
812
813    ~CommandObjectMultiwordObjC() override = default;
814};
815
816void
817AppleObjCRuntimeV2::Initialize()
818{
819    PluginManager::RegisterPlugin (GetPluginNameStatic(),
820                                   "Apple Objective C Language Runtime - Version 2",
821                                   CreateInstance,
822                                   [] (CommandInterpreter& interpreter) -> lldb::CommandObjectSP {
823                                       return CommandObjectSP(new CommandObjectMultiwordObjC(interpreter));
824                                   });
825}
826
827void
828AppleObjCRuntimeV2::Terminate()
829{
830    PluginManager::UnregisterPlugin (CreateInstance);
831}
832
833lldb_private::ConstString
834AppleObjCRuntimeV2::GetPluginNameStatic()
835{
836    static ConstString g_name("apple-objc-v2");
837    return g_name;
838}
839
840//------------------------------------------------------------------
841// PluginInterface protocol
842//------------------------------------------------------------------
843lldb_private::ConstString
844AppleObjCRuntimeV2::GetPluginName()
845{
846    return GetPluginNameStatic();
847}
848
849uint32_t
850AppleObjCRuntimeV2::GetPluginVersion()
851{
852    return 1;
853}
854
855BreakpointResolverSP
856AppleObjCRuntimeV2::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp)
857{
858    BreakpointResolverSP resolver_sp;
859
860    if (throw_bp)
861        resolver_sp.reset (new BreakpointResolverName (bkpt,
862                                                       "objc_exception_throw",
863                                                       eFunctionNameTypeBase,
864                                                       eLanguageTypeUnknown,
865                                                       Breakpoint::Exact,
866                                                       0,
867                                                       eLazyBoolNo));
868    // FIXME: We don't do catch breakpoints for ObjC yet.
869    // Should there be some way for the runtime to specify what it can do in this regard?
870    return resolver_sp;
871}
872
873UtilityFunction *
874AppleObjCRuntimeV2::CreateObjectChecker(const char *name)
875{
876    char check_function_code[2048];
877
878    int len = 0;
879    if (m_has_object_getClass)
880    {
881        len = ::snprintf (check_function_code,
882                          sizeof(check_function_code),
883                          "extern \"C\" void *gdb_object_getClass(void *);                                          \n"
884                          "extern \"C\"  int printf(const char *format, ...);                                       \n"
885                          "extern \"C\" void                                                                        \n"
886                          "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector)                                    \n"
887                          "{                                                                                        \n"
888                          "   if ($__lldb_arg_obj == (void *)0)                                                     \n"
889                          "       return; // nil is ok                                                              \n"
890                          "   if (!gdb_object_getClass($__lldb_arg_obj))                                            \n"
891                          "       *((volatile int *)0) = 'ocgc';                                                    \n"
892                          "   else if ($__lldb_arg_selector != (void *)0)                                           \n"
893                          "   {                                                                                     \n"
894                          "        signed char responds = (signed char) [(id) $__lldb_arg_obj                       \n"
895                          "                                                respondsToSelector:                      \n"
896                          "                                       (struct objc_selector *) $__lldb_arg_selector];   \n"
897                          "       if (responds == (signed char) 0)                                                  \n"
898                          "           *((volatile int *)0) = 'ocgc';                                                \n"
899                          "   }                                                                                     \n"
900                          "}                                                                                        \n",
901                          name);
902    }
903    else
904    {
905        len = ::snprintf (check_function_code,
906                          sizeof(check_function_code),
907                          "extern \"C\" void *gdb_class_getClass(void *);                                           \n"
908                          "extern \"C\"  int printf(const char *format, ...);                                       \n"
909                          "extern \"C\"  void                                                                       \n"
910                          "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector)                                    \n"
911                          "{                                                                                        \n"
912                          "   if ($__lldb_arg_obj == (void *)0)                                                     \n"
913                          "       return; // nil is ok                                                              \n"
914                          "    void **$isa_ptr = (void **)$__lldb_arg_obj;                                          \n"
915                          "    if (*$isa_ptr == (void *)0 || !gdb_class_getClass(*$isa_ptr))                        \n"
916                          "       *((volatile int *)0) = 'ocgc';                                                    \n"
917                          "   else if ($__lldb_arg_selector != (void *)0)                                           \n"
918                          "   {                                                                                     \n"
919                          "        signed char responds = (signed char) [(id) $__lldb_arg_obj                       \n"
920                          "                                                respondsToSelector:                      \n"
921                          "                                        (struct objc_selector *) $__lldb_arg_selector];  \n"
922                          "       if (responds == (signed char) 0)                                                  \n"
923                          "           *((volatile int *)0) = 'ocgc';                                                \n"
924                          "   }                                                                                     \n"
925                          "}                                                                                        \n",
926                          name);
927    }
928
929    assert (len < (int)sizeof(check_function_code));
930
931    Error error;
932    return GetTargetRef().GetUtilityFunctionForLanguage(check_function_code, eLanguageTypeObjC, name, error);
933}
934
935size_t
936AppleObjCRuntimeV2::GetByteOffsetForIvar (CompilerType &parent_ast_type, const char *ivar_name)
937{
938    uint32_t ivar_offset = LLDB_INVALID_IVAR_OFFSET;
939
940    const char *class_name = parent_ast_type.GetConstTypeName().AsCString();
941    if (class_name && class_name[0] && ivar_name && ivar_name[0])
942    {
943        //----------------------------------------------------------------------
944        // Make the objective C V2 mangled name for the ivar offset from the
945        // class name and ivar name
946        //----------------------------------------------------------------------
947        std::string buffer("OBJC_IVAR_$_");
948        buffer.append (class_name);
949        buffer.push_back ('.');
950        buffer.append (ivar_name);
951        ConstString ivar_const_str (buffer.c_str());
952
953        //----------------------------------------------------------------------
954        // Try to get the ivar offset address from the symbol table first using
955        // the name we created above
956        //----------------------------------------------------------------------
957        SymbolContextList sc_list;
958        Target &target = m_process->GetTarget();
959        target.GetImages().FindSymbolsWithNameAndType(ivar_const_str, eSymbolTypeObjCIVar, sc_list);
960
961        addr_t ivar_offset_address = LLDB_INVALID_ADDRESS;
962
963        Error error;
964        SymbolContext ivar_offset_symbol;
965        if (sc_list.GetSize() == 1 && sc_list.GetContextAtIndex(0, ivar_offset_symbol))
966        {
967            if (ivar_offset_symbol.symbol)
968                ivar_offset_address = ivar_offset_symbol.symbol->GetLoadAddress (&target);
969        }
970
971        //----------------------------------------------------------------------
972        // If we didn't get the ivar offset address from the symbol table, fall
973        // back to getting it from the runtime
974        //----------------------------------------------------------------------
975        if (ivar_offset_address == LLDB_INVALID_ADDRESS)
976            ivar_offset_address = LookupRuntimeSymbol(ivar_const_str);
977
978        if (ivar_offset_address != LLDB_INVALID_ADDRESS)
979            ivar_offset = m_process->ReadUnsignedIntegerFromMemory (ivar_offset_address,
980                                                                    4,
981                                                                    LLDB_INVALID_IVAR_OFFSET,
982                                                                    error);
983    }
984    return ivar_offset;
985}
986
987// tagged pointers are special not-a-real-pointer values that contain both type and value information
988// this routine attempts to check with as little computational effort as possible whether something
989// could possibly be a tagged pointer - false positives are possible but false negatives shouldn't
990bool
991AppleObjCRuntimeV2::IsTaggedPointer(addr_t ptr)
992{
993    if (!m_tagged_pointer_vendor_ap)
994        return false;
995    return m_tagged_pointer_vendor_ap->IsPossibleTaggedPointer(ptr);
996}
997
998class RemoteNXMapTable
999{
1000public:
1001    RemoteNXMapTable () :
1002        m_count (0),
1003        m_num_buckets_minus_one (0),
1004        m_buckets_ptr (LLDB_INVALID_ADDRESS),
1005        m_process (NULL),
1006        m_end_iterator (*this, -1),
1007        m_load_addr (LLDB_INVALID_ADDRESS),
1008        m_map_pair_size (0),
1009        m_invalid_key (0)
1010    {
1011    }
1012
1013    void
1014    Dump ()
1015    {
1016        printf ("RemoteNXMapTable.m_load_addr = 0x%" PRIx64 "\n", m_load_addr);
1017        printf ("RemoteNXMapTable.m_count = %u\n", m_count);
1018        printf ("RemoteNXMapTable.m_num_buckets_minus_one = %u\n", m_num_buckets_minus_one);
1019        printf ("RemoteNXMapTable.m_buckets_ptr = 0x%" PRIX64 "\n", m_buckets_ptr);
1020    }
1021
1022    bool
1023    ParseHeader (Process* process, lldb::addr_t load_addr)
1024    {
1025        m_process = process;
1026        m_load_addr = load_addr;
1027        m_map_pair_size = m_process->GetAddressByteSize() * 2;
1028        m_invalid_key = m_process->GetAddressByteSize() == 8 ? UINT64_MAX : UINT32_MAX;
1029        Error err;
1030
1031        // This currently holds true for all platforms we support, but we might
1032        // need to change this to use get the actually byte size of "unsigned"
1033        // from the target AST...
1034        const uint32_t unsigned_byte_size = sizeof(uint32_t);
1035        // Skip the prototype as we don't need it (const struct +NXMapTablePrototype *prototype)
1036
1037        bool success = true;
1038        if (load_addr == LLDB_INVALID_ADDRESS)
1039            success = false;
1040        else
1041        {
1042            lldb::addr_t cursor = load_addr + m_process->GetAddressByteSize();
1043
1044            // unsigned count;
1045            m_count = m_process->ReadUnsignedIntegerFromMemory(cursor, unsigned_byte_size, 0, err);
1046            if (m_count)
1047            {
1048                cursor += unsigned_byte_size;
1049
1050                // unsigned nbBucketsMinusOne;
1051                m_num_buckets_minus_one = m_process->ReadUnsignedIntegerFromMemory(cursor, unsigned_byte_size, 0, err);
1052                cursor += unsigned_byte_size;
1053
1054                // void *buckets;
1055                m_buckets_ptr = m_process->ReadPointerFromMemory(cursor, err);
1056
1057                success = m_count > 0 && m_buckets_ptr != LLDB_INVALID_ADDRESS;
1058            }
1059        }
1060
1061        if (!success)
1062        {
1063            m_count = 0;
1064            m_num_buckets_minus_one = 0;
1065            m_buckets_ptr = LLDB_INVALID_ADDRESS;
1066        }
1067        return success;
1068    }
1069
1070    // const_iterator mimics NXMapState and its code comes from NXInitMapState and NXNextMapState.
1071    typedef std::pair<ConstString, ObjCLanguageRuntime::ObjCISA> element;
1072
1073    friend class const_iterator;
1074    class const_iterator
1075    {
1076    public:
1077        const_iterator (RemoteNXMapTable &parent, int index) : m_parent(parent), m_index(index)
1078        {
1079            AdvanceToValidIndex();
1080        }
1081
1082        const_iterator (const const_iterator &rhs) : m_parent(rhs.m_parent), m_index(rhs.m_index)
1083        {
1084            // AdvanceToValidIndex() has been called by rhs already.
1085        }
1086
1087        const_iterator &operator=(const const_iterator &rhs)
1088        {
1089            // AdvanceToValidIndex() has been called by rhs already.
1090            assert (&m_parent == &rhs.m_parent);
1091            m_index = rhs.m_index;
1092            return *this;
1093        }
1094
1095        bool operator==(const const_iterator &rhs) const
1096        {
1097            if (&m_parent != &rhs.m_parent)
1098                return false;
1099            if (m_index != rhs.m_index)
1100                return false;
1101
1102            return true;
1103        }
1104
1105        bool operator!=(const const_iterator &rhs) const
1106        {
1107            return !(operator==(rhs));
1108        }
1109
1110        const_iterator &operator++()
1111        {
1112            AdvanceToValidIndex();
1113            return *this;
1114        }
1115
1116        const element operator*() const
1117        {
1118            if (m_index == -1)
1119            {
1120                // TODO find a way to make this an error, but not an assert
1121                return element();
1122            }
1123
1124            lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;
1125            size_t map_pair_size = m_parent.m_map_pair_size;
1126            lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);
1127
1128            Error err;
1129
1130            lldb::addr_t key = m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);
1131            if (!err.Success())
1132                return element();
1133            lldb::addr_t value = m_parent.m_process->ReadPointerFromMemory(pair_ptr + m_parent.m_process->GetAddressByteSize(), err);
1134            if (!err.Success())
1135                return element();
1136
1137            std::string key_string;
1138
1139            m_parent.m_process->ReadCStringFromMemory(key, key_string, err);
1140            if (!err.Success())
1141                return element();
1142
1143            return element(ConstString(key_string.c_str()), (ObjCLanguageRuntime::ObjCISA)value);
1144        }
1145
1146    private:
1147        void AdvanceToValidIndex ()
1148        {
1149            if (m_index == -1)
1150                return;
1151
1152            const lldb::addr_t pairs_ptr = m_parent.m_buckets_ptr;
1153            const size_t map_pair_size = m_parent.m_map_pair_size;
1154            const lldb::addr_t invalid_key = m_parent.m_invalid_key;
1155            Error err;
1156
1157            while (m_index--)
1158            {
1159                lldb::addr_t pair_ptr = pairs_ptr + (m_index * map_pair_size);
1160                lldb::addr_t key = m_parent.m_process->ReadPointerFromMemory(pair_ptr, err);
1161
1162                if (!err.Success())
1163                {
1164                    m_index = -1;
1165                    return;
1166                }
1167
1168                if (key != invalid_key)
1169                    return;
1170            }
1171        }
1172        RemoteNXMapTable   &m_parent;
1173        int                 m_index;
1174    };
1175
1176    const_iterator begin ()
1177    {
1178        return const_iterator(*this, m_num_buckets_minus_one + 1);
1179    }
1180
1181    const_iterator end ()
1182    {
1183        return m_end_iterator;
1184    }
1185
1186    uint32_t
1187    GetCount () const
1188    {
1189        return m_count;
1190    }
1191
1192    uint32_t
1193    GetBucketCount () const
1194    {
1195        return m_num_buckets_minus_one;
1196    }
1197
1198    lldb::addr_t
1199    GetBucketDataPointer () const
1200    {
1201        return m_buckets_ptr;
1202    }
1203
1204    lldb::addr_t
1205    GetTableLoadAddress() const
1206    {
1207        return m_load_addr;
1208    }
1209
1210private:
1211    // contents of _NXMapTable struct
1212    uint32_t m_count;
1213    uint32_t m_num_buckets_minus_one;
1214    lldb::addr_t m_buckets_ptr;
1215    lldb_private::Process *m_process;
1216    const_iterator m_end_iterator;
1217    lldb::addr_t m_load_addr;
1218    size_t m_map_pair_size;
1219    lldb::addr_t m_invalid_key;
1220};
1221
1222AppleObjCRuntimeV2::HashTableSignature::HashTableSignature() :
1223    m_count (0),
1224    m_num_buckets (0),
1225    m_buckets_ptr (0)
1226{
1227}
1228
1229void
1230AppleObjCRuntimeV2::HashTableSignature::UpdateSignature (const RemoteNXMapTable &hash_table)
1231{
1232    m_count = hash_table.GetCount();
1233    m_num_buckets = hash_table.GetBucketCount();
1234    m_buckets_ptr = hash_table.GetBucketDataPointer();
1235}
1236
1237bool
1238AppleObjCRuntimeV2::HashTableSignature::NeedsUpdate (Process *process, AppleObjCRuntimeV2 *runtime, RemoteNXMapTable &hash_table)
1239{
1240    if (!hash_table.ParseHeader(process, runtime->GetISAHashTablePointer ()))
1241    {
1242        return false; // Failed to parse the header, no need to update anything
1243    }
1244
1245    // Check with out current signature and return true if the count,
1246    // number of buckets or the hash table address changes.
1247    if (m_count == hash_table.GetCount() &&
1248        m_num_buckets == hash_table.GetBucketCount() &&
1249        m_buckets_ptr == hash_table.GetBucketDataPointer())
1250    {
1251        // Hash table hasn't changed
1252        return false;
1253    }
1254    // Hash table data has changed, we need to update
1255    return true;
1256}
1257
1258ObjCLanguageRuntime::ClassDescriptorSP
1259AppleObjCRuntimeV2::GetClassDescriptorFromISA (ObjCISA isa)
1260{
1261    ObjCLanguageRuntime::ClassDescriptorSP class_descriptor_sp;
1262    if (m_non_pointer_isa_cache_ap.get())
1263        class_descriptor_sp = m_non_pointer_isa_cache_ap->GetClassDescriptor(isa);
1264    if (!class_descriptor_sp)
1265        class_descriptor_sp = ObjCLanguageRuntime::GetClassDescriptorFromISA(isa);
1266    return class_descriptor_sp;
1267}
1268
1269ObjCLanguageRuntime::ClassDescriptorSP
1270AppleObjCRuntimeV2::GetClassDescriptor (ValueObject& valobj)
1271{
1272    ClassDescriptorSP objc_class_sp;
1273    if (valobj.IsBaseClass())
1274    {
1275        ValueObject *parent = valobj.GetParent();
1276        // if I am my own parent, bail out of here fast..
1277        if (parent && parent != &valobj)
1278        {
1279            ClassDescriptorSP parent_descriptor_sp = GetClassDescriptor(*parent);
1280            if (parent_descriptor_sp)
1281                return parent_descriptor_sp->GetSuperclass();
1282        }
1283        return nullptr;
1284    }
1285    // if we get an invalid VO (which might still happen when playing around
1286    // with pointers returned by the expression parser, don't consider this
1287    // a valid ObjC object)
1288    if (valobj.GetCompilerType().IsValid())
1289    {
1290        addr_t isa_pointer = valobj.GetPointerValue();
1291
1292        // tagged pointer
1293        if (IsTaggedPointer(isa_pointer))
1294        {
1295            return m_tagged_pointer_vendor_ap->GetClassDescriptor(isa_pointer);
1296        }
1297        else
1298        {
1299            ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
1300
1301            Process *process = exe_ctx.GetProcessPtr();
1302            if (process)
1303            {
1304                Error error;
1305                ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error);
1306                if (isa != LLDB_INVALID_ADDRESS)
1307                {
1308                    objc_class_sp = GetClassDescriptorFromISA (isa);
1309                    if (isa && !objc_class_sp)
1310                    {
1311                        Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1312                        if (log)
1313                            log->Printf("0x%" PRIx64 ": AppleObjCRuntimeV2::GetClassDescriptor() ISA was not in class descriptor cache 0x%" PRIx64,
1314                                        isa_pointer,
1315                                        isa);
1316                    }
1317                }
1318            }
1319        }
1320    }
1321    return objc_class_sp;
1322}
1323
1324lldb::addr_t
1325AppleObjCRuntimeV2::GetISAHashTablePointer ()
1326{
1327    if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS)
1328    {
1329        Process *process = GetProcess();
1330
1331        ModuleSP objc_module_sp(GetObjCModule());
1332
1333        if (!objc_module_sp)
1334            return LLDB_INVALID_ADDRESS;
1335
1336        static ConstString g_gdb_objc_realized_classes("gdb_objc_realized_classes");
1337
1338        const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(g_gdb_objc_realized_classes, lldb::eSymbolTypeAny);
1339        if (symbol)
1340        {
1341            lldb::addr_t gdb_objc_realized_classes_ptr = symbol->GetLoadAddress(&process->GetTarget());
1342
1343            if (gdb_objc_realized_classes_ptr != LLDB_INVALID_ADDRESS)
1344            {
1345                Error error;
1346                m_isa_hash_table_ptr = process->ReadPointerFromMemory(gdb_objc_realized_classes_ptr, error);
1347            }
1348        }
1349    }
1350    return m_isa_hash_table_ptr;
1351}
1352
1353bool
1354AppleObjCRuntimeV2::UpdateISAToDescriptorMapDynamic(RemoteNXMapTable &hash_table)
1355{
1356    Process *process = GetProcess();
1357
1358    if (process == NULL)
1359        return false;
1360
1361    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1362
1363    ExecutionContext exe_ctx;
1364
1365    ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();
1366
1367    if (!thread_sp)
1368        return false;
1369
1370    thread_sp->CalculateExecutionContext(exe_ctx);
1371    ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
1372
1373    if (!ast)
1374        return false;
1375
1376    Address function_address;
1377
1378    DiagnosticManager diagnostics;
1379
1380    const uint32_t addr_size = process->GetAddressByteSize();
1381
1382    Error err;
1383
1384    // Read the total number of classes from the hash table
1385    const uint32_t num_classes = hash_table.GetCount();
1386    if (num_classes == 0)
1387    {
1388        if (log)
1389            log->Printf ("No dynamic classes found in gdb_objc_realized_classes.");
1390        return false;
1391    }
1392
1393    // Make some types for our arguments
1394    CompilerType clang_uint32_t_type = ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
1395    CompilerType clang_void_pointer_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
1396
1397    ValueList arguments;
1398    FunctionCaller *get_class_info_function = nullptr;
1399
1400    if (!m_get_class_info_code.get())
1401    {
1402        Error error;
1403        m_get_class_info_code.reset (GetTargetRef().GetUtilityFunctionForLanguage (g_get_dynamic_class_info_body,
1404                                                                                   eLanguageTypeObjC,
1405                                                                                   g_get_dynamic_class_info_name,
1406                                                                                   error));
1407        if (error.Fail())
1408        {
1409            if (log)
1410                log->Printf ("Failed to get Utility Function for implementation lookup: %s", error.AsCString());
1411            m_get_class_info_code.reset();
1412        }
1413        else
1414        {
1415            diagnostics.Clear();
1416
1417            if (!m_get_class_info_code->Install(diagnostics, exe_ctx))
1418            {
1419                if (log)
1420                {
1421                    log->Printf("Failed to install implementation lookup");
1422                    diagnostics.Dump(log);
1423                }
1424                m_get_class_info_code.reset();
1425            }
1426        }
1427        if (!m_get_class_info_code.get())
1428            return false;
1429
1430        // Next make the runner function for our implementation utility function.
1431        Value value;
1432        value.SetValueType (Value::eValueTypeScalar);
1433        value.SetCompilerType (clang_void_pointer_type);
1434        arguments.PushValue (value);
1435        arguments.PushValue (value);
1436
1437        value.SetValueType (Value::eValueTypeScalar);
1438        value.SetCompilerType (clang_uint32_t_type);
1439        arguments.PushValue (value);
1440        arguments.PushValue (value);
1441
1442        get_class_info_function = m_get_class_info_code->MakeFunctionCaller(clang_uint32_t_type,
1443                                                                            arguments,
1444                                                                            thread_sp,
1445                                                                            error);
1446
1447        if (error.Fail())
1448        {
1449            if (log)
1450                log->Printf("Failed to make function caller for implementation lookup: %s.", error.AsCString());
1451            return false;
1452        }
1453    }
1454    else
1455    {
1456        get_class_info_function = m_get_class_info_code->GetFunctionCaller();
1457        if (!get_class_info_function)
1458        {
1459            if (log)
1460            {
1461                log->Printf("Failed to get implementation lookup function caller.");
1462                diagnostics.Dump(log);
1463            }
1464
1465            return false;
1466        }
1467        arguments = get_class_info_function->GetArgumentValues();
1468    }
1469
1470    diagnostics.Clear();
1471
1472    const uint32_t class_info_byte_size = addr_size + 4;
1473    const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;
1474    lldb::addr_t class_infos_addr = process->AllocateMemory(class_infos_byte_size,
1475                                                            ePermissionsReadable | ePermissionsWritable,
1476                                                            err);
1477
1478    if (class_infos_addr == LLDB_INVALID_ADDRESS)
1479        return false;
1480
1481    std::lock_guard<std::mutex> guard(m_get_class_info_args_mutex);
1482
1483    // Fill in our function argument values
1484    arguments.GetValueAtIndex(0)->GetScalar() = hash_table.GetTableLoadAddress();
1485    arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
1486    arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
1487    arguments.GetValueAtIndex(3)->GetScalar() = (GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES) == nullptr ? 0 : 1);
1488
1489
1490    bool success = false;
1491
1492    diagnostics.Clear();
1493
1494    // Write our function arguments into the process so we can run our function
1495    if (get_class_info_function->WriteFunctionArguments(exe_ctx, m_get_class_info_args, arguments, diagnostics))
1496    {
1497        EvaluateExpressionOptions options;
1498        options.SetUnwindOnError(true);
1499        options.SetTryAllThreads(false);
1500        options.SetStopOthers(true);
1501        options.SetIgnoreBreakpoints(true);
1502        options.SetTimeoutUsec(UTILITY_FUNCTION_TIMEOUT_USEC);
1503
1504        Value return_value;
1505        return_value.SetValueType (Value::eValueTypeScalar);
1506        //return_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
1507        return_value.SetCompilerType(clang_uint32_t_type);
1508        return_value.GetScalar() = 0;
1509
1510        diagnostics.Clear();
1511
1512        // Run the function
1513        ExpressionResults results = get_class_info_function->ExecuteFunction(exe_ctx, &m_get_class_info_args, options,
1514                                                                             diagnostics, return_value);
1515
1516        if (results == eExpressionCompleted)
1517        {
1518            // The result is the number of ClassInfo structures that were filled in
1519            uint32_t num_class_infos = return_value.GetScalar().ULong();
1520            if (log)
1521                log->Printf("Discovered %u ObjC classes\n",num_class_infos);
1522            if (num_class_infos > 0)
1523            {
1524                // Read the ClassInfo structures
1525                DataBufferHeap buffer (num_class_infos * class_info_byte_size, 0);
1526                if (process->ReadMemory(class_infos_addr, buffer.GetBytes(), buffer.GetByteSize(), err) == buffer.GetByteSize())
1527                {
1528                    DataExtractor class_infos_data (buffer.GetBytes(),
1529                                                    buffer.GetByteSize(),
1530                                                    process->GetByteOrder(),
1531                                                    addr_size);
1532                    ParseClassInfoArray (class_infos_data, num_class_infos);
1533                }
1534            }
1535            success = true;
1536        }
1537        else
1538        {
1539            if (log)
1540            {
1541                log->Printf("Error evaluating our find class name function.");
1542                diagnostics.Dump(log);
1543            }
1544        }
1545    }
1546    else
1547    {
1548        if (log)
1549        {
1550            log->Printf("Error writing function arguments.");
1551            diagnostics.Dump(log);
1552        }
1553    }
1554
1555    // Deallocate the memory we allocated for the ClassInfo array
1556    process->DeallocateMemory(class_infos_addr);
1557
1558    return success;
1559}
1560
1561uint32_t
1562AppleObjCRuntimeV2::ParseClassInfoArray (const DataExtractor &data, uint32_t num_class_infos)
1563{
1564    // Parses an array of "num_class_infos" packed ClassInfo structures:
1565    //
1566    //    struct ClassInfo
1567    //    {
1568    //        Class isa;
1569    //        uint32_t hash;
1570    //    } __attribute__((__packed__));
1571
1572    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1573
1574    uint32_t num_parsed = 0;
1575
1576    // Iterate through all ClassInfo structures
1577    lldb::offset_t offset = 0;
1578    for (uint32_t i=0; i<num_class_infos; ++i)
1579    {
1580        ObjCISA isa = data.GetPointer(&offset);
1581
1582        if (isa == 0)
1583        {
1584            if (log)
1585                log->Printf("AppleObjCRuntimeV2 found NULL isa, ignoring this class info");
1586            continue;
1587        }
1588        // Check if we already know about this ISA, if we do, the info will
1589        // never change, so we can just skip it.
1590        if (ISAIsCached(isa))
1591        {
1592            offset += 4;
1593        }
1594        else
1595        {
1596            // Read the 32 bit hash for the class name
1597            const uint32_t name_hash = data.GetU32(&offset);
1598            ClassDescriptorSP descriptor_sp (new ClassDescriptorV2(*this, isa, NULL));
1599            AddClass (isa, descriptor_sp, name_hash);
1600            num_parsed++;
1601            if (log && log->GetVerbose())
1602                log->Printf("AppleObjCRuntimeV2 added isa=0x%" PRIx64 ", hash=0x%8.8x, name=%s", isa, name_hash,descriptor_sp->GetClassName().AsCString("<unknown>"));
1603        }
1604    }
1605    return num_parsed;
1606}
1607
1608AppleObjCRuntimeV2::DescriptorMapUpdateResult
1609AppleObjCRuntimeV2::UpdateISAToDescriptorMapSharedCache()
1610{
1611    Process *process = GetProcess();
1612
1613    if (process == NULL)
1614        return DescriptorMapUpdateResult::Fail();
1615
1616    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1617
1618    ExecutionContext exe_ctx;
1619
1620    ThreadSP thread_sp = process->GetThreadList().GetExpressionExecutionThread();
1621
1622    if (!thread_sp)
1623        return DescriptorMapUpdateResult::Fail();
1624
1625    thread_sp->CalculateExecutionContext(exe_ctx);
1626    ClangASTContext *ast = process->GetTarget().GetScratchClangASTContext();
1627
1628    if (!ast)
1629        return DescriptorMapUpdateResult::Fail();
1630
1631    Address function_address;
1632
1633    DiagnosticManager diagnostics;
1634
1635    const uint32_t addr_size = process->GetAddressByteSize();
1636
1637    Error err;
1638
1639    const lldb::addr_t objc_opt_ptr = GetSharedCacheReadOnlyAddress();
1640
1641    if (objc_opt_ptr == LLDB_INVALID_ADDRESS)
1642        return DescriptorMapUpdateResult::Fail();
1643
1644    // Read the total number of classes from the hash table
1645    const uint32_t num_classes = 128*1024;
1646    if (num_classes == 0)
1647    {
1648        if (log)
1649            log->Printf ("No dynamic classes found in gdb_objc_realized_classes_addr.");
1650        return DescriptorMapUpdateResult::Fail();
1651    }
1652
1653    // Make some types for our arguments
1654    CompilerType clang_uint32_t_type = ast->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, 32);
1655    CompilerType clang_void_pointer_type = ast->GetBasicType(eBasicTypeVoid).GetPointerType();
1656
1657    ValueList arguments;
1658    FunctionCaller *get_shared_cache_class_info_function = nullptr;
1659
1660    if (!m_get_shared_cache_class_info_code.get())
1661    {
1662        Error error;
1663        m_get_shared_cache_class_info_code.reset (GetTargetRef().GetUtilityFunctionForLanguage (g_get_shared_cache_class_info_body,
1664                                                                                                eLanguageTypeObjC,
1665                                                                                                g_get_shared_cache_class_info_name,
1666                                                                                                error));
1667        if (error.Fail())
1668        {
1669            if (log)
1670                log->Printf ("Failed to get Utility function for implementation lookup: %s.", error.AsCString());
1671            m_get_shared_cache_class_info_code.reset();
1672        }
1673        else
1674        {
1675            diagnostics.Clear();
1676
1677            if (!m_get_shared_cache_class_info_code->Install(diagnostics, exe_ctx))
1678            {
1679                if (log)
1680                {
1681                    log->Printf("Failed to install implementation lookup.");
1682                    diagnostics.Dump(log);
1683                }
1684                m_get_shared_cache_class_info_code.reset();
1685            }
1686        }
1687
1688        if (!m_get_shared_cache_class_info_code.get())
1689            return DescriptorMapUpdateResult::Fail();
1690
1691        // Next make the function caller for our implementation utility function.
1692        Value value;
1693        value.SetValueType (Value::eValueTypeScalar);
1694        //value.SetContext (Value::eContextTypeClangType, clang_void_pointer_type);
1695        value.SetCompilerType (clang_void_pointer_type);
1696        arguments.PushValue (value);
1697        arguments.PushValue (value);
1698
1699        value.SetValueType (Value::eValueTypeScalar);
1700        //value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
1701        value.SetCompilerType (clang_uint32_t_type);
1702        arguments.PushValue (value);
1703        arguments.PushValue (value);
1704
1705        get_shared_cache_class_info_function = m_get_shared_cache_class_info_code->MakeFunctionCaller(clang_uint32_t_type,
1706                                                                                                      arguments,
1707                                                                                                      thread_sp,
1708                                                                                                      error);
1709
1710        if (get_shared_cache_class_info_function == nullptr)
1711            return DescriptorMapUpdateResult::Fail();
1712
1713    }
1714    else
1715    {
1716        get_shared_cache_class_info_function = m_get_shared_cache_class_info_code->GetFunctionCaller();
1717        if (get_shared_cache_class_info_function == nullptr)
1718            return DescriptorMapUpdateResult::Fail();
1719        arguments = get_shared_cache_class_info_function->GetArgumentValues();
1720    }
1721
1722    diagnostics.Clear();
1723
1724    const uint32_t class_info_byte_size = addr_size + 4;
1725    const uint32_t class_infos_byte_size = num_classes * class_info_byte_size;
1726    lldb::addr_t class_infos_addr = process->AllocateMemory (class_infos_byte_size,
1727                                                             ePermissionsReadable | ePermissionsWritable,
1728                                                             err);
1729
1730    if (class_infos_addr == LLDB_INVALID_ADDRESS)
1731        return DescriptorMapUpdateResult::Fail();
1732
1733    std::lock_guard<std::mutex> guard(m_get_shared_cache_class_info_args_mutex);
1734
1735    // Fill in our function argument values
1736    arguments.GetValueAtIndex(0)->GetScalar() = objc_opt_ptr;
1737    arguments.GetValueAtIndex(1)->GetScalar() = class_infos_addr;
1738    arguments.GetValueAtIndex(2)->GetScalar() = class_infos_byte_size;
1739    arguments.GetValueAtIndex(3)->GetScalar() = (GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES) == nullptr ? 0 : 1);
1740
1741
1742    bool success = false;
1743    bool any_found = false;
1744
1745    diagnostics.Clear();
1746
1747    // Write our function arguments into the process so we can run our function
1748    if (get_shared_cache_class_info_function->WriteFunctionArguments(exe_ctx, m_get_shared_cache_class_info_args,
1749                                                                     arguments, diagnostics))
1750    {
1751        EvaluateExpressionOptions options;
1752        options.SetUnwindOnError(true);
1753        options.SetTryAllThreads(false);
1754        options.SetStopOthers(true);
1755        options.SetIgnoreBreakpoints(true);
1756        options.SetTimeoutUsec(UTILITY_FUNCTION_TIMEOUT_USEC);
1757
1758        Value return_value;
1759        return_value.SetValueType (Value::eValueTypeScalar);
1760        //return_value.SetContext (Value::eContextTypeClangType, clang_uint32_t_type);
1761        return_value.SetCompilerType(clang_uint32_t_type);
1762        return_value.GetScalar() = 0;
1763
1764        diagnostics.Clear();
1765
1766        // Run the function
1767        ExpressionResults results = get_shared_cache_class_info_function->ExecuteFunction(
1768            exe_ctx, &m_get_shared_cache_class_info_args, options, diagnostics, return_value);
1769
1770        if (results == eExpressionCompleted)
1771        {
1772            // The result is the number of ClassInfo structures that were filled in
1773            uint32_t num_class_infos = return_value.GetScalar().ULong();
1774            if (log)
1775                log->Printf("Discovered %u ObjC classes in shared cache\n",num_class_infos);
1776#ifdef LLDB_CONFIGURATION_DEBUG
1777            assert (num_class_infos <= num_classes);
1778#endif
1779            if (num_class_infos > 0)
1780            {
1781                if (num_class_infos > num_classes)
1782                {
1783                    num_class_infos = num_classes;
1784
1785                    success = false;
1786                }
1787                else
1788                {
1789                    success = true;
1790                }
1791
1792                // Read the ClassInfo structures
1793                DataBufferHeap buffer (num_class_infos * class_info_byte_size, 0);
1794                if (process->ReadMemory(class_infos_addr,
1795                                        buffer.GetBytes(),
1796                                        buffer.GetByteSize(),
1797                                        err) == buffer.GetByteSize())
1798                {
1799                    DataExtractor class_infos_data (buffer.GetBytes(),
1800                                                    buffer.GetByteSize(),
1801                                                    process->GetByteOrder(),
1802                                                    addr_size);
1803
1804                    any_found = (ParseClassInfoArray (class_infos_data, num_class_infos) > 0);
1805                }
1806            }
1807            else
1808            {
1809                success = true;
1810            }
1811        }
1812        else
1813        {
1814            if (log)
1815            {
1816                log->Printf("Error evaluating our find class name function.");
1817                diagnostics.Dump(log);
1818            }
1819        }
1820    }
1821    else
1822    {
1823        if (log)
1824        {
1825            log->Printf("Error writing function arguments.");
1826            diagnostics.Dump(log);
1827        }
1828    }
1829
1830    // Deallocate the memory we allocated for the ClassInfo array
1831    process->DeallocateMemory(class_infos_addr);
1832
1833    return DescriptorMapUpdateResult(success, any_found);
1834}
1835
1836bool
1837AppleObjCRuntimeV2::UpdateISAToDescriptorMapFromMemory (RemoteNXMapTable &hash_table)
1838{
1839    Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
1840
1841    Process *process = GetProcess();
1842
1843    if (process == NULL)
1844        return false;
1845
1846    uint32_t num_map_table_isas = 0;
1847
1848    ModuleSP objc_module_sp(GetObjCModule());
1849
1850    if (objc_module_sp)
1851    {
1852        for (RemoteNXMapTable::element elt : hash_table)
1853        {
1854            ++num_map_table_isas;
1855
1856            if (ISAIsCached(elt.second))
1857                continue;
1858
1859            ClassDescriptorSP descriptor_sp = ClassDescriptorSP(new ClassDescriptorV2(*this, elt.second, elt.first.AsCString()));
1860
1861            if (log && log->GetVerbose())
1862                log->Printf("AppleObjCRuntimeV2 added (ObjCISA)0x%" PRIx64 " (%s) from dynamic table to isa->descriptor cache", elt.second, elt.first.AsCString());
1863
1864            AddClass (elt.second, descriptor_sp, elt.first.AsCString());
1865        }
1866    }
1867
1868    return num_map_table_isas > 0;
1869}
1870
1871lldb::addr_t
1872AppleObjCRuntimeV2::GetSharedCacheReadOnlyAddress()
1873{
1874    Process *process = GetProcess();
1875
1876    if (process)
1877    {
1878        ModuleSP objc_module_sp(GetObjCModule());
1879
1880        if (objc_module_sp)
1881        {
1882            ObjectFile *objc_object = objc_module_sp->GetObjectFile();
1883
1884            if (objc_object)
1885            {
1886                SectionList *section_list = objc_module_sp->GetSectionList();
1887
1888                if (section_list)
1889                {
1890                    SectionSP text_segment_sp (section_list->FindSectionByName(ConstString("__TEXT")));
1891
1892                    if (text_segment_sp)
1893                    {
1894                        SectionSP objc_opt_section_sp (text_segment_sp->GetChildren().FindSectionByName(ConstString("__objc_opt_ro")));
1895
1896                        if (objc_opt_section_sp)
1897                        {
1898                            return objc_opt_section_sp->GetLoadBaseAddress(&process->GetTarget());
1899                        }
1900                    }
1901                }
1902            }
1903        }
1904    }
1905    return LLDB_INVALID_ADDRESS;
1906}
1907
1908void
1909AppleObjCRuntimeV2::UpdateISAToDescriptorMapIfNeeded()
1910{
1911    Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
1912
1913    // Else we need to check with our process to see when the map was updated.
1914    Process *process = GetProcess();
1915
1916    if (process)
1917    {
1918        RemoteNXMapTable hash_table;
1919
1920        // Update the process stop ID that indicates the last time we updated the
1921        // map, whether it was successful or not.
1922        m_isa_to_descriptor_stop_id = process->GetStopID();
1923
1924        if (!m_hash_signature.NeedsUpdate(process, this, hash_table))
1925            return;
1926
1927        m_hash_signature.UpdateSignature (hash_table);
1928
1929        // Grab the dynamically loaded objc classes from the hash table in memory
1930        UpdateISAToDescriptorMapDynamic(hash_table);
1931
1932        // Now get the objc classes that are baked into the Objective C runtime
1933        // in the shared cache, but only once per process as this data never
1934        // changes
1935        if (!m_loaded_objc_opt)
1936        {
1937            DescriptorMapUpdateResult shared_cache_update_result = UpdateISAToDescriptorMapSharedCache();
1938            if (!shared_cache_update_result.any_found)
1939                WarnIfNoClassesCached ();
1940            else
1941                m_loaded_objc_opt = true;
1942        }
1943    }
1944    else
1945    {
1946        m_isa_to_descriptor_stop_id = UINT32_MAX;
1947    }
1948}
1949
1950void
1951AppleObjCRuntimeV2::WarnIfNoClassesCached ()
1952{
1953    if (m_noclasses_warning_emitted)
1954        return;
1955
1956    if (m_process &&
1957        m_process->GetTarget().GetPlatform() &&
1958        m_process->GetTarget().GetPlatform()->GetPluginName().GetStringRef().endswith("-simulator"))
1959    {
1960        // Simulators do not have the objc_opt_ro class table so don't actually complain to the user
1961        m_noclasses_warning_emitted = true;
1962        return;
1963    }
1964
1965    Debugger &debugger(GetProcess()->GetTarget().GetDebugger());
1966
1967    if (debugger.GetAsyncOutputStream())
1968    {
1969        debugger.GetAsyncOutputStream()->PutCString("warning: could not load any Objective-C class information from the dyld shared cache. This will significantly reduce the quality of type information available.\n");
1970        m_noclasses_warning_emitted = true;
1971    }
1972}
1973
1974// TODO: should we have a transparent_kvo parameter here to say if we
1975// want to replace the KVO swizzled class with the actual user-level type?
1976ConstString
1977AppleObjCRuntimeV2::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa)
1978{
1979    if (isa == g_objc_Tagged_ISA)
1980    {
1981        static const ConstString g_objc_tagged_isa_name ("_lldb_Tagged_ObjC_ISA");
1982        return g_objc_tagged_isa_name;
1983    }
1984    if (isa == g_objc_Tagged_ISA_NSAtom)
1985    {
1986        static const ConstString g_objc_tagged_isa_nsatom_name ("NSAtom");
1987        return g_objc_tagged_isa_nsatom_name;
1988    }
1989    if (isa == g_objc_Tagged_ISA_NSNumber)
1990    {
1991        static const ConstString g_objc_tagged_isa_nsnumber_name ("NSNumber");
1992        return g_objc_tagged_isa_nsnumber_name;
1993    }
1994    if (isa == g_objc_Tagged_ISA_NSDateTS)
1995    {
1996        static const ConstString g_objc_tagged_isa_nsdatets_name ("NSDateTS");
1997        return g_objc_tagged_isa_nsdatets_name;
1998    }
1999    if (isa == g_objc_Tagged_ISA_NSManagedObject)
2000    {
2001        static const ConstString g_objc_tagged_isa_nsmanagedobject_name ("NSManagedObject");
2002        return g_objc_tagged_isa_nsmanagedobject_name;
2003    }
2004    if (isa == g_objc_Tagged_ISA_NSDate)
2005    {
2006        static const ConstString g_objc_tagged_isa_nsdate_name ("NSDate");
2007        return g_objc_tagged_isa_nsdate_name;
2008    }
2009    return ObjCLanguageRuntime::GetActualTypeName(isa);
2010}
2011
2012DeclVendor *
2013AppleObjCRuntimeV2::GetDeclVendor()
2014{
2015    if (!m_decl_vendor_ap.get())
2016        m_decl_vendor_ap.reset(new AppleObjCDeclVendor(*this));
2017
2018    return m_decl_vendor_ap.get();
2019}
2020
2021lldb::addr_t
2022AppleObjCRuntimeV2::LookupRuntimeSymbol (const ConstString &name)
2023{
2024    lldb::addr_t ret = LLDB_INVALID_ADDRESS;
2025
2026    const char *name_cstr = name.AsCString();
2027
2028    if (name_cstr)
2029    {
2030        llvm::StringRef name_strref(name_cstr);
2031
2032        static const llvm::StringRef ivar_prefix("OBJC_IVAR_$_");
2033        static const llvm::StringRef class_prefix("OBJC_CLASS_$_");
2034
2035        if (name_strref.startswith(ivar_prefix))
2036        {
2037            llvm::StringRef ivar_skipped_prefix = name_strref.substr(ivar_prefix.size());
2038            std::pair<llvm::StringRef, llvm::StringRef> class_and_ivar = ivar_skipped_prefix.split('.');
2039
2040            if (class_and_ivar.first.size() && class_and_ivar.second.size())
2041            {
2042                const ConstString class_name_cs(class_and_ivar.first);
2043                ClassDescriptorSP descriptor = ObjCLanguageRuntime::GetClassDescriptorFromClassName(class_name_cs);
2044
2045                if (descriptor)
2046                {
2047                    const ConstString ivar_name_cs(class_and_ivar.second);
2048                    const char *ivar_name_cstr = ivar_name_cs.AsCString();
2049
2050                    auto ivar_func = [&ret, ivar_name_cstr](const char *name, const char *type, lldb::addr_t offset_addr, uint64_t size) -> lldb::addr_t
2051                    {
2052                        if (!strcmp(name, ivar_name_cstr))
2053                        {
2054                            ret = offset_addr;
2055                            return true;
2056                        }
2057                        return false;
2058                    };
2059
2060                    descriptor->Describe(std::function<void (ObjCISA)>(nullptr),
2061                                         std::function<bool (const char *, const char *)>(nullptr),
2062                                         std::function<bool (const char *, const char *)>(nullptr),
2063                                         ivar_func);
2064                }
2065            }
2066        }
2067        else if (name_strref.startswith(class_prefix))
2068        {
2069            llvm::StringRef class_skipped_prefix = name_strref.substr(class_prefix.size());
2070            const ConstString class_name_cs(class_skipped_prefix);
2071            ClassDescriptorSP descriptor = GetClassDescriptorFromClassName(class_name_cs);
2072
2073            if (descriptor)
2074                ret = descriptor->GetISA();
2075        }
2076    }
2077
2078    return ret;
2079}
2080
2081AppleObjCRuntimeV2::NonPointerISACache*
2082AppleObjCRuntimeV2::NonPointerISACache::CreateInstance (AppleObjCRuntimeV2& runtime, const lldb::ModuleSP& objc_module_sp)
2083{
2084    Process* process(runtime.GetProcess());
2085
2086    Error error;
2087
2088    auto objc_debug_isa_magic_mask = ExtractRuntimeGlobalSymbol(process,
2089                                                                ConstString("objc_debug_isa_magic_mask"),
2090                                                                objc_module_sp,
2091                                                                error);
2092    if (error.Fail())
2093        return NULL;
2094
2095    auto objc_debug_isa_magic_value = ExtractRuntimeGlobalSymbol(process,
2096                                                                 ConstString("objc_debug_isa_magic_value"),
2097                                                                 objc_module_sp,
2098                                                                 error);
2099    if (error.Fail())
2100        return NULL;
2101
2102    auto objc_debug_isa_class_mask = ExtractRuntimeGlobalSymbol(process,
2103                                                                ConstString("objc_debug_isa_class_mask"),
2104                                                                objc_module_sp,
2105                                                                error);
2106    if (error.Fail())
2107        return NULL;
2108
2109    // we might want to have some rules to outlaw these other values (e.g if the mask is zero but the value is non-zero, ...)
2110
2111    return new NonPointerISACache(runtime,
2112                                  objc_debug_isa_class_mask,
2113                                  objc_debug_isa_magic_mask,
2114                                  objc_debug_isa_magic_value);
2115}
2116
2117AppleObjCRuntimeV2::TaggedPointerVendorV2*
2118AppleObjCRuntimeV2::TaggedPointerVendorV2::CreateInstance (AppleObjCRuntimeV2& runtime, const lldb::ModuleSP& objc_module_sp)
2119{
2120    Process* process(runtime.GetProcess());
2121
2122    Error error;
2123
2124    auto objc_debug_taggedpointer_mask = ExtractRuntimeGlobalSymbol(process,
2125                                                                    ConstString("objc_debug_taggedpointer_mask"),
2126                                                                    objc_module_sp,
2127                                                                    error);
2128    if (error.Fail())
2129        return new TaggedPointerVendorLegacy(runtime);
2130
2131    auto objc_debug_taggedpointer_slot_shift = ExtractRuntimeGlobalSymbol(process,
2132                                                                          ConstString("objc_debug_taggedpointer_slot_shift"),
2133                                                                          objc_module_sp,
2134                                                                          error,
2135                                                                          true,
2136                                                                          4);
2137    if (error.Fail())
2138        return new TaggedPointerVendorLegacy(runtime);
2139
2140    auto objc_debug_taggedpointer_slot_mask = ExtractRuntimeGlobalSymbol(process,
2141                                                                          ConstString("objc_debug_taggedpointer_slot_mask"),
2142                                                                          objc_module_sp,
2143                                                                          error,
2144                                                                          true,
2145                                                                          4);
2146    if (error.Fail())
2147        return new TaggedPointerVendorLegacy(runtime);
2148
2149    auto objc_debug_taggedpointer_payload_lshift = ExtractRuntimeGlobalSymbol(process,
2150                                                                              ConstString("objc_debug_taggedpointer_payload_lshift"),
2151                                                                              objc_module_sp,
2152                                                                              error,
2153                                                                              true,
2154                                                                              4);
2155    if (error.Fail())
2156        return new TaggedPointerVendorLegacy(runtime);
2157
2158    auto objc_debug_taggedpointer_payload_rshift = ExtractRuntimeGlobalSymbol(process,
2159                                                                              ConstString("objc_debug_taggedpointer_payload_rshift"),
2160                                                                              objc_module_sp,
2161                                                                              error,
2162                                                                              true,
2163                                                                              4);
2164    if (error.Fail())
2165        return new TaggedPointerVendorLegacy(runtime);
2166
2167    auto objc_debug_taggedpointer_classes = ExtractRuntimeGlobalSymbol(process,
2168                                                                       ConstString("objc_debug_taggedpointer_classes"),
2169                                                                       objc_module_sp,
2170                                                                       error,
2171                                                                       false);
2172    if (error.Fail())
2173        return new TaggedPointerVendorLegacy(runtime);
2174
2175    // try to detect the "extended tagged pointer" variables - if any are missing, use the non-extended vendor
2176    do
2177    {
2178        auto objc_debug_taggedpointer_ext_mask = ExtractRuntimeGlobalSymbol(process,
2179                                                                            ConstString("objc_debug_taggedpointer_ext_mask"),
2180                                                                            objc_module_sp,
2181                                                                            error);
2182        if (error.Fail())
2183            break;
2184
2185        auto objc_debug_taggedpointer_ext_slot_shift = ExtractRuntimeGlobalSymbol(process,
2186                                                                                  ConstString("objc_debug_taggedpointer_ext_slot_shift"),
2187                                                                                  objc_module_sp,
2188                                                                                  error,
2189                                                                                  true,
2190                                                                                  4);
2191        if (error.Fail())
2192            break;
2193
2194        auto objc_debug_taggedpointer_ext_slot_mask = ExtractRuntimeGlobalSymbol(process,
2195                                                                                 ConstString("objc_debug_taggedpointer_ext_slot_mask"),
2196                                                                                 objc_module_sp,
2197                                                                                 error,
2198                                                                                 true,
2199                                                                                 4);
2200        if (error.Fail())
2201            break;
2202
2203        auto objc_debug_taggedpointer_ext_classes = ExtractRuntimeGlobalSymbol(process,
2204                                                                               ConstString("objc_debug_taggedpointer_ext_classes"),
2205                                                                               objc_module_sp,
2206                                                                               error,
2207                                                                               false);
2208        if (error.Fail())
2209            break;
2210
2211        auto objc_debug_taggedpointer_ext_payload_lshift = ExtractRuntimeGlobalSymbol(process,
2212                                                                                      ConstString("objc_debug_taggedpointer_ext_payload_lshift"),
2213                                                                                      objc_module_sp,
2214                                                                                      error,
2215                                                                                      true,
2216                                                                                      4);
2217        if (error.Fail())
2218            break;
2219
2220        auto objc_debug_taggedpointer_ext_payload_rshift = ExtractRuntimeGlobalSymbol(process,
2221                                                                                      ConstString("objc_debug_taggedpointer_ext_payload_rshift"),
2222                                                                                      objc_module_sp,
2223                                                                                      error,
2224                                                                                      true,
2225                                                                                      4);
2226        if (error.Fail())
2227            break;
2228
2229        return new TaggedPointerVendorExtended(runtime,
2230                                               objc_debug_taggedpointer_mask,
2231                                               objc_debug_taggedpointer_ext_mask,
2232                                               objc_debug_taggedpointer_slot_shift,
2233                                               objc_debug_taggedpointer_ext_slot_shift,
2234                                               objc_debug_taggedpointer_slot_mask,
2235                                               objc_debug_taggedpointer_ext_slot_mask,
2236                                               objc_debug_taggedpointer_payload_lshift,
2237                                               objc_debug_taggedpointer_payload_rshift,
2238                                               objc_debug_taggedpointer_ext_payload_lshift,
2239                                               objc_debug_taggedpointer_ext_payload_rshift,
2240                                               objc_debug_taggedpointer_classes,
2241                                               objc_debug_taggedpointer_ext_classes);
2242    } while(false);
2243
2244    // we might want to have some rules to outlaw these values (e.g if the table's address is zero)
2245
2246    return new TaggedPointerVendorRuntimeAssisted(runtime,
2247                                                  objc_debug_taggedpointer_mask,
2248                                                  objc_debug_taggedpointer_slot_shift,
2249                                                  objc_debug_taggedpointer_slot_mask,
2250                                                  objc_debug_taggedpointer_payload_lshift,
2251                                                  objc_debug_taggedpointer_payload_rshift,
2252                                                  objc_debug_taggedpointer_classes);
2253}
2254
2255bool
2256AppleObjCRuntimeV2::TaggedPointerVendorLegacy::IsPossibleTaggedPointer (lldb::addr_t ptr)
2257{
2258    return (ptr & 1);
2259}
2260
2261ObjCLanguageRuntime::ClassDescriptorSP
2262AppleObjCRuntimeV2::TaggedPointerVendorLegacy::GetClassDescriptor (lldb::addr_t ptr)
2263{
2264    if (!IsPossibleTaggedPointer(ptr))
2265        return ObjCLanguageRuntime::ClassDescriptorSP();
2266
2267    uint32_t foundation_version = m_runtime.GetFoundationVersion();
2268
2269    if (foundation_version == LLDB_INVALID_MODULE_VERSION)
2270        return ObjCLanguageRuntime::ClassDescriptorSP();
2271
2272    uint64_t class_bits = (ptr & 0xE) >> 1;
2273    ConstString name;
2274
2275    // TODO: make a table
2276    if (foundation_version >= 900)
2277    {
2278        switch (class_bits)
2279        {
2280            case 0:
2281                name = ConstString("NSAtom");
2282                break;
2283            case 3:
2284                name = ConstString("NSNumber");
2285                break;
2286            case 4:
2287                name = ConstString("NSDateTS");
2288                break;
2289            case 5:
2290                name = ConstString("NSManagedObject");
2291                break;
2292            case 6:
2293                name = ConstString("NSDate");
2294                break;
2295            default:
2296                return ObjCLanguageRuntime::ClassDescriptorSP();
2297        }
2298    }
2299    else
2300    {
2301        switch (class_bits)
2302        {
2303            case 1:
2304                name = ConstString("NSNumber");
2305                break;
2306            case 5:
2307                name = ConstString("NSManagedObject");
2308                break;
2309            case 6:
2310                name = ConstString("NSDate");
2311                break;
2312            case 7:
2313                name = ConstString("NSDateTS");
2314                break;
2315            default:
2316                return ObjCLanguageRuntime::ClassDescriptorSP();
2317        }
2318    }
2319    return ClassDescriptorSP(new ClassDescriptorV2Tagged(name,ptr));
2320}
2321
2322AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::TaggedPointerVendorRuntimeAssisted (AppleObjCRuntimeV2& runtime,
2323                                                                                            uint64_t objc_debug_taggedpointer_mask,
2324                                                                                            uint32_t objc_debug_taggedpointer_slot_shift,
2325                                                                                            uint32_t objc_debug_taggedpointer_slot_mask,
2326                                                                                            uint32_t objc_debug_taggedpointer_payload_lshift,
2327                                                                                            uint32_t objc_debug_taggedpointer_payload_rshift,
2328                                                                                            lldb::addr_t objc_debug_taggedpointer_classes) :
2329TaggedPointerVendorV2(runtime),
2330m_cache(),
2331m_objc_debug_taggedpointer_mask(objc_debug_taggedpointer_mask),
2332m_objc_debug_taggedpointer_slot_shift(objc_debug_taggedpointer_slot_shift),
2333m_objc_debug_taggedpointer_slot_mask(objc_debug_taggedpointer_slot_mask),
2334m_objc_debug_taggedpointer_payload_lshift(objc_debug_taggedpointer_payload_lshift),
2335m_objc_debug_taggedpointer_payload_rshift(objc_debug_taggedpointer_payload_rshift),
2336m_objc_debug_taggedpointer_classes(objc_debug_taggedpointer_classes)
2337{
2338}
2339
2340bool
2341AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::IsPossibleTaggedPointer (lldb::addr_t ptr)
2342{
2343    return (ptr & m_objc_debug_taggedpointer_mask) != 0;
2344}
2345
2346ObjCLanguageRuntime::ClassDescriptorSP
2347AppleObjCRuntimeV2::TaggedPointerVendorRuntimeAssisted::GetClassDescriptor (lldb::addr_t ptr)
2348{
2349    ClassDescriptorSP actual_class_descriptor_sp;
2350    uint64_t data_payload;
2351
2352    if (!IsPossibleTaggedPointer(ptr))
2353        return ObjCLanguageRuntime::ClassDescriptorSP();
2354
2355    uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_slot_shift) & m_objc_debug_taggedpointer_slot_mask;
2356
2357    CacheIterator iterator = m_cache.find(slot),
2358    end = m_cache.end();
2359    if (iterator != end)
2360    {
2361        actual_class_descriptor_sp = iterator->second;
2362    }
2363    else
2364    {
2365        Process* process(m_runtime.GetProcess());
2366        uintptr_t slot_ptr = slot*process->GetAddressByteSize()+m_objc_debug_taggedpointer_classes;
2367        Error error;
2368        uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);
2369        if (error.Fail() || slot_data == 0 || slot_data == uintptr_t(LLDB_INVALID_ADDRESS))
2370            return nullptr;
2371        actual_class_descriptor_sp = m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data);
2372        if (!actual_class_descriptor_sp)
2373            return ObjCLanguageRuntime::ClassDescriptorSP();
2374        m_cache[slot] = actual_class_descriptor_sp;
2375    }
2376
2377    data_payload = (((uint64_t)ptr << m_objc_debug_taggedpointer_payload_lshift) >> m_objc_debug_taggedpointer_payload_rshift);
2378
2379    return ClassDescriptorSP(new ClassDescriptorV2Tagged(actual_class_descriptor_sp,data_payload));
2380}
2381
2382AppleObjCRuntimeV2::TaggedPointerVendorExtended::TaggedPointerVendorExtended (AppleObjCRuntimeV2& runtime,
2383                                                                              uint64_t objc_debug_taggedpointer_mask,
2384                                                                              uint64_t objc_debug_taggedpointer_ext_mask,
2385                                                                              uint32_t objc_debug_taggedpointer_slot_shift,
2386                                                                              uint32_t objc_debug_taggedpointer_ext_slot_shift,
2387                                                                              uint32_t objc_debug_taggedpointer_slot_mask,
2388                                                                              uint32_t objc_debug_taggedpointer_ext_slot_mask,
2389                                                                              uint32_t objc_debug_taggedpointer_payload_lshift,
2390                                                                              uint32_t objc_debug_taggedpointer_payload_rshift,
2391                                                                              uint32_t objc_debug_taggedpointer_ext_payload_lshift,
2392                                                                              uint32_t objc_debug_taggedpointer_ext_payload_rshift,
2393                                                                              lldb::addr_t objc_debug_taggedpointer_classes,
2394                                                                              lldb::addr_t objc_debug_taggedpointer_ext_classes) :
2395TaggedPointerVendorRuntimeAssisted(runtime,
2396                                   objc_debug_taggedpointer_mask,
2397                                   objc_debug_taggedpointer_slot_shift,
2398                                   objc_debug_taggedpointer_slot_mask,
2399                                   objc_debug_taggedpointer_payload_lshift,
2400                                   objc_debug_taggedpointer_payload_rshift,
2401                                   objc_debug_taggedpointer_classes),
2402m_ext_cache(),
2403m_objc_debug_taggedpointer_ext_mask(objc_debug_taggedpointer_ext_mask),
2404m_objc_debug_taggedpointer_ext_slot_shift(objc_debug_taggedpointer_ext_slot_shift),
2405m_objc_debug_taggedpointer_ext_slot_mask(objc_debug_taggedpointer_ext_slot_mask),
2406m_objc_debug_taggedpointer_ext_payload_lshift(objc_debug_taggedpointer_ext_payload_lshift),
2407m_objc_debug_taggedpointer_ext_payload_rshift(objc_debug_taggedpointer_ext_payload_rshift),
2408m_objc_debug_taggedpointer_ext_classes(objc_debug_taggedpointer_ext_classes)
2409{
2410}
2411
2412bool
2413AppleObjCRuntimeV2::TaggedPointerVendorExtended::IsPossibleExtendedTaggedPointer (lldb::addr_t ptr)
2414{
2415    if (!IsPossibleTaggedPointer(ptr))
2416        return false;
2417
2418    if (m_objc_debug_taggedpointer_ext_mask == 0)
2419        return false;
2420
2421    return ((ptr & m_objc_debug_taggedpointer_ext_mask) == m_objc_debug_taggedpointer_ext_mask);
2422}
2423
2424ObjCLanguageRuntime::ClassDescriptorSP
2425AppleObjCRuntimeV2::TaggedPointerVendorExtended::GetClassDescriptor (lldb::addr_t ptr)
2426{
2427    ClassDescriptorSP actual_class_descriptor_sp;
2428    uint64_t data_payload;
2429
2430    if (!IsPossibleTaggedPointer(ptr))
2431        return ObjCLanguageRuntime::ClassDescriptorSP();
2432
2433    if (!IsPossibleExtendedTaggedPointer(ptr))
2434        return this->TaggedPointerVendorRuntimeAssisted::GetClassDescriptor(ptr);
2435
2436    uintptr_t slot = (ptr >> m_objc_debug_taggedpointer_ext_slot_shift) & m_objc_debug_taggedpointer_ext_slot_mask;
2437
2438    CacheIterator iterator = m_ext_cache.find(slot),
2439    end = m_ext_cache.end();
2440    if (iterator != end)
2441    {
2442        actual_class_descriptor_sp = iterator->second;
2443    }
2444    else
2445    {
2446        Process* process(m_runtime.GetProcess());
2447        uintptr_t slot_ptr = slot*process->GetAddressByteSize()+m_objc_debug_taggedpointer_ext_classes;
2448        Error error;
2449        uintptr_t slot_data = process->ReadPointerFromMemory(slot_ptr, error);
2450        if (error.Fail() || slot_data == 0 || slot_data == uintptr_t(LLDB_INVALID_ADDRESS))
2451            return nullptr;
2452        actual_class_descriptor_sp = m_runtime.GetClassDescriptorFromISA((ObjCISA)slot_data);
2453        if (!actual_class_descriptor_sp)
2454            return ObjCLanguageRuntime::ClassDescriptorSP();
2455        m_ext_cache[slot] = actual_class_descriptor_sp;
2456    }
2457
2458    data_payload = (((uint64_t)ptr << m_objc_debug_taggedpointer_ext_payload_lshift) >> m_objc_debug_taggedpointer_ext_payload_rshift);
2459
2460    return ClassDescriptorSP(new ClassDescriptorV2Tagged(actual_class_descriptor_sp,data_payload));
2461}
2462
2463AppleObjCRuntimeV2::NonPointerISACache::NonPointerISACache (AppleObjCRuntimeV2& runtime,
2464                                                            uint64_t objc_debug_isa_class_mask,
2465                                                            uint64_t objc_debug_isa_magic_mask,
2466                                                            uint64_t objc_debug_isa_magic_value) :
2467m_runtime(runtime),
2468m_cache(),
2469m_objc_debug_isa_class_mask(objc_debug_isa_class_mask),
2470m_objc_debug_isa_magic_mask(objc_debug_isa_magic_mask),
2471m_objc_debug_isa_magic_value(objc_debug_isa_magic_value)
2472{
2473}
2474
2475ObjCLanguageRuntime::ClassDescriptorSP
2476AppleObjCRuntimeV2::NonPointerISACache::GetClassDescriptor (ObjCISA isa)
2477{
2478    ObjCISA real_isa = 0;
2479    if (EvaluateNonPointerISA(isa, real_isa) == false)
2480        return ObjCLanguageRuntime::ClassDescriptorSP();
2481    auto cache_iter = m_cache.find(real_isa);
2482    if (cache_iter != m_cache.end())
2483        return cache_iter->second;
2484    auto descriptor_sp = m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA(real_isa);
2485    if (descriptor_sp) // cache only positive matches since the table might grow
2486        m_cache[real_isa] = descriptor_sp;
2487    return descriptor_sp;
2488}
2489
2490bool
2491AppleObjCRuntimeV2::NonPointerISACache::EvaluateNonPointerISA (ObjCISA isa, ObjCISA& ret_isa)
2492{
2493    if ( (isa & ~m_objc_debug_isa_class_mask) == 0)
2494        return false;
2495    if ( (isa & m_objc_debug_isa_magic_mask) == m_objc_debug_isa_magic_value)
2496    {
2497        ret_isa = isa & m_objc_debug_isa_class_mask;
2498        return (ret_isa != 0); // this is a pointer so 0 is not a valid value
2499    }
2500    return false;
2501}
2502
2503ObjCLanguageRuntime::EncodingToTypeSP
2504AppleObjCRuntimeV2::GetEncodingToType ()
2505{
2506    if (!m_encoding_to_type_sp)
2507        m_encoding_to_type_sp.reset(new AppleObjCTypeEncodingParser(*this));
2508    return m_encoding_to_type_sp;
2509}
2510
2511lldb_private::AppleObjCRuntime::ObjCISA
2512AppleObjCRuntimeV2::GetPointerISA (ObjCISA isa)
2513{
2514    ObjCISA ret = isa;
2515
2516    if (m_non_pointer_isa_cache_ap)
2517        m_non_pointer_isa_cache_ap->EvaluateNonPointerISA(isa, ret);
2518
2519    return ret;
2520}
2521