基本概念
OpenHarmony LiteOS-M提供异常接管调测手段,帮助开发者定位分析问题。异常接管是操作系统对运行期间发生的异常情况进行处理的一系列动作,例如打印异常发生时异常类型、发生异常时的系统状态、当前函数的调用栈信息、CPU现场信息、任务调用堆栈等信息。
运行机制
栈帧用于保存函数调用过程中的函数参数、变量、返回值等信息。调用函数时,会创建子函数的栈帧,同时将函数入参、局部变量、寄存器入栈。栈帧从高地址向低地址生长。以ARM32 CPU架构为例,每个栈帧中都会保存PC、LR、SP和FP寄存器的历史值。LR链接寄存器(Link Register)指向函数的返回地址,FP帧指针寄存器(Frame Point)指向当前函数的父函数的栈帧起始地址。利用FP寄存器可以得到父函数的栈帧,从栈帧中获取父函数的FP,就可以得到祖父函数的栈帧,以此类推,可以追溯程序调用栈,得到函数间的调用关系。
当系统发生异常时,系统打印异常函数的栈帧中保存的寄存器内容,以及父函数、祖父函数的栈帧中的LR链接寄存器、FP帧指针寄存器内容,用户就可以据此追溯函数间的调用关系,定位异常原因。
堆栈分析原理如下图所示,实际堆栈信息根据不同CPU架构有所差异,此处仅做示意。
图1 堆栈分析原理示意图
图中不同颜色的寄存器表示不同的函数。可以看到函数调用过程中,寄存器的保存。通过FP寄存器,栈回溯到异常函数的父函数,继续按照规律对栈进行解析,推出函数调用关系,方便用户定位问题。
接口说明
OpenHarmony LiteOS-M内核的回溯栈模块提供以下接口,接口详细信息可以查看API参考。
表1 回溯栈模块接口
接口名 | 功能 |
---|---|
LOS_BackTrace | 打印调用处的函数调用栈关系。 |
LOS_RecordLR | 在无法打印的场景,用该接口获取调用处的函数调用栈关系。 |
使用指导
开发流程
开启异常调测的典型流程如下:
- 配置异常接管相关宏。
需要在target_config.h头文件中修改配置:
配置项 | 含义 | 设置值 |
---|---|---|
LOSCFG_BACKTRACE_DEPTH | 函数调用栈深度,默认15层 | 15 |
LOSCFG_BACKTRACE_TYPE | 回溯栈类型: 0:表示关闭该功能; 1:表示支持Cortex-m系列硬件的函数调用栈解析; 2:表示用于Risc-v系列硬件的函数调用栈解析; |
根据工具链类型设置1或2 |
- 使用示例中有问题的代码,编译、运行工程,在串口终端中查看异常信息输出。示例代码模拟异常代码,实际产品开发时使用异常调测机制定位异常问题。
本示例演示异常输出,包含1个任务,该任务入口函数模拟若干函数调用,最终调用一个模拟异常的函数。代码实现如下:
本演示代码在./kernel/liteos_m/testsuites/src/osTest.c
中编译验证,在TestTaskEntry中调用验证入口函数ExampleExcEntry。
#include <stdio.h>
#include "los_config.h"
#include "los_interrupt.h"
#include "los_task.h"
UINT32 g_taskExcId;
#define TSK_PRIOR 4
/* 模拟异常函数 */
UINT32 GetResultException0(UINT16 dividend){
UINT32 result = *(UINT32 *)(0xffffffff);
printf("Enter GetResultException0\. %u\r\n", res