Commit 8bd4f244 authored by Mark Holden's avatar Mark Holden Committed by Dan Kalowsky
Browse files

coredump: ARM: Ensure sp in dump is set as gdb expects



Gdb is typically able to reconstruct the first two frames of the
failing stack using the "pc" and "lr" registers. After that, (if
the frame pointer is omitted) it appears to need the stack pointer
(sp register) to point to the top of the stack before a fatal
error occurred.

The ARM Cortex-M processors push registers r0-r3, r12, LR,
{possibly FPU registers}, PC, SPSR onto the stack before entering the
exception handler. We adjust the stack pointer back to the point
before these registers were pushed for preservation in the dump.

During k_oops/k_panic, the sp wasn't stored in the core dump at all.
Apply similar logic to store it when failures occur in that path.

Signed-off-by: default avatarMark Holden <mholden@meta.com>
parent 5d52e39a
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -336,12 +336,14 @@ _context_switch:

_oops:
    /*
     * Pass the exception frame to z_do_kernel_oops.  r0 contains the
     * exception reason.
     * Pass the exception frame to z_do_kernel_oops.
     */
    cps #MODE_SYS
    mov r0, sp
    cps #MODE_SVC
    /* Zero callee_regs and exc_return (only used on Cortex-M) */
    mov r1, #0
    mov r2, #0
    bl z_do_kernel_oops
    b z_arm_int_exit

+4 −2
Original line number Diff line number Diff line
@@ -150,10 +150,12 @@ offload:

_oops:
    /*
     * Pass the exception frame to z_do_kernel_oops.  r0 contains the
     * exception reason.
     * Pass the exception frame to z_do_kernel_oops.
     */
    mov r0, sp
    /* Zero callee_regs and exc_return (only used on Cortex-M) */
    mov r1, #0
    mov r2, #0
    bl z_do_kernel_oops

inv:
+1 −51
Original line number Diff line number Diff line
@@ -40,54 +40,6 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
#define EACD(edr)  (((edr) & SYSMPU_EDR_EACD_MASK) >> SYSMPU_EDR_EACD_SHIFT)
#endif

/* Exception Return (EXC_RETURN) is provided in LR upon exception entry.
 * It is used to perform an exception return and to detect possible state
 * transition upon exception.
 */

/* Prefix. Indicates that this is an EXC_RETURN value.
 * This field reads as 0b11111111.
 */
#define EXC_RETURN_INDICATOR_PREFIX     (0xFF << 24)
/* bit[0]: Exception Secure. The security domain the exception was taken to. */
#define EXC_RETURN_EXCEPTION_SECURE_Pos 0
#define EXC_RETURN_EXCEPTION_SECURE_Msk \
		BIT(EXC_RETURN_EXCEPTION_SECURE_Pos)
#define EXC_RETURN_EXCEPTION_SECURE_Non_Secure 0
#define EXC_RETURN_EXCEPTION_SECURE_Secure EXC_RETURN_EXCEPTION_SECURE_Msk
/* bit[2]: Stack Pointer selection. */
#define EXC_RETURN_SPSEL_Pos 2
#define EXC_RETURN_SPSEL_Msk BIT(EXC_RETURN_SPSEL_Pos)
#define EXC_RETURN_SPSEL_MAIN 0
#define EXC_RETURN_SPSEL_PROCESS EXC_RETURN_SPSEL_Msk
/* bit[3]: Mode. Indicates the Mode that was stacked from. */
#define EXC_RETURN_MODE_Pos 3
#define EXC_RETURN_MODE_Msk BIT(EXC_RETURN_MODE_Pos)
#define EXC_RETURN_MODE_HANDLER 0
#define EXC_RETURN_MODE_THREAD EXC_RETURN_MODE_Msk
/* bit[4]: Stack frame type. Indicates whether the stack frame is a standard
 * integer only stack frame or an extended floating-point stack frame.
 */
#define EXC_RETURN_STACK_FRAME_TYPE_Pos 4
#define EXC_RETURN_STACK_FRAME_TYPE_Msk BIT(EXC_RETURN_STACK_FRAME_TYPE_Pos)
#define EXC_RETURN_STACK_FRAME_TYPE_EXTENDED 0
#define EXC_RETURN_STACK_FRAME_TYPE_STANDARD EXC_RETURN_STACK_FRAME_TYPE_Msk
/* bit[5]: Default callee register stacking. Indicates whether the default
 * stacking rules apply, or whether the callee registers are already on the
 * stack.
 */
#define EXC_RETURN_CALLEE_STACK_Pos 5
#define EXC_RETURN_CALLEE_STACK_Msk BIT(EXC_RETURN_CALLEE_STACK_Pos)
#define EXC_RETURN_CALLEE_STACK_SKIPPED 0
#define EXC_RETURN_CALLEE_STACK_DEFAULT EXC_RETURN_CALLEE_STACK_Msk
/* bit[6]: Secure or Non-secure stack. Indicates whether a Secure or
 * Non-secure stack is used to restore stack frame on exception return.
 */
#define EXC_RETURN_RETURN_STACK_Pos 6
#define EXC_RETURN_RETURN_STACK_Msk BIT(EXC_RETURN_RETURN_STACK_Pos)
#define EXC_RETURN_RETURN_STACK_Non_Secure 0
#define EXC_RETURN_RETURN_STACK_Secure EXC_RETURN_RETURN_STACK_Msk

/* Integrity signature for an ARMv8-M implementation */
#if defined(CONFIG_ARMV7_M_ARMV8_M_FP)
#define INTEGRITY_SIGNATURE_STD 0xFEFA125BUL
@@ -1112,9 +1064,7 @@ void z_arm_fault(uint32_t msp, uint32_t psp, uint32_t exc_return,
	__ASSERT(esf != NULL,
		"ESF could not be retrieved successfully. Shall never occur.");

#ifdef CONFIG_DEBUG_COREDUMP
	z_arm_coredump_fault_sp = POINTER_TO_UINT(esf);
#endif
	z_arm_set_fault_sp(esf, exc_return);

	reason = fault_handle(esf, fault, &recoverable);
	if (recoverable) {
+1 −0
Original line number Diff line number Diff line
@@ -447,6 +447,7 @@ _oops:
    mov  r1, sp /* pointer to _callee_saved_t */
#endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE */
#endif /* CONFIG_EXTRA_EXCEPTION_INFO */
    mov r2, lr /* EXC_RETURN */
    bl z_do_kernel_oops
    /* return from SVC exception is done here */
#if defined(CONFIG_EXTRA_EXCEPTION_INFO)
+4 −1
Original line number Diff line number Diff line
@@ -101,8 +101,9 @@ void z_arm_fatal_error(unsigned int reason, const struct arch_esf *esf)
 *
 * @param esf exception frame
 * @param callee_regs Callee-saved registers (R4-R11)
 * @param exc_return EXC_RETURN value present in LR after exception entry.
 */
void z_do_kernel_oops(const struct arch_esf *esf, _callee_saved_t *callee_regs)
void z_do_kernel_oops(const struct arch_esf *esf, _callee_saved_t *callee_regs, uint32_t exc_return)
{
#if !(defined(CONFIG_EXTRA_EXCEPTION_INFO) && defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE))
	ARG_UNUSED(callee_regs);
@@ -110,6 +111,8 @@ void z_do_kernel_oops(const struct arch_esf *esf, _callee_saved_t *callee_regs)
	/* Stacked R0 holds the exception reason. */
	unsigned int reason = esf->basic.r0;

	z_arm_set_fault_sp(esf, exc_return);

#if defined(CONFIG_USERSPACE)
	if (z_arm_preempted_thread_in_user_mode(esf)) {
		/*
Loading