dyld-733.8.tar.gz
[apple/dyld.git] / testing / include / dyld_test.h
1 #include <mach/mach.h>
2
3 #include "darwintest.h"
4
5 T_GLOBAL_META(T_META_NAMESPACE("dyld"));
6
7 extern char** environ;
8
9 #if __x86_64__
10 cpu_type_t otherArch[] = { CPU_TYPE_I386 };
11 #elif __i386__
12 cpu_type_t otherArch[] = { CPU_TYPE_X86_64 };
13 #elif __arm64__
14 cpu_type_t otherArch[] = { CPU_TYPE_ARM };
15 #elif __arm__
16 cpu_type_t otherArch[] = { CPU_TYPE_ARM64 };
17 #endif
18
19 #define T_DECL_DYLD(name, description, ...) \
20 static void dyld_test_ ## name(void); \
21 T_DECL(name, description, ## __VA_ARGS__) { \
22 dyld_test_ ## name(); \
23 } \
24 static void dyld_test_ ## name(void)
25
26 /* Since the test runner manually invokes us in both dyld2 and dyld3 mode we do not need this yet
27
28 T_DECL(name ## _dyld3, description, T_META_ENVVAR("DYLD_USE_CLOSURES=1"), ## __VA_ARGS__) { \
29 dyld_test_ ## name(); \
30 } \
31
32 */
33
34
35 #define T_DLOPEN_EXPECT_NOTNULL(path, mode) \
36 ({ \
37 void* handle = dlopen(path, mode); \
38 T_QUIET; T_ASSERT_NOTNULL(handle, "Image \"%s\" failed to load with error: %s", path, dlerror()); \
39 T_QUIET; T_ASSERT_NULL(dlerror(), "dlerror() should be null after successfull dloepn()"); \
40 handle; \
41 })
42
43 #define T_DLSYM_EXPECT_NOTNULL(handle, symbol) \
44 ({ \
45 const void* sym = dlsym((void *)handle, symbol); \
46 T_QUIET; T_ASSERT_NOTNULL(sym, "dlsym(%s) should not be null", symbol); \
47 sym; \
48 })
49
50 #define T_DLCLOSE_EXPECT_NULL(handle) \
51 ({ \
52 int result = dlclose((void *)handle); \
53 T_QUIET; T_ASSERT_EQ_INT(result, 0, "dlclose() failed with error: %s", dlerror()); \
54 result; \
55 })
56
57 #define T_POSIXSPAWN_ASSERT(launchSuspended, launchOtherArch, program) \
58 ({ \
59 pid_t result = 0; \
60 posix_spawnattr_t attr = 0; \
61 T_QUIET; T_ASSERT_EQ_INT(posix_spawnattr_init(&attr), 0, "dyld_process_info posix_spawnattr_init() failed"); \
62 if ( launchSuspended ) { \
63 int result = posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED); \
64 T_QUIET; T_ASSERT_EQ_INT(result, 0, "posix_spawnattr_setflags() failed"); \
65 } \
66 if ( launchOtherArch ) { \
67 size_t copied; \
68 int result = posix_spawnattr_setbinpref_np(&attr, 1, otherArch, &copied); \
69 T_QUIET; T_ASSERT_EQ_INT(result, 0, "posix_spawnattr_setbinpref_np(), &copied) failed"); \
70 } \
71 const char* argv[] = { program, NULL }; \
72 int psResult = posix_spawn(&result, program, NULL, &attr, (char**)argv, environ); \
73 T_QUIET; T_ASSERT_EQ_INT(psResult, 0, "dyld_process_info posix_spawn(%s) failed, err=%d\n", program, psResult); \
74 T_QUIET; T_ASSERT_EQ_INT(posix_spawnattr_destroy(&attr), KERN_SUCCESS, "posix_spawnattr_destroy() failed"); \
75 result; \
76 })
77
78 #define T_TASK_FOR_PID_ASSERT(pid) \
79 ({ \
80 task_t result; \
81 T_QUIET; T_ASSERT_MACH_SUCCESS(task_for_pid(mach_task_self(), pid, &result), "task_for_pid() failed"); \
82 result; \
83 })
84
85 #pragma pack(4)
86 typedef struct exception_data {
87 mach_msg_header_t Head;
88 mach_msg_body_t msgh_body;
89 mach_msg_port_descriptor_t thread;
90 mach_msg_port_descriptor_t task;
91 NDR_record_t NDR;
92 exception_type_t exception;
93 mach_msg_type_number_t codeCnt;
94 __int64_t code[2];
95 } exception_data;
96 #pragma pack()
97
98 typedef bool(^exceptionValidator)(task_t task);
99
100 #define T_POSIXSPAWN_CRASH(program, validatorFunc, ...) \
101 ({ \
102 pid_t pid = 0; \
103 posix_spawnattr_t attr = 0; \
104 mach_port_t exceptionPort = MACH_PORT_NULL; \
105 T_QUIET; T_ASSERT_EQ_INT(posix_spawnattr_init(&attr), 0, "dyld_process_info posix_spawnattr_init() failed"); \
106 mach_port_options_t options = { .flags = MPO_CONTEXT_AS_GUARD | MPO_STRICT | MPO_INSERT_SEND_RIGHT, .mpl = { 1 }}; \
107 T_QUIET; T_ASSERT_MACH_SUCCESS(mach_port_construct(mach_task_self(), &options, (mach_port_context_t)exceptionPort, \
108 &exceptionPort), "mach_port_construct() failed"); \
109 int epResult = posix_spawnattr_setexceptionports_np(&attr, EXC_MASK_CORPSE_NOTIFY, exceptionPort, \
110 EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, 0); \
111 T_QUIET; T_ASSERT_EQ_INT(epResult, 0, "posix_spawnattr_setexceptionports_np() failed"); \
112 const char* argv[] = { program, NULL }; \
113 int psResult = posix_spawn(&pid, program, NULL, &attr, (char**)argv, environ); \
114 T_QUIET; T_ASSERT_EQ_INT(psResult, 0, "dyld_process_info posix_spawn(%s) failed, err=%d\n", program, psResult); \
115 T_QUIET; T_ASSERT_EQ_INT(posix_spawnattr_destroy(&attr), KERN_SUCCESS, "posix_spawnattr_destroy() failed"); \
116 uint8_t data[MACH_MSG_SIZE_RELIABLE]; \
117 exception_data* request = (exception_data*)&data[0]; \
118 T_QUIET; T_ASSERT_MACH_SUCCESS(mach_msg(&request->Head, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, \
119 MACH_MSG_SIZE_RELIABLE, exceptionPort, 10000, MACH_PORT_NULL), "mach_msg() failed"); \
120 validatorFunc((task_t)request->task.name); \
121 })