diff options
Diffstat (limited to 'runtime/arch/arm/fault_handler_arm.cc')
-rw-r--r-- | runtime/arch/arm/fault_handler_arm.cc | 18 |
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) { |