1 //===-- AppleObjCRuntimeV1.cpp --------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "AppleObjCRuntimeV1.h"
11 #include "AppleObjCTrampolineHandler.h"
12 #include "AppleObjCDeclVendor.h"
14 #include "clang/AST/Type.h"
16 #include "lldb/Breakpoint/BreakpointLocation.h"
17 #include "lldb/Core/ConstString.h"
18 #include "lldb/Core/Error.h"
19 #include "lldb/Core/Log.h"
20 #include "lldb/Core/Module.h"
21 #include "lldb/Core/PluginManager.h"
22 #include "lldb/Core/Scalar.h"
23 #include "lldb/Core/StreamString.h"
24 #include "lldb/Expression/FunctionCaller.h"
25 #include "lldb/Expression/UtilityFunction.h"
26 #include "lldb/Symbol/ClangASTContext.h"
27 #include "lldb/Symbol/Symbol.h"
28 #include "lldb/Target/ExecutionContext.h"
29 #include "lldb/Target/Process.h"
30 #include "lldb/Target/RegisterContext.h"
31 #include "lldb/Target/Target.h"
32 #include "lldb/Target/Thread.h"
37 using namespace lldb_private;
39 AppleObjCRuntimeV1::AppleObjCRuntimeV1(Process *process) :
40 AppleObjCRuntime (process),
42 m_isa_hash_table_ptr (LLDB_INVALID_ADDRESS)
46 // for V1 runtime we just try to return a class name as that is the minimum level of support
47 // required for the data formatters to work
49 AppleObjCRuntimeV1::GetDynamicTypeAndAddress (ValueObject &in_value,
50 lldb::DynamicValueType use_dynamic,
51 TypeAndOrName &class_type_or_name,
53 Value::ValueType &value_type)
55 class_type_or_name.Clear();
56 value_type = Value::ValueType::eValueTypeScalar;
57 if (CouldHaveDynamicValue(in_value))
59 auto class_descriptor(GetClassDescriptor(in_value));
60 if (class_descriptor && class_descriptor->IsValid() && class_descriptor->GetClassName())
62 const addr_t object_ptr = in_value.GetPointerValue();
63 address.SetRawAddress(object_ptr);
64 class_type_or_name.SetName(class_descriptor->GetClassName());
67 return class_type_or_name.IsEmpty() == false;
70 //------------------------------------------------------------------
72 //------------------------------------------------------------------
73 lldb_private::LanguageRuntime *
74 AppleObjCRuntimeV1::CreateInstance (Process *process, lldb::LanguageType language)
76 // FIXME: This should be a MacOS or iOS process, and we need to look for the OBJC section to make
77 // sure we aren't using the V1 runtime.
78 if (language == eLanguageTypeObjC)
80 ModuleSP objc_module_sp;
82 if (AppleObjCRuntime::GetObjCVersion (process, objc_module_sp) == ObjCRuntimeVersions::eAppleObjC_V1)
83 return new AppleObjCRuntimeV1 (process);
93 AppleObjCRuntimeV1::Initialize()
95 PluginManager::RegisterPlugin (GetPluginNameStatic(),
96 "Apple Objective C Language Runtime - Version 1",
101 AppleObjCRuntimeV1::Terminate()
103 PluginManager::UnregisterPlugin (CreateInstance);
106 lldb_private::ConstString
107 AppleObjCRuntimeV1::GetPluginNameStatic()
109 static ConstString g_name("apple-objc-v1");
113 //------------------------------------------------------------------
114 // PluginInterface protocol
115 //------------------------------------------------------------------
117 AppleObjCRuntimeV1::GetPluginName()
119 return GetPluginNameStatic();
123 AppleObjCRuntimeV1::GetPluginVersion()
129 AppleObjCRuntimeV1::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp)
131 BreakpointResolverSP resolver_sp;
134 resolver_sp.reset (new BreakpointResolverName (bkpt,
135 "objc_exception_throw",
136 eFunctionNameTypeBase,
137 eLanguageTypeUnknown,
141 // FIXME: don't do catch yet.
150 AppleObjCRuntimeV1::CreateObjectChecker(const char *name)
152 std::unique_ptr<BufStruct> buf(new BufStruct);
154 assert(snprintf(&buf->contents[0], sizeof(buf->contents),
155 "struct __objc_class \n"
157 " struct __objc_class *isa; \n"
158 " struct __objc_class *super_class; \n"
159 " const char *name; \n"
160 " // rest of struct elided because unused \n"
163 "struct __objc_object \n"
165 " struct __objc_class *isa; \n"
168 "extern \"C\" void \n"
169 "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) \n"
171 " struct __objc_object *obj = (struct __objc_object*)$__lldb_arg_obj; \n"
172 " (int)strlen(obj->isa->name); \n"
174 name) < (int)sizeof(buf->contents));
177 return GetTargetRef().GetUtilityFunctionForLanguage(buf->contents, eLanguageTypeObjC, name, error);
180 AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1 (ValueObject &isa_pointer)
182 Initialize (isa_pointer.GetValueAsUnsigned(0),
183 isa_pointer.GetProcessSP());
186 AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1 (ObjCISA isa, lldb::ProcessSP process_sp)
188 Initialize (isa, process_sp);
192 AppleObjCRuntimeV1::ClassDescriptorV1::Initialize (ObjCISA isa, lldb::ProcessSP process_sp)
194 if (!isa || !process_sp)
204 m_isa = process_sp->ReadPointerFromMemory(isa, error);
212 uint32_t ptr_size = process_sp->GetAddressByteSize();
214 if (!IsPointerValid(m_isa,ptr_size))
220 m_parent_isa = process_sp->ReadPointerFromMemory(m_isa + ptr_size,error);
228 if (!IsPointerValid(m_parent_isa,ptr_size,true))
234 lldb::addr_t name_ptr = process_sp->ReadPointerFromMemory(m_isa + 2 * ptr_size,error);
242 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0));
244 size_t count = process_sp->ReadCStringFromMemory(name_ptr, (char*)buffer_sp->GetBytes(), 1024, error);
253 m_name = ConstString((char*)buffer_sp->GetBytes());
255 m_name = ConstString();
257 m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(m_isa + 5 * ptr_size, ptr_size, 0, error);
265 m_process_wp = lldb::ProcessWP(process_sp);
268 AppleObjCRuntime::ClassDescriptorSP
269 AppleObjCRuntimeV1::ClassDescriptorV1::GetSuperclass ()
272 return AppleObjCRuntime::ClassDescriptorSP();
273 ProcessSP process_sp = m_process_wp.lock();
275 return AppleObjCRuntime::ClassDescriptorSP();
276 return ObjCLanguageRuntime::ClassDescriptorSP(new AppleObjCRuntimeV1::ClassDescriptorV1(m_parent_isa,process_sp));
279 AppleObjCRuntime::ClassDescriptorSP
280 AppleObjCRuntimeV1::ClassDescriptorV1::GetMetaclass () const
282 return ClassDescriptorSP();
286 AppleObjCRuntimeV1::ClassDescriptorV1::Describe (std::function <void (ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
287 std::function <bool (const char *, const char *)> const &instance_method_func,
288 std::function <bool (const char *, const char *)> const &class_method_func,
289 std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func) const
295 AppleObjCRuntimeV1::GetISAHashTablePointer ()
297 if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS)
299 ModuleSP objc_module_sp(GetObjCModule());
302 return LLDB_INVALID_ADDRESS;
304 static ConstString g_objc_debug_class_hash("_objc_debug_class_hash");
306 const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(g_objc_debug_class_hash, lldb::eSymbolTypeData);
307 if (symbol && symbol->ValueIsAddress())
309 Process *process = GetProcess();
313 lldb::addr_t objc_debug_class_hash_addr = symbol->GetAddressRef().GetLoadAddress(&process->GetTarget());
315 if (objc_debug_class_hash_addr != LLDB_INVALID_ADDRESS)
318 lldb::addr_t objc_debug_class_hash_ptr = process->ReadPointerFromMemory(objc_debug_class_hash_addr, error);
319 if (objc_debug_class_hash_ptr != 0 &&
320 objc_debug_class_hash_ptr != LLDB_INVALID_ADDRESS)
322 m_isa_hash_table_ptr = objc_debug_class_hash_ptr;
328 return m_isa_hash_table_ptr;
332 AppleObjCRuntimeV1::UpdateISAToDescriptorMapIfNeeded()
334 // TODO: implement HashTableSignature...
335 Process *process = GetProcess();
339 // Update the process stop ID that indicates the last time we updated the
340 // map, whether it was successful or not.
341 m_isa_to_descriptor_stop_id = process->GetStopID();
343 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
345 ProcessSP process_sp = process->shared_from_this();
347 ModuleSP objc_module_sp(GetObjCModule());
352 uint32_t isa_count = 0;
354 lldb::addr_t hash_table_ptr = GetISAHashTablePointer ();
355 if (hash_table_ptr != LLDB_INVALID_ADDRESS)
357 // Read the NXHashTable struct:
360 // const NXHashTablePrototype *prototype;
362 // unsigned nbBuckets;
368 DataBufferHeap buffer(1024, 0);
369 if (process->ReadMemory(hash_table_ptr, buffer.GetBytes(), 20, error) == 20)
371 const uint32_t addr_size = m_process->GetAddressByteSize();
372 const ByteOrder byte_order = m_process->GetByteOrder();
373 DataExtractor data (buffer.GetBytes(), buffer.GetByteSize(), byte_order, addr_size);
374 lldb::offset_t offset = addr_size; // Skip prototype
375 const uint32_t count = data.GetU32(&offset);
376 const uint32_t num_buckets = data.GetU32(&offset);
377 const addr_t buckets_ptr = data.GetPointer(&offset);
378 if (m_hash_signature.NeedsUpdate (count, num_buckets, buckets_ptr))
380 m_hash_signature.UpdateSignature (count, num_buckets, buckets_ptr);
382 const uint32_t data_size = num_buckets * 2 * sizeof(uint32_t);
383 buffer.SetByteSize(data_size);
385 if (process->ReadMemory(buckets_ptr, buffer.GetBytes(), data_size, error) == data_size)
387 data.SetData(buffer.GetBytes(), buffer.GetByteSize(), byte_order);
389 for (uint32_t bucket_idx = 0; bucket_idx < num_buckets; ++bucket_idx)
391 const uint32_t bucket_isa_count = data.GetU32 (&offset);
392 const lldb::addr_t bucket_data = data.GetU32 (&offset);
395 if (bucket_isa_count == 0)
398 isa_count += bucket_isa_count;
401 if (bucket_isa_count == 1)
403 // When we only have one entry in the bucket, the bucket data is the "isa"
407 if (!ISAIsCached(isa))
409 ClassDescriptorSP descriptor_sp (new ClassDescriptorV1(isa, process_sp));
411 if (log && log->GetVerbose())
412 log->Printf("AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64 " from _objc_debug_class_hash to isa->descriptor cache", isa);
414 AddClass (isa, descriptor_sp);
420 // When we have more than one entry in the bucket, the bucket data is a pointer
421 // to an array of "isa" values
422 addr_t isa_addr = bucket_data;
423 for (uint32_t isa_idx = 0; isa_idx < bucket_isa_count; ++isa_idx, isa_addr += addr_size)
425 isa = m_process->ReadPointerFromMemory(isa_addr, error);
427 if (isa && isa != LLDB_INVALID_ADDRESS)
429 if (!ISAIsCached(isa))
431 ClassDescriptorSP descriptor_sp (new ClassDescriptorV1(isa, process_sp));
433 if (log && log->GetVerbose())
434 log->Printf("AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64 " from _objc_debug_class_hash to isa->descriptor cache", isa);
436 AddClass (isa, descriptor_sp);
449 m_isa_to_descriptor_stop_id = UINT32_MAX;
454 AppleObjCRuntimeV1::GetDeclVendor()
456 if (!m_decl_vendor_ap.get())
457 m_decl_vendor_ap.reset(new AppleObjCDeclVendor(*this));
459 return m_decl_vendor_ap.get();