Handle nested signals
This allows for signals to be raised inside the ART signal handler.
This can occur when the JavaStackTraceHandler attempts to generate
a stack trace and something goes wrong.
It also fixes an issue where the fault manager was not being
correctly shut down inside the signal chaining code. In this
case the signal handler was not restored to the original.
Bug: 17006816
Bug: 17133266
(cherry picked from commit fabe91e0d558936ac26b98d2b4ee1af08f58831d)
Change-Id: I10730ef52d5d8d34610a5293253b3be6caf4829e
diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc
index 65a48f6..fb26f5f 100644
--- a/runtime/arch/x86/fault_handler_x86.cc
+++ b/runtime/arch/x86/fault_handler_x86.cc
@@ -35,12 +35,14 @@
#define CTX_EIP uc_mcontext->__ss.__rip
#define CTX_EAX uc_mcontext->__ss.__rax
#define CTX_METHOD uc_mcontext->__ss.__rdi
+#define CTX_JMP_BUF uc_mcontext->__ss.__rdi
#else
// 32 bit mac build.
#define CTX_ESP uc_mcontext->__ss.__esp
#define CTX_EIP uc_mcontext->__ss.__eip
#define CTX_EAX uc_mcontext->__ss.__eax
#define CTX_METHOD uc_mcontext->__ss.__eax
+#define CTX_JMP_BUF uc_mcontext->__ss.__eax
#endif
#elif defined(__x86_64__)
@@ -49,12 +51,15 @@
#define CTX_EIP uc_mcontext.gregs[REG_RIP]
#define CTX_EAX uc_mcontext.gregs[REG_RAX]
#define CTX_METHOD uc_mcontext.gregs[REG_RDI]
+#define CTX_RDI uc_mcontext.gregs[REG_RDI]
+#define CTX_JMP_BUF uc_mcontext.gregs[REG_RDI]
#else
// 32 bit linux build.
#define CTX_ESP uc_mcontext.gregs[REG_ESP]
#define CTX_EIP uc_mcontext.gregs[REG_EIP]
#define CTX_EAX uc_mcontext.gregs[REG_EAX]
#define CTX_METHOD uc_mcontext.gregs[REG_EAX]
+#define CTX_JMP_BUF uc_mcontext.gregs[REG_EAX]
#endif
//
@@ -76,6 +81,12 @@
#define EXT_SYM(sym) sym
#endif
+// Note this is different from the others (no underscore on 64 bit mac) due to
+// the way the symbol is defined in the .S file.
+// TODO: fix the symbols for 64 bit mac - there is a double underscore prefix for some
+// of them.
+extern "C" void art_nested_signal_return();
+
// Get the size of an instruction in bytes.
// Return 0 if the instruction is not handled.
static uint32_t GetInstructionSize(const uint8_t* pc) {
@@ -215,6 +226,21 @@
return pc - startpc;
}
+void FaultManager::HandleNestedSignal(int sig, siginfo_t* info, void* context) {
+ // For the Intel architectures we need to go to an assembly language
+ // stub. This is because the 32 bit call to longjmp is much different
+ // from the 64 bit ABI call and pushing things onto the stack inside this
+ // handler was unwieldy and ugly. The use of the stub means we can keep
+ // this code the same for both 32 and 64 bit.
+
+ Thread* self = Thread::Current();
+ CHECK(self != nullptr); // This will cause a SIGABRT if self is nullptr.
+
+ struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+ uc->CTX_JMP_BUF = reinterpret_cast<uintptr_t>(*self->GetNestedSignalState());
+ uc->CTX_EIP = reinterpret_cast<uintptr_t>(art_nested_signal_return);
+}
+
void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
mirror::ArtMethod** out_method,
uintptr_t* out_return_pc, uintptr_t* out_sp) {