dyld-832.7.1.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 //
404 // The dyld in the iOS simulator cannot do syscalls, so it calls back to
405 // host dyld.
406 //
407
408 #if TARGET_OS_SIMULATOR
409
410 int open(const char* path, int oflag, ...) {
411 int retval;
412
413 va_list args;
414 va_start(args, oflag);
415 retval = gSyscallHelpers->open(path, oflag, va_arg(args, int));
416 va_end(args);
417
418 return retval;
419 }
420
421 int close(int fd) {
422 return gSyscallHelpers->close(fd);
423 }
424
425 ssize_t pread(int fd, void* buf, size_t nbytes, off_t offset) {
426 return gSyscallHelpers->pread(fd, buf , nbytes, offset);
427 }
428
429 ssize_t write(int fd, const void *buf, size_t nbytes) {
430 return gSyscallHelpers->write(fd, buf , nbytes);
431 }
432
433 void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset) {
434 return gSyscallHelpers->mmap(addr, len, prot, flags, fd, offset);
435 }
436
437 int munmap(void* addr, size_t len) {
438 return gSyscallHelpers->munmap(addr, len);
439 }
440
441 int madvise(void* addr, size_t len, int advice) {
442 return gSyscallHelpers->madvise(addr, len, advice);
443 }
444
445 int stat(const char* path, struct stat* buf) {
446 return gSyscallHelpers->stat(path, buf);
447 }
448
449 int fcntl(int fd, int cmd, ...) {
450 int retval;
451
452 va_list args;
453 va_start(args, cmd);
454 retval = gSyscallHelpers->fcntl(fd, cmd, va_arg(args, void *));
455 va_end(args);
456
457 return retval;
458 }
459
460 int ioctl(int fd, unsigned long request, ...) {
461 int retval;
462
463 va_list args;
464 va_start(args, request);
465 retval = gSyscallHelpers->ioctl(fd, request, va_arg(args, void *));
466 va_end(args);
467
468 return retval;
469 }
470
471 int issetugid() {
472 return gSyscallHelpers->issetugid();
473 }
474
475 char* getcwd(char* buf, size_t size) {
476 return gSyscallHelpers->getcwd(buf, size);
477 }
478
479 char* realpath(const char* file_name, char* resolved_name) {
480 return gSyscallHelpers->realpath(file_name, resolved_name);
481 }
482
483
484
485 kern_return_t vm_allocate(vm_map_t target_task, vm_address_t *address,
486 vm_size_t size, int flags) {
487 return gSyscallHelpers->vm_allocate(target_task, address, size, flags);
488 }
489
490 kern_return_t vm_deallocate(vm_map_t target_task, vm_address_t address,
491 vm_size_t size) {
492 return gSyscallHelpers->vm_deallocate(target_task, address, size);
493 }
494
495 kern_return_t vm_protect(vm_map_t target_task, vm_address_t address,
496 vm_size_t size, boolean_t max, vm_prot_t prot) {
497 return gSyscallHelpers->vm_protect(target_task, address, size, max, prot);
498 }
499
500
501 void _ZN4dyld3logEPKcz(const char* format, ...) {
502 va_list list;
503 va_start(list, format);
504 gSyscallHelpers->vlog(format, list);
505 va_end(list);
506 }
507
508 #if __i386__
509 void _ZN4dyld4vlogEPKcPc(const char* format, va_list list) {
510 #else
511 void _ZN4dyld4vlogEPKcP13__va_list_tag(const char* format, va_list list) {
512 #endif
513 gSyscallHelpers->vlog(format, list);
514 }
515
516
517
518 void _ZN4dyld4warnEPKcz(const char* format, ...) {
519 va_list list;
520 va_start(list, format);
521 gSyscallHelpers->vwarn(format, list);
522 va_end(list);
523 }
524
525
526 int pthread_mutex_lock(pthread_mutex_t* m) {
527 return gSyscallHelpers->pthread_mutex_lock(m);
528 }
529
530 int pthread_mutex_unlock(pthread_mutex_t* m) {
531 return gSyscallHelpers->pthread_mutex_unlock(m);
532 }
533
534 mach_port_t mach_thread_self() {
535 return gSyscallHelpers->mach_thread_self();
536 }
537
538 kern_return_t mach_port_deallocate(ipc_space_t task, mach_port_name_t name) {
539 return gSyscallHelpers->mach_port_deallocate(task, name);
540 }
541
542 mach_port_name_t task_self_trap() {
543 return gSyscallHelpers->task_self_trap();
544 }
545
546 kern_return_t mach_timebase_info(mach_timebase_info_t info) {
547 return gSyscallHelpers->mach_timebase_info(info);
548 }
549
550 bool myOSAtomicCompareAndSwapPtrBarrier(void* old, void* new, void * volatile *value) __asm("_OSAtomicCompareAndSwapPtrBarrier");
551 bool myOSAtomicCompareAndSwapPtrBarrier(void* old, void* new, void * volatile *value) {
552 return gSyscallHelpers->OSAtomicCompareAndSwapPtrBarrier(old, new, value);
553 }
554
555 void myOSMemoryBarrier(void) __asm("_OSMemoryBarrier");
556 void myOSMemoryBarrier() {
557 return gSyscallHelpers->OSMemoryBarrier();
558 }
559
560 uint64_t mach_absolute_time(void) {
561 return gSyscallHelpers->mach_absolute_time();
562 }
563
564 kern_return_t thread_switch(mach_port_name_t thread_name,
565 int option, mach_msg_timeout_t option_time) {
566 if ( gSyscallHelpers->version < 2 )
567 return KERN_FAILURE;
568 return gSyscallHelpers->thread_switch(thread_name, option, option_time);
569 }
570
571 DIR* opendir(const char* path) {
572 if ( gSyscallHelpers->version < 3 )
573 return NULL;
574 return gSyscallHelpers->opendir(path);
575 }
576
577 int readdir_r(DIR* dirp, struct dirent* entry, struct dirent **result) {
578 if ( gSyscallHelpers->version < 3 )
579 return EPERM;
580 return gSyscallHelpers->readdir_r(dirp, entry, result);
581 }
582
583 // HACK: readdir() is not used in dyld_sim, but it is pulled in by libc.a, then dead stripped.
584 struct dirent* readdir(DIR *dirp) {
585 _ZN4dyld4haltEPKc("dyld_sim readdir() not supported\n");
586 }
587
588 int closedir(DIR* dirp) {
589 if ( gSyscallHelpers->version < 3 )
590 return EPERM;
591 return gSyscallHelpers->closedir(dirp);
592 }
593
594 void coresymbolication_load_notifier(void* connection, uint64_t timestamp, const char* path, const struct mach_header* mh)
595 {
596 // if host dyld supports this notifier, call into host dyld
597 if ( gSyscallHelpers->version >= 4 )
598 return gSyscallHelpers->coresymbolication_load_notifier(connection, timestamp, path, mh);
599 }
600
601 void coresymbolication_unload_notifier(void* connection, uint64_t timestamp, const char* path, const struct mach_header* mh)
602 {
603 // if host dyld supports this notifier, call into host dyld
604 if ( gSyscallHelpers->version >= 4 )
605 return gSyscallHelpers->coresymbolication_unload_notifier(connection, timestamp, path, mh);
606 }
607
608 int mprotect(void* addr, size_t len, int prot)
609 {
610 return vm_protect(mach_task_self(), (vm_address_t)addr, len, false, prot);
611 }
612
613
614 #define SUPPORT_HOST_10_11 1
615
616 #if SUPPORT_HOST_10_11
617 typedef int (*FuncPtr_proc_regionfilename)(int pid, uint64_t address, void* buffer, uint32_t bufferSize);
618 typedef pid_t (*FuncPtr_getpid)(void);
619 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);
620 typedef kern_return_t (*FuncPtr_mach_port_allocate)(ipc_space_t, mach_port_right_t, mach_port_name_t*);
621 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);
622 typedef void (*FuncPtr_mach_msg_destroy)(mach_msg_header_t *);
623 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);
624 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);
625
626 static FuncPtr_proc_regionfilename proc_proc_regionfilename = NULL;
627 static FuncPtr_getpid proc_getpid = NULL;
628 static FuncPtr_mach_port_insert_right proc_mach_port_insert_right = NULL;
629 static FuncPtr_mach_port_allocate proc_mach_port_allocate = NULL;
630 static FuncPtr_mach_msg proc_mach_msg = NULL;
631 static FuncPtr_mach_msg_destroy proc_mach_msg_destroy = NULL;
632 static FuncPtr_mach_port_construct proc_mach_port_construct = NULL;
633 static FuncPtr_mach_port_destruct proc_mach_port_destruct = NULL;
634
635 static mach_port_t* sNotifyReplyPorts = NULL;
636 static bool* sZombieNotifiers = NULL;
637
638 // Look up sycalls in host dyld needed by coresymbolication_ routines in dyld_sim
639 static void findHostFunctions() {
640 // Only look up symbols once
641 if ( proc_mach_msg != NULL )
642 return;
643
644 struct dyld_all_image_infos* imageInfo = (struct dyld_all_image_infos*)(gSyscallHelpers->getProcessInfo());
645 const struct mach_header* hostDyldMH = imageInfo->dyldImageLoadAddress;
646
647 // find symbol table and slide of host dyld
648 uintptr_t slide = 0;
649 const macho_nlist* symbolTable = NULL;
650 const char* symbolTableStrings = NULL;
651 const struct dysymtab_command* dynSymbolTable = NULL;
652 const uint32_t cmd_count = hostDyldMH->ncmds;
653 const struct load_command* const cmds = (struct load_command*)(((char*)hostDyldMH)+sizeof(macho_header));
654 const struct load_command* cmd = cmds;
655 const uint8_t* linkEditBase = NULL;
656 for (uint32_t i = 0; i < cmd_count; ++i) {
657 switch (cmd->cmd) {
658 case LC_SEGMENT_COMMAND:
659 {
660 const macho_segment_command* seg = (macho_segment_command*)cmd;
661 if ( (seg->fileoff == 0) && (seg->filesize != 0) )
662 slide = (uintptr_t)hostDyldMH - seg->vmaddr;
663 if ( strcmp(seg->segname, "__LINKEDIT") == 0 )
664 linkEditBase = (uint8_t*)(seg->vmaddr - seg->fileoff + slide);
665 }
666 break;
667 case LC_SYMTAB:
668 {
669 const struct symtab_command* symtab = (struct symtab_command*)cmd;
670 if ( linkEditBase == NULL )
671 return;
672 symbolTableStrings = (const char*)&linkEditBase[symtab->stroff];
673 symbolTable = (macho_nlist*)(&linkEditBase[symtab->symoff]);
674 }
675 break;
676 case LC_DYSYMTAB:
677 dynSymbolTable = (struct dysymtab_command*)cmd;
678 break;
679 }
680 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
681 }
682 if ( symbolTableStrings == NULL )
683 return;
684 if ( dynSymbolTable == NULL )
685 return;
686
687 // scan local symbols in host dyld looking for load/unload functions
688 const macho_nlist* const localsStart = &symbolTable[dynSymbolTable->ilocalsym];
689 const macho_nlist* const localsEnd= &localsStart[dynSymbolTable->nlocalsym];
690 for (const macho_nlist* s = localsStart; s < localsEnd; ++s) {
691 if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) {
692 const char* name = &symbolTableStrings[s->n_un.n_strx];
693 if ( strcmp(name, "_proc_regionfilename") == 0 )
694 proc_proc_regionfilename = (FuncPtr_proc_regionfilename)(s->n_value + slide);
695 else if ( strcmp(name, "_getpid") == 0 )
696 proc_getpid = (FuncPtr_getpid)(s->n_value + slide);
697 else if ( strcmp(name, "mach_port_insert_right") == 0 )
698 proc_mach_port_insert_right = (FuncPtr_mach_port_insert_right)(s->n_value + slide);
699 else if ( strcmp(name, "_mach_port_allocate") == 0 )
700 proc_mach_port_allocate = (FuncPtr_mach_port_allocate)(s->n_value + slide);
701 else if ( strcmp(name, "_mach_msg") == 0 )
702 proc_mach_msg = (FuncPtr_mach_msg)(s->n_value + slide);
703 else if (strcmp(name, "__ZN4dyldL17sNotifyReplyPortsE"))
704 sNotifyReplyPorts = (mach_port_t*)(s->n_value + slide);
705 else if (strcmp(name, "__ZN4dyldL16sZombieNotifiersE"))
706 sZombieNotifiers = (bool *)(s->n_value + slide);
707 }
708 }
709 }
710
711 // Look up sycalls in host dyld needed by coresymbolication_ routines in dyld_sim
712 static bool findHostLibSystemFunctions() {
713 // Only look up symbols once
714 if (proc_mach_msg_destroy != NULL && proc_mach_port_construct != NULL && proc_mach_port_destruct != NULL)
715 return true;
716
717 const struct mach_header* hostLibSystemMH = NULL;
718 struct dyld_all_image_infos* imageInfo = (struct dyld_all_image_infos*)(gSyscallHelpers->getProcessInfo());
719 const struct dyld_image_info* infoArray = imageInfo->infoArray;
720 if (infoArray == NULL)
721 return false;
722 uint32_t imageCount = imageInfo->infoArrayCount;
723 for (uint32_t i = 0; i<imageCount; ++i) {
724 if (strcmp("/usr/lib/system/libsystem_kernel.dylib", infoArray[i].imageFilePath) == 0) {
725 //Found the kernel interface
726 hostLibSystemMH = infoArray[i].imageLoadAddress;
727 break;
728 }
729 }
730 if (hostLibSystemMH == NULL)
731 return false;
732
733 // find symbol table and slide of host dyld
734 uintptr_t slide = 0;
735 const macho_nlist* symbolTable = NULL;
736 const char* symbolTableStrings = NULL;
737 const struct dysymtab_command* dynSymbolTable = NULL;
738 const uint32_t cmd_count = hostLibSystemMH->ncmds;
739 const struct load_command* const cmds = (struct load_command*)(((char*)hostLibSystemMH)+sizeof(macho_header));
740 const struct load_command* cmd = cmds;
741 const uint8_t* linkEditBase = NULL;
742 for (uint32_t i = 0; i < cmd_count; ++i) {
743 switch (cmd->cmd) {
744 case LC_SEGMENT_COMMAND:
745 {
746 const macho_segment_command* seg = (macho_segment_command*)cmd;
747 if ( (seg->fileoff == 0) && (seg->filesize != 0) )
748 slide = (uintptr_t)hostLibSystemMH - seg->vmaddr;
749 if ( strcmp(seg->segname, "__LINKEDIT") == 0 )
750 linkEditBase = (uint8_t*)(seg->vmaddr - seg->fileoff + slide);
751 }
752 break;
753 case LC_SYMTAB:
754 {
755 const struct symtab_command* symtab = (struct symtab_command*)cmd;
756 if ( linkEditBase == NULL )
757 return false;
758 symbolTableStrings = (const char*)&linkEditBase[symtab->stroff];
759 symbolTable = (macho_nlist*)(&linkEditBase[symtab->symoff]);
760 }
761 break;
762 case LC_DYSYMTAB:
763 dynSymbolTable = (struct dysymtab_command*)cmd;
764 break;
765 }
766 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
767 }
768 if ( symbolTableStrings == NULL )
769 return false;;
770 if ( dynSymbolTable == NULL )
771 return false;;
772
773 // scan local symbols in host dyld looking for load/unload functions
774 const macho_nlist* const localsStart = &symbolTable[dynSymbolTable->iextdefsym];
775 const macho_nlist* const localsEnd= &localsStart[dynSymbolTable->nextdefsym];
776 for (const macho_nlist* s = localsStart; s < localsEnd; ++s) {
777 if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) {
778 const char* name = &symbolTableStrings[s->n_un.n_strx];
779 if ( strcmp(name, "_mach_msg_destroy") == 0 )
780 proc_mach_msg_destroy = (FuncPtr_mach_msg_destroy)(s->n_value + slide);
781 else if ( strcmp(name, "_mach_port_construct") == 0 )
782 proc_mach_port_construct = (FuncPtr_mach_port_construct)(s->n_value + slide);
783 else if ( strcmp(name, "_mach_port_destruct") == 0 )
784 proc_mach_port_destruct = (FuncPtr_mach_port_destruct)(s->n_value + slide);
785 }
786 }
787 return (proc_mach_msg_destroy != NULL && proc_mach_port_construct != NULL && proc_mach_port_destruct != NULL);
788 }
789 #endif
790
791
792 int proc_regionfilename(int pid, uint64_t address, void* buffer, uint32_t bufferSize)
793 {
794 if ( gSyscallHelpers->version >= 5 )
795 return gSyscallHelpers->proc_regionfilename(pid, address, buffer, bufferSize);
796 #if SUPPORT_HOST_10_11
797 findHostFunctions();
798 if ( proc_proc_regionfilename )
799 return (*proc_proc_regionfilename)(pid, address, buffer, bufferSize);
800 else
801 return 0;
802 #else
803 return 0;
804 #endif
805 }
806
807 pid_t getpid()
808 {
809 if ( gSyscallHelpers->version >= 5 )
810 return gSyscallHelpers->getpid();
811 #if SUPPORT_HOST_10_11
812 findHostFunctions();
813 return (*proc_getpid)();
814 #else
815 return 0;
816 #endif
817 }
818
819 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)
820 {
821 if ( gSyscallHelpers->version >= 5 )
822 return gSyscallHelpers->mach_port_insert_right(task, name, poly, polyPoly);
823 #if SUPPORT_HOST_10_11
824 findHostFunctions();
825 if ( proc_mach_port_insert_right )
826 return (*proc_mach_port_insert_right)(task, name, poly, polyPoly);
827 else
828 return KERN_NOT_SUPPORTED;
829 #else
830 return KERN_NOT_SUPPORTED;
831 #endif
832 }
833
834 kern_return_t mach_port_allocate(ipc_space_t task, mach_port_right_t right, mach_port_name_t* name)
835 {
836 if ( gSyscallHelpers->version >= 5 )
837 return gSyscallHelpers->mach_port_allocate(task, right, name);
838 #if SUPPORT_HOST_10_11
839 findHostFunctions();
840 return (*proc_mach_port_allocate)(task, right, name);
841 #else
842 return KERN_NOT_SUPPORTED;
843 #endif
844 }
845
846 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)
847 {
848 if ( gSyscallHelpers->version >= 5 )
849 return gSyscallHelpers->mach_msg(msg, option, send_size, rcv_size, rcv_name, timeout, notify);
850 #if SUPPORT_HOST_10_11
851 findHostFunctions();
852 return (*proc_mach_msg)(msg, option, send_size, rcv_size, rcv_name, timeout, notify);
853 #else
854 return KERN_NOT_SUPPORTED;
855 #endif
856 }
857
858 void mach_msg_destroy(mach_msg_header_t *msg) {
859 if ( gSyscallHelpers->version >= 12 ) {
860 gSyscallHelpers->mach_msg_destroy(msg);
861 return;
862 }
863 #if SUPPORT_HOST_10_11
864 if (findHostLibSystemFunctions()) {
865 (*proc_mach_msg_destroy)(msg);
866 }
867 #endif
868 }
869
870 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) {
871 if ( gSyscallHelpers->version >= 12 ) {
872 return gSyscallHelpers->mach_port_construct(task, options, context, name);
873 }
874 #if SUPPORT_HOST_10_11
875 if (findHostLibSystemFunctions()) {
876 return (*proc_mach_port_construct)(task, options, context, name);
877 }
878 #endif
879 return KERN_NOT_SUPPORTED;
880 }
881
882 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) {
883 if ( gSyscallHelpers->version >= 12 ) {
884 return gSyscallHelpers->mach_port_destruct(task, name, srdelta, guard);
885 }
886 #if SUPPORT_HOST_10_11
887 if (findHostLibSystemFunctions()) {
888 return (*proc_mach_port_destruct)(task, name, srdelta, guard);
889 }
890 #endif
891 return KERN_NOT_SUPPORTED;
892 }
893
894 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)
895 {
896 if ( gSyscallHelpers->version >= 6 )
897 gSyscallHelpers->abort_with_payload(reason_namespace, reason_code, payload, payload_size, reason_string, reason_flags);
898 dyld_fatal_error(reason_string);
899 }
900
901 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) {
902 if ( gSyscallHelpers->version >= 8 )
903 return gSyscallHelpers->task_info(target_task, flavor, task_info_out, task_info_outCnt);
904 return KERN_NOT_SUPPORTED;
905 }
906
907 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) {
908 if ( gSyscallHelpers->version >= 8 )
909 return gSyscallHelpers->task_info(target_act, flavor, thread_info_out, thread_info_outCnt);
910 return KERN_NOT_SUPPORTED;
911 }
912
913 bool kdebug_is_enabled(uint32_t code) {
914 if ( gSyscallHelpers->version >= 8 )
915 return gSyscallHelpers->kdebug_is_enabled(code);
916 return false;
917 }
918
919 int kdebug_trace(uint32_t code, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) {
920 if ( gSyscallHelpers->version >= 8 )
921 return gSyscallHelpers->kdebug_trace(code, arg1, arg2, arg3, arg4);
922 return 0;
923 }
924
925 uint64_t kdebug_trace_string(uint32_t debugid, uint64_t str_id, const char *str) {
926 if ( gSyscallHelpers->version >= 9 )
927 return gSyscallHelpers->kdebug_trace_string(debugid, str_id, str);
928 return 0;
929 }
930
931 int amfi_check_dyld_policy_self(uint64_t inFlags, uint64_t* outFlags)
932 {
933 if ( gSyscallHelpers->version >= 10 )
934 return gSyscallHelpers->amfi_check_dyld_policy_self(inFlags, outFlags);
935 *outFlags = 0x3F; // on old kernel, simulator process get all flags
936 return 0;
937 }
938
939 void _ZN4dyld24notifyMonitoringDyldMainEv() {
940 if ( gSyscallHelpers->version >= 11 ) {
941 gSyscallHelpers->notifyMonitoringDyldMain();
942 return;
943 }
944 #if SUPPORT_HOST_10_11
945 findHostFunctions();
946 struct dyld_all_image_infos* imageInfo = (struct dyld_all_image_infos*)(gSyscallHelpers->getProcessInfo());
947 for (int slot=0; slot < DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT; ++slot) {
948 if ( (imageInfo->notifyPorts[slot] != 0 ) && !sZombieNotifiers[slot] ) {
949 if ( sNotifyReplyPorts[slot] == 0 ) {
950 if ( !mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &sNotifyReplyPorts[slot]) )
951 mach_port_insert_right(mach_task_self(), sNotifyReplyPorts[slot], sNotifyReplyPorts[slot], MACH_MSG_TYPE_MAKE_SEND);
952 //dyld::log("allocated reply port %d\n", sNotifyReplyPorts[slot]);
953 }
954 //dyld::log("found port to send to\n");
955 uint8_t messageBuffer[sizeof(mach_msg_header_t) + MAX_TRAILER_SIZE];
956 mach_msg_header_t* h = (mach_msg_header_t*)messageBuffer;
957 h->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND); // MACH_MSG_TYPE_MAKE_SEND_ONCE
958 h->msgh_id = DYLD_PROCESS_INFO_NOTIFY_MAIN_ID;
959 h->msgh_local_port = sNotifyReplyPorts[slot];
960 h->msgh_remote_port = imageInfo->notifyPorts[slot];
961 h->msgh_reserved = 0;
962 h->msgh_size = (mach_msg_size_t)sizeof(messageBuffer);
963 //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);
964 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);
965 //dyld::log("send result = 0x%X, msg_id=%d, msg_size=%d\n", sendResult, h->msgh_id, h->msgh_size);
966 if ( sendResult == MACH_SEND_INVALID_DEST ) {
967 // sender is not responding, detatch
968 //dyld::log("process requesting notification gone. deallocation send port %d and receive port %d\n", dyld::gProcessInfo->notifyPorts[slot], sNotifyReplyPorts[slot]);
969 mach_port_deallocate(mach_task_self(), imageInfo->notifyPorts[slot]);
970 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts[slot]);
971 imageInfo->notifyPorts[slot] = 0;
972 sNotifyReplyPorts[slot] = 0;
973 }
974 else if ( sendResult == MACH_RCV_TIMED_OUT ) {
975 // client took too long, ignore him from now on
976 sZombieNotifiers[slot] = true;
977 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts[slot]);
978 sNotifyReplyPorts[slot] = 0;
979 }
980 }
981 }
982 #endif
983 }
984
985 #if SUPPORT_HOST_10_11
986 static void notifyMonitoringDyld(bool unloading, unsigned portSlot, unsigned imageCount, const struct mach_header* loadAddresses[], const char* imagePaths[])
987 {
988 if ( sZombieNotifiers[portSlot] )
989 return;
990 struct dyld_all_image_infos* imageInfo = (struct dyld_all_image_infos*)(gSyscallHelpers->getProcessInfo());
991 unsigned entriesSize = imageCount*sizeof(struct dyld_process_info_image_entry);
992 unsigned pathsSize = 0;
993 for (unsigned j=0; j < imageCount; ++j) {
994 pathsSize += (strlen(imagePaths[j]) + 1);
995 }
996 unsigned totalSize = (sizeof(struct dyld_process_info_notify_header) + MAX_TRAILER_SIZE + entriesSize + pathsSize + 127) & -128; // align
997 if ( totalSize > DYLD_PROCESS_INFO_NOTIFY_MAX_BUFFER_SIZE ) {
998 // Putting all image paths into one message would make buffer too big.
999 // Instead split into two messages. Recurse as needed until paths fit in buffer.
1000 unsigned imageHalfCount = imageCount/2;
1001 notifyMonitoringDyld(unloading, portSlot, imageHalfCount, loadAddresses, imagePaths);
1002 notifyMonitoringDyld(unloading, portSlot, imageCount - imageHalfCount, &loadAddresses[imageHalfCount], &imagePaths[imageHalfCount]);
1003 return;
1004 }
1005 uint8_t buffer[totalSize];
1006 struct dyld_process_info_notify_header* header = (struct dyld_process_info_notify_header*)buffer;
1007 header->version = 1;
1008 header->imageCount = imageCount;
1009 header->imagesOffset = sizeof(struct dyld_process_info_notify_header);
1010 header->stringsOffset = sizeof(struct dyld_process_info_notify_header) + entriesSize;
1011 header->timestamp = imageInfo->infoArrayChangeTimestamp;
1012 struct dyld_process_info_image_entry* entries = (struct dyld_process_info_image_entry*)&buffer[header->imagesOffset];
1013 char* const pathPoolStart = (char*)&buffer[header->stringsOffset];
1014 char* pathPool = pathPoolStart;
1015 for (unsigned j=0; j < imageCount; ++j) {
1016 strcpy(pathPool, imagePaths[j]);
1017 uint32_t len = (uint32_t)strlen(pathPool);
1018 bzero(entries->uuid, 16);
1019 const macho_header* mh = (const macho_header*)loadAddresses[j];
1020 const uint32_t cmd_count = mh->ncmds;
1021 const struct load_command* const cmds = (struct load_command*)((char*)mh + sizeof(macho_header));
1022 const struct load_command* cmd = cmds;
1023 for (uint32_t i = 0; i < cmd_count; ++i) {
1024 if (cmd->cmd == LC_UUID) {
1025 struct uuid_command* uc = (struct uuid_command*)cmd;
1026 memcpy(&entries->uuid[0], uc->uuid, 16);
1027 break;
1028 }
1029 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
1030 }
1031 entries->loadAddress = (uint64_t)loadAddresses[j];
1032 entries->pathStringOffset = (uint32_t)(pathPool - pathPoolStart);
1033 entries->pathLength = len;
1034 pathPool += (len +1);
1035 ++entries;
1036 }
1037
1038 if ( sNotifyReplyPorts[portSlot] == 0 ) {
1039 if ( !mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &sNotifyReplyPorts[portSlot]) )
1040 mach_port_insert_right(mach_task_self(), sNotifyReplyPorts[portSlot], sNotifyReplyPorts[portSlot], MACH_MSG_TYPE_MAKE_SEND);
1041 //dyld::log("allocated reply port %d\n", sNotifyReplyPorts[portSlot]);
1042 }
1043 //dyld::log("found port to send to\n");
1044 mach_msg_header_t* h = (mach_msg_header_t*)buffer;
1045 h->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_MAKE_SEND); // MACH_MSG_TYPE_MAKE_SEND_ONCE
1046 h->msgh_id = unloading ? DYLD_PROCESS_INFO_NOTIFY_UNLOAD_ID : DYLD_PROCESS_INFO_NOTIFY_LOAD_ID;
1047 h->msgh_local_port = sNotifyReplyPorts[portSlot];
1048 h->msgh_remote_port = imageInfo->notifyPorts[portSlot];
1049 h->msgh_reserved = 0;
1050 h->msgh_size = (mach_msg_size_t)sizeof(buffer);
1051 //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);
1052 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);
1053 //dyld::log("send result = 0x%X, msg_id=%d, msg_size=%d\n", sendResult, h->msgh_id, h->msgh_size);
1054 if ( sendResult == MACH_SEND_INVALID_DEST ) {
1055 // sender is not responding, detatch
1056 //dyld::log("process requesting notification gone. deallocation send port %d and receive port %d\n", dyld::gProcessInfo->notifyPorts[portSlot], sNotifyReplyPorts[portSlot]);
1057 mach_port_deallocate(mach_task_self(), imageInfo->notifyPorts[portSlot]);
1058 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts[portSlot]);
1059 imageInfo->notifyPorts[portSlot] = 0;
1060 sNotifyReplyPorts[portSlot] = 0;
1061 }
1062 else if ( sendResult == MACH_RCV_TIMED_OUT ) {
1063 // client took too long, ignore him from now on
1064 sZombieNotifiers[portSlot] = true;
1065 mach_port_deallocate(mach_task_self(), sNotifyReplyPorts[portSlot]);
1066 sNotifyReplyPorts[portSlot] = 0;
1067 }
1068 }
1069 #endif
1070
1071 void _ZN4dyld20notifyMonitoringDyldEbjPPK11mach_headerPPKc(bool unloading, unsigned imageCount, const struct mach_header* loadAddresses[], const char* imagePaths[]) {
1072 if ( gSyscallHelpers->version >= 11 ) {
1073 gSyscallHelpers->notifyMonitoringDyld(unloading, imageCount, loadAddresses, imagePaths);
1074 return;
1075 }
1076 #if SUPPORT_HOST_10_11
1077 findHostFunctions();
1078 for (int slot=0; slot < DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT; ++slot) {
1079 notifyMonitoringDyld(unloading, slot, imageCount, loadAddresses, imagePaths);
1080 }
1081 #endif
1082 }
1083
1084 int* __error(void) {
1085 return gSyscallHelpers->errnoAddress();
1086 }
1087
1088 void mach_init() {
1089 mach_task_self_ = task_self_trap();
1090 //_task_reply_port = _mach_reply_port();
1091 }
1092
1093 mach_port_t mach_task_self_ = MACH_PORT_NULL;
1094
1095 extern int myerrno_fallback __asm("_errno");
1096 int myerrno_fallback = 0;
1097
1098
1099 vm_size_t vm_kernel_page_mask = 0xFFF;
1100 vm_size_t vm_page_size = 0x1000;
1101
1102 #endif // TARGET_OS_SIMULATOR
1103
1104
1105 #if ! TARGET_OS_SIMULATOR
1106 #include <mach-o/dyld_process_info.h>
1107
1108 void _dyld_debugger_notification(enum dyld_notify_mode mode, unsigned long count, uint64_t machHeaders[])
1109 {
1110 // Do nothing. This exists for the debugger to set a break point on to see what images have been loaded or unloaded.
1111 }
1112 #endif
1113
1114
1115 void* _NSConcreteStackBlock[32];
1116 void* _NSConcreteGlobalBlock[32];
1117
1118 void _Block_object_assign()
1119 {
1120 _ZN4dyld4haltEPKc("_Block_object_assign()");
1121 }
1122
1123 void _Block_object_dispose(const void* object, int flags)
1124 {
1125 // only support stack blocks in dyld: BLOCK_FIELD_IS_BYREF=8
1126 if ( flags != 8 )
1127 _ZN4dyld4haltEPKc("_Block_object_dispose()");
1128 }
1129
1130
1131
1132 #if !TARGET_OS_SIMULATOR
1133 errno_t memset_s(void* s, rsize_t smax, int c, rsize_t n)
1134 {
1135 errno_t err = 0;
1136 if (s == NULL)
1137 return EINVAL;
1138 if (n > smax) {
1139 err = EOVERFLOW;
1140 n = smax;
1141 }
1142 memset(s, c, n);
1143 return err;
1144 }
1145 #endif
1146
1147 void uuid_unparse_upper(const uuid_t uu, uuid_string_t out)
1148 {
1149 sprintf(out,
1150 "%02X%02X%02X%02X-"
1151 "%02X%02X-"
1152 "%02X%02X-"
1153 "%02X%02X-"
1154 "%02X%02X%02X%02X%02X%02X",
1155 uu[0], uu[1], uu[2], uu[3],
1156 uu[4], uu[5],
1157 uu[6], uu[7],
1158 uu[8], uu[9],
1159 uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
1160 }
1161
1162
1163