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