@@ -370,6 +370,155 @@ bool ClassDescriptorV2::ivar_t::Read(Process *process, lldb::addr_t addr) {
370
370
return !error.Fail ();
371
371
}
372
372
373
+ bool ClassDescriptorV2::relative_list_entry_t::Read (Process *process,
374
+ lldb::addr_t addr) {
375
+ Log *log = GetLog (LLDBLog::Types);
376
+ size_t size = sizeof (uint64_t ); // m_image_index : 16
377
+ // m_list_offset : 48
378
+
379
+ DataBufferHeap buffer (size, ' \0 ' );
380
+ Status error;
381
+
382
+ process->ReadMemory (addr, buffer.GetBytes (), size, error);
383
+ // FIXME: Propagate this error up
384
+ if (error.Fail ()) {
385
+ LLDB_LOG (log , " Failed to read relative_list_entry_t at address {0:x}" ,
386
+ addr);
387
+ return false ;
388
+ }
389
+
390
+ DataExtractor extractor (buffer.GetBytes (), size, process->GetByteOrder (),
391
+ process->GetAddressByteSize ());
392
+ lldb::offset_t cursor = 0 ;
393
+ uint64_t raw_entry = extractor.GetU64_unchecked (&cursor);
394
+ m_image_index = raw_entry & 0xFFFF ;
395
+ m_list_offset = (int64_t )(raw_entry >> 16 );
396
+ return true ;
397
+ }
398
+
399
+ bool ClassDescriptorV2::relative_list_list_t::Read (Process *process,
400
+ lldb::addr_t addr) {
401
+ Log *log = GetLog (LLDBLog::Types);
402
+ size_t size = sizeof (uint32_t ) // m_entsize
403
+ + sizeof (uint32_t ); // m_count
404
+
405
+ DataBufferHeap buffer (size, ' \0 ' );
406
+ Status error;
407
+
408
+ // FIXME: Propagate this error up
409
+ process->ReadMemory (addr, buffer.GetBytes (), size, error);
410
+ if (error.Fail ()) {
411
+ LLDB_LOG (log , " Failed to read relative_list_list_t at address 0x" PRIx64,
412
+ addr);
413
+ return false ;
414
+ }
415
+
416
+ DataExtractor extractor (buffer.GetBytes (), size, process->GetByteOrder (),
417
+ process->GetAddressByteSize ());
418
+ lldb::offset_t cursor = 0 ;
419
+ m_entsize = extractor.GetU32_unchecked (&cursor);
420
+ m_count = extractor.GetU32_unchecked (&cursor);
421
+ m_first_ptr = addr + cursor;
422
+ return true ;
423
+ }
424
+
425
+ std::optional<ClassDescriptorV2::method_list_t >
426
+ ClassDescriptorV2::GetMethodList (Process *process,
427
+ lldb::addr_t method_list_ptr) const {
428
+ Log *log = GetLog (LLDBLog::Types);
429
+ ClassDescriptorV2::method_list_t method_list;
430
+ if (!method_list.Read (process, method_list_ptr))
431
+ return std::nullopt;
432
+
433
+ const size_t method_size = method_t::GetSize (process, method_list.m_is_small );
434
+ if (method_list.m_entsize != method_size) {
435
+ LLDB_LOG (log ,
436
+ " method_list_t at address 0x" PRIx64 " has an entsize of " PRIu16
437
+ " but method size should be " PRIu64,
438
+ method_list_ptr, method_list.m_entsize , method_size);
439
+ return std::nullopt;
440
+ }
441
+
442
+ return method_list;
443
+ }
444
+
445
+ bool ClassDescriptorV2::ProcessMethodList (
446
+ std::function<bool (const char *, const char *)> const &instance_method_func,
447
+ ClassDescriptorV2::method_list_t &method_list) const {
448
+ lldb_private::Process *process = m_runtime.GetProcess ();
449
+ auto method = std::make_unique<method_t >();
450
+ lldb::addr_t relative_selector_base_addr =
451
+ m_runtime.GetRelativeSelectorBaseAddr ();
452
+ for (uint32_t i = 0 , e = method_list.m_count ; i < e; ++i) {
453
+ method->Read (process, method_list.m_first_ptr + (i * method_list.m_entsize ),
454
+ relative_selector_base_addr, method_list.m_is_small ,
455
+ method_list.m_has_direct_selector );
456
+ if (instance_method_func (method->m_name .c_str (), method->m_types .c_str ()))
457
+ break ;
458
+ }
459
+ return true ;
460
+ }
461
+
462
+ // The relevant data structures:
463
+ // - relative_list_list_t
464
+ // - uint32_t count
465
+ // - uint32_t entsize
466
+ // - Followed by <count> number of relative_list_entry_t of size <entsize>
467
+ //
468
+ // - relative_list_entry_t
469
+ // - uint64_t image_index : 16
470
+ // - int64_t list_offset : 48
471
+ // - Note: The above 2 fit into 8 bytes always
472
+ //
473
+ // image_index corresponds to an image in the shared cache
474
+ // list_offset is used to calculate the address of the method_list_t we want
475
+ bool ClassDescriptorV2::ProcessRelativeMethodLists (
476
+ std::function<bool (const char *, const char *)> const &instance_method_func,
477
+ lldb::addr_t relative_method_list_ptr) const {
478
+ lldb_private::Process *process = m_runtime.GetProcess ();
479
+ auto relative_method_lists = std::make_unique<relative_list_list_t >();
480
+
481
+ // 1. Process the count and entsize of the relative_list_list_t
482
+ if (!relative_method_lists->Read (process, relative_method_list_ptr))
483
+ return false ;
484
+
485
+ auto entry = std::make_unique<relative_list_entry_t >();
486
+ for (uint32_t i = 0 ; i < relative_method_lists->m_count ; i++) {
487
+ // 2. Extract the image index and the list offset from the
488
+ // relative_list_entry_t
489
+ const lldb::addr_t entry_addr = relative_method_lists->m_first_ptr +
490
+ (i * relative_method_lists->m_entsize );
491
+ if (!entry->Read (process, entry_addr))
492
+ return false ;
493
+
494
+ // 3. Calculate the pointer to the method_list_t from the
495
+ // relative_list_entry_t
496
+ const lldb::addr_t method_list_addr = entry_addr + entry->m_list_offset ;
497
+
498
+ // 4. Get the method_list_t from the pointer
499
+ std::optional<method_list_t > method_list =
500
+ GetMethodList (process, method_list_addr);
501
+ if (!method_list)
502
+ return false ;
503
+
504
+ // 5. Cache the result so we don't need to reconstruct it later.
505
+ m_image_to_method_lists[entry->m_image_index ].emplace_back (*method_list);
506
+
507
+ // 6. If the relevant image is loaded, add the methods to the Decl
508
+ if (!m_runtime.IsSharedCacheImageLoaded (entry->m_image_index ))
509
+ continue ;
510
+
511
+ if (!ProcessMethodList (instance_method_func, *method_list))
512
+ return false ;
513
+ }
514
+
515
+ // We need to keep track of the last time we updated so we can re-update the
516
+ // type information in the future
517
+ m_last_version_updated = m_runtime.GetSharedCacheImageHeaderVersion ();
518
+
519
+ return true ;
520
+ }
521
+
373
522
bool ClassDescriptorV2::Describe (
374
523
std::function<void (ObjCLanguageRuntime::ObjCISA)> const &superclass_func,
375
524
std::function<bool(const char *, const char *)> const &instance_method_func,
@@ -393,29 +542,18 @@ bool ClassDescriptorV2::Describe(
393
542
superclass_func (objc_class->m_superclass );
394
543
395
544
if (instance_method_func) {
396
- std::unique_ptr<method_list_t > base_method_list;
397
-
398
- base_method_list = std::make_unique<method_list_t >();
399
- if (!base_method_list->Read (process, class_ro->m_baseMethods_ptr ))
400
- return false ;
401
-
402
- bool is_small = base_method_list->m_is_small ;
403
- bool has_direct_selector = base_method_list->m_has_direct_selector ;
404
-
405
- if (base_method_list->m_entsize != method_t::GetSize (process, is_small))
406
- return false ;
407
-
408
- std::unique_ptr<method_t > method = std::make_unique<method_t >();
409
- lldb::addr_t relative_selector_base_addr =
410
- m_runtime.GetRelativeSelectorBaseAddr ();
411
- for (uint32_t i = 0 , e = base_method_list->m_count ; i < e; ++i) {
412
- method->Read (process,
413
- base_method_list->m_first_ptr +
414
- (i * base_method_list->m_entsize ),
415
- relative_selector_base_addr, is_small, has_direct_selector);
416
-
417
- if (instance_method_func (method->m_name .c_str (), method->m_types .c_str ()))
418
- break ;
545
+ // This is a relative list of lists
546
+ if (class_ro->m_baseMethods_ptr & 1 ) {
547
+ if (!ProcessRelativeMethodLists (instance_method_func,
548
+ class_ro->m_baseMethods_ptr ^ 1 ))
549
+ return false ;
550
+ } else {
551
+ std::optional<method_list_t > base_method_list =
552
+ GetMethodList (process, class_ro->m_baseMethods_ptr );
553
+ if (!base_method_list)
554
+ return false ;
555
+ if (!ProcessMethodList (instance_method_func, *base_method_list))
556
+ return false ;
419
557
}
420
558
}
421
559
0 commit comments