【发布时间】:2020-07-21 18:25:06
【问题描述】:
我正在努力处理写入本地/自动/堆栈变量的异常堆栈帧。
我正在为 SAM4L 使用 FreeRTOS 8.2.1 和 Microchip ASF 使用 Eclipse MCU 2018/09 和 Segger J-Link 6.40 进行开发。
[编辑]
第一次通过循环时,r7 具有不同的值(0x200044D0),看起来它可能是正确的值(与 SP 相同)。我现在在想,在等待 RTOS 消息队列时正在更改 r7,这发生在循环的顶部(但不是第一次!)
for(;;){
if(WaitTx(MSG_WAIT_TIME)){ calls xQueuePeek(...)
do{
>> First time here, r7 has the value 0x200044D0
>> Subsequent times, r7 has the value 0x200044B0
// Keep sending data until no more data
MsgBlock_t *tosend = BuildFrame(MSG_MAX_LEN);
if(tosend){
[/编辑]
我有一个运行顶级循环的 RTOS 线程。线程函数中的两个局部变量正在被破坏。在其中一个变量上设置观察点,我看到它在执行中断处理程序的第二条指令时触发。内存转储显示异常堆栈帧已写入线程堆栈的 32 个字节。最低的 5 个堆叠值对应于寄存器 r0-r3,r12。想必其他3个对应着原来的lr、pc和xpsr。这些值看起来正确。 代码:
TC02_Handler:
00013f84: push {r0, r1, r2, r4, r5, r6, r7, lr}
2141 tc_get_status(TC, BOARD_TC_CH_CMX);
00013f86: movs r1, #2 <<< Watchpoint triggers halt here
00013f88: ldr r0, [pc, #132] ;
注册:
r0 = 0x0 == Memory location 0x200044B0
r1 = 0x8 == Memory location 0x200044B4
r2 = 0x0 == Memory location 0x200044B8
r3 = 0x2000aab0 == Memory location 0x200044BC
r4 = 0x2000cd10
r5 = 0x0000cee3
r6 = 0x200044b0
r7 = 0x200044b0
r8-r11 all 0xa5a5a5a5 (RTOS fills stack with this value at startup)
r12= 0x6 == Memory location 0x200044C0
sp = 0x2000e3f8 (nowhere near where exception frame was stacked)
lr = 0xfffffffd
内存:
0x200044B0: 00000000 00000008 00000000 2000AAB0
0x200044C0: 00000006 0000CECB 0000CECC 01000000
---
0x2000E3F8: 00000000 00000008 00000000 2000CD10
0x2000E408: 0000CEE3 200044B0 200044B0 FFFFFFFD
我不明白的是,当观察点在处理程序的入口处触发时,堆栈指针指向一个完全不同的位置。异常堆栈帧被写入位置 0x200044B0 到 0x200044CF,但堆栈指针(在观察点停止 micro 之后)的值是 0x2000E3F8。
异常处理程序的第一条指令压入 r0-r2、r4-r7 和 lr。这些值被推送到 sp 指向的堆栈位置 0x2000E3F8 - 0x2000E417
在进入异常处理程序时,堆栈指针是否应该指向异常堆栈帧的底部?
其他一些与我相关的线索
调试器查看这些自动变量的错误地址。调试器“认为”我的变量应该位于 200044E4 和 200044E8 位置。
当代码访问它们时,它们会从位置 200044C0 和 200044C4 加载。这些是作为从 r7 的偏移量访问的。
ldr r0,[r7,#16] (r7 is 0x200044B0).
and
ldr r0,[r7,#20] (r7 is 0x200044B0).
- 在被破坏的线程执行期间,堆栈指针的值为 0x200044d0,但 r7(我猜它被用作“帧指针”)的值为 0x200044b0。异常栈帧根据sp的值正确放置。
谢谢
【问题讨论】:
-
答案取决于您用于给定目标/工具链的 freeRTOS 端口。 freeRTOS 文档中可能至少有一些抽象语句,所以你应该先检查一下。请注意,每个 freeRTOS 端口都可能以不同的方式处理这个问题。对于一个不同的 freeRTOS 端口,我看到 IRQ 处理程序将中断的上下文放置到专用的系统堆中,并将调度任务的上下文放置到它们各自的堆栈中。
-
感谢@HelpingHand - 看起来初始中断堆栈帧进入活动线程的堆栈,然后 FreeRTOS 切换到专用中断堆栈。这个问题神奇地消失了(在 PC 重新启动后,但没有重建)。我唯一的猜测是设备 Flash 中留下了一些调试器代码,这把事情搞砸了。
-
不客气 - 我很高兴你能解决你的问题。我从来没有听说过重新启动(开发)PC 可以解决出现在目标上的问题(或者它是由 freeRTOS 运行的 PC,哈哈……)。也许,您已经在构建 PC 上安装了一些工具或库,并且必须重新加载一些路径变量和脚本才能再次正常工作。