]> git.saurik.com Git - apple/dyld.git/blob - testing/test-cases/dyld_process_info.dtest/main.c
dyld-519.2.2.tar.gz
[apple/dyld.git] / testing / test-cases / dyld_process_info.dtest / main.c
1
2 // BUILD: $CC linksWithCF.c -o $BUILD_DIR/linksWithCF.exe -framework CoreFoundation
3 // BUILD: $CC main.c -o $BUILD_DIR/dyld_process_info.exe
4 // BUILD: $TASK_FOR_PID_ENABLE $BUILD_DIR/dyld_process_info.exe
5
6 // RUN: $SUDO ./dyld_process_info.exe $RUN_DIR/linksWithCF.exe
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <dlfcn.h>
11 #include <unistd.h>
12 #include <signal.h>
13 #include <spawn.h>
14 #include <errno.h>
15 #include <mach/mach.h>
16 #include <mach/machine.h>
17 #include <mach-o/dyld_process_info.h>
18 #include <Availability.h>
19
20
21 extern char** environ;
22
23 #if __x86_64__
24 cpu_type_t otherArch[] = { CPU_TYPE_I386 };
25 #elif __i386__
26 cpu_type_t otherArch[] = { CPU_TYPE_X86_64 };
27 #elif __arm64__
28 cpu_type_t otherArch[] = { CPU_TYPE_ARM };
29 #elif __arm__
30 cpu_type_t otherArch[] = { CPU_TYPE_ARM64 };
31 #endif
32
33 struct task_and_pid {
34 pid_t pid;
35 task_t task;
36 };
37
38 static struct task_and_pid launchTest(const char* testProgPath, bool launchOtherArch, bool launchSuspended)
39 {
40 posix_spawnattr_t attr = 0;
41 if ( posix_spawnattr_init(&attr) != 0 ) {
42 printf("[FAIL] dyld_process_info posix_spawnattr_init()\n");
43 exit(0);
44 }
45 if ( launchSuspended ) {
46 if ( posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED) != 0 ) {
47 printf("[FAIL] dyld_process_info POSIX_SPAWN_START_SUSPENDED\n");
48 exit(0);
49 }
50 }
51 if ( launchOtherArch ) {
52 size_t copied;
53 if ( posix_spawnattr_setbinpref_np(&attr, 1, otherArch, &copied) != 0 ) {
54 printf("[FAIL] dyld_process_info posix_spawnattr_setbinpref_np()\n");
55 exit(0);
56 }
57 }
58
59 struct task_and_pid child = {0, 0};
60 const char* argv[] = { testProgPath, NULL };
61 int psResult = posix_spawn(&child.pid, testProgPath, NULL, &attr, (char**)argv, environ);
62 if ( psResult != 0 ) {
63 printf("[FAIL] dyld_process_info posix_spawn(%s) failed, err=%d\n", testProgPath, psResult);
64 exit(0);
65 }
66 if (posix_spawnattr_destroy(&attr) != 0) {
67 printf("[FAIL] dyld_process_info posix_spawnattr_destroy()\n");
68 exit(0);
69 }
70
71 if ( task_for_pid(mach_task_self(), child.pid, &child.task) != KERN_SUCCESS ) {
72 printf("[FAIL] dyld_process_info task_for_pid()\n");
73 kill(child.pid, SIGKILL);
74 exit(0);
75 }
76
77 #if __x86_64__
78 //printf("child pid=%d task=%d (%s, %s)\n", child.pid, child.task, launchOtherArch ? "i386" : "x86_64", launchSuspended ? "suspended" : "active");
79 #endif
80
81 // wait until process is up and has suspended itself
82 struct task_basic_info info;
83 do {
84 unsigned count = TASK_BASIC_INFO_COUNT;
85 kern_return_t kr = task_info(child.task, TASK_BASIC_INFO, (task_info_t)&info, &count);
86 sleep(1);
87 } while ( info.suspend_count == 0 );
88
89 return child;
90 }
91
92 static void killTest(struct task_and_pid tp) {
93 int r = kill(tp.pid, SIGKILL);
94 waitpid(tp.pid, &r, 0);
95 }
96
97 static bool hasCF(task_t task, bool launchedSuspended)
98 {
99 kern_return_t result;
100 dyld_process_info info = _dyld_process_info_create(task, 0, &result);
101 if ( info == NULL ) {
102 printf("[FAIL] dyld_process_info _dyld_process_info_create(), kern_return_t=%d\n", result);
103 return false;
104 }
105
106 dyld_process_state_info stateInfo;
107 _dyld_process_info_get_state(info, &stateInfo);
108 bool valueSaysLaunchedSuspended = (stateInfo.dyldState == dyld_process_state_not_started);
109 if ( valueSaysLaunchedSuspended != launchedSuspended ) {
110 printf("[FAIL] dyld_process_info suspend state mismatch\n");
111 return false;
112 }
113
114 __block bool foundDyld = false;
115 _dyld_process_info_for_each_image(info, ^(uint64_t machHeaderAddress, const uuid_t uuid, const char* path) {
116 //fprintf(stderr, "0x%llX %s\n", machHeaderAddress, path);
117 if ( strstr(path, "/usr/lib/dyld") != NULL )
118 foundDyld = true;
119 });
120
121 if ( launchedSuspended ) {
122 // fprintf(stderr, "launched suspended image list:\n");
123 __block bool foundMain = false;
124 _dyld_process_info_for_each_image(info, ^(uint64_t machHeaderAddress, const uuid_t uuid, const char* path) {
125 //fprintf(stderr, "0x%llX %s\n", machHeaderAddress, path);
126 if ( strstr(path, "/linksWithCF.exe") != NULL )
127 foundMain = true;
128 });
129 return foundMain && foundDyld;
130 }
131
132 __block bool foundCF = false;
133 _dyld_process_info_for_each_image(info, ^(uint64_t machHeaderAddress, const uuid_t uuid, const char* path) {
134 //fprintf(stderr, "0x%llX %s\n", machHeaderAddress, path);
135 if ( strstr(path, "/CoreFoundation.framework/") != NULL )
136 foundCF = true;
137 });
138
139 _dyld_process_info_release(info);
140
141 return foundCF && foundDyld;
142 }
143
144
145 int main(int argc, const char* argv[])
146 {
147 kern_return_t kr = KERN_SUCCESS;
148 printf("[BEGIN] dyld_process_info\n");
149
150 if ( argc < 2 ) {
151 printf("[FAIL] dyld_process_info missing argument\n");
152 exit(0);
153 }
154
155 const char* testProgPath = argv[1];
156 struct task_and_pid child;
157
158 // launch test program same arch as this program
159 child = launchTest(testProgPath, false, false);
160 if ( ! hasCF(child.task, false) ) {
161 printf("[FAIL] dyld_process_info same arch does not link with CF and dyld\n");
162 killTest(child);
163 exit(0);
164 }
165 killTest(child);
166
167 // launch test program suspended
168 child = launchTest(testProgPath, false, true);
169 if ( ! hasCF(child.task, true) ) {
170 printf("[FAIL] dyld_process_info suspended does not link with CF and dyld\n");
171 killTest(child);
172 exit(0);
173 }
174 (void)kill(child.pid, SIGCONT);
175 killTest(child);
176
177 #if __MAC_OS_X_VERSION_MIN_REQUIRED
178 // only mac supports multiple architectures, run test program as other arch too
179 child = launchTest(testProgPath, true, false);
180 if ( ! hasCF(child.task, false) ) {
181 printf("[FAIL] dyld_process_info other arch does not link with CF and dyld\n");
182 killTest(child);
183 exit(0);
184 }
185 killTest(child);
186
187 // launch test program suspended
188 child = launchTest(testProgPath, true, true);
189 if ( ! hasCF(child.task, true) ) {
190 printf("[FAIL] dyld_process_info suspended does not link with CF and dyld\n");
191 killTest(child);
192 exit(0);
193 }
194 (void)kill(child.pid, SIGCONT);
195 killTest(child);
196 #endif
197
198 // verify this program does not use CF
199 if ( hasCF(mach_task_self(), false) ) {
200 printf("[FAIL] dyld_process_info self links with CF and dyld\n");
201 exit(0);
202 }
203
204 printf("[PASS] dyld_process_info\n");
205 return 0;
206 }