1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #define _FORTIFY_SOURCE 0
36 #include <mach/mach.h>
37 #include <mach/mach_time.h>
41 #include <sys/ioctl.h>
42 #include <TargetConditionals.h>
43 #include <libkern/OSAtomic.h>
46 #include <corecrypto/ccdigest.h>
47 #include <corecrypto/ccsha1.h>
48 #include <corecrypto/ccsha2.h>
50 #if TARGET_OS_SIMULATOR
51 #include "dyldSyscallInterface.h"
52 #include <mach-o/dyld_images.h>
53 #include <mach-o/loader.h>
54 #include <mach-o/nlist.h>
55 #include <mach/kern_return.h>
57 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
58 typedef struct segment_command_64 macho_segment_command
;
59 typedef struct mach_header_64 macho_header
;
60 typedef struct nlist_64 macho_nlist
;
62 #define LC_SEGMENT_COMMAND LC_SEGMENT
63 typedef struct segment_command macho_segment_command
;
64 typedef struct mach_header macho_header
;
65 typedef struct nlist macho_nlist
;
68 #define DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE (32*1024)
69 #define DYLD_PROCESS_INFO_NOTIFY_LOAD_ID 0x1000
70 #define DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID 0x2000
71 #define DYLD_PROCESS_INFO_NOTIFY_MAIN_ID 0x3000
73 struct dyld_process_info_image_entry
{
76 uint32_t pathStringOffset
;
80 struct dyld_process_info_notify_header
{
81 mach_msg_header_t header
;
84 uint32_t imagesOffset
;
85 uint32_t stringsOffset
;
90 // from _simple.h in libc
91 typedef struct _SIMPLE
* _SIMPLE_STRING
;
92 extern void _simple_vdprintf(int __fd
, const char *__fmt
, va_list __ap
);
93 extern void _simple_dprintf(int __fd
, const char *__fmt
, ...);
94 extern _SIMPLE_STRING
_simple_salloc(void);
95 extern int _simple_vsprintf(_SIMPLE_STRING __b
, const char *__fmt
, va_list __ap
);
96 extern void _simple_sfree(_SIMPLE_STRING __b
);
97 extern char * _simple_string(_SIMPLE_STRING __b
);
99 // dyld::log(const char* format, ...)
100 extern void _ZN4dyld3logEPKcz(const char*, ...);
102 // dyld::halt(const char* msg);
103 extern void _ZN4dyld4haltEPKc(const char* msg
) __attribute__((noreturn
));
105 extern void dyld_fatal_error(const char* errString
) __attribute__((noreturn
));
108 // abort called by C++ unwinding code
111 _ZN4dyld4haltEPKc("dyld calling abort()\n");
114 // std::terminate called by C++ unwinding code
115 void _ZSt9terminatev()
117 _ZN4dyld4haltEPKc("dyld std::terminate()\n");
120 // std::unexpected called by C++ unwinding code
121 void _ZSt10unexpectedv()
123 _ZN4dyld4haltEPKc("dyld std::unexpected()\n");
126 // __cxxabiv1::__terminate(void (*)()) called to terminate process
127 void _ZN10__cxxabiv111__terminateEPFvvE()
129 _ZN4dyld4haltEPKc("dyld std::__terminate()\n");
132 // __cxxabiv1::__unexpected(void (*)()) called to terminate process
133 void _ZN10__cxxabiv112__unexpectedEPFvvE()
135 _ZN4dyld4haltEPKc("dyld std::__unexpected()\n");
138 // std::__terminate() called by C++ unwinding code
139 void _ZSt11__terminatePFvvE(void (*func
)(void))
141 _ZN4dyld4haltEPKc("dyld std::__terminate()\n");
144 // std::__unexpected() called by C++ unwinding code
145 void _ZSt12__unexpectedPFvvE(void (*func
)(void))
147 _ZN4dyld4haltEPKc("dyld std::__unexpected()\n");
150 // terminate_handler get_terminate()
151 void* _ZSt13get_terminatev()
156 // unexpected_handler get_unexpected()
157 void* _ZSt14get_unexpectedv()
162 // new_handler get_new_handler()
163 void* _ZSt15get_new_handlerv()
170 // __cxxabiv1::__terminate_handler
171 void* _ZN10__cxxabiv119__terminate_handlerE
= &_ZSt9terminatev
;
173 // __cxxabiv1::__unexpected_handler
174 void* _ZN10__cxxabiv120__unexpected_handlerE
= &_ZSt10unexpectedv
;
177 int myfprintf(FILE* file
, const char* format
, ...) __asm("_fprintf");
179 // called by libuwind code before aborting
180 size_t fwrite(const void* ptr
, size_t size
, size_t nitme
, FILE* stream
)
182 return myfprintf(stream
, "%s", (char*)ptr
);
185 // called by libuwind code before aborting
186 int fprintf(FILE* file
, const char* format
, ...)
189 va_start(list
, format
);
190 _simple_vdprintf(STDERR_FILENO
, format
, list
);
195 // called by LIBC_ABORT
196 void abort_report_np(const char* format
, ...)
200 _SIMPLE_STRING s
= _simple_salloc();
202 va_start(list
, format
);
203 _simple_vsprintf(s
, format
, list
);
205 str
= _simple_string(s
);
208 // _simple_salloc failed, but at least format may have useful info by itself
211 _ZN4dyld4haltEPKc(str
);
212 // _ZN4dyld4haltEPKc doesn't return, so we can't call _simple_sfree
215 // libc uses assert()
216 #pragma clang diagnostic push
217 #pragma clang diagnostic ignored "-Winvalid-noreturn"
218 void __assert_rtn(const char* func
, const char* file
, int line
, const char* failedexpr
)
221 _ZN4dyld3logEPKcz("Assertion failed: (%s), file %s, line %d.\n", failedexpr
, file
, line
);
222 abort_report_np("Assertion failed: (%s), file %s, line %d.\n", failedexpr
, file
, line
);
224 _ZN4dyld3logEPKcz("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr
, func
, file
, line
);
225 abort_report_np("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr
, func
, file
, line
);
228 #pragma clang diagnostic pop
230 int sprintf(char * restrict str
, const char * restrict format
, ...)
233 _SIMPLE_STRING s
= _simple_salloc();
234 va_start(list
, format
);
235 _simple_vsprintf(s
, format
, list
);
237 strcpy(str
, _simple_string(s
));
242 // real cthread_set_errno_self() has error handling that pulls in
243 // pthread_exit() which pulls in fprintf()
244 extern int* __error(void);
245 void cthread_set_errno_self(int err
)
252 * We have our own localtime() to avoid needing the notify API which is used
253 * by the code in libc.a for localtime() which is used by arc4random().
255 struct tm
* localtime(const time_t* t
)
257 return (struct tm
*)NULL
;
260 // malloc calls exit(-1) in case of errors...
263 _ZN4dyld4haltEPKc("exit()");
266 // static initializers make calls to __cxa_atexit
269 // do nothing, dyld never terminates
273 // The stack protector routines in lib.c bring in too much stuff, so
274 // make our own custom ones.
276 long __stack_chk_guard
= 0;
279 void __guard_setup(const char* apple
[])
281 for (const char** p
= apple
; *p
!= NULL
; ++p
) {
282 if ( strncmp(*p
, "stack_guard=", 12) == 0 ) {
283 // kernel has provide a random value for us
284 for (const char* s
= *p
+ 12; *s
!= '\0'; ++s
) {
287 if ( (c
>= 'a') && (c
<= 'f') )
288 value
= c
- 'a' + 10;
289 else if ( (c
>= 'A') && (c
<= 'F') )
290 value
= c
- 'A' + 10;
291 else if ( (c
>= '0') && (c
<= '9') )
293 __stack_chk_guard
<<= 4;
294 __stack_chk_guard
|= value
;
296 if ( __stack_chk_guard
!= 0 )
300 #if !TARGET_OS_SIMULATOR
302 __stack_chk_guard
= ((long)arc4random() << 32) | arc4random();
304 __stack_chk_guard
= arc4random();
309 extern void _ZN4dyld4haltEPKc(const char*);
310 void __stack_chk_fail()
312 _ZN4dyld4haltEPKc("stack buffer overrun");
316 // std::_throw_bad_alloc()
317 void _ZSt17__throw_bad_allocv()
319 _ZN4dyld4haltEPKc("__throw_bad_alloc()");
322 // std::_throw_length_error(const char* x)
323 void _ZSt20__throw_length_errorPKc()
325 _ZN4dyld4haltEPKc("_throw_length_error()");
328 // The aligned version of new isn't in libc++abi-static.a but might be called
329 // by __libcpp_allocate unless it is optimized perfectly
330 extern void* _Znwm(unsigned long size
);
331 void* _ZnwmSt11align_val_t(unsigned long size
, size_t align
) {
335 // The aligned version of new isn't in libc++abi-static.a but might be called
336 // by __libcpp_deallocate unless it is optimized perfectly
337 extern void _ZdlPv(void* ptr
);
338 void _ZdlPvSt11align_val_t(void* ptr
, size_t align
) {
342 // the libc.a version of this drags in ASL
345 _ZN4dyld4haltEPKc("__chk_fail()");
349 // referenced by libc.a(pthread.o) but unneeded in dyld
350 void set_malloc_singlethreaded() {}
351 int PR_5243343_flag
= 0;
354 // used by some pthread routines
355 char* mach_error_string(mach_error_t err
)
357 return (char *)"unknown error code";
359 char* mach_error_type(mach_error_t err
)
361 return (char *)"(unknown/unknown)";
364 // _pthread_reap_thread calls fprintf(stderr).
365 // We map fprint to _simple_vdprintf and ignore FILE* stream, so ok for it to be NULL
366 FILE* __stderrp
= NULL
;
367 FILE* __stdoutp
= NULL
;
369 // work with c++abi.a
370 void (*__cxa_terminate_handler
)(void) = _ZSt9terminatev
;
371 void (*__cxa_unexpected_handler
)(void) = _ZSt10unexpectedv
;
373 void abort_message(const char* format
, ...)
376 va_start(list
, format
);
377 _simple_vdprintf(STDERR_FILENO
, format
, list
);
381 void __cxa_bad_typeid()
383 _ZN4dyld4haltEPKc("__cxa_bad_typeid()");
386 // to work with libc++
387 void _ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv()
389 _ZN4dyld4haltEPKc("std::vector<>::_throw_length_error()");
392 // libc.a sometimes missing memset
394 void* memset(void* b
, int c
, size_t len
)
396 uint8_t* p
= (uint8_t*)b
;
397 for(size_t i
=len
; i
> 0; --i
)
403 // <rdar://problem/10111032> wrap calls to stat() with check for EAGAIN
404 int _ZN4dyld7my_statEPKcP4stat(const char* path
, struct stat
* buf
)
408 result
= stat(path
, buf
);
409 } while ((result
== -1) && ((errno
== EAGAIN
) || (errno
== EINTR
)));
414 // <rdar://problem/13805025> dyld should retry open() if it gets an EGAIN
415 int _ZN4dyld7my_openEPKcii(const char* path
, int flag
, int other
)
419 result
= open(path
, flag
, other
);
420 } while ((result
== -1) && ((errno
== EAGAIN
) || (errno
== EINTR
)));
427 // The dyld in the iOS simulator cannot do syscalls, so it calls back to
431 #if TARGET_OS_SIMULATOR
433 int myopen(const char* path
, int oflag
, int extra
) __asm("_open");
434 int myopen(const char* path
, int oflag
, int extra
) {
435 return gSyscallHelpers
->open(path
, oflag
, extra
);
439 return gSyscallHelpers
->close(fd
);
442 ssize_t
pread(int fd
, void* buf
, size_t nbytes
, off_t offset
) {
443 return gSyscallHelpers
->pread(fd
, buf
, nbytes
, offset
);
446 ssize_t
write(int fd
, const void *buf
, size_t nbytes
) {
447 return gSyscallHelpers
->write(fd
, buf
, nbytes
);
450 void* mmap(void* addr
, size_t len
, int prot
, int flags
, int fd
, off_t offset
) {
451 return gSyscallHelpers
->mmap(addr
, len
, prot
, flags
, fd
, offset
);
454 int munmap(void* addr
, size_t len
) {
455 return gSyscallHelpers
->munmap(addr
, len
);
458 int madvise(void* addr
, size_t len
, int advice
) {
459 return gSyscallHelpers
->madvise(addr
, len
, advice
);
462 int stat(const char* path
, struct stat
* buf
) {
463 return gSyscallHelpers
->stat(path
, buf
);
466 int myfcntl(int fd
, int cmd
, void* result
) __asm("_fcntl");
467 int myfcntl(int fd
, int cmd
, void* result
) {
468 return gSyscallHelpers
->fcntl(fd
, cmd
, result
);
471 int myioctl(int fd
, unsigned long request
, void* result
) __asm("_ioctl");
472 int myioctl(int fd
, unsigned long request
, void* result
) {
473 return gSyscallHelpers
->ioctl(fd
, request
, result
);
477 return gSyscallHelpers
->issetugid();
480 char* getcwd(char* buf
, size_t size
) {
481 return gSyscallHelpers
->getcwd(buf
, size
);
484 char* realpath(const char* file_name
, char* resolved_name
) {
485 return gSyscallHelpers
->realpath(file_name
, resolved_name
);
490 kern_return_t
vm_allocate(vm_map_t target_task
, vm_address_t
*address
,
491 vm_size_t size
, int flags
) {
492 return gSyscallHelpers
->vm_allocate(target_task
, address
, size
, flags
);
495 kern_return_t
vm_deallocate(vm_map_t target_task
, vm_address_t address
,
497 return gSyscallHelpers
->vm_deallocate(target_task
, address
, size
);
500 kern_return_t
vm_protect(vm_map_t target_task
, vm_address_t address
,
501 vm_size_t size
, boolean_t max
, vm_prot_t prot
) {
502 return gSyscallHelpers
->vm_protect(target_task
, address
, size
, max
, prot
);
506 void _ZN4dyld3logEPKcz(const char* format
, ...) {
508 va_start(list
, format
);
509 gSyscallHelpers
->vlog(format
, list
);
514 void _ZN4dyld4vlogEPKcPc(const char* format
, va_list list
) {
516 void _ZN4dyld4vlogEPKcP13__va_list_tag(const char* format
, va_list list
) {
518 gSyscallHelpers
->vlog(format
, list
);
523 void _ZN4dyld4warnEPKcz(const char* format
, ...) {
525 va_start(list
, format
);
526 gSyscallHelpers
->vwarn(format
, list
);
531 int pthread_mutex_lock(pthread_mutex_t
* m
) {
532 return gSyscallHelpers
->pthread_mutex_lock(m
);
535 int pthread_mutex_unlock(pthread_mutex_t
* m
) {
536 return gSyscallHelpers
->pthread_mutex_unlock(m
);
539 mach_port_t
mach_thread_self() {
540 return gSyscallHelpers
->mach_thread_self();
543 kern_return_t
mach_port_deallocate(ipc_space_t task
, mach_port_name_t name
) {
544 return gSyscallHelpers
->mach_port_deallocate(task
, name
);
547 mach_port_name_t
task_self_trap() {
548 return gSyscallHelpers
->task_self_trap();
551 kern_return_t
mach_timebase_info(mach_timebase_info_t info
) {
552 return gSyscallHelpers
->mach_timebase_info(info
);
555 bool OSAtomicCompareAndSwapPtrBarrier(void* old
, void* new, void * volatile *value
) {
556 return gSyscallHelpers
->OSAtomicCompareAndSwapPtrBarrier(old
, new, value
);
559 void OSMemoryBarrier() {
560 return gSyscallHelpers
->OSMemoryBarrier();
563 uint64_t mach_absolute_time(void) {
564 return gSyscallHelpers
->mach_absolute_time();
567 kern_return_t
thread_switch(mach_port_name_t thread_name
,
568 int option
, mach_msg_timeout_t option_time
) {
569 if ( gSyscallHelpers
->version
< 2 )
571 return gSyscallHelpers
->thread_switch(thread_name
, option
, option_time
);
574 DIR* opendir(const char* path
) {
575 if ( gSyscallHelpers
->version
< 3 )
577 return gSyscallHelpers
->opendir(path
);
580 int readdir_r(DIR* dirp
, struct dirent
* entry
, struct dirent
**result
) {
581 if ( gSyscallHelpers
->version
< 3 )
583 return gSyscallHelpers
->readdir_r(dirp
, entry
, result
);
586 // HACK: readdir() is not used in dyld_sim, but it is pulled in by libc.a, then dead stripped.
587 struct dirent
* readdir(DIR *dirp
) {
588 _ZN4dyld4haltEPKc("dyld_sim readdir() not supported\n");
591 int closedir(DIR* dirp
) {
592 if ( gSyscallHelpers
->version
< 3 )
594 return gSyscallHelpers
->closedir(dirp
);
597 void coresymbolication_load_notifier(void* connection
, uint64_t timestamp
, const char* path
, const struct mach_header
* mh
)
599 // if host dyld supports this notifier, call into host dyld
600 if ( gSyscallHelpers
->version
>= 4 )
601 return gSyscallHelpers
->coresymbolication_load_notifier(connection
, timestamp
, path
, mh
);
604 void coresymbolication_unload_notifier(void* connection
, uint64_t timestamp
, const char* path
, const struct mach_header
* mh
)
606 // if host dyld supports this notifier, call into host dyld
607 if ( gSyscallHelpers
->version
>= 4 )
608 return gSyscallHelpers
->coresymbolication_unload_notifier(connection
, timestamp
, path
, mh
);
611 int mprotect(void* addr
, size_t len
, int prot
)
613 return vm_protect(mach_task_self(), (vm_address_t
)addr
, len
, false, prot
);
617 #define SUPPORT_HOST_10_11 1
619 #if SUPPORT_HOST_10_11
620 typedef int (*FuncPtr_proc_regionfilename
)(int pid
, uint64_t address
, void* buffer
, uint32_t bufferSize
);
621 typedef pid_t (*FuncPtr_getpid
)(void);
622 typedef bool (*FuncPtr_mach_port_insert_right
)(ipc_space_t task
, mach_port_name_t name
, mach_port_t poly
, mach_msg_type_name_t polyPoly
);
623 typedef kern_return_t (*FuncPtr_mach_port_allocate
)(ipc_space_t
, mach_port_right_t
, mach_port_name_t
*);
624 typedef mach_msg_return_t (*FuncPtr_mach_msg
)(mach_msg_header_t
*, mach_msg_option_t
, mach_msg_size_t
, mach_msg_size_t
, mach_port_name_t
, mach_msg_timeout_t
, mach_port_name_t
);
625 typedef void (*FuncPtr_mach_msg_destroy
)(mach_msg_header_t
*);
626 typedef kern_return_t (*FuncPtr_mach_port_construct
)(ipc_space_t task
, mach_port_options_ptr_t options
, mach_port_context_t context
, mach_port_name_t
*name
);
627 typedef kern_return_t (*FuncPtr_mach_port_destruct
)(ipc_space_t task
, mach_port_name_t name
, mach_port_delta_t srdelta
, mach_port_context_t guard
);
629 static FuncPtr_proc_regionfilename proc_proc_regionfilename
= NULL
;
630 static FuncPtr_getpid proc_getpid
= NULL
;
631 static FuncPtr_mach_port_insert_right proc_mach_port_insert_right
= NULL
;
632 static FuncPtr_mach_port_allocate proc_mach_port_allocate
= NULL
;
633 static FuncPtr_mach_msg proc_mach_msg
= NULL
;
634 static FuncPtr_mach_msg_destroy proc_mach_msg_destroy
= NULL
;
635 static FuncPtr_mach_port_construct proc_mach_port_construct
= NULL
;
636 static FuncPtr_mach_port_destruct proc_mach_port_destruct
= NULL
;
638 static mach_port_t
* sNotifyReplyPorts
= NULL
;
639 static bool* sZombieNotifiers
= NULL
;
641 // Look up sycalls in host dyld needed by coresymbolication_ routines in dyld_sim
642 static void findHostFunctions() {
643 // Only look up symbols once
644 if ( proc_mach_msg
!= NULL
)
647 struct dyld_all_image_infos
* imageInfo
= (struct dyld_all_image_infos
*)(gSyscallHelpers
->getProcessInfo());
648 const struct mach_header
* hostDyldMH
= imageInfo
->dyldImageLoadAddress
;
650 // find symbol table and slide of host dyld
652 const macho_nlist
* symbolTable
= NULL
;
653 const char* symbolTableStrings
= NULL
;
654 const struct dysymtab_command
* dynSymbolTable
= NULL
;
655 const uint32_t cmd_count
= hostDyldMH
->ncmds
;
656 const struct load_command
* const cmds
= (struct load_command
*)(((char*)hostDyldMH
)+sizeof(macho_header
));
657 const struct load_command
* cmd
= cmds
;
658 const uint8_t* linkEditBase
= NULL
;
659 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
661 case LC_SEGMENT_COMMAND
:
663 const macho_segment_command
* seg
= (macho_segment_command
*)cmd
;
664 if ( (seg
->fileoff
== 0) && (seg
->filesize
!= 0) )
665 slide
= (uintptr_t)hostDyldMH
- seg
->vmaddr
;
666 if ( strcmp(seg
->segname
, "__LINKEDIT") == 0 )
667 linkEditBase
= (uint8_t*)(seg
->vmaddr
- seg
->fileoff
+ slide
);
672 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
673 if ( linkEditBase
== NULL
)
675 symbolTableStrings
= (const char*)&linkEditBase
[symtab
->stroff
];
676 symbolTable
= (macho_nlist
*)(&linkEditBase
[symtab
->symoff
]);
680 dynSymbolTable
= (struct dysymtab_command
*)cmd
;
683 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
685 if ( symbolTableStrings
== NULL
)
687 if ( dynSymbolTable
== NULL
)
690 // scan local symbols in host dyld looking for load/unload functions
691 const macho_nlist
* const localsStart
= &symbolTable
[dynSymbolTable
->ilocalsym
];
692 const macho_nlist
* const localsEnd
= &localsStart
[dynSymbolTable
->nlocalsym
];
693 for (const macho_nlist
* s
= localsStart
; s
< localsEnd
; ++s
) {
694 if ( ((s
->n_type
& N_TYPE
) == N_SECT
) && ((s
->n_type
& N_STAB
) == 0) ) {
695 const char* name
= &symbolTableStrings
[s
->n_un
.n_strx
];
696 if ( strcmp(name
, "_proc_regionfilename") == 0 )
697 proc_proc_regionfilename
= (FuncPtr_proc_regionfilename
)(s
->n_value
+ slide
);
698 else if ( strcmp(name
, "_getpid") == 0 )
699 proc_getpid
= (FuncPtr_getpid
)(s
->n_value
+ slide
);
700 else if ( strcmp(name
, "mach_port_insert_right") == 0 )
701 proc_mach_port_insert_right
= (FuncPtr_mach_port_insert_right
)(s
->n_value
+ slide
);
702 else if ( strcmp(name
, "_mach_port_allocate") == 0 )
703 proc_mach_port_allocate
= (FuncPtr_mach_port_allocate
)(s
->n_value
+ slide
);
704 else if ( strcmp(name
, "_mach_msg") == 0 )
705 proc_mach_msg
= (FuncPtr_mach_msg
)(s
->n_value
+ slide
);
706 else if (strcmp(name
, "__ZN4dyldL17sNotifyReplyPortsE"))
707 sNotifyReplyPorts
= (mach_port_t
*)(s
->n_value
+ slide
);
708 else if (strcmp(name
, "__ZN4dyldL16sZombieNotifiersE"))
709 sZombieNotifiers
= (bool *)(s
->n_value
+ slide
);
714 // Look up sycalls in host dyld needed by coresymbolication_ routines in dyld_sim
715 static bool findHostLibSystemFunctions() {
716 // Only look up symbols once
717 if (proc_mach_msg_destroy
!= NULL
&& proc_mach_port_construct
!= NULL
&& proc_mach_port_destruct
!= NULL
)
720 const struct mach_header
* hostLibSystemMH
= NULL
;
721 struct dyld_all_image_infos
* imageInfo
= (struct dyld_all_image_infos
*)(gSyscallHelpers
->getProcessInfo());
722 const struct dyld_image_info
* infoArray
= imageInfo
->infoArray
;
723 if (infoArray
== NULL
)
725 uint32_t imageCount
= imageInfo
->infoArrayCount
;
726 for (uint32_t i
= 0; i
<imageCount
; ++i
) {
727 if (strcmp("/usr/lib/system/libsystem_kernel.dylib", infoArray
[i
].imageFilePath
) == 0) {
728 //Found the kernel interface
729 hostLibSystemMH
= infoArray
[i
].imageLoadAddress
;
733 if (hostLibSystemMH
== NULL
)
736 // find symbol table and slide of host dyld
738 const macho_nlist
* symbolTable
= NULL
;
739 const char* symbolTableStrings
= NULL
;
740 const struct dysymtab_command
* dynSymbolTable
= NULL
;
741 const uint32_t cmd_count
= hostLibSystemMH
->ncmds
;
742 const struct load_command
* const cmds
= (struct load_command
*)(((char*)hostLibSystemMH
)+sizeof(macho_header
));
743 const struct load_command
* cmd
= cmds
;
744 const uint8_t* linkEditBase
= NULL
;
745 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
747 case LC_SEGMENT_COMMAND
:
749 const macho_segment_command
* seg
= (macho_segment_command
*)cmd
;
750 if ( (seg
->fileoff
== 0) && (seg
->filesize
!= 0) )
751 slide
= (uintptr_t)hostLibSystemMH
- seg
->vmaddr
;
752 if ( strcmp(seg
->segname
, "__LINKEDIT") == 0 )
753 linkEditBase
= (uint8_t*)(seg
->vmaddr
- seg
->fileoff
+ slide
);
758 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
759 if ( linkEditBase
== NULL
)
761 symbolTableStrings
= (const char*)&linkEditBase
[symtab
->stroff
];
762 symbolTable
= (macho_nlist
*)(&linkEditBase
[symtab
->symoff
]);
766 dynSymbolTable
= (struct dysymtab_command
*)cmd
;
769 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
771 if ( symbolTableStrings
== NULL
)
773 if ( dynSymbolTable
== NULL
)
776 // scan local symbols in host dyld looking for load/unload functions
777 const macho_nlist
* const localsStart
= &symbolTable
[dynSymbolTable
->iextdefsym
];
778 const macho_nlist
* const localsEnd
= &localsStart
[dynSymbolTable
->nextdefsym
];
779 for (const macho_nlist
* s
= localsStart
; s
< localsEnd
; ++s
) {
780 if ( ((s
->n_type
& N_TYPE
) == N_SECT
) && ((s
->n_type
& N_STAB
) == 0) ) {
781 const char* name
= &symbolTableStrings
[s
->n_un
.n_strx
];
782 if ( strcmp(name
, "_mach_msg_destroy") == 0 )
783 proc_mach_msg_destroy
= (FuncPtr_mach_msg_destroy
)(s
->n_value
+ slide
);
784 else if ( strcmp(name
, "_mach_port_construct") == 0 )
785 proc_mach_port_construct
= (FuncPtr_mach_port_construct
)(s
->n_value
+ slide
);
786 else if ( strcmp(name
, "_mach_port_destruct") == 0 )
787 proc_mach_port_destruct
= (FuncPtr_mach_port_destruct
)(s
->n_value
+ slide
);
790 return (proc_mach_msg_destroy
!= NULL
&& proc_mach_port_construct
!= NULL
&& proc_mach_port_destruct
!= NULL
);
795 int proc_regionfilename(int pid
, uint64_t address
, void* buffer
, uint32_t bufferSize
)
797 if ( gSyscallHelpers
->version
>= 5 )
798 return gSyscallHelpers
->proc_regionfilename(pid
, address
, buffer
, bufferSize
);
799 #if SUPPORT_HOST_10_11
801 if ( proc_proc_regionfilename
)
802 return (*proc_proc_regionfilename
)(pid
, address
, buffer
, bufferSize
);
812 if ( gSyscallHelpers
->version
>= 5 )
813 return gSyscallHelpers
->getpid();
814 #if SUPPORT_HOST_10_11
816 return (*proc_getpid
)();
822 kern_return_t
mach_port_insert_right(ipc_space_t task
, mach_port_name_t name
, mach_port_t poly
, mach_msg_type_name_t polyPoly
)
824 if ( gSyscallHelpers
->version
>= 5 )
825 return gSyscallHelpers
->mach_port_insert_right(task
, name
, poly
, polyPoly
);
826 #if SUPPORT_HOST_10_11
828 if ( proc_mach_port_insert_right
)
829 return (*proc_mach_port_insert_right
)(task
, name
, poly
, polyPoly
);
831 return KERN_NOT_SUPPORTED
;
833 return KERN_NOT_SUPPORTED
;
837 kern_return_t
mach_port_allocate(ipc_space_t task
, mach_port_right_t right
, mach_port_name_t
* name
)
839 if ( gSyscallHelpers
->version
>= 5 )
840 return gSyscallHelpers
->mach_port_allocate(task
, right
, name
);
841 #if SUPPORT_HOST_10_11
843 return (*proc_mach_port_allocate
)(task
, right
, name
);
845 return KERN_NOT_SUPPORTED
;
849 kern_return_t
mach_msg(mach_msg_header_t
* msg
, mach_msg_option_t option
, mach_msg_size_t send_size
, mach_msg_size_t rcv_size
, mach_port_name_t rcv_name
, mach_msg_timeout_t timeout
, mach_port_name_t notify
)
851 if ( gSyscallHelpers
->version
>= 5 )
852 return gSyscallHelpers
->mach_msg(msg
, option
, send_size
, rcv_size
, rcv_name
, timeout
, notify
);
853 #if SUPPORT_HOST_10_11
855 return (*proc_mach_msg
)(msg
, option
, send_size
, rcv_size
, rcv_name
, timeout
, notify
);
857 return KERN_NOT_SUPPORTED
;
861 void mach_msg_destroy(mach_msg_header_t
*msg
) {
862 if ( gSyscallHelpers
->version
>= 12 ) {
863 gSyscallHelpers
->mach_msg_destroy(msg
);
866 #if SUPPORT_HOST_10_11
867 if (findHostLibSystemFunctions()) {
868 (*proc_mach_msg_destroy
)(msg
);
873 kern_return_t
mach_port_construct(ipc_space_t task
, mach_port_options_ptr_t options
, mach_port_context_t context
, mach_port_name_t
*name
) {
874 if ( gSyscallHelpers
->version
>= 12 ) {
875 return gSyscallHelpers
->mach_port_construct(task
, options
, context
, name
);
877 #if SUPPORT_HOST_10_11
878 if (findHostLibSystemFunctions()) {
879 return (*proc_mach_port_construct
)(task
, options
, context
, name
);
882 return KERN_NOT_SUPPORTED
;
885 kern_return_t
mach_port_destruct(ipc_space_t task
, mach_port_name_t name
, mach_port_delta_t srdelta
, mach_port_context_t guard
) {
886 if ( gSyscallHelpers
->version
>= 12 ) {
887 return gSyscallHelpers
->mach_port_destruct(task
, name
, srdelta
, guard
);
889 #if SUPPORT_HOST_10_11
890 if (findHostLibSystemFunctions()) {
891 return (*proc_mach_port_destruct
)(task
, name
, srdelta
, guard
);
894 return KERN_NOT_SUPPORTED
;
897 void abort_with_payload(uint32_t reason_namespace
, uint64_t reason_code
, void* payload
, uint32_t payload_size
, const char* reason_string
, uint64_t reason_flags
)
899 if ( gSyscallHelpers
->version
>= 6 )
900 gSyscallHelpers
->abort_with_payload(reason_namespace
, reason_code
, payload
, payload_size
, reason_string
, reason_flags
);
901 dyld_fatal_error(reason_string
);
904 kern_return_t
task_info(task_name_t target_task
, task_flavor_t flavor
, task_info_t task_info_out
, mach_msg_type_number_t
*task_info_outCnt
) {
905 if ( gSyscallHelpers
->version
>= 8 )
906 return gSyscallHelpers
->task_info(target_task
, flavor
, task_info_out
, task_info_outCnt
);
907 return KERN_NOT_SUPPORTED
;
910 kern_return_t
thread_info(thread_inspect_t target_act
, thread_flavor_t flavor
, thread_info_t thread_info_out
, mach_msg_type_number_t
*thread_info_outCnt
) {
911 if ( gSyscallHelpers
->version
>= 8 )
912 return gSyscallHelpers
->task_info(target_act
, flavor
, thread_info_out
, thread_info_outCnt
);
913 return KERN_NOT_SUPPORTED
;
916 bool kdebug_is_enabled(uint32_t code
) {
917 if ( gSyscallHelpers
->version
>= 8 )
918 return gSyscallHelpers
->kdebug_is_enabled(code
);
922 int kdebug_trace(uint32_t code
, uint64_t arg1
, uint64_t arg2
, uint64_t arg3
, uint64_t arg4
) {
923 if ( gSyscallHelpers
->version
>= 8 )
924 return gSyscallHelpers
->kdebug_trace(code
, arg1
, arg2
, arg3
, arg4
);
928 uint64_t kdebug_trace_string(uint32_t debugid
, uint64_t str_id
, const char *str
) {
929 if ( gSyscallHelpers
->version
>= 9 )
930 return gSyscallHelpers
->kdebug_trace_string(debugid
, str_id
, str
);
934 uint64_t amfi_check_dyld_policy_self(uint64_t inFlags
, uint64_t* outFlags
)
936 if ( gSyscallHelpers
->version
>= 10 )
937 return gSyscallHelpers
->amfi_check_dyld_policy_self(inFlags
, outFlags
);
938 *outFlags
= 0x3F; // on old kernel, simulator process get all flags
942 void _ZN4dyld24notifyMonitoringDyldMainEv() {
943 if ( gSyscallHelpers
->version
>= 11 ) {
944 gSyscallHelpers
->notifyMonitoringDyldMain();
947 #if SUPPORT_HOST_10_11
949 struct dyld_all_image_infos
* imageInfo
= (struct dyld_all_image_infos
*)(gSyscallHelpers
->getProcessInfo());
950 for (int slot
=0; slot
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) {
951 if ( (imageInfo
->notifyPorts
[slot
] != 0 ) && !sZombieNotifiers
[slot
] ) {
952 if ( sNotifyReplyPorts
[slot
] == 0 ) {
953 if ( !mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &sNotifyReplyPorts
[slot
]) )
954 mach_port_insert_right(mach_task_self(), sNotifyReplyPorts
[slot
], sNotifyReplyPorts
[slot
], MACH_MSG_TYPE_MAKE_SEND
);
955 //dyld::log("allocated reply port %d\n", sNotifyReplyPorts[slot]);
957 //dyld::log("found port to send to\n");
958 uint8_t messageBuffer
[sizeof(mach_msg_header_t
) + MAX_TRAILER_SIZE
];
959 mach_msg_header_t
* h
= (mach_msg_header_t
*)messageBuffer
;
960 h
->msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,MACH_MSG_TYPE_MAKE_SEND
); // MACH_MSG_TYPE_MAKE_SEND_ONCE
961 h
->msgh_id
= DYLD_PROCESS_INFO_NOTIFY_MAIN_ID
;
962 h
->msgh_local_port
= sNotifyReplyPorts
[slot
];
963 h
->msgh_remote_port
= imageInfo
->notifyPorts
[slot
];
964 h
->msgh_reserved
= 0;
965 h
->msgh_size
= (mach_msg_size_t
)sizeof(messageBuffer
);
966 //dyld::log("sending to port[%d]=%d, size=%d, reply port=%d, id=0x%X\n", slot, dyld::gProcessInfo->notifyPorts[slot], h->msgh_size, sNotifyReplyPorts[slot], h->msgh_id);
967 kern_return_t sendResult
= mach_msg(h
, MACH_SEND_MSG
| MACH_RCV_MSG
| MACH_RCV_TIMEOUT
, h
->msgh_size
, h
->msgh_size
, sNotifyReplyPorts
[slot
], 5000, MACH_PORT_NULL
);
968 //dyld::log("send result = 0x%X, msg_id=%d, msg_size=%d\n", sendResult, h->msgh_id, h->msgh_size);
969 if ( sendResult
== MACH_SEND_INVALID_DEST
) {
970 // sender is not responding, detatch
971 //dyld::log("process requesting notification gone. deallocation send port %d and receive port %d\n", dyld::gProcessInfo->notifyPorts[slot], sNotifyReplyPorts[slot]);
972 mach_port_deallocate(mach_task_self(), imageInfo
->notifyPorts
[slot
]);
973 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]);
974 imageInfo
->notifyPorts
[slot
] = 0;
975 sNotifyReplyPorts
[slot
] = 0;
977 else if ( sendResult
== MACH_RCV_TIMED_OUT
) {
978 // client took too long, ignore him from now on
979 sZombieNotifiers
[slot
] = true;
980 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]);
981 sNotifyReplyPorts
[slot
] = 0;
988 #if SUPPORT_HOST_10_11
989 static void notifyMonitoringDyld(bool unloading
, unsigned portSlot
, unsigned imageCount
, const struct mach_header
* loadAddresses
[], const char* imagePaths
[])
991 if ( sZombieNotifiers
[portSlot
] )
993 struct dyld_all_image_infos
* imageInfo
= (struct dyld_all_image_infos
*)(gSyscallHelpers
->getProcessInfo());
994 unsigned entriesSize
= imageCount
*sizeof(struct dyld_process_info_image_entry
);
995 unsigned pathsSize
= 0;
996 for (unsigned j
=0; j
< imageCount
; ++j
) {
997 pathsSize
+= (strlen(imagePaths
[j
]) + 1);
999 unsigned totalSize
= (sizeof(struct dyld_process_info_notify_header
) + MAX_TRAILER_SIZE
+ entriesSize
+ pathsSize
+ 127) & -128; // align
1000 if ( totalSize
> DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE
) {
1001 // Putting all image paths into one message would make buffer too big.
1002 // Instead split into two messages. Recurse as needed until paths fit in buffer.
1003 unsigned imageHalfCount
= imageCount
/2;
1004 notifyMonitoringDyld(unloading
, portSlot
, imageHalfCount
, loadAddresses
, imagePaths
);
1005 notifyMonitoringDyld(unloading
, portSlot
, imageCount
- imageHalfCount
, &loadAddresses
[imageHalfCount
], &imagePaths
[imageHalfCount
]);
1008 uint8_t buffer
[totalSize
];
1009 struct dyld_process_info_notify_header
* header
= (struct dyld_process_info_notify_header
*)buffer
;
1010 header
->version
= 1;
1011 header
->imageCount
= imageCount
;
1012 header
->imagesOffset
= sizeof(struct dyld_process_info_notify_header
);
1013 header
->stringsOffset
= sizeof(struct dyld_process_info_notify_header
) + entriesSize
;
1014 header
->timestamp
= imageInfo
->infoArrayChangeTimestamp
;
1015 struct dyld_process_info_image_entry
* entries
= (struct dyld_process_info_image_entry
*)&buffer
[header
->imagesOffset
];
1016 char* const pathPoolStart
= (char*)&buffer
[header
->stringsOffset
];
1017 char* pathPool
= pathPoolStart
;
1018 for (unsigned j
=0; j
< imageCount
; ++j
) {
1019 strcpy(pathPool
, imagePaths
[j
]);
1020 uint32_t len
= (uint32_t)strlen(pathPool
);
1021 bzero(entries
->uuid
, 16);
1022 const macho_header
* mh
= (const macho_header
*)loadAddresses
[j
];
1023 const uint32_t cmd_count
= mh
->ncmds
;
1024 const struct load_command
* const cmds
= (struct load_command
*)((char*)mh
+ sizeof(macho_header
));
1025 const struct load_command
* cmd
= cmds
;
1026 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1027 if (cmd
->cmd
== LC_UUID
) {
1028 struct uuid_command
* uc
= (struct uuid_command
*)cmd
;
1029 memcpy(&entries
->uuid
[0], uc
->uuid
, 16);
1032 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1034 entries
->loadAddress
= (uint64_t)loadAddresses
[j
];
1035 entries
->pathStringOffset
= (uint32_t)(pathPool
- pathPoolStart
);
1036 entries
->pathLength
= len
;
1037 pathPool
+= (len
+1);
1041 if ( sNotifyReplyPorts
[portSlot
] == 0 ) {
1042 if ( !mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &sNotifyReplyPorts
[portSlot
]) )
1043 mach_port_insert_right(mach_task_self(), sNotifyReplyPorts
[portSlot
], sNotifyReplyPorts
[portSlot
], MACH_MSG_TYPE_MAKE_SEND
);
1044 //dyld::log("allocated reply port %d\n", sNotifyReplyPorts[portSlot]);
1046 //dyld::log("found port to send to\n");
1047 mach_msg_header_t
* h
= (mach_msg_header_t
*)buffer
;
1048 h
->msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,MACH_MSG_TYPE_MAKE_SEND
); // MACH_MSG_TYPE_MAKE_SEND_ONCE
1049 h
->msgh_id
= unloading
? DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID
: DYLD_PROCESS_INFO_NOTIFY_LOAD_ID
;
1050 h
->msgh_local_port
= sNotifyReplyPorts
[portSlot
];
1051 h
->msgh_remote_port
= imageInfo
->notifyPorts
[portSlot
];
1052 h
->msgh_reserved
= 0;
1053 h
->msgh_size
= (mach_msg_size_t
)sizeof(buffer
);
1054 //dyld::log("sending to port[%d]=%d, size=%d, reply port=%d, id=0x%X\n", portSlot, dyld::gProcessInfo->notifyPorts[portSlot], h->msgh_size, sNotifyReplyPorts[portSlot], h->msgh_id);
1055 kern_return_t sendResult
= mach_msg(h
, MACH_SEND_MSG
| MACH_RCV_MSG
| MACH_RCV_TIMEOUT
, h
->msgh_size
, h
->msgh_size
, sNotifyReplyPorts
[portSlot
], 5000, MACH_PORT_NULL
);
1056 //dyld::log("send result = 0x%X, msg_id=%d, msg_size=%d\n", sendResult, h->msgh_id, h->msgh_size);
1057 if ( sendResult
== MACH_SEND_INVALID_DEST
) {
1058 // sender is not responding, detatch
1059 //dyld::log("process requesting notification gone. deallocation send port %d and receive port %d\n", dyld::gProcessInfo->notifyPorts[portSlot], sNotifyReplyPorts[portSlot]);
1060 mach_port_deallocate(mach_task_self(), imageInfo
->notifyPorts
[portSlot
]);
1061 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[portSlot
]);
1062 imageInfo
->notifyPorts
[portSlot
] = 0;
1063 sNotifyReplyPorts
[portSlot
] = 0;
1065 else if ( sendResult
== MACH_RCV_TIMED_OUT
) {
1066 // client took too long, ignore him from now on
1067 sZombieNotifiers
[portSlot
] = true;
1068 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[portSlot
]);
1069 sNotifyReplyPorts
[portSlot
] = 0;
1074 void _ZN4dyld20notifyMonitoringDyldEbjPPK11mach_headerPPKc(bool unloading
, unsigned imageCount
, const struct mach_header
* loadAddresses
[], const char* imagePaths
[]) {
1075 if ( gSyscallHelpers
->version
>= 11 ) {
1076 gSyscallHelpers
->notifyMonitoringDyld(unloading
, imageCount
, loadAddresses
, imagePaths
);
1079 #if SUPPORT_HOST_10_11
1080 findHostFunctions();
1081 for (int slot
=0; slot
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) {
1082 notifyMonitoringDyld(unloading
, slot
, imageCount
, loadAddresses
, imagePaths
);
1087 int* __error(void) {
1088 return gSyscallHelpers
->errnoAddress();
1092 mach_task_self_
= task_self_trap();
1093 //_task_reply_port = _mach_reply_port();
1096 mach_port_t mach_task_self_
= MACH_PORT_NULL
;
1098 extern int myerrno_fallback
__asm("_errno");
1099 int myerrno_fallback
= 0;
1102 vm_size_t vm_kernel_page_mask
= 0xFFF;
1103 vm_size_t vm_page_size
= 0x1000;
1105 #endif // TARGET_OS_SIMULATOR
1108 #if ! TARGET_OS_SIMULATOR
1109 #include <mach-o/dyld_process_info.h>
1111 void _dyld_debugger_notification(enum dyld_notify_mode mode
, unsigned long count
, uint64_t machHeaders
[])
1113 // Do nothing. This exists for the debugger to set a break point on to see what images have been loaded or unloaded.
1118 void* _NSConcreteStackBlock
[32];
1119 void* _NSConcreteGlobalBlock
[32];
1121 void _Block_object_assign()
1123 _ZN4dyld4haltEPKc("_Block_object_assign()");
1126 void _Block_object_dispose(const void* object
, int flags
)
1128 // only support stack blocks in dyld: BLOCK_FIELD_IS_BYREF=8
1130 _ZN4dyld4haltEPKc("_Block_object_dispose()");
1135 #if !TARGET_OS_SIMULATOR
1136 errno_t
memset_s(void* s
, rsize_t smax
, int c
, rsize_t n
)
1150 void uuid_unparse_upper(const uuid_t uu
, uuid_string_t out
)
1157 "%02X%02X%02X%02X%02X%02X",
1158 uu
[0], uu
[1], uu
[2], uu
[3],
1162 uu
[10], uu
[11], uu
[12], uu
[13], uu
[14], uu
[15]);