Skip to content

Commit 8bd4f24

Browse files
mrkhldndkalowsk
authored andcommitted
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: Mark Holden <[email protected]>
1 parent 5d52e39 commit 8bd4f24

File tree

7 files changed

+108
-56
lines changed

7 files changed

+108
-56
lines changed

arch/arm/core/cortex_a_r/swap_helper.S

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,12 +336,14 @@ _context_switch:
336336

337337
_oops:
338338
/*
339-
* Pass the exception frame to z_do_kernel_oops. r0 contains the
340-
* exception reason.
339+
* Pass the exception frame to z_do_kernel_oops.
341340
*/
342341
cps #MODE_SYS
343342
mov r0, sp
344343
cps #MODE_SVC
344+
/* Zero callee_regs and exc_return (only used on Cortex-M) */
345+
mov r1, #0
346+
mov r2, #0
345347
bl z_do_kernel_oops
346348
b z_arm_int_exit
347349

arch/arm/core/cortex_a_r/switch.S

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,12 @@ offload:
150150

151151
_oops:
152152
/*
153-
* Pass the exception frame to z_do_kernel_oops. r0 contains the
154-
* exception reason.
153+
* Pass the exception frame to z_do_kernel_oops.
155154
*/
156155
mov r0, sp
156+
/* Zero callee_regs and exc_return (only used on Cortex-M) */
157+
mov r1, #0
158+
mov r2, #0
157159
bl z_do_kernel_oops
158160

159161
inv:

arch/arm/core/cortex_m/fault.c

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -40,54 +40,6 @@ LOG_MODULE_DECLARE(os, CONFIG_KERNEL_LOG_LEVEL);
4040
#define EACD(edr) (((edr) & SYSMPU_EDR_EACD_MASK) >> SYSMPU_EDR_EACD_SHIFT)
4141
#endif
4242

43-
/* Exception Return (EXC_RETURN) is provided in LR upon exception entry.
44-
* It is used to perform an exception return and to detect possible state
45-
* transition upon exception.
46-
*/
47-
48-
/* Prefix. Indicates that this is an EXC_RETURN value.
49-
* This field reads as 0b11111111.
50-
*/
51-
#define EXC_RETURN_INDICATOR_PREFIX (0xFF << 24)
52-
/* bit[0]: Exception Secure. The security domain the exception was taken to. */
53-
#define EXC_RETURN_EXCEPTION_SECURE_Pos 0
54-
#define EXC_RETURN_EXCEPTION_SECURE_Msk \
55-
BIT(EXC_RETURN_EXCEPTION_SECURE_Pos)
56-
#define EXC_RETURN_EXCEPTION_SECURE_Non_Secure 0
57-
#define EXC_RETURN_EXCEPTION_SECURE_Secure EXC_RETURN_EXCEPTION_SECURE_Msk
58-
/* bit[2]: Stack Pointer selection. */
59-
#define EXC_RETURN_SPSEL_Pos 2
60-
#define EXC_RETURN_SPSEL_Msk BIT(EXC_RETURN_SPSEL_Pos)
61-
#define EXC_RETURN_SPSEL_MAIN 0
62-
#define EXC_RETURN_SPSEL_PROCESS EXC_RETURN_SPSEL_Msk
63-
/* bit[3]: Mode. Indicates the Mode that was stacked from. */
64-
#define EXC_RETURN_MODE_Pos 3
65-
#define EXC_RETURN_MODE_Msk BIT(EXC_RETURN_MODE_Pos)
66-
#define EXC_RETURN_MODE_HANDLER 0
67-
#define EXC_RETURN_MODE_THREAD EXC_RETURN_MODE_Msk
68-
/* bit[4]: Stack frame type. Indicates whether the stack frame is a standard
69-
* integer only stack frame or an extended floating-point stack frame.
70-
*/
71-
#define EXC_RETURN_STACK_FRAME_TYPE_Pos 4
72-
#define EXC_RETURN_STACK_FRAME_TYPE_Msk BIT(EXC_RETURN_STACK_FRAME_TYPE_Pos)
73-
#define EXC_RETURN_STACK_FRAME_TYPE_EXTENDED 0
74-
#define EXC_RETURN_STACK_FRAME_TYPE_STANDARD EXC_RETURN_STACK_FRAME_TYPE_Msk
75-
/* bit[5]: Default callee register stacking. Indicates whether the default
76-
* stacking rules apply, or whether the callee registers are already on the
77-
* stack.
78-
*/
79-
#define EXC_RETURN_CALLEE_STACK_Pos 5
80-
#define EXC_RETURN_CALLEE_STACK_Msk BIT(EXC_RETURN_CALLEE_STACK_Pos)
81-
#define EXC_RETURN_CALLEE_STACK_SKIPPED 0
82-
#define EXC_RETURN_CALLEE_STACK_DEFAULT EXC_RETURN_CALLEE_STACK_Msk
83-
/* bit[6]: Secure or Non-secure stack. Indicates whether a Secure or
84-
* Non-secure stack is used to restore stack frame on exception return.
85-
*/
86-
#define EXC_RETURN_RETURN_STACK_Pos 6
87-
#define EXC_RETURN_RETURN_STACK_Msk BIT(EXC_RETURN_RETURN_STACK_Pos)
88-
#define EXC_RETURN_RETURN_STACK_Non_Secure 0
89-
#define EXC_RETURN_RETURN_STACK_Secure EXC_RETURN_RETURN_STACK_Msk
90-
9143
/* Integrity signature for an ARMv8-M implementation */
9244
#if defined(CONFIG_ARMV7_M_ARMV8_M_FP)
9345
#define INTEGRITY_SIGNATURE_STD 0xFEFA125BUL
@@ -1112,9 +1064,7 @@ void z_arm_fault(uint32_t msp, uint32_t psp, uint32_t exc_return,
11121064
__ASSERT(esf != NULL,
11131065
"ESF could not be retrieved successfully. Shall never occur.");
11141066

1115-
#ifdef CONFIG_DEBUG_COREDUMP
1116-
z_arm_coredump_fault_sp = POINTER_TO_UINT(esf);
1117-
#endif
1067+
z_arm_set_fault_sp(esf, exc_return);
11181068

11191069
reason = fault_handle(esf, fault, &recoverable);
11201070
if (recoverable) {

arch/arm/core/cortex_m/swap_helper.S

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,7 @@ _oops:
447447
mov r1, sp /* pointer to _callee_saved_t */
448448
#endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE */
449449
#endif /* CONFIG_EXTRA_EXCEPTION_INFO */
450+
mov r2, lr /* EXC_RETURN */
450451
bl z_do_kernel_oops
451452
/* return from SVC exception is done here */
452453
#if defined(CONFIG_EXTRA_EXCEPTION_INFO)

arch/arm/core/fatal.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,15 +101,18 @@ void z_arm_fatal_error(unsigned int reason, const struct arch_esf *esf)
101101
*
102102
* @param esf exception frame
103103
* @param callee_regs Callee-saved registers (R4-R11)
104+
* @param exc_return EXC_RETURN value present in LR after exception entry.
104105
*/
105-
void z_do_kernel_oops(const struct arch_esf *esf, _callee_saved_t *callee_regs)
106+
void z_do_kernel_oops(const struct arch_esf *esf, _callee_saved_t *callee_regs, uint32_t exc_return)
106107
{
107108
#if !(defined(CONFIG_EXTRA_EXCEPTION_INFO) && defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE))
108109
ARG_UNUSED(callee_regs);
109110
#endif
110111
/* Stacked R0 holds the exception reason. */
111112
unsigned int reason = esf->basic.r0;
112113

114+
z_arm_set_fault_sp(esf, exc_return);
115+
113116
#if defined(CONFIG_USERSPACE)
114117
if (z_arm_preempted_thread_in_user_mode(esf)) {
115118
/*

arch/arm/include/cortex_a_r/exception.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ static ALWAYS_INLINE bool arch_is_in_nested_exception(const struct arch_esf *esf
4343
return (arch_curr_cpu()->arch.exc_depth > 1U) ? (true) : (false);
4444
}
4545

46+
/**
47+
* @brief No current implementation where core dump is not supported
48+
*
49+
* @param esf exception frame
50+
* @param exc_return EXC_RETURN value present in LR after exception entry.
51+
*/
52+
static ALWAYS_INLINE void z_arm_set_fault_sp(const struct arch_esf *esf, uint32_t exc_return)
53+
{}
54+
4655
#if defined(CONFIG_USERSPACE)
4756
/*
4857
* This function is used by privileged code to determine if the thread

arch/arm/include/cortex_m/exception.h

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,54 @@ extern volatile irq_offload_routine_t offload_routine;
3939
*/
4040
#define AIRCR_VECT_KEY_PERMIT_WRITE 0x05FAUL
4141

42+
/* Exception Return (EXC_RETURN) is provided in LR upon exception entry.
43+
* It is used to perform an exception return and to detect possible state
44+
* transition upon exception.
45+
*/
46+
47+
/* Prefix. Indicates that this is an EXC_RETURN value.
48+
* This field reads as 0b11111111.
49+
*/
50+
#define EXC_RETURN_INDICATOR_PREFIX (0xFF << 24)
51+
/* bit[0]: Exception Secure. The security domain the exception was taken to. */
52+
#define EXC_RETURN_EXCEPTION_SECURE_Pos 0
53+
#define EXC_RETURN_EXCEPTION_SECURE_Msk \
54+
BIT(EXC_RETURN_EXCEPTION_SECURE_Pos)
55+
#define EXC_RETURN_EXCEPTION_SECURE_Non_Secure 0
56+
#define EXC_RETURN_EXCEPTION_SECURE_Secure EXC_RETURN_EXCEPTION_SECURE_Msk
57+
/* bit[2]: Stack Pointer selection. */
58+
#define EXC_RETURN_SPSEL_Pos 2
59+
#define EXC_RETURN_SPSEL_Msk BIT(EXC_RETURN_SPSEL_Pos)
60+
#define EXC_RETURN_SPSEL_MAIN 0
61+
#define EXC_RETURN_SPSEL_PROCESS EXC_RETURN_SPSEL_Msk
62+
/* bit[3]: Mode. Indicates the Mode that was stacked from. */
63+
#define EXC_RETURN_MODE_Pos 3
64+
#define EXC_RETURN_MODE_Msk BIT(EXC_RETURN_MODE_Pos)
65+
#define EXC_RETURN_MODE_HANDLER 0
66+
#define EXC_RETURN_MODE_THREAD EXC_RETURN_MODE_Msk
67+
/* bit[4]: Stack frame type. Indicates whether the stack frame is a standard
68+
* integer only stack frame or an extended floating-point stack frame.
69+
*/
70+
#define EXC_RETURN_STACK_FRAME_TYPE_Pos 4
71+
#define EXC_RETURN_STACK_FRAME_TYPE_Msk BIT(EXC_RETURN_STACK_FRAME_TYPE_Pos)
72+
#define EXC_RETURN_STACK_FRAME_TYPE_EXTENDED 0
73+
#define EXC_RETURN_STACK_FRAME_TYPE_STANDARD EXC_RETURN_STACK_FRAME_TYPE_Msk
74+
/* bit[5]: Default callee register stacking. Indicates whether the default
75+
* stacking rules apply, or whether the callee registers are already on the
76+
* stack.
77+
*/
78+
#define EXC_RETURN_CALLEE_STACK_Pos 5
79+
#define EXC_RETURN_CALLEE_STACK_Msk BIT(EXC_RETURN_CALLEE_STACK_Pos)
80+
#define EXC_RETURN_CALLEE_STACK_SKIPPED 0
81+
#define EXC_RETURN_CALLEE_STACK_DEFAULT EXC_RETURN_CALLEE_STACK_Msk
82+
/* bit[6]: Secure or Non-secure stack. Indicates whether a Secure or
83+
* Non-secure stack is used to restore stack frame on exception return.
84+
*/
85+
#define EXC_RETURN_RETURN_STACK_Pos 6
86+
#define EXC_RETURN_RETURN_STACK_Msk BIT(EXC_RETURN_RETURN_STACK_Pos)
87+
#define EXC_RETURN_RETURN_STACK_Non_Secure 0
88+
#define EXC_RETURN_RETURN_STACK_Secure EXC_RETURN_RETURN_STACK_Msk
89+
4290
/*
4391
* The current executing vector is found in the IPSR register. All
4492
* IRQs and system exceptions are considered as interrupt context.
@@ -184,6 +232,43 @@ static ALWAYS_INLINE void z_arm_clear_faults(void)
184232
#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
185233
}
186234

235+
/**
236+
* @brief Set z_arm_coredump_fault_sp to stack pointer value expected by GDB
237+
*
238+
* @param esf exception frame
239+
* @param exc_return EXC_RETURN value present in LR after exception entry.
240+
*/
241+
static ALWAYS_INLINE void z_arm_set_fault_sp(const struct arch_esf *esf, uint32_t exc_return)
242+
{
243+
#ifdef CONFIG_DEBUG_COREDUMP
244+
z_arm_coredump_fault_sp = POINTER_TO_UINT(esf);
245+
#if defined(CONFIG_ARMV7_M_ARMV8_M_MAINLINE) || defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
246+
/* Gdb expects a stack pointer that does not include the exception stack frame in order to
247+
* unwind. So adjust the stack pointer accordingly.
248+
*/
249+
z_arm_coredump_fault_sp += sizeof(esf->basic);
250+
251+
#if defined(CONFIG_FPU) && defined(CONFIG_FPU_SHARING)
252+
/* Assess whether thread had been using the FP registers and add size of additional
253+
* registers if necessary
254+
*/
255+
if ((exc_return & EXC_RETURN_STACK_FRAME_TYPE_STANDARD) ==
256+
EXC_RETURN_STACK_FRAME_TYPE_EXTENDED) {
257+
z_arm_coredump_fault_sp += sizeof(esf->fpu);
258+
}
259+
#endif /* CONFIG_FPU && CONFIG_FPU_SHARING */
260+
261+
#ifndef CONFIG_ARMV8_M_MAINLINE
262+
if ((esf->basic.xpsr & SCB_CCR_STKALIGN_Msk) == SCB_CCR_STKALIGN_Msk) {
263+
/* Adjust stack alignment after PSR bit[9] detected */
264+
z_arm_coredump_fault_sp |= 0x4;
265+
}
266+
#endif /* !CONFIG_ARMV8_M_MAINLINE */
267+
268+
#endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE || CONFIG_ARMV6_M_ARMV8_M_BASELINE */
269+
#endif /* CONFIG_DEBUG_COREDUMP */
270+
}
271+
187272
/**
188273
* @brief Assess whether a debug monitor event should be treated as an error
189274
*

0 commit comments

Comments
 (0)