公司动态

Windows 下 STM32MP157‑M4 OpenOCD/GDB 疑难杂症:No registers、10054、UsageFault、编码警告

📅 2026/8/29 20:56:12
Windows 下 STM32MP157‑M4 OpenOCD/GDB 疑难杂症:No registers、10054、UsageFault、编码警告
技术博客面向 STM32MP157 M4 核 LiteOS-M 移植的开发者一句话结论M4 跑在内部 SRAM、用 OpenOCD GDB 在 Windows 上调试坑几乎全在「GDB 与 OpenOCD 的协作方式」上不在你的代码。本文把No registers、10054、UsageFault、CP1252 编码、CFSR 排查这些高频问题一次性讲透。摘要STM32MP157 的 M4 内核调试程序下载到 M4 内部 SRAM。Windows 环境下 OpenOCD GDB 组合会遇到一堆细碎坑新建 GDB 连接后报No registers无法修改 PC/SP关闭 GDB 重连出现 10054 套接字错误刚 attach 直接进入 UsageFault_Handlerprint Reset_Handler出现 CP1252 编码转换警告时而看到?? ()无符号时而直接显示异常函数符号。本文记录完整现象、截图说明、根因、标准调试流程同时补充CFSR 寄存器排查 UsageFault的实战方法。 适用场景STM32MP157 M4 独立运行在内部 SRAM、LiteOS-M 操作系统、GCC Makefile 裸金属开发不使用 Keil、不使用 STM32CubeIDE。1、报错现象 1set $pc 0x1000ddf4→ No registers含编码警告复现控制台完整输出(gdb) print Reset_Handler warning: could not convert Reset_Handler from the host encoding (CP1252) to UTF-32. This normally should not happen, please file a bug report. $1 (text variable, no debug info *) 0x1000ddf4 Reset_Handler (gdb) set $pc 0x1000ddf4 No registers. (gdb) set $pc 0x1000ddf4 No registers.根因1编码警告部分warning: could not convert Reset_Handler from the host encoding (CP1252) to UTF-32.这是 Windows 版arm-none-eabi-gdb工具链的一个老 bugWindows 系统默认代码页是 CP1252GDB 在解析符号名称做编码转换时失败。这个警告可以忽略不影响调试打印出来的函数地址0x1000ddf4是完全正确可用的。⚠️ 坑点不要直接写set $pc Reset_Handler继续使用符号会再次触发编码异常。直接写物理地址数字彻底绕开符号解析问题。2No registers 报错GDB 网络层面已经连上 OpenOCD 服务端但是M4 CPU 内核处于运行状态没有被硬件 halt 暂停。CPU 正在运行时GDB 无法读写内核通用寄存器、PC、SP因此执行set $pc、set $sp直接返回No registers。⚠️ 注意GDB 内置的halt命令在 OpenOCD 场景下无效。必须使用monitor halt把命令转发给 OpenOCD由 OpenOCD 在硬件层面暂停 M4 内核。只有内核 halt 之后才具备读写寄存器权限。正确操作顺序# 硬件暂停 M4 内核拿到寄存器访问权限 monitor halt # 读取向量表 0x10000000获取初始栈指针 SP x/w 0x10000000 # 填入上面 x/w 读到的栈地址 set $sp 0xXXXXXXXX # 使用物理地址设置程序入口规避 Windows gdb 编码 bug set $pc 0x1000ddf4 # 恢复 CPU 运行 continue2、报错现象 2OpenOCD 窗口 WSAGetLastError10054远程主机强迫关闭了一个现有的连接控制台输出Error: Error on socket GDB: WSAGetLastError10054message: 远程主机强迫关闭了一个现有的连接。 Info : dropped gdb connection根因我们直接关掉 GDB 客户端 CMD 窗口TCP 连接被强制断开OpenOCD 作为服务端打印这条日志。10054 不等于硬件故障OpenOCD 进程仍然正常运行ST-Link 连接正常M4 的 SRAM 不会清空上一次下载的程序还保留在内存里。窗口分工非常关键1OpenOCD 窗口服务端尽量后台常驻不要频繁关闭负责 ST-Link 硬件交互。只有 ST-Link 识别失败、芯片 HardFault 锁死时才重启。出现 10054 直接无视不需要重启 OpenOCD。2GDB 窗口客户端可以反复关闭、新建每次新开 GDB 终端必须重新执行连接命令建立 TCP 会话。连接命令选择❌ 不推荐旧命令target remote localhost:3334✅ 推荐使用extended-remote支持多次断开重连适配频繁开关 GDB 场景target extended-remote localhost:33343、现象 3attach 连上直接停在 UsageFault_Handler 异常****控制台现象0x10005a46 in UsageFault_Handler () at Core/Src/stm32mp1xx_it.c:143 143 while (1)两种 attach 现场对比场景 A刚 attach0x00000008 in ?? ()芯片复位、SRAM 为空还没有下载固件。GDB 读取该地址找不到对应 elf 符号信息显示问号?? ()。场景 B刚 attach 直接停在UsageFault_Handler ()有完整源码行号符号复现条件关闭 GDB 客户端芯片不断电、不复位。M4 的 SRAM 是易失内存但只有掉电才会清空关闭 GDB 不会擦除 SRAM上一次跑崩的程序仍然留在内存。上一次运行已经触发 UsageFault 异常死循环在 Fault_Handler重新 attach 上来直接读到内存代码识别到函数符号于是停在异常处理函数。⚠️ 高频大坑monitor load_image重新下载新版 elf 镜像仅仅是把新代码写入 SRAMCPU 的 PC/SP 寄存器不会自动跳转到 Reset_Handler。CPU 还停留在之前 Fault 死循环。下载完成后必须手动monitor halt再手动设置 SP、PC最后continue新程序才会正常启动。4、实战通过 CFSR 寄存器定位 UsageFault 故障根源UsageFault 属于 Cortex-M 内核的用法错误异常常见诱因栈溢出、非对齐访问、跳转到非法指令地址、执行 Thumb 模式错误、访问受保护外设地址。进入 Fault_Handler 死循环之后不要直接复位读取 CFSR 寄存器可以直接定位故障类型。操作步骤GDB 中执行# 内核先暂停 monitor halt # 打印全部内核寄存器里面包含 CFSR 寄存器 monitor reg在输出的一大段寄存器中找到cfsr。CFSR 是 32 位组合故障状态寄存器由三部分拼接低位到高位MMFSR[7:0]Memory Management Fault 状态位 0~7BFSR[15:8]Bus Fault 状态位 8~15UFSR[31:16]Usage Fault 状态位 16~31UFSRUsageFault关键位说明位UFSR 内宏定义CFSR 实际位含义BIT0UNDEFINSTRbit16执行了未定义的指令BIT1INVSTATEbit17无效的 EPSR 状态最常见内核跑进 ARM 模式Cortex-M 只支持 Thumb 指令集BIT2INVPCbit18异常返回时 PC 非法BIT3NOCPbit19访问不存在的协处理器指令BIT8UNALIGNEDbit24非对齐内存访问触发故障BIT9DIVBYZERObit25除零错误举例分析1. 如果看到UFSR BIT11即cfsr的 bit17典型值0x00020000→ INVSTATE根源程序跑入 ARM 指令模式。M4 只支持 Thumb-2 指令集一般是链接脚本入口设置错误或函数指针跳转地址最低位不是 1。Cortex-M 函数指针地址最低 bit 必须置 1代表 Thumb 模式。2. 如果看到UFSR BIT81bit24→ UNALIGNED根源非对齐访问比如对uint32_t变量做 4 字节读取但地址不是 4 字节对齐。LiteOS-M 配置里可以关闭非对齐访问报错。3. 如果看到UFSR BIT01bit16→ UNDEFINSTR根源跑到非法代码地址通常是栈溢出冲毁函数返回地址跳转到随机内存译码出非法指令。大概率任务栈配置太小发生栈溢出。补充读取故障发生时的 PC 地址monitor reg输出里的pc是当前停在 Fault_Handler 的 PC不是故障发生那一刻的 PC。发生异常时内核会把故障现场的 xPSR、PC、LR、R0~R3 压入发生异常时的栈。如果要拿到出事那一刻的 PC需要从 SP 指向的栈帧去回溯——这是 M4 内核调试排错很关键的技巧。 常见踩坑点移植 LiteOS-M任务栈大小配置过小任务运行栈溢出大概率直接触发 UsageFault。优先检查任务栈大小是否足够。5、Windows OpenOCD GDB M4 SRAM 调试完整模板新开 GDB 直接整套复制执行文件名以你工程实际产物为准本例为build/m4_liteos.elf若你的构建产物叫别的名字如liteos_m.elf替换对应路径即可。# 加载 elf 符号信息 file build/m4_liteos.elf # 连接 OpenOCD 服务端 target extended-remote localhost:3334 # 硬件暂停 M4 内核必须否则无法修改 pc/sp monitor halt # 下载镜像写入 M4 内部 SRAM monitor load_image build/m4_liteos.elf # 读取向量表拿到初始栈指针 x/w 0x10000000 # 将上面 x/w 打印出的栈地址替换此处 set $sp 0xXXXXXXXX # Reset_Handler 入口物理地址规避 Windows gdb 编码警告 bug set $pc 0x1000ddf4 # 设置断点示例 b main # 启动内核运行 continue6、全套踩坑总结修改$pc、$sp寄存器之前必须先执行monitor halt硬件暂停 M4 内核否则报No registersGDB 自带halt命令无效。Windows GDB 打印Reset_Handler报 CP1252 编码警告属于工具链 bug地址输出有效直接使用物理数字地址不要使用符号Reset_Handler。OpenOCD 打印 10054 套接字错误只是 GDB 客户端关闭硬件没有问题不要盲目重启 OpenOCD 服务端。M4 内部 SRAM 只有掉电才清空关闭 GDB 不会擦除内存重连会看到上一次程序崩溃现场。monitor load_image下载镜像不会自动复位 CPU下载完成务必手动设置 SP 与 PC否则 CPU 继续跑之前的异常死循环。GDB 连接优先选用target extended-remote不要用老旧target remote更适合反复断开重连调试。遇到 UsageFault 不要直接复位monitor halt monitor reg查看 CFSR 寄存器根据 UFSR 位定位非法指令、Thumb 模式错误、非对齐访问、栈溢出等问题LiteOS-M 移植优先检查任务栈大小是否足够。适用场景STM32MP157 M4 独立运行在内部 SRAM、LiteOS-M 操作系统、GCC Makefile 裸金属开发不使用 Keil、STM32CubeIDE。