|
54 | 54 | #include "signals_posix.hpp" |
55 | 55 | #include "utilities/align.hpp" |
56 | 56 | #include "utilities/debug.hpp" |
| 57 | +#include "utilities/decoder.hpp" |
57 | 58 | #include "utilities/events.hpp" |
| 59 | +#include "utilities/nativeStackPrinter.hpp" |
58 | 60 | #include "utilities/vmError.hpp" |
| 61 | +#include "compiler/disassembler.hpp" |
59 | 62 |
|
60 | 63 | // put OS-includes here |
61 | 64 | # include <sys/types.h> |
|
85 | 88 | #define SPELL_REG_SP "sp" |
86 | 89 |
|
87 | 90 | #ifdef __APPLE__ |
| 91 | +WXMode DefaultWXWriteMode; |
| 92 | + |
88 | 93 | // see darwin-xnu/osfmk/mach/arm/_structs.h |
89 | 94 |
|
90 | 95 | // 10.5 UNIX03 member name prefixes |
@@ -233,19 +238,56 @@ NOINLINE frame os::current_frame() { |
233 | 238 |
|
234 | 239 | bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, |
235 | 240 | ucontext_t* uc, JavaThread* thread) { |
236 | | - // Enable WXWrite: this function is called by the signal handler at arbitrary |
237 | | - // point of execution. |
238 | | - ThreadWXEnable wx(WXWrite, thread); |
239 | | - |
240 | 241 | // decide if this trap can be handled by a stub |
241 | 242 | address stub = nullptr; |
242 | | - |
243 | | - address pc = nullptr; |
| 243 | + address pc = nullptr; |
244 | 244 |
|
245 | 245 | //%note os_trap_1 |
246 | 246 | if (info != nullptr && uc != nullptr && thread != nullptr) { |
247 | 247 | pc = (address) os::Posix::ucontext_get_pc(uc); |
248 | 248 |
|
| 249 | +#ifdef MACOS_AARCH64 |
| 250 | + // If we got a SIGBUS because we tried to write into the code |
| 251 | + // cache, try enabling WXWrite mode. |
| 252 | + if (sig == SIGBUS |
| 253 | + && pc != info->si_addr |
| 254 | + && CodeCache::contains(info->si_addr) |
| 255 | + && os::address_is_in_vm(pc)) { |
| 256 | + WXMode *entry_mode = thread->_cur_wx_mode; |
| 257 | + if (entry_mode != nullptr && *entry_mode == WXArmedForWrite) { |
| 258 | + if (TraceWXHealing) { |
| 259 | + static const char *mode_names[3] = {"WXWrite", "WXExec", "WXArmedForWrite"}; |
| 260 | + tty->print("Healing WXMode %s at %p to WXWrite", |
| 261 | + mode_names[*entry_mode], entry_mode); |
| 262 | + char name[128]; |
| 263 | + int offset = 0; |
| 264 | + if (os::dll_address_to_function_name(pc, name, sizeof name, &offset)) { |
| 265 | + tty->print_cr(" (%s+0x%x)", name, offset); |
| 266 | + } else { |
| 267 | + tty->cr(); |
| 268 | + } |
| 269 | + if (Verbose) { |
| 270 | + char buf[O_BUFLEN]; |
| 271 | + NativeStackPrinter nsp(thread); |
| 272 | + nsp.print_stack(tty, buf, sizeof(buf), pc, |
| 273 | + true /* print_source_info */, -1 /* max stack */); |
| 274 | + } |
| 275 | + } |
| 276 | +#ifndef PRODUCT |
| 277 | + guarantee(StressWXHealing, |
| 278 | + "We should not reach here unless StressWXHealing"); |
| 279 | +#endif |
| 280 | + *(thread->_cur_wx_mode) = WXWrite; |
| 281 | + return thread->wx_enable_write(); |
| 282 | + } |
| 283 | + } |
| 284 | + |
| 285 | + // There may be cases where code after this point that we call |
| 286 | + // from the signal handler changes WX state, so we protect against |
| 287 | + // that by saving and restoring the state. |
| 288 | + ThreadWXEnable wx(thread->get_wx_state(), thread); |
| 289 | +#endif |
| 290 | + |
249 | 291 | // Handle ALL stack overflow variations here |
250 | 292 | if (sig == SIGSEGV || sig == SIGBUS) { |
251 | 293 | address addr = (address) info->si_addr; |
@@ -515,11 +557,42 @@ int os::extra_bang_size_in_bytes() { |
515 | 557 | return 0; |
516 | 558 | } |
517 | 559 |
|
518 | | -#ifdef __APPLE__ |
| 560 | +#ifdef MACOS_AARCH64 |
| 561 | +THREAD_LOCAL bool os::_jit_exec_enabled; |
| 562 | + |
| 563 | +// This is a wrapper around the standard library function |
| 564 | +// pthread_jit_write_protect_np(3). We keep track of the state of |
| 565 | +// per-thread write protection on the MAP_JIT region in the |
| 566 | +// thread-local variable os::_jit_exec_enabled |
519 | 567 | void os::current_thread_enable_wx(WXMode mode) { |
520 | | - pthread_jit_write_protect_np(mode == WXExec); |
| 568 | + bool exec_enabled = mode != WXWrite; |
| 569 | + if (exec_enabled != _jit_exec_enabled NOT_PRODUCT( || DefaultWXWriteMode == WXWrite)) { |
| 570 | + permit_forbidden_function::pthread_jit_write_protect_np(exec_enabled); |
| 571 | + _jit_exec_enabled = exec_enabled; |
| 572 | + } |
521 | 573 | } |
522 | | -#endif |
| 574 | + |
| 575 | +// If the current thread is in the WX state WXArmedForWrite, change |
| 576 | +// the state to WXWrite. |
| 577 | +bool Thread::wx_enable_write() { |
| 578 | + if (_wx_state == WXArmedForWrite) { |
| 579 | + _wx_state = WXWrite; |
| 580 | + os::current_thread_enable_wx(WXWrite); |
| 581 | + return true; |
| 582 | + } else { |
| 583 | + return false; |
| 584 | + } |
| 585 | +} |
| 586 | + |
| 587 | +// A wrapper around wx_enable_write() for when the current thread is |
| 588 | +// not known. |
| 589 | +void os::thread_wx_enable_write_impl() { |
| 590 | + if (!StressWXHealing) { |
| 591 | + Thread::current()->wx_enable_write(); |
| 592 | + } |
| 593 | +} |
| 594 | + |
| 595 | +#endif // MACOS_AARCH64 |
523 | 596 |
|
524 | 597 | static inline void atomic_copy64(const volatile void *src, volatile void *dst) { |
525 | 598 | *(jlong *) dst = *(const jlong *) src; |
|
0 commit comments