AppleObjCRuntimeV1.cpp revision 282c22c6a6b6e54324b0d474b90d918bbfd3a10e
1//===-- AppleObjCRuntimeV1.cpp --------------------------------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "AppleObjCRuntimeV1.h" 11#include "AppleObjCTrampolineHandler.h" 12#include "AppleObjCTypeVendor.h" 13 14#include "llvm/Support/MachO.h" 15#include "clang/AST/Type.h" 16 17#include "lldb/Breakpoint/BreakpointLocation.h" 18#include "lldb/Core/ConstString.h" 19#include "lldb/Core/Error.h" 20#include "lldb/Core/Log.h" 21#include "lldb/Core/Module.h" 22#include "lldb/Core/PluginManager.h" 23#include "lldb/Core/Scalar.h" 24#include "lldb/Core/StreamString.h" 25#include "lldb/Expression/ClangFunction.h" 26#include "lldb/Expression/ClangUtilityFunction.h" 27#include "lldb/Symbol/ClangASTContext.h" 28#include "lldb/Symbol/Symbol.h" 29#include "lldb/Target/ExecutionContext.h" 30#include "lldb/Target/Process.h" 31#include "lldb/Target/RegisterContext.h" 32#include "lldb/Target/Target.h" 33#include "lldb/Target/Thread.h" 34 35#include <vector> 36 37using namespace lldb; 38using namespace lldb_private; 39 40static const char *pluginName = "AppleObjCRuntimeV1"; 41static const char *pluginDesc = "Apple Objective C Language Runtime - Version 1"; 42static const char *pluginShort = "language.apple.objc.v1"; 43 44 45AppleObjCRuntimeV1::AppleObjCRuntimeV1(Process *process) : 46 AppleObjCRuntime (process), 47 m_hash_signature (), 48 m_isa_hash_table_ptr (LLDB_INVALID_ADDRESS) 49{ 50} 51 52bool 53AppleObjCRuntimeV1::GetDynamicTypeAndAddress (ValueObject &in_value, 54 lldb::DynamicValueType use_dynamic, 55 TypeAndOrName &class_type_or_name, 56 Address &address) 57{ 58 return false; 59} 60 61//------------------------------------------------------------------ 62// Static Functions 63//------------------------------------------------------------------ 64lldb_private::LanguageRuntime * 65AppleObjCRuntimeV1::CreateInstance (Process *process, lldb::LanguageType language) 66{ 67 // FIXME: This should be a MacOS or iOS process, and we need to look for the OBJC section to make 68 // sure we aren't using the V1 runtime. 69 if (language == eLanguageTypeObjC) 70 { 71 ModuleSP objc_module_sp; 72 73 if (AppleObjCRuntime::GetObjCVersion (process, objc_module_sp) == eAppleObjC_V1) 74 return new AppleObjCRuntimeV1 (process); 75 else 76 return NULL; 77 } 78 else 79 return NULL; 80} 81 82 83void 84AppleObjCRuntimeV1::Initialize() 85{ 86 PluginManager::RegisterPlugin (pluginName, 87 pluginDesc, 88 CreateInstance); 89} 90 91void 92AppleObjCRuntimeV1::Terminate() 93{ 94 PluginManager::UnregisterPlugin (CreateInstance); 95} 96 97//------------------------------------------------------------------ 98// PluginInterface protocol 99//------------------------------------------------------------------ 100const char * 101AppleObjCRuntimeV1::GetPluginName() 102{ 103 return pluginName; 104} 105 106const char * 107AppleObjCRuntimeV1::GetShortPluginName() 108{ 109 return pluginShort; 110} 111 112uint32_t 113AppleObjCRuntimeV1::GetPluginVersion() 114{ 115 return 1; 116} 117 118BreakpointResolverSP 119AppleObjCRuntimeV1::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp) 120{ 121 BreakpointResolverSP resolver_sp; 122 123 if (throw_bp) 124 resolver_sp.reset (new BreakpointResolverName (bkpt, 125 "objc_exception_throw", 126 eFunctionNameTypeBase, 127 Breakpoint::Exact, 128 eLazyBoolNo)); 129 // FIXME: don't do catch yet. 130 return resolver_sp; 131} 132 133struct BufStruct { 134 char contents[2048]; 135}; 136 137ClangUtilityFunction * 138AppleObjCRuntimeV1::CreateObjectChecker(const char *name) 139{ 140 std::auto_ptr<BufStruct> buf(new BufStruct); 141 142 assert(snprintf(&buf->contents[0], sizeof(buf->contents), 143 "struct __objc_class \n" 144 "{ \n" 145 " struct __objc_class *isa; \n" 146 " struct __objc_class *super_class; \n" 147 " const char *name; \n" 148 " // rest of struct elided because unused \n" 149 "}; \n" 150 " \n" 151 "struct __objc_object \n" 152 "{ \n" 153 " struct __objc_class *isa; \n" 154 "}; \n" 155 " \n" 156 "extern \"C\" void \n" 157 "%s(void *$__lldb_arg_obj, void *$__lldb_arg_selector) \n" 158 "{ \n" 159 " struct __objc_object *obj = (struct __objc_object*)$__lldb_arg_obj; \n" 160 " (int)strlen(obj->isa->name); \n" 161 "} \n", 162 name) < sizeof(buf->contents)); 163 164 return new ClangUtilityFunction(buf->contents, name); 165} 166 167// this code relies on the assumption that an Objective-C object always starts 168// with an ISA at offset 0. 169//ObjCLanguageRuntime::ObjCISA 170//AppleObjCRuntimeV1::GetISA(ValueObject& valobj) 171//{ 172//// if (ClangASTType::GetMinimumLanguage(valobj.GetClangAST(),valobj.GetClangType()) != eLanguageTypeObjC) 173//// return 0; 174// 175// // if we get an invalid VO (which might still happen when playing around 176// // with pointers returned by the expression parser, don't consider this 177// // a valid ObjC object) 178// if (valobj.GetValue().GetContextType() == Value::eContextTypeInvalid) 179// return 0; 180// 181// addr_t isa_pointer = valobj.GetPointerValue(); 182// 183// ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); 184// 185// Process *process = exe_ctx.GetProcessPtr(); 186// if (process) 187// { 188// uint8_t pointer_size = process->GetAddressByteSize(); 189// 190// Error error; 191// return process->ReadUnsignedIntegerFromMemory (isa_pointer, 192// pointer_size, 193// 0, 194// error); 195// } 196// return 0; 197//} 198 199AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1 (ValueObject &isa_pointer) 200{ 201 Initialize (isa_pointer.GetValueAsUnsigned(0), 202 isa_pointer.GetProcessSP()); 203} 204 205AppleObjCRuntimeV1::ClassDescriptorV1::ClassDescriptorV1 (ObjCISA isa, lldb::ProcessSP process_sp) 206{ 207 Initialize (isa, process_sp); 208} 209 210void 211AppleObjCRuntimeV1::ClassDescriptorV1::Initialize (ObjCISA isa, lldb::ProcessSP process_sp) 212{ 213 if (!isa || !process_sp) 214 { 215 m_valid = false; 216 return; 217 } 218 219 m_valid = true; 220 221 Error error; 222 223 m_isa = process_sp->ReadPointerFromMemory(isa, error); 224 225 if (error.Fail()) 226 { 227 m_valid = false; 228 return; 229 } 230 231 uint32_t ptr_size = process_sp->GetAddressByteSize(); 232 233 if (!IsPointerValid(m_isa,ptr_size)) 234 { 235 m_valid = false; 236 return; 237 } 238 239 m_parent_isa = process_sp->ReadPointerFromMemory(m_isa + ptr_size,error); 240 241 if (error.Fail()) 242 { 243 m_valid = false; 244 return; 245 } 246 247 if (!IsPointerValid(m_parent_isa,ptr_size,true)) 248 { 249 m_valid = false; 250 return; 251 } 252 253 lldb::addr_t name_ptr = process_sp->ReadPointerFromMemory(m_isa + 2 * ptr_size,error); 254 255 if (error.Fail()) 256 { 257 m_valid = false; 258 return; 259 } 260 261 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); 262 263 size_t count = process_sp->ReadCStringFromMemory(name_ptr, (char*)buffer_sp->GetBytes(), 1024, error); 264 265 if (error.Fail()) 266 { 267 m_valid = false; 268 return; 269 } 270 271 if (count) 272 m_name = ConstString((char*)buffer_sp->GetBytes()); 273 else 274 m_name = ConstString(); 275 276 m_instance_size = process_sp->ReadUnsignedIntegerFromMemory(m_isa + 5 * ptr_size, ptr_size, 0, error); 277 278 if (error.Fail()) 279 { 280 m_valid = false; 281 return; 282 } 283 284 m_process_wp = lldb::ProcessWP(process_sp); 285} 286 287AppleObjCRuntime::ClassDescriptorSP 288AppleObjCRuntimeV1::ClassDescriptorV1::GetSuperclass () 289{ 290 if (!m_valid) 291 return AppleObjCRuntime::ClassDescriptorSP(); 292 ProcessSP process_sp = m_process_wp.lock(); 293 if (!process_sp) 294 return AppleObjCRuntime::ClassDescriptorSP(); 295 return ObjCLanguageRuntime::ClassDescriptorSP(new AppleObjCRuntimeV1::ClassDescriptorV1(m_parent_isa,process_sp)); 296} 297 298bool 299AppleObjCRuntimeV1::ClassDescriptorV1::Describe (std::function <void (ObjCLanguageRuntime::ObjCISA)> const &superclass_func, 300 std::function <bool (const char *, const char *)> const &instance_method_func, 301 std::function <bool (const char *, const char *)> const &class_method_func, 302 std::function <bool (const char *, const char *, lldb::addr_t, uint64_t)> const &ivar_func) 303{ 304 return false; 305} 306 307lldb::addr_t 308AppleObjCRuntimeV1::GetISAHashTablePointer () 309{ 310 if (m_isa_hash_table_ptr == LLDB_INVALID_ADDRESS) 311 { 312 ModuleSP objc_module_sp(GetObjCModule()); 313 314 if (!objc_module_sp) 315 return LLDB_INVALID_ADDRESS; 316 317 static ConstString g_objc_debug_class_hash("_objc_debug_class_hash"); 318 319 const Symbol *symbol = objc_module_sp->FindFirstSymbolWithNameAndType(g_objc_debug_class_hash, lldb::eSymbolTypeData); 320 if (symbol) 321 { 322 Process *process = GetProcess(); 323 if (process) 324 { 325 326 lldb::addr_t objc_debug_class_hash_addr = symbol->GetAddress().GetLoadAddress(&process->GetTarget()); 327 328 if (objc_debug_class_hash_addr != LLDB_INVALID_ADDRESS) 329 { 330 Error error; 331 lldb::addr_t objc_debug_class_hash_ptr = process->ReadPointerFromMemory(objc_debug_class_hash_addr, error); 332 if (objc_debug_class_hash_ptr != 0 && 333 objc_debug_class_hash_ptr != LLDB_INVALID_ADDRESS) 334 { 335 m_isa_hash_table_ptr = objc_debug_class_hash_ptr; 336 } 337 } 338 } 339 } 340 } 341 return m_isa_hash_table_ptr; 342} 343 344void 345AppleObjCRuntimeV1::UpdateISAToDescriptorMapIfNeeded() 346{ 347 // TODO: implement HashTableSignature... 348 Process *process = GetProcess(); 349 350 if (process) 351 { 352 // Update the process stop ID that indicates the last time we updated the 353 // map, wether it was successful or not. 354 m_isa_to_descriptor_cache_stop_id = process->GetStopID(); 355 356 357 lldb::LogSP log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); 358 359 ProcessSP process_sp = process->shared_from_this(); 360 361 ModuleSP objc_module_sp(GetObjCModule()); 362 363 if (!objc_module_sp) 364 return; 365 366 uint32_t isa_count = 0; 367 368 lldb::addr_t hash_table_ptr = GetISAHashTablePointer (); 369 if (hash_table_ptr != LLDB_INVALID_ADDRESS) 370 { 371 // Read the NXHashTable struct: 372 // 373 // typedef struct { 374 // const NXHashTablePrototype *prototype; 375 // unsigned count; 376 // unsigned nbBuckets; 377 // void *buckets; 378 // const void *info; 379 // } NXHashTable; 380 381 Error error; 382 DataBufferHeap buffer(1024, 0); 383 if (process->ReadMemory(hash_table_ptr, buffer.GetBytes(), 20, error) == 20) 384 { 385 const uint32_t addr_size = m_process->GetAddressByteSize(); 386 const ByteOrder byte_order = m_process->GetByteOrder(); 387 DataExtractor data (buffer.GetBytes(), buffer.GetByteSize(), byte_order, addr_size); 388 uint32_t offset = addr_size; // Skip prototype 389 const uint32_t count = data.GetU32(&offset); 390 const uint32_t num_buckets = data.GetU32(&offset); 391 const addr_t buckets_ptr = data.GetPointer(&offset); 392 if (m_hash_signature.NeedsUpdate (count, num_buckets, buckets_ptr)) 393 { 394 m_hash_signature.UpdateSignature (count, num_buckets, buckets_ptr); 395 396 const uint32_t data_size = num_buckets * 2 * sizeof(uint32_t); 397 buffer.SetByteSize(data_size); 398 399 if (process->ReadMemory(buckets_ptr, buffer.GetBytes(), data_size, error) == data_size) 400 { 401 data.SetData(buffer.GetBytes(), buffer.GetByteSize(), byte_order); 402 offset = 0; 403 for (uint32_t bucket_idx = 0; bucket_idx < num_buckets; ++bucket_idx) 404 { 405 const uint32_t bucket_isa_count = data.GetU32 (&offset); 406 const lldb::addr_t bucket_data = data.GetU32 (&offset); 407 408 409 if (bucket_isa_count == 0) 410 continue; 411 412 isa_count += bucket_isa_count; 413 414 ObjCISA isa; 415 if (bucket_isa_count == 1) 416 { 417 // When we only have one entry in the bucket, the bucket data is the "isa" 418 isa = bucket_data; 419 if (isa) 420 { 421 if (m_isa_to_descriptor_cache.count(isa) == 0) 422 { 423 ClassDescriptorSP descriptor_sp (new ClassDescriptorV1(isa, process_sp)); 424 425 if (log && log->GetVerbose()) 426 log->Printf("AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64 " from _objc_debug_class_hash to isa->descriptor cache", isa); 427 428 m_isa_to_descriptor_cache[isa] = descriptor_sp; 429 } 430 } 431 } 432 else 433 { 434 // When we have more than one entry in the bucket, the bucket data is a pointer 435 // to an array of "isa" values 436 addr_t isa_addr = bucket_data; 437 for (uint32_t isa_idx = 0; isa_idx < bucket_isa_count; ++isa_idx, isa_addr += addr_size) 438 { 439 isa = m_process->ReadPointerFromMemory(isa_addr, error); 440 441 if (isa && isa != LLDB_INVALID_ADDRESS) 442 { 443 if (m_isa_to_descriptor_cache.count(isa) == 0) 444 { 445 ClassDescriptorSP descriptor_sp (new ClassDescriptorV1(isa, process_sp)); 446 447 if (log && log->GetVerbose()) 448 log->Printf("AppleObjCRuntimeV1 added (ObjCISA)0x%" PRIx64 " from _objc_debug_class_hash to isa->descriptor cache", isa); 449 450 m_isa_to_descriptor_cache[isa] = descriptor_sp; 451 } 452 } 453 } 454 } 455 } 456 } 457 } 458 } 459 } 460 } 461 else 462 { 463 m_isa_to_descriptor_cache_stop_id = UINT32_MAX; 464 } 465} 466 467TypeVendor * 468AppleObjCRuntimeV1::GetTypeVendor() 469{ 470 if (!m_type_vendor_ap.get()) 471 m_type_vendor_ap.reset(new AppleObjCTypeVendor(*this)); 472 473 return m_type_vendor_ap.get(); 474} 475