2 // BUILD: $CC foo.c -dynamiclib -install_name /cant/find/me.dylib -o $BUILD_DIR/libmissing.dylib
3 // BUILD: $CC foo.c -dynamiclib $BUILD_DIR/libmissing.dylib -install_name $RUN_DIR/libMissingDylib.dylib -o $BUILD_DIR/libMissingDylib.dylib
4 // BUILD: $CC emptyMain.c $BUILD_DIR/libMissingDylib.dylib -o $BUILD_DIR/prog_missing_dylib.exe
5 // BUILD: $CC defSymbol.c -dynamiclib -install_name $RUN_DIR/libMissingSymbols.dylib -o $BUILD_DIR/libMissingSymbols.dylib
6 // BUILD: $CC defSymbol.c -dynamiclib -install_name $RUN_DIR/libMissingSymbols.dylib -o $BUILD_DIR/libHasSymbols.dylib -DHAS_SYMBOL
7 // BUILD: $CC useSymbol.c $BUILD_DIR/libHasSymbols.dylib -o $BUILD_DIR/prog_missing_symbol.exe
8 // BUILD: $CC main.c -o $BUILD_DIR/dyld_abort_tests.exe
10 // NO_CRASH_LOG: prog_missing_dylib.exe
11 // NO_CRASH_LOG: prog_missing_symbol.exe
13 // RUN: ./dyld_abort_tests.exe
21 #include <mach/mach.h>
22 #include <mach/machine.h>
24 #include <System/sys/reason.h>
25 #include <System/sys/proc_info.h>
26 #include <System/kern/kern_cdata.h>
28 #include <mach-o/dyld_priv.h>
31 static bool sSignalCaught
= false;
32 static bool sChildAbortInfoCorrect
= false;
33 static pid_t sChildPid
= 0;
34 static uint64_t sExpectedDyldReason
= 0;
35 static const char* sExpectedDylibPath
= NULL
;
36 static const char* sExpectedSymbol
= NULL
;
39 static void childDied(int sig
)
42 //printf("sigchld for pid=%d\n", sChildPid);
44 struct proc_exitreasoninfo info
;
45 bzero(&info
, sizeof(info
));
46 uint8_t packReasonData
[OS_REASON_BUFFER_MAX_SIZE
];
47 bzero(packReasonData
, OS_REASON_BUFFER_MAX_SIZE
);
48 info
.eri_reason_buf_size
= OS_REASON_BUFFER_MAX_SIZE
;
49 info
.eri_kcd_buf
= (user_addr_t
)packReasonData
;
50 //fprintf(stderr, "info=%p\n", &info);
51 int procResult
= proc_pidinfo(sChildPid
, PROC_PIDEXITREASONINFO
, 1, &info
, PROC_PIDEXITREASONINFO_SIZE
);
52 if ( procResult
!= sizeof(struct proc_exitreasoninfo
) ) {
53 printf("bad return size from proc_pidinfo(), %d expected %lu\n", procResult
, PROC_PIDEXITREASONINFO_SIZE
);
56 if ( info
.eri_namespace
!= OS_REASON_DYLD
) {
57 printf("eri_namespace (%d) != OS_REASON_DYLD\n", info
.eri_namespace
);
60 if ( info
.eri_code
!= sExpectedDyldReason
) {
61 printf("eri_code (%llu) != %lld\n", sExpectedDyldReason
, info
.eri_code
);
64 kcdata_iter_t iter
= kcdata_iter(packReasonData
, info
.eri_reason_buf_size
);
66 if ( !kcdata_iter_valid(iter
) ) {
67 printf("invalid kcdata iterator from payload data\n");
71 if ( kcdata_iter_type(iter
) != KCDATA_BUFFER_BEGIN_OS_REASON
){
72 printf("first kcdata from payload data is not KCDATA_BUFFER_BEGIN_OS_REASON\n");
76 kcdata_iter_t payloadIter
= kcdata_iter_find_type(iter
, EXIT_REASON_USER_PAYLOAD
);
77 if ( !kcdata_iter_valid(payloadIter
) ) {
78 printf("invalid kcdata payload iterator from payload data\n");
81 const dyld_abort_payload
* dyldInfo
= (dyld_abort_payload
*)kcdata_iter_payload(payloadIter
);
83 if ( dyldInfo
->version
!= 1 ) {
84 printf("dyld payload is not version 1\n");
88 if ( (dyldInfo
->flags
& 1) == 0 ) {
89 printf("dyld flags should have low bit set to me process terminated at launch\n");
93 if ( sExpectedDylibPath
!= NULL
) {
94 if ( dyldInfo
->targetDylibPathOffset
!= 0 ) {
95 const char* targetDylib
= (char*)dyldInfo
+ dyldInfo
->targetDylibPathOffset
;
96 if ( strstr(targetDylib
, sExpectedDylibPath
) == NULL
) {
97 printf("dylib path (%s) not what expected (%s)\n", targetDylib
, sExpectedDylibPath
);
102 printf("dylib path (%s) not provided by dyld\n", sExpectedDylibPath
);
107 if ( sExpectedSymbol
!= NULL
) {
108 if ( dyldInfo
->targetDylibPathOffset
!= 0 ) {
109 const char* missingSymbol
= (char*)dyldInfo
+ dyldInfo
->symbolOffset
;
110 if ( strcmp(sExpectedSymbol
, missingSymbol
) != 0 ) {
111 printf("symbol (%s) not what expected (%s)\n", missingSymbol
, sExpectedSymbol
);
116 printf("symbol (%s) not provided by dyld\n", sExpectedSymbol
);
121 sChildAbortInfoCorrect
= true;
125 bool runTest(const char* prog
, uint64_t dyldReason
, const char* expectedDylibPath
, const char* expectedSymbol
)
127 sSignalCaught
= false;
128 sChildAbortInfoCorrect
= false;
129 sExpectedDyldReason
= dyldReason
;
130 sExpectedDylibPath
= expectedDylibPath
;
131 sExpectedSymbol
= expectedSymbol
;
133 // fork and exec child
136 err(EXIT_FAILURE
, "fork");
137 if ( sChildPid
== 0 ) {
139 char* childArgv
[] = { (char*)prog
, NULL
};
140 int result
= execvp(prog
, childArgv
);
141 err(EXIT_FAILURE
, "exec(\"%s\",...)", prog
);
143 for(int i
=0; i
< 10; ++i
) {
149 return sChildAbortInfoCorrect
;
153 int main(int argc
, const char* argv
[])
155 bool someTestFailed
= false;
156 printf("[BEGIN] dyld_abort_payload\n");
158 // set up signal handler for catching child terminations
159 signal(SIGCHLD
, childDied
);
161 // test launch program with missing library
162 if ( !runTest("./prog_missing_dylib.exe", DYLD_EXIT_REASON_DYLIB_MISSING
, "/cant/find/me.dylib", NULL
) ) {
163 printf("[FAIL] dyld_abort_payload DYLD_EXIT_REASON_DYLIB_MISSING\n");
164 someTestFailed
= true;
167 // test launch program with missing symbol
168 if ( !runTest("./prog_missing_symbol.exe", DYLD_EXIT_REASON_SYMBOL_MISSING
, "libMissingSymbols.dylib", "_slipperySymbol") ) {
169 printf("[FAIL] dyld_abort_payload DYLD_EXIT_REASON_SYMBOL_MISSING\n");
170 someTestFailed
= true;
173 if ( !someTestFailed
)
174 printf("[PASS] dyld_abort_payload\n");