]>
Commit | Line | Data |
---|---|---|
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 | #include <stddef.h> | |
26 | #include <stdlib.h> | |
27 | #include <string.h> | |
28 | #include <stdint.h> | |
29 | #include <time.h> | |
30 | #include <fcntl.h> | |
31 | #include <unistd.h> | |
32 | #include <stdarg.h> | |
33 | #include <stdio.h> | |
34 | #include <mach/mach.h> | |
35 | #include <mach/mach_time.h> | |
36 | #include <sys/stat.h> | |
37 | #include <sys/mman.h> | |
38 | #include <sys/stat.h> | |
39 | #include <sys/ioctl.h> | |
40 | #include <TargetConditionals.h> | |
41 | #include <libkern/OSAtomic.h> | |
42 | #include <errno.h> | |
43 | #include <pthread.h> | |
44 | #if TARGET_IPHONE_SIMULATOR | |
45 | #include "dyldSyscallInterface.h" | |
46 | #include "dyld_images.h" | |
47 | #include <mach-o/loader.h> | |
48 | #include <mach-o/nlist.h> | |
49 | #include <mach/kern_return.h> | |
50 | #if __LP64__ | |
51 | #define LC_SEGMENT_COMMAND LC_SEGMENT_64 | |
52 | typedef struct segment_command_64 macho_segment_command; | |
53 | typedef struct mach_header_64 macho_header; | |
54 | typedef struct nlist_64 macho_nlist; | |
55 | #else | |
56 | #define LC_SEGMENT_COMMAND LC_SEGMENT | |
57 | typedef struct segment_command macho_segment_command; | |
58 | typedef struct mach_header macho_header; | |
59 | typedef struct nlist macho_nlist; | |
60 | #endif | |
61 | #endif | |
62 | ||
63 | // from _simple.h in libc | |
64 | typedef struct _SIMPLE* _SIMPLE_STRING; | |
65 | extern void _simple_vdprintf(int __fd, const char *__fmt, va_list __ap); | |
66 | extern void _simple_dprintf(int __fd, const char *__fmt, ...); | |
67 | extern _SIMPLE_STRING _simple_salloc(void); | |
68 | extern int _simple_vsprintf(_SIMPLE_STRING __b, const char *__fmt, va_list __ap); | |
69 | extern void _simple_sfree(_SIMPLE_STRING __b); | |
70 | extern char * _simple_string(_SIMPLE_STRING __b); | |
71 | ||
72 | // dyld::log(const char* format, ...) | |
73 | extern void _ZN4dyld3logEPKcz(const char*, ...); | |
74 | ||
75 | // dyld::halt(const char* msg); | |
76 | extern void _ZN4dyld4haltEPKc(const char* msg) __attribute__((noreturn)); | |
77 | ||
78 | ||
79 | // abort called by C++ unwinding code | |
80 | void abort() | |
81 | { | |
82 | _ZN4dyld4haltEPKc("dyld calling abort()\n"); | |
83 | } | |
84 | ||
85 | // std::terminate called by C++ unwinding code | |
86 | void _ZSt9terminatev() | |
87 | { | |
88 | _ZN4dyld4haltEPKc("dyld std::terminate()\n"); | |
89 | } | |
90 | ||
91 | // std::unexpected called by C++ unwinding code | |
92 | void _ZSt10unexpectedv() | |
93 | { | |
94 | _ZN4dyld4haltEPKc("dyld std::unexpected()\n"); | |
95 | } | |
96 | ||
97 | // __cxxabiv1::__terminate(void (*)()) called to terminate process | |
98 | void _ZN10__cxxabiv111__terminateEPFvvE() | |
99 | { | |
100 | _ZN4dyld4haltEPKc("dyld std::__terminate()\n"); | |
101 | } | |
102 | ||
103 | // __cxxabiv1::__unexpected(void (*)()) called to terminate process | |
104 | void _ZN10__cxxabiv112__unexpectedEPFvvE() | |
105 | { | |
106 | _ZN4dyld4haltEPKc("dyld std::__unexpected()\n"); | |
107 | } | |
108 | ||
109 | // __cxxabiv1::__terminate_handler | |
110 | void* _ZN10__cxxabiv119__terminate_handlerE = &_ZSt9terminatev; | |
111 | ||
112 | // __cxxabiv1::__unexpected_handler | |
113 | void* _ZN10__cxxabiv120__unexpected_handlerE = &_ZSt10unexpectedv; | |
114 | ||
115 | // libc uses assert() | |
116 | void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr) | |
117 | { | |
118 | if (func == NULL) | |
119 | _ZN4dyld3logEPKcz("Assertion failed: (%s), file %s, line %d.\n", failedexpr, file, line); | |
120 | else | |
121 | _ZN4dyld3logEPKcz("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line); | |
122 | abort(); | |
123 | } | |
124 | ||
125 | ||
126 | int myfprintf(FILE* file, const char* format, ...) __asm("_fprintf"); | |
127 | ||
128 | // called by libuwind code before aborting | |
129 | size_t fwrite(const void* ptr, size_t size, size_t nitme, FILE* stream) | |
130 | { | |
131 | return myfprintf(stream, "%s", (char*)ptr); | |
132 | } | |
133 | ||
134 | // called by libuwind code before aborting | |
135 | int fprintf(FILE* file, const char* format, ...) | |
136 | { | |
137 | va_list list; | |
138 | va_start(list, format); | |
139 | _simple_vdprintf(STDERR_FILENO, format, list); | |
140 | va_end(list); | |
141 | return 0; | |
142 | } | |
143 | ||
144 | // called by LIBC_ABORT | |
145 | void abort_report_np(const char* format, ...) | |
146 | { | |
147 | va_list list; | |
148 | const char *str; | |
149 | _SIMPLE_STRING s = _simple_salloc(); | |
150 | if ( s != NULL ) { | |
151 | va_start(list, format); | |
152 | _simple_vsprintf(s, format, list); | |
153 | va_end(list); | |
154 | str = _simple_string(s); | |
155 | } | |
156 | else { | |
157 | // _simple_salloc failed, but at least format may have useful info by itself | |
158 | str = format; | |
159 | } | |
160 | _ZN4dyld4haltEPKc(str); | |
161 | // _ZN4dyld4haltEPKc doesn't return, so we can't call _simple_sfree | |
162 | } | |
163 | ||
164 | ||
165 | // real cthread_set_errno_self() has error handling that pulls in | |
166 | // pthread_exit() which pulls in fprintf() | |
167 | extern int* __error(void); | |
168 | void cthread_set_errno_self(int err) | |
169 | { | |
170 | int* ep = __error(); | |
171 | *ep = err; | |
172 | } | |
173 | ||
174 | /* | |
175 | * We have our own localtime() to avoid needing the notify API which is used | |
176 | * by the code in libc.a for localtime() which is used by arc4random(). | |
177 | */ | |
178 | struct tm* localtime(const time_t* t) | |
179 | { | |
180 | return (struct tm*)NULL; | |
181 | } | |
182 | ||
183 | // malloc calls exit(-1) in case of errors... | |
184 | void exit(int x) | |
185 | { | |
186 | _ZN4dyld4haltEPKc("exit()"); | |
187 | } | |
188 | ||
189 | // static initializers make calls to __cxa_atexit | |
190 | void __cxa_atexit() | |
191 | { | |
192 | // do nothing, dyld never terminates | |
193 | } | |
194 | ||
195 | // | |
196 | // The stack protector routines in lib.c bring in too much stuff, so | |
197 | // make our own custom ones. | |
198 | // | |
199 | long __stack_chk_guard = 0; | |
200 | ||
201 | ||
202 | void __guard_setup(const char* apple[]) | |
203 | { | |
204 | for (const char** p = apple; *p != NULL; ++p) { | |
205 | if ( strncmp(*p, "stack_guard=", 12) == 0 ) { | |
206 | // kernel has provide a random value for us | |
207 | for (const char* s = *p + 12; *s != '\0'; ++s) { | |
208 | char c = *s; | |
209 | long value = 0; | |
210 | if ( (c >= 'a') && (c <= 'f') ) | |
211 | value = c - 'a' + 10; | |
212 | else if ( (c >= 'A') && (c <= 'F') ) | |
213 | value = c - 'A' + 10; | |
214 | else if ( (c >= '0') && (c <= '9') ) | |
215 | value = c - '0'; | |
216 | __stack_chk_guard <<= 4; | |
217 | __stack_chk_guard |= value; | |
218 | } | |
219 | if ( __stack_chk_guard != 0 ) | |
220 | return; | |
221 | } | |
222 | } | |
223 | #if !TARGET_IPHONE_SIMULATOR | |
224 | #if __LP64__ | |
225 | __stack_chk_guard = ((long)arc4random() << 32) | arc4random(); | |
226 | #else | |
227 | __stack_chk_guard = arc4random(); | |
228 | #endif | |
229 | #endif | |
230 | } | |
231 | ||
232 | extern void _ZN4dyld4haltEPKc(const char*); | |
233 | void __stack_chk_fail() | |
234 | { | |
235 | _ZN4dyld4haltEPKc("stack buffer overrun"); | |
236 | } | |
237 | ||
238 | ||
239 | // std::_throw_bad_alloc() | |
240 | void _ZSt17__throw_bad_allocv() | |
241 | { | |
242 | _ZN4dyld4haltEPKc("__throw_bad_alloc()"); | |
243 | } | |
244 | ||
245 | // std::_throw_length_error(const char* x) | |
246 | void _ZSt20__throw_length_errorPKc() | |
247 | { | |
248 | _ZN4dyld4haltEPKc("_throw_length_error()"); | |
249 | } | |
250 | ||
251 | // the libc.a version of this drags in ASL | |
252 | void __chk_fail() | |
253 | { | |
254 | _ZN4dyld4haltEPKc("__chk_fail()"); | |
255 | } | |
256 | ||
257 | ||
258 | // referenced by libc.a(pthread.o) but unneeded in dyld | |
259 | void _init_cpu_capabilities() { } | |
260 | void _cpu_capabilities() {} | |
261 | void set_malloc_singlethreaded() {} | |
262 | int PR_5243343_flag = 0; | |
263 | ||
264 | ||
265 | // used by some pthread routines | |
266 | char* mach_error_string(mach_error_t err) | |
267 | { | |
268 | return (char *)"unknown error code"; | |
269 | } | |
270 | char* mach_error_type(mach_error_t err) | |
271 | { | |
272 | return (char *)"(unknown/unknown)"; | |
273 | } | |
274 | ||
275 | // _pthread_reap_thread calls fprintf(stderr). | |
276 | // We map fprint to _simple_vdprintf and ignore FILE* stream, so ok for it to be NULL | |
277 | FILE* __stderrp = NULL; | |
278 | FILE* __stdoutp = NULL; | |
279 | ||
280 | // work with c++abi.a | |
281 | void (*__cxa_terminate_handler)() = _ZSt9terminatev; | |
282 | void (*__cxa_unexpected_handler)() = _ZSt10unexpectedv; | |
283 | ||
284 | void abort_message(const char* format, ...) | |
285 | { | |
286 | va_list list; | |
287 | va_start(list, format); | |
288 | _simple_vdprintf(STDERR_FILENO, format, list); | |
289 | va_end(list); | |
290 | } | |
291 | ||
292 | void __cxa_bad_typeid() | |
293 | { | |
294 | _ZN4dyld4haltEPKc("__cxa_bad_typeid()"); | |
295 | } | |
296 | ||
297 | // to work with libc++ | |
298 | void _ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv() | |
299 | { | |
300 | _ZN4dyld4haltEPKc("std::vector<>::_throw_length_error()"); | |
301 | } | |
302 | ||
303 | // libc.a sometimes missing memset | |
304 | #undef memset | |
305 | void* memset(void* b, int c, size_t len) | |
306 | { | |
307 | uint8_t* p = (uint8_t*)b; | |
308 | for(size_t i=len; i > 0; --i) | |
309 | *p++ = c; | |
310 | return b; | |
311 | } | |
312 | ||
313 | ||
314 | // <rdar://problem/10111032> wrap calls to stat() with check for EAGAIN | |
315 | int _ZN4dyld7my_statEPKcP4stat(const char* path, struct stat* buf) | |
316 | { | |
317 | int result; | |
318 | do { | |
319 | result = stat(path, buf); | |
320 | } while ((result == -1) && (errno == EAGAIN)); | |
321 | ||
322 | return result; | |
323 | } | |
324 | ||
325 | // <rdar://problem/13805025> dyld should retry open() if it gets an EGAIN | |
326 | int _ZN4dyld7my_openEPKcii(const char* path, int flag, int other) | |
327 | { | |
328 | int result; | |
329 | do { | |
330 | result = open(path, flag, other); | |
331 | } while ((result == -1) && (errno == EAGAIN)); | |
332 | ||
333 | return result; | |
334 | } | |
335 | ||
336 | ||
337 | // | |
338 | // The dyld in the iOS simulator cannot do syscalls, so it calls back to | |
339 | // host dyld. | |
340 | // | |
341 | ||
342 | #if TARGET_IPHONE_SIMULATOR | |
343 | ||
344 | #include <coreSymbolicationDyldSupport.h> | |
345 | ||
346 | int myopen(const char* path, int oflag, int extra) __asm("_open"); | |
347 | int myopen(const char* path, int oflag, int extra) { | |
348 | return gSyscallHelpers->open(path, oflag, extra); | |
349 | } | |
350 | ||
351 | int close(int fd) { | |
352 | return gSyscallHelpers->close(fd); | |
353 | } | |
354 | ||
355 | ssize_t pread(int fd, void* buf, size_t nbytes, off_t offset) { | |
356 | return gSyscallHelpers->pread(fd, buf , nbytes, offset); | |
357 | } | |
358 | ||
359 | ssize_t write(int fd, const void *buf, size_t nbytes) { | |
360 | return gSyscallHelpers->write(fd, buf , nbytes); | |
361 | } | |
362 | ||
363 | void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset) { | |
364 | return gSyscallHelpers->mmap(addr, len, prot, flags, fd, offset); | |
365 | } | |
366 | ||
367 | int munmap(void* addr, size_t len) { | |
368 | return gSyscallHelpers->munmap(addr, len); | |
369 | } | |
370 | ||
371 | int madvise(void* addr, size_t len, int advice) { | |
372 | return gSyscallHelpers->madvise(addr, len, advice); | |
373 | } | |
374 | ||
375 | int stat(const char* path, struct stat* buf) { | |
376 | return gSyscallHelpers->stat(path, buf); | |
377 | } | |
378 | ||
379 | int myfcntl(int fd, int cmd, void* result) __asm("_fcntl"); | |
380 | int myfcntl(int fd, int cmd, void* result) { | |
381 | return gSyscallHelpers->fcntl(fd, cmd, result); | |
382 | } | |
383 | ||
384 | int myioctl(int fd, unsigned long request, void* result) __asm("_ioctl"); | |
385 | int myioctl(int fd, unsigned long request, void* result) { | |
386 | return gSyscallHelpers->ioctl(fd, request, result); | |
387 | } | |
388 | ||
389 | int issetugid() { | |
390 | return gSyscallHelpers->issetugid(); | |
391 | } | |
392 | ||
393 | char* getcwd(char* buf, size_t size) { | |
394 | return gSyscallHelpers->getcwd(buf, size); | |
395 | } | |
396 | ||
397 | char* realpath(const char* file_name, char* resolved_name) { | |
398 | return gSyscallHelpers->realpath(file_name, resolved_name); | |
399 | } | |
400 | ||
401 | ||
402 | ||
403 | kern_return_t vm_allocate(vm_map_t target_task, vm_address_t *address, | |
404 | vm_size_t size, int flags) { | |
405 | return gSyscallHelpers->vm_allocate(target_task, address, size, flags); | |
406 | } | |
407 | ||
408 | kern_return_t vm_deallocate(vm_map_t target_task, vm_address_t address, | |
409 | vm_size_t size) { | |
410 | return gSyscallHelpers->vm_deallocate(target_task, address, size); | |
411 | } | |
412 | ||
413 | kern_return_t vm_protect(vm_map_t target_task, vm_address_t address, | |
414 | vm_size_t size, boolean_t max, vm_prot_t prot) { | |
415 | return gSyscallHelpers->vm_protect(target_task, address, size, max, prot); | |
416 | } | |
417 | ||
418 | ||
419 | void _ZN4dyld3logEPKcz(const char* format, ...) { | |
420 | va_list list; | |
421 | va_start(list, format); | |
422 | gSyscallHelpers->vlog(format, list); | |
423 | va_end(list); | |
424 | } | |
425 | ||
426 | void _ZN4dyld4warnEPKcz(const char* format, ...) { | |
427 | va_list list; | |
428 | va_start(list, format); | |
429 | gSyscallHelpers->vwarn(format, list); | |
430 | va_end(list); | |
431 | } | |
432 | ||
433 | ||
434 | int pthread_mutex_lock(pthread_mutex_t* m) { | |
435 | return gSyscallHelpers->pthread_mutex_lock(m); | |
436 | } | |
437 | ||
438 | int pthread_mutex_unlock(pthread_mutex_t* m) { | |
439 | return gSyscallHelpers->pthread_mutex_unlock(m); | |
440 | } | |
441 | ||
442 | mach_port_t mach_thread_self() { | |
443 | return gSyscallHelpers->mach_thread_self(); | |
444 | } | |
445 | ||
446 | kern_return_t mach_port_deallocate(ipc_space_t task, mach_port_name_t name) { | |
447 | return gSyscallHelpers->mach_port_deallocate(task, name); | |
448 | } | |
449 | ||
450 | mach_port_name_t task_self_trap() { | |
451 | return gSyscallHelpers->task_self_trap(); | |
452 | } | |
453 | ||
454 | kern_return_t mach_timebase_info(mach_timebase_info_t info) { | |
455 | return gSyscallHelpers->mach_timebase_info(info); | |
456 | } | |
457 | ||
458 | bool OSAtomicCompareAndSwapPtrBarrier(void* old, void* new, void * volatile *value) { | |
459 | return gSyscallHelpers->OSAtomicCompareAndSwapPtrBarrier(old, new, value); | |
460 | } | |
461 | ||
462 | void OSMemoryBarrier() { | |
463 | return gSyscallHelpers->OSMemoryBarrier(); | |
464 | } | |
465 | ||
466 | uint64_t mach_absolute_time(void) { | |
467 | return gSyscallHelpers->mach_absolute_time(); | |
468 | } | |
469 | ||
470 | kern_return_t thread_switch(mach_port_name_t thread_name, | |
471 | int option, mach_msg_timeout_t option_time) { | |
472 | if ( gSyscallHelpers->version < 2 ) | |
473 | return KERN_FAILURE; | |
474 | return gSyscallHelpers->thread_switch(thread_name, option, option_time); | |
475 | } | |
476 | ||
477 | DIR* opendir(const char* path) { | |
478 | if ( gSyscallHelpers->version < 3 ) | |
479 | return NULL; | |
480 | return gSyscallHelpers->opendir(path); | |
481 | } | |
482 | ||
483 | int readdir_r(DIR* dirp, struct dirent* entry, struct dirent **result) { | |
484 | if ( gSyscallHelpers->version < 3 ) | |
485 | return EPERM; | |
486 | return gSyscallHelpers->readdir_r(dirp, entry, result); | |
487 | } | |
488 | ||
489 | int closedir(DIR* dirp) { | |
490 | if ( gSyscallHelpers->version < 3 ) | |
491 | return EPERM; | |
492 | return gSyscallHelpers->closedir(dirp); | |
493 | } | |
494 | ||
495 | #define SUPPORT_HOST_10_10 1 | |
496 | ||
497 | #if SUPPORT_HOST_10_10 | |
498 | typedef int (*FuncPtr_nanosleep)(const struct timespec*, struct timespec*); | |
499 | typedef kern_return_t (*FuncPtr_mach_port_allocate)(ipc_space_t, mach_port_right_t, mach_port_name_t*); | |
500 | 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); | |
501 | typedef int (*FuncPtr_kill)(pid_t pid, int sig); | |
502 | typedef pid_t (*FuncPtr_getpid)(); | |
503 | typedef bool (*FuncPtr_OSAtomicCompareAndSwap32)(int32_t, int32_t, volatile int32_t*); | |
504 | ||
505 | static FuncPtr_nanosleep proc_nanosleep = NULL; | |
506 | static FuncPtr_mach_port_allocate proc_mach_port_allocate = NULL; | |
507 | static FuncPtr_mach_msg proc_mach_msg = NULL; | |
508 | static FuncPtr_kill proc_kill = NULL; | |
509 | static FuncPtr_getpid proc_getpid = NULL; | |
510 | static FuncPtr_OSAtomicCompareAndSwap32 proc_OSAtomicCompareAndSwap32 = NULL; | |
511 | ||
512 | ||
513 | int nanosleep(const struct timespec* p1, struct timespec* p2) | |
514 | { | |
515 | return (*proc_nanosleep)(p1, p2); | |
516 | } | |
517 | ||
518 | kern_return_t mach_port_allocate(ipc_space_t p1, mach_port_right_t p2, mach_port_name_t* p3) | |
519 | { | |
520 | return (*proc_mach_port_allocate)(p1, p2, p3); | |
521 | } | |
522 | ||
523 | mach_msg_return_t mach_msg(mach_msg_header_t* p1, mach_msg_option_t p2, mach_msg_size_t p3, mach_msg_size_t p4, mach_port_name_t p5, mach_msg_timeout_t p6, mach_port_name_t p7) | |
524 | { | |
525 | return (*proc_mach_msg)(p1, p2, p3, p4, p5, p6, p7); | |
526 | } | |
527 | ||
528 | int kill(pid_t p1, int p2) | |
529 | { | |
530 | return (*proc_kill)(p1, p2); | |
531 | } | |
532 | ||
533 | pid_t getpid() | |
534 | { | |
535 | return (*proc_getpid)(); | |
536 | } | |
537 | ||
538 | bool OSAtomicCompareAndSwap32(int32_t p1, int32_t p2, volatile int32_t* p3) | |
539 | { | |
540 | return (*proc_OSAtomicCompareAndSwap32)(p1, p2, p3); | |
541 | } | |
542 | ||
543 | ||
544 | // Look up sycalls in host dyld needed by coresymbolication_ routines in dyld_sim | |
545 | static void findHostFunctions() { | |
546 | // Only look up symbols once | |
547 | if ( proc_nanosleep != NULL ) | |
548 | return; | |
549 | ||
550 | struct dyld_all_image_infos* imageInfo = (struct dyld_all_image_infos*)(gSyscallHelpers->getProcessInfo()); | |
551 | const struct mach_header* hostDyldMH = imageInfo->dyldImageLoadAddress; | |
552 | ||
553 | // find symbol table and slide of host dyld | |
554 | uintptr_t slide = 0; | |
555 | const macho_nlist* symbolTable = NULL; | |
556 | const char* symbolTableStrings = NULL; | |
557 | const struct dysymtab_command* dynSymbolTable = NULL; | |
558 | const uint32_t cmd_count = hostDyldMH->ncmds; | |
559 | const struct load_command* const cmds = (struct load_command*)(((char*)hostDyldMH)+sizeof(macho_header)); | |
560 | const struct load_command* cmd = cmds; | |
561 | const uint8_t* linkEditBase = NULL; | |
562 | for (uint32_t i = 0; i < cmd_count; ++i) { | |
563 | switch (cmd->cmd) { | |
564 | case LC_SEGMENT_COMMAND: | |
565 | { | |
566 | const macho_segment_command* seg = (macho_segment_command*)cmd; | |
567 | if ( (seg->fileoff == 0) && (seg->filesize != 0) ) | |
568 | slide = (uintptr_t)hostDyldMH - seg->vmaddr; | |
569 | if ( strcmp(seg->segname, "__LINKEDIT") == 0 ) | |
570 | linkEditBase = (uint8_t*)(seg->vmaddr - seg->fileoff + slide); | |
571 | } | |
572 | break; | |
573 | case LC_SYMTAB: | |
574 | { | |
575 | const struct symtab_command* symtab = (struct symtab_command*)cmd; | |
576 | if ( linkEditBase == NULL ) | |
577 | return; | |
578 | symbolTableStrings = (const char*)&linkEditBase[symtab->stroff]; | |
579 | symbolTable = (macho_nlist*)(&linkEditBase[symtab->symoff]); | |
580 | } | |
581 | break; | |
582 | case LC_DYSYMTAB: | |
583 | dynSymbolTable = (struct dysymtab_command*)cmd; | |
584 | break; | |
585 | } | |
586 | cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); | |
587 | } | |
588 | if ( symbolTableStrings == NULL ) | |
589 | return; | |
590 | if ( dynSymbolTable == NULL ) | |
591 | return; | |
592 | ||
593 | // scan local symbols in host dyld looking for load/unload functions | |
594 | const macho_nlist* const localsStart = &symbolTable[dynSymbolTable->ilocalsym]; | |
595 | const macho_nlist* const localsEnd= &localsStart[dynSymbolTable->nlocalsym]; | |
596 | for (const macho_nlist* s = localsStart; s < localsEnd; ++s) { | |
597 | if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) { | |
598 | const char* name = &symbolTableStrings[s->n_un.n_strx]; | |
599 | if ( strcmp(name, "_nanosleep") == 0 ) | |
600 | proc_nanosleep = (FuncPtr_nanosleep)(s->n_value + slide); | |
601 | else if ( strcmp(name, "_mach_port_allocate") == 0 ) | |
602 | proc_mach_port_allocate = (FuncPtr_mach_port_allocate)(s->n_value + slide); | |
603 | else if ( strcmp(name, "_mach_msg") == 0 ) | |
604 | proc_mach_msg = (FuncPtr_mach_msg)(s->n_value + slide); | |
605 | else if ( strcmp(name, "_kill") == 0 ) | |
606 | proc_kill = (FuncPtr_kill)(s->n_value + slide); | |
607 | else if ( strcmp(name, "_getpid") == 0 ) | |
608 | proc_getpid = (FuncPtr_getpid)(s->n_value + slide); | |
609 | else if ( strcmp(name, "_OSAtomicCompareAndSwap32") == 0 ) | |
610 | proc_OSAtomicCompareAndSwap32 = (FuncPtr_OSAtomicCompareAndSwap32)(s->n_value + slide); | |
611 | } | |
612 | } | |
613 | } | |
614 | #endif | |
615 | ||
616 | void xcoresymbolication_load_notifier(void* connection, uint64_t timestamp, const char* path, const struct mach_header* mh) | |
617 | { | |
618 | // if host dyld supports this notifier, call into host dyld | |
619 | if ( gSyscallHelpers->version >= 4 ) | |
620 | return gSyscallHelpers->coresymbolication_load_notifier(connection, timestamp, path, mh); | |
621 | #if SUPPORT_HOST_10_10 | |
622 | // otherwise use notifier code in dyld_sim | |
623 | findHostFunctions(); | |
624 | coresymbolication_load_notifier(connection, timestamp, path, mh); | |
625 | #endif | |
626 | } | |
627 | ||
628 | void xcoresymbolication_unload_notifier(void* connection, uint64_t timestamp, const char* path, const struct mach_header* mh) | |
629 | { | |
630 | // if host dyld supports this notifier, call into host dyld | |
631 | if ( gSyscallHelpers->version >= 4 ) | |
632 | return gSyscallHelpers->coresymbolication_unload_notifier(connection, timestamp, path, mh); | |
633 | #if SUPPORT_HOST_10_10 | |
634 | // otherwise use notifier code in dyld_sim | |
635 | findHostFunctions(); | |
636 | coresymbolication_unload_notifier(connection, timestamp, path, mh); | |
637 | #endif | |
638 | } | |
639 | ||
640 | ||
641 | int* __error(void) { | |
642 | return gSyscallHelpers->errnoAddress(); | |
643 | } | |
644 | ||
645 | void mach_init() { | |
646 | mach_task_self_ = task_self_trap(); | |
647 | //_task_reply_port = _mach_reply_port(); | |
648 | } | |
649 | ||
650 | mach_port_t mach_task_self_ = MACH_PORT_NULL; | |
651 | ||
652 | extern int myerrno_fallback __asm("_errno"); | |
653 | int myerrno_fallback = 0; | |
654 | ||
655 | #endif // TARGET_IPHONE_SIMULATOR | |
656 | ||
657 |