[En-Nut-Discussion] Post-mortem stack checks for Cortex-M
Philipp Burch
phip at hb9etc.ch
Fri Nov 14 18:14:47 CET 2014
Hi all,
as written in the other thread, I'm rather busy with sorting out system
crashes. To simplify that a bit, I extended the Cortex-M debug macro
somewhat: It can now also print a list of all alive threads together
with their current stack usage and a flag if the stack has been
corrupted or not. The configurator option is just implemented for the
TM4C family right now, but the exact same patch (see below) should work
for the other Cortex-M3/4 families as well. The patched code is included
in SVN r5891 in the devnut_tiva branch.
Cheers,
Philipp
Index: nut/conf/arch/cm3/tm4cfam.nut
===================================================================
--- nut/conf/arch/cm3/tm4cfam.nut (revision 5886)
+++ nut/conf/arch/cm3/tm4cfam.nut (working copy)
@@ -69,6 +69,20 @@
file = "include/cfg/cortex_debug.h"
},
{
+ macro = "DEBUG_THREADSTACK",
+ brief = "Enable post-mortem thread stack information",
+ description = "If this option is enabled, the exception
handler "..
+ "does a final iteration through all
threads and "..
+ "prints the free stack space for each
thread "..
+ "and if the stack of this thread could be "..
+ "corrupted.\n\n"..
+ "Beware, however, that the iteration
through "..
+ "the thread list could cause another
exception "..
+ "if the whole threading facility is
corrupt.",
+ flavor = "boolean",
+ file = "include/cfg/cortex_debug.h"
+ },
+ {
macro = "DEBUG_UART_NR",
brief = "Debug UART",
description = "Select the UART to use for low level
debugging",
Index: nut/arch/cm3/cmsis/cortex_debug.c
===================================================================
--- nut/arch/cm3/cmsis/cortex_debug.c (revision 5885)
+++ nut/arch/cm3/cmsis/cortex_debug.c (working copy)
@@ -143,6 +143,24 @@
#endif
}
+#ifdef DEBUG_THREADSTACK
+static void DebugPrintU32Dec(uint32_t val) {
+#ifdef DEBUG_MACRO
+ int i, nz = 0;
+ uint32_t div = 1000000000UL;
+ uint32_t digit;
+ for (i = 0; i < 10; ++i) {
+ digit = (val / div) % 10;
+ if (digit != 0 || i == 9) nz = 1;
+ if (nz) {
+ DebugPut('0' + digit);
+ }
+ div /= 10;
+ }
+#endif
+}
+#endif
+
static inline uint32_t bits(const uint32_t val, const uint32_t msbit,
const uint32_t lsbit)
{
return (val & ~(0xFFFFFFFF << (msbit + 1))) >> lsbit;
@@ -275,6 +293,27 @@
DebugPrint("\nSCB_SHCSR = 0x"); DebugPrintU32Hex(SCB->SHCSR);
DebugPrint("\n---------------------------------------------------\n");
+#ifdef DEBUG_THREADSTACK
+ /* This is post-mortem stack information. For each existing thread, the
+ * number of currently free stack bytes is printed, along with
+ * an information if the thread stack has most likely been corrupted.
+ */
+ NUTTHREADINFO *tdp;
+ DebugPrint("\nThread stack information:\n");
+ for (tdp = nutThreadList; tdp; tdp = tdp->td_next) {
+ DebugPrint(tdp->td_name);
+ DebugPrint(": ");
+ DebugPrintU32Dec((uint32_t)((uint8_t*)tdp->td_sp -
tdp->td_memory));
+ DebugPrint(" bytes free (");
+ if (*((uint32_t*)tdp->td_memory) != DEADBEEF) {
+ DebugPrint("CORRUPTED");
+ } else {
+ DebugPrint("OK");
+ }
+ DebugPrint(")\n");
+ }
+#endif
+
#ifdef DEBUG_BACKTRACE
/* These are experimental enhancements to the exception handler which
* allow to print out a stack dump and a call trace.
More information about the En-Nut-Discussion
mailing list