]> git.saurik.com Git - apple/dyld.git/blob - src/glue.c
dyld-733.8.tar.gz
[apple/dyld.git] / src / glue.c
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #define _FORTIFY_SOURCE 0
26
27 #include <stddef.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdint.h>
31 #include <time.h>
32 #include <fcntl.h>
33 #include <unistd.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <mach/mach.h>
37 #include <mach/mach_time.h>
38 #include <sys/stat.h>
39 #include <sys/mman.h>
40 #include <sys/stat.h>
41 #include <sys/ioctl.h>
42 #include <TargetConditionals.h>
43 #include <libkern/OSAtomic.h>
44 #include <errno.h>
45 #include <pthread.h>
46 #include <corecrypto/ccdigest.h>
47 #include <corecrypto/ccsha1.h>
48 #include <corecrypto/ccsha2.h>
49
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>
56 #if __LP64__
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;
61 #else
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;
66 #endif
67
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
72
73 struct dyld_process_info_image_entry {
74 uuid_t uuid;
75 uint64_t loadAddress;
76 uint32_t pathStringOffset;
77 uint32_t pathLength;
78 };
79
80 struct dyld_process_info_notify_header {
81 mach_msg_header_t header;
82 uint32_t version;
83 uint32_t imageCount;
84 uint32_t imagesOffset;
85 uint32_t stringsOffset;
86 uint64_t timestamp;
87 };
88 #endif
89
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);
98
99 // dyld::log(const char* format, ...)
100 extern void _ZN4dyld3logEPKcz(const char*, ...);
101
102 // dyld::halt(const char* msg);
103 extern void _ZN4dyld4haltEPKc(const char* msg) __attribute__((noreturn));
104
105 extern void dyld_fatal_error(const char* errString) __attribute__((noreturn));
106
107
108 // abort called by C++ unwinding code
109 void abort()
110 {
111 _ZN4dyld4haltEPKc("dyld calling abort()\n");
112 }
113
114 // std::terminate called by C++ unwinding code
115 void _ZSt9terminatev()
116 {
117 _ZN4dyld4haltEPKc("dyld std::terminate()\n");
118 }
119
120 // std::unexpected called by C++ unwinding code
121 void _ZSt10unexpectedv()
122 {
123 _ZN4dyld4haltEPKc("dyld std::unexpected()\n");
124 }
125
126 // __cxxabiv1::__terminate(void (*)()) called to terminate process
127 void _ZN10__cxxabiv111__terminateEPFvvE()
128 {
129 _ZN4dyld4haltEPKc("dyld std::__terminate()\n");
130 }
131
132 // __cxxabiv1::__unexpected(void (*)()) called to terminate process
133 void _ZN10__cxxabiv112__unexpectedEPFvvE()
134 {
135 _ZN4dyld4haltEPKc("dyld std::__unexpected()\n");
136 }
137
138 // std::__terminate() called by C++ unwinding code
139 void _ZSt11__terminatePFvvE(void (*func)(void))
140 {
141 _ZN4dyld4haltEPKc("dyld std::__terminate()\n");
142 }
143
144 // std::__unexpected() called by C++ unwinding code
145 void _ZSt12__unexpectedPFvvE(void (*func)(void))
146 {
147 _ZN4dyld4haltEPKc("dyld std::__unexpected()\n");
148 }
149
150 // terminate_handler get_terminate()
151 void* _ZSt13get_terminatev()
152 {
153 return NULL;
154 }
155
156 // unexpected_handler get_unexpected()
157 void* _ZSt14get_unexpectedv()
158 {
159 return NULL;
160 }
161
162 // new_handler get_new_handler()
163 void* _ZSt15get_new_handlerv()
164 {
165 return NULL;
166 }
167
168
169
170 // __cxxabiv1::__terminate_handler
171 void* _ZN10__cxxabiv119__terminate_handlerE = &_ZSt9terminatev;
172
173 // __cxxabiv1::__unexpected_handler
174 void* _ZN10__cxxabiv120__unexpected_handlerE = &_ZSt10unexpectedv;
175
176
177 int myfprintf(FILE* file, const char* format, ...) __asm("_fprintf");
178
179 // called by libuwind code before aborting
180 size_t fwrite(const void* ptr, size_t size, size_t nitme, FILE* stream)
181 {
182 return myfprintf(stream, "%s", (char*)ptr);
183 }
184
185 // called by libuwind code before aborting
186 int fprintf(FILE* file, const char* format, ...)
187 {
188 va_list list;
189 va_start(list, format);
190 _simple_vdprintf(STDERR_FILENO, format, list);
191 va_end(list);
192 return 0;
193 }
194
195 // called by LIBC_ABORT
196 void abort_report_np(const char* format, ...)
197 {
198 va_list list;
199 const char *str;
200 _SIMPLE_STRING s = _simple_salloc();
201 if ( s != NULL ) {
202 va_start(list, format);
203 _simple_vsprintf(s, format, list);
204 va_end(list);
205 str = _simple_string(s);
206 }
207 else {
208 // _simple_salloc failed, but at least format may have useful info by itself
209 str = format;
210 }
211 _ZN4dyld4haltEPKc(str);
212 // _ZN4dyld4haltEPKc doesn't return, so we can't call _simple_sfree
213 }
214
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)
219 {
220 if (func == NULL) {
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);
223 } else {
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);
226 }
227 }
228 #pragma clang diagnostic pop
229
230 int sprintf(char * restrict str, const char * restrict format, ...)
231 {
232 va_list list;
233 _SIMPLE_STRING s = _simple_salloc();
234 va_start(list, format);
235 _simple_vsprintf(s, format, list);
236 va_end(list);
237 strcpy(str, _simple_string(s));
238 _simple_sfree(s);
239 return 0;
240 }
241
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)
246 {
247 int* ep = __error();
248 *ep = err;
249 }
250
251 /*
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().
254 */
255 struct tm* localtime(const time_t* t)
256 {
257 return (struct tm*)NULL;
258 }
259
260 // malloc calls exit(-1) in case of errors...
261 void exit(int x)
262 {
263 _ZN4dyld4haltEPKc("exit()");
264 }
265
266 // static initializers make calls to __cxa_atexit
267 void __cxa_atexit()
268 {
269 // do nothing, dyld never terminates
270 }
271
272 //
273 // The stack protector routines in lib.c bring in too much stuff, so
274 // make our own custom ones.
275 //
276 long __stack_chk_guard = 0;
277
278
279 void __guard_setup(const char* apple[])
280 {
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) {
285 char c = *s;
286 long value = 0;
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') )
292 value = c - '0';
293 __stack_chk_guard <<= 4;
294 __stack_chk_guard |= value;
295 }
296 if ( __stack_chk_guard != 0 )
297 return;
298 }
299 }
300 #if !TARGET_OS_SIMULATOR
301 #if __LP64__
302 __stack_chk_guard = ((long)arc4random() << 32) | arc4random();
303 #else
304 __stack_chk_guard = arc4random();
305 #endif
306 #endif
307 }
308
309 extern void _ZN4dyld4haltEPKc(const char*);
310 void __stack_chk_fail()
311 {
312 _ZN4dyld4haltEPKc("stack buffer overrun");
313 }
314
315
316 // std::_throw_bad_alloc()
317 void _ZSt17__throw_bad_allocv()
318 {
319 _ZN4dyld4haltEPKc("__throw_bad_alloc()");
320 }
321
322 // std::_throw_length_error(const char* x)
323 void _ZSt20__throw_length_errorPKc()
324 {
325 _ZN4dyld4haltEPKc("_throw_length_error()");
326 }
327
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) {
332 return _Znwm(size);
333 }
334
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) {
339 _ZdlPv(ptr);
340 }
341
342 // the libc.a version of this drags in ASL
343 void __chk_fail()
344 {
345 _ZN4dyld4haltEPKc("__chk_fail()");
346 }
347
348
349 // referenced by libc.a(pthread.o) but unneeded in dyld
350 void set_malloc_singlethreaded() {}
351 int PR_5243343_flag = 0;
352
353
354 // used by some pthread routines
355 char* mach_error_string(mach_error_t err)
356 {
357 return (char *)"unknown error code";
358 }
359 char* mach_error_type(mach_error_t err)
360 {
361 return (char *)"(unknown/unknown)";
362 }
363
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;
368
369 // work with c++abi.a
370 void (*__cxa_terminate_handler)(void) = _ZSt9terminatev;
371 void (*__cxa_unexpected_handler)(void) = _ZSt10unexpectedv;
372
373 void abort_message(const char* format, ...)
374 {
375 va_list list;
376 va_start(list, format);
377 _simple_vdprintf(STDERR_FILENO, format, list);
378 va_end(list);
379 }
380
381 void __cxa_bad_typeid()
382 {
383 _ZN4dyld4haltEPKc("__cxa_bad_typeid()");
384 }
385
386 // to work with libc++
387 void _ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv()
388 {
389 _ZN4dyld4haltEPKc("std::vector<>::_throw_length_error()");
390 }
391
392 // libc.a sometimes missing memset
393 #undef memset
394 void* memset(void* b, int c, size_t len)
395 {
396 uint8_t* p = (uint8_t*)b;
397 for(size_t i=len; i > 0; --i)
398 *p++ = c;
399 return b;
400 }
401
402
403 // <rdar://problem/10111032> wrap calls to stat() with check for EAGAIN
404 int _ZN4dyld7my_statEPKcP4stat(const char* path, struct stat* buf)
405 {
406 int result;
407 do {
408 result = stat(path, buf);
409 } while ((result == -1) && ((errno == EAGAIN) || (errno == EINTR)));
410
411 return result;
412 }
413
414 // <rdar://problem/13805025> dyld should retry open() if it gets an EGAIN
415 int _ZN4dyld7my_openEPKcii(const char* path, int flag, int other)
416 {
417 int result;
418 do {
419 result = open(path, flag, other);
420 } while ((result == -1) && ((errno == EAGAIN) || (errno == EINTR)));
421
422 return result;
423 }
424
425
426 //
427 // The dyld in the iOS simulator cannot do syscalls, so it calls back to
428 // host dyld.
429 //
430
431 #if TARGET_OS_SIMULATOR
432
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);
436 }
437
438 int close(int fd) {
439 return gSyscallHelpers->close(fd);
440 }
441
442 ssize_t pread(int fd, void* buf, size_t nbytes, off_t offset) {
443 return gSyscallHelpers->pread(fd, buf , nbytes, offset);
444 }
445
446 ssize_t write(int fd, const void *buf, size_t nbytes) {
447 return gSyscallHelpers->write(fd, buf , nbytes);
448 }
449
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);
452 }
453
454 int munmap(void* addr, size_t len) {
455 return gSyscallHelpers->munmap(addr, len);
456 }
457
458 int madvise(void* addr, size_t len, int advice) {
459 return gSyscallHelpers->madvise(addr, len, advice);
460 }
461
462 int stat(const char* path, struct stat* buf) {
463 return gSyscallHelpers->stat(path, buf);
464 }
465
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);
469 }
470
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);
474 }
475
476 int issetugid() {
477 return gSyscallHelpers->issetugid();
478 }
479
480 char* getcwd(char* buf, size_t size) {
481 return gSyscallHelpers->getcwd(buf, size);
482 }
483
484 char* realpath(const char* file_name, char* resolved_name) {
485 return gSyscallHelpers->realpath(file_name, resolved_name);
486 }
487
488
489
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);
493 }
494
495 kern_return_t vm_deallocate(vm_map_t target_task, vm_address_t address,
496 vm_size_t size) {
497 return gSyscallHelpers->vm_deallocate(target_task, address, size);
498 }
499
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);
503 }
504
505
506 void _ZN4dyld3logEPKcz(const char* format, ...) {
507 va_list list;
508 va_start(list, format);
509 gSyscallHelpers->vlog(format, list);
510 va_end(list);
511 }
512
513 #if __i386__
514 void _ZN4dyld4vlogEPKcPc(const char* format, va_list list) {
515 #else
516 void _ZN4dyld4vlogEPKcP13__va_list_tag(const char* format, va_list list) {
517 #endif
518 gSyscallHelpers->vlog(format, list);
519 }
520
521
522
523 void _ZN4dyld4warnEPKcz(const char* format, ...) {
524 va_list list;
525 va_start(list, format);
526 gSyscallHelpers->vwarn(format, list);
527 va_end(list);
528 }
529
530
531 int pthread_mutex_lock(pthread_mutex_t* m) {
532 return gSyscallHelpers->pthread_mutex_lock(m);
533 }
534
535 int pthread_mutex_unlock(pthread_mutex_t* m) {
536 return gSyscallHelpers->pthread_mutex_unlock(m);
537 }
538
539 mach_port_t mach_thread_self() {
540 return gSyscallHelpers->mach_thread_self();
541 }
542
543 kern_return_t mach_port_deallocate(ipc_space_t task, mach_port_name_t name) {
544 return gSyscallHelpers->mach_port_deallocate(task, name);
545 }
546
547 mach_port_name_t task_self_trap() {
548 return gSyscallHelpers->task_self_trap();
549 }
550
551 kern_return_t mach_timebase_info(mach_timebase_info_t info) {
552 return gSyscallHelpers->mach_timebase_info(info);
553 }
554
555 bool OSAtomicCompareAndSwapPtrBarrier(void* old, void* new, void * volatile *value) {
556 return gSyscallHelpers->OSAtomicCompareAndSwapPtrBarrier(old, new, value);
557 }
558
559 void OSMemoryBarrier() {
560 return gSyscallHelpers->OSMemoryBarrier();
561 }
562
563 uint64_t mach_absolute_time(void) {
564 return gSyscallHelpers->mach_absolute_time();
565 }
566
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 )
570 return KERN_FAILURE;
571 return gSyscallHelpers->thread_switch(thread_name, option, option_time);
572 }
573
574 DIR* opendir(const char* path) {
575 if ( gSyscallHelpers->version < 3 )
576 return NULL;
577 return gSyscallHelpers->opendir(path);
578 }
579
580 int readdir_r(DIR* dirp, struct dirent* entry, struct dirent **result) {
581 if ( gSyscallHelpers->version < 3 )
582 return EPERM;
583 return gSyscallHelpers->readdir_r(dirp, entry, result);
584 }
585
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");
589 }
590
591 int closedir(DIR* dirp) {
592 if ( gSyscallHelpers->version < 3 )
593 return EPERM;
594 return gSyscallHelpers->closedir(dirp);
595 }
596
597 void coresymbolication_load_notifier(void* connection, uint64_t timestamp, const char* path, const struct mach_header* mh)
598 {
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);
602 }
603
604 void coresymbolication_unload_notifier(void* connection, uint64_t timestamp, const char* path, const struct mach_header* mh)
605 {
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);
609 }
610
611 int mprotect(void* addr, size_t len, int prot)
612 {
613 return vm_protect(mach_task_self(), (vm_address_t)addr, len, false, prot);
614 }
615
616
617 #define SUPPORT_HOST_10_11 1
618
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);
628
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;
637
638 static mach_port_t* sNotifyReplyPorts = NULL;
639 static bool* sZombieNotifiers = NULL;
640
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 )
645 return;
646
647 struct dyld_all_image_infos* imageInfo = (struct dyld_all_image_infos*)(gSyscallHelpers->getProcessInfo());
648 const struct mach_header* hostDyldMH = imageInfo->dyldImageLoadAddress;
649
650 // find symbol table and slide of host dyld
651 uintptr_t slide = 0;
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) {
660 switch (cmd->cmd) {
661 case LC_SEGMENT_COMMAND:
662 {
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);
668 }
669 break;
670 case LC_SYMTAB:
671 {
672 const struct symtab_command* symtab = (struct symtab_command*)cmd;
673 if ( linkEditBase == NULL )
674 return;
675 symbolTableStrings = (const char*)&linkEditBase[symtab->stroff];
676 symbolTable = (macho_nlist*)(&linkEditBase[symtab->symoff]);
677 }
678 break;
679 case LC_DYSYMTAB:
680 dynSymbolTable = (struct dysymtab_command*)cmd;
681 break;
682 }
683 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
684 }
685 if ( symbolTableStrings == NULL )
686 return;
687 if ( dynSymbolTable == NULL )
688 return;
689
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);
710 }
711 }
712 }
713
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)
718 return true;
719
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)
724 return false;
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;
730 break;
731 }
732 }
733 if (hostLibSystemMH == NULL)
734 return false;
735
736 // find symbol table and slide of host dyld
737 uintptr_t slide = 0;
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) {
746 switch (cmd->cmd) {
747 case LC_SEGMENT_COMMAND:
748 {
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);
754 }
755 break;
756 case LC_SYMTAB:
757 {
758 const struct symtab_command* symtab = (struct symtab_command*)cmd;
759 if ( linkEditBase == NULL )
760 return false;
761 symbolTableStrings = (const char*)&linkEditBase[symtab->stroff];
762 symbolTable = (macho_nlist*)(&linkEditBase[symtab->symoff]);
763 }
764 break;
765 case LC_DYSYMTAB:
766 dynSymbolTable = (struct dysymtab_command*)cmd;
767 break;
768 }
769 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
770 }
771 if ( symbolTableStrings == NULL )
772 return false;;
773 if ( dynSymbolTable == NULL )
774 return false;;
775
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);
788 }
789 }
790 return (proc_mach_msg_destroy != NULL && proc_mach_port_construct != NULL && proc_mach_port_destruct != NULL);
791 }
792 #endif
793
794
795 int proc_regionfilename(int pid, uint64_t address, void* buffer, uint32_t bufferSize)
796 {
797 if ( gSyscallHelpers->version >= 5 )
798 return gSyscallHelpers->proc_regionfilename(pid, address, buffer, bufferSize);
799 #if SUPPORT_HOST_10_11
800 findHostFunctions();
801 if ( proc_proc_regionfilename )
802 return (*proc_proc_regionfilename)(pid, address, buffer, bufferSize);
803 else
804 return 0;
805 #else
806 return 0;
807 #endif
808 }
809
810 pid_t getpid()
811 {
812 if ( gSyscallHelpers->version >= 5 )
813 return gSyscallHelpers->getpid();
814 #if SUPPORT_HOST_10_11
815 findHostFunctions();
816 return (*proc_getpid)();
817 #else
818 return 0;
819 #endif
820 }
821
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)
823 {
824 if ( gSyscallHelpers->version >= 5 )
825 return gSyscallHelpers->mach_port_insert_right(task, name, poly, polyPoly);
826 #if SUPPORT_HOST_10_11
827 findHostFunctions();
828 if ( proc_mach_port_insert_right )
829 return (*proc_mach_port_insert_right)(task, name, poly, polyPoly);
830 else
831 return KERN_NOT_SUPPORTED;
832 #else
833 return KERN_NOT_SUPPORTED;
834 #endif
835 }
836
837 kern_return_t mach_port_allocate(ipc_space_t task, mach_port_right_t right, mach_port_name_t* name)
838 {
839 if ( gSyscallHelpers->version >= 5 )
840 return gSyscallHelpers->mach_port_allocate(task, right, name);
841 #if SUPPORT_HOST_10_11
842 findHostFunctions();
843 return (*proc_mach_port_allocate)(task, right, name);
844 #else
845 return KERN_NOT_SUPPORTED;
846 #endif
847 }
848
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)
850 {
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
854 findHostFunctions();
855 return (*proc_mach_msg)(msg, option, send_size, rcv_size, rcv_name, timeout, notify);
856 #else
857 return KERN_NOT_SUPPORTED;
858 #endif
859 }
860
861 void mach_msg_destroy(mach_msg_header_t *msg) {
862 if ( gSyscallHelpers->version >= 12 ) {
863 gSyscallHelpers->mach_msg_destroy(msg);
864 return;
865 }
866 #if SUPPORT_HOST_10_11
867 if (findHostLibSystemFunctions()) {
868 (*proc_mach_msg_destroy)(msg);
869 }
870 #endif
871 }
872
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);
876 }
877 #if SUPPORT_HOST_10_11
878 if (findHostLibSystemFunctions()) {
879 return (*proc_mach_port_construct)(task, options, context, name);
880 }
881 #endif
882 return KERN_NOT_SUPPORTED;
883 }
884
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);
888 }
889 #if SUPPORT_HOST_10_11
890 if (findHostLibSystemFunctions()) {
891 return (*proc_mach_port_destruct)(task, name, srdelta, guard);
892 }
893 #endif
894 return KERN_NOT_SUPPORTED;
895 }
896
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)
898 {
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);
902 }
903
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;
908 }
909
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;
914 }
915
916 bool kdebug_is_enabled(uint32_t code) {
917 if ( gSyscallHelpers->version >= 8 )
918 return gSyscallHelpers->kdebug_is_enabled(code);
919 return false;
920 }
921
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);
925 return 0;
926 }
927
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);
931 return 0;
932 }
933
934 uint64_t amfi_check_dyld_policy_self(uint64_t inFlags, uint64_t* outFlags)
935 {
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
939 return 0;
940 }
941
942 void _ZN4dyld24notifyMonitoringDyldMainEv() {
943 if ( gSyscallHelpers->version >= 11 ) {
944 gSyscallHelpers->notifyMonitoringDyldMain();
945 return;
946 }
947 #if SUPPORT_HOST_10_11
948 findHostFunctions();
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]);
956 }
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;
976 }
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;
982 }
983 }
984 }
985 #endif
986 }
987
988 #if SUPPORT_HOST_10_11
989 static void notifyMonitoringDyld(bool unloading, unsigned portSlot, unsigned imageCount, const struct mach_header* loadAddresses[], const char* imagePaths[])
990 {
991 if ( sZombieNotifiers[portSlot] )
992 return;
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);
998 }
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]);
1006 return;
1007 }
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);
1030 break;
1031 }
1032 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1033 }
1034 entries->loadAddress = (uint64_t)loadAddresses[j];
1035 entries->pathStringOffset = (uint32_t)(pathPool - pathPoolStart);
1036 entries->pathLength = len;
1037 pathPool += (len +1);
1038 ++entries;
1039 }
1040
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]);
1045 }
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;
1064 }
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;
1070 }
1071 }
1072 #endif
1073
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);
1077 return;
1078 }
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);
1083 }
1084 #endif
1085 }
1086
1087 int* __error(void) {
1088 return gSyscallHelpers->errnoAddress();
1089 }
1090
1091 void mach_init() {
1092 mach_task_self_ = task_self_trap();
1093 //_task_reply_port = _mach_reply_port();
1094 }
1095
1096 mach_port_t mach_task_self_ = MACH_PORT_NULL;
1097
1098 extern int myerrno_fallback __asm("_errno");
1099 int myerrno_fallback = 0;
1100
1101
1102 vm_size_t vm_kernel_page_mask = 0xFFF;
1103 vm_size_t vm_page_size = 0x1000;
1104
1105 #endif // TARGET_OS_SIMULATOR
1106
1107
1108 #if ! TARGET_OS_SIMULATOR
1109 #include <mach-o/dyld_process_info.h>
1110
1111 void _dyld_debugger_notification(enum dyld_notify_mode mode, unsigned long count, uint64_t machHeaders[])
1112 {
1113 // Do nothing. This exists for the debugger to set a break point on to see what images have been loaded or unloaded.
1114 }
1115 #endif
1116
1117
1118 void* _NSConcreteStackBlock[32];
1119 void* _NSConcreteGlobalBlock[32];
1120
1121 void _Block_object_assign()
1122 {
1123 _ZN4dyld4haltEPKc("_Block_object_assign()");
1124 }
1125
1126 void _Block_object_dispose(const void* object, int flags)
1127 {
1128 // only support stack blocks in dyld: BLOCK_FIELD_IS_BYREF=8
1129 if ( flags != 8 )
1130 _ZN4dyld4haltEPKc("_Block_object_dispose()");
1131 }
1132
1133
1134
1135 #if !TARGET_OS_SIMULATOR
1136 errno_t memset_s(void* s, rsize_t smax, int c, rsize_t n)
1137 {
1138 errno_t err = 0;
1139 if (s == NULL)
1140 return EINVAL;
1141 if (n > smax) {
1142 err = EOVERFLOW;
1143 n = smax;
1144 }
1145 memset(s, c, n);
1146 return err;
1147 }
1148 #endif
1149
1150 void uuid_unparse_upper(const uuid_t uu, uuid_string_t out)
1151 {
1152 sprintf(out,
1153 "%02X%02X%02X%02X-"
1154 "%02X%02X-"
1155 "%02X%02X-"
1156 "%02X%02X-"
1157 "%02X%02X%02X%02X%02X%02X",
1158 uu[0], uu[1], uu[2], uu[3],
1159 uu[4], uu[5],
1160 uu[6], uu[7],
1161 uu[8], uu[9],
1162 uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
1163 }