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 $RUN_DIR/libMissingSymbols.dylib -o $BUILD_DIR/libMissingSymbols.dylib
5 // BUILD: $CC defSymbol.c -dynamiclib -install_name $RUN_DIR/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 // NO_CRASH_LOG: prog_missing_dylib.exe
10 // NO_CRASH_LOG: prog_missing_symbol.exe
12 // RUN: ./dyld_abort_tests.exe
20 #include <mach/mach.h>
21 #include <mach/machine.h>
23 #include <System/sys/reason.h>
24 #include <System/sys/proc_info.h>
25 #include <System/kern/kern_cdata.h>
27 #include <mach-o/dyld_priv.h>
30 static bool sSignalCaught
= false;
31 static bool sChildAbortInfoCorrect
= false;
32 static pid_t sChildPid
= 0;
33 static uint64_t sExpectedDyldReason
= 0;
34 static const char* sExpectedDylibPath
= NULL
;
35 static const char* sExpectedSymbol
= NULL
;
38 static void childDied(int sig
)
41 //printf("sigchld for pid=%d\n", sChildPid);
43 struct proc_exitreasoninfo info
;
44 bzero(&info
, sizeof(info
));
45 uint8_t packReasonData
[OS_REASON_BUFFER_MAX_SIZE
];
46 bzero(packReasonData
, OS_REASON_BUFFER_MAX_SIZE
);
47 info
.eri_reason_buf_size
= OS_REASON_BUFFER_MAX_SIZE
;
48 info
.eri_kcd_buf
= (user_addr_t
)packReasonData
;
49 //fprintf(stderr, "info=%p\n", &info);
50 int procResult
= proc_pidinfo(sChildPid
, PROC_PIDEXITREASONINFO
, 1, &info
, PROC_PIDEXITREASONINFO_SIZE
);
51 if ( procResult
!= sizeof(struct proc_exitreasoninfo
) ) {
52 printf("bad return size from proc_pidinfo(), %d expected %lu\n", procResult
, PROC_PIDEXITREASONINFO_SIZE
);
55 if ( info
.eri_namespace
!= OS_REASON_DYLD
) {
56 printf("eri_namespace (%d) != OS_REASON_DYLD\n", info
.eri_namespace
);
59 if ( info
.eri_code
!= sExpectedDyldReason
) {
60 printf("eri_code (%llu) != %lld\n", sExpectedDyldReason
, info
.eri_code
);
63 kcdata_iter_t iter
= kcdata_iter(packReasonData
, info
.eri_reason_buf_size
);
65 if ( !kcdata_iter_valid(iter
) ) {
66 printf("invalid kcdata iterator from payload data\n");
70 if ( kcdata_iter_type(iter
) != KCDATA_BUFFER_BEGIN_OS_REASON
){
71 printf("first kcdata from payload data is not KCDATA_BUFFER_BEGIN_OS_REASON\n");
75 kcdata_iter_t payloadIter
= kcdata_iter_find_type(iter
, EXIT_REASON_USER_PAYLOAD
);
76 if ( !kcdata_iter_valid(payloadIter
) ) {
77 printf("invalid kcdata payload iterator from payload data\n");
80 const dyld_abort_payload
* dyldInfo
= (dyld_abort_payload
*)kcdata_iter_payload(payloadIter
);
82 if ( dyldInfo
->version
!= 1 ) {
83 printf("dyld payload is not version 1\n");
87 if ( (dyldInfo
->flags
& 1) == 0 ) {
88 printf("dyld flags should have low bit set to me process terminated at launch\n");
92 if ( sExpectedDylibPath
!= NULL
) {
93 if ( dyldInfo
->targetDylibPathOffset
!= 0 ) {
94 const char* targetDylib
= (char*)dyldInfo
+ dyldInfo
->targetDylibPathOffset
;
95 if ( strstr(targetDylib
, sExpectedDylibPath
) == NULL
) {
96 printf("dylib path (%s) not what expected (%s)\n", targetDylib
, sExpectedDylibPath
);
101 printf("dylib path (%s) not provided by dyld\n", sExpectedDylibPath
);
106 if ( sExpectedSymbol
!= NULL
) {
107 if ( dyldInfo
->targetDylibPathOffset
!= 0 ) {
108 const char* missingSymbol
= (char*)dyldInfo
+ dyldInfo
->symbolOffset
;
109 if ( strcmp(sExpectedSymbol
, missingSymbol
) != 0 ) {
110 printf("symbol (%s) not what expected (%s)\n", missingSymbol
, sExpectedSymbol
);
115 printf("symbol (%s) not provided by dyld\n", sExpectedSymbol
);
120 sChildAbortInfoCorrect
= true;
124 bool runTest(const char* prog
, uint64_t dyldReason
, const char* expectedDylibPath
, const char* expectedSymbol
)
126 sSignalCaught
= false;
127 sChildAbortInfoCorrect
= false;
128 sExpectedDyldReason
= dyldReason
;
129 sExpectedDylibPath
= expectedDylibPath
;
130 sExpectedSymbol
= expectedSymbol
;
132 // fork and exec child
135 err(EXIT_FAILURE
, "fork");
136 if ( sChildPid
== 0 ) {
138 char* childArgv
[] = { (char*)prog
, NULL
};
139 int result
= execvp(prog
, childArgv
);
140 err(EXIT_FAILURE
, "exec(\"%s\",...)", prog
);
142 for(int i
=0; i
< 10; ++i
) {
148 return sChildAbortInfoCorrect
;
152 int main(int argc
, const char* argv
[])
154 bool someTestFailed
= false;
155 printf("[BEGIN] dyld_abort_payload\n");
157 // set up signal handler for catching child terminations
158 signal(SIGCHLD
, childDied
);
160 // test launch program with missing library
161 if ( !runTest("./prog_missing_dylib.exe", DYLD_EXIT_REASON_DYLIB_MISSING
, "/cant/find/me.dylib", NULL
) ) {
162 printf("[FAIL] dyld_abort_payload DYLD_EXIT_REASON_DYLIB_MISSING\n");
163 someTestFailed
= true;
166 // test launch program with missing symbol
167 if ( !runTest("./prog_missing_symbol.exe", DYLD_EXIT_REASON_SYMBOL_MISSING
, "libMissingSymbols.dylib", "_slipperySymbol") ) {
168 printf("[FAIL] dyld_abort_payload DYLD_EXIT_REASON_SYMBOL_MISSING\n");
169 someTestFailed
= true;
172 if ( !someTestFailed
)
173 printf("[PASS] dyld_abort_payload\n");