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