Debugging: Add code to print backtrace for guest on SIGSEGV
[nativeclient.git] / service_runtime / nacl_syscall_hook.c
bloba5599592cd02ba953a04279bb0d1bb853a8d55f5
1 /*
2 * Copyright 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * NaCl service run-time.
36 #include "native_client/include/portability.h"
37 #include "native_client/include/nacl_platform.h"
39 #include <stdlib.h>
40 #include <errno.h>
41 #if NACL_WINDOWS
42 /* TODO: IS THIS STILL NEEDED FOR WINDOWS ??? */
43 #include <sys/timeb.h>
44 #endif
45 #include <fcntl.h>
46 #include <time.h>
48 #include "native_client/service_runtime/nacl_globals.h"
49 #include "native_client/service_runtime/nacl_config.h"
50 #include "native_client/service_runtime/nacl_log.h"
51 #include "native_client/service_runtime/nacl_switch_to_app.h"
52 #include "native_client/service_runtime/nacl_syscall_handlers.h"
53 #include "native_client/service_runtime/sel_ldr.h"
55 #include "native_client/service_runtime/include/sys/errno.h"
56 #include "native_client/service_runtime/include/bits/nacl_syscalls.h"
59 * Simple RPC support. The default socket file descriptor is invalid.
61 int NaClSrpcFileDescriptor = -1;
63 int NaClArtificialDelay = -1;
67 * The first syscall is from the NaCl module's main thread, and there
68 * are no other user threads yet, so NACLDELAY check and the NACLCLOCK
69 * usages are okay; when the NaCl module is multithreaded, the
70 * variables they initialize are read-only.
72 typedef uint64_t tick_t;
73 static tick_t get_ticks() {
74 tick_t t = 0;
75 #if NACL_WINDOWS
76 uint32_t t_high, t_low;
78 __asm rdtsc;
79 __asm mov t_high, edx;
80 __asm mov t_low, eax;
81 t = (((tick_t) t_high) << 32) | t_low;
82 #else
83 asm volatile("rdtsc" : "=A" (t));
84 #endif
85 return t;
88 void NaClMicroSleep(int microseconds)
90 static int initialized = 0;
91 static tick_t cpu_clock = 0;
92 tick_t now;
93 tick_t end;
95 if (!initialized) {
96 char *env = getenv("NACLCLOCK");
97 if (NULL != env) {
98 cpu_clock = strtoul(env, (char **) NULL, 0);
101 initialized = 1;
104 now = get_ticks();
105 end = now + (cpu_clock * microseconds) / 1000000;
106 NaClLog(5, "Now %"PRId64". Waiting until %lld.\n", now, end);
107 while (get_ticks() < end)
112 NORETURN void NaClSyscallCSegHook(int32_t ldt_ix)
114 struct NaClAppThread *natp = nacl_thread[ldt_ix];
115 struct NaClApp *nap = natp->nap;
116 struct NaClThreadContext *user = &natp->user;
117 uintptr_t tramp_addr;
118 uint32_t tramp_ret;
119 uint32_t aligned_tramp_ret;
120 uint32_t sysnum;
122 /* esp must be okay for control to have gotten here */
123 #if !BENCHMARK
124 NaClLog(4, "Entered NaClSyscallCSegHook\n");
125 NaClLog(4, "user esp 0x%08x\n", user->esp);
126 #endif
129 * on user stack:
130 * esp+0: retaddr from lcall
131 * esp+4: code seg from lcall
132 * esp+8: retaddr from syscall wrapper
133 * esp+c: ...
135 tramp_addr = NaClUserToSys(nap, user->esp);
136 tramp_ret = *(uint32_t *) tramp_addr;
138 * return addr could have been tampered with by another thread, but
139 * the only result would be a bad sysnum.
141 sysnum = (tramp_ret - NACL_SYSCALL_START_ADDR)
142 >> NACL_SYSCALL_BLOCK_SHIFT;
144 #if !BENCHMARK
145 NaClLog(4, "system call %d\n", sysnum);
146 #endif
148 * keep tramp_ret in user addr; do not bother to ensure tramp_addr +
149 * 8 is valid, since even if we loaded two NaClApps next to each
150 * other this would just load the trampoline code, or hit the
151 * inaccessible page for NULL pointer detection (once we get that
152 * implemented). if it is not a valid address, we would just crash.
154 tramp_ret = *(uint32_t *) (tramp_addr + 8);
155 if (0 != nap->xlate_base) {
157 * ensure that tramp_ret value is ok. no need to ensure that this
158 * is in the app's address space, since the syscall return will
159 * just result in a fault after we reconstitute the sandbox and
160 * attempt to pass control to this address.
162 aligned_tramp_ret = tramp_ret & ~(nap->align_boundary - 1);
163 if (tramp_ret != aligned_tramp_ret) {
164 NaClLog(LOG_FATAL, ("NaClSyscallCSegHook: tramp_ret infinite loop:"
165 " %08x != %08x\nMake sure NaCl SDK and sel_ldr"
166 " agree on alignment (ELF header of NaCl app"
167 " claims alignment is %d).\n"),
168 tramp_ret, aligned_tramp_ret, nap->align_boundary);
170 tramp_ret = aligned_tramp_ret;
173 user->esp += 0xc; /* call, lcall */
174 if (sysnum >= NACL_MAX_SYSCALLS) {
175 NaClLog(2, "INVALID system call %d\n", sysnum);
176 natp->sysret = -NACL_ABI_EINVAL;
177 } else {
178 #if !BENCHMARK
179 NaClLog(4, "making system call %d, handler 0x%08"PRIxPTR"\n",
180 sysnum, (uintptr_t) nacl_syscall[sysnum].handler);
181 #endif
183 natp->x_esp = (uint32_t *) (tramp_addr + 0xc);
184 natp->sysret = (*nacl_syscall[sysnum].handler)(natp);
186 #if !BENCHMARK
187 NaClLog(4,
188 ("returning from system call %d, return value %"PRId32
189 " (0x%"PRIx32")\n"),
190 sysnum, natp->sysret, natp->sysret);
192 NaClLog(4, "return target 0x%08"PRIx32"\n", tramp_ret);
193 NaClLog(4, "user esp 0x%08"PRIx32"\n", user->esp);
194 #endif
195 if (-1 == NaClArtificialDelay) {
196 char *delay = getenv("NACLDELAY");
197 if (NULL != delay) {
198 NaClArtificialDelay = strtol(delay, (char **) NULL, 0);
199 NaClLog(0, "ARTIFICIAL DELAY %d us\n", NaClArtificialDelay);
200 } else {
201 NaClArtificialDelay = 0;
204 if (0 != NaClArtificialDelay) {
205 NaClMicroSleep(NaClArtificialDelay);
207 NaClSwitchToApp(natp, tramp_ret);
208 /* NOTREACHED */
210 fprintf(stderr, "NORETURN NaClSwitchToApp returned!?!\n");
211 abort();