The Direct Answer: Extracting the Core Dump
To extract an ESP32 Arduino core dump from flash, you must use the espcoredump.py utility bundled with the ESP32 Arduino Core or ESP-IDF. The exact command to decode the crash and map it to your source code is:
python espcoredump.py --port /dev/ttyUSB0 --baud 115200 info_sketch ./build/sketch.elf
This reads the dedicated coredump partition in the ESP32's flash memory, decodes the base64 or ELF-formatted crash data, and maps the memory addresses back to your compiled .elf file. The output reveals the exact backtrace, register states, and the specific line of C++ code that caused the panic.
Hardware & Software Spec Sheet
Before triggering a crash, ensure your bench setup matches these specifications. Core dumping requires sufficient flash space and a stable UART connection.
| Component | Specification / Variant | Notes |
|---|---|---|
| Target Board | ESP32-WROOM-32 DevKit V1 (30-pin) | Code and pin mappings below target this exact variant. |
| USB-to-UART Bridge | Onboard CP2102 or CH340G | Ensure you have the correct VCP drivers installed for your OS. |
| Flash Size | 4MB Minimum | Core dump partitions require at least 64KB of reserved flash. |
| Software Framework | Arduino IDE 2.x or PlatformIO | PlatformIO is highly recommended for easier ELF file access. |
| Python Environment | Python 3.8+ with pyserial |
Required to run the extraction script locally. |
Pin Mapping for UART Debugging
The core dump is transmitted and extracted via UART0. Do not wire these pins to external peripherals if you need reliable crash extraction.
| Function | GPIO Pin | Direction | Notes |
|---|---|---|---|
| UART0 TX | GPIO 1 | Output | Connects to onboard USB bridge RXD. |
| UART0 RX | GPIO 3 | Input | Connects to onboard USB bridge TXD. |
| Chip Enable | EN | Input | Pulled HIGH via 10k resistor; auto-reset circuit handles boot mode. |
Triggering the Crash: The Exact Error String
To test your extraction pipeline, you need a sketch that reliably forces a hardware exception. The code below targets the ESP32-WROOM-32 DevKit V1 and intentionally dereferences a null pointer, triggering a memory access violation.
// Target Board: ESP32-WROOM-32 DevKit V1
// Pin Mapping: UART0 TX (GPIO 1), RX (GPIO 3) via onboard USB-to-UART bridge
#include
void triggerCrash() {
int *nullPtr = nullptr;
// Force a LoadProhibited exception by reading from protected address 0x0
int crashVal = *nullPtr;
Serial.println(crashVal); // Execution never reaches this line
}
void setup() {
Serial.begin(115200);
unsigned long timeout = millis();
while(!Serial && (millis() - timeout < 3000)) {
delay(10); // Wait for serial monitor, with 3s timeout fallback
}
Serial.println("ESP32 Core Dump Trigger Sketch - Crashing in 2 seconds...");
delay(2000);
triggerCrash();
}
void loop() {
// Empty loop - crash happens in setup
}
When this sketch runs, the serial monitor will halt abruptly after printing the following exact error string:
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
Following this string, the ESP32 prints a register dump and a base64-encoded core dump block, then writes the binary core dump to the flash partition and reboots. According to the Espressif Core Dump Documentation, the LoadProhibited exception specifically means the CPU attempted to read from an unmapped or protected memory address.
Step-by-Step Extraction and Debugging
Extracting the dump in the Arduino IDE is notoriously difficult because the IDE hides the compiled .elf file in a temporary directory. PlatformIO makes this trivial, but here is the universal workflow.
- Locate your ELF file: In PlatformIO, this is at
.pio/build/esp32dev/firmware.elf. In Arduino IDE 2.x, go to File > Preferences, enable "Show verbose output during compilation", compile the sketch, and search the console output for the path ending in.elf. - Locate the Extraction Tool: The
espcoredump.pyscript is bundled in the ESP32 Arduino core packages. On Linux/Mac, it is typically found at~/.arduino15/packages/esp32/tools/esp32-arduino-libs/[version]/tools/espcoredump/espcoredump.py. - Close the Serial Monitor: The extraction script needs exclusive access to the COM port. Close the Arduino IDE serial monitor or any other terminal holding the port open.
- Run the Extraction Command: Open your system terminal and execute the command, replacing the paths with your actual file locations:
python3 /path/to/espcoredump.py --port /dev/ttyUSB0 --baud 115200 info_sketch /path/to/firmware.elf - Analyze the GDB Output: The script will download the flash partition, launch a local GDB session, and print the backtrace. Look for the first frame in your source code (e.g.,
triggerCrash() at sketch.ino:8) to identify the exact line that caused the panic.
First Three Things to Check When Extraction Fails
If the espcoredump.py script throws an error or returns garbage data, work through this ranked decision path:
- ELF File Mismatch (Most Common): Did you change a single line of code and recompile after the crash occurred? The core dump contains raw memory addresses. If the
.elffile you provide to the script doesn't exactly match the binary that was running on the chip during the crash, GDB will map the addresses to the wrong lines of code. Fix: Always keep a copy of the exact .elf file that was flashed when the crash happened. - Missing Core Dump Partition: The script will fail with a
Partition not founderror if your selected partition scheme doesn't include a coredump region. Standard "Default 4MB with spiffs" often omits it to save space. Fix: In the Arduino IDE Tools menu, change the Partition Scheme to "Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)" or an OTA scheme, which reserves 64KB for coredumps. See the Arduino ESP32 Partition Tables guide for exact CSV layouts. - Serial Port Locking or Baud Rate Mismatch: If you get a
serial.serialutil.SerialException: could not open port, another process holds the port. If the script connects but downloads corrupted hex data, your baud rate is too high for the USB bridge. Fix: Unplug/replug the USB cable, ensure no serial monitors are open, and drop the--baudargument to 115200 or 460800.
Extending and Simplifying Your Debug Build
Depending on your project constraints, you may want to strip out the core dump entirely or upgrade your debugging methodology.
How to Simplify (Reclaim Flash Space)
If you are building a production firmware image for a 4MB ESP32 and need every kilobyte for OTA updates and SPIFFS, disable the core dump. In PlatformIO, add CONFIG_ESP_COREDUMP_ENABLE=n to your sdkconfig.defaults file. In the Arduino IDE, select a partition scheme like "No OTA (2MB APP/2MB SPIFFS)". Instead of post-mortem dumps, rely on CORE_DEBUG_LEVEL=4 (Warning) or 5 (Verbose) in your build flags to catch errors via standard serial logging before they cause a hard panic.
How to Extend (Live JTAG Debugging)
Core dumps are post-mortem; they tell you where the code died, but not the state of the variables leading up to it. To extend your debug capabilities, use an ESP-PROG JTAG debugger. By wiring the JTAG pins (GPIO 12, 13, 14, 15 on the WROOM-32) to the ESP-PROG, you can use PlatformIO's built-in GDB server to set live breakpoints, step through code line-by-line, and inspect memory in real-time without relying on flash partitions or serial baud rates.
FAQ: Extracting ESP32 Arduino Core Dumps
Why is my ESP32 core dump partition missing from the flash?
The ESP32 flash is divided by a partition table CSV file. Many default Arduino partition schemes (especially those optimized for large SPIFFS or single-app no-OTA setups) omit the coredump partition to maximize application space. If the partition table does not explicitly define a partition with the type data and subtype coredump, the ESP-IDF panic handler has nowhere to write the crash data, and it will simply print the base64 string to the serial monitor and reboot without saving it to flash.
Can I extract the ESP32 Arduino core dump without the original ELF file?
Technically yes, but practically no. You can use espcoredump.py with the info command instead of info_sketch to extract the raw base64 or ELF binary of the crash itself. However, without the original .elf compilation file, GDB cannot map the raw hex memory addresses back to your C++ function names and line numbers. You will only see raw hex addresses (e.g., 0x400d1234), which requires manually cross-referencing the .map file generated during compilation to find the offending function.
How do I decode the base64 core dump string from the serial monitor manually?
If your partition table lacks a coredump partition, the ESP32 prints the crash data as a base64 string directly to the serial output between ================= CORE DUMP START ================= and CORE DUMP END markers. Copy everything between those markers (excluding the markers themselves), save it to a text file named dump.b64, and run the extraction tool using the file instead of the serial port: python espcoredump.py info_sketch --core-format b64 --core dump.b64 firmware.elf.






