From 77f302a78dc8567e4eb28a2ce8090ee466ad5b58 Mon Sep 17 00:00:00 2001
From: Angus Gratton <gus@projectgus.com>
Date: Thu, 10 Mar 2016 12:28:38 +1100
Subject: [PATCH] Add stack memory dump to fatal exception handler

---
 core/app_main.c          | 23 ++++++++++++++++++++++-
 core/exception_vectors.S |  7 ++++++-
 2 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/core/app_main.c b/core/app_main.c
index 2f4f7f1..d057598 100644
--- a/core/app_main.c
+++ b/core/app_main.c
@@ -85,6 +85,7 @@ static void zero_bss(void);
 static void init_networking(uint8_t *phy_info, uint8_t *mac_addr);
 static void init_g_ic(void);
 static void dump_excinfo(void);
+static void dump_stack(uint32_t *sp);
 static void user_start_phase2(void);
 static void dump_flash_sector(uint32_t start_sector, uint32_t length);
 static void dump_flash_config_sectors(uint32_t start_sector);
@@ -147,7 +148,7 @@ static void IRAM set_spi0_divisor(uint32_t divisor) {
 }
 
 // .text+0x148
-void IRAM sdk_user_fatal_exception_handler(void) {
+void IRAM sdk_user_fatal_exception_handler(uint32_t *sp) {
     if (!sdk_NMIIrqIsOn) {
         vPortEnterCritical();
         do {
@@ -157,6 +158,8 @@ void IRAM sdk_user_fatal_exception_handler(void) {
     Cache_Read_Disable();
     Cache_Read_Enable(0, 0, 1);
     dump_excinfo();
+    if (sp)
+        dump_stack(sp);
     uart_flush_txfifo(0);
     uart_flush_txfifo(1);
     sdk_system_restart_in_nmi();
@@ -363,6 +366,24 @@ static void dump_excinfo(void) {
     sdk_system_rtc_mem_write(0, excinfo, 32);
 }
 
+/* There's a lot of smart stuff we could do while dumping stack
+   but for now we just dump a likely looking section of stack
+   memory
+*/
+static void dump_stack(uint32_t *sp) {
+    printf("\nStack: SP=%p\n", sp);
+    for(uint32_t *p = sp; p < sp + 32; p += 4) {
+        if((intptr_t)p >= 0x3fffc000) {
+            break; /* approximate end of RAM */
+        }
+        printf("%p: %08x %08x %08x %08x\n", p, p[0], p[1], p[2], p[3]);
+        if(p[0] == 0xa5a5a5a5 && p[1] == 0xa5a5a5a5
+           && p[2] == 0xa5a5a5a5 && p[3] == 0xa5a5a5a5) {
+            break; /* FreeRTOS uses this pattern to mark untouched stack space */
+        }
+    }
+}
+
 // .irom0.text+0x398
 void sdk_wdt_init(void) {
     WDT.CTRL &= ~WDT_CTRL_ENABLE;
diff --git a/core/exception_vectors.S b/core/exception_vectors.S
index c1f1761..1980a0a 100644
--- a/core/exception_vectors.S
+++ b/core/exception_vectors.S
@@ -68,6 +68,7 @@ DebugExceptionVector:
         .type   DebugExceptionVector, @function
 
         wsr     a0, excsave2
+        mov     a2, a1
         call0   sdk_user_fatal_exception_handler
         rfi     2
 
@@ -81,6 +82,7 @@ KernelExceptionVector:
         .type   KernelExceptionVector, @function
 
         break   1, 0
+        mov     a2, a1
         call0   sdk_user_fatal_exception_handler
         rfe
 
@@ -98,6 +100,7 @@ DoubleExceptionVector:
         .type   DoubleExceptionVector, @function
 
         break   1, 4
+        mov     a2, a1
         call0   sdk_user_fatal_exception_handler
 
 /* Reset vector at offset 0x80 is unused, as vecbase gets reset to mask ROM
@@ -251,10 +254,11 @@ LoadStoreErrorHandler:
          * will have correct values */
         wsr     a0, sar
         l32i    a0, sp, 0
-        l32i    a2, sp, 0x08
+        /*l32i    a2, sp, 0x08*/
         l32i    a3, sp, 0x0c
         l32i    a4, sp, 0x10
         rsr     a1, excsave1
+        mov     a2, a1
         call0   sdk_user_fatal_exception_handler
 
         .balign 4
@@ -515,6 +519,7 @@ UserExceptionHandler:
         .literal_position
 .LUserFailOtherExceptionCause:
         break   1, 1
+        addi    a2, a1, 0x50 /* UserExceptionHandler pushes stack down 0x50 */
         call0   sdk_user_fatal_exception_handler
 
 /* _xt_user_exit is pushed onto the stack as part of the user exception handler,