// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #ifndef RUNTIME_VM_SIGNAL_HANDLER_H_ #define RUNTIME_VM_SIGNAL_HANDLER_H_ #include "vm/allocation.h" #include "vm/globals.h" #if defined(HOST_OS_LINUX) #include // NOLINT #include // NOLINT #elif defined(HOST_OS_ANDROID) #include // NOLINT #if !defined(__BIONIC_HAVE_UCONTEXT_T) #include // NOLINT // If ucontext_t is not defined on Android, define it here. typedef struct sigcontext mcontext_t; typedef struct ucontext { uint32_t uc_flags; struct ucontext* uc_link; stack_t uc_stack; struct sigcontext uc_mcontext; uint32_t uc_sigmask; } ucontext_t; #endif // !defined(__BIONIC_HAVE_UCONTEXT_T) #elif defined(HOST_OS_MACOS) #include // NOLINT #include // NOLINT #elif defined(HOST_OS_WINDOWS) // Stub out for windows. struct siginfo_t; struct mcontext_t; struct sigset_t {}; #elif defined(HOST_OS_FUCHSIA) #include // NOLINT #include // NOLINT #endif // Old linux kernels on ARM might require a trampoline to // work around incorrect Thumb -> ARM transitions. See SignalHandlerTrampoline // below for more details. #if defined(HOST_ARCH_ARM) && \ (defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID)) && \ !defined(__thumb__) #define USE_SIGNAL_HANDLER_TRAMPOLINE #endif namespace dart { typedef void (*SignalAction)(int signal, siginfo_t* info, void* context); class SignalHandler : public AllStatic { public: template static void Install() { #if defined(USE_SIGNAL_HANDLER_TRAMPOLINE) InstallImpl(SignalHandlerTrampoline); #else InstallImpl(action); #endif // defined(USE_SIGNAL_HANDLER_TRAMPOLINE) } static void Remove(); static uintptr_t GetProgramCounter(const mcontext_t& mcontext); static uintptr_t GetFramePointer(const mcontext_t& mcontext); static uintptr_t GetCStackPointer(const mcontext_t& mcontext); static uintptr_t GetDartStackPointer(const mcontext_t& mcontext); static uintptr_t GetLinkRegister(const mcontext_t& mcontext); private: static void InstallImpl(SignalAction action); #if defined(USE_SIGNAL_HANDLER_TRAMPOLINE) // Work around for a bug in old kernels (only fixed in 3.18 Android kernel): // // Kernel does not clear If-Then execution state bits when entering ARM signal // handler which violates requirements imposed by ARM architecture reference. // Some CPUs look at these bits even while in ARM mode which causes them // to skip some instructions in the prologue of the signal handler. // // To work around the issue we insert enough NOPs in the prologue to ensure // that no actual instructions are skipped and then branch to the actual // signal handler. // // For the kernel patch that fixes the issue see: // http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=6ecf830e5029598732e04067e325d946097519cb // // Note: this function is marked "naked" because we must guarantee that // our NOPs occur before any compiler generated prologue. template static __attribute__((naked)) void SignalHandlerTrampoline(int signal, siginfo_t* info, void* context_) { // IT (If-Then) instruction makes up to four instructions that follow it // conditional. // Note: clobber all register so that compiler does not attempt to hoist // anything from the next assembly block past this one. asm volatile("nop; nop; nop; nop;" : : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "memory"); // Tail-call into the actual signal handler. // // Note: this code is split into a separate inline assembly block because // any code that compiler generates to satisfy register constraints must // be generated after four NOPs. // // Note: there is no portable way to specify that we want to have // signal, info and context_ in r0 - r2 respectively. So we just mark them // as clobbered and hope that compiler does not emit any code that uses // these registers to satisfy action constraint (we tested on clang and // the generated code looks like one would expect). asm volatile("bx %0;" : : "r"(action) : "r0", "r1", "r2", "memory"); } #endif // defined(USE_SIGNAL_HANDLER_TRAMPOLINE) }; #undef USE_SIGNAL_HANDLER_TRAMPOLINE } // namespace dart #endif // RUNTIME_VM_SIGNAL_HANDLER_H_