Merge pull request #8 from biergaizi/upstream
[darwin-xtools.git] / dyld / src / glue.c
blob5616c87d709b3f418fb27468636877a11d0f0ad1
1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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.
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #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 #if __LP64__
50 #define LC_SEGMENT_COMMAND LC_SEGMENT_64
51 typedef struct segment_command_64 macho_segment_command;
52 typedef struct mach_header_64 macho_header;
53 typedef struct nlist_64 macho_nlist;
54 #else
55 #define LC_SEGMENT_COMMAND LC_SEGMENT
56 typedef struct segment_command macho_segment_command;
57 typedef struct mach_header macho_header;
58 typedef struct nlist macho_nlist;
59 #endif
60 #endif
62 // from _simple.h in libc
63 typedef struct _SIMPLE* _SIMPLE_STRING;
64 extern void _simple_vdprintf(int __fd, const char *__fmt, va_list __ap);
65 extern void _simple_dprintf(int __fd, const char *__fmt, ...);
66 extern _SIMPLE_STRING _simple_salloc(void);
67 extern int _simple_vsprintf(_SIMPLE_STRING __b, const char *__fmt, va_list __ap);
68 extern void _simple_sfree(_SIMPLE_STRING __b);
69 extern char * _simple_string(_SIMPLE_STRING __b);
71 // dyld::log(const char* format, ...)
72 extern void _ZN4dyld3logEPKcz(const char*, ...);
74 // dyld::halt(const char* msg);
75 extern void _ZN4dyld4haltEPKc(const char* msg) __attribute__((noreturn));
78 // abort called by C++ unwinding code
79 void abort()
81 _ZN4dyld4haltEPKc("dyld calling abort()\n");
84 // std::terminate called by C++ unwinding code
85 void _ZSt9terminatev()
87 _ZN4dyld4haltEPKc("dyld std::terminate()\n");
90 // std::unexpected called by C++ unwinding code
91 void _ZSt10unexpectedv()
93 _ZN4dyld4haltEPKc("dyld std::unexpected()\n");
96 // __cxxabiv1::__terminate(void (*)()) called to terminate process
97 void _ZN10__cxxabiv111__terminateEPFvvE()
99 _ZN4dyld4haltEPKc("dyld std::__terminate()\n");
102 // __cxxabiv1::__unexpected(void (*)()) called to terminate process
103 void _ZN10__cxxabiv112__unexpectedEPFvvE()
105 _ZN4dyld4haltEPKc("dyld std::__unexpected()\n");
108 // __cxxabiv1::__terminate_handler
109 void* _ZN10__cxxabiv119__terminate_handlerE = &_ZSt9terminatev;
111 // __cxxabiv1::__unexpected_handler
112 void* _ZN10__cxxabiv120__unexpected_handlerE = &_ZSt10unexpectedv;
114 // libc uses assert()
115 void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr)
117 if (func == NULL)
118 _ZN4dyld3logEPKcz("Assertion failed: (%s), file %s, line %d.\n", failedexpr, file, line);
119 else
120 _ZN4dyld3logEPKcz("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line);
121 abort();
125 int myfprintf(FILE* file, const char* format, ...) __asm("_fprintf");
127 // called by libuwind code before aborting
128 size_t fwrite(const void* ptr, size_t size, size_t nitme, FILE* stream)
130 return myfprintf(stream, "%s", (char*)ptr);
133 // called by libuwind code before aborting
134 int fprintf(FILE* file, const char* format, ...)
136 va_list list;
137 va_start(list, format);
138 _simple_vdprintf(STDERR_FILENO, format, list);
139 va_end(list);
140 return 0;
143 // called by LIBC_ABORT
144 void abort_report_np(const char* format, ...)
146 va_list list;
147 const char *str;
148 _SIMPLE_STRING s = _simple_salloc();
149 if ( s != NULL ) {
150 va_start(list, format);
151 _simple_vsprintf(s, format, list);
152 va_end(list);
153 str = _simple_string(s);
155 else {
156 // _simple_salloc failed, but at least format may have useful info by itself
157 str = format;
159 _ZN4dyld4haltEPKc(str);
160 // _ZN4dyld4haltEPKc doesn't return, so we can't call _simple_sfree
164 // real cthread_set_errno_self() has error handling that pulls in
165 // pthread_exit() which pulls in fprintf()
166 extern int* __error(void);
167 void cthread_set_errno_self(int err)
169 int* ep = __error();
170 *ep = err;
174 * We have our own localtime() to avoid needing the notify API which is used
175 * by the code in libc.a for localtime() which is used by arc4random().
177 struct tm* localtime(const time_t* t)
179 return (struct tm*)NULL;
182 // malloc calls exit(-1) in case of errors...
183 void exit(int x)
185 _ZN4dyld4haltEPKc("exit()");
188 // static initializers make calls to __cxa_atexit
189 void __cxa_atexit()
191 // do nothing, dyld never terminates
195 // The stack protector routines in lib.c bring in too much stuff, so
196 // make our own custom ones.
198 long __stack_chk_guard = 0;
201 void __guard_setup(const char* apple[])
203 for (const char** p = apple; *p != NULL; ++p) {
204 if ( strncmp(*p, "stack_guard=", 12) == 0 ) {
205 // kernel has provide a random value for us
206 for (const char* s = *p + 12; *s != '\0'; ++s) {
207 char c = *s;
208 long value = 0;
209 if ( (c >= 'a') && (c <= 'f') )
210 value = c - 'a' + 10;
211 else if ( (c >= 'A') && (c <= 'F') )
212 value = c - 'A' + 10;
213 else if ( (c >= '0') && (c <= '9') )
214 value = c - '0';
215 __stack_chk_guard <<= 4;
216 __stack_chk_guard |= value;
218 if ( __stack_chk_guard != 0 )
219 return;
222 #if !TARGET_IPHONE_SIMULATOR
223 #if __LP64__
224 __stack_chk_guard = ((long)arc4random() << 32) | arc4random();
225 #else
226 __stack_chk_guard = arc4random();
227 #endif
228 #endif
231 extern void _ZN4dyld4haltEPKc(const char*);
232 void __stack_chk_fail()
234 _ZN4dyld4haltEPKc("stack buffer overrun");
238 // std::_throw_bad_alloc()
239 void _ZSt17__throw_bad_allocv()
241 _ZN4dyld4haltEPKc("__throw_bad_alloc()");
244 // std::_throw_length_error(const char* x)
245 void _ZSt20__throw_length_errorPKc()
247 _ZN4dyld4haltEPKc("_throw_length_error()");
250 // the libc.a version of this drags in ASL
251 void __chk_fail()
253 _ZN4dyld4haltEPKc("__chk_fail()");
257 // referenced by libc.a(pthread.o) but unneeded in dyld
258 void _init_cpu_capabilities() { }
259 void _cpu_capabilities() {}
260 void set_malloc_singlethreaded() {}
261 int PR_5243343_flag = 0;
264 // used by some pthread routines
265 char* mach_error_string(mach_error_t err)
267 return (char *)"unknown error code";
269 char* mach_error_type(mach_error_t err)
271 return (char *)"(unknown/unknown)";
274 // _pthread_reap_thread calls fprintf(stderr).
275 // We map fprint to _simple_vdprintf and ignore FILE* stream, so ok for it to be NULL
276 FILE* __stderrp = NULL;
277 FILE* __stdoutp = NULL;
279 // work with c++abi.a
280 void (*__cxa_terminate_handler)() = _ZSt9terminatev;
281 void (*__cxa_unexpected_handler)() = _ZSt10unexpectedv;
283 void abort_message(const char* format, ...)
285 va_list list;
286 va_start(list, format);
287 _simple_vdprintf(STDERR_FILENO, format, list);
288 va_end(list);
291 void __cxa_bad_typeid()
293 _ZN4dyld4haltEPKc("__cxa_bad_typeid()");
296 // to work with libc++
297 void _ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv()
299 _ZN4dyld4haltEPKc("std::vector<>::_throw_length_error()");
302 // libc.a sometimes missing memset
303 #undef memset
304 void* memset(void* b, int c, size_t len)
306 uint8_t* p = (uint8_t*)b;
307 for(size_t i=len; i > 0; --i)
308 *p++ = c;
309 return b;
313 // <rdar://problem/10111032> wrap calls to stat() with check for EAGAIN
314 int _ZN4dyld7my_statEPKcP4stat(const char* path, struct stat* buf)
316 int result;
317 do {
318 result = stat(path, buf);
319 } while ((result == -1) && (errno == EAGAIN));
321 return result;
324 // <rdar://problem/13805025> dyld should retry open() if it gets an EGAIN
325 int _ZN4dyld7my_openEPKcii(const char* path, int flag, int other)
327 int result;
328 do {
329 result = open(path, flag, other);
330 } while ((result == -1) && (errno == EAGAIN));
332 return result;
337 // The dyld in the iOS simulator cannot do syscalls, so it calls back to
338 // host dyld.
341 #if TARGET_IPHONE_SIMULATOR
342 int myopen(const char* path, int oflag, int extra) __asm("_open");
343 int myopen(const char* path, int oflag, int extra) {
344 return gSyscallHelpers->open(path, oflag, extra);
347 int close(int fd) {
348 return gSyscallHelpers->close(fd);
351 ssize_t pread(int fd, void* buf, size_t nbytes, off_t offset) {
352 return gSyscallHelpers->pread(fd, buf , nbytes, offset);
355 ssize_t write(int fd, const void *buf, size_t nbytes) {
356 return gSyscallHelpers->write(fd, buf , nbytes);
359 void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset) {
360 return gSyscallHelpers->mmap(addr, len, prot, flags, fd, offset);
363 int munmap(void* addr, size_t len) {
364 return gSyscallHelpers->munmap(addr, len);
367 int madvise(void* addr, size_t len, int advice) {
368 return gSyscallHelpers->madvise(addr, len, advice);
371 int stat(const char* path, struct stat* buf) {
372 return gSyscallHelpers->stat(path, buf);
375 int myfcntl(int fd, int cmd, void* result) __asm("_fcntl");
376 int myfcntl(int fd, int cmd, void* result) {
377 return gSyscallHelpers->fcntl(fd, cmd, result);
380 int myioctl(int fd, unsigned long request, void* result) __asm("_ioctl");
381 int myioctl(int fd, unsigned long request, void* result) {
382 return gSyscallHelpers->ioctl(fd, request, result);
385 int issetugid() {
386 return gSyscallHelpers->issetugid();
389 char* getcwd(char* buf, size_t size) {
390 return gSyscallHelpers->getcwd(buf, size);
393 char* realpath(const char* file_name, char* resolved_name) {
394 return gSyscallHelpers->realpath(file_name, resolved_name);
399 kern_return_t vm_allocate(vm_map_t target_task, vm_address_t *address,
400 vm_size_t size, int flags) {
401 return gSyscallHelpers->vm_allocate(target_task, address, size, flags);
404 kern_return_t vm_deallocate(vm_map_t target_task, vm_address_t address,
405 vm_size_t size) {
406 return gSyscallHelpers->vm_deallocate(target_task, address, size);
409 kern_return_t vm_protect(vm_map_t target_task, vm_address_t address,
410 vm_size_t size, boolean_t max, vm_prot_t prot) {
411 return gSyscallHelpers->vm_protect(target_task, address, size, max, prot);
415 void _ZN4dyld3logEPKcz(const char* format, ...) {
416 va_list list;
417 va_start(list, format);
418 gSyscallHelpers->vlog(format, list);
419 va_end(list);
422 void _ZN4dyld4warnEPKcz(const char* format, ...) {
423 va_list list;
424 va_start(list, format);
425 gSyscallHelpers->vwarn(format, list);
426 va_end(list);
430 int pthread_mutex_lock(pthread_mutex_t* m) {
431 return gSyscallHelpers->pthread_mutex_lock(m);
434 int pthread_mutex_unlock(pthread_mutex_t* m) {
435 return gSyscallHelpers->pthread_mutex_unlock(m);
438 mach_port_t mach_thread_self() {
439 return gSyscallHelpers->mach_thread_self();
442 kern_return_t mach_port_deallocate(ipc_space_t task, mach_port_name_t name) {
443 return gSyscallHelpers->mach_port_deallocate(task, name);
446 mach_port_name_t task_self_trap() {
447 return gSyscallHelpers->task_self_trap();
450 kern_return_t mach_timebase_info(mach_timebase_info_t info) {
451 return gSyscallHelpers->mach_timebase_info(info);
454 bool OSAtomicCompareAndSwapPtrBarrier(void* old, void* new, void * volatile *value) {
455 return gSyscallHelpers->OSAtomicCompareAndSwapPtrBarrier(old, new, value);
458 void OSMemoryBarrier() {
459 return gSyscallHelpers->OSMemoryBarrier();
462 uint64_t mach_absolute_time(void) {
463 return gSyscallHelpers->mach_absolute_time();
466 DIR* opendir(const char* path) {
467 if ( gSyscallHelpers->version < 3 )
468 return NULL;
469 return gSyscallHelpers->opendir(path);
472 int readdir_r(DIR* dirp, struct dirent* entry, struct dirent **result) {
473 if ( gSyscallHelpers->version < 3 )
474 return EPERM;
475 return gSyscallHelpers->readdir_r(dirp, entry, result);
478 int closedir(DIR* dirp) {
479 if ( gSyscallHelpers->version < 3 )
480 return EPERM;
481 return gSyscallHelpers->closedir(dirp);
485 typedef void (*LoadFuncPtr)(void* shm, void* image, uint64_t timestamp);
486 typedef void (*UnloadFuncPtr)(void* shm, void* image);
488 static LoadFuncPtr sLoadPtr = NULL;
489 static UnloadFuncPtr sUnloadPtr = NULL;
491 // Lookup of coresymbolication functions in host dyld.
492 static void findCSProcs() {
493 struct dyld_all_image_infos* imageInfo = (struct dyld_all_image_infos*)(gSyscallHelpers->getProcessInfo());
494 const struct mach_header* hostDyldMH = imageInfo->dyldImageLoadAddress;
496 // find symbol table and slide of host dyld
497 uintptr_t slide = 0;
498 const macho_nlist* symbolTable = NULL;
499 const char* symbolTableStrings = NULL;
500 const struct dysymtab_command* dynSymbolTable = NULL;
501 const uint32_t cmd_count = hostDyldMH->ncmds;
502 const struct load_command* const cmds = (struct load_command*)(((char*)hostDyldMH)+sizeof(macho_header));
503 const struct load_command* cmd = cmds;
504 const uint8_t* linkEditBase = NULL;
505 for (uint32_t i = 0; i < cmd_count; ++i) {
506 switch (cmd->cmd) {
507 case LC_SEGMENT_COMMAND:
509 const macho_segment_command* seg = (macho_segment_command*)cmd;
510 if ( (seg->fileoff == 0) && (seg->filesize != 0) )
511 slide = (uintptr_t)hostDyldMH - seg->vmaddr;
512 if ( strcmp(seg->segname, "__LINKEDIT") == 0 )
513 linkEditBase = (uint8_t*)(seg->vmaddr - seg->fileoff + slide);
515 break;
516 case LC_SYMTAB:
518 const struct symtab_command* symtab = (struct symtab_command*)cmd;
519 if ( linkEditBase == NULL )
520 return;
521 symbolTableStrings = (const char*)&linkEditBase[symtab->stroff];
522 symbolTable = (macho_nlist*)(&linkEditBase[symtab->symoff]);
524 break;
525 case LC_DYSYMTAB:
526 dynSymbolTable = (struct dysymtab_command*)cmd;
527 break;
529 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize);
531 if ( symbolTableStrings == NULL )
532 return;
533 if ( dynSymbolTable == NULL )
534 return;
536 // scan local symbols in host dyld looking for load/unload functions
537 const macho_nlist* const localsStart = &symbolTable[dynSymbolTable->ilocalsym];
538 const macho_nlist* const localsEnd= &localsStart[dynSymbolTable->nlocalsym];
539 for (const macho_nlist* s = localsStart; s < localsEnd; ++s) {
540 if ( ((s->n_type & N_TYPE) == N_SECT) && ((s->n_type & N_STAB) == 0) ) {
541 const char* name = &symbolTableStrings[s->n_un.n_strx];
542 if ( strcmp(name, "__Z28coresymbolication_load_imageP25CSCppDyldSharedMemoryPagePK11ImageLoadery") == 0 )
543 sLoadPtr = (LoadFuncPtr)(s->n_value + slide);
544 else if ( strcmp(name, "__Z30coresymbolication_unload_imageP25CSCppDyldSharedMemoryPagePK11ImageLoader") == 0 )
545 sUnloadPtr = (UnloadFuncPtr)(s->n_value + slide);
550 //void coresymbolication_unload_image(void*, const ImageLoader*);
551 void _Z28coresymbolication_load_imagePvPK11ImageLoadery(void* shm, void* image, uint64_t time) {
552 // look up function in host dyld just once
553 if ( sLoadPtr == NULL )
554 findCSProcs();
555 if ( sLoadPtr != NULL )
556 (*sLoadPtr)(shm, image, time);
559 //void coresymbolication_load_image(void**, const ImageLoader*, uint64_t);
560 void _Z30coresymbolication_unload_imagePvPK11ImageLoader(void* shm, void* image) {
561 // look up function in host dyld just once
562 if ( sUnloadPtr == NULL )
563 findCSProcs();
564 if ( sUnloadPtr != NULL )
565 (*sUnloadPtr)(shm, image);
569 int* __error(void) {
570 return gSyscallHelpers->errnoAddress();
573 void mach_init() {
574 mach_task_self_ = task_self_trap();
575 //_task_reply_port = _mach_reply_port();
578 mach_port_t mach_task_self_ = MACH_PORT_NULL;
580 extern int myerrno_fallback __asm("_errno");
581 int myerrno_fallback = 0;
583 #endif // TARGET_IPHONE_SIMULATOR