bkpt_probe
One operation per invocation, one JSON object on stdout, exit 0. A failure still prints JSON: {"ran":false,"error":"..."} when the probe could not be opened, {"ran":true,"ok":false,"error":"...","addr":"0x..."} when the target refused an access. Every verb except list opens the probe, attaches over SWD without resetting the target, does its work, and releases the probe (an ST-LINK gets its DBG_EXIT, so the next opener finds it clean).
bkpt_probe <list|info|read-mem|write-mem|detect-trace|fault|reset-usb> [--probe stlink|jlink|auto] [--serial S] [--speed KHZ] [--jlink-dir DIR] [--device NAME]
list
Every probe on USB, no target access.
$ bkpt_probe list
{"ran":true,"probes":[{"kind":"stlink","serial":"0033004B3033510735393935","version":"STLINK-V3","vid":"0x0483","pid":"0x374e"}]}
info
Opens the probe, attaches, reads the DP IDCODE.
$ bkpt_probe info --probe stlink --serial 0033004B3033510735393935
{"ran":true,"present":true,"kind":"stlink","serial":"0033004B3033510735393935","version":"STLINK-V3 fw J17 @ 24000 kHz ap0","swo_max_hz":24000000,"idcode":"0x2ba01477","link":true}
version names the firmware and the SWD clock actually applied; swo_max_hz is the probe's SWO receiver ceiling (0 when it has none), the number the BKPT Debug extension bounds the SWO clock with; idcode is the debug port's ID (0x2ba01477 on every Cortex-M4). "present":true,"link":false means the probe answered but the target did not (unpowered, no SWD wiring, held in reset).
read-mem, write-mem
$ bkpt_probe read-mem --probe stlink --serial 0033004B3033510735393935 --addr 0xE000ED00 --len 4
{"ran":true,"ok":true,"addr":"0xe000ed00","len":4,"data":"41c20f41"}
$ bkpt_probe read-mem --probe stlink --addr 0xE000ED00,0xE000ED28 --len 4
{"ran":true,"ok":true,"reads":[{"addr":"0xe000ed00","len":4,"data":"41c20f41"},{"addr":"0xe000ed28","len":4,"data":"00000000"}]}
$ bkpt_probe write-mem --probe stlink --addr 0x20000100 --data 78563412
{"ran":true,"ok":true,"writes":[{"addr":"0x20000100","ok":true}]}
data is the raw little-endian bytes as hex (41c20f41 is CPUID 0x410FC241). A comma-separated --addr list (up to 64) reads or writes each in one probe session; --len applies to each read; --data takes one hex-byte string per address, whole words. Both stop at the first failure, whose entry carries "ok":false and the error, and the envelope then ends with "ok":false. Memory access goes over the MEM-AP while the core runs; nothing is halted.
detect-trace
The CoreSight ROM-table walk plus the trace-capability verdicts: what this core has and whether each hardware-trace feature can be used.
$ bkpt_probe detect-trace --probe stlink --serial 0033004B3033510735393935
{"ran":true,"present":true,
"probe":{"kind":"stlink","version":"STLINK-V3 fw J17 @ 24000 kHz ap0","swo_max_hz":24000000},
"idcode":"0x2ba01477","verdict":"pins","etm":true,"etmV4":false,
"sink":{"present":false,"kind":"none","base":null},"debugLocked":false,"rombase":"0xe00ff000","coreAp":0,
"components":[{"base":"0xe000e000","part":"0x00c","name":"SCS-M4","class":14},{"base":"0xe0001000","part":"0x002","name":"DWT","class":14},
{"base":"0xe0002000","part":"0x003","name":"FPB","class":14},{"base":"0xe0000000","part":"0x001","name":"ITM","class":14},
{"base":"0xe0040000","part":"0x9a1","name":"TPIU-M4","class":9,"coresight":true,"devtype":"0x11","devid":"0x00000ca1"},
{"base":"0xe0041000","part":"0x925","name":"ETM-M4","class":9,"coresight":true,"devtype":"0x13"}],
"dwt":{"present":true,"numcomp":4,"notrcpkt":false,"nocyccnt":false,"noprfcnt":false,"noexttrig":false,"ctrl":"0x40000001","func_id":[0,0,0,0]},
"itm":{"present":true,"ports":32},
"tpiu":{"present":true,"protocols":["nrz"]},
"verdicts":{"pc-sampling-onchip":"ok","exception-trace":"ok","data-trace":"ok","event-counters":"ok","itm-console":"ok","pc-sampling-poll":"ok"}}
| FIELD | MEANING |
|---|---|
verdict | How ETM trace could leave the chip: pins (a TPIU with a parallel trace port, the BKPT#1 case), etb (an on-chip buffer), unknown |
etm, etmV4 | An ETM is present, and whether it is ETMv4 |
sink | An on-chip trace sink (ETB/ETF) when there is one |
debugLocked | The ROM walk came back empty on a present target: debug access is disabled by option bytes or RDP |
components[] | Every ROM-table entry with its base, part number, name and class |
dwt | DWT_CTRL decoded: comparator count (numcomp), and the no* bits that say what the vendor left out (notrcpkt = no trace packets, so no PC sampling or exception trace over SWO; nocyccnt; noprfcnt = no event counters) |
itm, tpiu | Presence, stimulus port count, trace protocols |
verdicts | One per hardware-trace feature: ok or the reason it cannot be used on this core. The BKPT Debug extension's Target scan is this call |
--peek 0xADDR[,0xADDR...] adds 32-bit reads in the same session (the extension peeks DWT_CTRL this way). With a J-Link always pass --device (the SEGGER name, STM32G474RE): a generic attach makes the walk unreliable, and the tool says so instead of returning a verdict it cannot trust.
fault
Snapshots and decodes the Cortex-M fault state: halts a running core for the capture, reads the fault registers and the exception frame, and resumes it (--keep-halted leaves it stopped).
$ bkpt_probe fault --probe stlink --serial 0033004B3033510735393935
{"ran":true,"was_running":true,"left_halted":false,
"report":{"event":"fault","caught":"halted",
"arch":{"profile":"armv7-m","core":"Cortex-M4","cpuid":"0x410FC241","fpu":true,"security":false,"mpu_regions":8},
"exception":{"number":0,"name":"Thread"},"root_cause":"Thread","escalated":false,"faults":[],
"fault_address":{"valid":false},"precision":"n/a","exc_return":{"valid":false},"frame":{"trust":"none"},
"regs":{"r0":"0xD149043B", ..., "sp":"0x2001FF88","lr":"0x080005A1","pc":"0x08001406","xpsr":"0x81000000","msp":"0x2001FF88","psp":"0x00000000","control":"0x00","faultmask":"0x00","basepri":"0x00"}, ...}}
On a healthy core (above) exception.number is 0 and faults is empty. On a faulted one the report names the active exception, the root cause (HardFault escalated from a UsageFault INVSTATE, a BusFault PRECISERR with a valid fault_address, and so on), the decoded CFSR/HFSR/MMFAR/BFAR bits, the EXC_RETURN, and the stacked frame with how far it can be trusted. This is the same report the BKPT Debug Fault Analyzer shows, and bkpt_gdbserver's monitor fault.
reset-usb
For an ST-LINK that answers nothing (a session killed mid-transfer used to leave one streaming SWO): a libusb port reset, a re-open by serial, and a CPUID read to prove it is back.
$ bkpt_probe reset-usb --probe stlink --serial 0033004B3033510735393935
{"ran":true,"ok":true,"idcode":"0x2ba01477","cpuid":"0x410fc241"}
Unsupported on a J-Link (the SEGGER library owns the device). When even this fails, the probe needs a power cycle.
Exit codes and errors
The process exits 0 whenever it ran; read ran, ok and error in the JSON. Probe-open failures name the cause: no matching probe on USB, probe present but claimed by another process (a debugger session or another tool holds it), GET_CURRENT_MODE failed (an ST-LINK left mid-stream, try reset-usb), J-Link library not found (--jlink-dir).