summaryrefslogtreecommitdiffstats
path: root/runtime/arch/arm/fault_handler_arm.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/arch/arm/fault_handler_arm.cc')
-rw-r--r--runtime/arch/arm/fault_handler_arm.cc18
1 files changed, 18 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) {