dyld-732.8.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 // All the libraries have a copy of DyldProtocol
21 @protocol DyldProtocol
22 @end
23
24 // Only the main executable has DyldMainProtocol
25 @protocol DyldMainProtocol
26 @end
27
28 __attribute__((used))
29 static void* useDyldProtocol() {
30   return (void*)@protocol(DyldProtocol);
31 }
32
33 __attribute__((used))
34 static void* useDyldMainProtocol() {
35   return (void*)@protocol(DyldMainProtocol);
36 }
37
38 extern int printf(const char*, ...);
39
40 extern id objc_getProtocol(const char *name);
41
42 static bool gotDyldProtocolMain = false;
43 static bool gotDyldProtocolLinked = false;
44 static bool gotDyldProtocolLinked2 = false;
45
46 static bool isInImage(void* ptr, const char* name) {
47   Dl_info info;
48   if ( dladdr(ptr, &info) == 0 ) {
49     printf("[FAIL] _dyld_for_each_objc_protocol dladdr(protocol, xx) failed\n");
50     return false;
51   }
52   return strstr(info.dli_fname, name) != NULL;
53 }
54
55 int main() {
56   printf("[BEGIN] _dyld_for_each_objc_protocol\n");
57
58   // This API is only available with dyld3 and shared caches.  If we have dyld2 then don't do anything
59   const char* testDyldMode = getenv("TEST_DYLD_MODE");
60   assert(testDyldMode);
61
62   size_t unusedCacheLen;
63   bool haveSharedCache = _dyld_get_shared_cache_range(&unusedCacheLen) != 0;
64   if (!strcmp(testDyldMode, "2") || !haveSharedCache) {
65     __block bool sawProtocol = false;
66     _dyld_for_each_objc_protocol("DyldProtocol", ^(void* protocolPtr, bool isLoaded, bool* stop) {
67       sawProtocol = true;
68     });
69     if (sawProtocol) {
70       printf("[FAIL] _dyld_for_each_objc_protocol: dyld2 shouldn't see any protocols\n");
71       return 0;
72     }
73     printf("[PASS] _dyld_for_each_objc_protocol (dyld2 or no shared cache)\n");
74     return 0;
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     printf("[FAIL] _dyld_for_each_objc_protocol: DyldProtocol should have come from liblinked2\n");
81     return 0;
82   }
83
84   // Check that DyldLinkedProtocol comes from liblinked2 as it is last in load order
85   id runtimeDyldLinkedProtocol = objc_getProtocol("DyldLinkedProtocol");
86   if (!isInImage(runtimeDyldLinkedProtocol, "liblinked2")) {
87     printf("[FAIL] _dyld_for_each_objc_protocol: DyldLinkedProtocol should have come from liblinked2\n");
88     return 0;
89   }
90
91   // Walk all the implementations of "DyldProtocol"
92   _dyld_for_each_objc_protocol("DyldProtocol", ^(void* protocolPtr, bool isLoaded, bool* stop) {
93     // We should walk these in the order liblinked2, liblinked, main exe
94     if (!gotDyldProtocolLinked2) {
95       if (!isInImage(protocolPtr, "liblinked2")) {
96         printf("[FAIL] _dyld_for_each_objc_protocol: Optimized DyldProtocol should have come from liblinked2\n");
97         *stop = true;
98         return;
99       }
100       if (!isLoaded) {
101         printf("[FAIL] _dyld_for_each_objc_protocol: Optimized DyldProtocol isLoaded should have been set on liblinked2\n");
102         *stop = true;
103         return;
104       }
105       gotDyldProtocolLinked2 = true;
106       return;
107     }
108     if (!gotDyldProtocolLinked) {
109       if (!isInImage(protocolPtr, "liblinked1")) {
110         printf("[FAIL] _dyld_for_each_objc_protocol: Optimized DyldProtocol should have come from liblinked\n");
111         *stop = true;
112         return;
113       }
114       if (!isLoaded) {
115         printf("[FAIL] _dyld_for_each_objc_protocol: Optimized DyldProtocol isLoaded should have been set on liblinked\n");
116         *stop = true;
117         return;
118       }
119       gotDyldProtocolLinked = true;
120       return;
121     }
122     if (!gotDyldProtocolMain) {
123       if (!isInImage(protocolPtr, "_dyld_for_each_objc_protocol.exe")) {
124         printf("[FAIL] _dyld_for_each_objc_protocol: Optimized DyldProtocol should have come from main exe\n");
125         *stop = true;
126         return;
127       }
128       if (!isLoaded) {
129         printf("[FAIL] _dyld_for_each_objc_protocol: Optimized DyldProtocol isLoaded should have been set on main exe\n");
130         *stop = true;
131         return;
132       }
133       gotDyldProtocolMain = true;
134       return;
135     }
136     printf("[FAIL] _dyld_for_each_objc_protocol: Unexpected Optimized DyldProtocol\n");
137     return;
138   });
139
140   // Visit again, and return liblinked2's DyldProtocol
141   __block void* DyldProtocolImpl = nil;
142   _dyld_for_each_objc_protocol("DyldProtocol", ^(void* protocolPtr, bool isLoaded, bool* stop) {
143     DyldProtocolImpl = protocolPtr;
144     *stop = true;
145   });
146   if (!isInImage(DyldProtocolImpl, "liblinked2")) {
147     printf("[FAIL] _dyld_for_each_objc_protocol: _dyld_for_each_objc_protocol should have returned DyldProtocol from liblinked2\n");
148     return 0;
149   }
150
151   // Visit DyldMainProtocol and make sure it makes the callback for just the result from main.exe
152   __block void* DyldMainProtocolImpl = nil;
153   _dyld_for_each_objc_protocol("DyldMainProtocol", ^(void* protocolPtr, bool isLoaded, bool* stop) {
154     DyldMainProtocolImpl = protocolPtr;
155     *stop = true;
156   });
157   if (!isInImage(DyldMainProtocolImpl, "_dyld_for_each_objc_protocol.exe")) {
158     printf("[FAIL] _dyld_for_each_objc_protocol: _dyld_for_each_objc_protocol should have returned DyldMainProtocol from main.exe\n");
159     return 0;
160   }
161
162   printf("[PASS] _dyld_for_each_objc_protocol\n");
163
164   return 0;
165 }