]> granicus.if.org Git - esp-idf/commitdiff
Add option to automatically set a watchpoint at the end of the swapped-in task
authorJeroen Domburg <jeroen@espressif.com>
Mon, 9 Jan 2017 08:42:45 +0000 (16:42 +0800)
committerJeroen Domburg <jeroen@espressif.com>
Mon, 9 Jan 2017 08:42:45 +0000 (16:42 +0800)
components/esp32/include/esp_panic.h
components/esp32/panic.c
components/freertos/Kconfig
components/freertos/tasks.c

index 6aba6c5f481354c25337b3e81353fddce43735bf..ce4ea3c501c4d3f2a8a5a6002d8114014b1876df 100644 (file)
 
 #ifndef __ASSEMBLER__
 
+#include "esp_err.h"
+
 void esp_set_breakpoint_if_jtag(void *fn);
 
+#define ESP_WATCHPOINT_LOAD 0x40000000
+#define ESP_WATCHPOINT_STORE 0x80000000
+#define ESP_WATCHPOINT_ACCESS 0xC0000000
+
+esp_err_t esp_set_watchpoint(int no, void *adr, int size, int flags);
+void esp_clear_watchpoint(int no);
+
+
 #endif
 
 #endif
\ No newline at end of file
index 3cdbfb3e3977600f2f9de792c66fc3d0395fc1aa..b4a84aee8eaa20380ca3d1497ec39005d22ce5dc 100644 (file)
@@ -32,6 +32,7 @@
 #include "esp_gdbstub.h"
 #include "esp_panic.h"
 #include "esp_attr.h"
+#include "esp_err.h"
 
 /*
   Panic handlers; these get called when an unhandled exception occurs or the assembly-level
@@ -353,3 +354,50 @@ void esp_set_breakpoint_if_jtag(void *fn)
         setFirstBreakpoint((uint32_t)fn);
     }
 }
+
+
+esp_err_t esp_set_watchpoint(int no, void *adr, int size, int flags)
+{
+    int x;
+    if (no<0 || no>1) return ESP_ERR_INVALID_ARG;
+    if (flags&(~0xC0000000)) return ESP_ERR_INVALID_ARG;
+    int dbreakc=0x3F;
+    //We support watching 2^n byte values, from 1 to 64. Calculate the mask for that.
+    for (x=0; x<6; x++) {
+        if (size==(1<<x)) break;
+        dbreakc<<=1;
+    }
+    if (x==6) return ESP_ERR_INVALID_ARG;
+    //Mask mask and add in flags.
+    dbreakc=(dbreakc&0x3f)|flags;
+
+    if (no==0) {
+        asm volatile(
+            "wsr.dbreaka0 %0\n" \
+            "wsr.dbreakc0 %1\n" \
+            ::"r"(adr),"r"(dbreakc));
+    } else {
+        asm volatile(
+            "wsr.dbreaka1 %0\n" \
+            "wsr.dbreakc1 %1\n" \
+            ::"r"(adr),"r"(dbreakc));
+    }
+    return ESP_OK;
+}
+
+void esp_clear_watchpoint(int no)
+{
+    //Setting a dbreakc register to 0 makes it trigger on neither load nor store, effectively disabling it.
+    int dbreakc=0;
+    if (no==0) {
+        asm volatile(
+            "wsr.dbreakc0 %0\n" \
+            ::"r"(dbreakc));
+    } else {
+        asm volatile(
+            "wsr.dbreakc1 %0\n" \
+            ::"r"(dbreakc));
+    }
+}
+
+
index fe7e6afd88aaec2da4be67a9be6a3b2dd49fba4b..15178539b4358ab67ce93d8fa168163d0feb9921 100644 (file)
@@ -197,6 +197,22 @@ config FREERTOS_PORTMUX_DEBUG_RECURSIVE
         portMUX usage.
 endif #FREERTOS_UNICORE
 
+
+config FREERTOS_WATCHPOINT_END_OF_STACK
+    bool "Set a debug watchpoint at the end of each stack"
+    default n
+    help
+        FreeRTOS can check if a stack has overflown its bounds by checking either the value of
+        the stack pointer or by checking the integrity of canary bytes. (See FREERTOS_CHECK_STACKOVERFLOW
+        for more information.) These checks only happen on a context switch, and the situation that caused
+        the stack overflow may already be long gone by then. This option will use the debug memory 
+        watchpoint 1 (the second one) to allow breaking into the debugger (or panic'ing) as soon as any 
+        of the last 32 bytes on the stack of a task are overwritten. The side effect is that using gdb, you
+        effectively only have one watchpoint; the 2nd one is overwritten as soon as a task switch happens.
+        
+        When this watchpoint is hit, gdb will stop with a SIGTRAP message. When no OCD is attached, esp-idf
+        will panic on an unhandled debug exception.
+
 endif # FREERTOS_DEBUG_INTERNALS
 
 endmenu
index 159d96c5b2173a24ceea2870138f2355c49711de..72e7a1d33fe3a926045560eb217bad1a1a16b03e 100644 (file)
@@ -78,6 +78,7 @@ task.h is included from an application file. */
 
 #include "rom/ets_sys.h"
 #include "esp_newlib.h"
+#include "esp_panic.h"
 
 /* FreeRTOS includes. */
 #include "FreeRTOS.h"
@@ -2809,6 +2810,12 @@ void vTaskSwitchContext( void )
 
                traceTASK_SWITCHED_IN();
 
+#if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
+               //Set watchpoint 1 to watch the last 32 bytes of the stack.
+               esp_set_watchpoint(1, pxCurrentTCB[xPortGetCoreID()]->pxStack, 32, ESP_WATCHPOINT_STORE);
+#endif
+
+
        }
        portEXIT_CRITICAL_NESTED(irqstate);
 }