Skip to content

Commit d33f060

Browse files
author
Alex B
committed
[llvm-objdump][macho] Add support for ObjC relative method lists
1 parent 597f976 commit d33f060

File tree

4 files changed

+188
-0
lines changed

4 files changed

+188
-0
lines changed
Binary file not shown.
Binary file not shown.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
RUN: llvm-objdump --macho --objc-meta-data %p/Inputs/rel-method-lists-arm64_32.dylib | FileCheck %s --check-prefix=CHK32
2+
RUN: llvm-otool -ov %p/Inputs/rel-method-lists-arm64_32.dylib | FileCheck %s --check-prefix=CHK32
3+
4+
RUN: llvm-objdump --macho --objc-meta-data %p/Inputs/rel-method-lists-arm64.dylib | FileCheck %s --check-prefix=CHK64
5+
RUN: llvm-otool -ov %p/Inputs/rel-method-lists-arm64.dylib | FileCheck %s --check-prefix=CHK64
6+
7+
CHK32: baseMethods 0x660 (struct method_list_t *)
8+
CHK32-NEXT: entsize 12 (relative)
9+
CHK32-NEXT: count 3
10+
CHK32-NEXT: name 0x144 (0x7ac) instance_method_00
11+
CHK32-NEXT: types 0x91 (0x6fd) v8@0:4
12+
CHK32-NEXT: imp 0xffffff18 (0x588) -[MyClass instance_method_00]
13+
CHK32-NEXT: name 0x13c (0x7b0) instance_method_01
14+
CHK32-NEXT: types 0x85 (0x6fd) v8@0:4
15+
CHK32-NEXT: imp 0xffffff28 (0x5a4) -[MyClass instance_method_01]
16+
CHK32-NEXT: name 0x134 (0x7b4) instance_method_02
17+
CHK32-NEXT: types 0x79 (0x6fd) v8@0:4
18+
CHK32-NEXT: imp 0xffffff38 (0x5c0) -[MyClass instance_method_02]
19+
20+
CHK32: baseMethods 0x630 (struct method_list_t *)
21+
CHK32-NEXT: entsize 12 (relative)
22+
CHK32-NEXT: count 3
23+
CHK32-NEXT: name 0x180 (0x7b8) class_method_00
24+
CHK32-NEXT: types 0xc1 (0x6fd) v8@0:4
25+
CHK32-NEXT: imp 0xffffff9c (0x5dc) +[MyClass class_method_00]
26+
CHK32-NEXT: name 0x178 (0x7bc) class_method_01
27+
CHK32-NEXT: types 0xb5 (0x6fd) v8@0:4
28+
CHK32-NEXT: imp 0xffffffac (0x5f8) +[MyClass class_method_01]
29+
CHK32-NEXT: name 0x170 (0x7c0) class_method_02
30+
CHK32-NEXT: types 0xa9 (0x6fd) v8@0:4
31+
CHK32-NEXT: imp 0xffffffbc (0x614) +[MyClass class_method_02]
32+
33+
CHK64: baseMethods 0x7d8 (struct method_list_t *)
34+
CHK64-NEXT: entsize 24
35+
CHK64-NEXT: count 3
36+
CHK64-NEXT: name 0x6a4 instance_method_00
37+
CHK64-NEXT: types 0x6dd v16@0:8
38+
CHK64-NEXT: imp -[MyClass instance_method_00]
39+
CHK64-NEXT: name 0x6b7 instance_method_01
40+
CHK64-NEXT: types 0x6dd v16@0:8
41+
CHK64-NEXT: imp -[MyClass instance_method_01]
42+
CHK64-NEXT: name 0x6ca instance_method_02
43+
CHK64-NEXT: types 0x6dd v16@0:8
44+
CHK64-NEXT: imp -[MyClass instance_method_02]
45+
46+
CHK64: baseMethods 0x740 (struct method_list_t *)
47+
CHK64-NEXT: entsize 24
48+
CHK64-NEXT: count 3
49+
CHK64-NEXT: name 0x674 class_method_00
50+
CHK64-NEXT: types 0x6dd v16@0:8
51+
CHK64-NEXT: imp +[MyClass class_method_00]
52+
CHK64-NEXT: name 0x684 class_method_01
53+
CHK64-NEXT: types 0x6dd v16@0:8
54+
CHK64-NEXT: imp +[MyClass class_method_01]
55+
CHK64-NEXT: name 0x694 class_method_02
56+
CHK64-NEXT: types 0x6dd v16@0:8
57+
CHK64-NEXT: imp +[MyClass class_method_02]

llvm/tools/llvm-objdump/MachODump.cpp

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3519,6 +3519,12 @@ static const char *get_pointer_64(uint64_t Address, uint32_t &offset,
35193519
return nullptr;
35203520
}
35213521

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+
35223528
static const char *get_pointer_32(uint32_t Address, uint32_t &offset,
35233529
uint32_t &left, SectionRef &S,
35243530
DisassembleInfo *info,
@@ -3661,6 +3667,10 @@ struct class_ro32_t {
36613667
#define RO_ROOT (1 << 1)
36623668
#define RO_HAS_CXX_STRUCTORS (1 << 2)
36633669

3670+
/* Values for method_list{64,32,_delta}_t->entsize */
3671+
#define ML_HAS_DELTAS (1 << 31)
3672+
#define ML_ENTSIZE_MASK 0xFFFF
3673+
36643674
struct method_list64_t {
36653675
uint32_t entsize;
36663676
uint32_t count;
@@ -3673,6 +3683,12 @@ struct method_list32_t {
36733683
/* struct method32_t first; These structures follow inline */
36743684
};
36753685

3686+
struct method_list_delta_t {
3687+
uint32_t entsize;
3688+
uint32_t count;
3689+
/* struct method32_t first; These structures follow inline */
3690+
};
3691+
36763692
struct method64_t {
36773693
uint64_t name; /* SEL (64-bit pointer) */
36783694
uint64_t types; /* const char * (64-bit pointer) */
@@ -3685,6 +3701,12 @@ struct method32_t {
36853701
uint32_t imp; /* IMP (32-bit pointer) */
36863702
};
36873703

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+
36883710
struct protocol_list64_t {
36893711
uint64_t count; /* uintptr_t (a 64-bit value) */
36903712
/* struct protocol64_t * list[0]; These pointers follow inline */
@@ -3974,6 +3996,11 @@ inline void swapStruct(struct method_list32_t &ml) {
39743996
sys::swapByteOrder(ml.count);
39753997
}
39763998

3999+
inline void swapStruct(struct method_list_delta_t &ml) {
4000+
sys::swapByteOrder(ml.entsize);
4001+
sys::swapByteOrder(ml.count);
4002+
}
4003+
39774004
inline void swapStruct(struct method64_t &m) {
39784005
sys::swapByteOrder(m.name);
39794006
sys::swapByteOrder(m.types);
@@ -3986,6 +4013,12 @@ inline void swapStruct(struct method32_t &m) {
39864013
sys::swapByteOrder(m.imp);
39874014
}
39884015

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+
39894022
inline void swapStruct(struct protocol_list64_t &pl) {
39904023
sys::swapByteOrder(pl.count);
39914024
}
@@ -4440,8 +4473,103 @@ static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {
44404473
print_layout_map(layout_map, left);
44414474
}
44424475

4476+
// Return true if this is a delta method list, false otherwise
4477+
//
4478+
static bool print_method_list_delta_t(uint64_t p, struct DisassembleInfo *info,
4479+
const char *indent,
4480+
uint32_t pointerBits) {
4481+
struct method_list_delta_t ml;
4482+
struct method_delta_t m;
4483+
const char *r, *name;
4484+
uint32_t offset, xoffset, left, i;
4485+
SectionRef S, xS;
4486+
4487+
r = get_pointer_32(p, offset, left, S, info);
4488+
if (r == nullptr)
4489+
return false;
4490+
memset(&ml, '\0', sizeof(struct method_list_delta_t));
4491+
if (left < sizeof(struct method_list_delta_t)) {
4492+
memcpy(&ml, r, left);
4493+
outs() << " (method_delta_t entends past the end of the section)\n";
4494+
} else
4495+
memcpy(&ml, r, sizeof(struct method_list_delta_t));
4496+
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4497+
swapStruct(ml);
4498+
if ((ml.entsize & ML_HAS_DELTAS) == 0)
4499+
return false;
4500+
4501+
outs() << indent << "\t\t entsize " << (ml.entsize & ML_ENTSIZE_MASK)
4502+
<< " (relative) \n";
4503+
outs() << indent << "\t\t count " << ml.count << "\n";
4504+
4505+
p += sizeof(struct method_list_delta_t);
4506+
offset += sizeof(struct method_delta_t);
4507+
for (i = 0; i < ml.count; i++) {
4508+
r = get_value_32(p, offset, left, S, info);
4509+
if (r == nullptr)
4510+
return true;
4511+
memset(&m, '\0', sizeof(struct method_delta_t));
4512+
if (left < sizeof(struct method_delta_t)) {
4513+
memcpy(&ml, r, left);
4514+
outs() << indent << " (method_t entends past the end of the section)\n";
4515+
} else
4516+
memcpy(&m, r, sizeof(struct method_delta_t));
4517+
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
4518+
swapStruct(m);
4519+
4520+
outs() << indent << "\t\t name " << format("0x%" PRIx32, m.name);
4521+
uint64_t relNameRefVA = p + offsetof(struct method_delta_t, name);
4522+
uint64_t absNameRefVA = relNameRefVA + m.name;
4523+
outs() << " (" << format("0x%" PRIx32, absNameRefVA) << ")";
4524+
4525+
// since this is a delta list, absNameRefVA is the address of the
4526+
// __objc_selrefs entry, so a pointer, not the actual name
4527+
const char *nameRefPtr =
4528+
get_pointer_32(absNameRefVA, xoffset, left, xS, info);
4529+
if (nameRefPtr) {
4530+
uint32_t pointerSize = pointerBits / CHAR_BIT;
4531+
if (left < pointerSize)
4532+
outs() << indent << " (nameRefPtr entends past the end of the section)";
4533+
else {
4534+
uint64_t nameVA = 0;
4535+
memcpy(&nameVA, nameRefPtr, pointerSize);
4536+
const char *name = get_pointer_32(nameVA, xoffset, left, xS, info);
4537+
if (name != nullptr)
4538+
outs() << format(" %.*s", left, name);
4539+
}
4540+
}
4541+
outs() << "\n";
4542+
4543+
outs() << indent << "\t\t types " << format("0x%" PRIx32, m.types);
4544+
uint64_t relTypesVA = p + offsetof(struct method_delta_t, types);
4545+
uint64_t absTypesVA = relTypesVA + m.types;
4546+
outs() << " (" << format("0x%" PRIx32, absTypesVA) << ")";
4547+
name = get_pointer_32(absTypesVA, xoffset, left, xS, info);
4548+
if (name != nullptr)
4549+
outs() << format(" %.*s", left, name);
4550+
outs() << "\n";
4551+
4552+
outs() << indent << "\t\t imp " << format("0x%" PRIx32, m.imp);
4553+
uint64_t relImpVA = p + offsetof(struct method_delta_t, imp);
4554+
uint64_t absImpVA = relImpVA + m.imp;
4555+
outs() << " (" << format("0x%" PRIx32, absImpVA) << ")";
4556+
name = GuessSymbolName(absImpVA, info->AddrMap);
4557+
if (name != nullptr)
4558+
outs() << " " << name;
4559+
outs() << "\n";
4560+
4561+
p += sizeof(struct method_delta_t);
4562+
offset += sizeof(struct method_delta_t);
4563+
}
4564+
4565+
return true;
4566+
}
4567+
44434568
static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
44444569
const char *indent) {
4570+
if (print_method_list_delta_t(p, info, indent, /*pointerBits=*/64))
4571+
return;
4572+
44454573
struct method_list64_t ml;
44464574
struct method64_t m;
44474575
const char *r;
@@ -4535,6 +4663,9 @@ static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
45354663

45364664
static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,
45374665
const char *indent) {
4666+
if (print_method_list_delta_t(p, info, indent, /*pointerBits=*/32))
4667+
return;
4668+
45384669
struct method_list32_t ml;
45394670
struct method32_t m;
45404671
const char *r, *name;

0 commit comments

Comments
 (0)