[llvm] [llvm-objdump][macho] Add support for ObjC relative method lists (PR #84250)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 14 09:24:31 PDT 2024
https://github.com/alx32 updated https://github.com/llvm/llvm-project/pull/84250
>From c99ad35d40438ce92425f42ed3bdb9a53ce5abde Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Wed, 6 Mar 2024 14:31:24 -0800
Subject: [PATCH 1/3] [llvm-objdump][macho] Add support for ObjC relative
method lists
---
.../Inputs/rel-method-lists-arm64.dylib | Bin 0 -> 3160 bytes
.../Inputs/rel-method-lists-arm64_32.dylib | Bin 0 -> 2716 bytes
.../AArch64/macho-relative-method-lists.test | 87 ++++++++++++
llvm/tools/llvm-objdump/MachODump.cpp | 134 ++++++++++++++++++
4 files changed, 221 insertions(+)
create mode 100755 llvm/test/tools/llvm-objdump/MachO/AArch64/Inputs/rel-method-lists-arm64.dylib
create mode 100755 llvm/test/tools/llvm-objdump/MachO/AArch64/Inputs/rel-method-lists-arm64_32.dylib
create mode 100644 llvm/test/tools/llvm-objdump/MachO/AArch64/macho-relative-method-lists.test
diff --git a/llvm/test/tools/llvm-objdump/MachO/AArch64/Inputs/rel-method-lists-arm64.dylib b/llvm/test/tools/llvm-objdump/MachO/AArch64/Inputs/rel-method-lists-arm64.dylib
new file mode 100755
index 0000000000000000000000000000000000000000..9b39fc98fb5d96b544894f21e1f7857891735e6f
GIT binary patch
literal 3160
zcmcguO=whC6h6L*P1>X}!3dT{h*m`H&%7BVgwjH$GXs;ViJFL!BDXJZp3TU6^M=mT
zBy<yMyDbU|S-LQwn-Xwgmsv^|ZEZyYVrdqNE(8m1;-Y%ad*{r&xs!>uiyk<0?|1IK
z- at EsmbI+Y$pFjDh3t$tVyn)({y0jVKd*~q(yo0)eqe at NWCnrKv!;jhC06{QPfGEvS
zDsX0l`dppw8BIo+jT#_qa6fF?U_K6&@~6(&%66 at 4wQPBg&gar$P&%Rp1T$>pMkDii
zPB2Y$P3H}mufzm`UxP20t2Fc7*Y+p4HQ(9tOsQN{rSfS%+;3w%9x-2m2?#g%Pl&mt
zxIRKvDwmnasO;G2co<!YUle_)#Zzzs*N_r7+2V0<OVywipTvRqX?;wDIy5m~$+Nz4
z=%_m15a*ll5q{M<hr;}&bJo8)%sdyu%m)xW&sfeWdzEwg<!YG4(Y~7b%ov}nt<S3W
zn6GFBR%q1uDty2ryoB(^e75g-ep$Yt^DQ%9+}UwH-nJ|c?|lK0Qin!H59V_teD{B2
zo-4dqco!HGPn_#*#9yLr*X+q at -*b|d>&#C1U)xqWsRFN(G*hZ-c@@`Dc$!Mdb&~$s
zKuliBvux!S2M>HyoO4T4$Oy0tVBW-*_CeohB`Y{y!9mIuns?;QsMeWpApvf<lWeFY
zXbQCrTdIfuMc&0l^qp_FecFB{J^0}I))T!ytX^JBqip~+@)3U3=nngl`z&KWj>TiN
zhj9V-ORnF?nD$Sy1C{14A=Nc9yoS8U!tKA>VQn=5YuLZIoKScF58L6nER|~ri?*Ut
z>lc-2YB;6gG?ehpS!LUaEom~PnrEfqTxxLG{CJ35LjLY&-^5$W2YPD`U`y(89i=|S
zqzhN}aI~;v$i2iN7)GTS(>!?(q>h`+^BuQh&oREF*(Vtj*Irg^Y9jBK)T!D)i;nE;
zs`eduXK!lu4#q!g_I}3Xr}aekwZipuy*Y8)0wr-wZZVcRvX`;U6MyUTF7Wqycf!$K
z9VfHL@~F8=$E0v?QuzPF82jw=tb+dN&w}Gsf;k1FU}O(v#>dreB^jAJoS(?(#*qX(
z?ZMzK^x`c&7g$p+KI67!PdiXdz;Z7R-NK<ro^|$-z)6JNm~7(b8OGw@%Z$aZHyBI4
z{K8oB<S}E(k2d7)MjuHYyvJDlkzp+Huo;VADUMsPc8FgoPY8>@sXlGN0x15 at GnV)a
zfC_!8J1erT=SF_%BIif$YcR2AKm3A&G0=3k%~P<!XlldJ^eK41#;g^d)<ekIY84Wy
z=&-w0<ODo)VJtUZOC}z!`{LMGEY)g at NAMq4W;B~uE!Icm4QnwL&;RUN#^xF-MmCf_
zv{6_ufq^fU5k7GNVz~-9uXAa at z*6=vWuv$EkH3H4x_I-)*;W7Poo{B&-`j3qeE313
P at Y7=7C&xFholn06PJ`vL
literal 0
HcmV?d00001
diff --git a/llvm/test/tools/llvm-objdump/MachO/AArch64/Inputs/rel-method-lists-arm64_32.dylib b/llvm/test/tools/llvm-objdump/MachO/AArch64/Inputs/rel-method-lists-arm64_32.dylib
new file mode 100755
index 0000000000000000000000000000000000000000..d3a339057abc349e5959a3a67077f0ae5c5bafe8
GIT binary patch
literal 2716
zcmd5-J!}+L5FYz3Kw_{RiNaD`K!PG533q2Xkrh#JxjV^Dz$W%7fC74~_m=pg-P;ql
zU|;7VNE9?kq=_g}I8s0^h=2l#!jW7fXn-PBDuakbi6SMJ at 7sNQe%{4IqGEJ&^Sya9
zvorJl?*0AOzuQH6dqiXlcnA34TOt=^P^i0)Kc%Xb<5dg{I=VF)P{KT9`jeCjoP{95
z(Ric(ML7J53CiAeGm)$;#zUq2+3#)TIl-J;Zw09w^7z<E7*l3qr-aloY}abF8kXlI
z>$n8pZSbKq$;`>fgCSCRT!C*L&Xgu?5+i6g(=q;mFWX6J(#9C)8uRr=P1PG`d>AEb
z$s)iw^pvKb8E<_(%f)JOeTHjz14GK6A=yuIoQ~N?E{0NR|19k3pZNA5)FJ5 at b<g_F
zVF}3?Rrqo(C=)Ss1lAnx3EOXALx7SoPQv#n^pyV-qvg0~oinX;jAi%^AqJ%x16ws&
zOU()_rjg2H6~23+r!- at P#`;ew+xI-b5$lq*JcBR$K{8`-4Pzo611oiSV)Cm>c_Kce
zaJ&Jh=ZLWkNjuYzXZ$pnb(;FzobNd~%XJoJ{j;{!$f>|<=JEyAvb?72Fym(3b#nf>
zAXd#=fj#H9lw133^gylc)@Kp(eUZgHB){Kn8pbI?o-UL~G0Y{vxF2}<Z3IAKeZX8#
z(mR^D&uH^H^d6j8^VM%Y{rH!aeCM}|*Z%xz`SucXjq+qBJ+i+$1_12_?*uPm6YxGH
zeF&zHi=6S3eR|9qUWYm*d9ap|>uUpYXD!oneXURKKzDg1qaMCVb9gHjc{gx<euuo;
z>2wx=Zv!s_H-WDK-vx${*uD(?WsHZQKL~sQcrWlMa2t3G_(;3Nt6IVfJG}b+n#$)B
z<3eIQB6ZvcR>O7-mz1iIwi=Q1V~6sekA`Pp7&(wk$=$#=Y7~-O&=(>xd$1jz(JP6;
zV027*=1GUZwBf!Xllac?y-E_lV-oF7zr=18x<}xrV7 at m?;9KCw`kTBnNIyVQ$6R6^
z??lqOyQMiaJw9DNR%~Xg#jmAD;qC67`r^xylHurrb-ZTKRx&BQrNhOU8MQ~nD^osF
zsTPyUiHxicpxDO)ILfwV&*6nTA6T=lBeje?<J5CZp_hHbBsl at xk9B8n=QUme{!!x<
z;F}u%0eny67r;+6-if-ih|!Pcv8Nws%)V8Kafh>VwWweICH2!oKhxAZDLNh_O-G
ztBS_FyLO2R`;sg;(!Q(}`h|)bs9Rz7RJY}mZ*@a=rS at t5l)PfL at XFbdQ}R(aa^ete
zK82W at c_E;Riru54CZOo?sq##BLv*JnCTFU}$x=maVzJ(>=_zAFY5yqrh8e8Gf2j)e
A#{d8T
literal 0
HcmV?d00001
diff --git a/llvm/test/tools/llvm-objdump/MachO/AArch64/macho-relative-method-lists.test b/llvm/test/tools/llvm-objdump/MachO/AArch64/macho-relative-method-lists.test
new file mode 100644
index 00000000000000..be8b7f8f3b2ce0
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/MachO/AArch64/macho-relative-method-lists.test
@@ -0,0 +1,87 @@
+RUN: llvm-objdump --macho --objc-meta-data %p/Inputs/rel-method-lists-arm64_32.dylib | FileCheck %s --check-prefix=CHK32
+RUN: llvm-otool -ov %p/Inputs/rel-method-lists-arm64_32.dylib | FileCheck %s --check-prefix=CHK32
+
+RUN: llvm-objdump --macho --objc-meta-data %p/Inputs/rel-method-lists-arm64.dylib | FileCheck %s --check-prefix=CHK64
+RUN: llvm-otool -ov %p/Inputs/rel-method-lists-arm64.dylib | FileCheck %s --check-prefix=CHK64
+
+CHK32: baseMethods 0x660 (struct method_list_t *)
+CHK32-NEXT: entsize 12 (relative)
+CHK32-NEXT: count 3
+CHK32-NEXT: name 0x144 (0x7ac) instance_method_00
+CHK32-NEXT: types 0x91 (0x6fd) v8 at 0:4
+CHK32-NEXT: imp 0xffffff18 (0x588) -[MyClass instance_method_00]
+CHK32-NEXT: name 0x13c (0x7b0) instance_method_01
+CHK32-NEXT: types 0x85 (0x6fd) v8 at 0:4
+CHK32-NEXT: imp 0xffffff28 (0x5a4) -[MyClass instance_method_01]
+CHK32-NEXT: name 0x134 (0x7b4) instance_method_02
+CHK32-NEXT: types 0x79 (0x6fd) v8 at 0:4
+CHK32-NEXT: imp 0xffffff38 (0x5c0) -[MyClass instance_method_02]
+
+CHK32: baseMethods 0x630 (struct method_list_t *)
+CHK32-NEXT: entsize 12 (relative)
+CHK32-NEXT: count 3
+CHK32-NEXT: name 0x180 (0x7b8) class_method_00
+CHK32-NEXT: types 0xc1 (0x6fd) v8 at 0:4
+CHK32-NEXT: imp 0xffffff9c (0x5dc) +[MyClass class_method_00]
+CHK32-NEXT: name 0x178 (0x7bc) class_method_01
+CHK32-NEXT: types 0xb5 (0x6fd) v8 at 0:4
+CHK32-NEXT: imp 0xffffffac (0x5f8) +[MyClass class_method_01]
+CHK32-NEXT: name 0x170 (0x7c0) class_method_02
+CHK32-NEXT: types 0xa9 (0x6fd) v8 at 0:4
+CHK32-NEXT: imp 0xffffffbc (0x614) +[MyClass class_method_02]
+
+CHK64: baseMethods 0x7d8 (struct method_list_t *)
+CHK64-NEXT: entsize 24
+CHK64-NEXT: count 3
+CHK64-NEXT: name 0x6a4 instance_method_00
+CHK64-NEXT: types 0x6dd v16 at 0:8
+CHK64-NEXT: imp -[MyClass instance_method_00]
+CHK64-NEXT: name 0x6b7 instance_method_01
+CHK64-NEXT: types 0x6dd v16 at 0:8
+CHK64-NEXT: imp -[MyClass instance_method_01]
+CHK64-NEXT: name 0x6ca instance_method_02
+CHK64-NEXT: types 0x6dd v16 at 0:8
+CHK64-NEXT: imp -[MyClass instance_method_02]
+
+CHK64: baseMethods 0x740 (struct method_list_t *)
+CHK64-NEXT: entsize 24
+CHK64-NEXT: count 3
+CHK64-NEXT: name 0x674 class_method_00
+CHK64-NEXT: types 0x6dd v16 at 0:8
+CHK64-NEXT: imp +[MyClass class_method_00]
+CHK64-NEXT: name 0x684 class_method_01
+CHK64-NEXT: types 0x6dd v16 at 0:8
+CHK64-NEXT: imp +[MyClass class_method_01]
+CHK64-NEXT: name 0x694 class_method_02
+CHK64-NEXT: types 0x6dd v16 at 0:8
+CHK64-NEXT: imp +[MyClass class_method_02]
+
+
+######## Generate rel-method-lists-arm64.dylib ########
+// clang -c main.mm -o main.o -target arm64-apple-macos -arch arm64
+// ld64.ld64 -dylib -demangle -dynamic main.o -o rel-method-lists-arm64.dylib -syslibroot MacOSX14.2.sdk -segalign 0x10 -objc_relative_method_lists
+
+######## Generate rel-method-lists-arm64_32.dylib ########
+// clang -c main.mm -o main.o -target arm64_32-apple-watchos -arch arm64_32
+// ld64.ld64 -dylib -demangle -dynamic main.o -o rel-method-lists-arm64_32.dylib -syslibroot WatchOS.sdk -segalign 0x10 -objc_relative_method_lists
+
+// ~~~~~~~~~~~~~~~~~~~~~~~~~ main.mm ~~~~~~~~~~~~~~~~~~~~~~~~~
+__attribute__((objc_root_class))
+ at interface MyClass
+- (void)instance_method_00;
+- (void)instance_method_01;
+- (void)instance_method_02;
++ (void)class_method_00;
++ (void)class_method_01;
++ (void)class_method_02;
+ at end
+ at implementation MyClass
+- (void)instance_method_00 {}
+- (void)instance_method_01 {}
+- (void)instance_method_02 {}
++ (void)class_method_00 {}
++ (void)class_method_01 {}
++ (void)class_method_02 {}
+ at end
+void *_objc_empty_cache;
+void *_objc_empty_vtable;
diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp
index 0e6935c0ac5895..ffde83d5d88f3f 100644
--- a/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/llvm/tools/llvm-objdump/MachODump.cpp
@@ -3519,6 +3519,12 @@ static const char *get_pointer_64(uint64_t Address, uint32_t &offset,
return nullptr;
}
+static const char *get_value_32(uint32_t Address, uint32_t &offset,
+ uint32_t &left, SectionRef &S,
+ DisassembleInfo *info, bool objc_only = false) {
+ return get_pointer_64(Address, offset, left, S, info, objc_only);
+}
+
static const char *get_pointer_32(uint32_t Address, uint32_t &offset,
uint32_t &left, SectionRef &S,
DisassembleInfo *info,
@@ -3661,6 +3667,10 @@ struct class_ro32_t {
#define RO_ROOT (1 << 1)
#define RO_HAS_CXX_STRUCTORS (1 << 2)
+/* Values for method_list{64,32,_delta}_t->entsize */
+#define ML_HAS_DELTAS (1 << 31)
+#define ML_ENTSIZE_MASK 0xFFFF
+
struct method_list64_t {
uint32_t entsize;
uint32_t count;
@@ -3673,6 +3683,12 @@ struct method_list32_t {
/* struct method32_t first; These structures follow inline */
};
+struct method_list_delta_t {
+ uint32_t entsize;
+ uint32_t count;
+ /* struct method_delta_t first; These structures follow inline */
+};
+
struct method64_t {
uint64_t name; /* SEL (64-bit pointer) */
uint64_t types; /* const char * (64-bit pointer) */
@@ -3685,6 +3701,12 @@ struct method32_t {
uint32_t imp; /* IMP (32-bit pointer) */
};
+struct method_delta_t {
+ int32_t name; /* SEL (32-bit delta) */
+ int32_t types; /* const char * (32-bit delta) */
+ int32_t imp; /* IMP (32-bit delta) */
+};
+
struct protocol_list64_t {
uint64_t count; /* uintptr_t (a 64-bit value) */
/* struct protocol64_t * list[0]; These pointers follow inline */
@@ -3974,6 +3996,11 @@ inline void swapStruct(struct method_list32_t &ml) {
sys::swapByteOrder(ml.count);
}
+inline void swapStruct(struct method_list_delta_t &ml) {
+ sys::swapByteOrder(ml.entsize);
+ sys::swapByteOrder(ml.count);
+}
+
inline void swapStruct(struct method64_t &m) {
sys::swapByteOrder(m.name);
sys::swapByteOrder(m.types);
@@ -3986,6 +4013,12 @@ inline void swapStruct(struct method32_t &m) {
sys::swapByteOrder(m.imp);
}
+inline void swapStruct(struct method_delta_t &m) {
+ sys::swapByteOrder(m.name);
+ sys::swapByteOrder(m.types);
+ sys::swapByteOrder(m.imp);
+}
+
inline void swapStruct(struct protocol_list64_t &pl) {
sys::swapByteOrder(pl.count);
}
@@ -4440,8 +4473,104 @@ static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {
print_layout_map(layout_map, left);
}
+// Return true if this is a delta method list, false otherwise
+static bool print_method_list_delta_t(uint64_t p, struct DisassembleInfo *info,
+ const char *indent,
+ uint32_t pointerBits) {
+ struct method_list_delta_t ml;
+ struct method_delta_t m;
+ const char *r, *name;
+ uint32_t offset, xoffset, left, i;
+ SectionRef S, xS;
+
+ r = get_pointer_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return false;
+ memset(&ml, '\0', sizeof(struct method_list_delta_t));
+ if (left < sizeof(struct method_list_delta_t)) {
+ memcpy(&ml, r, left);
+ outs() << " (method_delta_t extends past the end of the section)\n";
+ } else
+ memcpy(&ml, r, sizeof(struct method_list_delta_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(ml);
+ if ((ml.entsize & ML_HAS_DELTAS) == 0)
+ return false;
+
+ outs() << indent << "\t\t entsize " << (ml.entsize & ML_ENTSIZE_MASK)
+ << " (relative) \n";
+ outs() << indent << "\t\t count " << ml.count << "\n";
+
+ p += sizeof(struct method_list_delta_t);
+ offset += sizeof(struct method_delta_t);
+ for (i = 0; i < ml.count; i++) {
+ r = get_value_32(p, offset, left, S, info);
+ if (r == nullptr)
+ return true;
+ memset(&m, '\0', sizeof(struct method_delta_t));
+ if (left < sizeof(struct method_delta_t)) {
+ memcpy(&m, r, left);
+ outs() << indent << " (method_t extends past the end of the section)\n";
+ } else
+ memcpy(&m, r, sizeof(struct method_delta_t));
+ if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
+ swapStruct(m);
+
+ outs() << indent << "\t\t name " << format("0x%" PRIx32, m.name);
+ uint64_t relNameRefVA = p + offsetof(struct method_delta_t, name);
+ uint64_t absNameRefVA = relNameRefVA + m.name;
+ outs() << " (" << format("0x%" PRIx32, absNameRefVA) << ")";
+
+ // since this is a delta list, absNameRefVA is the address of the
+ // __objc_selrefs entry, so a pointer, not the actual name
+ const char *nameRefPtr =
+ get_pointer_32(absNameRefVA, xoffset, left, xS, info);
+ if (nameRefPtr) {
+ uint32_t pointerSize = pointerBits / CHAR_BIT;
+ if (left < pointerSize)
+ outs() << indent << " (nameRefPtr extends past the end of the section)";
+ else {
+ uint64_t nameVA = 0;
+ memcpy(&nameVA, nameRefPtr, pointerSize);
+ name = get_pointer_32(nameVA, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ }
+ }
+ outs() << "\n";
+
+ outs() << indent << "\t\t types " << format("0x%" PRIx32, m.types);
+ uint64_t relTypesVA = p + offsetof(struct method_delta_t, types);
+ uint64_t absTypesVA = relTypesVA + m.types;
+ outs() << " (" << format("0x%" PRIx32, absTypesVA) << ")";
+ name = get_pointer_32(absTypesVA, xoffset, left, xS, info);
+ if (name != nullptr)
+ outs() << format(" %.*s", left, name);
+ outs() << "\n";
+
+ outs() << indent << "\t\t imp " << format("0x%" PRIx32, m.imp);
+ uint64_t relImpVA = p + offsetof(struct method_delta_t, imp);
+ uint64_t absImpVA = relImpVA + m.imp;
+ outs() << " (" << format("0x%" PRIx32, absImpVA) << ")";
+ name = GuessSymbolName(absImpVA, info->AddrMap);
+ if (name != nullptr)
+ outs() << " " << name;
+ outs() << "\n";
+
+ p += sizeof(struct method_delta_t);
+ offset += sizeof(struct method_delta_t);
+ }
+
+ return true;
+}
+
static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
const char *indent) {
+ // Attempt to parse the method list as a delta list. If successful, return
+ // early since the parsing is complete.
+ if (print_method_list_delta_t(p, info, indent, /*pointerBits=*/64))
+ return;
+
struct method_list64_t ml;
struct method64_t m;
const char *r;
@@ -4535,6 +4664,11 @@ static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,
const char *indent) {
+ // Attempt to parse the method list as a delta list. If successful, return
+ // early since the parsing is complete.
+ if (print_method_list_delta_t(p, info, indent, /*pointerBits=*/32))
+ return;
+
struct method_list32_t ml;
struct method32_t m;
const char *r, *name;
>From 6080be01ae8ac08448be944ee7c14e04ab268e75 Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Wed, 13 Mar 2024 16:11:17 -0700
Subject: [PATCH 2/3] [lld-macho] Address Feedback #1
---
llvm/tools/llvm-objdump/MachODump.cpp | 132 +++++++++++---------------
1 file changed, 53 insertions(+), 79 deletions(-)
diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp
index ffde83d5d88f3f..616938a5563de0 100644
--- a/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/llvm/tools/llvm-objdump/MachODump.cpp
@@ -3519,12 +3519,6 @@ static const char *get_pointer_64(uint64_t Address, uint32_t &offset,
return nullptr;
}
-static const char *get_value_32(uint32_t Address, uint32_t &offset,
- uint32_t &left, SectionRef &S,
- DisassembleInfo *info, bool objc_only = false) {
- return get_pointer_64(Address, offset, left, S, info, objc_only);
-}
-
static const char *get_pointer_32(uint32_t Address, uint32_t &offset,
uint32_t &left, SectionRef &S,
DisassembleInfo *info,
@@ -3667,8 +3661,8 @@ struct class_ro32_t {
#define RO_ROOT (1 << 1)
#define RO_HAS_CXX_STRUCTORS (1 << 2)
-/* Values for method_list{64,32,_delta}_t->entsize */
-#define ML_HAS_DELTAS (1 << 31)
+/* Values for method_list{64,32}_t->entsize */
+#define ML_HAS_RELATIVE_PTRS (1 << 31)
#define ML_ENTSIZE_MASK 0xFFFF
struct method_list64_t {
@@ -3683,12 +3677,6 @@ struct method_list32_t {
/* struct method32_t first; These structures follow inline */
};
-struct method_list_delta_t {
- uint32_t entsize;
- uint32_t count;
- /* struct method_delta_t first; These structures follow inline */
-};
-
struct method64_t {
uint64_t name; /* SEL (64-bit pointer) */
uint64_t types; /* const char * (64-bit pointer) */
@@ -3701,10 +3689,10 @@ struct method32_t {
uint32_t imp; /* IMP (32-bit pointer) */
};
-struct method_delta_t {
- int32_t name; /* SEL (32-bit delta) */
- int32_t types; /* const char * (32-bit delta) */
- int32_t imp; /* IMP (32-bit delta) */
+struct method_relative_t {
+ int32_t name; /* SEL (32-bit relative) */
+ int32_t types; /* const char * (32-bit relative) */
+ int32_t imp; /* IMP (32-bit relative) */
};
struct protocol_list64_t {
@@ -3996,11 +3984,6 @@ inline void swapStruct(struct method_list32_t &ml) {
sys::swapByteOrder(ml.count);
}
-inline void swapStruct(struct method_list_delta_t &ml) {
- sys::swapByteOrder(ml.entsize);
- sys::swapByteOrder(ml.count);
-}
-
inline void swapStruct(struct method64_t &m) {
sys::swapByteOrder(m.name);
sys::swapByteOrder(m.types);
@@ -4013,7 +3996,7 @@ inline void swapStruct(struct method32_t &m) {
sys::swapByteOrder(m.imp);
}
-inline void swapStruct(struct method_delta_t &m) {
+inline void swapStruct(struct method_relative_t &m) {
sys::swapByteOrder(m.name);
sys::swapByteOrder(m.types);
sys::swapByteOrder(m.imp);
@@ -4473,66 +4456,55 @@ static void print_layout_map32(uint32_t p, struct DisassembleInfo *info) {
print_layout_map(layout_map, left);
}
-// Return true if this is a delta method list, false otherwise
-static bool print_method_list_delta_t(uint64_t p, struct DisassembleInfo *info,
- const char *indent,
- uint32_t pointerBits) {
- struct method_list_delta_t ml;
- struct method_delta_t m;
+static void print_relative_method_list(uint32_t structSizeAndFlags,
+ uint32_t structCount, uint64_t p,
+ struct DisassembleInfo *info,
+ const char *indent,
+ uint32_t pointerBits) {
+ struct method_relative_t m;
const char *r, *name;
uint32_t offset, xoffset, left, i;
SectionRef S, xS;
- r = get_pointer_32(p, offset, left, S, info);
- if (r == nullptr)
- return false;
- memset(&ml, '\0', sizeof(struct method_list_delta_t));
- if (left < sizeof(struct method_list_delta_t)) {
- memcpy(&ml, r, left);
- outs() << " (method_delta_t extends past the end of the section)\n";
- } else
- memcpy(&ml, r, sizeof(struct method_list_delta_t));
- if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
- swapStruct(ml);
- if ((ml.entsize & ML_HAS_DELTAS) == 0)
- return false;
+ assert(((structSizeAndFlags & ML_HAS_RELATIVE_PTRS) != 0) &&
+ "expected structSizeAndFlags to have ML_HAS_RELATIVE_PTRS flag");
- outs() << indent << "\t\t entsize " << (ml.entsize & ML_ENTSIZE_MASK)
- << " (relative) \n";
- outs() << indent << "\t\t count " << ml.count << "\n";
+ outs() << indent << "\t\t entsize "
+ << (structSizeAndFlags & ML_ENTSIZE_MASK) << " (relative) \n";
+ outs() << indent << "\t\t count " << structCount << "\n";
- p += sizeof(struct method_list_delta_t);
- offset += sizeof(struct method_delta_t);
- for (i = 0; i < ml.count; i++) {
- r = get_value_32(p, offset, left, S, info);
- if (r == nullptr)
- return true;
- memset(&m, '\0', sizeof(struct method_delta_t));
- if (left < sizeof(struct method_delta_t)) {
+ for (i = 0; i < structCount; i++) {
+ r = get_pointer_64(p, offset, left, S, info);
+ memset(&m, '\0', sizeof(struct method_relative_t));
+ if (left < sizeof(struct method_relative_t)) {
memcpy(&m, r, left);
outs() << indent << " (method_t extends past the end of the section)\n";
} else
- memcpy(&m, r, sizeof(struct method_delta_t));
+ memcpy(&m, r, sizeof(struct method_relative_t));
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
swapStruct(m);
outs() << indent << "\t\t name " << format("0x%" PRIx32, m.name);
- uint64_t relNameRefVA = p + offsetof(struct method_delta_t, name);
+ uint64_t relNameRefVA = p + offsetof(struct method_relative_t, name);
uint64_t absNameRefVA = relNameRefVA + m.name;
outs() << " (" << format("0x%" PRIx32, absNameRefVA) << ")";
- // since this is a delta list, absNameRefVA is the address of the
+ // since this is a relative list, absNameRefVA is the address of the
// __objc_selrefs entry, so a pointer, not the actual name
const char *nameRefPtr =
- get_pointer_32(absNameRefVA, xoffset, left, xS, info);
+ get_pointer_64(absNameRefVA, xoffset, left, xS, info);
if (nameRefPtr) {
uint32_t pointerSize = pointerBits / CHAR_BIT;
if (left < pointerSize)
outs() << indent << " (nameRefPtr extends past the end of the section)";
else {
- uint64_t nameVA = 0;
- memcpy(&nameVA, nameRefPtr, pointerSize);
- name = get_pointer_32(nameVA, xoffset, left, xS, info);
+ if (pointerSize == 64) {
+ name = get_pointer_64(*reinterpret_cast<const uint64_t *>(nameRefPtr),
+ xoffset, left, xS, info);
+ } else {
+ name = get_pointer_32(*reinterpret_cast<const uint32_t *>(nameRefPtr),
+ xoffset, left, xS, info);
+ }
if (name != nullptr)
outs() << format(" %.*s", left, name);
}
@@ -4540,7 +4512,7 @@ static bool print_method_list_delta_t(uint64_t p, struct DisassembleInfo *info,
outs() << "\n";
outs() << indent << "\t\t types " << format("0x%" PRIx32, m.types);
- uint64_t relTypesVA = p + offsetof(struct method_delta_t, types);
+ uint64_t relTypesVA = p + offsetof(struct method_relative_t, types);
uint64_t absTypesVA = relTypesVA + m.types;
outs() << " (" << format("0x%" PRIx32, absTypesVA) << ")";
name = get_pointer_32(absTypesVA, xoffset, left, xS, info);
@@ -4549,7 +4521,7 @@ static bool print_method_list_delta_t(uint64_t p, struct DisassembleInfo *info,
outs() << "\n";
outs() << indent << "\t\t imp " << format("0x%" PRIx32, m.imp);
- uint64_t relImpVA = p + offsetof(struct method_delta_t, imp);
+ uint64_t relImpVA = p + offsetof(struct method_relative_t, imp);
uint64_t absImpVA = relImpVA + m.imp;
outs() << " (" << format("0x%" PRIx32, absImpVA) << ")";
name = GuessSymbolName(absImpVA, info->AddrMap);
@@ -4557,20 +4529,13 @@ static bool print_method_list_delta_t(uint64_t p, struct DisassembleInfo *info,
outs() << " " << name;
outs() << "\n";
- p += sizeof(struct method_delta_t);
- offset += sizeof(struct method_delta_t);
+ p += sizeof(struct method_relative_t);
+ offset += sizeof(struct method_relative_t);
}
-
- return true;
}
static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
const char *indent) {
- // Attempt to parse the method list as a delta list. If successful, return
- // early since the parsing is complete.
- if (print_method_list_delta_t(p, info, indent, /*pointerBits=*/64))
- return;
-
struct method_list64_t ml;
struct method64_t m;
const char *r;
@@ -4590,10 +4555,17 @@ static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
memcpy(&ml, r, sizeof(struct method_list64_t));
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
swapStruct(ml);
+ p += sizeof(struct method_list64_t);
+
+ if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {
+ print_relative_method_list(ml.entsize, ml.count, p, info, indent,
+ /*pointerBits=*/32);
+ return;
+ }
+
outs() << indent << "\t\t entsize " << ml.entsize << "\n";
outs() << indent << "\t\t count " << ml.count << "\n";
- p += sizeof(struct method_list64_t);
offset += sizeof(struct method_list64_t);
for (i = 0; i < ml.count; i++) {
r = get_pointer_64(p, offset, left, S, info);
@@ -4664,11 +4636,6 @@ static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,
const char *indent) {
- // Attempt to parse the method list as a delta list. If successful, return
- // early since the parsing is complete.
- if (print_method_list_delta_t(p, info, indent, /*pointerBits=*/32))
- return;
-
struct method_list32_t ml;
struct method32_t m;
const char *r, *name;
@@ -4686,10 +4653,17 @@ static void print_method_list32_t(uint64_t p, struct DisassembleInfo *info,
memcpy(&ml, r, sizeof(struct method_list32_t));
if (info->O->isLittleEndian() != sys::IsLittleEndianHost)
swapStruct(ml);
+ p += sizeof(struct method_list32_t);
+
+ if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {
+ print_relative_method_list(ml.entsize, ml.count, p, info, indent,
+ /*pointerBits=*/32);
+ return;
+ }
+
outs() << indent << "\t\t entsize " << ml.entsize << "\n";
outs() << indent << "\t\t count " << ml.count << "\n";
- p += sizeof(struct method_list32_t);
offset += sizeof(struct method_list32_t);
for (i = 0; i < ml.count; i++) {
r = get_pointer_32(p, offset, left, S, info);
>From e9ae6a2267fcda7da4395c217ae49d6543bc1647 Mon Sep 17 00:00:00 2001
From: Alex B <alexborcan at meta.com>
Date: Thu, 14 Mar 2024 09:24:12 -0700
Subject: [PATCH 3/3] Address Feedback #2
---
llvm/tools/llvm-objdump/MachODump.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp
index 616938a5563de0..1b0e5ba279d06b 100644
--- a/llvm/tools/llvm-objdump/MachODump.cpp
+++ b/llvm/tools/llvm-objdump/MachODump.cpp
@@ -4559,7 +4559,7 @@ static void print_method_list64_t(uint64_t p, struct DisassembleInfo *info,
if ((ml.entsize & ML_HAS_RELATIVE_PTRS) != 0) {
print_relative_method_list(ml.entsize, ml.count, p, info, indent,
- /*pointerBits=*/32);
+ /*pointerBits=*/64);
return;
}
More information about the llvm-commits
mailing list