You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2020/12/09 12:44:22 UTC

[incubator-nuttx] 05/06: arch/xtensa: Add a pseudo save area to be able to backtrace from interrupts

This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit 7075c989781d7a058d9bbc456c1507475fa57790
Author: Abdelatif Guettouche <ab...@espressif.com>
AuthorDate: Tue Dec 1 16:53:57 2020 +0000

    arch/xtensa: Add a pseudo save area to be able to backtrace from
    interrupts
    
    Signed-off-by: Abdelatif Guettouche <ab...@espressif.com>
---
 arch/xtensa/Kconfig                          |  7 +++
 arch/xtensa/src/common/xtensa_int_handlers.S | 69 +++++++++++++++++++++++-----
 arch/xtensa/src/common/xtensa_user_handler.S | 25 ++++++++--
 3 files changed, 86 insertions(+), 15 deletions(-)

diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index 1986457..6253c77 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -108,6 +108,13 @@ config XTENSA_BTDEPTH
 	---help---
 		This is the depth of the backtrace.
 
+config XTENSA_INTBACKTRACE
+	bool "Full backtrace from interrupts"
+	default n
+	depends on XTENSA_DUMPBT_ON_ASSERT
+	---help---
+		Add necessary logic to be able to have a full backtrace from an interrupt context.
+
 config XTENSA_USE_SEPARATE_IMEM
 	bool "Use a separate heap for internal memory"
 	default n
diff --git a/arch/xtensa/src/common/xtensa_int_handlers.S b/arch/xtensa/src/common/xtensa_int_handlers.S
index 16b4a0f..c75fefa 100644
--- a/arch/xtensa/src/common/xtensa_int_handlers.S
+++ b/arch/xtensa/src/common/xtensa_int_handlers.S
@@ -187,6 +187,29 @@ g_intstackbase:
 	and		a6, a6, a3				/* a6 = Set of pending, enabled interrupts for this level */
 	beqz	a6, 1f						/* Nothing to do */
 
+  /* At this point, the exception frame should have been allocated and filled,
+   * and current sp points to the interrupt stack (if enabled). Copy the
+   * pre-exception's base save area below the current SP.
+   */
+
+#ifdef CONFIG_XTENSA_INTBACKTRACE
+  rsr  a0, EXCSAVE_1 + \level - 1  /* Get exception frame pointer stored in EXCSAVE_x */
+  l32i a3, a0, (4 * REG_A0)        /* Copy pre-exception a0 (return address) */
+  s32e a3, sp, -16
+  l32i a3, a0, (4 * REG_A1)        /* Copy pre-exception a1 (stack pointer) */
+  s32e a3, sp, -12
+
+  /* Backtracing only needs a0 and a1, no need to create full base save area.
+   * Also need to change current frame's return address to point to pre-exception's
+   * last run instruction.
+   */
+
+  rsr a0, EPC_1 + \level - 1  /* return address */
+  movi a4, 0xc0000000         /* constant with top 2 bits set (call size) */
+  or a0, a0, a4               /* set top 2 bits */
+  addx2 a0, a4, a0            /* clear top bit -- simulating call4 size   */
+#endif
+  
 	/* Call xtensa_int_decode passing the address of the register save area
 	 * as a parameter (A7).
 	 */
@@ -270,7 +293,7 @@ g_intstackbase:
 
 _xtensa_level1_handler:
 
-	mov		a0, sp							              /* sp == a1 */
+	mov		a0, sp							              /* Save SP in A0 */
 	addi	sp, sp, -(4 * XCPTCONTEXT_SIZE)   /* Allocate interrupt stack frame */
 	s32i	a0, sp, (4 * REG_A1)			        /* Save pre-interrupt SP */
 	rsr		a0, PS						                /* Save interruptee's PS */
@@ -280,6 +303,10 @@ _xtensa_level1_handler:
 	rsr		a0, EXCSAVE_1					            /* Save interruptee's a0 */
 	s32i	a0, sp, (4 * REG_A0)
 
+#ifdef CONFIG_XTENSA_INTBACKTRACE
+  wsr sp, EXCSAVE_1
+#endif
+
 	/* Save rest of interrupt context. */
 
 	s32i	a2, sp, (4 * REG_A2)
@@ -369,7 +396,7 @@ _xtensa_level1_handler:
 
 _xtensa_level2_handler:
 
-	mov		a0, sp							/* sp == a1 */
+	mov		a0, sp							/* Save SP in A0 */
 	addi	sp, sp, -(4 * XCPTCONTEXT_SIZE)	/* Allocate interrupt stack frame */
 	s32i	a0, sp, (4 * REG_A1)			/* Save pre-interrupt SP */
 	rsr		a0, EPS_2						/* Save interruptee's PS */
@@ -379,6 +406,10 @@ _xtensa_level2_handler:
 	rsr		a0, EXCSAVE_2					/* Save interruptee's a0 */
 	s32i	a0, sp, (4 * REG_A0)
 
+#ifdef CONFIG_XTENSA_INTBACKTRACE
+  wsr sp, EXCSAVE_2
+#endif
+
 	/* Save rest of interrupt context. */
 
 	s32i	a2, sp, (4 * REG_A2)
@@ -430,7 +461,7 @@ _xtensa_level2_handler:
 
 _xtensa_level3_handler:
 
-	mov		a0, sp							/* sp == a1 */
+	mov		a0, sp							/* Save SP in A0 */
 	addi	sp, sp, -(4 * XCPTCONTEXT_SIZE)	/* Allocate interrupt stack frame */
 	s32i	a0, sp, (4 * REG_A1)			/* Save pre-interrupt SP */
 	rsr		a0, EPS_3						/* Save interruptee's PS */
@@ -440,6 +471,10 @@ _xtensa_level3_handler:
 	rsr		a0, EXCSAVE_3					/* Save interruptee's a0 */
 	s32i	a0, sp, (4 * REG_A0)
 
+#ifdef CONFIG_XTENSA_INTBACKTRACE
+  wsr sp, EXCSAVE_3
+#endif
+
 	/* Save rest of interrupt context. */
 
 	s32i	a2, sp, (4 * REG_A2)
@@ -491,7 +526,7 @@ _xtensa_level3_handler:
 
 _xtensa_level4_handler:
 
-	mov		a0, sp							/* sp == a1 */
+	mov		a0, sp							/* Save SP in A0 */
 	addi	sp, sp, -(4 * XCPTCONTEXT_SIZE)	/* Allocate interrupt stack frame */
 	s32i	a0, sp, (4 * REG_A1)			/* Save pre-interrupt SP */
 	rsr		a0, EPS_4						/* Save interruptee's PS */
@@ -501,6 +536,10 @@ _xtensa_level4_handler:
 	rsr		a0, EXCSAVE_4					/* Save interruptee's a0 */
 	s32i	a0, sp, (4 * REG_A0)
 
+#ifdef CONFIG_XTENSA_INTBACKTRACE
+  wsr sp, EXCSAVE_4
+#endif
+
 	/* Save rest of interrupt context. */
 
 	s32i	a2, sp, (4 * REG_A2)
@@ -552,7 +591,7 @@ _xtensa_level4_handler:
 
 _xtensa_level5_handler:
 
-	mov		a0, sp							/* sp == a1 */
+	mov		a0, sp							/* Save SP in A0 */
 	addi	sp, sp, -(4 * XCPTCONTEXT_SIZE)	/* Allocate interrupt stack frame */
 	s32i	a0, sp, (4 * REG_A1)			/* Save pre-interrupt SP */
 	rsr		a0, EPS_5						/* Save interruptee's PS */
@@ -562,6 +601,10 @@ _xtensa_level5_handler:
 	rsr		a0, EXCSAVE_5					/* Save interruptee's a0 */
 	s32i	a0, sp, (4 * REG_A0)
 
+#ifdef CONFIG_XTENSA_INTBACKTRACE
+  wsr sp, EXCSAVE_5
+#endif
+
 	/* Save rest of interrupt context. */
 
 	s32i	a2, sp, (4 * REG_A2)
@@ -613,7 +656,7 @@ _xtensa_level5_handler:
 
 _xtensa_level6_handler:
 
-	mov		a0, sp							/* sp == a1 */
+	mov		a0, sp							/* Save SP in A0 */
 	addi	sp, sp, -(4 * XCPTCONTEXT_SIZE)	/* Allocate interrupt stack frame */
 	s32i	a0, sp, (4 * REG_A1)			/* Save pre-interrupt SP */
 	rsr		a0, EPS_6						/* Save interruptee's PS */
@@ -623,6 +666,10 @@ _xtensa_level6_handler:
 	rsr		a0, EXCSAVE_6					/* Save interruptee's a0 */
 	s32i	a0, sp, (4 * REG_A0)
 
+#ifdef CONFIG_XTENSA_INTBACKTRACE
+  wsr sp, EXCSAVE_6
+#endif
+
 	/* Save rest of interrupt context. */
 
 	s32i	a2, sp, (4 * REG_A2)
@@ -713,7 +760,7 @@ _xtensa_level2_handler:
 #if 1
 	/* For now, just panic */
 
-	mov		a0, sp							/* sp == a1 */
+	mov		a0, sp							/* Save SP in A0 */
 	addi	sp, sp, -(4 * XCPTCONTEXT_SIZE)	/* Allocate interrupt stack frame */
 	s32i	a0, sp, (4 * REG_A1)			/* Save pre-interrupt SP */
 	rsr		a0, EPS_2						/* Save interruptee's PS */
@@ -747,7 +794,7 @@ _xtensa_level3_handler:
 #if 1
 	/* For now, just panic */
 
-	mov		a0, sp							/* sp == a1 */
+	mov		a0, sp							/* Save SP in A0 */
 	addi	sp, sp, -(4 * XCPTCONTEXT_SIZE)	/* Allocate interrupt stack frame */
 	s32i	a0, sp, (4 * REG_A1)			/* Save pre-interrupt SP */
 	rsr		a0, EPS_3						/* Save interruptee's PS */
@@ -783,7 +830,7 @@ _xtensa_level4_handler:
 #if 1
 	/* For now, just panic */
 
-	mov		a0, sp							/* sp == a1 */
+	mov		a0, sp							/* Save SP in A0 */
 	addi	sp, sp, -(4 * XCPTCONTEXT_SIZE)	/* Allocate interrupt stack frame */
 	s32i	a0, sp, (4 * REG_A1)			/* Save pre-interrupt SP */
 	rsr		a0, EPS_4						/* Save interruptee's PS */
@@ -819,7 +866,7 @@ _xtensa_level5_handler:
 #if 1
 	/* For now, just panic */
 
-	mov		a0, sp							/* sp == a1 */
+	mov		a0, sp							/* Save SP in A0 */
 	addi	sp, sp, -(4 * XCPTCONTEXT_SIZE)	/* Allocate interrupt stack frame */
 	s32i	a0, sp, (4 * REG_A1)			/* Save pre-interrupt SP */
 	rsr		a0, EPS_5						/* Save interruptee's PS */
@@ -855,7 +902,7 @@ _xtensa_level6_handler:
 #if 1
 	/* For now, just panic */
 
-	mov		a0, sp							/* sp == a1 */
+	mov		a0, sp							/* Save SP in A0 */
 	addi	sp, sp, -(4 * XCPTCONTEXT_SIZE)	/* Allocate interrupt stack frame */
 	s32i	a0, sp, (4 * REG_A1)			/* Save pre-interrupt SP */
 	rsr		a0, EPS_6						/* Save interruptee's PS */
diff --git a/arch/xtensa/src/common/xtensa_user_handler.S b/arch/xtensa/src/common/xtensa_user_handler.S
index bc01f53..5fb94f6 100644
--- a/arch/xtensa/src/common/xtensa_user_handler.S
+++ b/arch/xtensa/src/common/xtensa_user_handler.S
@@ -193,7 +193,7 @@ _xtensa_user_handler:
 
 	/* Allocate exception frame and save minimal context. */
 
-	mov		a0, sp							/* sp == a1 */
+	mov		a0, sp							/* Save SP in A0 */
 	addi	sp, sp, -(4 * XCPTCONTEXT_SIZE)	/* Allocate interrupt stack frame */
 	s32i	a0, sp, (4 * REG_A1)			/* Save pre-interrupt SP */
 	rsr		a0, PS							/* Save interruptee's PS */
@@ -224,7 +224,24 @@ _xtensa_user_handler:
 	movi	a0, PS_INTLEVEL(XCHAL_EXCM_LEVEL) | PS_UM | PS_WOE
 #endif
 	wsr		a0, PS
-	rsync
+
+  /* Create pseudo base save area. At this point, sp is still pointing to the
+   * allocated and filled exception stack frame.
+   */
+
+#ifdef CONFIG_XTENSA_INTBACKTRACE
+  l32i    a3, sp, (4 * REG_A0)     /* Copy pre-exception a0 (return address) */
+  s32e    a3, sp, -16
+  l32i    a3, sp, (4 * REG_A1)     /* Copy pre-exception a1 (stack pointer) */
+  s32e    a3, sp, -12
+  rsr     a0, EPC_1                /* return address for debug backtrace */
+  movi    a4, 0xc0000000           /* constant with top 2 bits set (call size) */
+  rsync                            /* wait for WSR.PS to complete */
+  or      a0, a0, a4               /* set top 2 bits */
+  addx2   a0, a4, a0               /* clear top bit -- thus simulating call4 size */
+#else
+  rsync                            /* wait for WSR.PS to complete */
+#endif
 
 	/* Call xtensa_user, passing both the EXCCAUSE and a pointer to the
 	 * beginning of the register save area.
@@ -284,7 +301,7 @@ _xtensa_syscall_handler:
 
 	/* Allocate stack frame and save A0, A1, and PS */
 
-	mov		a0, sp							/* sp == a1 */
+	mov		a0, sp							/* Save SP in A0 */
 	addi	sp, sp, -(4 * XCPTCONTEXT_SIZE)	/* Allocate interrupt stack frame */
 	s32i	a0, sp, (4 * REG_A1)			/* Save pre-interrupt SP */
 	rsr		a0, PS							/* Save interruptee's PS */
@@ -451,7 +468,7 @@ _xtensa_coproc_handler:
 
 	/* For now, just panic */
 
-	mov		a0, sp							/* sp == a1 */
+	mov		a0, sp							/* Save SP in A0 */
 	addi	sp, sp, -(4 * XCPTCONTEXT_SIZE)	/* Allocate interrupt stack frame */
 	s32i	a0, sp, (4 * REG_A1)			/* Save pre-interrupt SP */
 	rsr		a0, PS							/* Save interruptee's PS */