Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9e28694
feat: auto capture + replay ESP crashes
dankeboy36 Feb 14, 2026
de132be
chore: use next version lib + bump GH actions
dankeboy36 Feb 14, 2026
3e64f48
fix: add badge + correct hash + ignore incomplete crash
dankeboy36 Feb 14, 2026
79bf756
chore: bump get-next version to verify fail fast
dankeboy36 Feb 15, 2026
e23de81
fix: invalid fetch for next version
dankeboy36 Feb 15, 2026
cb65ca1
fix: code ql; invalid backtick escape
dankeboy36 Feb 15, 2026
5052d04
fix(test): win32 path mismatches for elf guessing
dankeboy36 Feb 15, 2026
555f683
fix: reword welcome
dankeboy36 Feb 16, 2026
4de3ce9
fix: drop fqbn from capturer tree item label
dankeboy36 Feb 16, 2026
c277789
fix: refactor quick fixes
dankeboy36 Feb 16, 2026
cbb659c
fix(test): respect win32 paths for the setup
dankeboy36 Feb 16, 2026
5023241
fix: drop markdown hints
dankeboy36 Feb 17, 2026
6228cec
fix(deps): fixed GDB MI paths on win32 fro trbr
dankeboy36 Feb 18, 2026
ac5a3ca
fix: clear events and delete capturer
dankeboy36 Feb 18, 2026
8d725ef
fix: update main static in readme
dankeboy36 Feb 18, 2026
820df6f
fix: ditch unused reply file
dankeboy36 Feb 18, 2026
2f4e71b
fix: add capture flow to the readme
dankeboy36 Feb 18, 2026
0f53194
fix(doc): :lipstick:
dankeboy36 Feb 18, 2026
ec2d97f
fix: indentation of new-gh notes
dankeboy36 Feb 18, 2026
4485ec6
fix(doc): use old info format for nested sections
dankeboy36 Feb 18, 2026
7801525
fix(doc): correct link to VS Code help
dankeboy36 Feb 19, 2026
869f24d
fix: reduce noisy event tooltip markdown
dankeboy36 Feb 19, 2026
d5952e9
chore: switch to `@vscode/test-cli`, ditch nyc
dankeboy36 Feb 19, 2026
fcaf830
chore: refresh screenshots
dankeboy36 Feb 19, 2026
afdb982
fix: reduce terminal usage screenshot
dankeboy36 Feb 19, 2026
8af9753
fix(doc): add how to reopen/refocus the view
dankeboy36 Feb 19, 2026
02cd7e5
fix(format): :lipstick:
dankeboy36 Feb 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 24 additions & 20 deletions .github/workflows/build.yml → .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build
name: CI
permissions:
contents: read
pull-requests: write
Expand All @@ -22,15 +22,15 @@ jobs:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get_version.outputs.version }}
short_sha: ${{ steps.get_sha.outputs.short_sha }}
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
fetch-depth: 0

- name: Use Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: 22.14.0

Expand All @@ -41,16 +41,16 @@ jobs:
id: get_version
run: |
set -euo pipefail
OUTPUT="$(npx semantic-release --dry-run --no-ci 2>/dev/null || true)"
VERSION="$(echo "$OUTPUT" | awk '/next release version is/ {print $5}' | tail -n1)"
MODE=""
if [ "${{ github.ref }}" = "refs/heads/main" ]; then MODE="--release"; fi
VERSION=$(npx next-version-helper $MODE)
if [ -z "$VERSION" ]; then
VERSION="$(node -p "require('./package.json').version")"
echo "semantic-release did not return a next version." >&2
exit 1
fi
echo "version=$VERSION" >> "$GITHUB_OUTPUT"

- name: Get Short SHA
id: get_sha
run: echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
env:
DEBUG: semantic-release-next-version,semantic-release:*

test:
name: Test (${{ matrix.os }}, node-${{ matrix.node }})
Expand All @@ -62,12 +62,12 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
token: ${{ secrets.GITHUB_TOKEN }}

- name: Use Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: ${{ matrix.node }}

Expand All @@ -92,20 +92,20 @@ jobs:
needs: [test, determine-version]
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false

- name: Use Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: 22.14.0

- name: Install Dependencies
run: npm ci

- name: Set Version
run: npm pkg set version="${{ needs.determine-version.outputs.version }}-preview-${{ needs.determine-version.outputs.short_sha }}"
run: npm pkg set version="${{ needs.determine-version.outputs.version }}"

- name: Package
run: npm run package
Expand All @@ -114,28 +114,32 @@ jobs:
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: esp-exception-decoder-${{ needs.determine-version.outputs.version }}-preview-${{ needs.determine-version.outputs.short_sha }}
name: esp-exception-decoder-${{ needs.determine-version.outputs.version }}
path: '*.vsix'

release:
name: Release
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
runs-on: ubuntu-latest
needs: [test]
needs: [determine-version, test]
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
fetch-depth: 0

- name: Use Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
with:
node-version: 22.14.0

- name: Install Dependencies
run: npm ci

- name: Set Version
run: npm pkg set version="${{ needs.determine-version.outputs.version }}"

- name: Package
run: npm run package

Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ out
dist
node_modules
.vscode-test
coverage
*.vsix
.nyc_output
36 changes: 36 additions & 0 deletions .vscode-test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const noTestTimeout =
typeof process.env.NO_TEST_TIMEOUT === 'string' &&
/true/i.test(process.env.NO_TEST_TIMEOUT)

export default {
tests: [
{
label: 'extension-host',
files: 'out/test/**/*.test.js',
extensionDevelopmentPath: process.cwd(),
skipExtensionDependencies: true,
env: {
TEST_DEBUG: process.env.DEBUG,
NO_COLOR: undefined,
FORCE_COLOR: '1',
MOCHA_COLORS: '1',
},
mocha: {
ui: 'bdd',
color: true,
timeout: noTestTimeout ? 0 : 2_000,
},
},
],
coverage: {
reporter: ['text-summary', 'html', 'lcovonly'],
includeAll: true,
exclude: [
'src/test/**',
'out/test/**',
'**/*.test.*',
'**/test/**',
'**/__tests__/**',
],
},
}
10 changes: 9 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@
"request": "launch",
"args": ["--extensionDevelopmentPath=${workspaceFolder}"],
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
"preLaunchTask": "${defaultBuildTask}"
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack:/esp-exception-decoder/*": "${workspaceFolder}/*",
"webpack://esp-exception-decoder/*": "${workspaceFolder}/*",
"webpack:///./*": "${workspaceFolder}/*",
"webpack://*/./*": "${workspaceFolder}/*",
"webpack://*/*": "${workspaceFolder}/*"
},
"preLaunchTask": "build:webpack:debug"
},
{
"name": "Extension Tests",
Expand Down
15 changes: 14 additions & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@
"version": "2.0.0",
"tasks": [
{
"label": "build:webpack",
"type": "npm",
"script": "build",
"problemMatcher": []
},
{
"label": "build:webpack:debug",
"type": "npm",
"script": "build:debug",
"problemMatcher": []
},
{
"label": "watch:webpack",
"type": "npm",
"script": "watch",
"problemMatcher": "$ts-webpack-watch",
Expand All @@ -28,7 +41,7 @@
},
{
"label": "tasks: watch-tests",
"dependsOn": ["npm: watch", "npm: watch-tests"],
"dependsOn": ["watch:webpack", "npm: watch-tests"],
"problemMatcher": []
},
{
Expand Down
3 changes: 2 additions & 1 deletion .vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ eslint.config.*
.github/**
release.config.js
CHANGELOG.md
.nyc_output
.vscode-test.mjs
coverage/**
62 changes: 52 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,80 @@
# ESP Exception Decoder

ESP Exception Decoder helps you understand crash stack traces and backtraces from ESP8266 and ESP32 boards.
ESP Exception Decoder helps you analyze ESP8266 and ESP32 crashes by decoding stack traces, backtraces, and panic output. It supports both automatic crash capture (recommended) and manual decoding workflows.

![ESP Exception Decoder](./resources/static/esp-exception-decoder-main.png)
![ESP Exception Decoder](./resources/static/esp-exception-decoder.gif)

- **VS Code (recommended):** Runs as a Visual Studio Code extension and integrates with [BoardLab](https://github.com/dankeboy36/boardlab).
- **Arduino IDE 2.2.x (deprecated):** Older **1.x** versions still work when installed manually as a VSIX.
- **Arduino IDE 2.2.x (deprecated):** Only the **1.x** release line is supported via manual VSIX installation.

> [!NOTE]
> **Arduino IDE 2.2.x support is deprecated.**
>
> Starting with version **2.x**, ESP Exception Decoder targets **Visual Studio Code** and requires **BoardLab**.
>
> Arduino IDE 2.2.x users must stay on the **1.x** release line and install the extension manually as a VSIX.
> Arduino IDE 2.2.x users must stay on the **1.x** release line and install the extension manually as a VSIX file.

This extension uses the [TraceBreaker CLI](https://github.com/dankeboy36/trbr) internally. This project is inspired by the original Java-based [ESP8266/ESP32 Exception Stack Trace Decoder](https://github.com/me-no-dev/EspExceptionDecoder). The RISC-V decoder implementation originates from the [`esp_idf_monitor`](https://github.com/espressif/esp-idf-monitor/blob/fae383ecf281655abaa5e65433f671e274316d10/esp_idf_monitor/gdb_panic_server.py).

## Usage

### Recommended: ESP Crash Capturer (VS Code + BoardLab)

1. In BoardLab, select the target **Sketch**, **Board** (`esp32` or `esp8266`), and **Port**.
2. Compile and upload the sketch.
> **ⓘ** Recommended: compile with debug symbols for better stacktrace/source decoding.
3. Open the **ESP Decoder** panel and the **ESP Crash Capturer** view.

> **ⓘ** If you cannot see the **ESP Crash Capturer** view, open the _Command Palette_ (<kbd>Ctrl/⌘</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>) and run `ESP Decoder: Focus on ESP Crash Capturer View`.

4. Click **+** in the view title to create a crash capturer.

![ESP Crash Capturer View](./resources/static/usage-capturer-view-empty.png)

5. Click **Start Capturing** on the capturer item (this enables crash detection for the current device session). The serial monitor is handled automatically.

![ESP Crash Capturer Start Capturing](./resources/static/usage-capturer-start-capturing.png)

6. Reproduce the crash on your board while the monitor is running.
7. Open the captured event with **Preview Crash Event**.

![ESP Crash Capturer Events](./resources/static/usage-capturer-running-events.png)

8. If the capturer reports problems, open **Quick Fixes...** from the capturer item menu.

![ESP Crash Capturer Quick Fixes](./resources/static/usage-capturer-quick-fixes.png)

> [!TIP]
> FQBN mismatch warnings compare the capturer setup with the sketch/build configuration.
> They do not verify the exact firmware currently flashed on the board from monitor output.
> If things look out of sync, recompile, upload again, and sync the capturer target.

The Capturer analyzes the serial monitor stream and groups repeated crash signatures. Each captured crash event can be previewed and decoded without manually copying stack traces. There is no need to stop capturing before compiling or uploading new firmware. Uploads are handled automatically, and a new crash event group is created for the newly flashed ELF. Previously recorded events can be cleared manually if desired.

### Manual: Decoder Terminal (Legacy Workflow)

This workflow is kept for compatibility and for users who already have copied crash output. It does not require a Capturer and works independently of the monitor integration.

Use this if you already have copied crash text and want to decode it manually.

1. Compile the sketch.
2. Upload the sketch to the ESP8266/ESP32 board.
3. Open the Monitor and wait for an exception.
4. When an exception occurs, open the **ESP Exception Decoder terminal**:
- Open the _Command Palette_ using <kbd>Ctrl/⌘</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>.
3. Open the serial monitor and wait for a crash (panic output or backtrace).
4. When a crash occurs, open the **ESP Exception Decoder terminal**:
- Open the _Command Palette_ with <kbd>Ctrl/⌘</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>.
- Run `ESP Exception Decoder: Show Decoder Terminal`.

5. Paste the exception stack trace or backtrace into the decoder terminal.
> **ⓘ** For more details on copying and pasting in the terminal, see the VS Code documentation: https://code.visualstudio.com/docs/terminal/basics#copy-paste

![ESP Exception Decoder Terminal](./resources/static/usage-terminal-manual.png)

> [!TIP]
> For terminal copy/paste details, see: https://code.visualstudio.com/docs/terminal/basics#_copy-paste

## Installation

### VS Code

Install from the Visual Studio Code Marketplace.
Install from the Visual Studio Code Marketplace (required for the 2.x release line).

- ESP Exception Decoder: https://marketplace.visualstudio.com/items?itemName=dankeboy36.esp-exception-decoder

Expand Down
3 changes: 2 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default [
...neostandard({
semi: false,
ts: true,
ignores: ['out', 'dist', 'node_modules', '.vscode-test', '.nyc_output'],
ignores: ['out', 'dist', 'node_modules', '.vscode-test'],
}),
{
plugins: {
Expand All @@ -21,6 +21,7 @@ export default [
'@stylistic/comma-dangle': 'off',
'@stylistic/indent': 'off',
'@stylistic/no-tabs': 'off',
'@stylistic/brace-style': 'off',
'@stylistic/space-before-function-paren': [
'error',
{
Expand Down
Loading