基于GNU、arm v7、threadx的backtrace

根据栈帧FP进行backtrace,threadx会在任务调度前将sp指向申请的任务栈空间,任务栈空间可在链接脚本中指定。

随便写个例子如下:

void func0()

{

        int i = 6;

        i++;

}

void func1()

{

        *(uint32_t *)0x80000000 = 1; //访问一块不在mpu范围内的内存会发生Abort

        func0();

}

void func2()

{

        func1();

}

void func3()

{

        func2();

}

func3在任务中调用;反汇编如下:

据此可画出调用关系图:

 如上图所示,每个函数的堆栈区中的FP指向它的调用这的LR地址,对于func1、func2、func3三个非叶子函数而言,寄存器R11(即fp)指向它们各自堆栈区的LR地址(add fp,sp,#4实现),对于叶子函数func0而言,寄存器R11(即fp)指向它堆栈区的FP地址(add fp,sp,#0实现,最后一级函数不调用别的函数,因此LR不用入栈)。

综上,当根据FP进行backtrace的时候,需要区分叶子函数和非叶子函数。叶子函数func0的FP寄存器指向func0堆栈中的FP值,该FP指向func1的堆栈中的LR地址,以此类推。非叶子函数func1的FP寄存器指向func1堆栈中的LR地址,由此可直接获取LR值,以此类推。

那么如何区分crash的时候所在函数是叶子函数还是非叶子函数呢,可通过FP的值与任务栈的起始地址做比较得到:

 如果是非叶子函数,FP指向的是LR,那么*fp得到的值一定存在text段,该值小于start;如果是叶子函数,FP指向的是任务栈中的FP,那么*fp得到的是上个栈帧,在任务栈中,该值大于start。由此可分情况进行backtrace。

另外,对于在叶子函数func0中进入异常的情况,由于func0的堆栈中并没有将LR入栈,该LR指向func1中,所以要想得到func1,需要在异常中(各个异常有各自的LR和SP)将异常模式切换成出异常之前的模式(通过CPS指令),这时候的LR就指向func1,如此能得到完成的backtrace。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值