mirror of
https://github.com/esp8266/Arduino.git
synced 2025-07-02 14:22:55 +03:00
Hardware WDT Stack Dump Tool (#7010)
* Hardware WDT Stack Dump This Sketch demonstrates the use of a tool to print a stack dump at reboot after a Hardware WDT event. The module hwdt_app_entry.cpp writes a stack dump to the serial interface after a Hardware Watchdog Timer has struck and a new boot cycle has begun. The sketch must properly initialized the Serial port before the crash. hwdt_app_entry.cpp is the core file that does the work. * Corrected Style. Improved HWDT reset detectionat boot. * Style and typos * Update comments. * Improvements to reset reason determination. Improved comments. Added option to match the UART speed used by the sketch. Added option to print greeting at the start to indicate the HWDT stack dump code is active. Isolated logic for handling strings: one assuming they are not inited at the time the code is running and one that does. The later appears to be the case. * Style plus Fix issue with HWDT reason detection when sketch crashes too fast. Added sample sketch menu option for crashing with a function defined with a weak attribute via prototype, but never actually defined in full function form. eg. `void trouble(void){return;}` * Moved all configuration options to the top. Adjusted configuration option order for most likely to be used to the top. Tried to improve comments. Replace numbers with enum values. * Removed clutter of having an alternate printing method. Regular global strings have worked reliably. Tweaked reset reason detection. Reordered elements in global structure. Improve #if test for debug option Always improving comments. * Added delays around uart_div_modify. This appeara to resolve the lost data problem that occurs when printing after a flash upload using esptool. Curiously, esptool stub also uses similar delays. Word choices and description improvements. * Finished TODO looked at assembly of app_entry_redefinable to confirm no mixed up stack frame was created. Also removed no longer needed extra level of function calling. Use existing macros from uart_register,h to handle getting current UART speed. Added some missing `const`. * Comment changes. Added a few newlines to printing. Decreased the settling delay after the uart_div_modify call. * Improved comments. Print caution message when stack integrity checks failed. * Several corrections to set_uart_speed Comment improvements Added missing ";" * Removed unused include. Code cleanup. Comments. * Now runs from flash before SDK is started. Cache_Read_Enable working. Free 1K of IRAM and 200 bytes of DRAM. * Changed ICACHE size from 32K to 16K to avoid conflict with SDK or core selecting smaller 16K ICACHE. The Issue: Cache_Read_Enable does not clear the bit field when mapping IRAM to ICACHE on register 0x3FF00024. Thus, no problem upgrading from 16K to 32K; however, you cannot downgrade from 32K to 16K. These bits are cleared at boot. Improved uart data rate change handling. Update comments. * Added support to print ThunkStack. Adjustments to inline asm. Added "memory" when callx0 is used. * comment cleanup. added missing additional #if defined() Made structure name unique. Changed HWDT_INFO to HWDR_INFO_S. * Update style used for structure and typedef to match that used in core when snake case is used. Moved a constexpr block up a scope so that some #ifdef debug code compiles again. * Updated comments * Corrected new errors from upgrade to GCC 10.1 toolchain related to constexpr and casting integers to pointers. Cleared warning for asm. * Work around divide by 0 HWDT event under toolchain 10.1. * Changes to move feature into core. Making ready for selection via tools menu, updated defines to DEBUG_ESP_,,, format. Added HWDT and HWDT_NO4KEXTRA options to boards.txt.py. These options are selectable from Arduino IDE 'Tools->Debug Level' Converted macro names that use to be constexprs to uppercase. Update comments. Added comments to maintainers anotated by '//C' Revised example. * Fix stack character buffer length. * Updated comment to reflect support via Arduino IDE Tools menu. * Improve meshing of HWDT and NOEXTRA4K * Made compatible with `disable_extra4k_at_link_time()` usage. Changed to strings containing "no4kextra" to "noextra4k" to be consistant with original usage. Updated example to provide indications of which build options were used or resulted. Some comment cleanup. * CI style * Adjusted down the ROM Stack space for the extra 4K Heap option. If too large, a really bad crashes occurs. Updated the example to start WiFi. This helps double check ROM Stack space size is not too small at start. Removed stale comment. Changed cont stack check functions to make globally available. * Add replacement aes_unwrap for the debug HWDT option. Improves the SYS stack space available when using the extra 4K Heap option in conjunction with HWDT. Replaces the ROM AES buffer at 0x3FFFEA80 with one provided by malloc(). * Update umm_info_safe_printf_P to support default of unaligned PROGMEM strings. * Improve cont stack trace for yielding case. Check if cont stack is yielding to SYS, use g_pcont->sp_yield to limit the amount of the cont stack dumped. Generalized dev logic path to create a generalized debug function hwdt_pre_sdk_init_icache. * Added missed update to heap.cpp for change to use PSTR instead of PSTR4 * Updated comments and #if in aes_unwrap. * Update boards.txt
This commit is contained in:
82
libraries/esp8266/examples/HwdtStackDump/HwdtStackDump.ino
Normal file
82
libraries/esp8266/examples/HwdtStackDump/HwdtStackDump.ino
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
|
||||
There is a tool to print a stack dump at boot after a Hardware WDT
|
||||
reset. To use the Hardware WDT Reset stack dump tool, you can select HWDT or
|
||||
HWDT_NOEXTRA4K from the Arduino IDE menu "Tools->Debug Level" before
|
||||
building your sketch. Note, 'Tools->Debug port' selection is not needed or
|
||||
referenced for printing the HWDT stack dump.
|
||||
|
||||
When the ESP8266 restarts because of a Hardware WDT reset, the serial port
|
||||
speed defaults to 115200 bps. The HWDT stack dump will always print on port
|
||||
'Serial'.
|
||||
|
||||
To demonstrates this tool, this Sketch offers a few options for crashing the
|
||||
ESP8266 with and without a HWDT reset.
|
||||
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <Esp.h>
|
||||
#include <user_interface.h>
|
||||
#include <coredecls.h> // g_pcont - only needed for this debug demo
|
||||
|
||||
#ifndef STASSID
|
||||
#define STASSID "your-ssid"
|
||||
#define STAPSK "your-password"
|
||||
#endif
|
||||
|
||||
const char* ssid = STASSID;
|
||||
const char* password = STAPSK;
|
||||
|
||||
void setup(void) {
|
||||
WiFi.persistent(false); // w/o this a flash write occurs at every boot
|
||||
WiFi.mode(WIFI_OFF);
|
||||
Serial.begin(115200);
|
||||
delay(20); // This delay helps when using the 'Modified Serial monitor' otherwise it is not needed.
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
Serial.println(F("The Hardware Watchdog Timer Demo is starting ..."));
|
||||
Serial.println();
|
||||
|
||||
// We don't need this for this example; however, starting WiFi uses a little
|
||||
// more of the SYS stack.
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.begin(ssid, password);
|
||||
Serial.println(F("A WiFi connection attmpt has been started."));
|
||||
Serial.println();
|
||||
|
||||
// #define DEMO_NOEXTRA4K
|
||||
#ifdef DEMO_NOEXTRA4K
|
||||
/*
|
||||
When a call to disable_extra4k_at_link_time() is made, building with HWDT
|
||||
selected on the Arduino IDE menu "Tools->Debug Level", will have the same
|
||||
result as if built with HWDT_NOEXTRA4K selected.
|
||||
*/
|
||||
disable_extra4k_at_link_time();
|
||||
#endif
|
||||
|
||||
Serial.printf_P(PSTR("This example was built with%s an extra 4K of heap space (g_pcont == 0x%08lX)\r\n"),
|
||||
((uintptr_t)0x3FFFC000 < (uintptr_t)g_pcont) ? "" : "out",
|
||||
(uintptr_t)g_pcont);
|
||||
#if defined(DEBUG_ESP_HWDT) || defined(DEBUG_ESP_HWDT_NOEXTRA4K)
|
||||
Serial.print(F("and with the HWDT"));
|
||||
#if defined(DEBUG_ESP_HWDT_NOEXTRA4K)
|
||||
Serial.print(F("_NOEXTRA4K"));
|
||||
#endif
|
||||
Serial.println(F(" option specified."));
|
||||
#endif
|
||||
|
||||
Serial.println();
|
||||
Serial.println(F("The Hardware Watchdog Timer Demo is now available for crashing ..."));
|
||||
Serial.println();
|
||||
processKey(Serial, '?');
|
||||
}
|
||||
|
||||
|
||||
void loop(void) {
|
||||
if (Serial.available() > 0) {
|
||||
int hotKey = Serial.read();
|
||||
processKey(Serial, hotKey);
|
||||
}
|
||||
}
|
116
libraries/esp8266/examples/HwdtStackDump/ProcessKey.ino
Normal file
116
libraries/esp8266/examples/HwdtStackDump/ProcessKey.ino
Normal file
@ -0,0 +1,116 @@
|
||||
#include <esp8266_undocumented.h>
|
||||
void crashMeIfYouCan(void)__attribute__((weak));
|
||||
int divideA_B(int a, int b);
|
||||
|
||||
int* nullPointer = NULL;
|
||||
|
||||
void processKey(Print& out, int hotKey) {
|
||||
switch (hotKey) {
|
||||
case 'r':
|
||||
out.printf_P(PSTR("Reset, ESP.reset(); ...\r\n"));
|
||||
ESP.reset();
|
||||
break;
|
||||
case 't':
|
||||
out.printf_P(PSTR("Restart, ESP.restart(); ...\r\n"));
|
||||
ESP.restart();
|
||||
break;
|
||||
case 's': {
|
||||
uint32_t startTime = millis();
|
||||
out.printf_P(PSTR("Now crashing with Software WDT. This will take about 3 seconds.\r\n"));
|
||||
ets_install_putc1(ets_putc);
|
||||
while (true) {
|
||||
ets_printf("%9lu\r", (millis() - startTime));
|
||||
ets_delay_us(250000);
|
||||
// stay in an loop blocking other system activity.
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
out.printf_P(PSTR("Now crashing with Hardware WDT. This will take about 6 seconds.\r\n"));
|
||||
asm volatile("mov.n a2, %0\n\t"
|
||||
"mov.n a3, %1\n\t"
|
||||
"mov.n a4, %2\n\t"
|
||||
"mov.n a5, %3\n\t"
|
||||
"mov.n a6, %4\n\t"
|
||||
: : "r"(0xaaaaaaaa), "r"(0xaaaaaaaa), "r"(0xaaaaaaaa), "r"(0xaaaaaaaa), "r"(0xaaaaaaaa) : "memory");
|
||||
// Could not find these in the stack dump, unless interrupts were enabled.
|
||||
{
|
||||
uint32_t startTime = millis();
|
||||
// Avoid all the Core functions that play nice, so we can hog
|
||||
// the system and crash.
|
||||
ets_install_putc1(ets_putc);
|
||||
xt_rsil(15);
|
||||
while (true) {
|
||||
ets_printf("%9lu\r", (millis() - startTime));
|
||||
ets_delay_us(250000);
|
||||
// stay in an loop blocking other system activity.
|
||||
//
|
||||
// Note:
|
||||
// Hardware WDT kicks in if Software WDT is unable to perform.
|
||||
// With the Hardware WDT, nothing is saved on the stack, that I have seen.
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
out.println(F("Time to panic()!"));
|
||||
panic();
|
||||
break;
|
||||
case 'z':
|
||||
out.println(F("Crashing by dividing by zero. This should generate an exception(0)."));
|
||||
out.printf_P(PSTR("This should not print %d\n"), divideA_B(1, 0));
|
||||
break;
|
||||
case 'w':
|
||||
out.println(F("Now calling: void crashMeIfYouCan(void)__attribute__((weak));"));
|
||||
out.println(F("This function has a prototype but was missing when the sketch was linked. ..."));
|
||||
crashMeIfYouCan();
|
||||
break;
|
||||
case 'b':
|
||||
out.println(F("Executing a break instruction w/o GDB will cause a HWDT reset."));
|
||||
asm volatile("break 1, 15;");
|
||||
out.println(F("This line will not be printable w/o running GDB"));
|
||||
break;
|
||||
case '0':
|
||||
out.println(F("Crashing at an embeded 'break 1, 15' instruction that was generated"));
|
||||
out.println(F("by the compiler after detecting a divide by zero."));
|
||||
out.printf_P(PSTR("This should not print %d\n"), divideA_B_bp(1, 0));
|
||||
break;
|
||||
case '\r':
|
||||
out.println();
|
||||
case '\n':
|
||||
break;
|
||||
case '?':
|
||||
out.println();
|
||||
out.println(F("Press a key + <enter>"));
|
||||
out.println(F(" r - Reset, ESP.reset();"));
|
||||
out.println(F(" t - Restart, ESP.restart();"));
|
||||
out.println(F(" ? - Print Help"));
|
||||
out.println();
|
||||
out.println(F("Crash with:"));
|
||||
out.println(F(" s - Software WDT"));
|
||||
out.println(F(" h - Hardware WDT - looping with interrupts disabled"));
|
||||
out.println(F(" w - Hardware WDT - calling a missing (weak) function."));
|
||||
out.println(F(" 0 - Hardware WDT - a hard coded compiler breakpoint from a compile time detected divide by zero"));
|
||||
out.println(F(" b - Hardware WDT - a forgotten hard coded 'break 1, 15;' and no GDB running."));
|
||||
out.println(F(" z - Divide by zero, exception(0);"));
|
||||
out.println(F(" p - panic();"));
|
||||
out.println();
|
||||
break;
|
||||
default:
|
||||
out.printf_P(PSTR("\"%c\" - Not an option? / ? - help"), hotKey);
|
||||
out.println();
|
||||
processKey(out, '?');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// With the current toolchain 10.1, using this to divide by zero will *not* be
|
||||
// caught at compile time.
|
||||
int __attribute__((noinline)) divideA_B(int a, int b) {
|
||||
return (a / b);
|
||||
}
|
||||
|
||||
// With the current toolchain 10.1, using this to divide by zero *will* be
|
||||
// caught at compile time. And a hard coded breakpoint will be inserted.
|
||||
int divideA_B_bp(int a, int b) {
|
||||
return (a / b);
|
||||
}
|
Reference in New Issue
Block a user