1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef V8_TRAP_HANDLER_TRAP_HANDLER_H_
6 #define V8_TRAP_HANDLER_TRAP_HANDLER_H_
7
8 #include <stdint.h>
9 #include <stdlib.h>
10
11 #include <atomic>
12
13 #include "src/base/build_config.h"
14 #include "src/common/globals.h"
15 #include "src/flags/flags.h"
16
17 namespace v8 {
18 namespace internal {
19 namespace trap_handler {
20
21 // TODO(eholk): Support trap handlers on other platforms.
22 #if V8_TARGET_ARCH_X64 && V8_OS_LINUX && !V8_OS_ANDROID
23 #define V8_TRAP_HANDLER_SUPPORTED true
24 #elif V8_TARGET_ARCH_X64 && V8_OS_WIN
25 #define V8_TRAP_HANDLER_SUPPORTED true
26 #elif V8_TARGET_ARCH_X64 && V8_OS_MACOSX
27 #define V8_TRAP_HANDLER_SUPPORTED true
28 #elif V8_TARGET_ARCH_X64 && V8_OS_FREEBSD
29 #define V8_TRAP_HANDLER_SUPPORTED true
30 #else
31 #define V8_TRAP_HANDLER_SUPPORTED false
32 #endif
33
34 struct ProtectedInstructionData {
35 // The offset of this instruction from the start of its code object.
36 // Wasm code never grows larger than 2GB, so uint32_t is sufficient.
37 uint32_t instr_offset;
38
39 // The offset of the landing pad from the start of its code object.
40 //
41 // TODO(eholk): Using a single landing pad and store parameters here.
42 uint32_t landing_offset;
43 };
44
45 const int kInvalidIndex = -1;
46
47 /// Adds the handler data to the place where the trap handler will find it.
48 ///
49 /// This returns a number that can be used to identify the handler data to
50 /// ReleaseHandlerData, or -1 on failure.
51 int V8_EXPORT_PRIVATE RegisterHandlerData(
52 Address base, size_t size, size_t num_protected_instructions,
53 const ProtectedInstructionData* protected_instructions);
54
55 /// Removes the data from the master list and frees any memory, if necessary.
56 /// TODO(mtrofin): We can switch to using size_t for index and not need
57 /// kInvalidIndex.
58 void V8_EXPORT_PRIVATE ReleaseHandlerData(int index);
59
60 #if V8_OS_WIN
61 #define THREAD_LOCAL __declspec(thread)
62 #elif V8_OS_ANDROID
63 // TODO(eholk): fix this before enabling for trap handlers for Android.
64 #define THREAD_LOCAL
65 #else
66 #define THREAD_LOCAL __thread
67 #endif
68
69 // Initially false, set to true if when trap handlers are enabled. Never goes
70 // back to false then.
71 extern bool g_is_trap_handler_enabled;
72
73 // Initially true, set to false when either {IsTrapHandlerEnabled} or
74 // {EnableTrapHandler} is called to prevent calling {EnableTrapHandler}
75 // repeatedly, or after {IsTrapHandlerEnabled}. Needs to be atomic because
76 // {IsTrapHandlerEnabled} can be called from any thread. Updated using relaxed
77 // semantics, since it's not used for synchronization.
78 extern std::atomic<bool> g_can_enable_trap_handler;
79
80 // Enables trap handling for WebAssembly bounds checks.
81 //
82 // use_v8_handler indicates that V8 should install its own handler
83 // rather than relying on the embedder to do it.
84 V8_EXPORT_PRIVATE bool EnableTrapHandler(bool use_v8_handler);
85
IsTrapHandlerEnabled()86 inline bool IsTrapHandlerEnabled() {
87 DCHECK_IMPLIES(g_is_trap_handler_enabled, V8_TRAP_HANDLER_SUPPORTED);
88 // Disallow enabling the trap handler after retrieving the current value.
89 // Re-enabling them late can produce issues because code or objects might have
90 // been generated under the assumption that trap handlers are disabled.
91 // Note: We test before setting to avoid contention by an unconditional write.
92 if (g_can_enable_trap_handler.load(std::memory_order_relaxed)) {
93 g_can_enable_trap_handler.store(false, std::memory_order_relaxed);
94 }
95 return g_is_trap_handler_enabled;
96 }
97
98 extern THREAD_LOCAL int g_thread_in_wasm_code;
99
100 // Return the address of the thread-local {g_thread_in_wasm_code} variable. This
101 // pointer can be accessed and modified as long as the thread calling this
102 // function exists. Only use if from the same thread do avoid race conditions.
103 V8_NOINLINE V8_EXPORT_PRIVATE int* GetThreadInWasmThreadLocalAddress();
104
105 // On Windows, asan installs its own exception handler which maps shadow
106 // memory. Since our exception handler may be executed before the asan exception
107 // handler, we have to make sure that asan shadow memory is not accessed here.
IsThreadInWasm()108 DISABLE_ASAN inline bool IsThreadInWasm() { return g_thread_in_wasm_code; }
109
SetThreadInWasm()110 inline void SetThreadInWasm() {
111 if (IsTrapHandlerEnabled()) {
112 DCHECK(!IsThreadInWasm());
113 g_thread_in_wasm_code = true;
114 }
115 }
116
ClearThreadInWasm()117 inline void ClearThreadInWasm() {
118 if (IsTrapHandlerEnabled()) {
119 DCHECK(IsThreadInWasm());
120 g_thread_in_wasm_code = false;
121 }
122 }
123
124 bool RegisterDefaultTrapHandler();
125 V8_EXPORT_PRIVATE void RemoveTrapHandler();
126
127 size_t GetRecoveredTrapCount();
128
129 } // namespace trap_handler
130 } // namespace internal
131 } // namespace v8
132
133 #endif // V8_TRAP_HANDLER_TRAP_HANDLER_H_
134