]> git.saurik.com Git - apple/dyld.git/blob - src/glue.c
dyld-353.2.1.tar.gz
[apple/dyld.git] / src / glue.c
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
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);
70
71 // dyld::log(const char* format, ...)
72 extern void _ZN4dyld3logEPKcz(const char*, ...);
73
74 // dyld::halt(const char* msg);
75 extern void _ZN4dyld4haltEPKc(const char* msg) __attribute__((noreturn));
76
77
78 // abort called by C++ unwinding code
79 void abort()
80 {
81 _ZN4dyld4haltEPKc("dyld calling abort()\n");
82 }
83
84 // std::terminate called by C++ unwinding code
85 void _ZSt9terminatev()
86 {
87 _ZN4dyld4haltEPKc("dyld std::terminate()\n");
88 }
89
90 // std::unexpected called by C++ unwinding code
91 void _ZSt10unexpectedv()
92 {
93 _ZN4dyld4haltEPKc("dyld std::unexpected()\n");
94 }
95
96 // __cxxabiv1::__terminate(void (*)()) called to terminate process
97 void _ZN10__cxxabiv111__terminateEPFvvE()
98 {
99 _ZN4dyld4haltEPKc("dyld std::__terminate()\n");
100 }
101
102 // __cxxabiv1::__unexpected(void (*)()) called to terminate process
103 void _ZN10__cxxabiv112__unexpectedEPFvvE()
104 {
105 _ZN4dyld4haltEPKc("dyld std::__unexpected()\n");
106 }
107
108 // __cxxabiv1::__terminate_handler
109 void* _ZN10__cxxabiv119__terminate_handlerE = &_ZSt9terminatev;
110
111 // __cxxabiv1::__unexpected_handler
112 void* _ZN10__cxxabiv120__unexpected_handlerE = &_ZSt10unexpectedv;
113
114 // libc uses assert()
115 void __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
125 int myfprintf(FILE* file, const char* format, ...) __asm("_fprintf");
126
127 // called by libuwind code before aborting
128 size_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
134 int 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
144 void 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()
166 extern int* __error(void);
167 void 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 */
177 struct tm* localtime(const time_t* t)
178 {
179 return (struct tm*)NULL;
180 }
181
182 // malloc calls exit(-1) in case of errors...
183 void exit(int x)
184 {
185 _ZN4dyld4haltEPKc("exit()");
186 }
187
188 // static initializers make calls to __cxa_atexit
189 void __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 //
198 long __stack_chk_guard = 0;
199
200
201 void __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
231 extern void _ZN4dyld4haltEPKc(const char*);
232 void __stack_chk_fail()
233 {
234 _ZN4dyld4haltEPKc("stack buffer overrun");
235 }
236
237
238 // std::_throw_bad_alloc()
239 void _ZSt17__throw_bad_allocv()
240 {
241 _ZN4dyld4haltEPKc("__throw_bad_alloc()");
242 }
243
244 // std::_throw_length_error(const char* x)
245 void _ZSt20__throw_length_errorPKc()
246 {
247 _ZN4dyld4haltEPKc("_throw_length_error()");
248 }
249
250 // the libc.a version of this drags in ASL
251 void __chk_fail()
252 {
253 _ZN4dyld4haltEPKc("__chk_fail()");
254 }
255
256
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;
262
263
264 // used by some pthread routines
265 char* mach_error_string(mach_error_t err)
266 {
267 return (char *)"unknown error code";
268 }
269 char* 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
276 FILE* __stderrp = NULL;
277 FILE* __stdoutp = NULL;
278
279 // work with c++abi.a
280 void (*__cxa_terminate_handler)() = _ZSt9terminatev;
281 void (*__cxa_unexpected_handler)() = _ZSt10unexpectedv;
282
283 void 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
291 void __cxa_bad_typeid()
292 {
293 _ZN4dyld4haltEPKc("__cxa_bad_typeid()");
294 }
295
296 // to work with libc++
297 void _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
304 void* 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
314 int _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
325 int _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
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);
345 }
346
347 int close(int fd) {
348 return gSyscallHelpers->close(fd);
349 }
350
351 ssize_t pread(int fd, void* buf, size_t nbytes, off_t offset) {
352 return gSyscallHelpers->pread(fd, buf , nbytes, offset);
353 }
354
355 ssize_t write(int fd, const void *buf, size_t nbytes) {
356 return gSyscallHelpers->write(fd, buf , nbytes);
357 }
358
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);
361 }
362
363 int munmap(void* addr, size_t len) {
364 return gSyscallHelpers->munmap(addr, len);
365 }
366
367 int madvise(void* addr, size_t len, int advice) {
368 return gSyscallHelpers->madvise(addr, len, advice);
369 }
370
371 int stat(const char* path, struct stat* buf) {
372 return gSyscallHelpers->stat(path, buf);
373 }
374
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);
378 }
379
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);
383 }
384
385 int issetugid() {
386 return gSyscallHelpers->issetugid();
387 }
388
389 char* getcwd(char* buf, size_t size) {
390 return gSyscallHelpers->getcwd(buf, size);
391 }
392
393 char* realpath(const char* file_name, char* resolved_name) {
394 return gSyscallHelpers->realpath(file_name, resolved_name);
395 }
396
397
398
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);
402 }
403
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);
407 }
408
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);
412 }
413
414
415 void _ZN4dyld3logEPKcz(const char* format, ...) {
416 va_list list;
417 va_start(list, format);
418 gSyscallHelpers->vlog(format, list);
419 va_end(list);
420 }
421
422 void _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
430 int pthread_mutex_lock(pthread_mutex_t* m) {
431 return gSyscallHelpers->pthread_mutex_lock(m);
432 }
433
434 int pthread_mutex_unlock(pthread_mutex_t* m) {
435 return gSyscallHelpers->pthread_mutex_unlock(m);
436 }
437
438 mach_port_t mach_thread_self() {
439 return gSyscallHelpers->mach_thread_self();
440 }
441
442 kern_return_t mach_port_deallocate(ipc_space_t task, mach_port_name_t name) {
443 return gSyscallHelpers->mach_port_deallocate(task, name);
444 }
445
446 mach_port_name_t task_self_trap() {
447 return gSyscallHelpers->task_self_trap();
448 }
449
450 kern_return_t mach_timebase_info(mach_timebase_info_t info) {
451 return gSyscallHelpers->mach_timebase_info(info);
452 }
453
454 bool OSAtomicCompareAndSwapPtrBarrier(void* old, void* new, void * volatile *value) {
455 return gSyscallHelpers->OSAtomicCompareAndSwapPtrBarrier(old, new, value);
456 }
457
458 void OSMemoryBarrier() {
459 return gSyscallHelpers->OSMemoryBarrier();
460 }
461
462 uint64_t mach_absolute_time(void) {
463 return gSyscallHelpers->mach_absolute_time();
464 }
465
466 DIR* opendir(const char* path) {
467 if ( gSyscallHelpers->version < 3 )
468 return NULL;
469 return gSyscallHelpers->opendir(path);
470 }
471
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);
476 }
477
478 int closedir(DIR* dirp) {
479 if ( gSyscallHelpers->version < 3 )
480 return EPERM;
481 return gSyscallHelpers->closedir(dirp);
482 }
483
484
485 typedef void (*LoadFuncPtr)(void* shm, void* image, uint64_t timestamp);
486 typedef void (*UnloadFuncPtr)(void* shm, void* image);
487
488 static LoadFuncPtr sLoadPtr = NULL;
489 static UnloadFuncPtr sUnloadPtr = NULL;
490
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;
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*);
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);
557 }
558
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);
566 }
567
568
569 int* __error(void) {
570 return gSyscallHelpers->errnoAddress();
571 }
572
573 void mach_init() {
574 mach_task_self_ = task_self_trap();
575 //_task_reply_port = _mach_reply_port();
576 }
577
578 mach_port_t mach_task_self_ = MACH_PORT_NULL;
579
580 extern int myerrno_fallback __asm("_errno");
581 int myerrno_fallback = 0;
582
583 #endif // TARGET_IPHONE_SIMULATOR
584
585