GDB(通过pyocd)读取MAX32660内存显示陈旧内容的问题
我使用SWD探针在MAX32660上运行下述程序,同时向内存地址0x20017000写入数据:
while (true) { DEBUG("x=%d", *(int volatile*)0x20017000); Tick_Delay_US(1000000); }
程序运行正常,能正确显示探针写入的数值:
92503131 main.c:81 x=125300000 93503118 main.c:81 x=125400000 94503104 main.c:81 x=125600000 95503090 main.c:81 x=125700000 96503077 main.c:81 x=125900000 97503063 main.c:81 x=126100000 98503050 main.c:81 x=126200000 99503036 main.c:81 x=126400000
但通过pyocd server连接的GDB存在问题:每次程序停止后,仅能读取一次内存中的最新值,后续重复读取都返回相同的缓存值:
(gdb) print *(int volatile*)0x20017000 $1 = 178700000 (gdb) print *(int volatile*)0x20017000 $2 = 178700000 (gdb) print *(int volatile*)0x20017000 $3 = 178700000 (gdb) cont Continuing. ^C Program received signal SIGINT, Interrupt. 0x000003aa in Tick_Reached (target=<optimized out>) at ../../max/Tick.h:60 60 {while (!Tick_Reached(target));} (gdb) print *(int volatile*)0x20017000 $8 = 180800000 (gdb) print *(int volatile*)0x20017000 $9 = 180800000
查看探针日志发现,GDB仅在第一次请求时通过MEM-AP的TAR/DRW寄存器读取该值,后续均未重新发起读取请求。
我原本以为GDB会在程序停止时快照内存,但实际是按需读取却只缓存第一次的结果,这种情况实用性很低。想请教两个问题:
- 程序运行状态与内存缓存的关联是什么?
- 除了重新运行程序外,有没有办法强制GDB重新读取内存中的值?
1. 程序运行状态与内存缓存的关联
GDB的内存缓存策略和程序是否处于运行/停止状态直接绑定:
- 程序运行时,GDB不会缓存内存数据——因为此时内存可能被程序或外部探针随时修改,缓存完全没有意义。
- 程序停止(比如中断、断点触发)后,GDB默认判定内存状态稳定,后续重复的内存读取请求会直接返回缓存结果,以此减少SWD总线的通信开销。
你遇到的特殊情况是:程序停止后,外部探针仍在修改0x20017000的内存,但GDB默认假设停止后的内存不会被自身以外的因素修改,所以不会主动重新读取。另外要注意,目标代码中的volatile关键字只影响编译器的编译行为(不让编译器缓存变量),对GDB的调试缓存策略没有作用,GDB不识别这个标记。
2. 强制GDB重新读取内存的方法
有几种实用方法可以绕过缓存,强制读取目标硬件的最新内存值:
方法1:清空缓存后重新读取
执行flushregs命令清空GDB的寄存器和内存缓存,之后再执行print就会重新从目标硬件读取:
(gdb) flushregs (gdb) print *(int volatile*)0x20017000
方法2:标记目标地址为非缓存区域
用mem命令将0x20017000地址设置为非缓存区域,后续所有对该地址的读取都会直接访问硬件:
(gdb) mem 0x20017000 0x4 nocache
其中0x4是内存区域大小(对应int类型的4字节),nocache表示禁用缓存。
方法3:使用x命令读取
x(examine)命令默认绕过缓存,直接读取目标内存,用它查看地址值会每次都获取最新数据:
(gdb) x/d 0x20017000
/d表示以十进制格式显示,效果和print一致,但不会使用缓存。
方法4:全局禁用远程缓存
如果需要全局关闭GDB的远程内存缓存,执行以下命令即可,所有内存读取请求都会直接发送到目标硬件:
(gdb) set remotecache off
注意:这个设置会增加SWD总线的通信量,可能降低调试速度,不需要时可以用set remotecache on恢复默认。
内容的提问来源于stack exchange,提问作者personal_cloud

