2 // BUILD: $CC foo.c -dynamiclib -install_name /cant/find/me.dylib -o $BUILD_DIR/libmissing.dylib
3 // BUILD: $CC emptyMain.c $BUILD_DIR/libmissing.dylib -o $BUILD_DIR/prog_missing_dylib.exe
4 // BUILD: $CC defSymbol.c -dynamiclib -install_name libMissingSymbols.dylib -o $BUILD_DIR/libMissingSymbols.dylib
5 // BUILD: $CC defSymbol.c -dynamiclib -install_name libMissingSymbols.dylib -o $BUILD_DIR/libHasSymbols.dylib -DHAS_SYMBOL
6 // BUILD: $CC useSymbol.c $BUILD_DIR/libHasSymbols.dylib -o $BUILD_DIR/prog_missing_symbol.exe
7 // BUILD: $CC main.c -o $BUILD_DIR/dyld_abort_tests.exe
9 // RUN: ./dyld_abort_tests.exe
17 #include <mach/mach.h>
18 #include <mach/machine.h>
20 #include <System/sys/reason.h>
21 #include <System/sys/proc_info.h>
22 #include <System/kern/kern_cdata.h>
24 #include <mach-o/dyld_priv.h>
27 static bool sSignalCaught
= false;
28 static bool sChildAbortInfoCorrect
= false;
29 static pid_t sChildPid
= 0;
30 static uint64_t sExpectedDyldReason
= 0;
31 static const char* sExpectedDylibPath
= NULL
;
32 static const char* sExpectedSymbol
= NULL
;
35 static void childDied(int sig
)
38 //printf("sigchld for pid=%d\n", sChildPid);
40 struct proc_exitreasoninfo info
;
41 bzero(&info
, sizeof(info
));
42 uint8_t packReasonData
[OS_REASON_BUFFER_MAX_SIZE
];
43 bzero(packReasonData
, OS_REASON_BUFFER_MAX_SIZE
);
44 info
.eri_reason_buf_size
= OS_REASON_BUFFER_MAX_SIZE
;
45 info
.eri_kcd_buf
= (user_addr_t
)packReasonData
;
46 //fprintf(stderr, "info=%p\n", &info);
47 if ( proc_pidinfo(sChildPid
, PROC_PIDEXITREASONINFO
, 1, &info
, PROC_PIDEXITREASONINFO_SIZE
) != sizeof(struct proc_exitreasoninfo
) ) {
48 printf("bad return size from proc_pidinfo()\n");
51 if ( info
.eri_namespace
!= OS_REASON_DYLD
) {
52 printf("eri_namespace != OS_REASON_DYLD\n");
55 if ( info
.eri_code
!= sExpectedDyldReason
) {
56 printf("eri_code != %lld\n", sExpectedDyldReason
);
59 kcdata_iter_t iter
= kcdata_iter(packReasonData
, info
.eri_reason_buf_size
);
61 if ( !kcdata_iter_valid(iter
) ) {
62 printf("invalid kcdata iterator from payload data\n");
66 if ( kcdata_iter_type(iter
) != KCDATA_BUFFER_BEGIN_OS_REASON
){
67 printf("first kcdata from payload data is not KCDATA_BUFFER_BEGIN_OS_REASON\n");
71 kcdata_iter_t payloadIter
= kcdata_iter_find_type(iter
, EXIT_REASON_USER_PAYLOAD
);
72 if ( !kcdata_iter_valid(payloadIter
) ) {
73 printf("invalid kcdata payload iterator from payload data\n");
76 const dyld_abort_payload
* dyldInfo
= (dyld_abort_payload
*)kcdata_iter_payload(payloadIter
);
78 if ( dyldInfo
->version
!= 1 ) {
79 printf("dyld payload is not version 1\n");
83 if ( (dyldInfo
->flags
& 1) == 0 ) {
84 printf("dyld flags should have low bit set to me process terminated at launch\n");
88 if ( sExpectedDylibPath
!= NULL
) {
89 if ( dyldInfo
->targetDylibPathOffset
!= 0 ) {
90 const char* targetDylib
= (char*)dyldInfo
+ dyldInfo
->targetDylibPathOffset
;
91 if ( strcmp(sExpectedDylibPath
, targetDylib
) != 0 ) {
92 printf("dylib path (%s) not what expected (%s)\n", targetDylib
, sExpectedDylibPath
);
97 printf("dylib path (%s) not provided by dyld\n", sExpectedDylibPath
);
102 if ( sExpectedSymbol
!= NULL
) {
103 if ( dyldInfo
->targetDylibPathOffset
!= 0 ) {
104 const char* missingSymbol
= (char*)dyldInfo
+ dyldInfo
->symbolOffset
;
105 if ( strcmp(sExpectedSymbol
, missingSymbol
) != 0 ) {
106 printf("symbol (%s) not what expected (%s)\n", missingSymbol
, sExpectedSymbol
);
111 printf("symbol (%s) not provided by dyld\n", sExpectedSymbol
);
116 sChildAbortInfoCorrect
= true;
120 bool runTest(const char* prog
, uint64_t dyldReason
, const char* expectedDylibPath
, const char* expectedSymbol
)
122 sSignalCaught
= false;
123 sChildAbortInfoCorrect
= false;
124 sExpectedDyldReason
= dyldReason
;
125 sExpectedDylibPath
= expectedDylibPath
;
126 sExpectedSymbol
= expectedSymbol
;
128 // fork and exec child
131 err(EXIT_FAILURE
, "fork");
132 if ( sChildPid
== 0 ) {
134 char* childArgv
[] = { (char*)prog
, NULL
};
135 int result
= execvp(prog
, childArgv
);
136 err(EXIT_FAILURE
, "exec(\"%s\",...)", prog
);
138 for(int i
=0; i
< 10; ++i
) {
144 return sChildAbortInfoCorrect
;
148 int main(int argc
, const char* argv
[])
150 bool someTestFailed
= false;
151 printf("[BEGIN] dyld_abort_payload\n");
153 // set up signal handler for catching child terminations
154 signal(SIGCHLD
, childDied
);
156 // test launch program with missing library
157 if ( !runTest("./prog_missing_dylib.exe", DYLD_EXIT_REASON_DYLIB_MISSING
, "/cant/find/me.dylib", NULL
) ) {
158 printf("[FAIL] dyld_abort_payload DYLD_EXIT_REASON_DYLIB_MISSING\n");
159 someTestFailed
= true;
162 // test launch program with missing symbol
163 if ( !runTest("./prog_missing_symbol.exe", DYLD_EXIT_REASON_SYMBOL_MISSING
, "libMissingSymbols.dylib", "_slipperySymbol") ) {
164 printf("[FAIL] dyld_abort_payload DYLD_EXIT_REASON_SYMBOL_MISSING\n");
165 someTestFailed
= true;
168 if ( !someTestFailed
)
169 printf("[PASS] dyld_abort_payload\n");