1 //===-- AppleObjCClassDescriptorV2.cpp ------------------------------------===// 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 "AppleObjCClassDescriptorV2.h" 10 11 #include "lldb/Expression/FunctionCaller.h" 12 #include "lldb/Target/ABI.h" 13 #include "lldb/Utility/LLDBLog.h" 14 #include "lldb/Utility/Log.h" 15 16 using namespace lldb; 17 using namespace lldb_private; 18 19 bool ClassDescriptorV2::Read_objc_class( 20 Process *process, std::unique_ptr<objc_class_t> &objc_class) const { 21 objc_class = std::make_unique<objc_class_t>(); 22 23 bool ret = objc_class->Read(process, m_objc_class_ptr); 24 25 if (!ret) 26 objc_class.reset(); 27 28 return ret; 29 } 30 31 static lldb::addr_t GetClassDataMask(Process *process) { 32 switch (process->GetAddressByteSize()) { 33 case 4: 34 return 0xfffffffcUL; 35 case 8: 36 return 0x00007ffffffffff8UL; 37 default: 38 break; 39 } 40 41 return LLDB_INVALID_ADDRESS; 42 } 43 44 bool ClassDescriptorV2::objc_class_t::Read(Process *process, 45 lldb::addr_t addr) { 46 size_t ptr_size = process->GetAddressByteSize(); 47 48 size_t objc_class_size = ptr_size // uintptr_t isa; 49 + ptr_size // Class superclass; 50 + ptr_size // void *cache; 51 + ptr_size // IMP *vtable; 52 + ptr_size; // uintptr_t data_NEVER_USE; 53 54 DataBufferHeap objc_class_buf(objc_class_size, '\0'); 55 Status error; 56 57 process->ReadMemory(addr, objc_class_buf.GetBytes(), objc_class_size, error); 58 if (error.Fail()) { 59 return false; 60 } 61 62 DataExtractor extractor(objc_class_buf.GetBytes(), objc_class_size, 63 process->GetByteOrder(), 64 process->GetAddressByteSize()); 65 66 lldb::offset_t cursor = 0; 67 68 m_isa = extractor.GetAddress_unchecked(&cursor); // uintptr_t isa; 69 m_superclass = extractor.GetAddress_unchecked(&cursor); // Class superclass; 70 m_cache_ptr = extractor.GetAddress_unchecked(&cursor); // void *cache; 71 m_vtable_ptr = extractor.GetAddress_unchecked(&cursor); // IMP *vtable; 72 lldb::addr_t data_NEVER_USE = 73 extractor.GetAddress_unchecked(&cursor); // uintptr_t data_NEVER_USE; 74 75 m_flags = (uint8_t)(data_NEVER_USE & (lldb::addr_t)3); 76 m_data_ptr = data_NEVER_USE & GetClassDataMask(process); 77 78 if (ABISP abi_sp = process->GetABI()) { 79 m_isa = abi_sp->FixCodeAddress(m_isa); 80 m_superclass = abi_sp->FixCodeAddress(m_superclass); 81 } 82 return true; 83 } 84 85 bool ClassDescriptorV2::class_rw_t::Read(Process *process, lldb::addr_t addr) { 86 size_t ptr_size = process->GetAddressByteSize(); 87 88 size_t size = sizeof(uint32_t) // uint32_t flags; 89 + sizeof(uint32_t) // uint32_t version; 90 + ptr_size // const class_ro_t *ro; 91 + ptr_size // union { method_list_t **method_lists; 92 // method_list_t *method_list; }; 93 + ptr_size // struct chained_property_list *properties; 94 + ptr_size // const protocol_list_t **protocols; 95 + ptr_size // Class firstSubclass; 96 + ptr_size; // Class nextSiblingClass; 97 98 DataBufferHeap buffer(size, '\0'); 99 Status error; 100 101 process->ReadMemory(addr, buffer.GetBytes(), size, error); 102 if (error.Fail()) { 103 return false; 104 } 105 106 DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), 107 process->GetAddressByteSize()); 108 109 lldb::offset_t cursor = 0; 110 111 m_flags = extractor.GetU32_unchecked(&cursor); 112 m_version = extractor.GetU32_unchecked(&cursor); 113 m_ro_ptr = extractor.GetAddress_unchecked(&cursor); 114 if (ABISP abi_sp = process->GetABI()) 115 m_ro_ptr = abi_sp->FixCodeAddress(m_ro_ptr); 116 m_method_list_ptr = extractor.GetAddress_unchecked(&cursor); 117 m_properties_ptr = extractor.GetAddress_unchecked(&cursor); 118 m_firstSubclass = extractor.GetAddress_unchecked(&cursor); 119 m_nextSiblingClass = extractor.GetAddress_unchecked(&cursor); 120 121 if (m_ro_ptr & 1) { 122 DataBufferHeap buffer(ptr_size, '\0'); 123 process->ReadMemory(m_ro_ptr ^ 1, buffer.GetBytes(), ptr_size, error); 124 if (error.Fail()) 125 return false; 126 cursor = 0; 127 DataExtractor extractor(buffer.GetBytes(), ptr_size, 128 process->GetByteOrder(), 129 process->GetAddressByteSize()); 130 m_ro_ptr = extractor.GetAddress_unchecked(&cursor); 131 if (ABISP abi_sp = process->GetABI()) 132 m_ro_ptr = abi_sp->FixCodeAddress(m_ro_ptr); 133 } 134 135 return true; 136 } 137 138 bool ClassDescriptorV2::class_ro_t::Read(Process *process, lldb::addr_t addr) { 139 size_t ptr_size = process->GetAddressByteSize(); 140 141 size_t size = sizeof(uint32_t) // uint32_t flags; 142 + sizeof(uint32_t) // uint32_t instanceStart; 143 + sizeof(uint32_t) // uint32_t instanceSize; 144 + (ptr_size == 8 ? sizeof(uint32_t) 145 : 0) // uint32_t reserved; // __LP64__ only 146 + ptr_size // const uint8_t *ivarLayout; 147 + ptr_size // const char *name; 148 + ptr_size // const method_list_t *baseMethods; 149 + ptr_size // const protocol_list_t *baseProtocols; 150 + ptr_size // const ivar_list_t *ivars; 151 + ptr_size // const uint8_t *weakIvarLayout; 152 + ptr_size; // const property_list_t *baseProperties; 153 154 DataBufferHeap buffer(size, '\0'); 155 Status error; 156 157 process->ReadMemory(addr, buffer.GetBytes(), size, error); 158 if (error.Fail()) { 159 return false; 160 } 161 162 DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), 163 process->GetAddressByteSize()); 164 165 lldb::offset_t cursor = 0; 166 167 m_flags = extractor.GetU32_unchecked(&cursor); 168 m_instanceStart = extractor.GetU32_unchecked(&cursor); 169 m_instanceSize = extractor.GetU32_unchecked(&cursor); 170 if (ptr_size == 8) 171 m_reserved = extractor.GetU32_unchecked(&cursor); 172 else 173 m_reserved = 0; 174 m_ivarLayout_ptr = extractor.GetAddress_unchecked(&cursor); 175 m_name_ptr = extractor.GetAddress_unchecked(&cursor); 176 m_baseMethods_ptr = extractor.GetAddress_unchecked(&cursor); 177 m_baseProtocols_ptr = extractor.GetAddress_unchecked(&cursor); 178 m_ivars_ptr = extractor.GetAddress_unchecked(&cursor); 179 m_weakIvarLayout_ptr = extractor.GetAddress_unchecked(&cursor); 180 m_baseProperties_ptr = extractor.GetAddress_unchecked(&cursor); 181 182 DataBufferHeap name_buf(1024, '\0'); 183 184 process->ReadCStringFromMemory(m_name_ptr, (char *)name_buf.GetBytes(), 185 name_buf.GetByteSize(), error); 186 187 if (error.Fail()) { 188 return false; 189 } 190 191 m_name.assign((char *)name_buf.GetBytes()); 192 193 return true; 194 } 195 196 bool ClassDescriptorV2::Read_class_row( 197 Process *process, const objc_class_t &objc_class, 198 std::unique_ptr<class_ro_t> &class_ro, 199 std::unique_ptr<class_rw_t> &class_rw) const { 200 class_ro.reset(); 201 class_rw.reset(); 202 203 Status error; 204 uint32_t class_row_t_flags = process->ReadUnsignedIntegerFromMemory( 205 objc_class.m_data_ptr, sizeof(uint32_t), 0, error); 206 if (!error.Success()) 207 return false; 208 209 if (class_row_t_flags & RW_REALIZED) { 210 class_rw = std::make_unique<class_rw_t>(); 211 212 if (!class_rw->Read(process, objc_class.m_data_ptr)) { 213 class_rw.reset(); 214 return false; 215 } 216 217 class_ro = std::make_unique<class_ro_t>(); 218 219 if (!class_ro->Read(process, class_rw->m_ro_ptr)) { 220 class_rw.reset(); 221 class_ro.reset(); 222 return false; 223 } 224 } else { 225 class_ro = std::make_unique<class_ro_t>(); 226 227 if (!class_ro->Read(process, objc_class.m_data_ptr)) { 228 class_ro.reset(); 229 return false; 230 } 231 } 232 233 return true; 234 } 235 236 bool ClassDescriptorV2::method_list_t::Read(Process *process, 237 lldb::addr_t addr) { 238 size_t size = sizeof(uint32_t) // uint32_t entsize_NEVER_USE; 239 + sizeof(uint32_t); // uint32_t count; 240 241 DataBufferHeap buffer(size, '\0'); 242 Status error; 243 244 if (ABISP abi_sp = process->GetABI()) 245 addr = abi_sp->FixCodeAddress(addr); 246 process->ReadMemory(addr, buffer.GetBytes(), size, error); 247 if (error.Fail()) { 248 return false; 249 } 250 251 DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), 252 process->GetAddressByteSize()); 253 254 lldb::offset_t cursor = 0; 255 256 uint32_t entsize = extractor.GetU32_unchecked(&cursor); 257 m_is_small = (entsize & 0x80000000) != 0; 258 m_has_direct_selector = (entsize & 0x40000000) != 0; 259 m_entsize = entsize & 0xfffc; 260 m_count = extractor.GetU32_unchecked(&cursor); 261 m_first_ptr = addr + cursor; 262 263 return true; 264 } 265 266 bool ClassDescriptorV2::method_t::Read(Process *process, lldb::addr_t addr, 267 lldb::addr_t relative_selector_base_addr, 268 bool is_small, bool has_direct_sel) { 269 size_t ptr_size = process->GetAddressByteSize(); 270 size_t size = GetSize(process, is_small); 271 272 DataBufferHeap buffer(size, '\0'); 273 Status error; 274 275 process->ReadMemory(addr, buffer.GetBytes(), size, error); 276 if (error.Fail()) { 277 return false; 278 } 279 280 DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), 281 ptr_size); 282 lldb::offset_t cursor = 0; 283 284 if (is_small) { 285 uint32_t nameref_offset = extractor.GetU32_unchecked(&cursor); 286 uint32_t types_offset = extractor.GetU32_unchecked(&cursor); 287 uint32_t imp_offset = extractor.GetU32_unchecked(&cursor); 288 289 m_name_ptr = addr + nameref_offset; 290 291 if (!has_direct_sel) { 292 // The SEL offset points to a SELRef. We need to dereference twice. 293 m_name_ptr = process->ReadUnsignedIntegerFromMemory(m_name_ptr, ptr_size, 294 0, error); 295 if (!error.Success()) 296 return false; 297 } else if (relative_selector_base_addr != LLDB_INVALID_ADDRESS) { 298 m_name_ptr = relative_selector_base_addr + nameref_offset; 299 } 300 m_types_ptr = addr + 4 + types_offset; 301 m_imp_ptr = addr + 8 + imp_offset; 302 } else { 303 m_name_ptr = extractor.GetAddress_unchecked(&cursor); 304 m_types_ptr = extractor.GetAddress_unchecked(&cursor); 305 m_imp_ptr = extractor.GetAddress_unchecked(&cursor); 306 } 307 308 process->ReadCStringFromMemory(m_name_ptr, m_name, error); 309 if (error.Fail()) { 310 return false; 311 } 312 313 process->ReadCStringFromMemory(m_types_ptr, m_types, error); 314 return !error.Fail(); 315 } 316 317 bool ClassDescriptorV2::ivar_list_t::Read(Process *process, lldb::addr_t addr) { 318 size_t size = sizeof(uint32_t) // uint32_t entsize; 319 + sizeof(uint32_t); // uint32_t count; 320 321 DataBufferHeap buffer(size, '\0'); 322 Status error; 323 324 process->ReadMemory(addr, buffer.GetBytes(), size, error); 325 if (error.Fail()) { 326 return false; 327 } 328 329 DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), 330 process->GetAddressByteSize()); 331 332 lldb::offset_t cursor = 0; 333 334 m_entsize = extractor.GetU32_unchecked(&cursor); 335 m_count = extractor.GetU32_unchecked(&cursor); 336 m_first_ptr = addr + cursor; 337 338 return true; 339 } 340 341 bool ClassDescriptorV2::ivar_t::Read(Process *process, lldb::addr_t addr) { 342 size_t size = GetSize(process); 343 344 DataBufferHeap buffer(size, '\0'); 345 Status error; 346 347 process->ReadMemory(addr, buffer.GetBytes(), size, error); 348 if (error.Fail()) { 349 return false; 350 } 351 352 DataExtractor extractor(buffer.GetBytes(), size, process->GetByteOrder(), 353 process->GetAddressByteSize()); 354 355 lldb::offset_t cursor = 0; 356 357 m_offset_ptr = extractor.GetAddress_unchecked(&cursor); 358 m_name_ptr = extractor.GetAddress_unchecked(&cursor); 359 m_type_ptr = extractor.GetAddress_unchecked(&cursor); 360 m_alignment = extractor.GetU32_unchecked(&cursor); 361 m_size = extractor.GetU32_unchecked(&cursor); 362 363 process->ReadCStringFromMemory(m_name_ptr, m_name, error); 364 if (error.Fail()) { 365 return false; 366 } 367 368 process->ReadCStringFromMemory(m_type_ptr, m_type, error); 369 return !error.Fail(); 370 } 371 372 bool ClassDescriptorV2::Describe( 373 std::function<void(ObjCLanguageRuntime::ObjCISA)> const &superclass_func, 374 std::function<bool(const char *, const char *)> const &instance_method_func, 375 std::function<bool(const char *, const char *)> const &class_method_func, 376 std::function<bool(const char *, const char *, lldb::addr_t, 377 uint64_t)> const &ivar_func) const { 378 lldb_private::Process *process = m_runtime.GetProcess(); 379 380 std::unique_ptr<objc_class_t> objc_class; 381 std::unique_ptr<class_ro_t> class_ro; 382 std::unique_ptr<class_rw_t> class_rw; 383 384 if (!Read_objc_class(process, objc_class)) 385 return false; 386 if (!Read_class_row(process, *objc_class, class_ro, class_rw)) 387 return false; 388 389 static ConstString NSObject_name("NSObject"); 390 391 if (m_name != NSObject_name && superclass_func) 392 superclass_func(objc_class->m_superclass); 393 394 if (instance_method_func) { 395 std::unique_ptr<method_list_t> base_method_list; 396 397 base_method_list = std::make_unique<method_list_t>(); 398 if (!base_method_list->Read(process, class_ro->m_baseMethods_ptr)) 399 return false; 400 401 bool is_small = base_method_list->m_is_small; 402 bool has_direct_selector = base_method_list->m_has_direct_selector; 403 404 if (base_method_list->m_entsize != method_t::GetSize(process, is_small)) 405 return false; 406 407 std::unique_ptr<method_t> method = std::make_unique<method_t>(); 408 lldb::addr_t relative_selector_base_addr = 409 m_runtime.GetRelativeSelectorBaseAddr(); 410 for (uint32_t i = 0, e = base_method_list->m_count; i < e; ++i) { 411 method->Read(process, 412 base_method_list->m_first_ptr + 413 (i * base_method_list->m_entsize), 414 relative_selector_base_addr, is_small, has_direct_selector); 415 416 if (instance_method_func(method->m_name.c_str(), method->m_types.c_str())) 417 break; 418 } 419 } 420 421 if (class_method_func) { 422 AppleObjCRuntime::ClassDescriptorSP metaclass(GetMetaclass()); 423 424 // We don't care about the metaclass's superclass, or its class methods. 425 // Its instance methods are our class methods. 426 427 if (metaclass) { 428 metaclass->Describe( 429 std::function<void(ObjCLanguageRuntime::ObjCISA)>(nullptr), 430 class_method_func, 431 std::function<bool(const char *, const char *)>(nullptr), 432 std::function<bool(const char *, const char *, lldb::addr_t, 433 uint64_t)>(nullptr)); 434 } 435 } 436 437 if (ivar_func) { 438 if (class_ro->m_ivars_ptr != 0) { 439 ivar_list_t ivar_list; 440 if (!ivar_list.Read(process, class_ro->m_ivars_ptr)) 441 return false; 442 443 if (ivar_list.m_entsize != ivar_t::GetSize(process)) 444 return false; 445 446 ivar_t ivar; 447 448 for (uint32_t i = 0, e = ivar_list.m_count; i < e; ++i) { 449 ivar.Read(process, ivar_list.m_first_ptr + (i * ivar_list.m_entsize)); 450 451 if (ivar_func(ivar.m_name.c_str(), ivar.m_type.c_str(), 452 ivar.m_offset_ptr, ivar.m_size)) 453 break; 454 } 455 } 456 } 457 458 return true; 459 } 460 461 ConstString ClassDescriptorV2::GetClassName() { 462 if (!m_name) { 463 lldb_private::Process *process = m_runtime.GetProcess(); 464 465 if (process) { 466 std::unique_ptr<objc_class_t> objc_class; 467 std::unique_ptr<class_ro_t> class_ro; 468 std::unique_ptr<class_rw_t> class_rw; 469 470 if (!Read_objc_class(process, objc_class)) 471 return m_name; 472 if (!Read_class_row(process, *objc_class, class_ro, class_rw)) 473 return m_name; 474 475 m_name = ConstString(class_ro->m_name.c_str()); 476 } 477 } 478 return m_name; 479 } 480 481 ObjCLanguageRuntime::ClassDescriptorSP ClassDescriptorV2::GetSuperclass() { 482 lldb_private::Process *process = m_runtime.GetProcess(); 483 484 if (!process) 485 return ObjCLanguageRuntime::ClassDescriptorSP(); 486 487 std::unique_ptr<objc_class_t> objc_class; 488 489 if (!Read_objc_class(process, objc_class)) 490 return ObjCLanguageRuntime::ClassDescriptorSP(); 491 492 return m_runtime.ObjCLanguageRuntime::GetClassDescriptorFromISA( 493 objc_class->m_superclass); 494 } 495 496 ObjCLanguageRuntime::ClassDescriptorSP ClassDescriptorV2::GetMetaclass() const { 497 lldb_private::Process *process = m_runtime.GetProcess(); 498 499 if (!process) 500 return ObjCLanguageRuntime::ClassDescriptorSP(); 501 502 std::unique_ptr<objc_class_t> objc_class; 503 504 if (!Read_objc_class(process, objc_class)) 505 return ObjCLanguageRuntime::ClassDescriptorSP(); 506 507 lldb::addr_t candidate_isa = m_runtime.GetPointerISA(objc_class->m_isa); 508 509 return ObjCLanguageRuntime::ClassDescriptorSP( 510 new ClassDescriptorV2(m_runtime, candidate_isa, nullptr)); 511 } 512 513 uint64_t ClassDescriptorV2::GetInstanceSize() { 514 lldb_private::Process *process = m_runtime.GetProcess(); 515 516 if (process) { 517 std::unique_ptr<objc_class_t> objc_class; 518 std::unique_ptr<class_ro_t> class_ro; 519 std::unique_ptr<class_rw_t> class_rw; 520 521 if (!Read_objc_class(process, objc_class)) 522 return 0; 523 if (!Read_class_row(process, *objc_class, class_ro, class_rw)) 524 return 0; 525 526 return class_ro->m_instanceSize; 527 } 528 529 return 0; 530 } 531 532 ClassDescriptorV2::iVarsStorage::iVarsStorage() : m_ivars(), m_mutex() {} 533 534 size_t ClassDescriptorV2::iVarsStorage::size() { return m_ivars.size(); } 535 536 ClassDescriptorV2::iVarDescriptor &ClassDescriptorV2::iVarsStorage:: 537 operator[](size_t idx) { 538 return m_ivars[idx]; 539 } 540 541 void ClassDescriptorV2::iVarsStorage::fill(AppleObjCRuntimeV2 &runtime, 542 ClassDescriptorV2 &descriptor) { 543 if (m_filled) 544 return; 545 std::lock_guard<std::recursive_mutex> guard(m_mutex); 546 Log *log = GetLog(LLDBLog::Types); 547 LLDB_LOGV(log, "class_name = {0}", descriptor.GetClassName()); 548 m_filled = true; 549 ObjCLanguageRuntime::EncodingToTypeSP encoding_to_type_sp( 550 runtime.GetEncodingToType()); 551 Process *process(runtime.GetProcess()); 552 if (!encoding_to_type_sp) 553 return; 554 descriptor.Describe(nullptr, nullptr, nullptr, [this, process, 555 encoding_to_type_sp, 556 log](const char *name, 557 const char *type, 558 lldb::addr_t offset_ptr, 559 uint64_t size) -> bool { 560 const bool for_expression = false; 561 const bool stop_loop = false; 562 LLDB_LOGV(log, "name = {0}, encoding = {1}, offset_ptr = {2:x}, size = {3}", 563 name, type, offset_ptr, size); 564 CompilerType ivar_type = 565 encoding_to_type_sp->RealizeType(type, for_expression); 566 if (ivar_type) { 567 LLDB_LOGV(log, 568 "name = {0}, encoding = {1}, offset_ptr = {2:x}, size = " 569 "{3}, type_size = {4}", 570 name, type, offset_ptr, size, 571 ivar_type.GetByteSize(nullptr).getValueOr(0)); 572 Scalar offset_scalar; 573 Status error; 574 const int offset_ptr_size = 4; 575 const bool is_signed = false; 576 size_t read = process->ReadScalarIntegerFromMemory( 577 offset_ptr, offset_ptr_size, is_signed, offset_scalar, error); 578 if (error.Success() && 4 == read) { 579 LLDB_LOGV(log, "offset_ptr = {0:x} --> {1}", offset_ptr, 580 offset_scalar.SInt()); 581 m_ivars.push_back( 582 {ConstString(name), ivar_type, size, offset_scalar.SInt()}); 583 } else 584 LLDB_LOGV(log, "offset_ptr = {0:x} --> read fail, read = %{1}", 585 offset_ptr, read); 586 } 587 return stop_loop; 588 }); 589 } 590 591 void ClassDescriptorV2::GetIVarInformation() { 592 m_ivars_storage.fill(m_runtime, *this); 593 } 594