@@ -3519,6 +3519,12 @@ static const char *get_pointer_64(uint64_t Address, uint32_t &offset,
3519
3519
return nullptr ;
3520
3520
}
3521
3521
3522
+ static const char *get_value_32 (uint32_t Address, uint32_t &offset,
3523
+ uint32_t &left, SectionRef &S,
3524
+ DisassembleInfo *info, bool objc_only = false ) {
3525
+ return get_pointer_64 (Address, offset, left, S, info, objc_only);
3526
+ }
3527
+
3522
3528
static const char *get_pointer_32 (uint32_t Address, uint32_t &offset,
3523
3529
uint32_t &left, SectionRef &S,
3524
3530
DisassembleInfo *info,
@@ -3661,6 +3667,10 @@ struct class_ro32_t {
3661
3667
#define RO_ROOT (1 << 1 )
3662
3668
#define RO_HAS_CXX_STRUCTORS (1 << 2 )
3663
3669
3670
+ /* Values for method_list{64,32,_delta}_t->entsize */
3671
+ #define ML_HAS_DELTAS (1 << 31 )
3672
+ #define ML_ENTSIZE_MASK 0xFFFF
3673
+
3664
3674
struct method_list64_t {
3665
3675
uint32_t entsize;
3666
3676
uint32_t count;
@@ -3673,6 +3683,12 @@ struct method_list32_t {
3673
3683
/* struct method32_t first; These structures follow inline */
3674
3684
};
3675
3685
3686
+ struct method_list_delta_t {
3687
+ uint32_t entsize;
3688
+ uint32_t count;
3689
+ /* struct method_delta_t first; These structures follow inline */
3690
+ };
3691
+
3676
3692
struct method64_t {
3677
3693
uint64_t name; /* SEL (64-bit pointer) */
3678
3694
uint64_t types; /* const char * (64-bit pointer) */
@@ -3685,6 +3701,12 @@ struct method32_t {
3685
3701
uint32_t imp; /* IMP (32-bit pointer) */
3686
3702
};
3687
3703
3704
+ struct method_delta_t {
3705
+ int32_t name; /* SEL (32-bit delta) */
3706
+ int32_t types; /* const char * (32-bit delta) */
3707
+ int32_t imp; /* IMP (32-bit delta) */
3708
+ };
3709
+
3688
3710
struct protocol_list64_t {
3689
3711
uint64_t count; /* uintptr_t (a 64-bit value) */
3690
3712
/* struct protocol64_t * list[0]; These pointers follow inline */
@@ -3974,6 +3996,11 @@ inline void swapStruct(struct method_list32_t &ml) {
3974
3996
sys::swapByteOrder (ml.count );
3975
3997
}
3976
3998
3999
+ inline void swapStruct (struct method_list_delta_t &ml) {
4000
+ sys::swapByteOrder (ml.entsize );
4001
+ sys::swapByteOrder (ml.count );
4002
+ }
4003
+
3977
4004
inline void swapStruct (struct method64_t &m) {
3978
4005
sys::swapByteOrder (m.name );
3979
4006
sys::swapByteOrder (m.types );
@@ -3986,6 +4013,12 @@ inline void swapStruct(struct method32_t &m) {
3986
4013
sys::swapByteOrder (m.imp );
3987
4014
}
3988
4015
4016
+ inline void swapStruct (struct method_delta_t &m) {
4017
+ sys::swapByteOrder (m.name );
4018
+ sys::swapByteOrder (m.types );
4019
+ sys::swapByteOrder (m.imp );
4020
+ }
4021
+
3989
4022
inline void swapStruct (struct protocol_list64_t &pl) {
3990
4023
sys::swapByteOrder (pl.count );
3991
4024
}
@@ -4440,8 +4473,103 @@ static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {
4440
4473
print_layout_map (layout_map, left);
4441
4474
}
4442
4475
4476
+ // Return true if this is a delta method list, false otherwise
4477
+ static bool print_method_list_delta_t (uint64_t p, struct DisassembleInfo *info,
4478
+ const char *indent,
4479
+ uint32_t pointerBits) {
4480
+ struct method_list_delta_t ml;
4481
+ struct method_delta_t m;
4482
+ const char *r, *name;
4483
+ uint32_t offset, xoffset, left, i;
4484
+ SectionRef S, xS;
4485
+
4486
+ r = get_pointer_32 (p, offset, left, S, info);
4487
+ if (r == nullptr )
4488
+ return false ;
4489
+ memset (&ml, ' \0 ' , sizeof (struct method_list_delta_t ));
4490
+ if (left < sizeof (struct method_list_delta_t )) {
4491
+ memcpy (&ml, r, left);
4492
+ outs () << " (method_delta_t entends past the end of the section)\n " ;
4493
+ } else
4494
+ memcpy (&ml, r, sizeof (struct method_list_delta_t ));
4495
+ if (info->O ->isLittleEndian () != sys::IsLittleEndianHost)
4496
+ swapStruct (ml);
4497
+ if ((ml.entsize & ML_HAS_DELTAS) == 0 )
4498
+ return false ;
4499
+
4500
+ outs () << indent << " \t\t entsize " << (ml.entsize & ML_ENTSIZE_MASK)
4501
+ << " (relative) \n " ;
4502
+ outs () << indent << " \t\t count " << ml.count << " \n " ;
4503
+
4504
+ p += sizeof (struct method_list_delta_t );
4505
+ offset += sizeof (struct method_delta_t );
4506
+ for (i = 0 ; i < ml.count ; i++) {
4507
+ r = get_value_32 (p, offset, left, S, info);
4508
+ if (r == nullptr )
4509
+ return true ;
4510
+ memset (&m, ' \0 ' , sizeof (struct method_delta_t ));
4511
+ if (left < sizeof (struct method_delta_t )) {
4512
+ memcpy (&ml, r, left);
4513
+ outs () << indent << " (method_t entends past the end of the section)\n " ;
4514
+ } else
4515
+ memcpy (&m, r, sizeof (struct method_delta_t ));
4516
+ if (info->O ->isLittleEndian () != sys::IsLittleEndianHost)
4517
+ swapStruct (m);
4518
+
4519
+ outs () << indent << " \t\t name " << format (" 0x%" PRIx32, m.name );
4520
+ uint64_t relNameRefVA = p + offsetof (struct method_delta_t , name);
4521
+ uint64_t absNameRefVA = relNameRefVA + m.name ;
4522
+ outs () << " (" << format (" 0x%" PRIx32, absNameRefVA) << " )" ;
4523
+
4524
+ // since this is a delta list, absNameRefVA is the address of the
4525
+ // __objc_selrefs entry, so a pointer, not the actual name
4526
+ const char *nameRefPtr =
4527
+ get_pointer_32 (absNameRefVA, xoffset, left, xS, info);
4528
+ if (nameRefPtr) {
4529
+ uint32_t pointerSize = pointerBits / CHAR_BIT;
4530
+ if (left < pointerSize)
4531
+ outs () << indent << " (nameRefPtr entends past the end of the section)" ;
4532
+ else {
4533
+ uint64_t nameVA = 0 ;
4534
+ memcpy (&nameVA, nameRefPtr, pointerSize);
4535
+ const char *name = get_pointer_32 (nameVA, xoffset, left, xS, info);
4536
+ if (name != nullptr )
4537
+ outs () << format (" %.*s" , left, name);
4538
+ }
4539
+ }
4540
+ outs () << " \n " ;
4541
+
4542
+ outs () << indent << " \t\t types " << format (" 0x%" PRIx32, m.types );
4543
+ uint64_t relTypesVA = p + offsetof (struct method_delta_t , types);
4544
+ uint64_t absTypesVA = relTypesVA + m.types ;
4545
+ outs () << " (" << format (" 0x%" PRIx32, absTypesVA) << " )" ;
4546
+ name = get_pointer_32 (absTypesVA, xoffset, left, xS, info);
4547
+ if (name != nullptr )
4548
+ outs () << format (" %.*s" , left, name);
4549
+ outs () << " \n " ;
4550
+
4551
+ outs () << indent << " \t\t imp " << format (" 0x%" PRIx32, m.imp );
4552
+ uint64_t relImpVA = p + offsetof (struct method_delta_t , imp);
4553
+ uint64_t absImpVA = relImpVA + m.imp ;
4554
+ outs () << " (" << format (" 0x%" PRIx32, absImpVA) << " )" ;
4555
+ name = GuessSymbolName (absImpVA, info->AddrMap );
4556
+ if (name != nullptr )
4557
+ outs () << " " << name;
4558
+ outs () << " \n " ;
4559
+
4560
+ p += sizeof (struct method_delta_t );
4561
+ offset += sizeof (struct method_delta_t );
4562
+ }
4563
+
4564
+ return true ;
4565
+ }
4566
+
4443
4567
static void print_method_list64_t (uint64_t p, struct DisassembleInfo *info,
4444
4568
const char *indent) {
4569
+ // Try to parse it as a delta list. If successful, just return
4570
+ if (print_method_list_delta_t (p, info, indent, /* pointerBits=*/ 64 ))
4571
+ return ;
4572
+
4445
4573
struct method_list64_t ml;
4446
4574
struct method64_t m;
4447
4575
const char *r;
@@ -4535,6 +4663,10 @@ static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
4535
4663
4536
4664
static void print_method_list32_t (uint64_t p, struct DisassembleInfo *info,
4537
4665
const char *indent) {
4666
+ // Try to parse it as a delta list. If successful, just return
4667
+ if (print_method_list_delta_t (p, info, indent, /* pointerBits=*/ 32 ))
4668
+ return ;
4669
+
4538
4670
struct method_list32_t ml;
4539
4671
struct method32_t m;
4540
4672
const char *r, *name;
0 commit comments