dyld-832.7.1.tar.gz
[apple/dyld.git] / testing / test-cases / _dyld_for_each_objc_protocol.dtest / main.m
1
2 // BUILD:  $CC linked1.m -dynamiclib -o $BUILD_DIR/liblinked1.dylib -install_name $RUN_DIR/liblinked1.dylib -lobjc
3 // BUILD:  $CC linked2.m -dynamiclib -o $BUILD_DIR/liblinked2.dylib -install_name $RUN_DIR/liblinked2.dylib -lobjc
4 // BUILD:  $CC main.m -o $BUILD_DIR/_dyld_for_each_objc_protocol.exe $BUILD_DIR/liblinked1.dylib $BUILD_DIR/liblinked2.dylib -lobjc
5
6 // RUN:  ./_dyld_for_each_objc_protocol.exe
7
8 // The preoptimized objc protocol information is available via _dyld_for_each_objc_protocol().
9 // This test ensures that we match the objc behaviour when there are duplicates.
10 // For objc today, it walks the images in reverse load order, so the deepest library will be
11 // the canonical definition of a protocol.
12
13 #include <mach-o/dyld_priv.h>
14 #include <objc/runtime.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <dlfcn.h>
19
20 #include "test_support.h"
21
22 static bool objcOptimizedByDyld() {
23     extern const uint32_t objcInfo[]  __asm("section$start$__DATA_CONST$__objc_imageinfo");
24     return (objcInfo[1] & 0x80);
25 }
26
27 static bool haveDyldCache() {
28     size_t unusedCacheLen;
29     return (_dyld_get_shared_cache_range(&unusedCacheLen) != NULL);
30 }
31
32 // All the libraries have a copy of DyldProtocol
33 @protocol DyldProtocol
34 @end
35
36 // Only the main executable has DyldMainProtocol
37 @protocol DyldMainProtocol
38 @end
39
40 __attribute__((used))
41 static void* useDyldProtocol() {
42   return (void*)@protocol(DyldProtocol);
43 }
44
45 __attribute__((used))
46 static void* useDyldMainProtocol() {
47   return (void*)@protocol(DyldMainProtocol);
48 }
49
50 extern id objc_getProtocol(const char *name);
51
52 static bool gotDyldProtocolMain = false;
53 static bool gotDyldProtocolLinked = false;
54 static bool gotDyldProtocolLinked2 = false;
55
56 static bool isInImage(void* ptr, const char* name) {
57   Dl_info info;
58   if ( dladdr(ptr, &info) == 0 ) {
59     FAIL("dladdr(protocol, xx) failed");
60     return false;
61   }
62   return strstr(info.dli_fname, name) != NULL;
63 }
64
65 int main(int argc, const char* argv[], const char* envp[], const char* apple[]) {
66    if (!objcOptimizedByDyld() || !haveDyldCache()) {
67     __block bool sawClass = false;
68     _dyld_for_each_objc_class("DyldClass", ^(void* classPtr, bool isLoaded, bool* stop) {
69       sawClass = true;
70     });
71     if (sawClass) {
72       FAIL("dyld2 shouldn't see any classes");
73     }
74     PASS("no shared cache or no dyld optimized objc");
75   }
76
77   // Check that DyldProtocol comes from liblinked2 as it is last in load order
78   id runtimeDyldProtocol = objc_getProtocol("DyldProtocol");
79   if (!isInImage(runtimeDyldProtocol, "liblinked2")) {
80     FAIL("DyldProtocol should have come from liblinked2");
81   }
82
83   // Check that DyldLinkedProtocol comes from liblinked2 as it is last in load order
84   id runtimeDyldLinkedProtocol = objc_getProtocol("DyldLinkedProtocol");
85   if (!isInImage(runtimeDyldLinkedProtocol, "liblinked2")) {
86     FAIL("DyldLinkedProtocol should have come from liblinked2");
87   }
88
89   // Walk all the implementations of "DyldProtocol"
90   _dyld_for_each_objc_protocol("DyldProtocol", ^(void* protocolPtr, bool isLoaded, bool* stop) {
91     // We should walk these in the order liblinked2, liblinked, main exe
92     if (!gotDyldProtocolLinked2) {
93       if (!isInImage(protocolPtr, "liblinked2")) {
94         FAIL("Optimized DyldProtocol should have come from liblinked2");
95       }
96       if (!isLoaded) {
97         FAIL("Optimized DyldProtocol isLoaded should have been set on liblinked2");
98       }
99       gotDyldProtocolLinked2 = true;
100       return;
101     }
102     if (!gotDyldProtocolLinked) {
103       if (!isInImage(protocolPtr, "liblinked1")) {
104         FAIL("Optimized DyldProtocol should have come from liblinked");
105       }
106       if (!isLoaded) {
107         FAIL("Optimized DyldProtocol isLoaded should have been set on liblinked");
108       }
109       gotDyldProtocolLinked = true;
110       return;
111     }
112     if (!gotDyldProtocolMain) {
113       if (!isInImage(protocolPtr, "_dyld_for_each_objc_protocol.exe")) {
114         FAIL("Optimized DyldProtocol should have come from main exe");
115       }
116       if (!isLoaded) {
117         FAIL("Optimized DyldProtocol isLoaded should have been set on main exe");
118       }
119       gotDyldProtocolMain = true;
120       return;
121     }
122     FAIL("Unexpected Optimized DyldProtocol");
123     return;
124   });
125
126   // Visit again, and return liblinked2's DyldProtocol
127   __block void* DyldProtocolImpl = nil;
128   _dyld_for_each_objc_protocol("DyldProtocol", ^(void* protocolPtr, bool isLoaded, bool* stop) {
129     DyldProtocolImpl = protocolPtr;
130     *stop = true;
131   });
132   if (!isInImage(DyldProtocolImpl, "liblinked2")) {
133     FAIL("_dyld_for_each_objc_protocol should have returned DyldProtocol from liblinked2");
134   }
135
136   // Visit DyldMainProtocol and make sure it makes the callback for just the result from main.exe
137   __block void* DyldMainProtocolImpl = nil;
138   _dyld_for_each_objc_protocol("DyldMainProtocol", ^(void* protocolPtr, bool isLoaded, bool* stop) {
139     DyldMainProtocolImpl = protocolPtr;
140     *stop = true;
141   });
142   if (!isInImage(DyldMainProtocolImpl, "_dyld_for_each_objc_protocol.exe")) {
143     FAIL("_dyld_for_each_objc_protocol should have returned DyldMainProtocol from main.exe");
144   }
145
146 #if __has_feature(ptrauth_calls)
147   // Check the ISA was signed correctly on arm64e
148   id dyldMainProtocol = @protocol(DyldMainProtocol);
149   void* originalISA = *(void **)dyldMainProtocol;
150   void* strippedISA = __builtin_ptrauth_strip(originalISA, ptrauth_key_asda);
151   uint64_t discriminator = __builtin_ptrauth_blend_discriminator((void*)dyldMainProtocol, 27361);
152   void* signedISA = __builtin_ptrauth_sign_unauthenticated((void*)strippedISA, 2, discriminator);
153   if ( originalISA != signedISA ) {
154     FAIL("_dyld_for_each_objc_protocol DyldMainProtocol ISA is not signed correctly: %p vs %p",
155          originalISA, signedISA);
156   }
157 #endif
158
159   PASS("Success");
160 }