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_ |