我在尝试调试 EFR32BG12 处理器上的硬故障时束手无策。我一直在按照 Silicon Labs 知识库中的说明进行操作:
https://www.silabs.com/community/mcu/32-bit/knowledge-base.entry.html/2014/05/26/debug_a_hardfault-78gc
我也一直在这里使用 Keil 应用笔记来填写一些细节:
http://www.keil.com/appnotes/files/apnt209.pdf
我已经设法让硬故障在一个地方始终如一地发生。当硬故障发生时,知识库文章中的代码为我提供了以下值(在调用硬故障处理程序之前由处理器插入堆栈):
Name Type Value Location
~~~~ ~~~~ ~~~~~ ~~~~~~~~
cfsr uint32_t 0x20000 (Hex) 0x2000078c
hfsr uint32_t 0x40000000 (Hex) 0x20000788
mmfar uint32_t 0xe000ed34 (Hex) 0x20000784
bfar uint32_t 0xe000ed38 (Hex) 0x20000780
r0 uint32_t 0x0 (Hex) 0x2000077c
r1 uint32_t 0x8 (Hex) 0x20000778
r2 uint32_t 0x0 (Hex) 0x20000774
r3 uint32_t 0x0 (Hex) 0x20000770
r12 uint32_t 0x1 (Hex) 0x2000076c
lr uint32_t 0xab61 (Hex) 0x20000768
pc uint32_t 0x38dc8 (Hex) 0x20000764
psr uint32_t 0x0 (Hex) 0x20000760
查看 Keil 应用说明,我相信 0x20000 的 CFSR 值表示设置了 INVSTATE 位的使用错误,即:
INVSTATE: Invalid state: 0 = no invalid state 1 = the processor has attempted to execute an instruction that makes illegal use of the Execution Program Status Register (EPSR). When this bit is set, the PC value stacked for the exception return points to the instruction that attempted the illegal use of the EPSR. Potential reasons: a) Loading a branch target address to PC with LSB=0. b) Stacked PSR corrupted during exception or interrupt handling. c) Vector table contains a vector address with LSB=0.
异常压入堆栈的 PC 值(由知识库文章中的代码提供)似乎是 0x38dc8。如果我在 Simplicity Studio“反汇编”窗口中转到此地址,我会看到以下内容:
00038db8: str r5,[r5,#0x14]
00038dba: str r0,[r7,r1]
00038dbc: str r4,[r5,#0x14]
00038dbe: ldr r4,[pc,#0x1e4] ; 0x38fa0
00038dc0: strb r1,[r4,#0x11]
00038dc2: ldr r5,[r4,#0x64]
00038dc4: ldrb r3,[r4,#0x5]
00038dc6: movs r3,r6
00038dc8: strb r1,[r4,#0x15]
00038dca: ldr r4,[r4,#0x14]
00038dcc: cmp r7,#0x6f
00038dce: cmp r6,#0x30
00038dd0: str r7,[r6,#0x14]
00038dd2: lsls r6,r6,#1
00038dd4: movs r5,r0
00038dd6: movs r0,r0
该地址似乎远远超出了我的代码末尾。如果我在“内存”窗口中查看相同的地址,我会看到:
0x00038DC8 69647561 2E302F6F 00766177 00000005 audio/0.wav.....
0x00038DD8 00000000 000F4240 00000105 00000000 ....@B..........
0x00038DE8 00000000 00000000 00000005 00000000 ................
0x00038DF8 0001C200 00000500 00001000 00000000 .Â..............
0x00038E08 00000000 F00000F0 02F00001 0003F000 ....ð..ð..ð..ð..
0x00038E18 F00004F0 06010005 01020101 01011201 ð..ð............
0x00038E28 35010121 01010D01 6C363025 2E6E6775 !..5....%06lugn.
0x00038E38 00746164 00000001 000008D0 00038400 dat.....Ð.......
奇怪的是,“audio/0.wav”是一个静态字符串,它是固件的一部分。如果我理解正确,我在这里学到的是 PC 以某种方式设置到内存中的这一点,这当然不是有效指令并导致硬故障。
要调试这个问题,我需要知道 PC 是如何被设置为这个不正确的值的。我相信 LR 寄存器应该给我一个想法。异常压入堆栈的LR寄存器似乎是0xab61。如果我查看此位置,我会在“反汇编”窗口中看到以下内容:
1270 dp->sect = clst2sect(fs, clst);
0000ab58: ldr r0,[r7,#0x10]
0000ab5a: ldr r1,[r7,#0x14]
0000ab5c: bl 0x00009904
0000ab60: mov r2,r0
0000ab62: ldr r3,[r7,#0x4]
0000ab64: str r2,[r3,#0x18]
在我看来,这个问题特别是在这次通话中发生的:
0000ab5c: bl 0x00009904
这让我认为问题是由于堆栈损坏导致的,这导致 clst2sect 返回到内存的无效部分而不是 0xab60。 clst2sect 的代码非常无害:
/*-----------------------------------------------------------------------*/
/* Get physical sector number from cluster number */
/*-----------------------------------------------------------------------*/
DWORD clst2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */
FATFS* fs, /* Filesystem object */
DWORD clst /* Cluster# to be converted */
)
{
clst -= 2; /* Cluster number is origin from 2 */
if (clst >= fs->n_fatent - 2) return 0; /* Is it invalid cluster number? */
return fs->database + fs->csize * clst; /* Start sector number of the cluster */
}
这个分析听起来对吗?
我想我遇到的问题是我不知道什么可能导致这种行为......我已经尝试在我所有的中断处理程序中放置断点,看看其中一个是否可能会破坏堆栈,但似乎没有任何模式——有时,没有调用中断处理程序,但问题仍然存在。
但是,在那种情况下,我很难看到程序如何尝试在代码实际结束之后的位置执行代码......我觉得函数指针可能是一个可能的候选者,但在那种情况下我希望看到问题出现,例如,在哪里使用函数指针。但是,我没有看到在发生错误的地方附近使用了任何函数指针。
也许我可以从上面给出的调试信息中提取更多信息?这个问题是非常可重现的,所以如果有什么我没有尝试过,但你认为可能会提供一些见解,我很想听听。
谢谢你的尽心帮助!
最佳答案
经过大约一个月的追逐,我设法确定了问题的原因。我希望我可以在这里提供足够的信息,这对其他人有用。
最后,问题是由将指向非静态局部变量的指针传递给状态机引起的,该状态机稍后更改了该内存位置的值。因为局部变量不再在范围内,所以该内存位置是堆栈中的一个随机点,并且更改那里的值会破坏堆栈。
这个问题很难追踪,原因有两个:
一些工具对确定问题的原因非常有帮助:
感谢@SeanHoulihane 和@cooperised,他们帮助我消除了一些可能的原因,让我对调试工具更有信心。
关于调试 ARM Cortex-M4 中的硬故障,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53253652/