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
15 #include <mach/mach.h>
16 #include <mach/machine.h>
17 #include <mach-o/dyld_process_info.h>
18 #include <Availability.h>
21 extern char** environ
;
24 cpu_type_t otherArch
[] = { CPU_TYPE_I386
};
26 cpu_type_t otherArch
[] = { CPU_TYPE_X86_64
};
28 cpu_type_t otherArch
[] = { CPU_TYPE_ARM
};
30 cpu_type_t otherArch
[] = { CPU_TYPE_ARM64
};
38 static struct task_and_pid
launchTest(const char* testProgPath
, bool launchOtherArch
, bool launchSuspended
)
40 posix_spawnattr_t attr
= 0;
41 if ( posix_spawnattr_init(&attr
) != 0 ) {
42 printf("[FAIL] dyld_process_info posix_spawnattr_init()\n");
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");
51 if ( launchOtherArch
) {
53 if ( posix_spawnattr_setbinpref_np(&attr
, 1, otherArch
, &copied
) != 0 ) {
54 printf("[FAIL] dyld_process_info posix_spawnattr_setbinpref_np()\n");
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
);
66 if (posix_spawnattr_destroy(&attr
) != 0) {
67 printf("[FAIL] dyld_process_info posix_spawnattr_destroy()\n");
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
);
78 //printf("child pid=%d task=%d (%s, %s)\n", child.pid, child.task, launchOtherArch ? "i386" : "x86_64", launchSuspended ? "suspended" : "active");
81 // wait until process is up and has suspended itself
82 struct task_basic_info info
;
84 unsigned count
= TASK_BASIC_INFO_COUNT
;
85 kern_return_t kr
= task_info(child
.task
, TASK_BASIC_INFO
, (task_info_t
)&info
, &count
);
87 } while ( info
.suspend_count
== 0 );
92 static void killTest(struct task_and_pid tp
) {
93 int r
= kill(tp
.pid
, SIGKILL
);
94 waitpid(tp
.pid
, &r
, 0);
97 static bool hasCF(task_t task
, bool launchedSuspended
)
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
);
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");
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
)
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
)
129 return foundMain
&& foundDyld
;
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
)
139 _dyld_process_info_release(info
);
141 return foundCF
&& foundDyld
;
145 int main(int argc
, const char* argv
[])
147 kern_return_t kr
= KERN_SUCCESS
;
148 printf("[BEGIN] dyld_process_info\n");
151 printf("[FAIL] dyld_process_info missing argument\n");
155 const char* testProgPath
= argv
[1];
156 struct task_and_pid child
;
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");
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");
174 (void)kill(child
.pid
, SIGCONT
);
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");
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");
194 (void)kill(child
.pid
, SIGCONT
);
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");
204 printf("[PASS] dyld_process_info\n");