dyld-832.7.1.tar.gz
[apple/dyld.git] / testing / test-cases / dyld_process_info.dtest / main.cpp
1
2 // BUILD: $CC linksWithCF.c -o $BUILD_DIR/linksWithCF.exe -framework CoreFoundation
3 // BUILD: $CXX main.cpp -o $BUILD_DIR/dyld_process_info.exe -DRUN_DIR="$RUN_DIR"
4 // BUILD: $TASK_FOR_PID_ENABLE $BUILD_DIR/dyld_process_info.exe
5
6 // RUN: $SUDO ./dyld_process_info.exe
7
8 #include <Block.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <dlfcn.h>
12 #include <unistd.h>
13 #include <signal.h>
14 #include <spawn.h>
15 #include <errno.h>
16 #include <sys/uio.h>
17 #include <sys/wait.h>
18 #include <sys/types.h>
19 #include <mach/mach.h>
20 #include <mach/machine.h>
21 #include <mach-o/dyld_priv.h>
22 #include <mach-o/dyld_process_info.h>
23 #include <Availability.h>
24
25 #include "test_support.h"
26
27
28 static void inspectProcess(task_t task, bool launchedSuspended, bool expectCF, bool forceIOSMac)
29 {
30 kern_return_t result;
31 dyld_process_info info = _dyld_process_info_create(task, 0, &result);
32 if (result != KERN_SUCCESS) {
33 FAIL("dyld_process_info() should succeed");
34 }
35 if (info == NULL) {
36 FAIL("dyld_process_info(task, 0) alwats return a value");
37 }
38
39 dyld_process_state_info stateInfo;
40 bzero(&stateInfo, sizeof(stateInfo));
41 _dyld_process_info_get_state(info, &stateInfo);
42 if ((stateInfo.dyldState == dyld_process_state_not_started) != launchedSuspended) {
43 FAIL("If launchSuspended then stateInfo.dyldState shoould be dyld_process_state_not_started");
44 }
45 if ( !launchedSuspended ) {
46 if (stateInfo.dyldState < dyld_process_state_libSystem_initialized) { FAIL("libSystem should be initalized by now"); }
47 if (stateInfo.imageCount == 0) { return FAIL("image count should be > 0"); }
48 if (stateInfo.initialImageCount == 0) { return FAIL("initial image count should be > 0"); }
49 if (stateInfo.imageCount < stateInfo.initialImageCount) { FAIL("image count should be >= initial image count"); }
50 }
51
52 dyld_platform_t remotePlatform = _dyld_process_info_get_platform(info);
53 dyld_platform_t localPlatform = dyld_get_active_platform();
54 if (launchedSuspended) {
55 if (remotePlatform != 0) {
56 FAIL("_dyld_process_info_get_platform() should be 0 for launchSuspended processes");
57 }
58 } else if (forceIOSMac && (remotePlatform != PLATFORM_MACCATALYST)) {
59 FAIL("_dyld_process_info_get_platform(%u) should be PLATFORM_MACCATALYST", remotePlatform);
60 } else if (!forceIOSMac && (remotePlatform != localPlatform)) {
61 FAIL("_dyld_process_info_get_platform(%u) should be the same dyld_get_active_platform(%u)",
62 remotePlatform, localPlatform);
63 }
64
65 __block bool foundDyld = false;
66 __block bool foundMain = false;
67 __block bool foundCF = false;
68 _dyld_process_info_for_each_image(info, ^(uint64_t machHeaderAddress, const uuid_t uuid, const char* path) {
69 if ( strstr(path, "/dyld") != NULL )
70 foundDyld = true;
71 if ( strstr(path, "/linksWithCF.exe") != NULL )
72 foundMain = true;
73 if ( strstr(path, "/dyld_process_info.exe") != NULL )
74 foundMain = true;
75 if ( strstr(path, "/CoreFoundation.framework/") != NULL )
76 foundCF = true;
77 });
78 if (!foundDyld) { FAIL("dyld should always be in the image list"); }
79 if (!foundMain) { FAIL("The main executable should always be in the image list"); }
80 if (expectCF && !foundCF) { FAIL("CF should be in the image list"); }
81
82 _dyld_process_info_release(info);
83 }
84
85 #if __x86_64__
86 cpu_type_t otherArch[] = { CPU_TYPE_I386 };
87 #elif __i386__
88 cpu_type_t otherArch[] = { CPU_TYPE_X86_64 };
89 #elif __arm64__
90 cpu_type_t otherArch[] = { CPU_TYPE_ARM };
91 #elif __arm__
92 cpu_type_t otherArch[] = { CPU_TYPE_ARM64 };
93 #endif
94
95
96 static void launchTest(bool launchOtherArch, bool launchSuspended, bool forceIOSMac)
97 {
98 LOG("launchTest %s", launchSuspended ? "suspended" : "unsuspended");
99 const char * program = RUN_DIR "/linksWithCF.exe";
100
101 _process process;
102 process.set_executable_path(RUN_DIR "/linksWithCF.exe");
103 process.set_launch_suspended(launchSuspended);
104 process.set_launch_async(true);
105 if (forceIOSMac) {
106 LOG("Launching native");
107 const char* env[] = { "TEST_OUTPUT=None", "DYLD_FORCE_PLATFORM=6", NULL};
108 process.set_env(env);
109 } else {
110 LOG("Launching iOSMac");
111 const char* env[] = { "TEST_OUTPUT=None", NULL};
112 process.set_env(env);
113 }
114 pid_t pid = process.launch();
115 LOG("launchTest pid: %d", pid);
116
117 task_t task;
118 if (task_for_pid(mach_task_self(), pid, &task) != KERN_SUCCESS) {
119 FAIL("task_for_pid() failed");
120 }
121 LOG("launchTest task: %u", task);
122
123 // wait until process is up and has suspended itself
124 if (!launchSuspended) {
125 dispatch_queue_t queue = dispatch_queue_create("com.apple.test.dyld_process_info", NULL);
126 // We do this instead of using a dispatch_semaphore to prevent priority inversions
127 dispatch_block_t oneShotSemaphore = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{});
128 dispatch_source_t signalSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGUSR1,
129 0, queue);
130 dispatch_source_set_event_handler(signalSource, ^{
131 LOG("Recieved signal");
132 oneShotSemaphore();
133 dispatch_source_cancel(signalSource);
134 });
135 dispatch_resume(signalSource);
136 dispatch_block_wait(oneShotSemaphore, DISPATCH_TIME_FOREVER);
137 }
138 LOG("task running");
139
140 inspectProcess(task, launchSuspended, !launchSuspended, forceIOSMac);
141 }
142
143 int main(int argc, const char* argv[], const char* envp[], const char* apple[]) {
144 signal(SIGUSR1, SIG_IGN);
145 TIMEOUT(120);
146 launchTest(false, false, false);
147 launchTest(false, true, false);
148 #if __MAC_OS_X_VERSION_MIN_REQUIRED
149 // FIXME: Reenable these ones i386 is turned back on for simulators
150 //launchTest(true, false, false);
151 //launchTest(true, true, false);
152 launchTest(false, false, true);
153 launchTest(false, true, true);
154 //FIXME: This functionality is broken, but it is an edge case no one should ever hit
155 //launchTest(true, true, true);
156 #endif
157 dispatch_async( dispatch_get_main_queue(), ^{
158 inspectProcess(mach_task_self(), false, false, false);
159 PASS("Success");
160 });
161 dispatch_main();
162 }