summaryrefslogtreecommitdiffstats
path: root/runtime/arch
diff options
context:
space:
mode:
authorDave Allison <dallison@google.com>2014-08-26 11:07:58 -0700
committerDave Allison <dallison@google.com>2014-08-27 12:47:44 -0700
commit8ce6b9040747054b444a7fa706503cd257801936 (patch)
tree04712170addb252d307ef9015abfc9bfc2b73581 /runtime/arch
parenta0a0da29e7d4d5c1bd471c49f1a4b6ec98fb767a (diff)
downloadart-8ce6b9040747054b444a7fa706503cd257801936.zip
art-8ce6b9040747054b444a7fa706503cd257801936.tar.gz
art-8ce6b9040747054b444a7fa706503cd257801936.tar.bz2
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
Diffstat (limited to 'runtime/arch')
-rw-r--r--runtime/arch/arm/fault_handler_arm.cc18
-rw-r--r--runtime/arch/arm64/fault_handler_arm64.cc14
-rw-r--r--runtime/arch/x86/fault_handler_x86.cc26
-rw-r--r--runtime/arch/x86/quick_entrypoints_x86.S13
-rw-r--r--runtime/arch/x86_64/quick_entrypoints_x86_64.S14
5 files changed, 85 insertions, 0 deletions
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index 28b69ec..564fcba 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -16,6 +16,7 @@
#include "fault_handler.h"
+
#include <sys/ucontext.h>
#include "base/macros.h"
#include "base/hex_dump.h"
@@ -46,6 +47,23 @@ static uint32_t GetInstructionSize(uint8_t* pc) {
return instr_size;
}
+void FaultManager::HandleNestedSignal(int sig, siginfo_t* info, void* context) {
+ // Note that in this handler we set up the registers and return to
+ // longjmp directly rather than going through an assembly language stub. The
+ // reason for this is that longjmp is (currently) in ARM mode and that would
+ // require switching modes in the stub - incurring an unwanted relocation.
+
+ struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+ struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
+ Thread* self = Thread::Current();
+ CHECK(self != nullptr); // This will cause a SIGABRT if self is nullptr.
+
+ sc->arm_r0 = reinterpret_cast<uintptr_t>(*self->GetNestedSignalState());
+ sc->arm_r1 = 1;
+ sc->arm_pc = reinterpret_cast<uintptr_t>(longjmp);
+ VLOG(signals) << "longjmp address: " << reinterpret_cast<void*>(sc->arm_pc);
+}
+
void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
mirror::ArtMethod** out_method,
uintptr_t* out_return_pc, uintptr_t* out_sp) {
diff --git a/runtime/arch/arm64/fault_handler_arm64.cc b/runtime/arch/arm64/fault_handler_arm64.cc
index b5948cb..687d232 100644
--- a/runtime/arch/arm64/fault_handler_arm64.cc
+++ b/runtime/arch/arm64/fault_handler_arm64.cc
@@ -37,6 +37,20 @@ extern "C" void art_quick_implicit_suspend();
namespace art {
+void FaultManager::HandleNestedSignal(int sig, siginfo_t* info, void* context) {
+ // To match the case used in ARM we return directly to the longjmp function
+ // rather than through a trivial assembly language stub.
+
+ struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+ struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
+ Thread* self = Thread::Current();
+ CHECK(self != nullptr); // This will cause a SIGABRT if self is nullptr.
+
+ sc->regs[0] = reinterpret_cast<uintptr_t>(*self->GetNestedSignalState());
+ sc->regs[1] = 1;
+ sc->pc = reinterpret_cast<uintptr_t>(longjmp);
+}
+
void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
mirror::ArtMethod** out_method,
uintptr_t* out_return_pc, uintptr_t* out_sp) {
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 @@ extern "C" void art_quick_test_suspend();
#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 @@ static uint32_t GetInstructionSize(const uint8_t* pc) {
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) {
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index a21d672..337e5fe 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1369,5 +1369,18 @@ DEFINE_FUNCTION art_quick_string_compareto
ret
END_FUNCTION art_quick_string_compareto
+// Return from a nested signal:
+// Entry:
+// eax: address of jmp_buf in TLS
+
+DEFINE_FUNCTION art_nested_signal_return
+ SETUP_GOT_NOSAVE // sets %ebx for call into PLT
+ movl LITERAL(1), %ecx
+ pushl %ecx // second arg to longjmp (1)
+ pushl %eax // first arg to longjmp (jmp_buf)
+ call PLT_SYMBOL(longjmp)
+ int3 // won't get here.
+END_FUNCTION art_nested_signal_return
+
// TODO: implement these!
UNIMPLEMENTED art_quick_memcmp16
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index e9b5a72..e68cfbc 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -1593,3 +1593,17 @@ DEFINE_FUNCTION art_quick_assignable_from_code
RESTORE_FP_CALLEE_SAVE_FRAME
ret
END_FUNCTION art_quick_assignable_from_code
+
+
+// Return from a nested signal:
+// Entry:
+// rdi: address of jmp_buf in TLS
+
+DEFINE_FUNCTION art_nested_signal_return
+ // first arg to longjmp is already in correct register
+ movq LITERAL(1), %rsi // second arg to longjmp (1)
+ call PLT_SYMBOL(longjmp)
+ int3 // won't get here
+END_FUNCTION art_nested_signal_return
+
+