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