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#endif 47 48// from _simple.h in libc 49typedef struct _SIMPLE* _SIMPLE_STRING; 50extern void _simple_vdprintf(int __fd, const char *__fmt, va_list __ap); 51extern void _simple_dprintf(int __fd, const char *__fmt, ...); 52extern _SIMPLE_STRING _simple_salloc(void); 53extern int _simple_vsprintf(_SIMPLE_STRING __b, const char *__fmt, va_list __ap); 54extern void _simple_sfree(_SIMPLE_STRING __b); 55extern char * _simple_string(_SIMPLE_STRING __b); 56 57// dyld::log(const char* format, ...) 58extern void _ZN4dyld3logEPKcz(const char*, ...); 59 60// dyld::halt(const char* msg); 61extern void _ZN4dyld4haltEPKc(const char* msg) __attribute__((noreturn)); 62 63 64// abort called by C++ unwinding code 65void abort() 66{ 67 _ZN4dyld4haltEPKc("dyld calling abort()\n"); 68} 69 70// std::terminate called by C++ unwinding code 71void _ZSt9terminatev() 72{ 73 _ZN4dyld4haltEPKc("dyld std::terminate()\n"); 74} 75 76// std::unexpected called by C++ unwinding code 77void _ZSt10unexpectedv() 78{ 79 _ZN4dyld4haltEPKc("dyld std::unexpected()\n"); 80} 81 82// __cxxabiv1::__terminate(void (*)()) called to terminate process 83void _ZN10__cxxabiv111__terminateEPFvvE() 84{ 85 _ZN4dyld4haltEPKc("dyld std::__terminate()\n"); 86} 87 88// __cxxabiv1::__unexpected(void (*)()) called to terminate process 89void _ZN10__cxxabiv112__unexpectedEPFvvE() 90{ 91 _ZN4dyld4haltEPKc("dyld std::__unexpected()\n"); 92} 93 94// __cxxabiv1::__terminate_handler 95void* _ZN10__cxxabiv119__terminate_handlerE = &_ZSt9terminatev; 96 97// __cxxabiv1::__unexpected_handler 98void* _ZN10__cxxabiv120__unexpected_handlerE = &_ZSt10unexpectedv; 99 100// libc uses assert() 101void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr) 102{ 103 if (func == NULL) 104 _ZN4dyld3logEPKcz("Assertion failed: (%s), file %s, line %d.\n", failedexpr, file, line); 105 else 106 _ZN4dyld3logEPKcz("Assertion failed: (%s), function %s, file %s, line %d.\n", failedexpr, func, file, line); 107 abort(); 108} 109 110 111// called by libuwind code before aborting 112size_t fwrite(const void* ptr, size_t size, size_t nitme, FILE* stream) 113{ 114 return fprintf(stream, "%s", (char*)ptr); 115} 116 117// called by libuwind code before aborting 118int fprintf(FILE* file, const char* format, ...) 119{ 120 va_list list; 121 va_start(list, format); 122 _simple_vdprintf(STDERR_FILENO, format, list); 123 va_end(list); 124 return 0; 125} 126 127// called by LIBC_ABORT 128void abort_report_np(const char* format, ...) 129{ 130 va_list list; 131 const char *str; 132 _SIMPLE_STRING s = _simple_salloc(); 133 if ( s != NULL ) { 134 va_start(list, format); 135 _simple_vsprintf(s, format, list); 136 va_end(list); 137 str = _simple_string(s); 138 } 139 else { 140 // _simple_salloc failed, but at least format may have useful info by itself 141 str = format; 142 } 143 _ZN4dyld4haltEPKc(str); 144 // _ZN4dyld4haltEPKc doesn't return, so we can't call _simple_sfree 145} 146 147 148// real cthread_set_errno_self() has error handling that pulls in 149// pthread_exit() which pulls in fprintf() 150extern int* __error(void); 151void cthread_set_errno_self(int err) 152{ 153 int* ep = __error(); 154 *ep = err; 155} 156 157/* 158 * We have our own localtime() to avoid needing the notify API which is used 159 * by the code in libc.a for localtime() which is used by arc4random(). 160 */ 161struct tm* localtime(const time_t* t) 162{ 163 return (struct tm*)NULL; 164} 165 166// malloc calls exit(-1) in case of errors... 167void exit(int x) 168{ 169 _ZN4dyld4haltEPKc("exit()"); 170} 171 172// static initializers make calls to __cxa_atexit 173void __cxa_atexit() 174{ 175 // do nothing, dyld never terminates 176} 177 178// 179// The stack protector routines in lib.c bring in too much stuff, so 180// make our own custom ones. 181// 182long __stack_chk_guard = 0; 183 184 185void __guard_setup(const char* apple[]) 186{ 187 for (const char** p = apple; *p != NULL; ++p) { 188 if ( strncmp(*p, "stack_guard=", 12) == 0 ) { 189 // kernel has provide a random value for us 190 for (const char* s = *p + 12; *s != '\0'; ++s) { 191 char c = *s; 192 long value = 0; 193 if ( (c >= 'a') && (c <= 'f') ) 194 value = c - 'a' + 10; 195 else if ( (c >= 'A') && (c <= 'F') ) 196 value = c - 'A' + 10; 197 else if ( (c >= '0') && (c <= '9') ) 198 value = c - '0'; 199 __stack_chk_guard <<= 4; 200 __stack_chk_guard |= value; 201 } 202 if ( __stack_chk_guard != 0 ) 203 return; 204 } 205 } 206#if !TARGET_IPHONE_SIMULATOR 207#if __LP64__ 208 __stack_chk_guard = ((long)arc4random() << 32) | arc4random(); 209#else 210 __stack_chk_guard = arc4random(); 211#endif 212#endif 213} 214 215extern void _ZN4dyld4haltEPKc(const char*); 216void __stack_chk_fail() 217{ 218 _ZN4dyld4haltEPKc("stack buffer overrun"); 219} 220 221 222// std::_throw_bad_alloc() 223void _ZSt17__throw_bad_allocv() 224{ 225 _ZN4dyld4haltEPKc("__throw_bad_alloc()"); 226} 227 228// std::_throw_length_error(const char* x) 229void _ZSt20__throw_length_errorPKc() 230{ 231 _ZN4dyld4haltEPKc("_throw_length_error()"); 232} 233 234// the libc.a version of this drags in ASL 235void __chk_fail() 236{ 237 _ZN4dyld4haltEPKc("__chk_fail()"); 238} 239 240 241// referenced by libc.a(pthread.o) but unneeded in dyld 242void _init_cpu_capabilities() { } 243void _cpu_capabilities() {} 244void set_malloc_singlethreaded() {} 245int PR_5243343_flag = 0; 246 247 248// used by some pthread routines 249char* mach_error_string(mach_error_t err) 250{ 251 return (char *)"unknown error code"; 252} 253char* mach_error_type(mach_error_t err) 254{ 255 return (char *)"(unknown/unknown)"; 256} 257 258// _pthread_reap_thread calls fprintf(stderr). 259// We map fprint to _simple_vdprintf and ignore FILE* stream, so ok for it to be NULL 260FILE* __stderrp = NULL; 261FILE* __stdoutp = NULL; 262 263// work with c++abi.a 264void (*__cxa_terminate_handler)() = _ZSt9terminatev; 265void (*__cxa_unexpected_handler)() = _ZSt10unexpectedv; 266 267void abort_message(const char* format, ...) 268{ 269 va_list list; 270 va_start(list, format); 271 _simple_vdprintf(STDERR_FILENO, format, list); 272 va_end(list); 273} 274 275void __cxa_bad_typeid() 276{ 277 _ZN4dyld4haltEPKc("__cxa_bad_typeid()"); 278} 279 280// to work with libc++ 281void _ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv() 282{ 283 _ZN4dyld4haltEPKc("std::vector<>::_throw_length_error()"); 284} 285 286// libc.a sometimes missing memset 287#undef memset 288void* memset(void* b, int c, size_t len) 289{ 290 uint8_t* p = (uint8_t*)b; 291 for(size_t i=len; i > 0; --i) 292 *p++ = c; 293 return b; 294} 295 296 297// <rdar://problem/10111032> wrap calls to stat() with check for EAGAIN 298int _ZN4dyld7my_statEPKcP4stat(const char* path, struct stat* buf) 299{ 300 int result; 301 do { 302 result = stat(path, buf); 303 } while ((result == -1) && (errno == EAGAIN)); 304 305 return result; 306} 307 308// <rdar://problem/13805025> dyld should retry open() if it gets an EGAIN 309int _ZN4dyld7my_openEPKcii(const char* path, int flag, int other) 310{ 311 int result; 312 do { 313 result = open(path, flag, other); 314 } while ((result == -1) && (errno == EAGAIN)); 315 316 return result; 317} 318 319 320// 321// The dyld in the iOS simulator cannot do syscalls, so it calls back to 322// host dyld. 323// 324 325#if TARGET_IPHONE_SIMULATOR 326int myopen(const char* path, int oflag, int extra) __asm("_open"); 327int myopen(const char* path, int oflag, int extra) { 328 return gSyscallHelpers->open(path, oflag, extra); 329} 330 331int close(int fd) { 332 return gSyscallHelpers->close(fd); 333} 334 335ssize_t pread(int fd, void* buf, size_t nbytes, off_t offset) { 336 return gSyscallHelpers->pread(fd, buf , nbytes, offset); 337} 338 339ssize_t write(int fd, const void *buf, size_t nbytes) { 340 return gSyscallHelpers->write(fd, buf , nbytes); 341} 342 343void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset) { 344 return gSyscallHelpers->mmap(addr, len, prot, flags, fd, offset); 345} 346 347int munmap(void* addr, size_t len) { 348 return gSyscallHelpers->munmap(addr, len); 349} 350 351int madvise(void* addr, size_t len, int advice) { 352 return gSyscallHelpers->madvise(addr, len, advice); 353} 354 355int stat(const char* path, struct stat* buf) { 356 return gSyscallHelpers->stat(path, buf); 357} 358 359int myfcntl(int fd, int cmd, void* result) __asm("_fcntl"); 360int myfcntl(int fd, int cmd, void* result) { 361 return gSyscallHelpers->fcntl(fd, cmd, result); 362} 363 364int myioctl(int fd, unsigned long request, void* result) __asm("_ioctl"); 365int myioctl(int fd, unsigned long request, void* result) { 366 return gSyscallHelpers->ioctl(fd, request, result); 367} 368 369int issetugid() { 370 return gSyscallHelpers->issetugid(); 371} 372 373char* getcwd(char* buf, size_t size) { 374 return gSyscallHelpers->getcwd(buf, size); 375} 376 377char* realpath(const char* file_name, char* resolved_name) { 378 return gSyscallHelpers->realpath(file_name, resolved_name); 379} 380 381 382 383kern_return_t vm_allocate(vm_map_t target_task, vm_address_t *address, 384 vm_size_t size, int flags) { 385 return gSyscallHelpers->vm_allocate(target_task, address, size, flags); 386} 387 388kern_return_t vm_deallocate(vm_map_t target_task, vm_address_t address, 389 vm_size_t size) { 390 return gSyscallHelpers->vm_deallocate(target_task, address, size); 391} 392 393kern_return_t vm_protect(vm_map_t target_task, vm_address_t address, 394 vm_size_t size, boolean_t max, vm_prot_t prot) { 395 return gSyscallHelpers->vm_protect(target_task, address, size, max, prot); 396} 397 398 399void _ZN4dyld3logEPKcz(const char* format, ...) { 400 va_list list; 401 va_start(list, format); 402 gSyscallHelpers->vlog(format, list); 403 va_end(list); 404} 405 406void _ZN4dyld4warnEPKcz(const char* format, ...) { 407 va_list list; 408 va_start(list, format); 409 gSyscallHelpers->vwarn(format, list); 410 va_end(list); 411} 412 413 414int pthread_mutex_lock(pthread_mutex_t* m) { 415 return gSyscallHelpers->pthread_mutex_lock(m); 416} 417 418int pthread_mutex_unlock(pthread_mutex_t* m) { 419 return gSyscallHelpers->pthread_mutex_unlock(m); 420} 421 422mach_port_t mach_thread_self() { 423 return gSyscallHelpers->mach_thread_self(); 424} 425 426kern_return_t mach_port_deallocate(ipc_space_t task, mach_port_name_t name) { 427 return gSyscallHelpers->mach_port_deallocate(task, name); 428} 429 430mach_port_name_t task_self_trap() { 431 return gSyscallHelpers->task_self_trap(); 432} 433 434kern_return_t mach_timebase_info(mach_timebase_info_t info) { 435 return gSyscallHelpers->mach_timebase_info(info); 436} 437 438bool OSAtomicCompareAndSwapPtrBarrier(void* old, void* new, void * volatile *value) { 439 return gSyscallHelpers->OSAtomicCompareAndSwapPtrBarrier(old, new, value); 440} 441 442void OSMemoryBarrier() { 443 return gSyscallHelpers->OSMemoryBarrier(); 444} 445 446uint64_t mach_absolute_time(void) { 447 return gSyscallHelpers->mach_absolute_time(); 448} 449 450int* __error(void) { 451 return gSyscallHelpers->errnoAddress(); 452} 453 454void mach_init() { 455 mach_task_self_ = task_self_trap(); 456 //_task_reply_port = _mach_reply_port(); 457 458} 459 460mach_port_t mach_task_self_ = MACH_PORT_NULL; 461 462extern int myerrno_fallback __asm("_errno"); 463int myerrno_fallback = 0; 464 465#endif // TARGET_IPHONE_SIMULATOR 466 467 468