]> git.saurik.com Git - apple/dyld.git/blame - src/glue.c
dyld-353.2.3.tar.gz
[apple/dyld.git] / src / glue.c
CommitLineData
0959b6d4
A
1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
412ebb8e 3 * Copyright (c) 2004-2010 Apple Inc. All rights reserved.
0959b6d4
A
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>
832b6fce 28#include <stdint.h>
0959b6d4 29#include <time.h>
2fd3f4e8 30#include <fcntl.h>
bac542e6 31#include <unistd.h>
39a8cd10
A
32#include <stdarg.h>
33#include <stdio.h>
2fd3f4e8
A
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"
19894a12
A
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
2fd3f4e8 60#endif
39a8cd10
A
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
0959b6d4 77
bac542e6
A
78// abort called by C++ unwinding code
79void abort()
39a8cd10
A
80{
81 _ZN4dyld4haltEPKc("dyld calling abort()\n");
0959b6d4
A
82}
83
bac542e6
A
84// std::terminate called by C++ unwinding code
85void _ZSt9terminatev()
0959b6d4 86{
39a8cd10 87 _ZN4dyld4haltEPKc("dyld std::terminate()\n");
0959b6d4
A
88}
89
bac542e6
A
90// std::unexpected called by C++ unwinding code
91void _ZSt10unexpectedv()
0959b6d4 92{
39a8cd10 93 _ZN4dyld4haltEPKc("dyld std::unexpected()\n");
0959b6d4
A
94}
95
bac542e6
A
96// __cxxabiv1::__terminate(void (*)()) called to terminate process
97void _ZN10__cxxabiv111__terminateEPFvvE()
0959b6d4 98{
39a8cd10 99 _ZN4dyld4haltEPKc("dyld std::__terminate()\n");
0959b6d4
A
100}
101
bac542e6
A
102// __cxxabiv1::__unexpected(void (*)()) called to terminate process
103void _ZN10__cxxabiv112__unexpectedEPFvvE()
0959b6d4 104{
39a8cd10 105 _ZN4dyld4haltEPKc("dyld std::__unexpected()\n");
0959b6d4
A
106}
107
bac542e6
A
108// __cxxabiv1::__terminate_handler
109void* _ZN10__cxxabiv119__terminate_handlerE = &_ZSt9terminatev;
0959b6d4 110
bac542e6
A
111// __cxxabiv1::__unexpected_handler
112void* _ZN10__cxxabiv120__unexpected_handlerE = &_ZSt10unexpectedv;
0959b6d4 113
39a8cd10
A
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
19894a12
A
125int myfprintf(FILE* file, const char* format, ...) __asm("_fprintf");
126
39a8cd10
A
127// called by libuwind code before aborting
128size_t fwrite(const void* ptr, size_t size, size_t nitme, FILE* stream)
129{
19894a12 130 return myfprintf(stream, "%s", (char*)ptr);
39a8cd10
A
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}
0959b6d4 142
39a8cd10
A
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}
a3afc008 162
bac542e6
A
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)
a3afc008 168{
bac542e6
A
169 int* ep = __error();
170 *ep = err;
0959b6d4
A
171}
172
173/*
174 * We have our own localtime() to avoid needing the notify API which is used
bac542e6 175 * by the code in libc.a for localtime() which is used by arc4random().
0959b6d4
A
176 */
177struct tm* localtime(const time_t* t)
178{
179 return (struct tm*)NULL;
180}
181
412ebb8e
A
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}
2de2b37b 193
39a8cd10
A
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;
2fd3f4e8
A
199
200
201void __guard_setup(const char* apple[])
39a8cd10 202{
412ebb8e
A
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 }
2fd3f4e8 222#if !TARGET_IPHONE_SIMULATOR
39a8cd10
A
223#if __LP64__
224 __stack_chk_guard = ((long)arc4random() << 32) | arc4random();
225#else
226 __stack_chk_guard = arc4random();
227#endif
2fd3f4e8 228#endif
39a8cd10 229}
2fd3f4e8 230
39a8cd10
A
231extern void _ZN4dyld4haltEPKc(const char*);
232void __stack_chk_fail()
233{
234 _ZN4dyld4haltEPKc("stack buffer overrun");
235}
236
237
412ebb8e
A
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
412ebb8e
A
276FILE* __stderrp = NULL;
277FILE* __stdoutp = NULL;
412ebb8e
A
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}
832b6fce
A
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
2fd3f4e8
A
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
19894a12
A
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
2fd3f4e8
A
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();
2fd3f4e8
A
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