如何释放ARM Cortex M3堆栈

贝特曼鲁

当发生崩溃时,ARM Coretex STM32的HardFault_Handler只能获取几个寄存器值,分别为r0,r1,r2,r3,lr,pc,xPSR。但是堆栈中没有FP和SP。因此我无法解开堆栈。有什么解决办法吗?非常感谢。

[更新]
遵循Web指令,通过添加编译选项“ --use_frame_pointer”,让ARMGCC(Keil uvision IDE)生成FP,但是我在堆栈中找不到FP。我是一个真正的新手。下面是我的演示代码:

int test2(int i, int j)
{
    return i/j;
}

int main()
{
    SCB->CCR |= 0x10;
    int a = 10;
    int b = 0;
    int c;
    c = test2(a,b);
}

enum { r0 = 0, r1, r2, r3, r11, r12, lr, pc, psr};
void Hard_Fault_Handler(uint32_t *faultStackAddress)
{
    uint32_t r0_val = faultStackAddress[r0]; 
    uint32_t r1_val = faultStackAddress[r1];
    uint32_t r2_val = faultStackAddress[r2]; 
    uint32_t r3_val = faultStackAddress[r3];
    uint32_t r12_val = faultStackAddress[r12]; 
    uint32_t r11_val = faultStackAddress[r11]; 
    uint32_t lr_val =  faultStackAddress[lr];
    uint32_t pc_val =  faultStackAddress[pc];
    uint32_t psr_val = faultStackAddress[psr];
}

我在这里有两个问题:
1.我不确定FP(r11)的索引在堆栈中的哪个位置,或者是否将其推入堆栈中我假设它在r12之前,因为我比较了添加选项“ --use_frame_pointer”前后的汇编源。我还比较了从Hard_Fault_Handler读取的值,似乎r11不在堆栈中。因为我读取的r11地址指向代码不是我的代码的地方。[更新]我已经确认FP已被推入堆栈。第二个问题仍然需要回答。

请参见下面的代码段代码:

没有选项“ --use_frame_pointer”

test2 PROC
        MOVS     r0,#3
        BX       lr
        ENDP

main PROC
        PUSH     {lr}
        MOVS     r0,#0
        BL       test2
        MOVS     r0,#0
        POP      {pc}
        ENDP

使用选项“ --use_frame_pointer”

test2 PROC
        PUSH     {r11,lr}
        ADD      r11,sp,#4
        MOVS     r0,#3
        MOV      sp,r11
        SUB      sp,sp,#4
        POP      {r11,pc}
        ENDP

main PROC
        PUSH     {r11,lr}
        ADD      r11,sp,#4
        MOVS     r0,#0
        BL       test2
        MOVS     r0,#0
        MOV      sp,r11
        SUB      sp,sp,#4
        POP      {r11,pc}
        ENDP

2.似乎FP不在Hard_Fault_Handler()的输入参数faultStackAddress中,在哪里可以获取调用者的FP来展开堆栈?
[再次更新]现在,我知道最后一个FP(r11)未存储在堆栈中。我需要做的就是读取r11寄存器的值,然后可以展开整个堆栈。
因此,现在我的最后一个问题是如何使用C的内联汇编器读取它。我尝试了以下代码,但是在参考http://infocenter.arm.com/help/index.jsp的引用后,无法从r11读取正确的值? topic = / com.arm.doc.dui0472f / Cihfhjhg.html

volatile int top_fp;
__asm
{
    mov top_fp, r11
}

r11的值为0x20009DCC top_fp的值为0x00000004


[更新3]以下是我的完整代码。

int test5(int i, int j, int k)
{
    char a[128] = {0} ;
    a[0] = 'a';
    return i/j;
}
int test2(int i, int j)
{
    char a[18] = {0} ;
    a[0] = 'a';
    return test5(i, j, 0);    
}


int main()
{
    SCB->CCR |= 0x10;
    int a = 10;
    int b = 0;
    int c;
    c = test2(a,b); //create a divide by zero crash
}

/ *故障处理程序实现调用一个名为Hard_Fault_Handler()的函数。* /

#if defined(__CC_ARM)
__asm void HardFault_Handler(void)
{
   TST lr, #4
   ITE EQ
   MRSEQ r0, MSP
   MRSNE r0, PSP
   B __cpp(Hard_Fault_Handler)
}
#else
void HardFault_Handler(void)
{
   __asm("TST lr, #4");
   __asm("ITE EQ");
   __asm("MRSEQ r0, MSP");
   __asm("MRSNE r0, PSP");
   __asm("B Hard_Fault_Handler");
}
#endif

void Hard_Fault_Handler(uint32_t *faultStackAddress)
{
   volatile int top_fp;
   __asm
   {
       mov top_fp, r11
   }
   //TODO: use top_fp to unwind the whole stack.

 }

[更新4]最后,我确定了。我的解决方案:
注意:要访问r11,我们必须使用嵌入式汇编程序,请参见此处,这花费了我很多时间来解决它。

//we have to use embedded assembler.     
__asm int getRegisterR11()
{
    mov r0,r11
    BX LR
}

//call it from Hard_Fault_Handler function.
/*
Function call stack frame:
   FP1(r11) ->    | lr |(High Address)
                  | FP2|(prev FP)
                  | ...| 
Current FP(r11) ->| lr |
                  | FP1|(prev FP)
                  | ...|(Low Address)

    With FP, we can access lr(link register) which is the address to return when the current functions returns(where you were).
    Then (current FP - 1) points to prev FP.
    Thus we can unwind the stack.
*/
void unwindBacktrace(uint32_t topFp, uint16_t* backtrace)
{
    uint32_t nextFp = topFp;
    int j = 0;

    //#define BACK_TRACE_DEPTH 5
    //loop backtrace using FP(r11), save lr into an uint16_t array.
    for(int i = 0; i < BACK_TRACE_DEPTH; i++)
    {
        uint32_t lr = *((uint32_t*)nextFp);
        if ((lr >= 0x08000000) && (lr <= 0x08FFFFFF))
        {
            backtrace[j*2] = LOW_16_BITS(lr);
            backtrace[j*2 + 1] = HIGH_16_BITS(lr);
            j += 1;
        }
        nextFp = *((uint32_t*)nextFp - 1);
        if (nextFp == 0)
        {
            break;
        }
    }
}

#if defined(__CC_ARM)
__asm void HardFault_Handler(void)
{
   TST lr, #4
   ITE EQ
   MRSEQ r0, MSP
   MRSNE r0, PSP
   B __cpp(Hard_Fault_Handler)
}
#else
void HardFault_Handler(void)
{
   __asm("TST lr, #4");
   __asm("ITE EQ");
   __asm("MRSEQ r0, MSP");
   __asm("MRSNE r0, PSP");
   __asm("B Hard_Fault_Handler");
}
#endif

void Hard_Fault_Handler(uint32_t *faultStackAddress)
{
       //get back trace
    int topFp = getRegisterR11();

    unwindBacktrace(topFp, persistentData.faultStack.back_trace);
}
mkmk88

在这种情况下,展开堆栈的一种非常原始的方法是读取HardFault_Handler时看到的高于SP的所有堆栈内存,并使用arm-none-eabi-addr2line处理它保存在堆栈上的所有链接寄存器条目都将转换为源代码行(请记住,实际代码路径LR指向该行之前已到达该行)。请注意,如果使用分支指令(b)而不是分支和链接(bl)调用之间的函数,则使用此方法将看不到它们。

(我没有足够的声誉积分来写评论,所以我在编辑答案):

问题2的更新:

您为什么期望Hard_Fault_Handler有任何参数?Hard_Fault_Handler通常是一个在向量(异常)表中存储地址的函数。当处理器异常发生时,将执行Hard_Fault_Handler。这样做不涉及任何参数传递。但是,仍然保留故障发生时的所有寄存器。具体来说,如果您在编译时没有省略帧指针,则只能读取R11的值(或在Thumb-2模式下为R7)。但是,要确保在您的代码中Hard_Fault_Handler实际上是一个真正的硬故障处理程序,请查看startup.s代码,然后查看Hard_Fault_Handler是否位于第三个位置。向量表中的条目。如果还有其他函数,则意味着仅从该函数显式调用Hard_Fault_Handler有关详细信息,请参见本文您也可以阅读我的博客:)关于Android的示例中有关于堆栈的一章,但总体上有很多相同之处。

还要注意,最有可能在faultStackAddress中存储堆栈指针,而不是帧指针。

更新2

好,让我们澄清一些事情。首先,请粘贴您从中调用Hard_Fault_Handler的代码其次,我想您是从真正的HardFault异常处理程序中调用它的。在那种情况下,您不能指望R11将位于faultStackAddress [r11]处您已经在问题的第一句话中提到了它。将有只有R0-R3,R12,LR,PC和PSR

您还写了:

但是堆栈中没有FP和SP。因此我无法解开堆栈。有什么解决办法吗?

SP不在“堆栈中”,因为您已经在堆栈寄存器之一(msp或psp)中拥有它。再次参见本文章此外,FP对于展开堆栈不是至关重要的,因为您可以在没有堆栈的情况下执行堆栈操作(通过“导航”已保存的链接寄存器)。另一件事是,如果将内存转储到SP之下,则可以根据需要将FP与保存的LR相邻。

回答您的最后一个问题:我现在不知道如何验证此代码以及如何调用它(您需要粘贴完整的代码)。您可以查看该功能的汇编,并查看幕后情况。您可以做的另一件事是按照这篇文章作为模板。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

ARM Cortex M3:原子写入

来自分类Dev

如何使用C的内联汇编器访问ARM Cortex M3的r11寄存器

来自分类Dev

ARM Cortex M3上的int64_t原子

来自分类Dev

将C代码转换为ARM Cortex M3汇编代码

来自分类Dev

ARM Cortex-M3启动代码

来自分类Dev

如何检查Cortex M3中是否启用了中断?

来自分类Dev

在启动代码的情况下,如何在cortex m3中执行复位序列?

来自分类Dev

修改Comipler RT汇编代码以针对Arm Cortex M3 / M4进行编译(CPSR / APSR位操作)

来自分类Dev

ARM Cortex-M 内存访问

来自分类Dev

我正在尝试为 ARM Cortex M3 编写模拟器。如何读取二进制文件然后对其进行解码?

来自分类Dev

查找哪个指令在Cortex M3上造成陷阱

来自分类Dev

与Cortex M3的Keil ARMCC int64比较

来自分类Dev

检索ARM Cortex M0上异常的返回地址

来自分类Dev

ARM Cortex M4硬故障-浮点

来自分类Dev

Ocaml是否适用于ARM cortex M4?

来自分类Dev

确定ARM Cortex-M系列上函数的返回地址

来自分类Dev

ARM Cortex M0的程序等效项是什么?

来自分类Dev

ARM Cortex M4和C,如何为特定的c文件指定RAM部分

来自分类Dev

如何在 Cortex-M0 中禁用 PendSV?

来自分类Dev

适用于ARM Cortex-m3的llsr和llsl(64位移位)

来自分类Dev

如何在没有计时器的情况下将ARM Cortex M0 +延迟n个周期?

来自分类Dev

为LPC1769 Cortex M3编写GPIO中断处理程序

来自分类Dev

为LPC1769 Cortex M3编写GPIO中断处理程序

来自分类Dev

__lib_init_array中CC2538(Cortex m3)启动时的Hardfault

来自分类Dev

未对齐的访问会导致ARM Cortex-M4出错

来自分类Dev

从一开始就发生ARM中断(Cortex-M4)

来自分类Dev

引导加载程序。ARM CORTEX M0 +重定位中断表程序集错误

来自分类Dev

适用于ARM Cortex M Procssor的GNU科学库编译错误

来自分类Dev

ARM是否假定所有Cortex-M微控制器都是低端字节序的?

Related 相关文章

  1. 1

    ARM Cortex M3:原子写入

  2. 2

    如何使用C的内联汇编器访问ARM Cortex M3的r11寄存器

  3. 3

    ARM Cortex M3上的int64_t原子

  4. 4

    将C代码转换为ARM Cortex M3汇编代码

  5. 5

    ARM Cortex-M3启动代码

  6. 6

    如何检查Cortex M3中是否启用了中断?

  7. 7

    在启动代码的情况下,如何在cortex m3中执行复位序列?

  8. 8

    修改Comipler RT汇编代码以针对Arm Cortex M3 / M4进行编译(CPSR / APSR位操作)

  9. 9

    ARM Cortex-M 内存访问

  10. 10

    我正在尝试为 ARM Cortex M3 编写模拟器。如何读取二进制文件然后对其进行解码?

  11. 11

    查找哪个指令在Cortex M3上造成陷阱

  12. 12

    与Cortex M3的Keil ARMCC int64比较

  13. 13

    检索ARM Cortex M0上异常的返回地址

  14. 14

    ARM Cortex M4硬故障-浮点

  15. 15

    Ocaml是否适用于ARM cortex M4?

  16. 16

    确定ARM Cortex-M系列上函数的返回地址

  17. 17

    ARM Cortex M0的程序等效项是什么?

  18. 18

    ARM Cortex M4和C,如何为特定的c文件指定RAM部分

  19. 19

    如何在 Cortex-M0 中禁用 PendSV?

  20. 20

    适用于ARM Cortex-m3的llsr和llsl(64位移位)

  21. 21

    如何在没有计时器的情况下将ARM Cortex M0 +延迟n个周期?

  22. 22

    为LPC1769 Cortex M3编写GPIO中断处理程序

  23. 23

    为LPC1769 Cortex M3编写GPIO中断处理程序

  24. 24

    __lib_init_array中CC2538(Cortex m3)启动时的Hardfault

  25. 25

    未对齐的访问会导致ARM Cortex-M4出错

  26. 26

    从一开始就发生ARM中断(Cortex-M4)

  27. 27

    引导加载程序。ARM CORTEX M0 +重定位中断表程序集错误

  28. 28

    适用于ARM Cortex M Procssor的GNU科学库编译错误

  29. 29

    ARM是否假定所有Cortex-M微控制器都是低端字节序的?

热门标签

归档