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 # 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( _BP_RE = re.compile(
r"Breakpoint\([^)]*\):\s*(?P<addr>0x[0-9a-fA-F]+),\s*" r"(?:(?P<old>Breakpoint\([^)]*\))|(?:(?:IVA|CONTEXT)\s+breakpoint)):\s*"
r"(?P<len>0x[0-9a-fA-F]+),\s*(?P<hw>\d+)" 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: # 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.""" """Parse the output of ``bp`` (no arguments) into Breakpoint objects."""
breakpoints: list[Breakpoint] = [] breakpoints: list[Breakpoint] = []
for idx, m in enumerate(_BP_RE.finditer(text)): 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( breakpoints.append(
Breakpoint( Breakpoint(
number=idx, number=idx,
type="hw" if hw_flag else "sw", type="hw" if is_hw else "sw",
address=int(m.group("addr"), 16), address=int(m.group("addr"), 16),
length=int(m.group("len"), 16), length=int(m.group("len"), 16),
enabled=True, enabled=True,

View File

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