Fix breakpoint_list parser for OpenOCD 0.12.0 dual-format output

OpenOCD uses two different output formats for breakpoint listing within
the same session: Breakpoint(IVA) for hardware (FPB) and IVA breakpoint
for software (patched). The old regex only matched the first format,
causing breakpoint_list() to always return empty when software
breakpoints were present. The third field is a comparator index or bp
number, not a hw/sw type flag — the format variant itself indicates the
breakpoint type.

Verified against live STM32F103C6T6 hardware: 8/9 lifecycle tests pass,
154/154 mock tests pass.
This commit is contained in:
Ryan Malloy 2026-02-17 22:13:50 -07:00
parent f917af678a
commit 2fa4aca286
2 changed files with 16 additions and 7 deletions

View File

@ -27,10 +27,15 @@ class BreakpointError(OpenOCDError):
# Parsers
# ---------------------------------------------------------------------------
# Breakpoint(IVA): 0x08001234, 0x2, 1 (hw=1) or 0 (sw)
# OpenOCD breakpoint listing uses two format variants (even within a single
# session) depending on breakpoint type:
# HW (FPB): Breakpoint(IVA): 0x08000000, 0x2, 0 (third = comparator idx)
# SW (patch): IVA breakpoint: 0x08000100, 0x2, 0x03 (third = bp number)
# The format variant itself indicates hw vs sw; the third field is NOT a type flag.
_BP_RE = re.compile(
r"Breakpoint\([^)]*\):\s*(?P<addr>0x[0-9a-fA-F]+),\s*"
r"(?P<len>0x[0-9a-fA-F]+),\s*(?P<hw>\d+)"
r"(?:(?P<old>Breakpoint\([^)]*\))|(?:(?:IVA|CONTEXT)\s+breakpoint)):\s*"
r"(?P<addr>0x[0-9a-fA-F]+),\s*"
r"(?P<len>0x[0-9a-fA-F]+),\s*(?P<num>0x[0-9a-fA-F]+|\d+)"
)
# Watchpoint output varies across OpenOCD versions. Common formats:
@ -57,11 +62,14 @@ def _parse_breakpoint_list(text: str) -> list[Breakpoint]:
"""Parse the output of ``bp`` (no arguments) into Breakpoint objects."""
breakpoints: list[Breakpoint] = []
for idx, m in enumerate(_BP_RE.finditer(text)):
hw_flag = int(m.group("hw"))
# The "old" named group matches only for the Breakpoint(...) format,
# which OpenOCD uses for hardware (FPB) breakpoints. The bare
# "IVA breakpoint:" format is used for software (patched) breakpoints.
is_hw = m.group("old") is not None
breakpoints.append(
Breakpoint(
number=idx,
type="hw" if hw_flag else "sw",
type="hw" if is_hw else "sw",
address=int(m.group("addr"), 16),
length=int(m.group("len"), 16),
enabled=True,

View File

@ -68,8 +68,9 @@ SCAN_CHAIN_RESPONSE = """\
0 stm32f1x.cpu Y 0x3ba00477 0x3ba00477 4 0x01 0x0f"""
BP_LIST_RESPONSE = """\
Breakpoint(IVA): 0x08001234, 0x2, 1
Breakpoint(IVA): 0x08001300, 0x2, 0"""
Breakpoint(IVA): 0x08001234, 0x2, 0
IVA breakpoint: 0x08001300, 0x2, 0x03
Breakpoint(IVA): 0x08001400, 0x4, 1"""
RTT_CHANNELS_RESPONSE = """\
Up-channels: