Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / native_client / tests / signal_handler_single_step / step_test_host.c
1 /*
2  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3  * Use of this source code is governed by a BSD-style license that can be
4  * found in the LICENSE file.
5  */
6
7 #include <stdarg.h>
8 #include <signal.h>
9
10 #include "native_client/src/shared/platform/nacl_check.h"
11 #include "native_client/src/shared/platform/nacl_exit.h"
12 #include "native_client/src/shared/platform/nacl_log.h"
13 #include "native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h"
14 #include "native_client/src/trusted/service_runtime/load_file.h"
15 #include "native_client/src/trusted/service_runtime/nacl_all_modules.h"
16 #include "native_client/src/trusted/service_runtime/nacl_app.h"
17 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
18 #include "native_client/src/trusted/service_runtime/nacl_copy.h"
19 #include "native_client/src/trusted/service_runtime/nacl_signal.h"
20 #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
21 #include "native_client/src/trusted/service_runtime/nacl_syscall_handlers.h"
22 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
23 #include "native_client/tests/signal_handler_single_step/step_test_common.h"
24 #include "native_client/tests/signal_handler_single_step/step_test_syscalls.h"
25
26
27 /*
28  * This test case checks that NaCl's Linux signal handler can be
29  * entered at any point during the context switches between trusted
30  * and untrusted code.
31  *
32  * In particular, this tests that the signal handler correctly
33  * restores %gs on x86-32.  This is tricky because NaCl's context
34  * switch code must set %cs and %gs separately, so there is a small
35  * window during which %gs is set to the untrusted-code value but %cs
36  * is not.  The signal handler needs to work at this point if we are
37  * to handle asynchronous signals correctly (such as for implementing
38  * thread suspension).
39  */
40
41 /* This should be at least 2 so that we test the syscall return path. */
42 static const int kNumberOfCallsToTest = 5;
43
44 static int g_call_count = 0;
45 static int g_in_untrusted_code = 0;
46 static int g_context_switch_count = 0;
47
48 static int g_instruction_count = 0;
49 static int g_instruction_byte_count = 0;
50 static int g_jump_count = 0;
51 static nacl_reg_t g_last_prog_ctr = 0;
52
53 static const char* g_description = NULL;
54
55
56 static void SignalSafePrintf(const char *format, ...) {
57   va_list args;
58   char buf[200];
59   int len;
60   va_start(args, format);
61   len = vsnprintf(buf, sizeof(buf), format, args);
62   va_end(args);
63   SignalSafeWrite(buf, len);
64 }
65
66 /*
67  * We use a custom NaCl syscall here partly because we need to avoid
68  * making any Linux syscalls while the trap flag is set.  On x86-32
69  * Linux, doing a syscall with the trap flag set will sometimes kill
70  * the process with SIGTRAP rather than entering the signal handler.
71  * This might be a kernel bug.  x86-64 processes do not have the same
72  * problem.
73  */
74 static int32_t TestSyscall(struct NaClAppThread *natp) {
75   NaClCopyDropLock(natp->nap);
76
77   /* Check that the trap flag has not been unset by anything unexpected. */
78   CHECK(GetTrapFlag());
79
80   if (++g_call_count == kNumberOfCallsToTest) {
81     UnsetTrapFlag();
82     NaClReportExitStatus(natp->nap, 0);
83     NaClAppThreadTeardown(natp);
84   }
85   return 0;
86 }
87
88 static void TrapSignalHandler(int signal,
89                               const struct NaClSignalContext *context,
90                               int is_untrusted) {
91   if (signal == SIGTRAP) {
92     g_instruction_count++;
93     /*
94      * This is a heuristic for detecting jumps, based on the maximum
95      * length of an x86 instruction being 15 bytes.  We would miss
96      * short forward jumps.
97      */
98     if (context->prog_ctr - g_last_prog_ctr > 15) {
99       g_jump_count++;
100     } else {
101       /* Measure total size of instructions, except for taken branches. */
102       g_instruction_byte_count += context->prog_ctr - g_last_prog_ctr;
103     }
104     g_last_prog_ctr = context->prog_ctr;
105
106     if (g_in_untrusted_code != is_untrusted) {
107       g_context_switch_count++;
108       g_in_untrusted_code = is_untrusted;
109
110       SignalSafePrintf("Switching to %s: since previous switch: "
111                        "%i instructions, %i instruction bytes, %i jumps\n",
112                        is_untrusted ? "untrusted" : "trusted",
113                        g_instruction_count,
114                        g_instruction_byte_count,
115                        g_jump_count);
116       if (is_untrusted && g_call_count == kNumberOfCallsToTest - 1) {
117         SignalSafePrintf("RESULT InstructionsPerSyscall: %s= "
118                          "%i count\n", g_description, g_instruction_count);
119         SignalSafePrintf("RESULT InstructionBytesPerSyscall: %s= "
120                          "%i count\n",
121                          g_description, g_instruction_byte_count);
122         SignalSafePrintf("RESULT JumpsPerSyscall: %s= "
123                          "%i count\n", g_description, g_jump_count);
124       }
125       g_instruction_count = 0;
126       g_instruction_byte_count = 0;
127       g_jump_count = 0;
128     }
129   } else {
130     SignalSafeLogStringLiteral("Error: Received unexpected signal\n");
131     _exit(1);
132   }
133 }
134
135 static void ThreadCreateHook(struct NaClAppThread *natp) {
136   UNREFERENCED_PARAMETER(natp);
137
138   SetTrapFlag();
139 }
140
141 static void ThreadExitHook(struct NaClAppThread *natp) {
142   UNREFERENCED_PARAMETER(natp);
143 }
144
145 static void ProcessExitHook(void) {
146 }
147
148 static const struct NaClDebugCallbacks debug_callbacks = {
149   ThreadCreateHook,
150   ThreadExitHook,
151   ProcessExitHook
152 };
153
154 int main(int argc, char **argv) {
155   struct NaClApp app;
156   struct NaClSyscallTableEntry syscall_table[NACL_MAX_SYSCALLS] = {{0}};
157   int index;
158   for (index = 0; index < NACL_MAX_SYSCALLS; index++) {
159     syscall_table[index].handler = NaClSysNotImplementedDecoder;
160   }
161   syscall_table[SINGLE_STEP_TEST_SYSCALL].handler = TestSyscall;
162
163   NaClAllModulesInit();
164
165   if (argc != 3) {
166     NaClLog(LOG_FATAL, "Expected 2 arguments: <executable filename> "
167                        "<description-string>\n");
168   }
169   g_description = argv[2];
170
171   CHECK(NaClAppWithSyscallTableCtor(&app, syscall_table));
172
173   app.debug_stub_callbacks = &debug_callbacks;
174   NaClSignalHandlerInit();
175   NaClSignalHandlerSet(TrapSignalHandler);
176
177   CHECK(NaClAppLoadFileFromFilename(&app, argv[1]) == LOAD_OK);
178   CHECK(NaClCreateMainThread(&app, 0, NULL, NULL));
179   CHECK(NaClWaitForMainThreadToExit(&app) == 0);
180
181   CHECK(!g_in_untrusted_code);
182   CHECK(g_context_switch_count == kNumberOfCallsToTest * 2);
183
184   /*
185    * Avoid calling exit() because it runs process-global destructors
186    * which might break code that is running in our unjoined threads.
187    */
188   NaClExit(0);
189   return 0;
190 }