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 "include/v8config.h"
14 #include "src/base/immediate-crash.h"
15
16 namespace v8 {
17 namespace internal {
18 namespace trap_handler {
19
20 // X64 on Linux, Windows, MacOS, FreeBSD.
21 #if V8_HOST_ARCH_X64 && V8_TARGET_ARCH_X64 && \
22 ((V8_OS_LINUX && !V8_OS_ANDROID) || V8_OS_WIN || V8_OS_DARWIN || \
23 V8_OS_FREEBSD)
24 #define V8_TRAP_HANDLER_SUPPORTED true
25 // Arm64 (non-simulator) on Mac.
26 #elif V8_TARGET_ARCH_ARM64 && V8_HOST_ARCH_ARM64 && V8_OS_DARWIN
27 #define V8_TRAP_HANDLER_SUPPORTED true
28 // Arm64 simulator on x64 on Linux, Mac, or Windows.
29 #elif V8_TARGET_ARCH_ARM64 && V8_HOST_ARCH_X64 && \
30 (V8_OS_LINUX || V8_OS_DARWIN)
31 #define V8_TRAP_HANDLER_VIA_SIMULATOR
32 #define V8_TRAP_HANDLER_SUPPORTED true
33 // Everything else is unsupported.
34 #else
35 #define V8_TRAP_HANDLER_SUPPORTED false
36 #endif
37
38 // Setup for shared library export.
39 #if defined(BUILDING_V8_SHARED) && defined(V8_OS_WIN)
40 #define TH_EXPORT_PRIVATE __declspec(dllexport)
41 #elif defined(BUILDING_V8_SHARED)
42 #define TH_EXPORT_PRIVATE __attribute__((visibility("default")))
43 #elif defined(USING_V8_SHARED) && defined(V8_OS_WIN)
44 #define TH_EXPORT_PRIVATE __declspec(dllimport)
45 #else
46 #define TH_EXPORT_PRIVATE
47 #endif
48
49 #define TH_CHECK(condition) \
50 if (!(condition)) IMMEDIATE_CRASH();
51 #ifdef DEBUG
52 #define TH_DCHECK(condition) TH_CHECK(condition)
53 #else
54 #define TH_DCHECK(condition) void(0)
55 #endif
56
57 #if defined(__has_feature)
58 #if __has_feature(address_sanitizer)
59 #define TH_DISABLE_ASAN __attribute__((no_sanitize_address))
60 #else
61 #define TH_DISABLE_ASAN
62 #endif
63 #else
64 #define TH_DISABLE_ASAN
65 #endif
66
67 struct ProtectedInstructionData {
68 // The offset of this instruction from the start of its code object.
69 // Wasm code never grows larger than 2GB, so uint32_t is sufficient.
70 uint32_t instr_offset;
71
72 // The offset of the landing pad from the start of its code object.
73 //
74 // TODO(eholk): Using a single landing pad and store parameters here.
75 uint32_t landing_offset;
76 };
77
78 const int kInvalidIndex = -1;
79
80 /// Adds the handler data to the place where the trap handler will find it.
81 ///
82 /// This returns a number that can be used to identify the handler data to
83 /// ReleaseHandlerData, or -1 on failure.
84 int TH_EXPORT_PRIVATE RegisterHandlerData(
85 uintptr_t base, size_t size, size_t num_protected_instructions,
86 const ProtectedInstructionData* protected_instructions);
87
88 /// Removes the data from the master list and frees any memory, if necessary.
89 /// TODO(mtrofin): We can switch to using size_t for index and not need
90 /// kInvalidIndex.
91 void TH_EXPORT_PRIVATE ReleaseHandlerData(int index);
92
93 // Initially false, set to true if when trap handlers are enabled. Never goes
94 // back to false then.
95 extern bool g_is_trap_handler_enabled;
96
97 // Initially true, set to false when either {IsTrapHandlerEnabled} or
98 // {EnableTrapHandler} is called to prevent calling {EnableTrapHandler}
99 // repeatedly, or after {IsTrapHandlerEnabled}. Needs to be atomic because
100 // {IsTrapHandlerEnabled} can be called from any thread. Updated using relaxed
101 // semantics, since it's not used for synchronization.
102 extern std::atomic<bool> g_can_enable_trap_handler;
103
104 // Enables trap handling for WebAssembly bounds checks.
105 //
106 // use_v8_handler indicates that V8 should install its own handler
107 // rather than relying on the embedder to do it.
108 TH_EXPORT_PRIVATE bool EnableTrapHandler(bool use_v8_handler);
109
IsTrapHandlerEnabled()110 inline bool IsTrapHandlerEnabled() {
111 TH_DCHECK(!g_is_trap_handler_enabled || V8_TRAP_HANDLER_SUPPORTED);
112 // Disallow enabling the trap handler after retrieving the current value.
113 // Re-enabling them late can produce issues because code or objects might have
114 // been generated under the assumption that trap handlers are disabled.
115 // Note: We test before setting to avoid contention by an unconditional write.
116 if (g_can_enable_trap_handler.load(std::memory_order_relaxed)) {
117 g_can_enable_trap_handler.store(false, std::memory_order_relaxed);
118 }
119 return g_is_trap_handler_enabled;
120 }
121
122 #if defined(V8_OS_AIX)
123 // `thread_local` does not link on AIX:
124 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100641
125 extern __thread int g_thread_in_wasm_code;
126 #else
127 extern thread_local int g_thread_in_wasm_code;
128 #endif
129
130 // Return the address of the thread-local {g_thread_in_wasm_code} variable. This
131 // pointer can be accessed and modified as long as the thread calling this
132 // function exists. Only use if from the same thread do avoid race conditions.
133 V8_NOINLINE TH_EXPORT_PRIVATE int* GetThreadInWasmThreadLocalAddress();
134
135 // On Windows, asan installs its own exception handler which maps shadow
136 // memory. Since our exception handler may be executed before the asan exception
137 // handler, we have to make sure that asan shadow memory is not accessed here.
IsThreadInWasm()138 TH_DISABLE_ASAN inline bool IsThreadInWasm() { return g_thread_in_wasm_code; }
139
SetThreadInWasm()140 inline void SetThreadInWasm() {
141 if (IsTrapHandlerEnabled()) {
142 TH_DCHECK(!IsThreadInWasm());
143 g_thread_in_wasm_code = true;
144 }
145 }
146
ClearThreadInWasm()147 inline void ClearThreadInWasm() {
148 if (IsTrapHandlerEnabled()) {
149 TH_DCHECK(IsThreadInWasm());
150 g_thread_in_wasm_code = false;
151 }
152 }
153
154 bool RegisterDefaultTrapHandler();
155 TH_EXPORT_PRIVATE void RemoveTrapHandler();
156
157 TH_EXPORT_PRIVATE size_t GetRecoveredTrapCount();
158
159 } // namespace trap_handler
160 } // namespace internal
161 } // namespace v8
162
163 #endif // V8_TRAP_HANDLER_TRAP_HANDLER_H_
164