From 981c87899b565a9def5f12fc6ac337cf93078bf3 Mon Sep 17 00:00:00 2001
From: Angus Gratton <gus@projectgus.com>
Date: Sun, 15 May 2016 10:36:33 +1000
Subject: [PATCH] Add heap information to fatal exception & abort dumps

---
 FreeRTOS/Source/portable/esp8266/port.c |  5 ++--
 core/debug_dumps.c                      | 39 +++++++++++++++++++++++++
 core/include/debug_dumps.h              |  5 +++-
 core/include/xtensa_ops.h               |  2 +-
 4 files changed, 47 insertions(+), 4 deletions(-)

diff --git a/FreeRTOS/Source/portable/esp8266/port.c b/FreeRTOS/Source/portable/esp8266/port.c
index 21a0d55..a9dac2d 100644
--- a/FreeRTOS/Source/portable/esp8266/port.c
+++ b/FreeRTOS/Source/portable/esp8266/port.c
@@ -73,6 +73,7 @@
 #include <malloc.h>
 #include <unistd.h>
 #include <stdio.h>
+#include <xtensa_ops.h>
 
 #include "FreeRTOS.h"
 #include "task.h"
@@ -87,7 +88,7 @@ char level1_int_disabled;
    After tasks start, task stacks are all allocated from the heap and
    FreeRTOS checks for stack overflow.
 */
-static uint32_t xPortSupervisorStackPointer;
+uint32_t xPortSupervisorStackPointer;
 
 /*
  * Stack initialization
@@ -220,7 +221,7 @@ size_t xPortGetFreeHeapSize( void )
 
     uint32_t sp = xPortSupervisorStackPointer;
     if(sp == 0) /* scheduler not started */
-        __asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp));
+        SP(sp);
     return sp - brk_val + mi.fordblks;
 }
 
diff --git a/core/debug_dumps.c b/core/debug_dumps.c
index 15396ac..8b20c1b 100644
--- a/core/debug_dumps.c
+++ b/core/debug_dumps.c
@@ -11,6 +11,8 @@
 #include <stdio.h>
 #include <FreeRTOS.h>
 #include <task.h>
+#include <malloc.h>
+#include <unistd.h>
 
 #include "debug_dumps.h"
 #include "common_macros.h"
@@ -156,18 +158,55 @@ static void fatal_exception_handler_inner(uint32_t *sp, bool registers_saved_on_
         }
         dump_stack(sp);
     }
+    dump_heapinfo();
     uart_flush_txfifo(0);
     uart_flush_txfifo(1);
     sdk_system_restart_in_nmi();
     while(1) {}
 }
 
+void dump_heapinfo(void)
+{
+    extern char _heap_start;
+    extern uint32_t xPortSupervisorStackPointer;
+    struct mallinfo mi = mallinfo();
+    uint32_t brk_val = (uint32_t) sbrk(0);
+    uint32_t sp = xPortSupervisorStackPointer;
+    if(sp == 0) {
+        SP(sp);
+    }
+
+    /* Total free heap is all memory that could be allocated via
+       malloc (assuming fragmentation doesn't become a problem) */
+    printf("\nFree Heap: %d\n", sp - brk_val + mi.fordblks);
+
+    /* delta between brk & supervisor sp is the contiguous memory
+       region that is available to be put into heap space via
+       brk(). */
+    printf("_heap_start %p brk 0x%08x supervisor sp 0x%08x sp-brk %d bytes\n",
+           &_heap_start, brk_val, sp, sp-brk_val);
+
+    /* arena/fordblks/uordblks determines the amount of free space
+      inside the heap region already added via brk(). May be
+      fragmented.
+
+       The values in parentheses are the values used internally by
+       nano-mallocr.c, the field names outside parentheses are the
+       POSIX compliant field names of the mallinfo structure.
+
+       "arena" should be equal to brk-_heap_start ie total size available.
+     */
+    printf("arena (total_size) %d fordblks (free_size) %d uordblocks (used_size) %d\n",
+           mi.arena, mi.fordblks, mi.uordblks);
+}
+
 /* Main part of abort handler, can be run from flash to save some
    IRAM.
 */
 static void abort_handler_inner(uint32_t *caller, uint32_t *sp) {
     printf("abort() invoked at %p.\n", caller);
     dump_stack(sp);
+    dump_heapinfo();
     uart_flush_txfifo(0);
     uart_flush_txfifo(1);
     sdk_system_restart_in_nmi();
diff --git a/core/include/debug_dumps.h b/core/include/debug_dumps.h
index 809b87a..ab3c972 100644
--- a/core/include/debug_dumps.h
+++ b/core/include/debug_dumps.h
@@ -10,9 +10,12 @@
 #define _DEBUG_DUMPS_H
 #include <stdint.h>
 
-/* Dump stack memory starting from stack pointer address sp. */
+/* Dump stack memory to stdout, starting from stack pointer address sp. */
 void dump_stack(uint32_t *sp);
 
+/* Dump heap statistics to stdout */
+void dump_heapinfo(void);
+
 /* Called from exception_vectors.S when a fatal exception occurs.
 
    Probably not useful to be called in other contexts.
diff --git a/core/include/xtensa_ops.h b/core/include/xtensa_ops.h
index 1ef68e9..52eba2a 100644
--- a/core/include/xtensa_ops.h
+++ b/core/include/xtensa_ops.h
@@ -19,7 +19,7 @@
  * Note that the compiler will push a stack frame (minimum 16 bytes)
  * in the prelude of a C function that calls any other functions.
  */
-#define SP(var) asm volatile ("mov %0, a1" : "=r" (var));
+#define SP(var) asm volatile ("mov %0, a1" : "=r" (var))
 
 /* Read the function return address to a variable.
  *