Skip to content

Commit e3f25f6

Browse files
Copilotsofthack007
andcommitted
Add exception decoding and crash analysis for QEMU output
Enhanced QEMU testing to better analyze firmware crashes: Crash Detection: - Added analysis step to detect ESP32 exceptions in QEMU output - Searches for "exception", "abort", "backtrace", "panic", "guru meditation" - Displays context around crashes (20 lines after, 5 before) - Shows first 100 lines of exception context Improved Logging: - Display last 200 lines of QEMU output on failures - Added clear markers for different failure scenarios - Better error messages distinguishing QEMU vs firmware issues Documentation: - Created docs/QEMU-ISSUES.md explaining QEMU limitations - Documents common crash patterns (WiFi, peripherals, real bugs) - Explains how to analyze crashes - Clarifies expected vs unexpected behavior in QEMU Dependencies: - Added Python setup for exception decoder tools - Installed platformio for potential addr2line usage - Added binutils for debugging tools Note: Full exception decoding with addr2line requires toolchain access. Current implementation focuses on detecting and displaying crashes clearly. Co-authored-by: softhack007 <91616163+softhack007@users.noreply.github.com>
1 parent 129a138 commit e3f25f6

File tree

4 files changed

+203
-4
lines changed

4 files changed

+203
-4
lines changed

.github/scripts/monitor-qemu.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Monitor QEMU ESP32 serial output and decode exceptions
4+
This script watches the QEMU serial output and uses the ESP32 exception decoder
5+
to translate stack traces into human-readable format.
6+
"""
7+
8+
import sys
9+
import re
10+
import subprocess
11+
import os
12+
13+
def find_elf_file(firmware_dir):
14+
"""Find the ELF file for symbol resolution"""
15+
elf_path = os.path.join(firmware_dir, "firmware.elf")
16+
if os.path.exists(elf_path):
17+
return elf_path
18+
return None
19+
20+
def decode_exception(lines, elf_file):
21+
"""Decode an ESP32 exception using addr2line"""
22+
if not elf_file or not os.path.exists(elf_file):
23+
return None
24+
25+
# Extract addresses from backtrace
26+
addresses = []
27+
for line in lines:
28+
# Look for patterns like: 0x4008xxxx:0x3ffbxxxx
29+
matches = re.findall(r'0x[0-9a-fA-F]{8}', line)
30+
addresses.extend(matches)
31+
32+
if not addresses:
33+
return None
34+
35+
# Use addr2line to decode addresses
36+
try:
37+
# Get the toolchain path from environment or use default
38+
toolchain_prefix = os.environ.get('TOOLCHAIN_PREFIX', 'xtensa-esp32-elf-')
39+
addr2line = f"{toolchain_prefix}addr2line"
40+
41+
cmd = [addr2line, '-e', elf_file, '-f', '-C'] + addresses
42+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=5)
43+
44+
if result.returncode == 0 and result.stdout:
45+
return result.stdout
46+
except Exception as e:
47+
print(f"[Decoder] Error decoding: {e}", file=sys.stderr)
48+
49+
return None
50+
51+
def monitor_output(firmware_dir):
52+
"""Monitor stdin and decode exceptions"""
53+
elf_file = find_elf_file(firmware_dir)
54+
55+
if elf_file:
56+
print(f"[Decoder] Using ELF file: {elf_file}", file=sys.stderr)
57+
else:
58+
print(f"[Decoder] Warning: ELF file not found in {firmware_dir}", file=sys.stderr)
59+
print(f"[Decoder] Exception decoding will not be available", file=sys.stderr)
60+
61+
exception_lines = []
62+
in_exception = False
63+
64+
for line in sys.stdin:
65+
# Print the original line
66+
print(line, end='', flush=True)
67+
68+
# Detect exception start
69+
if 'Guru Meditation Error' in line or 'Backtrace:' in line or 'abort()' in line:
70+
in_exception = True
71+
exception_lines = [line]
72+
print("\n[Decoder] ========== ESP32 EXCEPTION DETECTED ==========", file=sys.stderr)
73+
elif in_exception:
74+
exception_lines.append(line)
75+
76+
# Check if exception block ended
77+
if line.strip() == '' or 'ELF file SHA256' in line or len(exception_lines) > 20:
78+
# Try to decode
79+
decoded = decode_exception(exception_lines, elf_file)
80+
if decoded:
81+
print("\n[Decoder] Decoded stack trace:", file=sys.stderr)
82+
print(decoded, file=sys.stderr)
83+
print("[Decoder] ================================================\n", file=sys.stderr)
84+
else:
85+
print("[Decoder] Could not decode exception (toolchain not available)", file=sys.stderr)
86+
print("[Decoder] ================================================\n", file=sys.stderr)
87+
88+
in_exception = False
89+
exception_lines = []
90+
91+
if __name__ == '__main__':
92+
firmware_dir = sys.argv[1] if len(sys.argv) > 1 else '.pio/build/esp32dev'
93+
monitor_output(firmware_dir)

.github/scripts/run-qemu.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
#!/bin/bash
22
# Run WLED firmware in QEMU ESP32
33
# This script starts QEMU with the compiled firmware and enables network access
4+
#
5+
# Note: QEMU ESP32 emulation has limitations:
6+
# - Not all peripherals are fully emulated (WiFi, I2C, some GPIOs)
7+
# - Some firmware features may crash in QEMU but work on real hardware
8+
# - This is expected behavior for testing web UI functionality
49

510
set -e
611

.github/workflows/qemu-e2e-test.yml

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ jobs:
7070
steps:
7171
- uses: actions/checkout@v4
7272

73+
- name: Set up Python
74+
uses: actions/setup-python@v5
75+
with:
76+
python-version: '3.9'
77+
7378
- name: Set up Node.js
7479
uses: actions/setup-node@v4
7580
with:
@@ -88,15 +93,26 @@ jobs:
8893
- name: Install Playwright Browsers
8994
run: npx playwright install --with-deps chromium
9095

96+
- name: Install ESP32 exception decoder
97+
run: |
98+
pip install esptool
99+
# Install the exception decoder from platformio
100+
pip install platformio
101+
# The xtensa toolchain should be available from the firmware build artifacts
102+
91103
- name: Install QEMU dependencies
92104
run: |
93105
sudo apt-get update
94-
sudo apt-get install -y libsdl2-2.0-0 libpixman-1-0 libglib2.0-0
106+
sudo apt-get install -y libsdl2-2.0-0 libpixman-1-0 libglib2.0-0 binutils
95107
96108
- name: Setup QEMU ESP32
97109
run: |
98110
bash .github/scripts/setup-qemu.sh
99111
112+
- name: Make decoder script executable
113+
run: |
114+
chmod +x .github/scripts/monitor-qemu.py
115+
100116
- name: Start QEMU with WLED firmware in background
101117
run: |
102118
chmod +x .github/scripts/run-qemu.sh
@@ -108,14 +124,16 @@ jobs:
108124
run: |
109125
if [ ! -f qemu.pid ]; then
110126
echo "ERROR: qemu.pid not found"
111-
cat qemu-output.log || true
127+
echo "=== QEMU Output (last 200 lines) ==="
128+
tail -200 qemu-output.log || true
112129
exit 1
113130
fi
114131
115132
QEMU_PID=$(cat qemu.pid)
116133
if ! kill -0 $QEMU_PID 2>/dev/null; then
117134
echo "ERROR: QEMU process not running"
118-
cat qemu-output.log || true
135+
echo "=== QEMU Output (last 200 lines) ==="
136+
tail -200 qemu-output.log || true
119137
exit 1
120138
fi
121139
@@ -133,14 +151,45 @@ jobs:
133151
done
134152
135153
echo "ERROR: HTTP server not responding after 2 minutes"
136-
cat qemu-output.log || true
154+
echo "=== QEMU Output (last 200 lines) ==="
155+
tail -200 qemu-output.log || true
156+
echo ""
157+
echo "=== Checking for ESP32 exceptions/crashes ==="
158+
if grep -i "exception\|abort\|backtrace\|panic" qemu-output.log; then
159+
echo "FOUND: Firmware crash detected in QEMU output"
160+
else
161+
echo "No obvious crash patterns found"
162+
fi
137163
exit 1
138164
139165
- name: Run Playwright tests against QEMU
140166
env:
141167
WLED_BASE_URL: http://localhost:8080
142168
run: npm run test:e2e
143169

170+
- name: Analyze QEMU output for crashes
171+
if: always()
172+
run: |
173+
echo "=== Analyzing QEMU output for ESP32 crashes ==="
174+
if [ -f qemu-output.log ]; then
175+
if grep -i "exception\|abort\|backtrace\|panic\|guru meditation" qemu-output.log > /dev/null; then
176+
echo "ESP32 Exception/Crash detected in QEMU output!"
177+
echo ""
178+
echo "=== Exception Context ==="
179+
grep -A 20 -B 5 -i "exception\|abort\|backtrace\|panic\|guru meditation" qemu-output.log | head -100
180+
echo ""
181+
echo "Note: This could be a QEMU-specific issue or a real firmware bug."
182+
echo "QEMU ESP32 emulation has limitations:"
183+
echo " - Many peripherals are not fully emulated"
184+
echo " - Some hardware features may cause crashes in QEMU but work on real hardware"
185+
echo " - Network/WiFi emulation is limited"
186+
else
187+
echo "No ESP32 exceptions detected in QEMU output"
188+
fi
189+
else
190+
echo "No QEMU output log found"
191+
fi
192+
144193
- name: Upload QEMU logs
145194
uses: actions/upload-artifact@v4
146195
if: always()

docs/QEMU-ISSUES.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# QEMU ESP32 Testing - Known Issues and Limitations
2+
3+
## QEMU Limitations
4+
5+
ESP32 QEMU emulation is not perfect and has several known limitations:
6+
7+
### Hardware Emulation
8+
- **WiFi**: Not fully emulated - WiFi operations may fail or behave differently
9+
- **Bluetooth**: Not emulated
10+
- **I2C/SPI**: Limited emulation - some peripherals may not work
11+
- **GPIO**: Partial emulation - LED outputs and some inputs work, but not all
12+
- **ADC**: Not emulated
13+
- **Touch sensors**: Not emulated
14+
- **RTC**: Limited emulation
15+
16+
### Common Crash Patterns
17+
18+
#### 1. WiFi-Related Crashes
19+
**Symptom**: Crashes when trying to initialize WiFi or connect to networks
20+
**Cause**: WiFi hardware is not fully emulated in QEMU
21+
**Analysis**: Check if crash occurs during WiFi initialization
22+
**Solution**: These are expected in QEMU and don't indicate real firmware bugs
23+
24+
#### 2. Peripheral Access Crashes
25+
**Symptom**: Crashes when accessing I2C, SPI, or other peripherals
26+
**Cause**: Peripheral emulation is incomplete
27+
**Analysis**: Check which peripheral is being accessed in the backtrace
28+
**Solution**: These may be QEMU-specific issues
29+
30+
#### 3. Real Firmware Bugs
31+
**Symptom**: Crashes in application code (not hardware access)
32+
**Cause**: Actual bugs in WLED firmware
33+
**Analysis**: Look for null pointers, stack overflows, buffer overruns
34+
**Solution**: These should be fixed in the firmware
35+
36+
## Analyzing Crashes
37+
38+
### Check Exception Type
39+
Common ESP32 exceptions:
40+
- `LoadProhibited`: Reading from invalid memory address
41+
- `StoreProhibited`: Writing to invalid memory address
42+
- `IllegalInstruction`: Executing invalid code
43+
44+
### Expected Behavior in QEMU
45+
For WLED testing in QEMU, we expect:
46+
- ✅ Web server to start successfully
47+
- ✅ HTTP requests to be handled
48+
- ✅ Web UI pages to load
49+
- ⚠️ WiFi operations to fail/be limited
50+
- ⚠️ Some LED control features may not work fully
51+
52+
See full QEMU logs in GitHub Actions artifacts.

0 commit comments

Comments
 (0)