Target Control
The Target subsystem controls the execution state of the debug target — halting, resuming, single-stepping, resetting, and querying the current state. Access it through session.target.
TargetState dataclass
Section titled “TargetState dataclass”Most target operations return a TargetState, a frozen dataclass with three fields:
@dataclass(frozen=True)class TargetState: name: str state: Literal["running", "halted", "reset", "debug-running", "unknown"] current_pc: int | None = None| Field | Description |
|---|---|
name | Target name as reported by OpenOCD (e.g. "stm32f1x.cpu") |
state | Current execution state |
current_pc | Program counter value when halted, None otherwise |
The current_pc is only populated when state is "halted". If the target is halted but the PC cannot be read for any reason, current_pc will be None and a debug log message is emitted.
Querying target state
Section titled “Querying target state”Call state() to get the current execution state without changing it:
async with Session.connect() as ocd: state = await ocd.target.state() print(f"Target: {state.name}") print(f"State: {state.state}")
if state.state == "halted" and state.current_pc is not None: print(f"PC: 0x{state.current_pc:08X}")with Session.connect_sync() as ocd: state = ocd.target.state() print(f"Target: {state.name}") print(f"State: {state.state}")
if state.state == "halted" and state.current_pc is not None: print(f"PC: 0x{state.current_pc:08X}")Internally, state() sends the targets command to OpenOCD and parses the tabular output using a regex. The output looks like:
TargetName Type Endian TapName State-- ------------------ ---------- ------ ------------------ ----- 0* stm32f1x.cpu cortex_m little stm32f1x.cpu haltedHalting the target
Section titled “Halting the target”halt() stops the target and returns the resulting state:
state = await ocd.target.halt()print(f"Halted at PC=0x{state.current_pc:08X}")state = ocd.target.halt()print(f"Halted at PC=0x{state.current_pc:08X}")If the target is already halted, halt() succeeds silently (OpenOCD reports “already halted”, which the library does not treat as an error). A TargetError is raised only if the halt command actually fails.
Resuming execution
Section titled “Resuming execution”resume() starts the target running from the current PC, or from a specific address:
# Resume from current PCawait ocd.target.resume()
# Resume from a specific addressawait ocd.target.resume(address=0x08000000)ocd.target.resume()ocd.target.resume(address=0x08000000)resume() returns None. If you need to verify the target started running, call state() afterward.
Single-stepping
Section titled “Single-stepping”step() executes one instruction and returns the resulting state:
state = await ocd.target.step()print(f"Stepped to PC=0x{state.current_pc:08X}")
# Step from a specific addressstate = await ocd.target.step(address=0x08001000)state = ocd.target.step()print(f"Stepped to PC=0x{state.current_pc:08X}")
state = ocd.target.step(address=0x08001000)Like halt(), step() returns a TargetState with the updated program counter.
Resetting the target
Section titled “Resetting the target”reset() issues a target reset with one of three modes:
| Mode | Behavior |
|---|---|
"halt" | Reset and halt at the reset vector (default) |
"run" | Reset and immediately resume execution |
"init" | Reset and run OpenOCD init scripts |
# Reset and halt (most common for debugging)await ocd.target.reset(mode="halt")
# Reset and run (for production flash-and-go)await ocd.target.reset(mode="run")
# Reset and run init scriptsawait ocd.target.reset(mode="init")ocd.target.reset(mode="halt")ocd.target.reset(mode="run")ocd.target.reset(mode="init")reset() returns None. After a reset("halt"), the target should be halted at the reset vector. Query state() to confirm and read the PC.
Waiting for halt
Section titled “Waiting for halt”wait_halt() blocks until the target halts or the timeout expires. This is useful after setting a breakpoint and resuming:
await ocd.target.resume()
try: state = await ocd.target.wait_halt(timeout_ms=5000) print(f"Target halted at PC=0x{state.current_pc:08X}")except TimeoutError: print("Target did not halt within 5 seconds")ocd.target.resume()
try: state = ocd.target.wait_halt(timeout_ms=5000) print(f"Target halted at PC=0x{state.current_pc:08X}")except TimeoutError: print("Target did not halt within 5 seconds")| Parameter | Default | Description |
|---|---|---|
timeout_ms | 5000 | Maximum wait time in milliseconds |
The timeout is enforced by OpenOCD (the wait_halt command), not by the Python library. A TimeoutError is raised if the response contains “timed out” or “time out”. Any other error response raises a TargetError.
Complete workflow example
Section titled “Complete workflow example”A typical debug workflow that halts, inspects, modifies, and resumes:
import asynciofrom openocd import Session, TargetNotHaltedError, TimeoutError
async def debug_session(): async with Session.connect() as ocd: # Reset and halt at the reset vector await ocd.target.reset(mode="halt") state = await ocd.target.state() print(f"Reset vector: 0x{state.current_pc:08X}")
# Step through the first 5 instructions for i in range(5): state = await ocd.target.step() print(f" Step {i+1}: PC=0x{state.current_pc:08X}")
# Set a breakpoint and run to it await ocd.breakpoints.add(0x08001000) await ocd.target.resume()
try: state = await ocd.target.wait_halt(timeout_ms=3000) print(f"Hit breakpoint at PC=0x{state.current_pc:08X}") except TimeoutError: print("Breakpoint not hit, halting manually") await ocd.target.halt()
# Clean up breakpoint and resume await ocd.breakpoints.remove(0x08001000) await ocd.target.resume()
asyncio.run(debug_session())from openocd import Session, TargetNotHaltedError, TimeoutError
with Session.connect_sync() as ocd: ocd.target.reset(mode="halt") state = ocd.target.state() print(f"Reset vector: 0x{state.current_pc:08X}")
for i in range(5): state = ocd.target.step() print(f" Step {i+1}: PC=0x{state.current_pc:08X}")
ocd.breakpoints.add(0x08001000) ocd.target.resume()
try: state = ocd.target.wait_halt(timeout_ms=3000) print(f"Hit breakpoint at PC=0x{state.current_pc:08X}") except TimeoutError: print("Breakpoint not hit, halting manually") ocd.target.halt()
ocd.breakpoints.remove(0x08001000) ocd.target.resume()Method summary
Section titled “Method summary”| Method | Returns | Description |
|---|---|---|
state() | TargetState | Query current state without changing it |
halt() | TargetState | Halt the target |
resume(address=None) | None | Resume execution |
step(address=None) | TargetState | Single-step one instruction |
reset(mode="halt") | None | Reset the target |
wait_halt(timeout_ms=5000) | TargetState | Block until target halts |
Errors
Section titled “Errors”| Exception | When |
|---|---|
TargetError | Any target command fails (halt, resume, step, reset) |
TimeoutError | wait_halt exceeds its deadline |
Next steps
Section titled “Next steps”- Register Access — read and write CPU registers (requires halted target)
- Memory Operations — read and write target memory
- Error Handling — full exception reference