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 #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 61 62// from _simple.h in libc 63typedef struct _SIMPLE* _SIMPLE_STRING; 64extern void _simple_vdprintf(int __fd, const char *__fmt, va_list __ap); 65extern void _simple_dprintf(int __fd, const char *__fmt, ...); 66extern _SIMPLE_STRING _simple_salloc(void); 67extern int _simple_vsprintf(_SIMPLE_STRING __b, const char *__fmt, va_list __ap); 68extern void _simple_sfree(_SIMPLE_STRING __b); 69extern char * _simple_string(_SIMPLE_STRING __b); 70 71// dyld::log(const char* format, ...) 72extern void _ZN4dyld3logEPKcz(const char*, ...); 73 74// dyld::halt(const char* msg); 75extern void _ZN4dyld4haltEPKc(const char* msg) __attribute__((noreturn)); 76 77 78// abort called by C++ unwinding code 79void abort() 80{ 81 _ZN4dyld4haltEPKc("dyld calling abort()\n"); 82} 83 84// std::terminate called by C++ unwinding code 85void _ZSt9terminatev() 86{ 87 _ZN4dyld4haltEPKc("dyld std::terminate()\n"); 88} 89 90// std::unexpected called by C++ unwinding code 91void _ZSt10unexpectedv() 92{ 93 _ZN4dyld4haltEPKc("dyld std::unexpected()\n"); 94} 95 96// __cxxabiv1::__terminate(void (*)()) called to terminate process 97void _ZN10__cxxabiv111__terminateEPFvvE() 98{ 99 _ZN4dyld4haltEPKc("dyld std::__terminate()\n"); 100} 101 102// __cxxabiv1::__unexpected(void (*)()) called to terminate process 103void _ZN10__cxxabiv112__unexpectedEPFvvE() 104{ 105 _ZN4dyld4haltEPKc("dyld std::__unexpected()\n"); 106} 107 108// __cxxabiv1::__terminate_handler 109void* _ZN10__cxxabiv119__terminate_handlerE = &_ZSt9terminatev; 110 111// __cxxabiv1::__unexpected_handler 112void* _ZN10__cxxabiv120__unexpected_handlerE = &_ZSt10unexpectedv; 113 114// libc uses assert() 115void __assert_rtn(const char* func, const char* file, int line, const char* failedexpr) 116{ 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(); 122} 123 124 125int myfprintf(FILE* file, const char* format, ...) __asm("_fprintf"); 126 127// called by libuwind code before aborting 128size_t fwrite(const void* ptr, size_t size, size_t nitme, FILE* stream) 129{ 130 return myfprintf(stream, "%s", (char*)ptr); 131} 132 133// called by libuwind code before aborting 134int fprintf(FILE* file, const char* format, ...) 135{ 136 va_list list; 137 va_start(list, format); 138 _simple_vdprintf(STDERR_FILENO, format, list); 139 va_end(list); 140 return 0; 141} 142 143// called by LIBC_ABORT 144void abort_report_np(const char* format, ...) 145{ 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); 154 } 155 else { 156 // _simple_salloc failed, but at least format may have useful info by itself 157 str = format; 158 } 159 _ZN4dyld4haltEPKc(str); 160 // _ZN4dyld4haltEPKc doesn't return, so we can't call _simple_sfree 161} 162 163 164// real cthread_set_errno_self() has error handling that pulls in 165// pthread_exit() which pulls in fprintf() 166extern int* __error(void); 167void cthread_set_errno_self(int err) 168{ 169 int* ep = __error(); 170 *ep = err; 171} 172 173/* 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(). 176 */ 177struct tm* localtime(const time_t* t) 178{ 179 return (struct tm*)NULL; 180} 181 182// malloc calls exit(-1) in case of errors... 183void exit(int x) 184{ 185 _ZN4dyld4haltEPKc("exit()"); 186} 187 188// static initializers make calls to __cxa_atexit 189void __cxa_atexit() 190{ 191 // do nothing, dyld never terminates 192} 193 194// 195// The stack protector routines in lib.c bring in too much stuff, so 196// make our own custom ones. 197// 198long __stack_chk_guard = 0; 199 200 201void __guard_setup(const char* apple[]) 202{ 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; 217 } 218 if ( __stack_chk_guard != 0 ) 219 return; 220 } 221 } 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 229} 230 231extern void _ZN4dyld4haltEPKc(const char*); 232void __stack_chk_fail() 233{ 234 _ZN4dyld4haltEPKc("stack buffer overrun"); 235} 236 237 238// std::_throw_bad_alloc() 239void _ZSt17__throw_bad_allocv() 240{ 241 _ZN4dyld4haltEPKc("__throw_bad_alloc()"); 242} 243 244// std::_throw_length_error(const char* x) 245void _ZSt20__throw_length_errorPKc() 246{ 247 _ZN4dyld4haltEPKc("_throw_length_error()"); 248} 249 250// the libc.a version of this drags in ASL 251void __chk_fail() 252{ 253 _ZN4dyld4haltEPKc("__chk_fail()"); 254} 255 256 257// referenced by libc.a(pthread.o) but unneeded in dyld 258void _init_cpu_capabilities() { } 259void _cpu_capabilities() {} 260void set_malloc_singlethreaded() {} 261int PR_5243343_flag = 0; 262 263 264// used by some pthread routines 265char* mach_error_string(mach_error_t err) 266{ 267 return (char *)"unknown error code"; 268} 269char* mach_error_type(mach_error_t err) 270{ 271 return (char *)"(unknown/unknown)"; 272} 273 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 276FILE* __stderrp = NULL; 277FILE* __stdoutp = NULL; 278 279// work with c++abi.a 280void (*__cxa_terminate_handler)() = _ZSt9terminatev; 281void (*__cxa_unexpected_handler)() = _ZSt10unexpectedv; 282 283void abort_message(const char* format, ...) 284{ 285 va_list list; 286 va_start(list, format); 287 _simple_vdprintf(STDERR_FILENO, format, list); 288 va_end(list); 289} 290 291void __cxa_bad_typeid() 292{ 293 _ZN4dyld4haltEPKc("__cxa_bad_typeid()"); 294} 295 296// to work with libc++ 297void _ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv() 298{ 299 _ZN4dyld4haltEPKc("std::vector<>::_throw_length_error()"); 300} 301 302// libc.a sometimes missing memset 303#undef memset 304void* memset(void* b, int c, size_t len) 305{ 306 uint8_t* p = (uint8_t*)b; 307 for(size_t i=len; i > 0; --i) 308 *p++ = c; 309 return b; 310} 311 312 313// <rdar://problem/10111032> wrap calls to stat() with check for EAGAIN 314int _ZN4dyld7my_statEPKcP4stat(const char* path, struct stat* buf) 315{ 316 int result; 317 do { 318 result = stat(path, buf); 319 } while ((result == -1) && (errno == EAGAIN)); 320 321 return result; 322} 323 324// <rdar://problem/13805025> dyld should retry open() if it gets an EGAIN 325int _ZN4dyld7my_openEPKcii(const char* path, int flag, int other) 326{ 327 int result; 328 do { 329 result = open(path, flag, other); 330 } while ((result == -1) && (errno == EAGAIN)); 331 332 return result; 333} 334 335 336// 337// The dyld in the iOS simulator cannot do syscalls, so it calls back to 338// host dyld. 339// 340 341#if TARGET_IPHONE_SIMULATOR 342int myopen(const char* path, int oflag, int extra) __asm("_open"); 343int myopen(const char* path, int oflag, int extra) { 344 return gSyscallHelpers->open(path, oflag, extra); 345} 346 347int close(int fd) { 348 return gSyscallHelpers->close(fd); 349} 350 351ssize_t pread(int fd, void* buf, size_t nbytes, off_t offset) { 352 return gSyscallHelpers->pread(fd, buf , nbytes, offset); 353} 354 355ssize_t write(int fd, const void *buf, size_t nbytes) { 356 return gSyscallHelpers->write(fd, buf , nbytes); 357} 358 359void* 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); 361} 362 363int munmap(void* addr, size_t len) { 364 return gSyscallHelpers->munmap(addr, len); 365} 366 367int madvise(void* addr, size_t len, int advice) { 368 return gSyscallHelpers->madvise(addr, len, advice); 369} 370 371int stat(const char* path, struct stat* buf) { 372 return gSyscallHelpers->stat(path, buf); 373} 374 375int myfcntl(int fd, int cmd, void* result) __asm("_fcntl"); 376int myfcntl(int fd, int cmd, void* result) { 377 return gSyscallHelpers->fcntl(fd, cmd, result); 378} 379 380int myioctl(int fd, unsigned long request, void* result) __asm("_ioctl"); 381int myioctl(int fd, unsigned long request, void* result) { 382 return gSyscallHelpers->ioctl(fd, request, result); 383} 384 385int issetugid() { 386 return gSyscallHelpers->issetugid(); 387} 388 389char* getcwd(char* buf, size_t size) { 390 return gSyscallHelpers->getcwd(buf, size); 391} 392 393char* realpath(const char* file_name, char* resolved_name) { 394 return gSyscallHelpers->realpath(file_name, resolved_name); 395} 396 397 398 399kern_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); 402} 403 404kern_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); 407} 408 409kern_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); 412} 413 414 415void _ZN4dyld3logEPKcz(const char* format, ...) { 416 va_list list; 417 va_start(list, format); 418 gSyscallHelpers->vlog(format, list); 419 va_end(list); 420} 421 422void _ZN4dyld4warnEPKcz(const char* format, ...) { 423 va_list list; 424 va_start(list, format); 425 gSyscallHelpers->vwarn(format, list); 426 va_end(list); 427} 428 429 430int pthread_mutex_lock(pthread_mutex_t* m) { 431 return gSyscallHelpers->pthread_mutex_lock(m); 432} 433 434int pthread_mutex_unlock(pthread_mutex_t* m) { 435 return gSyscallHelpers->pthread_mutex_unlock(m); 436} 437 438mach_port_t mach_thread_self() { 439 return gSyscallHelpers->mach_thread_self(); 440} 441 442kern_return_t mach_port_deallocate(ipc_space_t task, mach_port_name_t name) { 443 return gSyscallHelpers->mach_port_deallocate(task, name); 444} 445 446mach_port_name_t task_self_trap() { 447 return gSyscallHelpers->task_self_trap(); 448} 449 450kern_return_t mach_timebase_info(mach_timebase_info_t info) { 451 return gSyscallHelpers->mach_timebase_info(info); 452} 453 454bool OSAtomicCompareAndSwapPtrBarrier(void* old, void* new, void * volatile *value) { 455 return gSyscallHelpers->OSAtomicCompareAndSwapPtrBarrier(old, new, value); 456} 457 458void OSMemoryBarrier() { 459 return gSyscallHelpers->OSMemoryBarrier(); 460} 461 462uint64_t mach_absolute_time(void) { 463 return gSyscallHelpers->mach_absolute_time(); 464} 465 466DIR* opendir(const char* path) { 467 if ( gSyscallHelpers->version < 3 ) 468 return NULL; 469 return gSyscallHelpers->opendir(path); 470} 471 472int 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); 476} 477 478int closedir(DIR* dirp) { 479 if ( gSyscallHelpers->version < 3 ) 480 return EPERM; 481 return gSyscallHelpers->closedir(dirp); 482} 483 484 485typedef void (*LoadFuncPtr)(void* shm, void* image, uint64_t timestamp); 486typedef void (*UnloadFuncPtr)(void* shm, void* image); 487 488static LoadFuncPtr sLoadPtr = NULL; 489static UnloadFuncPtr sUnloadPtr = NULL; 490 491// Lookup of coresymbolication functions in host dyld. 492static void findCSProcs() { 493 struct dyld_all_image_infos* imageInfo = (struct dyld_all_image_infos*)(gSyscallHelpers->getProcessInfo()); 494 const struct mach_header* hostDyldMH = imageInfo->dyldImageLoadAddress; 495 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: 508 { 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); 514 } 515 break; 516 case LC_SYMTAB: 517 { 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]); 523 } 524 break; 525 case LC_DYSYMTAB: 526 dynSymbolTable = (struct dysymtab_command*)cmd; 527 break; 528 } 529 cmd = (const struct load_command*)(((char*)cmd)+cmd->cmdsize); 530 } 531 if ( symbolTableStrings == NULL ) 532 return; 533 if ( dynSymbolTable == NULL ) 534 return; 535 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); 546 } 547 } 548} 549 550//void coresymbolication_unload_image(void*, const ImageLoader*); 551void _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); 557} 558 559//void coresymbolication_load_image(void**, const ImageLoader*, uint64_t); 560void _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); 566} 567 568 569int* __error(void) { 570 return gSyscallHelpers->errnoAddress(); 571} 572 573void mach_init() { 574 mach_task_self_ = task_self_trap(); 575 //_task_reply_port = _mach_reply_port(); 576} 577 578mach_port_t mach_task_self_ = MACH_PORT_NULL; 579 580extern int myerrno_fallback __asm("_errno"); 581int myerrno_fallback = 0; 582 583#endif // TARGET_IPHONE_SIMULATOR 584 585 586