LLDB  mainline
AppleObjCRuntimeV1.cpp
Go to the documentation of this file.
1 //===-- AppleObjCRuntimeV1.cpp --------------------------------------*- C++
2 //-*-===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "AppleObjCRuntimeV1.h"
11 #include "AppleObjCDeclVendor.h"
13 
14 #include "clang/AST/Type.h"
15 
17 #include "lldb/Core/Module.h"
22 #include "lldb/Symbol/Symbol.h"
24 #include "lldb/Target/Process.h"
26 #include "lldb/Target/Target.h"
27 #include "lldb/Target/Thread.h"
29 #include "lldb/Utility/Log.h"
30 #include "lldb/Utility/Scalar.h"
31 #include "lldb/Utility/Status.h"
33 
34 #include <memory>
35 #include <vector>
36 
37 using namespace lldb;
38 using namespace lldb_private;
39 
40 AppleObjCRuntimeV1::AppleObjCRuntimeV1(Process *process)
41  : AppleObjCRuntime(process), m_hash_signature(),
42  m_isa_hash_table_ptr(LLDB_INVALID_ADDRESS) {}
43 
44 // for V1 runtime we just try to return a class name as that is the minimum
45 // level of support required for the data formatters to work
47  ValueObject &in_value, lldb::DynamicValueType use_dynamic,
48  TypeAndOrName &class_type_or_name, Address &address,
49  Value::ValueType &value_type) {
50  class_type_or_name.Clear();
51  value_type = Value::ValueType::eValueTypeScalar;
52  if (CouldHaveDynamicValue(in_value)) {
53  auto class_descriptor(GetClassDescriptor(in_value));
54  if (class_descriptor && class_descriptor->IsValid() &&
55  class_descriptor->GetClassName()) {
56  const addr_t object_ptr = in_value.GetPointerValue();
57  address.SetRawAddress(object_ptr);
58  class_type_or_name.SetName(class_descriptor->GetClassName());
59  }
60  }
61  return !class_type_or_name.IsEmpty();
62 }
63 
64 // Static Functions
67  lldb::LanguageType language) {
68  // FIXME: This should be a MacOS or iOS process, and we need to look for the
69  // OBJC section to make
70  // sure we aren't using the V1 runtime.
71  if (language == eLanguageTypeObjC) {
72  ModuleSP objc_module_sp;
73 
74  if (AppleObjCRuntime::GetObjCVersion(process, objc_module_sp) ==
76  return new AppleObjCRuntimeV1(process);
77  else
78  return NULL;
79  } else
80  return NULL;
81 }
82 
85  GetPluginNameStatic(), "Apple Objective-C Language Runtime - Version 1",
86  CreateInstance);
87 }
88 
90  PluginManager::UnregisterPlugin(CreateInstance);
91 }
92 
94  static ConstString g_name("apple-objc-v1");
95  return g_name;
96 }
97 
98 // PluginInterface protocol
100  return GetPluginNameStatic();
101 }
102 
104 
105 BreakpointResolverSP
107  bool throw_bp) {
108  BreakpointResolverSP resolver_sp;
109 
110  if (throw_bp)
111  resolver_sp = std::make_shared<BreakpointResolverName>(
112  bkpt, std::get<1>(GetExceptionThrowLocation()).AsCString(),
113  eFunctionNameTypeBase, eLanguageTypeUnknown, Breakpoint::Exact, 0,
114  eLazyBoolNo);
115  // FIXME: don't do catch yet.
116  return resolver_sp;
117 }
118 
119 struct BufStruct {
120  char contents[2048];
121 };
122 
124  std::unique_ptr<BufStruct> buf(new BufStruct);
125 
126  int strformatsize = snprintf(&buf->contents[0], sizeof(buf->contents),
127  "struct __objc_class "
128  " \n"
129  "{ "
130  " \n"
131  " struct __objc_class *isa; "
132  " \n"
133  " struct __objc_class *super_class; "
134  " \n"
135  " const char *name; "
136  " \n"
137  " // rest of struct elided because unused "
138  " \n"
139  "}; "
140  " \n"
141  " "
142  " \n"
143  "struct __objc_object "
144  " \n"
145  "{ "
146  " \n"
147  " struct __objc_class *isa; "
148  " \n"
149  "}; "
150  " \n"
151  " "
152  " \n"
153  "extern \"C\" void "
154  " \n"
155  "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) "
156  " \n"
157  "{ "
158  " \n"
159  " struct __objc_object *obj = (struct "
160  "__objc_object*)$__lldb_arg_obj; \n"
161  " if ($__lldb_arg_obj == (void *)0) "
162  " \n"
163  " return; // nil is ok "
164  " (int)strlen(obj->isa->name); "
165  " \n"
166  "} "
167  " \n",
168  name);
169  assert(strformatsize < (int)sizeof(buf->contents));
170  (void)strformatsize;
171 
172  Status error;
174  buf->contents, eLanguageTypeObjC, name, error);
175 }
176 
178  ValueObject &isa_pointer) {
179  Initialize(isa_pointer.GetValueAsUnsigned(0), isa_pointer.GetProcessSP());
180 }
181 
183  ObjCISA isa, lldb::ProcessSP process_sp) {
184  Initialize(isa, process_sp);
185 }
186 
188  ObjCISA isa, lldb::ProcessSP process_sp) {
189  if (!isa || !process_sp) {
190  m_valid = false;
191  return;
192  }
193 
194  m_valid = true;
195 
196  Status error;
197 
198  m_isa = process_sp->ReadPointerFromMemory(isa, error);
199 
200  if (error.Fail()) {
201  m_valid = false;
202  return;
203  }
204 
205  uint32_t ptr_size = process_sp->GetAddressByteSize();
206 
207  if (!IsPointerValid(m_isa, ptr_size)) {
208  m_valid = false;
209  return;
210  }
211 
212  m_parent_isa = process_sp->ReadPointerFromMemory(m_isa + ptr_size, error);
213 
214  if (error.Fail()) {
215  m_valid = false;
216  return;
217  }
218 
219  if (!IsPointerValid(m_parent_isa, ptr_size, true)) {
220  m_valid = false;
221  return;
222  }
223 
224  lldb::addr_t name_ptr =
225  process_sp->ReadPointerFromMemory(m_isa + 2 * ptr_size, error);
226 
227  if (error.Fail()) {
228  m_valid = false;
229  return;
230  }
231 
232  lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
233 
234  size_t count = process_sp->ReadCStringFromMemory(
235  name_ptr, (char *)buffer_sp->GetBytes(), 1024, error);
236 
237  if (error.Fail()) {
238  m_valid = false;
239  return;
240  }
241 
242  if (count)
243  m_name = ConstString((char *)buffer_sp->GetBytes());
244  else
245  m_name = ConstString();
246 
247  m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(
248  m_isa + 5 * ptr_size, ptr_size, 0, error);
249 
250  if (error.Fail()) {
251  m_valid = false;
252  return;
253  }
254 
255  m_process_wp = lldb::ProcessWP(process_sp);
256 }
257 
260  if (!m_valid)
262  ProcessSP process_sp = m_process_wp.lock();
263  if (!process_sp)
266  new AppleObjCRuntimeV1::ClassDescriptorV1(m_parent_isa, process_sp));
267 }
268 
271  return ClassDescriptorSP();
272 }
273 
275  std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
276  std::function<bool(const char *, const char *)> const &instance_method_func,
277  std::function<bool(const char *, const char *)> const &class_method_func,
278  std::function<bool(const char *, const char *, lldb::addr_t,
279  uint64_t)> const &ivar_func) const {
280  return false;
281 }
282 
284  return 0;
285 }
286 
288  if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) {
289  ModuleSP objc_module_sp(GetObjCModule());
290 
291  if (!objc_module_sp)
292  return LLDB_INVALID_ADDRESS;
293 
294  static ConstString g_objc_debug_class_hash("_objc_debug_class_hash");
295 
296  const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(
297  g_objc_debug_class_hash, lldb::eSymbolTypeData);
298  if (symbol && symbol->ValueIsAddress()) {
299  Process *process = GetProcess();
300  if (process) {
301 
302  lldb::addr_t objc_debug_class_hash_addr =
303  symbol->GetAddressRef().GetLoadAddress(&process->GetTarget());
304 
305  if (objc_debug_class_hash_addr != LLDB_INVALID_ADDRESS) {
306  Status error;
307  lldb::addr_t objc_debug_class_hash_ptr =
308  process->ReadPointerFromMemory(objc_debug_class_hash_addr, error);
309  if (objc_debug_class_hash_ptr != 0 &&
310  objc_debug_class_hash_ptr != LLDB_INVALID_ADDRESS) {
311  m_isa_hash_table_ptr = objc_debug_class_hash_ptr;
312  }
313  }
314  }
315  }
316  }
317  return m_isa_hash_table_ptr;
318 }
319 
321  // TODO: implement HashTableSignature...
322  Process *process = GetProcess();
323 
324  if (process) {
325  // Update the process stop ID that indicates the last time we updated the
326  // map, whether it was successful or not.
328 
330 
331  ProcessSP process_sp = process->shared_from_this();
332 
333  ModuleSP objc_module_sp(GetObjCModule());
334 
335  if (!objc_module_sp)
336  return;
337 
338  uint32_t isa_count = 0;
339 
340  lldb::addr_t hash_table_ptr = GetISAHashTablePointer();
341  if (hash_table_ptr != LLDB_INVALID_ADDRESS) {
342  // Read the NXHashTable struct:
343  //
344  // typedef struct {
345  // const NXHashTablePrototype *prototype;
346  // unsigned count;
347  // unsigned nbBuckets;
348  // void *buckets;
349  // const void *info;
350  // } NXHashTable;
351 
352  Status error;
353  DataBufferHeap buffer(1024, 0);
354  if (process->ReadMemory(hash_table_ptr, buffer.GetBytes(), 20, error) ==
355  20) {
356  const uint32_t addr_size = m_process->GetAddressByteSize();
357  const ByteOrder byte_order = m_process->GetByteOrder();
358  DataExtractor data(buffer.GetBytes(), buffer.GetByteSize(), byte_order,
359  addr_size);
360  lldb::offset_t offset = addr_size; // Skip prototype
361  const uint32_t count = data.GetU32(&offset);
362  const uint32_t num_buckets = data.GetU32(&offset);
363  const addr_t buckets_ptr = data.GetPointer(&offset);
364  if (m_hash_signature.NeedsUpdate(count, num_buckets, buckets_ptr)) {
365  m_hash_signature.UpdateSignature(count, num_buckets, buckets_ptr);
366 
367  const uint32_t data_size = num_buckets * 2 * sizeof(uint32_t);
368  buffer.SetByteSize(data_size);
369 
370  if (process->ReadMemory(buckets_ptr, buffer.GetBytes(), data_size,
371  error) == data_size) {
372  data.SetData(buffer.GetBytes(), buffer.GetByteSize(), byte_order);
373  offset = 0;
374  for (uint32_t bucket_idx = 0; bucket_idx < num_buckets;
375  ++bucket_idx) {
376  const uint32_t bucket_isa_count = data.GetU32(&offset);
377  const lldb::addr_t bucket_data = data.GetU32(&offset);
378 
379  if (bucket_isa_count == 0)
380  continue;
381 
382  isa_count += bucket_isa_count;
383 
384  ObjCISA isa;
385  if (bucket_isa_count == 1) {
386  // When we only have one entry in the bucket, the bucket data
387  // is the "isa"
388  isa = bucket_data;
389  if (isa) {
390  if (!ISAIsCached(isa)) {
391  ClassDescriptorSP descriptor_sp(
392  new ClassDescriptorV1(isa, process_sp));
393 
394  if (log && log->GetVerbose())
395  log->Printf("AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64
396  " from _objc_debug_class_hash to "
397  "isa->descriptor cache",
398  isa);
399 
400  AddClass(isa, descriptor_sp);
401  }
402  }
403  } else {
404  // When we have more than one entry in the bucket, the bucket
405  // data is a pointer to an array of "isa" values
406  addr_t isa_addr = bucket_data;
407  for (uint32_t isa_idx = 0; isa_idx < bucket_isa_count;
408  ++isa_idx, isa_addr += addr_size) {
409  isa = m_process->ReadPointerFromMemory(isa_addr, error);
410 
411  if (isa && isa != LLDB_INVALID_ADDRESS) {
412  if (!ISAIsCached(isa)) {
413  ClassDescriptorSP descriptor_sp(
414  new ClassDescriptorV1(isa, process_sp));
415 
416  if (log && log->GetVerbose())
417  log->Printf(
418  "AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64
419  " from _objc_debug_class_hash to isa->descriptor "
420  "cache",
421  isa);
422 
423  AddClass(isa, descriptor_sp);
424  }
425  }
426  }
427  }
428  }
429  }
430  }
431  }
432  }
433  } else {
435  }
436 }
437 
439  return nullptr;
440 }
Address & GetAddressRef()
Definition: Symbol.h:56
bool AddClass(ObjCISA isa, const ClassDescriptorSP &descriptor_sp)
An data extractor class.
Definition: DataExtractor.h:47
bool GetDynamicTypeAndAddress(ValueObject &in_value, lldb::DynamicValueType use_dynamic, TypeAndOrName &class_type_or_name, Address &address, Value::ValueType &value_type) override
bool Describe(std::function< void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func, std::function< bool(const char *, const char *)> const &instance_method_func, std::function< bool(const char *, const char *)> const &class_method_func, std::function< bool(const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func) const override
#define LIBLLDB_LOG_PROCESS
Definition: Logging.h:15
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
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
lldb::addr_t GetLoadAddress(Target *target) const
Get the load address.
Definition: Address.cpp:292
General Outline: A breakpoint has four main parts, a filter, a resolver, the list of breakpoint locat...
Definition: Breakpoint.h:78
void Initialize(ObjCISA isa, lldb::ProcessSP process_sp)
DeclVendor * GetDeclVendor() override
static bool RegisterPlugin(ConstString name, const char *description, ABICreateInstance create_callback)
lldb::offset_t SetByteSize(lldb::offset_t byte_size)
Set the number of bytes in the data buffer.
ConstString GetPluginName() override
static std::tuple< FileSpec, ConstString > GetExceptionThrowLocation()
lldb::ByteOrder GetByteOrder() const
Definition: Process.cpp:3366
std::shared_ptr< ClassDescriptor > ClassDescriptorSP
void SetName(ConstString type_name)
Definition: Type.cpp:726
UtilityFunction * CreateObjectChecker(const char *) override
lldb::addr_t GetPointerValue(AddressType *address_type=nullptr)
A subclass of DataBuffer that stores a data buffer on the heap.
static lldb_private::LanguageRuntime * CreateInstance(Process *process, lldb::LanguageType language)
lldb::BreakpointResolverSP CreateExceptionResolver(Breakpoint *bkpt, bool catch_bp, bool throw_bp) override
#define UINT32_MAX
Definition: lldb-defines.h:31
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
LanguageType
Programming language type.
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
uint32_t GetAddressByteSize() const
Definition: Process.cpp:3370
bool ValueIsAddress() const
Definition: Symbol.cpp:114
A plug-in interface definition class for debugging a process.
Definition: Process.h:353
bool CouldHaveDynamicValue(ValueObject &in_value) override
bool GetVerbose() const
Definition: Log.cpp:250
void SetRawAddress(lldb::addr_t addr)
Definition: Address.h:425
A section + offset based address class.
Definition: Address.h:80
bool IsEmpty() const
Definition: Type.cpp:748
lldb::addr_t ReadPointerFromMemory(lldb::addr_t vm_addr, Status &error)
Definition: Process.cpp:2172
Target & GetTarget()
Get the target object pointer for this module.
Definition: Process.h:1194
uint64_t addr_t
Definition: lldb-types.h:83
static bool UnregisterPlugin(ABICreateInstance create_callback)
A uniqued constant string class.
Definition: ConstString.h:38
Unknown or invalid language value.
bool Fail() const
Test for error condition.
Definition: Status.cpp:181
lldb::ProcessSP GetProcessSP() const
Definition: ValueObject.h:361
virtual uint64_t GetValueAsUnsigned(uint64_t fail_value, bool *success=nullptr)
Definition: SBAddress.h:15
static lldb_private::ConstString GetPluginNameStatic()
uint8_t * GetBytes() override
virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value)
static ObjCRuntimeVersions GetObjCVersion(Process *process, lldb::ModuleSP &objc_module_sp)
"lldb/Expression/UtilityFunction.h" Encapsulates a bit of source code that provides a function that i...
lldb::offset_t GetByteSize() const override
void Printf(const char *format,...) __attribute__((format(printf
Definition: Log.cpp:113
UtilityFunction * GetUtilityFunctionForLanguage(const char *expr, lldb::LanguageType language, const char *name, Status &error)
Definition: Target.cpp:2274
An error handling class.
Definition: Status.h:44
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