Chromium Code Reviews| Index: runtime/vm/signal_handler.h |
| diff --git a/runtime/vm/signal_handler.h b/runtime/vm/signal_handler.h |
| index b204c55d55f1b127f781fc8c73b8c50989861b3d..9f1ef93288ca51662bbc4160197441c921bfa6cc 100644 |
| --- a/runtime/vm/signal_handler.h |
| +++ b/runtime/vm/signal_handler.h |
| @@ -36,6 +36,16 @@ struct sigset_t { |
| }; |
| #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) && \ |
|
Florian Schneider
2016/05/02 14:43:43
s/HOST_ARCH_ARM/TARGET_ARCH_ARM/
zra
2016/05/02 15:53:54
I think HOST might be right since we don't want th
|
| + (defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID)) |
| +#define USE_SIGNAL_HANDLER_TRAMPOLINE |
| +#endif |
| + |
| + |
| namespace dart { |
| typedef void (*SignalAction)(int signal, siginfo_t* info, |
| @@ -43,17 +53,68 @@ typedef void (*SignalAction)(int signal, siginfo_t* info, |
| class SignalHandler : public AllStatic { |
| public: |
| - static void Install(SignalAction action); |
| + template<SignalAction action> |
| + static void Install() { |
| +#if defined(USE_SIGNAL_HANDLER_TRAMPOLINE) |
| + InstallImpl(SignalHandlerTrampoline<action>); |
| +#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 <SignalAction action> |
| + 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. |
| + asm volatile("nop; nop; nop; nop" : : : "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. |
| + register int arg0 asm("r0") = signal; |
| + register siginfo_t* arg1 asm("r1") = info; |
| + register void* arg2 asm("r2") = context_; |
| + asm volatile("bx %3" |
| + : |
| + : "r"(arg0), "r"(arg1), "r"(arg2), |
| + "r"(action) |
| + : "memory"); |
| + } |
| +#endif // defined(USE_SIGNAL_HANDLER_TRAMPOLINE) |
| }; |
| +#undef USE_SIGNAL_HANDLER_TRAMPOLINE |
| + |
| + |
| } // namespace dart |
| #endif // VM_SIGNAL_HANDLER_H_ |