// address set to SignalHandlerWorkerReturn during SIGSEGV handling.
// It enables the unwinder to unwind stack from the handling code to the actual failure site.
NESTED_ENTRY CallSignalHandlerWrapper\Alignment, _TEXT, NoHandler
- alloc_stack (8 + \Alignment) // red zone + alignment
- PROLOG_PUSH "{r7, lr}"
+#ifndef __linux__
+__StackAllocationSize = (8 + 4 + \Alignment) // red zone + alignment
+ alloc_stack __StackAllocationSize
+ PROLOG_PUSH "{r7, r11, lr}"
bl EXTERNAL_C_FUNC(signal_handler_worker)
LOCAL_LABEL(SignalHandlerWorkerReturn\Alignment):
- EPILOG_POP "{r7, lr}"
- free_stack (8 + \Alignment)
+ EPILOG_POP "{r7, r11, lr}"
+ free_stack __StackAllocationSize
bx lr
+#else
+ // This unwind information is needed for lldb gdb doesn't use it and tries
+ // to read all registers from $sp + 12
+ .save {r0-r15}
+ .pad #12
+ bl EXTERNAL_C_FUNC(signal_handler_worker)
+LOCAL_LABEL(SignalHandlerWorkerReturn\Alignment):
+ // Following instruction are needed to say gdb that this frame is SIGTRAMP_FRAME
+ // and it can restore all registers from stack
+ mov.w r7, #119
+ svc 0
+#endif
NESTED_END CallSignalHandlerWrapper\Alignment, _TEXT
.endm
// preserve 8 bytes long red zone and align stack pointer
size_t* sp = (size_t*)ALIGN_DOWN(faultSp - 8, 8);
+#ifndef __linux__
+ size_t cpsr = (size_t)MCREG_Cpsr(ucontext->uc_mcontext);
+
// Build fake stack frame to enable the stack unwinder to unwind from signal_handler_worker to the faulting instruction
- // pushed LR
- *--sp = (size_t)MCREG_Pc(ucontext->uc_mcontext);
+ // align
+ --sp;
+ // pushed LR with correct mode bit
+ *--sp = (size_t)MCREG_Pc(ucontext->uc_mcontext) | ((cpsr & (1 << 5)) >> 5);
// pushed frame pointer
+ *--sp = (size_t)MCREG_R11(ucontext->uc_mcontext);
*--sp = (size_t)MCREG_R7(ucontext->uc_mcontext);
+#else
+ size_t size = ALIGN_UP(sizeof(ucontext->uc_mcontext), 8);
+ sp -= size / sizeof(size_t);
+ *(sigcontext *)sp = ucontext->uc_mcontext;
+#endif
// Switch the current context to the signal_handler_worker and the original stack
CONTEXT context2;