Skip to main content
Use Debug mode when you need to stop the target at a specific point, or inspect its stack, variables, registers, and memory. Embedder starts the debug server for your probe, connects to it, and reports what it finds. Switch with /debug. In VS Code, Debug mode also adds a Debug Output tab to the Embedder Monitor.

Prepare

  1. Build the firmware artifact with debug symbols: an ELF for J-Link or OpenOCD, the CCS debug artifact for TI, or a .xe application for XMOS.
  2. Connect and power the target and probe, or choose the simulator explicitly.
  3. Run /debug and ask Embedder to check debugger readiness.
  4. Name the exact MCU, probe, and artifact when the project has several. If the project has more than one platform, Embedder asks which one to debug.
Then follow the setup guide for your probe or target: Two other probe guides cover work that isn’t interactive debugging: SEGGER J-Trace for Arm ETM instruction trace and coverage, and probe-rs for programming a board on a remote bridge.

How Embedder picks a debugger

Unless you ask for a specific debugger, Embedder chooses in this order:
  1. The Debug Interface value in EMBEDDER.md:
    • jlink selects J-Link, when the SEGGER software is installed.
    • st-link or cmsis-dap selects OpenOCD with that adapter.
    • xgdb selects XMOS xgdb. An XMOS platform or a .embedder/xmos.json file selects it too.
    • xds110, xds100, xds100v1, xds100v2, xds100v3, or ccs selects TI CCS.
  2. A connected J-Link probe, when the J-Link software is installed.
  3. OpenOCD. If no OpenOCD is installed, Embedder downloads its own copy on supported hosts.
Embedder also downloads its own GDB client for J-Link and OpenOCD. See J-Link or OpenOCD for the supported hosts.

Choose programming or attachment

A normal J-Link or OpenOCD connection programs the ELF and tries to run to main. Programming and debugger startup change or halt target execution. Ask for attach-only to load symbols without programming or running to main.
Embedder asks you to approve before it starts a debug server or runs a debugging script, unless your approval settings already allow it. Check the request before you approve: approving is what lets Embedder program or halt the target. Say which behavior you want. The options also appear as arguments in hardware scripts: XMOS behaves differently: no-halt continues execution after connecting, which can resume a halted fault. See XMOS xTAG and xgdb.

Program a fresh debug run

If the target doesn’t reach main within about 5 seconds, Embedder halts it where it is. Check the reported stop location before you rely on the result.

Attach to a running target

Use attach-only with no-halt to look at firmware that’s already running, such as a board that just faulted. These options control what Embedder requests. They don’t guarantee that every probe and target configuration leaves execution untouched during startup. Before connecting to a live fault:
  • Check the setup guide for your probe, and reuse an existing debugger session where possible.
  • State whether a reset or halt is acceptable.
  • Expect to halt the target to read state. Registers, memory, and the stack are read from a halted target, so a running target has to be interrupted first.
“Don’t run to main” and “attach only” are different requests. Turning off run-to-main still programs the target.

Inspect a fault

For a Cortex-M target with a HardFault_Handler symbol:
Once connected, you can ask for:
  • Breakpoints by function, file and line, or address.
  • Continue, interrupt, step, step over, and step out.
  • Stack frames and local variables.
  • Register and memory reads, and expression evaluation.
  • Thread or RTOS task information, when available.
Set breakpoints by asking in chat, as in the examples above, or with gdb.breakpoint() in a hardware script. Embedder doesn’t add a debugger to VS Code’s Run and Debug view, and it doesn’t use breakpoints you set in the editor gutter. A task view depends on the debugger and firmware providing enough information. Variables that are optimized out may need a debug build. TI CCS sessions have no thread or task view, and whether they show the call stack depends on the probe and CCS version; see Supported probes.

Verify peripheral state

Use register lookup to check addresses and access rules first. A reset value in a reference is not a live measurement.

Script helpers

For a repeatable check, a hardware script opens the connection with gdb.jlink_connect(), gdb.openocd_connect(), gdb.ccs_connect(), or gdb.xmos_connect(). Each probe’s guide lists the connection options. These helpers then control and inspect the target:
After gdb.jlink_connect(), gdb.openocd_connect(), or gdb.ccs_connect(), these helpers are available too. Other debuggers report them as unsupported. Breakpoints belong to the script that set them. Embedder removes them when the script exits, including after a failure. J-Link exposes the "default" reset. OpenOCD exposes "halt" and "init", and resets all configured targets. On J-Link and OpenOCD, a reset leaves the target halted, so call gdb.resume() to run. CCS lists the resets its runtime offers.

Finish cleanly

Tell Embedder whether to leave the firmware running or halted, then ask it to disconnect. Other probe operations take over the probe:
  • Flashing closes an open debugger session first.
  • A J-Trace capture closes open debugger and RTT sessions before it starts.

Troubleshoot

  • No debug server found: install the J-Link software, or let Embedder download OpenOCD on a supported host. If that download fails or your host isn’t supported, install OpenOCD yourself. See the guide for your probe.
  • Target not found: check power, probe wiring, device spelling, and the selected interface.
  • OpenOCD can’t match the MCU: use the exact target configuration. Don’t substitute a nearby family.
  • Several platforms: name the MCU you want to debug.
  • Probe busy: close competing debug applications, stop the active hardware task, or run /hardware-queue to check other chats.
  • Target is running: ask Embedder to interrupt it before reading registers, memory, or the stack.
  • Wrong symbols: use the debug artifact from the firmware build that’s on the board.
  • Variable unavailable: check debug information and optimization settings.
Last modified on November 13, 2026