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>
38 #include <mach/mach_traps.h>
42 #include <sys/ioctl.h>
43 #include <TargetConditionals.h>
44 #include <libkern/OSAtomic.h>
47 #include <corecrypto/ccdigest.h>
48 #include <corecrypto/ccsha1.h>
49 #include <corecrypto/ccsha2.h>
51 #if TARGET_OS_SIMULATOR
52 #include "dyldSyscallInterface.h"
53 #include <mach-o/dyld_images.h>
54 #include <mach-o/loader.h>
55 #include <mach-o/nlist.h>
56 #include <mach/kern_return.h>
58 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
59 typedef struct segment_command_64 macho_segment_command
;
60 typedef struct mach_header_64 macho_header
;
61 typedef struct nlist_64 macho_nlist
;
63 #define LC_SEGMENT_COMMAND LC_SEGMENT
64 typedef struct segment_command macho_segment_command
;
65 typedef struct mach_header macho_header
;
66 typedef struct nlist macho_nlist
;
69 #define DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE (32*1024)
70 #define DYLD_PROCESS_INFO_NOTIFY_LOAD_ID 0x1000
71 #define DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID 0x2000
72 #define DYLD_PROCESS_INFO_NOTIFY_MAIN_ID 0x3000
74 struct dyld_process_info_image_entry
{
77 uint32_t pathStringOffset
;
81 struct dyld_process_info_notify_header
{
82 mach_msg_header_t header
;
85 uint32_t imagesOffset
;
86 uint32_t stringsOffset
;
91 // from _simple.h in libc
92 typedef struct _SIMPLE
* _SIMPLE_STRING
;
93 extern void _simple_vdprintf(int __fd
, const char *__fmt
, va_list __ap
);
94 extern void _simple_dprintf(int __fd
, const char *__fmt
, ...);
95 extern _SIMPLE_STRING
_simple_salloc(void);
96 extern int _simple_vsprintf(_SIMPLE_STRING __b
, const char *__fmt
, va_list __ap
);
97 extern void _simple_sfree(_SIMPLE_STRING __b
);
98 extern char * _simple_string(_SIMPLE_STRING __b
);
100 // dyld::log(const char* format, ...)
101 extern void _ZN4dyld3logEPKcz(const char*, ...);
103 // dyld::halt(const char* msg);
104 extern void _ZN4dyld4haltEPKc(const char* msg
) __attribute__((noreturn
));
106 extern void dyld_fatal_error(const char* errString
) __attribute__((noreturn
));
109 // abort called by C++ unwinding code
112 _ZN4dyld4haltEPKc("dyld calling abort()\n");
115 // std::terminate called by C++ unwinding code
116 void _ZSt9terminatev()
118 _ZN4dyld4haltEPKc("dyld std::terminate()\n");
121 // std::unexpected called by C++ unwinding code
122 void _ZSt10unexpectedv()
124 _ZN4dyld4haltEPKc("dyld std::unexpected()\n");
127 // __cxxabiv1::__terminate(void (*)()) called to terminate process
128 void _ZN10__cxxabiv111__terminateEPFvvE()
130 _ZN4dyld4haltEPKc("dyld std::__terminate()\n");
133 // __cxxabiv1::__unexpected(void (*)()) called to terminate process
134 void _ZN10__cxxabiv112__unexpectedEPFvvE()
136 _ZN4dyld4haltEPKc("dyld std::__unexpected()\n");
139 // std::__terminate() called by C++ unwinding code
140 void _ZSt11__terminatePFvvE(void (*func
)(void))
142 _ZN4dyld4haltEPKc("dyld std::__terminate()\n");
145 // std::__unexpected() called by C++ unwinding code
146 void _ZSt12__unexpectedPFvvE(void (*func
)(void))
148 _ZN4dyld4haltEPKc("dyld std::__unexpected()\n");
151 // terminate_handler get_terminate()
152 void* _ZSt13get_terminatev()
157 // unexpected_handler get_unexpected()
158 void* _ZSt14get_unexpectedv()
163 // new_handler get_new_handler()
164 void* _ZSt15get_new_handlerv()
171 // __cxxabiv1::__terminate_handler
172 void* _ZN10__cxxabiv119__terminate_handlerE
= &_ZSt9terminatev
;
174 // __cxxabiv1::__unexpected_handler
175 void* _ZN10__cxxabiv120__unexpected_handlerE
= &_ZSt10unexpectedv
;
178 int myfprintf(FILE* file
, const char* format
, ...) __asm("_fprintf");
180 // called by libuwind code before aborting
181 size_t fwrite(const void* ptr
, size_t size
, size_t nitme
, FILE* stream
)
183 return myfprintf(stream
, "%s", (char*)ptr
);
186 // called by libuwind code before aborting
187 int fprintf(FILE* file
, const char* format
, ...)
190 va_start(list
, format
);
191 _simple_vdprintf(STDERR_FILENO
, format
, list
);
196 // called by LIBC_ABORT
197 void abort_report_np(const char* format
, ...)
201 _SIMPLE_STRING s
= _simple_salloc();
203 va_start(list
, format
);
204 _simple_vsprintf(s
, format
, list
);
206 str
= _simple_string(s
);
209 // _simple_salloc failed, but at least format may have useful info by itself
212 _ZN4dyld4haltEPKc(str
);
213 // _ZN4dyld4haltEPKc doesn't return, so we can't call _simple_sfree
216 // libc uses assert()
217 #pragma clang diagnostic push
218 #pragma clang diagnostic ignored "-Winvalid-noreturn"
219 void __assert_rtn(const char* func
, const char* file
, int line
, const char* failedexpr
)
222 _ZN4dyld3logEPKcz("Assertion failed: (%s), file %s, line %d.\n", failedexpr
, file
, line
);
223 abort_report_np("Assertion failed: (%s), file %s, line %d.\n", failedexpr
, file
, line
);
225 _ZN4dyld3logEPKcz("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr
, func
, file
, line
);
226 abort_report_np("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr
, func
, file
, line
);
229 #pragma clang diagnostic pop
231 int sprintf(char * restrict str
, const char * restrict format
, ...)
234 _SIMPLE_STRING s
= _simple_salloc();
235 va_start(list
, format
);
236 _simple_vsprintf(s
, format
, list
);
238 strcpy(str
, _simple_string(s
));
243 // real cthread_set_errno_self() has error handling that pulls in
244 // pthread_exit() which pulls in fprintf()
245 extern int* __error(void);
246 void cthread_set_errno_self(int err
)
253 * We have our own localtime() to avoid needing the notify API which is used
254 * by the code in libc.a for localtime() which is used by arc4random().
256 struct tm
* localtime(const time_t* t
)
258 return (struct tm
*)NULL
;
261 // malloc calls exit(-1) in case of errors...
264 _ZN4dyld4haltEPKc("exit()");
267 // static initializers make calls to __cxa_atexit
270 // do nothing, dyld never terminates
274 // The stack protector routines in lib.c bring in too much stuff, so
275 // make our own custom ones.
277 long __stack_chk_guard
= 0;
280 void __guard_setup(const char* apple
[])
282 for (const char** p
= apple
; *p
!= NULL
; ++p
) {
283 if ( strncmp(*p
, "stack_guard=", 12) == 0 ) {
284 // kernel has provide a random value for us
285 for (const char* s
= *p
+ 12; *s
!= '\0'; ++s
) {
288 if ( (c
>= 'a') && (c
<= 'f') )
289 value
= c
- 'a' + 10;
290 else if ( (c
>= 'A') && (c
<= 'F') )
291 value
= c
- 'A' + 10;
292 else if ( (c
>= '0') && (c
<= '9') )
294 __stack_chk_guard
<<= 4;
295 __stack_chk_guard
|= value
;
297 if ( __stack_chk_guard
!= 0 )
301 #if !TARGET_OS_SIMULATOR
303 __stack_chk_guard
= ((long)arc4random() << 32) | arc4random();
305 __stack_chk_guard
= arc4random();
310 extern void _ZN4dyld4haltEPKc(const char*);
311 void __stack_chk_fail()
313 _ZN4dyld4haltEPKc("stack buffer overrun");
317 // std::_throw_bad_alloc()
318 void _ZSt17__throw_bad_allocv()
320 _ZN4dyld4haltEPKc("__throw_bad_alloc()");
323 // std::_throw_length_error(const char* x)
324 void _ZSt20__throw_length_errorPKc()
326 _ZN4dyld4haltEPKc("_throw_length_error()");
329 // The aligned version of new isn't in libc++abi-static.a but might be called
330 // by __libcpp_allocate unless it is optimized perfectly
331 extern void* _Znwm(unsigned long size
);
332 void* _ZnwmSt11align_val_t(unsigned long size
, size_t align
) {
336 // The aligned version of new isn't in libc++abi-static.a but might be called
337 // by __libcpp_deallocate unless it is optimized perfectly
338 extern void _ZdlPv(void* ptr
);
339 void _ZdlPvSt11align_val_t(void* ptr
, size_t align
) {
343 // the libc.a version of this drags in ASL
346 _ZN4dyld4haltEPKc("__chk_fail()");
350 // referenced by libc.a(pthread.o) but unneeded in dyld
351 void set_malloc_singlethreaded() {}
352 int PR_5243343_flag
= 0;
355 // used by some pthread routines
356 char* mach_error_string(mach_error_t err
)
358 return (char *)"unknown error code";
360 char* mach_error_type(mach_error_t err
)
362 return (char *)"(unknown/unknown)";
365 // _pthread_reap_thread calls fprintf(stderr).
366 // We map fprint to _simple_vdprintf and ignore FILE* stream, so ok for it to be NULL
367 FILE* __stderrp
= NULL
;
368 FILE* __stdoutp
= NULL
;
370 // work with c++abi.a
371 void (*__cxa_terminate_handler
)(void) = _ZSt9terminatev
;
372 void (*__cxa_unexpected_handler
)(void) = _ZSt10unexpectedv
;
374 void abort_message(const char* format
, ...)
377 va_start(list
, format
);
378 _simple_vdprintf(STDERR_FILENO
, format
, list
);
382 void __cxa_bad_typeid()
384 _ZN4dyld4haltEPKc("__cxa_bad_typeid()");
387 // to work with libc++
388 void _ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv()
390 _ZN4dyld4haltEPKc("std::vector<>::_throw_length_error()");
393 // libc.a sometimes missing memset
395 void* memset(void* b
, int c
, size_t len
)
397 uint8_t* p
= (uint8_t*)b
;
398 for(size_t i
=len
; i
> 0; --i
)
405 // The dyld in the iOS simulator cannot do syscalls, so it calls back to
409 #if TARGET_OS_SIMULATOR
411 int open(const char* path
, int oflag
, ...) {
415 va_start(args
, oflag
);
416 retval
= gSyscallHelpers
->open(path
, oflag
, va_arg(args
, int));
423 return gSyscallHelpers
->close(fd
);
426 ssize_t
pread(int fd
, void* buf
, size_t nbytes
, off_t offset
) {
427 return gSyscallHelpers
->pread(fd
, buf
, nbytes
, offset
);
430 ssize_t
write(int fd
, const void *buf
, size_t nbytes
) {
431 return gSyscallHelpers
->write(fd
, buf
, nbytes
);
434 void* mmap(void* addr
, size_t len
, int prot
, int flags
, int fd
, off_t offset
) {
435 return gSyscallHelpers
->mmap(addr
, len
, prot
, flags
, fd
, offset
);
438 int munmap(void* addr
, size_t len
) {
439 return gSyscallHelpers
->munmap(addr
, len
);
442 int madvise(void* addr
, size_t len
, int advice
) {
443 return gSyscallHelpers
->madvise(addr
, len
, advice
);
446 int stat(const char* path
, struct stat
* buf
) {
447 return gSyscallHelpers
->stat(path
, buf
);
450 int fcntl(int fd
, int cmd
, ...) {
455 retval
= gSyscallHelpers
->fcntl(fd
, cmd
, va_arg(args
, void *));
461 int ioctl(int fd
, unsigned long request
, ...) {
465 va_start(args
, request
);
466 retval
= gSyscallHelpers
->ioctl(fd
, request
, va_arg(args
, void *));
473 return gSyscallHelpers
->issetugid();
476 char* getcwd(char* buf
, size_t size
) {
477 return gSyscallHelpers
->getcwd(buf
, size
);
480 char* realpath(const char* file_name
, char* resolved_name
) {
481 return gSyscallHelpers
->realpath(file_name
, resolved_name
);
486 kern_return_t
vm_allocate(vm_map_t target_task
, vm_address_t
*address
,
487 vm_size_t size
, int flags
) {
488 return gSyscallHelpers
->vm_allocate(target_task
, address
, size
, flags
);
491 kern_return_t
vm_deallocate(vm_map_t target_task
, vm_address_t address
,
493 return gSyscallHelpers
->vm_deallocate(target_task
, address
, size
);
496 kern_return_t
vm_protect(vm_map_t target_task
, vm_address_t address
,
497 vm_size_t size
, boolean_t max
, vm_prot_t prot
) {
498 return gSyscallHelpers
->vm_protect(target_task
, address
, size
, max
, prot
);
502 void _ZN4dyld3logEPKcz(const char* format
, ...) {
504 va_start(list
, format
);
505 gSyscallHelpers
->vlog(format
, list
);
510 void _ZN4dyld4vlogEPKcPc(const char* format
, va_list list
) {
512 void _ZN4dyld4vlogEPKcP13__va_list_tag(const char* format
, va_list list
) {
514 gSyscallHelpers
->vlog(format
, list
);
519 void _ZN4dyld4warnEPKcz(const char* format
, ...) {
521 va_start(list
, format
);
522 gSyscallHelpers
->vwarn(format
, list
);
527 int pthread_mutex_lock(pthread_mutex_t
* m
) {
528 return gSyscallHelpers
->pthread_mutex_lock(m
);
531 int pthread_mutex_unlock(pthread_mutex_t
* m
) {
532 return gSyscallHelpers
->pthread_mutex_unlock(m
);
535 mach_port_t
mach_thread_self() {
536 return gSyscallHelpers
->mach_thread_self();
539 kern_return_t
mach_port_deallocate(ipc_space_t task
, mach_port_name_t name
) {
540 return gSyscallHelpers
->mach_port_deallocate(task
, name
);
543 mach_port_name_t
task_self_trap() {
544 return gSyscallHelpers
->task_self_trap();
547 kern_return_t
mach_timebase_info(mach_timebase_info_t info
) {
548 return gSyscallHelpers
->mach_timebase_info(info
);
551 bool myOSAtomicCompareAndSwapPtrBarrier(void* old
, void* new, void * volatile *value
) __asm("_OSAtomicCompareAndSwapPtrBarrier");
552 bool myOSAtomicCompareAndSwapPtrBarrier(void* old
, void* new, void * volatile *value
) {
553 return gSyscallHelpers
->OSAtomicCompareAndSwapPtrBarrier(old
, new, value
);
556 void myOSMemoryBarrier(void) __asm("_OSMemoryBarrier");
557 void myOSMemoryBarrier() {
558 return gSyscallHelpers
->OSMemoryBarrier();
561 uint64_t mach_absolute_time(void) {
562 return gSyscallHelpers
->mach_absolute_time();
565 kern_return_t
thread_switch(mach_port_name_t thread_name
,
566 int option
, mach_msg_timeout_t option_time
) {
567 if ( gSyscallHelpers
->version
< 2 )
569 return gSyscallHelpers
->thread_switch(thread_name
, option
, option_time
);
572 DIR* opendir(const char* path
) {
573 if ( gSyscallHelpers
->version
< 3 )
575 return gSyscallHelpers
->opendir(path
);
578 int readdir_r(DIR* dirp
, struct dirent
* entry
, struct dirent
**result
) {
579 if ( gSyscallHelpers
->version
< 3 )
581 return gSyscallHelpers
->readdir_r(dirp
, entry
, result
);
584 // HACK: readdir() is not used in dyld_sim, but it is pulled in by libc.a, then dead stripped.
585 struct dirent
* readdir(DIR *dirp
) {
586 _ZN4dyld4haltEPKc("dyld_sim readdir() not supported\n");
589 int closedir(DIR* dirp
) {
590 if ( gSyscallHelpers
->version
< 3 )
592 return gSyscallHelpers
->closedir(dirp
);
595 void coresymbolication_load_notifier(void* connection
, uint64_t timestamp
, const char* path
, const struct mach_header
* mh
)
597 // if host dyld supports this notifier, call into host dyld
598 if ( gSyscallHelpers
->version
>= 4 )
599 return gSyscallHelpers
->coresymbolication_load_notifier(connection
, timestamp
, path
, mh
);
602 void coresymbolication_unload_notifier(void* connection
, uint64_t timestamp
, const char* path
, const struct mach_header
* mh
)
604 // if host dyld supports this notifier, call into host dyld
605 if ( gSyscallHelpers
->version
>= 4 )
606 return gSyscallHelpers
->coresymbolication_unload_notifier(connection
, timestamp
, path
, mh
);
609 int mprotect(void* addr
, size_t len
, int prot
)
611 return vm_protect(mach_task_self(), (vm_address_t
)addr
, len
, false, prot
);
615 #define SUPPORT_HOST_10_11 1
617 #if SUPPORT_HOST_10_11
618 typedef int (*FuncPtr_proc_regionfilename
)(int pid
, uint64_t address
, void* buffer
, uint32_t bufferSize
);
619 typedef pid_t (*FuncPtr_getpid
)(void);
620 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
);
621 typedef kern_return_t (*FuncPtr_mach_port_allocate
)(ipc_space_t
, mach_port_right_t
, mach_port_name_t
*);
622 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
);
623 typedef void (*FuncPtr_mach_msg_destroy
)(mach_msg_header_t
*);
624 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
);
625 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
);
627 static FuncPtr_proc_regionfilename proc_proc_regionfilename
= NULL
;
628 static FuncPtr_getpid proc_getpid
= NULL
;
629 static FuncPtr_mach_port_insert_right proc_mach_port_insert_right
= NULL
;
630 static FuncPtr_mach_port_allocate proc_mach_port_allocate
= NULL
;
631 static FuncPtr_mach_msg proc_mach_msg
= NULL
;
632 static FuncPtr_mach_msg_destroy proc_mach_msg_destroy
= NULL
;
633 static FuncPtr_mach_port_construct proc_mach_port_construct
= NULL
;
634 static FuncPtr_mach_port_destruct proc_mach_port_destruct
= NULL
;
636 static mach_port_t
* sNotifyReplyPorts
= NULL
;
637 static bool* sZombieNotifiers
= NULL
;
639 // Look up sycalls in host dyld needed by coresymbolication_ routines in dyld_sim
640 static void findHostFunctions() {
641 // Only look up symbols once
642 if ( proc_mach_msg
!= NULL
)
645 struct dyld_all_image_infos
* imageInfo
= (struct dyld_all_image_infos
*)(gSyscallHelpers
->getProcessInfo());
646 const struct mach_header
* hostDyldMH
= imageInfo
->dyldImageLoadAddress
;
648 // find symbol table and slide of host dyld
650 const macho_nlist
* symbolTable
= NULL
;
651 const char* symbolTableStrings
= NULL
;
652 const struct dysymtab_command
* dynSymbolTable
= NULL
;
653 const uint32_t cmd_count
= hostDyldMH
->ncmds
;
654 const struct load_command
* const cmds
= (struct load_command
*)(((char*)hostDyldMH
)+sizeof(macho_header
));
655 const struct load_command
* cmd
= cmds
;
656 const uint8_t* linkEditBase
= NULL
;
657 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
659 case LC_SEGMENT_COMMAND
:
661 const macho_segment_command
* seg
= (macho_segment_command
*)cmd
;
662 if ( (seg
->fileoff
== 0) && (seg
->filesize
!= 0) )
663 slide
= (uintptr_t)hostDyldMH
- seg
->vmaddr
;
664 if ( strcmp(seg
->segname
, "__LINKEDIT") == 0 )
665 linkEditBase
= (uint8_t*)(seg
->vmaddr
- seg
->fileoff
+ slide
);
670 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
671 if ( linkEditBase
== NULL
)
673 symbolTableStrings
= (const char*)&linkEditBase
[symtab
->stroff
];
674 symbolTable
= (macho_nlist
*)(&linkEditBase
[symtab
->symoff
]);
678 dynSymbolTable
= (struct dysymtab_command
*)cmd
;
681 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
683 if ( symbolTableStrings
== NULL
)
685 if ( dynSymbolTable
== NULL
)
688 // scan local symbols in host dyld looking for load/unload functions
689 const macho_nlist
* const localsStart
= &symbolTable
[dynSymbolTable
->ilocalsym
];
690 const macho_nlist
* const localsEnd
= &localsStart
[dynSymbolTable
->nlocalsym
];
691 for (const macho_nlist
* s
= localsStart
; s
< localsEnd
; ++s
) {
692 if ( ((s
->n_type
& N_TYPE
) == N_SECT
) && ((s
->n_type
& N_STAB
) == 0) ) {
693 const char* name
= &symbolTableStrings
[s
->n_un
.n_strx
];
694 if ( strcmp(name
, "_proc_regionfilename") == 0 )
695 proc_proc_regionfilename
= (FuncPtr_proc_regionfilename
)(s
->n_value
+ slide
);
696 else if ( strcmp(name
, "_getpid") == 0 )
697 proc_getpid
= (FuncPtr_getpid
)(s
->n_value
+ slide
);
698 else if ( strcmp(name
, "mach_port_insert_right") == 0 )
699 proc_mach_port_insert_right
= (FuncPtr_mach_port_insert_right
)(s
->n_value
+ slide
);
700 else if ( strcmp(name
, "_mach_port_allocate") == 0 )
701 proc_mach_port_allocate
= (FuncPtr_mach_port_allocate
)(s
->n_value
+ slide
);
702 else if ( strcmp(name
, "_mach_msg") == 0 )
703 proc_mach_msg
= (FuncPtr_mach_msg
)(s
->n_value
+ slide
);
704 else if (strcmp(name
, "__ZN4dyldL17sNotifyReplyPortsE"))
705 sNotifyReplyPorts
= (mach_port_t
*)(s
->n_value
+ slide
);
706 else if (strcmp(name
, "__ZN4dyldL16sZombieNotifiersE"))
707 sZombieNotifiers
= (bool *)(s
->n_value
+ slide
);
712 // Look up sycalls in host dyld needed by coresymbolication_ routines in dyld_sim
713 static bool findHostLibSystemFunctions() {
714 // Only look up symbols once
715 if (proc_mach_msg_destroy
!= NULL
&& proc_mach_port_construct
!= NULL
&& proc_mach_port_destruct
!= NULL
)
718 const struct mach_header
* hostLibSystemMH
= NULL
;
719 struct dyld_all_image_infos
* imageInfo
= (struct dyld_all_image_infos
*)(gSyscallHelpers
->getProcessInfo());
720 const struct dyld_image_info
* infoArray
= imageInfo
->infoArray
;
721 if (infoArray
== NULL
)
723 uint32_t imageCount
= imageInfo
->infoArrayCount
;
724 for (uint32_t i
= 0; i
<imageCount
; ++i
) {
725 if (strcmp("/usr/lib/system/libsystem_kernel.dylib", infoArray
[i
].imageFilePath
) == 0) {
726 //Found the kernel interface
727 hostLibSystemMH
= infoArray
[i
].imageLoadAddress
;
731 if (hostLibSystemMH
== NULL
)
734 // find symbol table and slide of host dyld
736 const macho_nlist
* symbolTable
= NULL
;
737 const char* symbolTableStrings
= NULL
;
738 const struct dysymtab_command
* dynSymbolTable
= NULL
;
739 const uint32_t cmd_count
= hostLibSystemMH
->ncmds
;
740 const struct load_command
* const cmds
= (struct load_command
*)(((char*)hostLibSystemMH
)+sizeof(macho_header
));
741 const struct load_command
* cmd
= cmds
;
742 const uint8_t* linkEditBase
= NULL
;
743 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
745 case LC_SEGMENT_COMMAND
:
747 const macho_segment_command
* seg
= (macho_segment_command
*)cmd
;
748 if ( (seg
->fileoff
== 0) && (seg
->filesize
!= 0) )
749 slide
= (uintptr_t)hostLibSystemMH
- seg
->vmaddr
;
750 if ( strcmp(seg
->segname
, "__LINKEDIT") == 0 )
751 linkEditBase
= (uint8_t*)(seg
->vmaddr
- seg
->fileoff
+ slide
);
756 const struct symtab_command
* symtab
= (struct symtab_command
*)cmd
;
757 if ( linkEditBase
== NULL
)
759 symbolTableStrings
= (const char*)&linkEditBase
[symtab
->stroff
];
760 symbolTable
= (macho_nlist
*)(&linkEditBase
[symtab
->symoff
]);
764 dynSymbolTable
= (struct dysymtab_command
*)cmd
;
767 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
769 if ( symbolTableStrings
== NULL
)
771 if ( dynSymbolTable
== NULL
)
774 // scan local symbols in host dyld looking for load/unload functions
775 const macho_nlist
* const localsStart
= &symbolTable
[dynSymbolTable
->iextdefsym
];
776 const macho_nlist
* const localsEnd
= &localsStart
[dynSymbolTable
->nextdefsym
];
777 for (const macho_nlist
* s
= localsStart
; s
< localsEnd
; ++s
) {
778 if ( ((s
->n_type
& N_TYPE
) == N_SECT
) && ((s
->n_type
& N_STAB
) == 0) ) {
779 const char* name
= &symbolTableStrings
[s
->n_un
.n_strx
];
780 if ( strcmp(name
, "_mach_msg_destroy") == 0 )
781 proc_mach_msg_destroy
= (FuncPtr_mach_msg_destroy
)(s
->n_value
+ slide
);
782 else if ( strcmp(name
, "_mach_port_construct") == 0 )
783 proc_mach_port_construct
= (FuncPtr_mach_port_construct
)(s
->n_value
+ slide
);
784 else if ( strcmp(name
, "_mach_port_destruct") == 0 )
785 proc_mach_port_destruct
= (FuncPtr_mach_port_destruct
)(s
->n_value
+ slide
);
788 return (proc_mach_msg_destroy
!= NULL
&& proc_mach_port_construct
!= NULL
&& proc_mach_port_destruct
!= NULL
);
793 int proc_regionfilename(int pid
, uint64_t address
, void* buffer
, uint32_t bufferSize
)
795 if ( gSyscallHelpers
->version
>= 5 )
796 return gSyscallHelpers
->proc_regionfilename(pid
, address
, buffer
, bufferSize
);
797 #if SUPPORT_HOST_10_11
799 if ( proc_proc_regionfilename
)
800 return (*proc_proc_regionfilename
)(pid
, address
, buffer
, bufferSize
);
810 if ( gSyscallHelpers
->version
>= 5 )
811 return gSyscallHelpers
->getpid();
812 #if SUPPORT_HOST_10_11
814 return (*proc_getpid
)();
820 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
)
822 if ( gSyscallHelpers
->version
>= 5 )
823 return gSyscallHelpers
->mach_port_insert_right(task
, name
, poly
, polyPoly
);
824 #if SUPPORT_HOST_10_11
826 if ( proc_mach_port_insert_right
)
827 return (*proc_mach_port_insert_right
)(task
, name
, poly
, polyPoly
);
829 return KERN_NOT_SUPPORTED
;
831 return KERN_NOT_SUPPORTED
;
835 kern_return_t
mach_port_allocate(ipc_space_t task
, mach_port_right_t right
, mach_port_name_t
* name
)
837 if ( gSyscallHelpers
->version
>= 5 )
838 return gSyscallHelpers
->mach_port_allocate(task
, right
, name
);
839 #if SUPPORT_HOST_10_11
841 return (*proc_mach_port_allocate
)(task
, right
, name
);
843 return KERN_NOT_SUPPORTED
;
847 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
)
849 if ( gSyscallHelpers
->version
>= 5 )
850 return gSyscallHelpers
->mach_msg(msg
, option
, send_size
, rcv_size
, rcv_name
, timeout
, notify
);
851 #if SUPPORT_HOST_10_11
853 return (*proc_mach_msg
)(msg
, option
, send_size
, rcv_size
, rcv_name
, timeout
, notify
);
855 return KERN_NOT_SUPPORTED
;
859 void mach_msg_destroy(mach_msg_header_t
*msg
) {
860 if ( gSyscallHelpers
->version
>= 12 ) {
861 gSyscallHelpers
->mach_msg_destroy(msg
);
864 #if SUPPORT_HOST_10_11
865 if (findHostLibSystemFunctions()) {
866 (*proc_mach_msg_destroy
)(msg
);
871 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
) {
872 if ( gSyscallHelpers
->version
>= 12 ) {
873 return gSyscallHelpers
->mach_port_construct(task
, options
, context
, name
);
875 #if SUPPORT_HOST_10_11
876 if (findHostLibSystemFunctions()) {
877 return (*proc_mach_port_construct
)(task
, options
, context
, name
);
880 return KERN_NOT_SUPPORTED
;
883 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
) {
884 if ( gSyscallHelpers
->version
>= 12 ) {
885 return gSyscallHelpers
->mach_port_destruct(task
, name
, srdelta
, guard
);
887 #if SUPPORT_HOST_10_11
888 if (findHostLibSystemFunctions()) {
889 return (*proc_mach_port_destruct
)(task
, name
, srdelta
, guard
);
892 return KERN_NOT_SUPPORTED
;
895 kern_return_t
task_dyld_process_info_notify_get( mach_port_name_array_t names_addr
, mach_msg_type_number_t
*names_count_addr
) {
896 if ( gSyscallHelpers
->version
>= 14 ) {
897 return gSyscallHelpers
->task_dyld_process_info_notify_get(names_addr
, names_count_addr
);
899 struct dyld_all_image_infos
* imageInfo
= (struct dyld_all_image_infos
*)(gSyscallHelpers
->getProcessInfo());
900 for (int slot
=0; slot
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) {
901 if ( imageInfo
->notifyPorts
[slot
] != 0 ) {
903 (void)mach_port_mod_refs(mach_task_self(), imageInfo
->notifyPorts
[slot
], MACH_PORT_RIGHT_SEND
, 1);
907 return KERN_NOT_SUPPORTED
;
910 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
)
912 if ( gSyscallHelpers
->version
>= 6 )
913 gSyscallHelpers
->abort_with_payload(reason_namespace
, reason_code
, payload
, payload_size
, reason_string
, reason_flags
);
914 dyld_fatal_error(reason_string
);
917 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
) {
918 if ( gSyscallHelpers
->version
>= 8 )
919 return gSyscallHelpers
->task_info(target_task
, flavor
, task_info_out
, task_info_outCnt
);
920 return KERN_NOT_SUPPORTED
;
923 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
) {
924 if ( gSyscallHelpers
->version
>= 8 )
925 return gSyscallHelpers
->task_info(target_act
, flavor
, thread_info_out
, thread_info_outCnt
);
926 return KERN_NOT_SUPPORTED
;
929 bool kdebug_is_enabled(uint32_t code
) {
930 if ( gSyscallHelpers
->version
>= 8 )
931 return gSyscallHelpers
->kdebug_is_enabled(code
);
935 int kdebug_trace(uint32_t code
, uint64_t arg1
, uint64_t arg2
, uint64_t arg3
, uint64_t arg4
) {
936 if ( gSyscallHelpers
->version
>= 8 )
937 return gSyscallHelpers
->kdebug_trace(code
, arg1
, arg2
, arg3
, arg4
);
941 uint64_t kdebug_trace_string(uint32_t debugid
, uint64_t str_id
, const char *str
) {
942 if ( gSyscallHelpers
->version
>= 9 )
943 return gSyscallHelpers
->kdebug_trace_string(debugid
, str_id
, str
);
947 int amfi_check_dyld_policy_self(uint64_t inFlags
, uint64_t* outFlags
)
949 if ( gSyscallHelpers
->version
>= 10 )
950 return gSyscallHelpers
->amfi_check_dyld_policy_self(inFlags
, outFlags
);
951 *outFlags
= 0x3F; // on old kernel, simulator process get all flags
955 void _ZN4dyld24notifyMonitoringDyldMainEv() {
956 if ( gSyscallHelpers
->version
>= 11 ) {
957 gSyscallHelpers
->notifyMonitoringDyldMain();
960 #if SUPPORT_HOST_10_11
962 struct dyld_all_image_infos
* imageInfo
= (struct dyld_all_image_infos
*)(gSyscallHelpers
->getProcessInfo());
963 for (int slot
=0; slot
< DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT
; ++slot
) {
964 if ( (imageInfo
->notifyPorts
[slot
] != 0 ) && !sZombieNotifiers
[slot
] ) {
965 if ( sNotifyReplyPorts
[slot
] == 0 ) {
966 if ( !mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &sNotifyReplyPorts
[slot
]) )
967 mach_port_insert_right(mach_task_self(), sNotifyReplyPorts
[slot
], sNotifyReplyPorts
[slot
], MACH_MSG_TYPE_MAKE_SEND
);
968 //dyld::log("allocated reply port %d\n", sNotifyReplyPorts[slot]);
970 //dyld::log("found port to send to\n");
971 uint8_t messageBuffer
[sizeof(mach_msg_header_t
) + MAX_TRAILER_SIZE
];
972 mach_msg_header_t
* h
= (mach_msg_header_t
*)messageBuffer
;
973 h
->msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,MACH_MSG_TYPE_MAKE_SEND
); // MACH_MSG_TYPE_MAKE_SEND_ONCE
974 h
->msgh_id
= DYLD_PROCESS_INFO_NOTIFY_MAIN_ID
;
975 h
->msgh_local_port
= sNotifyReplyPorts
[slot
];
976 h
->msgh_remote_port
= imageInfo
->notifyPorts
[slot
];
977 h
->msgh_reserved
= 0;
978 h
->msgh_size
= (mach_msg_size_t
)sizeof(messageBuffer
);
979 //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);
980 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
);
981 //dyld::log("send result = 0x%X, msg_id=%d, msg_size=%d\n", sendResult, h->msgh_id, h->msgh_size);
982 if ( sendResult
== MACH_SEND_INVALID_DEST
) {
983 // sender is not responding, detatch
984 //dyld::log("process requesting notification gone. deallocation send port %d and receive port %d\n", dyld::gProcessInfo->notifyPorts[slot], sNotifyReplyPorts[slot]);
985 mach_port_deallocate(mach_task_self(), imageInfo
->notifyPorts
[slot
]);
986 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]);
987 imageInfo
->notifyPorts
[slot
] = 0;
988 sNotifyReplyPorts
[slot
] = 0;
990 else if ( sendResult
== MACH_RCV_TIMED_OUT
) {
991 // client took too long, ignore him from now on
992 sZombieNotifiers
[slot
] = true;
993 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[slot
]);
994 sNotifyReplyPorts
[slot
] = 0;
1001 #if SUPPORT_HOST_10_11
1002 static void notifyMonitoringDyld(bool unloading
, unsigned portSlot
, unsigned imageCount
, const struct mach_header
* loadAddresses
[], const char* imagePaths
[])
1004 if ( sZombieNotifiers
[portSlot
] )
1006 struct dyld_all_image_infos
* imageInfo
= (struct dyld_all_image_infos
*)(gSyscallHelpers
->getProcessInfo());
1007 unsigned entriesSize
= imageCount
*sizeof(struct dyld_process_info_image_entry
);
1008 unsigned pathsSize
= 0;
1009 for (unsigned j
=0; j
< imageCount
; ++j
) {
1010 pathsSize
+= (strlen(imagePaths
[j
]) + 1);
1012 unsigned totalSize
= (sizeof(struct dyld_process_info_notify_header
) + MAX_TRAILER_SIZE
+ entriesSize
+ pathsSize
+ 127) & -128; // align
1013 if ( totalSize
> DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE
) {
1014 // Putting all image paths into one message would make buffer too big.
1015 // Instead split into two messages. Recurse as needed until paths fit in buffer.
1016 unsigned imageHalfCount
= imageCount
/2;
1017 notifyMonitoringDyld(unloading
, portSlot
, imageHalfCount
, loadAddresses
, imagePaths
);
1018 notifyMonitoringDyld(unloading
, portSlot
, imageCount
- imageHalfCount
, &loadAddresses
[imageHalfCount
], &imagePaths
[imageHalfCount
]);
1021 uint8_t buffer
[totalSize
];
1022 struct dyld_process_info_notify_header
* header
= (struct dyld_process_info_notify_header
*)buffer
;
1023 header
->version
= 1;
1024 header
->imageCount
= imageCount
;
1025 header
->imagesOffset
= sizeof(struct dyld_process_info_notify_header
);
1026 header
->stringsOffset
= sizeof(struct dyld_process_info_notify_header
) + entriesSize
;
1027 header
->timestamp
= imageInfo
->infoArrayChangeTimestamp
;
1028 struct dyld_process_info_image_entry
* entries
= (struct dyld_process_info_image_entry
*)&buffer
[header
->imagesOffset
];
1029 char* const pathPoolStart
= (char*)&buffer
[header
->stringsOffset
];
1030 char* pathPool
= pathPoolStart
;
1031 for (unsigned j
=0; j
< imageCount
; ++j
) {
1032 strcpy(pathPool
, imagePaths
[j
]);
1033 uint32_t len
= (uint32_t)strlen(pathPool
);
1034 bzero(entries
->uuid
, 16);
1035 const macho_header
* mh
= (const macho_header
*)loadAddresses
[j
];
1036 const uint32_t cmd_count
= mh
->ncmds
;
1037 const struct load_command
* const cmds
= (struct load_command
*)((char*)mh
+ sizeof(macho_header
));
1038 const struct load_command
* cmd
= cmds
;
1039 for (uint32_t i
= 0; i
< cmd_count
; ++i
) {
1040 if (cmd
->cmd
== LC_UUID
) {
1041 struct uuid_command
* uc
= (struct uuid_command
*)cmd
;
1042 memcpy(&entries
->uuid
[0], uc
->uuid
, 16);
1045 cmd
= (const struct load_command
*)(((char*)cmd
)+cmd
->cmdsize
);
1047 entries
->loadAddress
= (uint64_t)loadAddresses
[j
];
1048 entries
->pathStringOffset
= (uint32_t)(pathPool
- pathPoolStart
);
1049 entries
->pathLength
= len
;
1050 pathPool
+= (len
+1);
1054 if ( sNotifyReplyPorts
[portSlot
] == 0 ) {
1055 if ( !mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &sNotifyReplyPorts
[portSlot
]) )
1056 mach_port_insert_right(mach_task_self(), sNotifyReplyPorts
[portSlot
], sNotifyReplyPorts
[portSlot
], MACH_MSG_TYPE_MAKE_SEND
);
1057 //dyld::log("allocated reply port %d\n", sNotifyReplyPorts[portSlot]);
1059 //dyld::log("found port to send to\n");
1060 mach_msg_header_t
* h
= (mach_msg_header_t
*)buffer
;
1061 h
->msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
,MACH_MSG_TYPE_MAKE_SEND
); // MACH_MSG_TYPE_MAKE_SEND_ONCE
1062 h
->msgh_id
= unloading
? DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID
: DYLD_PROCESS_INFO_NOTIFY_LOAD_ID
;
1063 h
->msgh_local_port
= sNotifyReplyPorts
[portSlot
];
1064 h
->msgh_remote_port
= imageInfo
->notifyPorts
[portSlot
];
1065 h
->msgh_reserved
= 0;
1066 h
->msgh_size
= (mach_msg_size_t
)sizeof(buffer
);
1067 //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);
1068 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
);
1069 //dyld::log("send result = 0x%X, msg_id=%d, msg_size=%d\n", sendResult, h->msgh_id, h->msgh_size);
1070 if ( sendResult
== MACH_SEND_INVALID_DEST
) {
1071 // sender is not responding, detatch
1072 //dyld::log("process requesting notification gone. deallocation send port %d and receive port %d\n", dyld::gProcessInfo->notifyPorts[portSlot], sNotifyReplyPorts[portSlot]);
1073 mach_port_deallocate(mach_task_self(), imageInfo
->notifyPorts
[portSlot
]);
1074 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[portSlot
]);
1075 imageInfo
->notifyPorts
[portSlot
] = 0;
1076 sNotifyReplyPorts
[portSlot
] = 0;
1078 else if ( sendResult
== MACH_RCV_TIMED_OUT
) {
1079 // client took too long, ignore him from now on
1080 sZombieNotifiers
[portSlot
] = true;
1081 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts
[portSlot
]);
1082 sNotifyReplyPorts
[portSlot
] = 0;
1087 void _ZN4dyld20notifyMonitoringDyldEbjPPK11mach_headerPPKc(bool unloading
, unsigned imageCount
, const struct mach_header
* loadAddresses
[], const char* imagePaths
[]) {
1088 if ( gSyscallHelpers
->version
>= 11 ) {
1089 gSyscallHelpers
->notifyMonitoringDyld(unloading
, imageCount
, loadAddresses
, imagePaths
);
1094 int* __error(void) {
1095 return gSyscallHelpers
->errnoAddress();
1099 mach_task_self_
= task_self_trap();
1100 //_task_reply_port = _mach_reply_port();
1103 mach_port_t mach_task_self_
= MACH_PORT_NULL
;
1105 extern int myerrno_fallback
__asm("_errno");
1106 int myerrno_fallback
= 0;
1109 vm_size_t vm_kernel_page_mask
= 0xFFF;
1110 vm_size_t vm_page_size
= 0x1000;
1112 #endif // TARGET_OS_SIMULATOR
1115 #if ! TARGET_OS_SIMULATOR
1116 #include <mach-o/dyld_process_info.h>
1118 // <rdar://problem/69456906> dyld should mark _dyld_debugger_notification `noinline`
1119 __attribute__ ((noinline
))
1120 void _dyld_debugger_notification(enum dyld_notify_mode mode
, unsigned long count
, uint64_t machHeaders
[])
1122 // Do nothing. This exists for the debugger to set a break point on to see what images have been loaded or unloaded.
1127 void* _NSConcreteStackBlock
[32];
1128 void* _NSConcreteGlobalBlock
[32];
1130 void _Block_object_assign()
1132 _ZN4dyld4haltEPKc("_Block_object_assign()");
1135 void _Block_object_dispose(const void* object
, int flags
)
1137 // only support stack blocks in dyld: BLOCK_FIELD_IS_BYREF=8
1139 _ZN4dyld4haltEPKc("_Block_object_dispose()");
1144 #if !TARGET_OS_SIMULATOR
1145 errno_t
memset_s(void* s
, rsize_t smax
, int c
, rsize_t n
)
1159 void uuid_unparse_upper(const uuid_t uu
, uuid_string_t out
)
1166 "%02X%02X%02X%02X%02X%02X",
1167 uu
[0], uu
[1], uu
[2], uu
[3],
1171 uu
[10], uu
[11], uu
[12], uu
[13], uu
[14], uu
[15]);