Skip to content

Debug Session

This example demonstrates a typical debug workflow: connect to OpenOCD, halt the target, inspect registers and memory, single-step through code, and resume execution.

import asyncio
import logging
from openocd import Session, TargetError, TargetNotHaltedError, ConnectionError
logging.basicConfig(level=logging.INFO)
log = logging.getLogger("debug-session")
async def main():
# --- Connect ---
try:
session = await Session.connect(host="localhost", port=6666, timeout=5.0)
except ConnectionError as e:
log.error("Cannot connect to OpenOCD: %s", e)
log.error("Make sure OpenOCD is running with TCL RPC enabled on port 6666")
return
async with session:
# --- Check initial state ---
state = await session.target.state()
log.info("Target: %s, State: %s", state.name, state.state)
# --- Halt ---
if state.state != "halted":
log.info("Halting target...")
try:
state = await session.target.halt()
except TargetError as e:
log.error("Failed to halt: %s", e)
return
log.info("Halted at PC=0x%08X", state.current_pc or 0)
# --- Read registers ---
pc = await session.registers.pc()
sp = await session.registers.sp()
lr = await session.registers.lr()
log.info("PC=0x%08X SP=0x%08X LR=0x%08X", pc, sp, lr)
# Read all general-purpose registers
all_regs = await session.registers.read_all()
for name, reg in sorted(all_regs.items(), key=lambda x: x[1].number):
if reg.number <= 15: # r0-r15 on ARM
log.info(" %-6s = 0x%08X%s",
reg.name, reg.value,
" (dirty)" if reg.dirty else "")
# --- Read memory around PC ---
log.info("Memory at PC (8 words):")
words = await session.memory.read_u32(pc, count=8)
for i, word in enumerate(words):
log.info(" 0x%08X: 0x%08X", pc + i * 4, word)
# --- Hexdump of stack ---
log.info("Stack (64 bytes from SP):")
hexdump = await session.memory.hexdump(sp, 64)
for line in hexdump.splitlines():
log.info(" %s", line)
# --- Single-step ---
log.info("Single-stepping 3 instructions...")
for i in range(3):
state = await session.target.step()
new_pc = state.current_pc or 0
log.info(" Step %d: PC=0x%08X", i + 1, new_pc)
# --- Resume ---
log.info("Resuming execution...")
await session.target.resume()
# Verify the target is running
state = await session.target.state()
log.info("Target state after resume: %s", state.state)
log.info("Session closed")
asyncio.run(main())
import logging
from openocd import Session, TargetError, ConnectionError
logging.basicConfig(level=logging.INFO)
log = logging.getLogger("debug-session")
def main():
# --- Connect ---
try:
session = Session.connect_sync(host="localhost", port=6666, timeout=5.0)
except ConnectionError as e:
log.error("Cannot connect to OpenOCD: %s", e)
return
with session:
# --- Check initial state ---
state = session.target.state()
log.info("Target: %s, State: %s", state.name, state.state)
# --- Halt ---
if state.state != "halted":
log.info("Halting target...")
try:
state = session.target.halt()
except TargetError as e:
log.error("Failed to halt: %s", e)
return
log.info("Halted at PC=0x%08X", state.current_pc or 0)
# --- Read registers ---
pc = session.registers.pc()
sp = session.registers.sp()
lr = session.registers.lr()
log.info("PC=0x%08X SP=0x%08X LR=0x%08X", pc, sp, lr)
# Read all general-purpose registers
all_regs = session.registers.read_all()
for name, reg in sorted(all_regs.items(), key=lambda x: x[1].number):
if reg.number <= 15:
log.info(" %-6s = 0x%08X%s",
reg.name, reg.value,
" (dirty)" if reg.dirty else "")
# --- Read memory around PC ---
log.info("Memory at PC (8 words):")
words = session.memory.read_u32(pc, count=8)
for i, word in enumerate(words):
log.info(" 0x%08X: 0x%08X", pc + i * 4, word)
# --- Hexdump of stack ---
log.info("Stack (64 bytes from SP):")
hexdump = session.memory.hexdump(sp, 64)
for line in hexdump.splitlines():
log.info(" %s", line)
# --- Single-step ---
log.info("Single-stepping 3 instructions...")
for i in range(3):
state = session.target.step()
new_pc = state.current_pc or 0
log.info(" Step %d: PC=0x%08X", i + 1, new_pc)
# --- Resume ---
log.info("Resuming execution...")
session.target.resume()
state = session.target.state()
log.info("Target state after resume: %s", state.state)
log.info("Session closed")
main()
INFO:debug-session:Target: stm32f1x.cpu, State: running
INFO:debug-session:Halting target...
INFO:debug-session:Halted at PC=0x08001234
INFO:debug-session:PC=0x08001234 SP=0x20004FF0 LR=0x08000A51
INFO:debug-session: r0 = 0x00000001
INFO:debug-session: r1 = 0x20000100
INFO:debug-session: r2 = 0x00000000
INFO:debug-session: ...
INFO:debug-session:Memory at PC (8 words):
INFO:debug-session: 0x08001234: 0x4B02B510
INFO:debug-session: 0x08001238: 0x47984601
INFO:debug-session: ...
INFO:debug-session:Stack (64 bytes from SP):
INFO:debug-session: 20004FF0: 08 00 0A 51 00 00 00 00 01 00 00 00 00 01 00 20 |...Q........... |
INFO:debug-session: ...
INFO:debug-session:Single-stepping 3 instructions...
INFO:debug-session: Step 1: PC=0x08001236
INFO:debug-session: Step 2: PC=0x08001238
INFO:debug-session: Step 3: PC=0x0800123A
INFO:debug-session:Resuming execution...
INFO:debug-session:Target state after resume: running
INFO:debug-session:Session closed
  • Always check the target state before operating. Some operations (register reads, memory inspection) require a halted target.
  • The TargetState dataclass includes current_pc only when the target is halted. Check for None before using it.
  • Use session.registers.read_all() for a snapshot of all registers, or individual accessors like session.registers.pc() for specific values.
  • session.memory.hexdump() returns a formatted string — it does not print directly. This lets you log or display it however you prefer.
  • The session context manager (async with / with) ensures the connection is closed cleanly on exit, even if an exception occurs.