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