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