esp32-guru-upload#

Upload Guru Meditation crashdumps from an ESP32 to a Flask server endpoint.

ESP32 firmware captures crashdumps from the dedicated coredump partition.

Crashdumps are uploaded via HTTP POST to a Flask server

How To#

1. Open in Codespaces#

This repository is preconfigured with a development container.

Open it in GitHub Codespaces to get the ESP-IDF and Python environment ready.

2. Start ESP32 Firmware in QEMU#

Launch the emulated ESP32 firmware with port forwarding:

cd esp32-guru-upload
get_idf   # setup ESP-IDF environment
idf.py qemu --qemu-extra-args "-nic user,hostfwd=tcp::8081-:8080"

For more insight on QEMU visit my Blog.

3. Start the Flask Server#

In another terminal:

cd esp32-guru-upload
python endpoint_app.py

Demo view of the server: abd-01.github.io/esp32-guru-upload

4. Access the Web UI#

Visit: http://localhost:8080/ or the GitHub Codespaces-provided URL.

Overview#

ESP32 Firmware#

Runs on real hardware or in QEMU. It intentionally triggers crashes, captures crashdumps from the dedicated coredump partition, and uploads them over HTTP.

Flask Server#

Receives crashdumps via POST /upload, stores them as .elf files, and provides a simple web interface to browse and analyze dumps using ESP-IDF tools.

Development Container#

Preconfigured for GitHub Codespaces or VS Code Dev Containers. Includes the ESP-IDF toolchain, QEMU emulator, and Python environment.

Project Structure#

abd-01-esp32-guru-upload/
├── .devcontainer/         # Devcontainer setup (ESP-IDF, QEMU, Flask)
├── main/                  # ESP32 firmware sources
│   ├── crash_app.c        # Crash simulation
│   ├── dummy_app.c        # Random dummy tasks
│   ├── guru-upload.c      # Main app, Wi-Fi & tasks
│   ├── upload_coredump_app.c # Upload task
│   └── http_service/      # HTTP client helpers
├── templates/             # Flask HTML templates
├── endpoint_app.py        # Flask server entrypoint
└── README.md

Explanation#

Background#

I was recently working on Hardfault Diagnostics for ARM Cortex-M, which could create crashlogs in the event of a Hardfault.

My work is in progress and can be viewed here.

I would have eventually looked into ESP32, however, this gave me the chance to get into the Guru Meditation earlier.

Software#

QEMU has been an integral part of my work for the last couple of months, as it allowed me to get into different machines without needing the actual hardware. (I also use QEMU as my go-to virtual machine emulator instead of VMware or other software.) You can check out my blog on QEMU if you like.

The official qemu-system-xtensa does not support ESP32 targets. Thankfully, Espressif maintains a fork of QEMU with patches that support these chips.

Fork of QEMU with Espressif patches: github.com/espressif/qemu

Build this version from source, and if everything works correctly, we have esp32 in the supported machines list:

$ qemu-system-xtensa -M help
Supported machines are:
esp32                Espressif ESP32 machine
esp32s3              Espressif ESP32S3 machine
kc705                kc705 EVB (dc232b)
kc705-nommu          kc705 noMMU EVB (de212)
lx200                lx200 EVB (dc232b)
lx200-nommu          lx200 noMMU EVB (de212)
lx60                 lx60 EVB (dc232b)
lx60-nommu           lx60 noMMU EVB (de212)
ml605                ml605 EVB (dc232b)
ml605-nommu          ml605 noMMU EVB (de212)
none                 empty machine
sim                  sim machine (dc232b) (default)
virt                 virt machine (dc232b)

The next thing used is the ESP-IDF (Espressif IoT Development Framework). Just follow the manual for installation.

I have set up all the installation into the devcontainer so you don’t have to worry about installing any prerequisite software.

Implementation#

For a Guru Meditation to be triggered, there has to be a piece of notorious code.

I have written crash_app.c, which just calls a few functions (to showcase stack depth) and writes to a prohibited location:

==================== THREAD 1 (TCB: 0x3ffb94b0, name: 'CrashTask') =====================
#0  0x400da38f in baz (val=99) at esp32-guru-upload/main/crash_app.c:49
#1  bar (val=67) at esp32-guru-upload/main/crash_app.c:36
#2  foo (val=67) at esp32-guru-upload/main/crash_app.c:28
#3  CrashTask (pvParameters=<optimized out>) at esp32-guru-upload/main/crash_app.c:20
#4  0x40085f54 in vPortTaskWrapper (pxCode=0x400da2f0 <CrashTask>, pvParameters=0x0) at esp-idf/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:139

Visit abd-01.github.io/esp32-guru-upload/device_log for complete logs.

ESP-IDF (Espressif IoT Development Framework) through its menuconfig provides an option for coredumps to be sent over UART or saved in Flash. See sdkconfig or run idf.py menuconfig:

# Core dump

CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH=y
CONFIG_ESP_COREDUMP_ENABLE_TO_UART=n
CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=n
CONFIG_ESP_COREDUMP_DATA_FORMAT_BIN=n
CONFIG_ESP_COREDUMP_DATA_FORMAT_ELF=y
CONFIG_ESP_COREDUMP_CHECKSUM_CRC32=y
CONFIG_ESP_COREDUMP_CHECK_BOOT=y
CONFIG_ESP_COREDUMP_ENABLE=y
CONFIG_ESP_COREDUMP_LOGS=y
CONFIG_ESP_COREDUMP_MAX_TASKS_NUM=64

Coredump-related public APIs can be used by including esp_core_dump.h.

guru_upload.c is the main file of the project implementing app_main, and the first thing it does is check if a coredump exists in flash:

esp_err_t err = esp_core_dump_image_get(&addr, &size);

If a coredump is found, UploadCoredumpTask is invoked as a separate RTOS task (implementation in upload_coredump_app.c).

Other than that, guru_upload.c starts a dummy application (which just prints logs based on a pseudorandom number) and an HTTP webserver that responds with “Hello from ESP32”.

The project, instead of being created from scratch, was created using the HTTP Request Example template.

The HTTP client operations are also inspired by the provided examples. See esp_http_client_example.c#http_native_request.

upload_coredump_app.c reads the coredump saved in flash and posts it chunk by chunk to the server:

coredump = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_COREDUMP, NULL);
esp_err_t err = esp_partition_read(coredump, offset, buffer, buffer_size);
http_upload_send_chunk(client, buffer, buffer_size);

Server#

I had a fair share of experience with Flask, and having worked with connected vehicle protocols and protobuf, I also put together a Flask-based server where I can upload the coredump data. See endpoint_app.py for internal details.

http://localhost:8080/ displays the list of coredumps received. http://localhost:8080/coredump/coredump-<timestamp>.elf will run esp_coredump on the file and display the results.

For demo visit: abd-01.github.io/esp32-guru-upload/coredump/coredump-1758023059.elf

http://localhost:8080/upload is the endpoint that receives the coredump via POST method.

The ESP32 is also running an HTTP server which can be viewed at http://localhost:8080/esp_server

License#

GNU Affero General Public License v3.0 (AGPL-3.0). See LICENSE for details.