]> git.saurik.com Git - apple/dyld.git/blob - testing/test-cases/dyld_process_info.dtest/main.c
9e5b41e28715105eb3cdeab65a235cbae7da0f1a
[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
19
20 extern char** environ;
21
22 #if __x86_64__
23 cpu_type_t otherArch[] = { CPU_TYPE_I386 };
24 #elif __i386__
25 cpu_type_t otherArch[] = { CPU_TYPE_X86_64 };
26 #elif __arm64__
27 cpu_type_t otherArch[] = { CPU_TYPE_ARM };
28 #elif __arm__
29 cpu_type_t otherArch[] = { CPU_TYPE_ARM64 };
30 #endif
31
32 static task_t launchTest(const char* testProgPath, bool launchOtherArch, bool launchSuspended)
33 {
34 posix_spawnattr_t attr;
35 if ( posix_spawnattr_init(&attr) != 0 ) {
36 printf("[FAIL] dyld_process_info posix_spawnattr_init()\n");
37 exit(0);
38 }
39 if ( launchSuspended ) {
40 if ( posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED) != 0 ) {
41 printf("[FAIL] dyld_process_info POSIX_SPAWN_START_SUSPENDED\n");
42 exit(0);
43 }
44 }
45 if ( launchOtherArch ) {
46 size_t copied;
47 if ( posix_spawnattr_setbinpref_np(&attr, 1, otherArch, &copied) != 0 ) {
48 printf("[FAIL] dyld_process_info posix_spawnattr_setbinpref_np()\n");
49 exit(0);
50 }
51 }
52
53 pid_t childPid;
54 const char* argv[] = { testProgPath, NULL };
55 int psResult = posix_spawn(&childPid, testProgPath, NULL, &attr, (char**)argv, environ);
56 if ( psResult != 0 ) {
57 printf("[FAIL] dyld_process_info posix_spawn(%s) failed, err=%d\n", testProgPath, psResult);
58 exit(0);
59 }
60 //printf("child pid=%d\n", childPid);
61
62 task_t childTask = 0;
63 if ( task_for_pid(mach_task_self(), childPid, &childTask) != KERN_SUCCESS ) {
64 printf("[FAIL] dyld_process_info task_for_pid()\n");
65 kill(childPid, SIGKILL);
66 exit(0);
67 }
68
69 // wait until process is up and has suspended itself
70 struct task_basic_info info;
71 do {
72 unsigned count = TASK_BASIC_INFO_COUNT;
73 kern_return_t kr = task_info(childTask, TASK_BASIC_INFO, (task_info_t)&info, &count);
74 sleep(1);
75 } while ( info.suspend_count == 0 );
76
77 return childTask;
78 }
79
80 static bool hasCF(task_t task, bool launchedSuspended)
81 {
82 kern_return_t result;
83 dyld_process_info info = _dyld_process_info_create(task, 0, &result);
84 if ( info == NULL ) {
85 printf("[FAIL] dyld_process_info _dyld_process_info_create(), kern_return_t=%d\n", result);
86 return false;
87 }
88
89 dyld_process_state_info stateInfo;
90 _dyld_process_info_get_state(info, &stateInfo);
91 bool valueSaysLaunchedSuspended = (stateInfo.dyldState == dyld_process_state_not_started);
92 if ( valueSaysLaunchedSuspended != launchedSuspended ) {
93 printf("[FAIL] dyld_process_info suspend state mismatch\n");
94 return false;
95 }
96
97 __block bool foundDyld = false;
98 _dyld_process_info_for_each_image(info, ^(uint64_t machHeaderAddress, const uuid_t uuid, const char* path) {
99 //fprintf(stderr, "0x%llX %s\n", machHeaderAddress, path);
100 if ( strstr(path, "/usr/lib/dyld") != NULL )
101 foundDyld = true;
102 });
103
104 if ( launchedSuspended ) {
105 // fprintf(stderr, "launched suspended image list:\n");
106 __block bool foundMain = false;
107 _dyld_process_info_for_each_image(info, ^(uint64_t machHeaderAddress, const uuid_t uuid, const char* path) {
108 //fprintf(stderr, "0x%llX %s\n", machHeaderAddress, path);
109 if ( strstr(path, "/linksWithCF.exe") != NULL )
110 foundMain = true;
111 });
112 return foundMain && foundDyld;
113 }
114
115 __block bool foundCF = false;
116 _dyld_process_info_for_each_image(info, ^(uint64_t machHeaderAddress, const uuid_t uuid, const char* path) {
117 //fprintf(stderr, "0x%llX %s\n", machHeaderAddress, path);
118 if ( strstr(path, "/CoreFoundation.framework/") != NULL )
119 foundCF = true;
120 });
121
122 _dyld_process_info_release(info);
123
124 return foundCF && foundDyld;
125 }
126
127
128 int main(int argc, const char* argv[])
129 {
130 printf("[BEGIN] dyld_process_info\n");
131
132 if ( argc < 2 ) {
133 printf("[FAIL] dyld_process_info missing argument\n");
134 exit(0);
135 }
136 const char* testProgPath = argv[1];
137 task_t childTask;
138
139 // launch test program same arch as this program
140 childTask = launchTest(testProgPath, false, false);
141 if ( ! hasCF(childTask, false) ) {
142 printf("[FAIL] dyld_process_info same arch does not link with CF and dyld\n");
143 task_terminate(childTask);
144 exit(0);
145 }
146 task_terminate(childTask);
147
148 // launch test program suspended
149 childTask = launchTest(testProgPath, false, true);
150 if ( ! hasCF(childTask, true) ) {
151 printf("[FAIL] dyld_process_info suspended does not link with CF and dyld\n");
152 task_terminate(childTask);
153 exit(0);
154 }
155 task_resume(childTask);
156 task_terminate(childTask);
157
158 #if !TARGET_OS_WATCH && !TARGET_OS_TV && __LP64__
159 // on 64/32 devices, run test program as other arch too
160 childTask = launchTest(testProgPath, true, false);
161 if ( ! hasCF(childTask, false) ) {
162 printf("[FAIL] dyld_process_info other arch does not link with CF and dyld\n");
163 task_terminate(childTask);
164 exit(0);
165 }
166 task_terminate(childTask);
167 #endif
168
169 // verify this program does not use CF
170 if ( hasCF(mach_task_self(), false) ) {
171 printf("[FAIL] dyld_process_info self links with CF and dyld\n");
172 exit(0);
173 }
174
175 printf("[PASS] dyld_process_info\n");
176 return 0;
177 }