我试图在我的代码中找出一个特定的中断发生在哪里。在本例中,它位于stm32f4微控制器上,中断是SysTick_Handler。
我想要的基本上是从系统中断发生的地方找出答案。我正在使用arm-none-eabi-gdb试图找到回溯,但我从那里得到的唯一信息是:
(gdb) bt
#0 SysTick_Handler () at modules/profiling.c:66
#1 <signal handler called>
#2 0x55555554 in ?? () Backtrace stopped: previous frame identical to this frame (corrupt stack?)如何获得中断启动前程序所在位置的一些信息?
看看arm文档这里,我似乎应该能够读取堆栈指针,并从那里获得PC。但是,这正是GDB的展开器正在做的事情,不是吗?
发布于 2016-08-03 11:44:43
正如你们中的许多人所评论的,PC将位于两个不同的堆栈中,我解决这个问题的方法是在汇编中找到一个HardFault_Handling代码,并从那里获取我需要的东西。为了正确地获得PC值,我使用以下代码。
register int *r0 __asm("r0");
__asm( "TST lr, #4\n"
"ITE EQ\n"
"MRSEQ r0, MSP\n"
"MRSNE r0, PSP\n" // stack pointer now in r0
"ldr r0, [r0, #0x18]\n" // stored pc now in r0
//"add r0, r0, #6\n" // address to stored pc now in r0
);中断发生的位置的值现在可以由
uint32_t PC = *r0;现在可以用来做任何我想要的东西。不幸的是,我没有设法让GDB为我自动展开堆栈。但至少我知道了中断是在哪里发射的,这就是目标。
发布于 2016-08-02 18:52:57
问题结束时你走在了正确的轨道上。ARM Cortex-M核有两个堆栈指针,主堆栈指针(MSP,用于中断)和进程堆栈指针(PSP,用于任务)。
当具有优先级的中断出现时,当前寄存器值(大多数寄存器)被推入当前堆栈(如果中断后台应用程序,则将PSP推入当前堆栈;如果中断优先级较低的中断,则将PSP推送到当前堆栈),然后堆栈切换到MSP (如果还没有)。
当您第一次输入中断时,链接寄存器(LR,返回地址)的值主要是F的,而不是实际的返回地址。此值告诉核心在分支到时如何退出。通常,如果后台任务被中断,您将看到一个0xFFFFFFFD的值,如果低优先级的中断被中断,您将看到一个0xFFFFFFF1。如果使用浮点单元,则这些值将有所不同。不过,这个值的神奇之处在于,bit 2 (0x4)告诉您堆栈框架是在PSP还是MSP上。
一旦您确定您的框架处于哪个堆栈上,您就可以通过查看相应的堆栈指针减去24 (6 32位位置)找到正在执行的地址。参见链接中的图2.3。这将指向你被打断的个人电脑。
发布于 2016-08-02 21:36:47
我们不断地看到这个问题的各种形式,人们不断地说有两个堆栈。所以我自己用糖浆试试看。
文档中说,我们处于线程模式,没有重置,如果您停止使用openocd,它会说
target halted due to debug-request, current mode: Thread 我有一些代码可以转储寄存器:
20000000 APSR
00000000 IPSR
00000000 EPSR
00000000 CONTROL
00000000 SP_PROCESS
20000D00 SP_PROCESS after I modified it
20000FF0 SP_MAIN
20000FF0 mov r0,sp
then I dump the stack up to 0x20001000 which is where I know my stack started
20000FF0 00000000
20000FF4 00000000
20000FF8 00000000
20000FFC 0100005F 我设置并等待一个系统中断,处理程序转储寄存器和ram,然后进入无限循环。一般情况下练习不好,但这里只是调试/学习而已。在中断之前,我准备一些寄存器:
.thumb_func
.globl iwait
iwait:
mov r0,#1
mov r1,#2
mov r2,#3
mov r3,#4
mov r4,#13
mov r12,r4
mov r4,#15
mov r14,r4
b .在处理程序中我看到
20000000 APSR
0000000F IPSR
00000000 EPSR
00000000 CONTROL
20000D00 SP_PROCESS
20000FC0 SP_MAIN
20000FC0 mov r0,sp
20000FC0 0000000F
20000FC4 20000FFF
20000FC8 00000000
20000FCC FFFFFFF9 this is our special lr (not one rjp mentioned)
20000FD0 00000001 this is r0
20000FD4 00000002 this is r1
20000FD8 00000003 this is r2
20000FDC 00000004 this is r3
20000FE0 0000000D this is r12
20000FE4 0000000F this is r14/lr
20000FE8 01000074 and this is where we were interrupted from
20000FEC 21000000 this is probably the xpsr mentioned
20000FF0 00000000 stuff that was there before
20000FF4 00000000
20000FF8 00000000
20000FFC 0100005F
01000064 <iwait>:
1000064: 2001 movs r0, #1
1000066: 2102 movs r1, #2
1000068: 2203 movs r2, #3
100006a: 2304 movs r3, #4
100006c: 240d movs r4, #13
100006e: 46a4 mov ip, r4
1000070: 240f movs r4, #15
1000072: 46a6 mov lr, r4
1000074: e7fe b.n 1000074 <iwait+0x10>
1000076: bf00 nop因此,在本例中,直接从ARM文档中可以看出,它不是在使用sp_process,而是在使用sp_main。它正在推送手册上表示正在推送的项目,包括中断/返回地址,即0x1000074。
现在,如果我设置了SPSEL位(请注意先设置PSP ),那么在应用程序/线程模式中的mov r0,sp将使用PSP。但是,处理程序使用msp作为mov r0,sp,但似乎将
在线程/前台之前
20000000 APSR
00000000 IPSR
00000000 EPSR
00000000 SP_PROCESS
20000D00 SP_PROCESS modified
00000000 CONTROL
00000002 CONTROL modified
20000FF0 SP_MAIN
20000D00 mov r0,sp现在在处理程序中
20000000 APSR
0000000F IPSR
00000000 EPSR
00000000 CONTROL (interesting!)
20000CE0 SP_PROCESS
20000FE0 SP_MAIN
20000FE0 mov r0,sp
dump of that stack
20000FE0 0000000F
20000FE4 20000CFF
20000FE8 00000000
20000FEC FFFFFFFD
20000FF0 00000000
20000FF4 00000000
20000FF8 00000000
20000FFC 0100005F
dump of sp_process stack
20000CE0 00000001
20000CE4 00000002
20000CE8 00000003
20000CEC 00000004
20000CF0 0000000D
20000CF4 0000000F
20000CF8 01000074 our return value
20000CFC 21000000 因此,要处理人们一直提到的备用堆栈,您必须将自己置于该位置(或一些您所依赖的代码)。为什么你会想要这样做的简单裸金属程序,谁知道,所有的零控制寄存器是好的和容易的,可以共享一个堆栈很好。
我不使用gdb,但您需要让它转储所有寄存器sp_process和sp_main,然后根据您发现的内容,然后在每个目录中转储十几个单词,在其中您应该看到0xFFFFFFFFx作为一个标记,然后从它中计数以查看返回地址。您也可以让您的处理程序读取两个堆栈指针,然后查看gprs。使用gnu汇编程序mrs rX,psp;mrs rX,msp;用于进程和主堆栈指针。
https://stackoverflow.com/questions/38724658
复制相似问题