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
6 // RUN: $SUDO ./dyld_process_info.exe $RUN_DIR/linksWithCF.exe
17 #include <sys/types.h>
18 #include <mach/mach.h>
19 #include <mach/machine.h>
20 #include <mach-o/dyld_process_info.h>
21 #include <Availability.h>
24 extern char** environ
;
27 cpu_type_t otherArch
[] = { CPU_TYPE_I386
};
29 cpu_type_t otherArch
[] = { CPU_TYPE_X86_64
};
31 cpu_type_t otherArch
[] = { CPU_TYPE_ARM
};
33 cpu_type_t otherArch
[] = { CPU_TYPE_ARM64
};
41 static struct task_and_pid
launchTest(const char* testProgPath
, bool launchOtherArch
, bool launchSuspended
)
43 posix_spawnattr_t attr
= 0;
44 if ( posix_spawnattr_init(&attr
) != 0 ) {
45 printf("[FAIL] dyld_process_info posix_spawnattr_init()\n");
48 if ( launchSuspended
) {
49 if ( posix_spawnattr_setflags(&attr
, POSIX_SPAWN_START_SUSPENDED
) != 0 ) {
50 printf("[FAIL] dyld_process_info POSIX_SPAWN_START_SUSPENDED\n");
54 if ( launchOtherArch
) {
56 if ( posix_spawnattr_setbinpref_np(&attr
, 1, otherArch
, &copied
) != 0 ) {
57 printf("[FAIL] dyld_process_info posix_spawnattr_setbinpref_np()\n");
62 struct task_and_pid child
= {0, 0};
63 const char* argv
[] = { testProgPath
, NULL
};
64 int psResult
= posix_spawn(&child
.pid
, testProgPath
, NULL
, &attr
, (char**)argv
, environ
);
65 if ( psResult
!= 0 ) {
66 printf("[FAIL] dyld_process_info posix_spawn(%s) failed, err=%d\n", testProgPath
, psResult
);
69 if (posix_spawnattr_destroy(&attr
) != 0) {
70 printf("[FAIL] dyld_process_info posix_spawnattr_destroy()\n");
74 if ( task_for_pid(mach_task_self(), child
.pid
, &child
.task
) != KERN_SUCCESS
) {
75 printf("[FAIL] dyld_process_info task_for_pid()\n");
76 kill(child
.pid
, SIGKILL
);
81 //printf("child pid=%d task=%d (%s, %s)\n", child.pid, child.task, launchOtherArch ? "i386" : "x86_64", launchSuspended ? "suspended" : "active");
84 // wait until process is up and has suspended itself
85 struct task_basic_info info
;
87 unsigned count
= TASK_BASIC_INFO_COUNT
;
88 kern_return_t kr
= task_info(child
.task
, TASK_BASIC_INFO
, (task_info_t
)&info
, &count
);
90 } while ( info
.suspend_count
== 0 );
95 static void killTest(struct task_and_pid tp
) {
96 int r
= kill(tp
.pid
, SIGKILL
);
97 waitpid(tp
.pid
, &r
, 0);
100 static bool hasCF(task_t task
, bool launchedSuspended
)
102 kern_return_t result
;
103 dyld_process_info info
= _dyld_process_info_create(task
, 0, &result
);
104 if ( info
== NULL
) {
105 printf("[FAIL] dyld_process_info _dyld_process_info_create(), kern_return_t=%d\n", result
);
109 dyld_process_state_info stateInfo
;
110 _dyld_process_info_get_state(info
, &stateInfo
);
111 bool valueSaysLaunchedSuspended
= (stateInfo
.dyldState
== dyld_process_state_not_started
);
112 if ( valueSaysLaunchedSuspended
!= launchedSuspended
) {
113 printf("[FAIL] dyld_process_info suspend state mismatch\n");
114 _dyld_process_info_release(info
);
118 __block
bool foundDyld
= false;
119 _dyld_process_info_for_each_image(info
, ^(uint64_t machHeaderAddress
, const uuid_t uuid
, const char* path
) {
120 //fprintf(stderr, "0x%llX %s\n", machHeaderAddress, path);
121 if ( strstr(path
, "/dyld") != NULL
)
125 if ( launchedSuspended
) {
126 // fprintf(stderr, "launched suspended image list:\n");
127 __block
bool foundMain
= false;
128 _dyld_process_info_for_each_image(info
, ^(uint64_t machHeaderAddress
, const uuid_t uuid
, const char* path
) {
129 //fprintf(stderr, "0x%llX %s\n", machHeaderAddress, path);
130 if ( strstr(path
, "/linksWithCF.exe") != NULL
)
133 _dyld_process_info_release(info
);
134 return foundMain
&& foundDyld
;
137 __block
bool foundCF
= false;
138 _dyld_process_info_for_each_image(info
, ^(uint64_t machHeaderAddress
, const uuid_t uuid
, const char* path
) {
139 //fprintf(stderr, "0x%llX %s\n", machHeaderAddress, path);
140 if ( strstr(path
, "/CoreFoundation.framework/") != NULL
)
144 _dyld_process_info_release(info
);
146 return foundCF
&& foundDyld
;
149 static void checkForLeaks(const char *name
) {
150 printf("[BEGIN] %s checkForLeaks\n", name
);
153 char buffer
[PAGE_SIZE
];
154 (void)snprintf(&buffer
[0], 128, "%d", getpid());
156 const char* argv
[] = { "/usr/bin/leaks", buffer
, NULL
};
157 int psResult
= posix_spawn(&child
, "/usr/bin/leaks", NULL
, NULL
, (char**)argv
, environ
);
158 if ( psResult
!= 0 ) {
159 printf("[FAIL] %s checkForLeaks posix_spawn failed, err=%d\n", name
, psResult
);
163 (void)wait4(child
, &stat_loc
, 0, NULL
);
164 ssize_t readBytes
= 0;
165 if (WIFEXITED(stat_loc
) == 0) {
166 printf("[FAIL] %s checkForLeaks leaks did not exit\n", name
);
169 if (WEXITSTATUS(stat_loc
) == 1) {
170 printf("[FAIL] %s checkForLeaks found leaks\n", name
);
173 if (WEXITSTATUS(stat_loc
) != 0) {
174 printf("[FAIL] %s checkForLeaks leaks errored out\n", name
);
177 printf("[PASS] %s checkForLeaks\n", name
);
181 int main(int argc
, const char* argv
[])
183 kern_return_t kr
= KERN_SUCCESS
;
184 printf("[BEGIN] dyld_process_info\n");
187 printf("[FAIL] dyld_process_info missing argument\n");
191 const char* testProgPath
= argv
[1];
192 struct task_and_pid child
;
194 // launch test program same arch as this program
195 child
= launchTest(testProgPath
, false, false);
196 if ( ! hasCF(child
.task
, false) ) {
197 printf("[FAIL] dyld_process_info same arch does not link with CF and dyld\n");
203 // launch test program suspended
204 child
= launchTest(testProgPath
, false, true);
205 if ( ! hasCF(child
.task
, true) ) {
206 printf("[FAIL] dyld_process_info suspended does not link with CF and dyld\n");
210 (void)kill(child
.pid
, SIGCONT
);
213 #if __MAC_OS_X_VERSION_MIN_REQUIRED
214 // only mac supports multiple architectures, run test program as other arch too
215 child
= launchTest(testProgPath
, true, false);
216 if ( ! hasCF(child
.task
, false) ) {
217 printf("[FAIL] dyld_process_info other arch does not link with CF and dyld\n");
223 // launch test program suspended
224 child
= launchTest(testProgPath
, true, true);
225 if ( ! hasCF(child
.task
, true) ) {
226 printf("[FAIL] dyld_process_info suspended does not link with CF and dyld\n");
230 (void)kill(child
.pid
, SIGCONT
);
234 // verify this program does not use CF
235 if ( hasCF(mach_task_self(), false) ) {
236 printf("[FAIL] dyld_process_info self links with CF and dyld\n");
240 printf("[PASS] dyld_process_info\n");
241 checkForLeaks("dyld_process_info");