mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 00:13:50 +00:00
Work around a kernel bug on Android.
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 This causes sporadic crashes with SIGILL on some testing devices (e.g. Nexus 7). R=fschneider@google.com BUG= Review URL: https://codereview.chromium.org/1940883002 .
This commit is contained in:
parent
fcf97b6c3d
commit
b089d4f004
|
@ -36,6 +36,17 @@ 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) && \
|
||||
(defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID)) && \
|
||||
!defined(__thumb__)
|
||||
#define USE_SIGNAL_HANDLER_TRAMPOLINE
|
||||
#endif
|
||||
|
||||
|
||||
namespace dart {
|
||||
|
||||
typedef void (*SignalAction)(int signal, siginfo_t* info,
|
||||
|
@ -43,17 +54,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_
|
||||
|
|
|
@ -100,7 +100,7 @@ uintptr_t SignalHandler::GetLinkRegister(const mcontext_t& mcontext) {
|
|||
}
|
||||
|
||||
|
||||
void SignalHandler::Install(SignalAction action) {
|
||||
void SignalHandler::InstallImpl(SignalAction action) {
|
||||
struct sigaction act;
|
||||
memset(&act, 0, sizeof(act));
|
||||
act.sa_sigaction = action;
|
||||
|
|
|
@ -99,7 +99,7 @@ uintptr_t SignalHandler::GetLinkRegister(const mcontext_t& mcontext) {
|
|||
}
|
||||
|
||||
|
||||
void SignalHandler::Install(SignalAction action) {
|
||||
void SignalHandler::InstallImpl(SignalAction action) {
|
||||
struct sigaction act;
|
||||
act.sa_handler = NULL;
|
||||
act.sa_sigaction = action;
|
||||
|
|
|
@ -102,7 +102,7 @@ uintptr_t SignalHandler::GetLinkRegister(const mcontext_t& mcontext) {
|
|||
}
|
||||
|
||||
|
||||
void SignalHandler::Install(SignalAction action) {
|
||||
void SignalHandler::InstallImpl(SignalAction action) {
|
||||
struct sigaction act;
|
||||
act.sa_handler = NULL;
|
||||
act.sa_sigaction = action;
|
||||
|
|
|
@ -38,7 +38,7 @@ uintptr_t SignalHandler::GetLinkRegister(const mcontext_t& mcontext) {
|
|||
}
|
||||
|
||||
|
||||
void SignalHandler::Install(SignalAction action) {
|
||||
void SignalHandler::InstallImpl(SignalAction action) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
|
|
|
@ -57,8 +57,8 @@ void ThreadInterrupter::InterruptThread(OSThread* thread) {
|
|||
|
||||
|
||||
void ThreadInterrupter::InstallSignalHandler() {
|
||||
SignalHandler::Install(
|
||||
ThreadInterrupterAndroid::ThreadInterruptSignalHandler);
|
||||
SignalHandler::Install<
|
||||
ThreadInterrupterAndroid::ThreadInterruptSignalHandler>();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -54,7 +54,8 @@ void ThreadInterrupter::InterruptThread(OSThread* thread) {
|
|||
|
||||
|
||||
void ThreadInterrupter::InstallSignalHandler() {
|
||||
SignalHandler::Install(ThreadInterrupterLinux::ThreadInterruptSignalHandler);
|
||||
SignalHandler::Install<
|
||||
ThreadInterrupterLinux::ThreadInterruptSignalHandler>();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -55,7 +55,8 @@ void ThreadInterrupter::InterruptThread(OSThread* thread) {
|
|||
|
||||
|
||||
void ThreadInterrupter::InstallSignalHandler() {
|
||||
SignalHandler::Install(ThreadInterrupterMacOS::ThreadInterruptSignalHandler);
|
||||
SignalHandler::Install<
|
||||
ThreadInterrupterMacOS::ThreadInterruptSignalHandler>();
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue