WasmSignalHandlers.cpp (37679B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * 4 * Copyright 2014 Mozilla Foundation 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 #include "wasm/WasmSignalHandlers.h" 20 21 #include "mozilla/Casting.h" 22 #include "mozilla/ThreadLocal.h" 23 24 #include "threading/Thread.h" 25 #include "vm/JitActivation.h" // js::jit::JitActivation 26 #include "vm/Realm.h" 27 #include "vm/Runtime.h" 28 #include "wasm/WasmCode.h" 29 #include "wasm/WasmInstance.h" 30 31 #if defined(XP_WIN) 32 # include <winternl.h> // must include before util/WindowsWrapper.h's `#undef`s 33 # include "util/WindowsWrapper.h" 34 #elif defined(XP_DARWIN) 35 # include <mach/exc.h> 36 # include <mach/mach.h> 37 #elif !defined(__wasi__) 38 # include <signal.h> 39 #endif 40 41 using namespace js; 42 using namespace js::wasm; 43 44 #if !defined(JS_CODEGEN_NONE) 45 46 // ============================================================================= 47 // This following pile of macros and includes defines the ToRegisterState() and 48 // the ContextTo{PC,FP,SP,LR}() functions from the (highly) platform-specific 49 // CONTEXT struct which is provided to the signal handler. 50 // ============================================================================= 51 52 # if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 53 # include <sys/ucontext.h> // for ucontext_t, mcontext_t 54 # endif 55 56 # if defined(__x86_64__) 57 # if defined(__DragonFly__) 58 # include <machine/npx.h> // for union savefpu 59 # elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \ 60 defined(__NetBSD__) || defined(__OpenBSD__) 61 # include <machine/fpu.h> // for struct savefpu/fxsave64 62 # endif 63 # endif 64 65 # if defined(XP_WIN) 66 # define EIP_sig(p) ((p)->Eip) 67 # define EBP_sig(p) ((p)->Ebp) 68 # define ESP_sig(p) ((p)->Esp) 69 # define RIP_sig(p) ((p)->Rip) 70 # define RSP_sig(p) ((p)->Rsp) 71 # define RBP_sig(p) ((p)->Rbp) 72 # define R11_sig(p) ((p)->R11) 73 # define R13_sig(p) ((p)->R13) 74 # define R14_sig(p) ((p)->R14) 75 # define R15_sig(p) ((p)->R15) 76 # define EPC_sig(p) ((p)->Pc) 77 # define RFP_sig(p) ((p)->Fp) 78 # define R31_sig(p) ((p)->Sp) 79 # define RLR_sig(p) ((p)->Lr) 80 # elif defined(__OpenBSD__) 81 # define EIP_sig(p) ((p)->sc_eip) 82 # define EBP_sig(p) ((p)->sc_ebp) 83 # define ESP_sig(p) ((p)->sc_esp) 84 # define RIP_sig(p) ((p)->sc_rip) 85 # define RSP_sig(p) ((p)->sc_rsp) 86 # define RBP_sig(p) ((p)->sc_rbp) 87 # define R11_sig(p) ((p)->sc_r11) 88 # if defined(__arm__) 89 # define R13_sig(p) ((p)->sc_usr_sp) 90 # define R14_sig(p) ((p)->sc_usr_lr) 91 # define R15_sig(p) ((p)->sc_pc) 92 # else 93 # define R13_sig(p) ((p)->sc_r13) 94 # define R14_sig(p) ((p)->sc_r14) 95 # define R15_sig(p) ((p)->sc_r15) 96 # endif 97 # if defined(__aarch64__) 98 # define EPC_sig(p) ((p)->sc_elr) 99 # define RFP_sig(p) ((p)->sc_x[29]) 100 # define RLR_sig(p) ((p)->sc_lr) 101 # define R31_sig(p) ((p)->sc_sp) 102 # endif 103 # if defined(__riscv) 104 # define RPC_sig(p) ((p)->sc_sepc) 105 # define RRA_sig(p) ((p)->sc_ra) 106 # define RFP_sig(p) ((p)->sc_s[0]) 107 # define R02_sig(p) ((p)->sc_sp) 108 # endif 109 # if defined(__mips__) 110 # define EPC_sig(p) ((p)->sc_pc) 111 # define RFP_sig(p) ((p)->sc_regs[30]) 112 # endif 113 # if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \ 114 defined(__PPC64LE__) 115 # define R01_sig(p) ((p)->sc_frame.fixreg[1]) 116 # define R32_sig(p) ((p)->sc_frame.srr0) 117 # endif 118 # elif defined(__linux__) || defined(__sun) 119 # if defined(__linux__) 120 # define EIP_sig(p) ((p)->uc_mcontext.gregs[REG_EIP]) 121 # define EBP_sig(p) ((p)->uc_mcontext.gregs[REG_EBP]) 122 # define ESP_sig(p) ((p)->uc_mcontext.gregs[REG_ESP]) 123 # else 124 # define EIP_sig(p) ((p)->uc_mcontext.gregs[REG_PC]) 125 # define EBP_sig(p) ((p)->uc_mcontext.gregs[REG_EBP]) 126 # define ESP_sig(p) ((p)->uc_mcontext.gregs[REG_ESP]) 127 # endif 128 # define RIP_sig(p) ((p)->uc_mcontext.gregs[REG_RIP]) 129 # define RSP_sig(p) ((p)->uc_mcontext.gregs[REG_RSP]) 130 # define RBP_sig(p) ((p)->uc_mcontext.gregs[REG_RBP]) 131 # if defined(__linux__) && defined(__arm__) 132 # define R11_sig(p) ((p)->uc_mcontext.arm_fp) 133 # define R13_sig(p) ((p)->uc_mcontext.arm_sp) 134 # define R14_sig(p) ((p)->uc_mcontext.arm_lr) 135 # define R15_sig(p) ((p)->uc_mcontext.arm_pc) 136 # else 137 # define R11_sig(p) ((p)->uc_mcontext.gregs[REG_R11]) 138 # define R13_sig(p) ((p)->uc_mcontext.gregs[REG_R13]) 139 # define R14_sig(p) ((p)->uc_mcontext.gregs[REG_R14]) 140 # define R15_sig(p) ((p)->uc_mcontext.gregs[REG_R15]) 141 # endif 142 # if defined(__linux__) && defined(__aarch64__) 143 # define EPC_sig(p) ((p)->uc_mcontext.pc) 144 # define RFP_sig(p) ((p)->uc_mcontext.regs[29]) 145 # define RLR_sig(p) ((p)->uc_mcontext.regs[30]) 146 # define R31_sig(p) ((p)->uc_mcontext.sp) 147 # endif 148 # if defined(__linux__) && defined(__mips__) 149 # define EPC_sig(p) ((p)->uc_mcontext.pc) 150 # define RFP_sig(p) ((p)->uc_mcontext.gregs[30]) 151 # define RSP_sig(p) ((p)->uc_mcontext.gregs[29]) 152 # define R31_sig(p) ((p)->uc_mcontext.gregs[31]) 153 # endif 154 # if defined(__linux__) && (defined(__sparc__) && defined(__arch64__)) 155 # define PC_sig(p) ((p)->uc_mcontext.mc_gregs[MC_PC]) 156 # define FP_sig(p) ((p)->uc_mcontext.mc_fp) 157 # define SP_sig(p) ((p)->uc_mcontext.mc_i7) 158 # endif 159 # if defined(__linux__) && (defined(__ppc64__) || defined(__PPC64__) || \ 160 defined(__ppc64le__) || defined(__PPC64LE__)) 161 # define R01_sig(p) ((p)->uc_mcontext.gp_regs[1]) 162 # define R32_sig(p) ((p)->uc_mcontext.gp_regs[32]) 163 # endif 164 # if defined(__linux__) && defined(__loongarch__) 165 # define EPC_sig(p) ((p)->uc_mcontext.__pc) 166 # define RRA_sig(p) ((p)->uc_mcontext.__gregs[1]) 167 # define R03_sig(p) ((p)->uc_mcontext.__gregs[3]) 168 # define RFP_sig(p) ((p)->uc_mcontext.__gregs[22]) 169 # endif 170 # if defined(__linux__) && defined(__riscv) 171 # define RPC_sig(p) ((p)->uc_mcontext.__gregs[REG_PC]) 172 # define RRA_sig(p) ((p)->uc_mcontext.__gregs[REG_RA]) 173 # define RFP_sig(p) ((p)->uc_mcontext.__gregs[REG_S0]) 174 # define R02_sig(p) ((p)->uc_mcontext.__gregs[REG_SP]) 175 # endif 176 # if defined(__sun__) && defined(__sparc__) 177 # define PC_sig(p) ((p)->uc_mcontext.gregs[REG_PC]) 178 # define FP_sig(p) ((p)->uc_mcontext.gregs[REG_FPRS]) 179 # define SP_sig(p) ((p)->uc_mcontext.gregs[REG_SP]) 180 # endif 181 # elif defined(__NetBSD__) 182 # define EIP_sig(p) ((p)->uc_mcontext.__gregs[_REG_EIP]) 183 # define EBP_sig(p) ((p)->uc_mcontext.__gregs[_REG_EBP]) 184 # define ESP_sig(p) ((p)->uc_mcontext.__gregs[_REG_ESP]) 185 # define RIP_sig(p) ((p)->uc_mcontext.__gregs[_REG_RIP]) 186 # define RSP_sig(p) ((p)->uc_mcontext.__gregs[_REG_RSP]) 187 # define RBP_sig(p) ((p)->uc_mcontext.__gregs[_REG_RBP]) 188 # define R11_sig(p) ((p)->uc_mcontext.__gregs[_REG_R11]) 189 # define R13_sig(p) ((p)->uc_mcontext.__gregs[_REG_R13]) 190 # define R14_sig(p) ((p)->uc_mcontext.__gregs[_REG_R14]) 191 # define R15_sig(p) ((p)->uc_mcontext.__gregs[_REG_R15]) 192 # if defined(__aarch64__) 193 # define EPC_sig(p) ((p)->uc_mcontext.__gregs[_REG_PC]) 194 # define RFP_sig(p) ((p)->uc_mcontext.__gregs[_REG_X29]) 195 # define RLR_sig(p) ((p)->uc_mcontext.__gregs[_REG_X30]) 196 # define R31_sig(p) ((p)->uc_mcontext.__gregs[_REG_SP]) 197 # endif 198 # if defined(__mips__) 199 # define EPC_sig(p) ((p)->uc_mcontext.__gregs[_REG_EPC]) 200 # define RFP_sig(p) ((p)->uc_mcontext.__gregs[_REG_S8]) 201 # endif 202 # if defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \ 203 defined(__PPC64LE__) 204 # define R01_sig(p) ((p)->uc_mcontext.__gregs[_REG_R1]) 205 # define R32_sig(p) ((p)->uc_mcontext.__gregs[_REG_PC]) 206 # endif 207 # elif defined(__DragonFly__) || defined(__FreeBSD__) || \ 208 defined(__FreeBSD_kernel__) 209 # define EIP_sig(p) ((p)->uc_mcontext.mc_eip) 210 # define EBP_sig(p) ((p)->uc_mcontext.mc_ebp) 211 # define ESP_sig(p) ((p)->uc_mcontext.mc_esp) 212 # define RIP_sig(p) ((p)->uc_mcontext.mc_rip) 213 # define RSP_sig(p) ((p)->uc_mcontext.mc_rsp) 214 # define RBP_sig(p) ((p)->uc_mcontext.mc_rbp) 215 # if defined(__FreeBSD__) && defined(__arm__) 216 # define R11_sig(p) ((p)->uc_mcontext.__gregs[_REG_R11]) 217 # define R13_sig(p) ((p)->uc_mcontext.__gregs[_REG_R13]) 218 # define R14_sig(p) ((p)->uc_mcontext.__gregs[_REG_R14]) 219 # define R15_sig(p) ((p)->uc_mcontext.__gregs[_REG_R15]) 220 # else 221 # define R11_sig(p) ((p)->uc_mcontext.mc_r11) 222 # define R13_sig(p) ((p)->uc_mcontext.mc_r13) 223 # define R14_sig(p) ((p)->uc_mcontext.mc_r14) 224 # define R15_sig(p) ((p)->uc_mcontext.mc_r15) 225 # endif 226 # if defined(__FreeBSD__) && defined(__aarch64__) 227 # define EPC_sig(p) ((p)->uc_mcontext.mc_gpregs.gp_elr) 228 # define RFP_sig(p) ((p)->uc_mcontext.mc_gpregs.gp_x[29]) 229 # define RLR_sig(p) ((p)->uc_mcontext.mc_gpregs.gp_lr) 230 # define R31_sig(p) ((p)->uc_mcontext.mc_gpregs.gp_sp) 231 # endif 232 # if defined(__FreeBSD__) && defined(__mips__) 233 # define EPC_sig(p) ((p)->uc_mcontext.mc_pc) 234 # define RFP_sig(p) ((p)->uc_mcontext.mc_regs[30]) 235 # endif 236 # if defined(__FreeBSD__) && (defined(__ppc64__) || defined(__PPC64__) || \ 237 defined(__ppc64le__) || defined(__PPC64LE__)) 238 # define R01_sig(p) ((p)->uc_mcontext.mc_gpr[1]) 239 # define R32_sig(p) ((p)->uc_mcontext.mc_srr0) 240 # endif 241 # elif defined(XP_DARWIN) 242 # define EIP_sig(p) ((p)->thread.uts.ts32.__eip) 243 # define EBP_sig(p) ((p)->thread.uts.ts32.__ebp) 244 # define ESP_sig(p) ((p)->thread.uts.ts32.__esp) 245 # define RIP_sig(p) ((p)->thread.__rip) 246 # define RBP_sig(p) ((p)->thread.__rbp) 247 # define RSP_sig(p) ((p)->thread.__rsp) 248 # define R11_sig(p) ((p)->thread.__r[11]) 249 # define R13_sig(p) ((p)->thread.__sp) 250 # define R14_sig(p) ((p)->thread.__lr) 251 # define R15_sig(p) ((p)->thread.__pc) 252 # define EPC_sig(p) ((p)->thread.__pc) 253 # define RFP_sig(p) ((p)->thread.__fp) 254 # define R31_sig(p) ((p)->thread.__sp) 255 # define RLR_sig(p) ((p)->thread.__lr) 256 # else 257 # error \ 258 "Don't know how to read/write to the thread state via the mcontext_t." 259 # endif 260 261 # if defined(ANDROID) 262 // Not all versions of the Android NDK define ucontext_t or mcontext_t. 263 // Detect this and provide custom but compatible definitions. Note that these 264 // follow the GLibc naming convention to access register values from 265 // mcontext_t. 266 // 267 // See: https://chromiumcodereview.appspot.com/10829122/ 268 // See: http://code.google.com/p/android/issues/detail?id=34784 269 # if !defined(__BIONIC_HAVE_UCONTEXT_T) 270 # if defined(__arm__) 271 272 // GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'. 273 // Old versions of the C library <signal.h> didn't define the type. 274 # if !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT) 275 # include <asm/sigcontext.h> 276 # endif 277 278 typedef struct sigcontext mcontext_t; 279 280 typedef struct ucontext { 281 uint32_t uc_flags; 282 struct ucontext* uc_link; 283 stack_t uc_stack; 284 mcontext_t uc_mcontext; 285 // Other fields are not used so don't define them here. 286 } ucontext_t; 287 288 # elif defined(__mips__) 289 290 typedef struct { 291 uint32_t regmask; 292 uint32_t status; 293 uint64_t pc; 294 uint64_t gregs[32]; 295 uint64_t fpregs[32]; 296 uint32_t acx; 297 uint32_t fpc_csr; 298 uint32_t fpc_eir; 299 uint32_t used_math; 300 uint32_t dsp; 301 uint64_t mdhi; 302 uint64_t mdlo; 303 uint32_t hi1; 304 uint32_t lo1; 305 uint32_t hi2; 306 uint32_t lo2; 307 uint32_t hi3; 308 uint32_t lo3; 309 } mcontext_t; 310 311 typedef struct ucontext { 312 uint32_t uc_flags; 313 struct ucontext* uc_link; 314 stack_t uc_stack; 315 mcontext_t uc_mcontext; 316 // Other fields are not used so don't define them here. 317 } ucontext_t; 318 319 # elif defined(__loongarch64) 320 321 typedef struct { 322 uint64_t pc; 323 uint64_t gregs[32]; 324 uint64_t fpregs[32]; 325 uint32_t fpc_csr; 326 } mcontext_t; 327 328 typedef struct ucontext { 329 uint32_t uc_flags; 330 struct ucontext* uc_link; 331 stack_t uc_stack; 332 mcontext_t uc_mcontext; 333 // Other fields are not used so don't define them here. 334 } ucontext_t; 335 336 # elif defined(__i386__) 337 // x86 version for Android. 338 typedef struct { 339 uint32_t gregs[19]; 340 void* fpregs; 341 uint32_t oldmask; 342 uint32_t cr2; 343 } mcontext_t; 344 345 typedef uint32_t kernel_sigset_t[2]; // x86 kernel uses 64-bit signal masks 346 typedef struct ucontext { 347 uint32_t uc_flags; 348 struct ucontext* uc_link; 349 stack_t uc_stack; 350 mcontext_t uc_mcontext; 351 // Other fields are not used by V8, don't define them here. 352 } ucontext_t; 353 enum { REG_EIP = 14 }; 354 # endif // defined(__i386__) 355 # endif // !defined(__BIONIC_HAVE_UCONTEXT_T) 356 # endif // defined(ANDROID) 357 358 # if defined(XP_DARWIN) 359 # if defined(__x86_64__) 360 struct macos_x64_context { 361 x86_thread_state64_t thread; 362 x86_float_state64_t float_; 363 }; 364 # define CONTEXT macos_x64_context 365 # elif defined(__i386__) 366 struct macos_x86_context { 367 x86_thread_state_t thread; 368 x86_float_state_t float_; 369 }; 370 # define CONTEXT macos_x86_context 371 # elif defined(__arm__) 372 struct macos_arm_context { 373 arm_thread_state_t thread; 374 arm_neon_state_t float_; 375 }; 376 # define CONTEXT macos_arm_context 377 # elif defined(__aarch64__) 378 struct macos_aarch64_context { 379 arm_thread_state64_t thread; 380 arm_neon_state64_t float_; 381 }; 382 # define CONTEXT macos_aarch64_context 383 # else 384 # error Unsupported architecture 385 # endif 386 # elif !defined(XP_WIN) 387 # define CONTEXT ucontext_t 388 # endif 389 390 # if defined(_M_X64) || defined(__x86_64__) 391 # define PC_sig(p) RIP_sig(p) 392 # define FP_sig(p) RBP_sig(p) 393 # define SP_sig(p) RSP_sig(p) 394 # elif defined(_M_IX86) || defined(__i386__) 395 # define PC_sig(p) EIP_sig(p) 396 # define FP_sig(p) EBP_sig(p) 397 # define SP_sig(p) ESP_sig(p) 398 # elif defined(__arm__) 399 # define FP_sig(p) R11_sig(p) 400 # define SP_sig(p) R13_sig(p) 401 # define LR_sig(p) R14_sig(p) 402 # define PC_sig(p) R15_sig(p) 403 # elif defined(_M_ARM64) || defined(__aarch64__) 404 # define PC_sig(p) EPC_sig(p) 405 # define FP_sig(p) RFP_sig(p) 406 # define SP_sig(p) R31_sig(p) 407 # define LR_sig(p) RLR_sig(p) 408 # elif defined(__mips__) 409 # define PC_sig(p) EPC_sig(p) 410 # define FP_sig(p) RFP_sig(p) 411 # define SP_sig(p) RSP_sig(p) 412 # define LR_sig(p) R31_sig(p) 413 # elif defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \ 414 defined(__PPC64LE__) 415 # define PC_sig(p) R32_sig(p) 416 # define SP_sig(p) R01_sig(p) 417 # define FP_sig(p) R01_sig(p) 418 # elif defined(__loongarch__) 419 # define PC_sig(p) EPC_sig(p) 420 # define FP_sig(p) RFP_sig(p) 421 # define SP_sig(p) R03_sig(p) 422 # define LR_sig(p) RRA_sig(p) 423 # elif defined(__riscv) 424 # define PC_sig(p) RPC_sig(p) 425 # define FP_sig(p) RFP_sig(p) 426 # define SP_sig(p) R02_sig(p) 427 # define LR_sig(p) RRA_sig(p) 428 # endif 429 430 static void SetContextPC(CONTEXT* context, uint8_t* pc) { 431 # ifdef PC_sig 432 *mozilla::BitwiseCast<uint8_t**>(&PC_sig(context)) = pc; 433 # else 434 MOZ_CRASH(); 435 # endif 436 } 437 438 static uint8_t* ContextToPC(CONTEXT* context) { 439 # ifdef PC_sig 440 return mozilla::BitwiseCast<uint8_t*>(PC_sig(context)); 441 # else 442 MOZ_CRASH(); 443 # endif 444 } 445 446 static uint8_t* ContextToFP(CONTEXT* context) { 447 # ifdef FP_sig 448 return mozilla::BitwiseCast<uint8_t*>(FP_sig(context)); 449 # else 450 MOZ_CRASH(); 451 # endif 452 } 453 454 static uint8_t* ContextToSP(CONTEXT* context) { 455 # ifdef SP_sig 456 return mozilla::BitwiseCast<uint8_t*>(SP_sig(context)); 457 # else 458 MOZ_CRASH(); 459 # endif 460 } 461 462 # if defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 463 defined(__loongarch__) || defined(__riscv) 464 static uint8_t* ContextToLR(CONTEXT* context) { 465 # ifdef LR_sig 466 return mozilla::BitwiseCast<uint8_t*>(LR_sig(context)); 467 # else 468 MOZ_CRASH(); 469 # endif 470 } 471 # endif 472 473 static JS::ProfilingFrameIterator::RegisterState ToRegisterState( 474 CONTEXT* context) { 475 JS::ProfilingFrameIterator::RegisterState state; 476 state.fp = ContextToFP(context); 477 state.pc = ContextToPC(context); 478 state.sp = ContextToSP(context); 479 # if defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \ 480 defined(__loongarch__) || defined(__riscv) 481 state.lr = ContextToLR(context); 482 # else 483 state.lr = (void*)UINTPTR_MAX; 484 # endif 485 return state; 486 } 487 488 // ============================================================================= 489 // All signals/exceptions funnel down to this one trap-handling function which 490 // tests whether the pc is in a wasm module and, if so, whether there is 491 // actually a trap expected at this pc. These tests both avoid real bugs being 492 // silently converted to wasm traps and provides the trapping wasm bytecode 493 // offset we need to report in the error. 494 // 495 // Crashing inside wasm trap handling (due to a bug in trap handling or exposed 496 // during trap handling) must be reported like a normal crash, not cause the 497 // crash report to be lost. On Windows and non-Mach Unix, a crash during the 498 // handler reenters the handler, possibly repeatedly until exhausting the stack, 499 // and so we prevent recursion with the thread-local sAlreadyHandlingTrap. On 500 // Mach, the wasm exception handler has its own thread and is installed only on 501 // the thread-level debugging ports of JSRuntime threads, so a crash on 502 // exception handler thread will not recurse; it will bubble up to the 503 // process-level debugging ports (where Breakpad is installed). 504 // ============================================================================= 505 506 static MOZ_THREAD_LOCAL(bool) sAlreadyHandlingTrap; 507 508 struct AutoHandlingTrap { 509 AutoHandlingTrap() { 510 MOZ_ASSERT(!sAlreadyHandlingTrap.get()); 511 sAlreadyHandlingTrap.set(true); 512 } 513 514 ~AutoHandlingTrap() { 515 MOZ_ASSERT(sAlreadyHandlingTrap.get()); 516 sAlreadyHandlingTrap.set(false); 517 } 518 }; 519 520 [[nodiscard]] static bool HandleTrap(CONTEXT* context, 521 JSContext* assertCx = nullptr) { 522 MOZ_ASSERT(sAlreadyHandlingTrap.get()); 523 524 uint8_t* pc = ContextToPC(context); 525 const CodeBlock* codeBlock = LookupCodeBlock(pc); 526 if (!codeBlock) { 527 return false; 528 } 529 530 Trap trap; 531 TrapSite trapSite; 532 if (!codeBlock->lookupTrap(pc, &trap, &trapSite)) { 533 return false; 534 } 535 536 // We have a safe, expected wasm trap, so fp is well-defined to be a Frame*. 537 // For the first sanity check, the Trap::IndirectCallBadSig special case is 538 // due to this trap occurring in the indirect call prologue, while fp points 539 // to the caller's Frame which can be in a different Module. In any case, 540 // though, the containing JSContext is the same. 541 542 auto* frame = reinterpret_cast<Frame*>(ContextToFP(context)); 543 Instance* instance = GetNearestEffectiveInstance(frame); 544 MOZ_RELEASE_ASSERT(&instance->code() == codeBlock->code || 545 trap == Trap::IndirectCallBadSig); 546 547 // Ensure the active FP has a valid instance pointer that the trap stub can 548 // use. 549 ((FrameWithInstances*)frame)->setCalleeInstance(instance); 550 551 JSContext* cx = 552 instance->realm()->runtimeFromAnyThread()->mainContextFromAnyThread(); 553 MOZ_RELEASE_ASSERT(!assertCx || cx == assertCx); 554 555 // JitActivation::startWasmTrap() stores enough register state from the 556 // point of the trap to allow stack unwinding or resumption, both of which 557 // will call finishWasmTrap(). 558 jit::JitActivation* activation = cx->activation()->asJit(); 559 activation->startWasmTrap(trap, trapSite, ToRegisterState(context)); 560 SetContextPC(context, codeBlock->code->trapCode()); 561 return true; 562 } 563 564 // ============================================================================= 565 // The following platform-specific handlers funnel all signals/exceptions into 566 // the shared HandleTrap() above. 567 // ============================================================================= 568 569 # if defined(XP_WIN) 570 // Obtained empirically from thread_local codegen on x86/x64/arm64. 571 // Compiled in all user binaries, so should be stable over time. 572 static const unsigned sThreadLocalArrayPointerIndex = 11; 573 574 static LONG WINAPI WasmTrapHandler(LPEXCEPTION_POINTERS exception) { 575 // Make sure TLS is initialized before reading sAlreadyHandlingTrap. 576 if (!NtCurrentTeb()->Reserved1[sThreadLocalArrayPointerIndex]) { 577 return EXCEPTION_CONTINUE_SEARCH; 578 } 579 580 if (sAlreadyHandlingTrap.get()) { 581 return EXCEPTION_CONTINUE_SEARCH; 582 } 583 AutoHandlingTrap aht; 584 585 EXCEPTION_RECORD* record = exception->ExceptionRecord; 586 if (record->ExceptionCode != EXCEPTION_ACCESS_VIOLATION && 587 record->ExceptionCode != EXCEPTION_ILLEGAL_INSTRUCTION) { 588 return EXCEPTION_CONTINUE_SEARCH; 589 } 590 591 JSContext* cx = TlsContext.get(); // Cold signal handling code 592 if (!HandleTrap(exception->ContextRecord, cx)) { 593 return EXCEPTION_CONTINUE_SEARCH; 594 } 595 596 return EXCEPTION_CONTINUE_EXECUTION; 597 } 598 599 # elif defined(XP_DARWIN) 600 // On OSX we are forced to use the lower-level Mach exception mechanism instead 601 // of Unix signals because breakpad uses Mach exceptions and would otherwise 602 // report a crash before wasm gets a chance to handle the exception. 603 604 // This definition was generated by mig (the Mach Interface Generator) for the 605 // routine 'exception_raise' (exc.defs). 606 # pragma pack(4) 607 typedef struct { 608 mach_msg_header_t Head; 609 /* start of the kernel processed data */ 610 mach_msg_body_t msgh_body; 611 mach_msg_port_descriptor_t thread; 612 mach_msg_port_descriptor_t task; 613 /* end of the kernel processed data */ 614 NDR_record_t NDR; 615 exception_type_t exception; 616 mach_msg_type_number_t codeCnt; 617 int64_t code[2]; 618 } Request__mach_exception_raise_t; 619 # pragma pack() 620 621 // The full Mach message also includes a trailer. 622 struct ExceptionRequest { 623 Request__mach_exception_raise_t body; 624 mach_msg_trailer_t trailer; 625 }; 626 627 static bool HandleMachException(const ExceptionRequest& request) { 628 // Get the port of the JSContext's thread from the message. 629 mach_port_t cxThread = request.body.thread.name; 630 631 // Read out the JSRuntime thread's register state. 632 CONTEXT context; 633 # if defined(__x86_64__) 634 unsigned int thread_state_count = x86_THREAD_STATE64_COUNT; 635 unsigned int float_state_count = x86_FLOAT_STATE64_COUNT; 636 int thread_state = x86_THREAD_STATE64; 637 int float_state = x86_FLOAT_STATE64; 638 # elif defined(__i386__) 639 unsigned int thread_state_count = x86_THREAD_STATE_COUNT; 640 unsigned int float_state_count = x86_FLOAT_STATE_COUNT; 641 int thread_state = x86_THREAD_STATE; 642 int float_state = x86_FLOAT_STATE; 643 # elif defined(__arm__) 644 unsigned int thread_state_count = ARM_THREAD_STATE_COUNT; 645 unsigned int float_state_count = ARM_NEON_STATE_COUNT; 646 int thread_state = ARM_THREAD_STATE; 647 int float_state = ARM_NEON_STATE; 648 # elif defined(__aarch64__) 649 unsigned int thread_state_count = ARM_THREAD_STATE64_COUNT; 650 unsigned int float_state_count = ARM_NEON_STATE64_COUNT; 651 int thread_state = ARM_THREAD_STATE64; 652 int float_state = ARM_NEON_STATE64; 653 # else 654 # error Unsupported architecture 655 # endif 656 kern_return_t kret; 657 kret = thread_get_state(cxThread, thread_state, 658 (thread_state_t)&context.thread, &thread_state_count); 659 if (kret != KERN_SUCCESS) { 660 return false; 661 } 662 kret = thread_get_state(cxThread, float_state, 663 (thread_state_t)&context.float_, &float_state_count); 664 if (kret != KERN_SUCCESS) { 665 return false; 666 } 667 668 if (request.body.exception != EXC_BAD_ACCESS && 669 request.body.exception != EXC_BAD_INSTRUCTION) { 670 return false; 671 } 672 673 { 674 AutoNoteSingleThreadedRegion anstr; 675 AutoHandlingTrap aht; 676 if (!HandleTrap(&context)) { 677 return false; 678 } 679 } 680 681 // Update the thread state with the new pc and register values. 682 kret = thread_set_state(cxThread, float_state, 683 (thread_state_t)&context.float_, float_state_count); 684 if (kret != KERN_SUCCESS) { 685 return false; 686 } 687 kret = thread_set_state(cxThread, thread_state, 688 (thread_state_t)&context.thread, thread_state_count); 689 if (kret != KERN_SUCCESS) { 690 return false; 691 } 692 693 return true; 694 } 695 696 static mach_port_t sMachDebugPort = MACH_PORT_NULL; 697 698 static void MachExceptionHandlerThread() { 699 ThisThread::SetName("JS Wasm MachExceptionHandler"); 700 701 // Taken from mach_exc in /usr/include/mach/mach_exc.defs. 702 static const unsigned EXCEPTION_MSG_ID = 2405; 703 704 while (true) { 705 ExceptionRequest request; 706 kern_return_t kret = 707 mach_msg(&request.body.Head, MACH_RCV_MSG, 0, sizeof(request), 708 sMachDebugPort, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 709 710 // If we fail even receiving the message, we can't even send a reply! 711 // Rather than hanging the faulting thread (hanging the browser), crash. 712 if (kret != KERN_SUCCESS) { 713 fprintf(stderr, "MachExceptionHandlerThread: mach_msg failed with %d\n", 714 (int)kret); 715 MOZ_CRASH(); 716 } 717 718 if (request.body.Head.msgh_id != EXCEPTION_MSG_ID) { 719 fprintf(stderr, "Unexpected msg header id %d\n", 720 (int)request.body.Head.msgh_bits); 721 MOZ_CRASH(); 722 } 723 724 // Some thread just commited an EXC_BAD_ACCESS and has been suspended by 725 // the kernel. The kernel is waiting for us to reply with instructions. 726 // Our default is the "not handled" reply (by setting the RetCode field 727 // of the reply to KERN_FAILURE) which tells the kernel to continue 728 // searching at the process and system level. If this is an asm.js 729 // expected exception, we handle it and return KERN_SUCCESS. 730 bool handled = HandleMachException(request); 731 kern_return_t replyCode = handled ? KERN_SUCCESS : KERN_FAILURE; 732 733 // This magic incantation to send a reply back to the kernel was 734 // derived from the exc_server generated by 735 // 'mig -v /usr/include/mach/mach_exc.defs'. 736 __Reply__exception_raise_t reply; 737 reply.Head.msgh_bits = 738 MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(request.body.Head.msgh_bits), 0); 739 reply.Head.msgh_size = sizeof(reply); 740 reply.Head.msgh_remote_port = request.body.Head.msgh_remote_port; 741 reply.Head.msgh_local_port = MACH_PORT_NULL; 742 reply.Head.msgh_id = request.body.Head.msgh_id + 100; 743 reply.NDR = NDR_record; 744 reply.RetCode = replyCode; 745 mach_msg(&reply.Head, MACH_SEND_MSG, sizeof(reply), 0, MACH_PORT_NULL, 746 MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); 747 } 748 } 749 750 # else // If not Windows or Mac, assume Unix 751 752 # if defined(__mips__) || defined(__loongarch__) 753 static const uint32_t kWasmTrapSignal = SIGFPE; 754 # else 755 static const uint32_t kWasmTrapSignal = SIGILL; 756 # endif 757 758 static struct sigaction sPrevSEGVHandler; 759 static struct sigaction sPrevSIGBUSHandler; 760 static struct sigaction sPrevWasmTrapHandler; 761 762 static void WasmTrapHandler(int signum, siginfo_t* info, void* context) { 763 if (!sAlreadyHandlingTrap.get()) { 764 AutoHandlingTrap aht; 765 MOZ_RELEASE_ASSERT(signum == SIGSEGV || signum == SIGBUS || 766 signum == kWasmTrapSignal); 767 JSContext* cx = TlsContext.get(); // Cold signal handling code 768 if (HandleTrap((CONTEXT*)context, cx)) { 769 return; 770 } 771 } 772 773 struct sigaction* previousSignal = nullptr; 774 switch (signum) { 775 case SIGSEGV: 776 previousSignal = &sPrevSEGVHandler; 777 break; 778 case SIGBUS: 779 previousSignal = &sPrevSIGBUSHandler; 780 break; 781 case kWasmTrapSignal: 782 previousSignal = &sPrevWasmTrapHandler; 783 break; 784 } 785 MOZ_ASSERT(previousSignal); 786 787 // This signal is not for any asm.js code we expect, so we need to forward 788 // the signal to the next handler. If there is no next handler (SIG_IGN or 789 // SIG_DFL), then it's time to crash. To do this, we set the signal back to 790 // its original disposition and return. This will cause the faulting op to 791 // be re-executed which will crash in the normal way. The advantage of 792 // doing this to calling _exit() is that we remove ourselves from the crash 793 // stack which improves crash reports. If there is a next handler, call it. 794 // It will either crash synchronously, fix up the instruction so that 795 // execution can continue and return, or trigger a crash by returning the 796 // signal to it's original disposition and returning. 797 // 798 // Note: the order of these tests matter. 799 if (previousSignal->sa_flags & SA_SIGINFO) { 800 previousSignal->sa_sigaction(signum, info, context); 801 } else if (previousSignal->sa_handler == SIG_DFL || 802 previousSignal->sa_handler == SIG_IGN) { 803 sigaction(signum, previousSignal, nullptr); 804 } else { 805 previousSignal->sa_handler(signum); 806 } 807 } 808 # endif // XP_WIN || XP_DARWIN || assume unix 809 810 struct InstallState { 811 bool tried; 812 bool success; 813 InstallState() : tried(false), success(false) {} 814 }; 815 816 MOZ_RUNINIT static ExclusiveData<InstallState> sEagerInstallState( 817 mutexid::WasmSignalInstallState); 818 819 #endif // !(JS_CODEGEN_NONE) 820 821 void wasm::EnsureEagerProcessSignalHandlers() { 822 #ifdef JS_CODEGEN_NONE 823 // If there is no JIT, then there should be no Wasm signal handlers. 824 return; 825 #else 826 auto eagerInstallState = sEagerInstallState.lock(); 827 if (eagerInstallState->tried) { 828 return; 829 } 830 831 eagerInstallState->tried = true; 832 MOZ_RELEASE_ASSERT(eagerInstallState->success == false); 833 834 sAlreadyHandlingTrap.infallibleInit(); 835 836 // Install whatever exception/signal handler is appropriate for the OS. 837 # if defined(XP_WIN) 838 839 # if defined(MOZ_ASAN) 840 // Under ASan we need to let the ASan runtime's ShadowExceptionHandler stay 841 // in the first handler position. 842 const bool firstHandler = false; 843 # else 844 // Otherwise, WasmTrapHandler needs to go first, so that we can recover 845 // from wasm faults and continue execution without triggering handlers 846 // such as Breakpad that assume we are crashing. 847 const bool firstHandler = true; 848 # endif 849 if (!AddVectoredExceptionHandler(firstHandler, WasmTrapHandler)) { 850 // Windows has all sorts of random security knobs for disabling things 851 // so make this a dynamic failure that disables wasm, not a MOZ_CRASH(). 852 return; 853 } 854 855 # elif defined(XP_DARWIN) 856 // All the Mach setup in EnsureLazyProcessSignalHandlers. 857 # else 858 // SA_NODEFER allows us to reenter the signal handler if we crash while 859 // handling the signal, and fall through to the Breakpad handler by testing 860 // handlingSegFault. 861 862 // Allow handling OOB with signals on all architectures 863 struct sigaction faultHandler; 864 faultHandler.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK; 865 faultHandler.sa_sigaction = WasmTrapHandler; 866 sigemptyset(&faultHandler.sa_mask); 867 if (sigaction(SIGSEGV, &faultHandler, &sPrevSEGVHandler)) { 868 MOZ_CRASH("unable to install segv handler"); 869 } 870 871 # if defined(JS_CODEGEN_ARM) 872 // On Arm Handle Unaligned Accesses 873 struct sigaction busHandler; 874 busHandler.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK; 875 busHandler.sa_sigaction = WasmTrapHandler; 876 sigemptyset(&busHandler.sa_mask); 877 if (sigaction(SIGBUS, &busHandler, &sPrevSIGBUSHandler)) { 878 MOZ_CRASH("unable to install sigbus handler"); 879 } 880 # endif 881 882 // Install a handler to handle the instructions that are emitted to implement 883 // wasm traps. 884 struct sigaction wasmTrapHandler; 885 wasmTrapHandler.sa_flags = SA_SIGINFO | SA_NODEFER | SA_ONSTACK; 886 wasmTrapHandler.sa_sigaction = WasmTrapHandler; 887 sigemptyset(&wasmTrapHandler.sa_mask); 888 if (sigaction(kWasmTrapSignal, &wasmTrapHandler, &sPrevWasmTrapHandler)) { 889 MOZ_CRASH("unable to install wasm trap handler"); 890 } 891 # endif 892 893 eagerInstallState->success = true; 894 #endif 895 } 896 897 #ifndef JS_CODEGEN_NONE 898 MOZ_RUNINIT static ExclusiveData<InstallState> sLazyInstallState( 899 mutexid::WasmSignalInstallState); 900 901 static bool EnsureLazyProcessSignalHandlers() { 902 auto lazyInstallState = sLazyInstallState.lock(); 903 if (lazyInstallState->tried) { 904 return lazyInstallState->success; 905 } 906 907 lazyInstallState->tried = true; 908 MOZ_RELEASE_ASSERT(lazyInstallState->success == false); 909 910 # ifdef XP_DARWIN 911 // Create the port that all JSContext threads will redirect their traps to. 912 kern_return_t kret; 913 kret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, 914 &sMachDebugPort); 915 if (kret != KERN_SUCCESS) { 916 return false; 917 } 918 kret = mach_port_insert_right(mach_task_self(), sMachDebugPort, 919 sMachDebugPort, MACH_MSG_TYPE_MAKE_SEND); 920 if (kret != KERN_SUCCESS) { 921 return false; 922 } 923 924 // Create the thread that will wait on and service sMachDebugPort. 925 // It's not useful to destroy this thread on process shutdown so 926 // immediately detach on successful start. 927 Thread handlerThread; 928 if (!handlerThread.init(MachExceptionHandlerThread)) { 929 return false; 930 } 931 handlerThread.detach(); 932 # endif 933 934 lazyInstallState->success = true; 935 return true; 936 } 937 #endif // JS_CODEGEN_NONE 938 939 bool wasm::EnsureFullSignalHandlers(JSContext* cx) { 940 #ifdef JS_CODEGEN_NONE 941 return false; 942 #else 943 if (cx->wasm().triedToInstallSignalHandlers) { 944 return cx->wasm().haveSignalHandlers; 945 } 946 947 cx->wasm().triedToInstallSignalHandlers = true; 948 MOZ_RELEASE_ASSERT(!cx->wasm().haveSignalHandlers); 949 950 { 951 auto eagerInstallState = sEagerInstallState.lock(); 952 MOZ_RELEASE_ASSERT(eagerInstallState->tried); 953 if (!eagerInstallState->success) { 954 return false; 955 } 956 } 957 958 if (!EnsureLazyProcessSignalHandlers()) { 959 return false; 960 } 961 962 # ifdef XP_DARWIN 963 // In addition to the process-wide signal handler setup, OSX needs each 964 // thread configured to send its exceptions to sMachDebugPort. While there 965 // are also task-level (i.e. process-level) exception ports, those are 966 // "claimed" by breakpad and chaining Mach exceptions is dark magic that we 967 // avoid by instead intercepting exceptions at the thread level before they 968 // propagate to the process-level. This works because there are no other 969 // uses of thread-level exception ports. 970 MOZ_RELEASE_ASSERT(sMachDebugPort != MACH_PORT_NULL); 971 thread_port_t thisThread = mach_thread_self(); 972 kern_return_t kret = thread_set_exception_ports( 973 thisThread, EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION, 974 sMachDebugPort, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, 975 THREAD_STATE_NONE); 976 mach_port_deallocate(mach_task_self(), thisThread); 977 if (kret != KERN_SUCCESS) { 978 return false; 979 } 980 # endif 981 982 cx->wasm().haveSignalHandlers = true; 983 return true; 984 #endif 985 } 986 987 bool wasm::MemoryAccessTraps(const RegisterState& regs, uint8_t* addr, 988 uint32_t numBytes, uint8_t** newPC) { 989 #ifdef JS_CODEGEN_NONE 990 return false; 991 #else 992 const wasm::CodeBlock* codeBlock = wasm::LookupCodeBlock(regs.pc); 993 if (!codeBlock) { 994 return false; 995 } 996 997 Trap trap; 998 TrapSite trapSite; 999 if (!codeBlock->code->lookupTrap(regs.pc, &trap, &trapSite)) { 1000 return false; 1001 } 1002 switch (trap) { 1003 case Trap::OutOfBounds: 1004 break; 1005 case Trap::NullPointerDereference: 1006 case Trap::BadCast: 1007 break; 1008 # ifdef WASM_HAS_HEAPREG 1009 case Trap::IndirectCallToNull: 1010 // We use the null pointer exception from loading the heapreg to 1011 // handle indirect calls to null. 1012 break; 1013 # endif 1014 default: 1015 return false; 1016 } 1017 1018 // This is a safe and expected wasm trap. This guarantees that FP is pointing 1019 // at a wasm frame. 1020 FrameWithInstances* frame = (FrameWithInstances*)(regs.fp); 1021 Instance& instance = *GetNearestEffectiveInstance(frame); 1022 MOZ_ASSERT(&instance.code() == codeBlock->code); 1023 1024 // Ensure the active FP has a valid instance pointer that the trap stub can 1025 // use. 1026 frame->setCalleeInstance(&instance); 1027 1028 switch (trap) { 1029 case Trap::OutOfBounds: 1030 if (!instance.memoryAccessInGuardRegion((uint8_t*)addr, numBytes)) { 1031 return false; 1032 } 1033 break; 1034 case Trap::NullPointerDereference: 1035 case Trap::BadCast: 1036 if ((uintptr_t)addr >= NullPtrGuardSize) { 1037 return false; 1038 } 1039 break; 1040 # ifdef WASM_HAS_HEAPREG 1041 case Trap::IndirectCallToNull: 1042 // Null pointer plus the appropriate offset. 1043 if (addr != 1044 reinterpret_cast<uint8_t*>(wasm::Instance::offsetOfMemory0Base())) { 1045 return false; 1046 } 1047 break; 1048 # endif 1049 default: 1050 MOZ_CRASH("Should not happen"); 1051 } 1052 1053 JSContext* cx = TlsContext.get(); // Cold simulator helper function 1054 jit::JitActivation* activation = cx->activation()->asJit(); 1055 activation->startWasmTrap(trap, trapSite, regs); 1056 *newPC = codeBlock->code->trapCode(); 1057 return true; 1058 #endif 1059 } 1060 1061 bool wasm::HandleIllegalInstruction(const RegisterState& regs, 1062 uint8_t** newPC) { 1063 #ifdef JS_CODEGEN_NONE 1064 return false; 1065 #else 1066 const wasm::CodeBlock* codeBlock = wasm::LookupCodeBlock(regs.pc); 1067 if (!codeBlock) { 1068 return false; 1069 } 1070 1071 Trap trap; 1072 TrapSite trapSite; 1073 if (!codeBlock->code->lookupTrap(regs.pc, &trap, &trapSite)) { 1074 return false; 1075 } 1076 1077 // This is a safe and expected wasm trap. This guarantees that FP is pointing 1078 // at a wasm frame. 1079 FrameWithInstances* frame = (FrameWithInstances*)(regs.fp); 1080 Instance& instance = *GetNearestEffectiveInstance(frame); 1081 MOZ_ASSERT(&instance.code() == codeBlock->code); 1082 1083 // Ensure the active FP has a valid instance pointer that the trap stub can 1084 // use. 1085 frame->setCalleeInstance(&instance); 1086 1087 JSContext* cx = TlsContext.get(); // Cold simulator helper function 1088 jit::JitActivation* activation = cx->activation()->asJit(); 1089 activation->startWasmTrap(trap, trapSite, regs); 1090 *newPC = codeBlock->code->trapCode(); 1091 return true; 1092 #endif 1093 }