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