Debugging Guide =============== The ESP32 Template supports full GDB debugging in both emulator (QEMU) and hardware modes. This guide focuses on QEMU debugging since it's fully supported in GitHub Codespaces. Quick Start: Debugging in QEMU ------------------------------- 1. Start QEMU Debug Server ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The QEMU emulator automatically starts with GDB support enabled: .. code-block:: bash ./tools/run-qemu-network.sh This starts QEMU in debug mode, waiting for a debugger connection on port 3333. 2. Start Debugging in VS Code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Simply press **F5** or use the Debug panel: 1. Open the Debug view (Ctrl+Shift+D / Cmd+Shift+D) 2. Select "**QEMU: GDB**" from the dropdown 3. Click the green play button or press F5 VS Code will: - ✅ Connect to QEMU's GDB server (port 3333) - ✅ Load symbols from the built ELF file - ✅ Break at ``app_main()`` - ✅ Show full call stack and variables Debugging Features ------------------ Breakpoints ~~~~~~~~~~~ Set breakpoints by clicking in the editor gutter (left of line numbers): .. code-block:: c void app_main(void) { // Breakpoint here: Click in gutter at line number ESP_LOGI(TAG, "ESP32 Application Starting..."); // Conditional breakpoint: Right-click → Add Conditional Breakpoint if (value < 10) { // Break only when value < 10 } } **Breakpoint Types:** - **Line Breakpoint**: Break when reaching specific line - **Conditional Breakpoint**: Break only when condition is true - **Logpoint**: Log message without stopping (useful for tracing) Step Through Code ~~~~~~~~~~~~~~~~~ Use VS Code debug toolbar or keyboard shortcuts: - **F10** - Step Over (execute current line, don't enter functions) - **F11** - Step Into (enter function calls) - **Shift+F11** - Step Out (return from current function) - **F5** - Continue (run until next breakpoint) Inspect Variables ~~~~~~~~~~~~~~~~~ **Variables Panel**: Shows local variables and function parameters automatically **Watch Panel**: Add custom expressions to monitor .. code-block:: c // Example: Monitor a struct member config.led_count // Example: Monitor array element buffer[5] // Example: Evaluate expression (value * 2) > threshold Call Stack ~~~~~~~~~~ The Call Stack panel shows the complete function call hierarchy: .. code-block:: text #0 my_function() at main.c:42 #1 process_data() at main.c:128 #2 app_main() at main.c:200 #3 main_task() at cpu_start.c:... Click any frame to inspect its local variables and source code. Debug Console ~~~~~~~~~~~~~ Execute GDB commands directly in the Debug Console: .. code-block:: text # Print variable p my_variable # Print in hex p/x my_variable # Print array p my_array[0]@10 # Call function call my_debug_function() Hardware Debugging ------------------ Debugging on Real ESP32 ~~~~~~~~~~~~~~~~~~~~~~~ For hardware debugging, you need a JTAG adapter. The template doesn't include hardware debugging configuration by default (focus is on QEMU). For production projects, see `ESP-IDF JTAG Debugging `_ documentation. Debug Configuration ------------------- QEMU Debug Configuration ~~~~~~~~~~~~~~~~~~~~~~~~~ The ``.vscode/launch.json`` contains the QEMU debug configuration: .. code-block:: json { "name": "QEMU: GDB", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/build/esp32-template.elf", "cwd": "${workspaceFolder}", "MIMode": "gdb", "miDebuggerPath": "xtensa-esp32-elf-gdb", "miDebuggerServerAddress": "localhost:3333" } **Key Settings:** - **program**: Path to ELF file with debug symbols - **miDebuggerPath**: GDB executable (ESP32 toolchain) - **miDebuggerServerAddress**: QEMU GDB server (port 3333) Advanced Debugging ------------------ Debugging FreeRTOS Tasks ~~~~~~~~~~~~~~~~~~~~~~~~ View FreeRTOS task information: .. code-block:: text # In Debug Console info threads # Switch to specific task thread 3 Memory Inspection ~~~~~~~~~~~~~~~~~ Inspect memory directly: .. code-block:: text # View memory at address (hex) x/16x 0x3FFB0000 # View memory as string x/s 0x3FFB0000 # Examine stack x/32x $sp Performance Analysis ~~~~~~~~~~~~~~~~~~~~ Measure execution time: .. code-block:: c // Add timing code uint64_t start = esp_timer_get_time(); // Your code here my_function(); uint64_t elapsed = esp_timer_get_time() - start; ESP_LOGI(TAG, "Execution time: %llu us", elapsed); Set breakpoints before and after, inspect ``elapsed`` value. Common Debugging Scenarios --------------------------- Crash Analysis ~~~~~~~~~~~~~~ When ESP32 crashes, look for: 1. **Stack trace** in serial output 2. **Program Counter (PC)** - use ``addr2line`` to find source line 3. **Register dump** - shows CPU state at crash .. code-block:: bash # Convert crash address to source line xtensa-esp32-elf-addr2line -e build/esp32-template.elf 0x400d1234 Memory Leaks ~~~~~~~~~~~~ Monitor heap usage: .. code-block:: c ESP_LOGI(TAG, "Free heap: %d bytes", esp_get_free_heap_size()); ESP_LOGI(TAG, "Min free heap: %d bytes", esp_get_minimum_free_heap_size()); Stack Overflow ~~~~~~~~~~~~~~ Check stack high water mark: .. code-block:: c UBaseType_t stack_left = uxTaskGetStackHighWaterMark(NULL); ESP_LOGI(TAG, "Stack space left: %d words", stack_left); Troubleshooting --------------- GDB Won't Connect ~~~~~~~~~~~~~~~~~ **Problem:** VS Code can't connect to QEMU **Solutions:** 1. Ensure QEMU is running: ``ps aux | grep qemu`` 2. Check port 3333 is available: ``lsof -i :3333`` 3. Restart QEMU: ``./tools/stop_qemu.sh && ./tools/run-qemu-network.sh`` No Debug Symbols ~~~~~~~~~~~~~~~~ **Problem:** Can't see source code or variable names **Solutions:** 1. Ensure debug build: ``idf.py menuconfig`` → Component config → Compiler options → Optimization Level → Debug (-Og) 2. Rebuild: ``idf.py fullclean build`` Breakpoint Not Hit ~~~~~~~~~~~~~~~~~~ **Problem:** Breakpoint is set but never triggers **Checks:** 1. Code is actually executed (not in dead code path) 2. Compiler didn't optimize code away (check disassembly) 3. Breakpoint is in correct file (check paths match) Tips and Best Practices ------------------------ Efficient Debugging ~~~~~~~~~~~~~~~~~~~ ✅ **Use Logpoints**: Don't stop execution, just log information ✅ **Conditional Breakpoints**: Break only when specific conditions occur ✅ **Watch Expressions**: Monitor key variables without manual inspection ✅ **Call Stack Navigation**: Quickly find where problems originate Logging vs Debugging ~~~~~~~~~~~~~~~~~~~~~ **Use Logging For:** - Production code monitoring - Long-running operations - Intermittent issues - Field diagnostics **Use Debugging For:** - Development and troubleshooting - Complex state inspection - Step-by-step execution analysis - One-time investigation Debug Optimization ~~~~~~~~~~~~~~~~~~ **During Development:** - Use Debug (-Og) optimization for best debugging experience - Enable all debug symbols **For Release:** - Switch to Release optimization (-O2 or -Os) - Disable verbose logging - Keep ESP_LOGI for important events Resources --------- - `ESP-IDF Debugging Guide `_ - `GDB Manual `_ - `VS Code Debugging `_ Next Steps ---------- - :doc:`qemu-emulator` - Learn more about QEMU emulation - :doc:`qemu-network-internals` - Understand network implementation - :doc:`devcontainer` - Set up your development environment