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