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.
Async version
Section titled “Async version”import asyncioimport loggingfrom 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())Sync version
Section titled “Sync version”import loggingfrom 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()Expected output
Section titled “Expected output”INFO:debug-session:Target: stm32f1x.cpu, State: runningINFO:debug-session:Halting target...INFO:debug-session:Halted at PC=0x08001234INFO:debug-session:PC=0x08001234 SP=0x20004FF0 LR=0x08000A51INFO:debug-session: r0 = 0x00000001INFO:debug-session: r1 = 0x20000100INFO:debug-session: r2 = 0x00000000INFO:debug-session: ...INFO:debug-session:Memory at PC (8 words):INFO:debug-session: 0x08001234: 0x4B02B510INFO:debug-session: 0x08001238: 0x47984601INFO: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=0x08001236INFO:debug-session: Step 2: PC=0x08001238INFO:debug-session: Step 3: PC=0x0800123AINFO:debug-session:Resuming execution...INFO:debug-session:Target state after resume: runningINFO:debug-session:Session closedKey points
Section titled “Key points”- Always check the target state before operating. Some operations (register reads, memory inspection) require a halted target.
- The
TargetStatedataclass includescurrent_pconly when the target is halted. Check forNonebefore using it. - Use
session.registers.read_all()for a snapshot of all registers, or individual accessors likesession.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.