--- name: openocd description: >- OpenOCD 下载与调试工具,用于探针探测、固件烧录、Flash 擦除、GDB Server 启动、目标复位控制、 Telnet 在线调试(halt/resume/step/寄存器/内存/断点)、GDB 源码级调试,以及 Semihosting/ITM 输出捕获和底层查询。 当用户提到 OpenOCD、ST-Link、CMSIS-DAP、DAPLink、FTDI、烧录固件、擦除 Flash、GDB Server、 reset、interface/target/board 配置、openocd.cfg、在线调试、单步、断点、寄存器查看、 内存读写、semihosting 时自动触发,也兼容 /openocd 显式调用。 即使用户只是说"烧录一下"、"启动 GDB Server"、"擦除芯片"、"看看寄存器"、"单步调试" 或"抓一下 semihosting",只要上下文涉及 OpenOCD 支持的开源调试器就应触发此 skill。 argument-hint: "[probe|flash|erase|reset|reset-init|targets|flash-banks|adapter-info|raw|gdb-server|gdb|halt|resume|step|reg|read-mem|write-mem|bp|rbp|run-to|semihosting|itm] ..." --- # OpenOCD 下载与调试 本 skill 提供 OpenOCD 的探针探测、固件烧录、Flash 擦除、GDB Server 启动、目标复位、 Telnet 在线调试、GDB 源码级调试和 Semihosting 输出捕获能力。 ## 配置 ### 环境级配置(skill/config.json) skill 目录下的 `config.json` 包含环境级配置(工具路径、端口号等),首次使用前确认 `exe` 路径正确: ```json { "exe": "openocd", "scripts_dir": "", "gdb_port": 3333, "telnet_port": 4444, "gdb_exe": "", "operation_mode": 1 } ``` - `exe`:openocd.exe 路径或命令名(必填) - `scripts_dir`:OpenOCD 配置脚本目录,为空时使用 OpenOCD 内置路径 - `gdb_port`:GDB Server 端口,默认 3333 - `telnet_port`:Telnet 端口,默认 4444 - `gdb_exe`:arm-none-eabi-gdb 路径,GDB 调试子命令(run/backtrace/locals)需要 - `operation_mode`:`1` 直接执行 / `2` 输出风险摘要但不阻塞 / `3` 执行前确认 ### 工程级配置(.embeddedskills/config.json) board/interface/target 等工程参数统一在工作区的 `.embeddedskills/config.json` 中管理: ```json { "openocd": { "board": "", "interface": "interface/stlink.cfg", "target": "target/stm32f4x.cfg", "adapter_speed": "4000", "transport": "swd", "tpiu_name": "stm32f4x.tpiu", "traceclk": "168000000", "pin_freq": "2000000" } } ``` - `board`:board 配置(如 `board/stm32f4discovery.cfg`),优先级高于 interface+target - `interface`:interface 配置(如 `interface/stlink.cfg`) - `target`:target 配置(如 `target/stm32f4x.cfg`) - `adapter_speed`:调试速率 kHz - `transport`:传输协议(swd/jtag) - `tpiu_name` / `traceclk` / `pin_freq`:ITM/SWO 观测所需的 TPIU 参数 参数解析优先级:**CLI 显式参数 > `.embeddedskills/config.json`(工程级)> `skill/config.json`(环境级)> `.embeddedskills/state.json` > 默认值/报错** 成功执行后,确认过的参数会自动写回工程配置。 ## 子命令 ### 基础操作 | 子命令 | 用途 | 风险 | |--------|------|------| | `probe` | 验证 board 或 interface+target 组合,探测目标连通性 | 低 | | `flash` | 烧录固件(.elf / .hex / .bin) | 高 | | `erase` | 擦除目标 Flash | 高 | | `reset` / `reset-init` | 复位目标芯片 | 高 | | `targets` / `flash-banks` / `adapter-info` | 查询底层 target / flash / adapter 信息 | 低 | | `raw` | 执行受控 OpenOCD 原生命令 | 高 | ### GDB Server | 子命令 | 用途 | 风险 | |--------|------|------| | `gdb-server` | 启动 GDB Server,保持运行等待 GDB 连接 | 低 | | `gdb backtrace/locals` | 快捷获取调用栈和局部变量 | 低 | | `gdb break/continue/next/step/finish/until` | one-shot 执行流控制 | 低 | | `gdb frame/print/watch/disassemble/threads/crash-report` | one-shot 源码级诊断 | 低 | ### Telnet 在线调试 | 子命令 | 用途 | 风险 | |--------|------|------| | `halt` | 暂停 CPU,返回 PC/xPSR | 低 | | `resume` | 恢复 CPU 运行 | 低 | | `step` | 单步执行(支持 `--count N`) | 低 | | `reg` | 查看所有 CPU 寄存器 | 低 | | `read-mem` | 读内存(`--width 8/16/32`,`--length N`) | 低 | | `write-mem` | 写内存(`--width 8/16/32`) | 高 | | `bp` | 设置硬件断点 | 低 | | `rbp` | 移除断点 | 低 | | `run-to` | 运行到指定地址(设置断点 + resume + 等待命中) | 低 | ### Semihosting | 子命令 | 用途 | 风险 | |--------|------|------| | `semihosting` | 启用 ARM Semihosting 并捕获目标 printf 输出 | 低 | | `itm` | 基于 TPIU/ITM 读取 SWO/ITM 观测数据 | 低 | ## 执行流程 1. 读取 `skill/config.json`,确认 `exe` 路径有效 2. 读取 `.embeddedskills/config.json` 获取工程级配置(board/interface/target 等) 3. 读取 `.embeddedskills/state.json` 获取历史状态 4. 参数解析优先级:**CLI 显式参数 > `.embeddedskills/config.json`(工程级)> `skill/config.json`(环境级)> `.embeddedskills/state.json` > 默认值/报错** 5. 已知 `board` 时优先使用 `-f board/*.cfg`,否则组合 `-f interface/*.cfg -f target/*.cfg` 6. `board`、`interface`、`target` 同时缺失时,不自动拼接组合,直接要求用户补充 7. 按 `operation_mode` 决定是否需要确认后执行 8. 根据子命令调用对应脚本 9. 统一解析输出中的 `Info`、`Error` 和就绪日志,返回结构化结果 10. 成功执行后,将确认过的参数写回 `.embeddedskills/config.json` ## 脚本调用 skill 目录下有五个 Python 脚本,使用标准库实现,无额外依赖。 ### openocd_run.py — 探测 / 烧录 / 擦除 / 复位 ```bash # 探测连通性(使用 board) python /scripts/openocd_run.py probe --board board/stm32f4discovery.cfg --json # 探测连通性(使用 interface + target) python /scripts/openocd_run.py probe --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 烧录 ELF 固件 python /scripts/openocd_run.py flash --file build/app.elf --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 烧录 BIN 固件(必须提供地址) python /scripts/openocd_run.py flash --file build/app.bin --address 0x08000000 --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 擦除 Flash(自动选择 mass/sector) python /scripts/openocd_run.py erase --mode auto --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 复位目标 python /scripts/openocd_run.py reset --mode halt --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 查询 target 列表 python /scripts/openocd_run.py targets --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 查询 flash bank python /scripts/openocd_run.py flash-banks --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 执行受控 raw 命令 python /scripts/openocd_run.py raw --interface interface/stlink.cfg --target target/stm32f4x.cfg --command "init" "targets" --json ``` 通用可选参数:`--board `、`--search <目录>`、`--adapter-speed `、`--transport `、`--exe ` ### openocd_gdb.py — GDB Server 启动与调试 ```bash # 启动 GDB Server(保持运行) python /scripts/openocd_gdb.py server --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 无子命令时默认 server(向后兼容) python /scripts/openocd_gdb.py --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 执行自定义 GDB 命令序列 python /scripts/openocd_gdb.py run --gdb-exe arm-none-eabi-gdb --elf build/app.elf --interface interface/stlink.cfg --target target/stm32f4x.cfg --commands "break main" "continue" "backtrace" "info locals" --json # 快捷获取调用栈 python /scripts/openocd_gdb.py backtrace --gdb-exe arm-none-eabi-gdb --elf build/app.elf --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 快捷查看局部变量 python /scripts/openocd_gdb.py locals --gdb-exe arm-none-eabi-gdb --elf build/app.elf --interface interface/stlink.cfg --target target/stm32f4x.cfg --json ``` 可选参数:`--gdb-port`、`--telnet-port`、`--search`、`--adapter-speed`、`--transport`、`--board` ### openocd_telnet.py — Telnet 在线调试 ```bash # 暂停 CPU python /scripts/openocd_telnet.py halt --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 恢复运行 python /scripts/openocd_telnet.py resume --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 单步 5 次 python /scripts/openocd_telnet.py step --count 5 --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 查看寄存器 python /scripts/openocd_telnet.py reg --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 读内存(32bit x 16 个字) python /scripts/openocd_telnet.py read-mem --address 0x20000000 --length 16 --width 32 --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 写内存 python /scripts/openocd_telnet.py write-mem --address 0x20000000 --value 0xDEADBEEF --width 32 --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 设置硬件断点 python /scripts/openocd_telnet.py bp --address 0x08001234 --bp-length 2 --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 移除断点 python /scripts/openocd_telnet.py rbp --address 0x08001234 --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 运行到指定地址(设置断点 + resume + 等待) python /scripts/openocd_telnet.py run-to --address 0x08001234 --timeout-ms 3000 --interface interface/stlink.cfg --target target/stm32f4x.cfg --json ``` 通用可选参数:`--board`、`--search`、`--adapter-speed`、`--transport`、`--gdb-port`、`--telnet-port` ### openocd_semihosting.py — Semihosting 输出捕获 ```bash # 捕获 semihosting 输出(持续到 Ctrl+C) python /scripts/openocd_semihosting.py --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 捕获 30 秒 python /scripts/openocd_semihosting.py --timeout 30 --interface interface/stlink.cfg --target target/stm32f4x.cfg --json ``` ### openocd_itm.py — ITM/SWO 观测 ```bash # 使用配置中的 TPIU 参数持续读取 ITM python /scripts/openocd_itm.py --interface interface/stlink.cfg --target target/stm32f4x.cfg --json # 指定 TPIU 名称和端口 python /scripts/openocd_itm.py \ --interface interface/stlink.cfg --target target/stm32f4x.cfg \ --tpiu-name stm32f4x.tpiu --traceclk 168000000 --pin-freq 2000000 \ --itm-port 0 --itm-port 1 --json ``` `openocd_itm.py` 会启动独立 OpenOCD Server,打开 TPIU/ITM 配置后,把 trace 输出统一包装成 JSON Lines。 ## 调试典型工作流 ### 快速检查(Telnet) ``` halt -> reg -> read-mem 0x20000000 -> step -> resume ``` 适合快速查看当前 CPU 状态和内存内容。 ### 断点调试(Telnet) ``` run-to 0x08001234 -> reg -> read-mem -> resume ``` 运行到指定地址后暂停,检查寄存器和内存。 ### 源码级调试(GDB) ```bash gdb run --elf app.elf --commands "break main" "continue" "backtrace" "info locals" ``` 使用 ELF 文件提供符号信息,进行函数级断点和变量查看。 ### Semihosting 输出 ```bash semihosting ``` 捕获目标通过 `printf`(SVC 指令)输出的调试信息,类似 J-Link RTT。 ## 输出格式 所有脚本以 JSON 格式返回,基础字段为 `status`(ok/error)、`action`、`summary`、`details`,并可能附带 `context`、`artifacts`、`metrics`、`state`、`next_actions`、`timing`。流式观测命令使用 JSON Lines,并统一输出 `source`、`channel_type`、`stream_type`。 成功示例: ```json { "status": "ok", "action": "halt", "summary": "已暂停,PC=0x08000298", "details": { "pc": "0x08000298", "xpsr": "0x01000000", "msp": "0x20020000", "halted": true } } ``` GDB 调用栈示例: ```json { "status": "ok", "action": "backtrace", "summary": "GDB backtrace 执行成功", "details": { "gdb_port": 3333, "frames": [ {"frame": 0, "function": "main", "location": "src/main.c:42"} ] } } ``` 错误示例: ```json { "status": "error", "action": "halt", "error": { "code": "server_failed", "message": "OpenOCD 启动失败或超时" } } ``` ## 核心规则 - 不自动猜测 `board`、`interface`、`target` 的组合,缺失时必须询问用户 - 已知 `board` 时优先使用 board 配置,不再需要 interface+target - 参数解析优先级为:**CLI 显式参数 > `.embeddedskills/config.json`(工程级)> `skill/config.json`(环境级)> `.embeddedskills/state.json` > 默认值/报错** - `.bin` 文件必须显式提供烧录地址,缺失时报错 - STM32F4 等已映射 target 在 `erase --mode auto` 下会先 `reset halt`,再优先使用 mass erase - `erase --mode mass` 在未命中映射时直接返回 `mass_erase_unsupported`,避免误以为已做整片擦除 - 检测到 Flash 锁保护时只提示,不自动解锁 - 连接失败时给出排查建议(检查连线、供电、驱动、cfg 路径),不自动尝试更激进参数 - 烧录、擦除、复位在参数完整且用户意图明确时直接执行 - `gdb-server` 启动后返回端口和连接方式,进程保持运行 - GDB 调试(run/backtrace/locals)需要配置 `gdb_exe`(arm-none-eabi-gdb 路径) - Telnet 调试命令每次启动独立的 OpenOCD Server,执行完自动关闭 - Semihosting 通过 Telnet 启用后持续读取 OpenOCD stderr 输出 - 结果回显中始终包含 cfg 组合、端口和执行动作 - 产物路径(elf/file)不进入工程配置,仍只依赖 `state.json` - `last_flash`/`last_debug`/`last_observe` 等运行状态继续写入 `state.json` ## 参考 遇到 board/interface/target 配置问题时可查阅 `references/common_targets.md`。