OpenHarmony设备开发小型系统内核(LiteOS-A) 调测与工具
版本:V3.2Beta
其他内核调测手段
临终遗言
使用场景
在无串口的设备上,将系统异常时打印的信息保存到不丢失的存储介质上,方便对运行时问题进行定位。
功能说明
该调测功能提供了一种用于保存系统异常时打印信息到不丢失存储介质中的机制,用户可自行注册读写异常时打印信息的钩子函数,实现在不同存储介质上保存异常信息的能力,这样方便无串口的设备的问题定位。接口名为LOS_ExcInfoRegHook,该函数声明在los_config.h中,函数原型:
typedef VOID (*log_read_write_fn)(UINT32 startAddr, UINT32 space, UINT32 rwFlag, CHAR *buf);
......
VOID LOS_ExcInfoRegHook(UINT32 startAddr, UINT32 space, CHAR *buf, log_read_write_fn hook);
参数说明
表1 LOS_ExcInfoRegHook 参数说明
参数 | 参数说明 |
startAddr | 存取异常信息的物理介质起始地址 |
space | 存取的空间大小 |
buf | 存取异常信息的内存缓冲区 |
log_read_write_fn | 存取异常信息的函数 |
表2 log_read_write_fn 参数说明
参数 | 参数说明 |
startAddr | 存取异常信息的物理介质起始地址 |
space | 存取的空间大小 |
rwFlag | 读写标记,0为写,1为读 |
buf | 存取异常信息的内存缓冲区 |
开发流程
该功能依赖于宏LOSCFG_SAVE_EXCINFO,使用临终遗言功能时,在配置项中开启“ Enable Saving Exception Information ”:Debug-> Enable Saving Exception Information ;若关闭该选项,则该功能失效。功能开启后,可在SystemInit中调用LOS_ExcInfoRegHook来注册存取异常信息的位置、大小、内存缓冲区以及存取函数。当系统进入异常时,会将异常时系统各类信息先保存在注册时传入的内存缓冲区中,最后调用注册的存取函数,将异常信息写入到物理存储介质中。
说明:
- 注册的存取位置不要跟其他存储重叠。
- 注册的内存缓冲区不能太小,建议不低于16KiB,否则异常信息会存储不完整。
- 注册的读写函数对应的具体存储介质的驱动功能正常,才能保证存取功能正常。
常见问题
通过异常信息定位问题
系统异常被挂起后,会在串口看到一些关键寄存器的信息,如图1所示。可通过这些信息定位到异常所在函数和其调用栈关系,为原因分析提供第一手资料。
图1 异常信息
上图中的异常信息主要解释4个标签:
标签1:标识异常在内核态;
标签2:标识了异常类型(数据异常时,far后的值是系统异常时CPU访问的地址);
标签3:pc的值标识系统异常时执行指令的位置,klr的值一般标识pc所在函数执行完后下一条要执行的命令。(注:标签4处 traceback 0 lr有值时不用关注klr)。
标签4:lr 的值依次标识正常情况下PC要依次执行的指令的位置。
对于内核异常打印信息,确定PC和LR的具体位置的指令需要结合out目录下OHOS_Image.asm(跟烧写的系统镜像OHOS_Image.bin对应的汇编文件)查看,根据指令所在的位置可确认使用该指令的函数,依次确定LR位置所在的函数,即得到异常发生时的函数调用关系。
内存池完整性验证
仅凭上节异常信息定位的基本方法,常常无法直接定位问题所在。并且常常会因为异常的寄存器值而无法对问题进行定位。若怀疑是堆内存越界导致的问题,可以调用内存池完整性检测函数LOS_MemIntegrityCheck进行检查。函数LOS_MemIntegrityCheck将会对系统动态内存池所有的节点进行遍历,如果所有节点正常则函数返回0,不会有任何打印,否则将打印相关的错误信息。该函数的入参使用(VOID *)OS_SYS_MEM_ADDR。
定位堆内存越界踩的问题,一般是在可能存在问题的业务逻辑代码前后使用LOS_MemIntegrityCheck,如果该业务代码不存在问题,则前后两次LOS_MemIntegrityCheck调用不会失败,按前述方式逐步缩小问题定位范围。
全局变量踩内存定位方法
如果已知一个全局变量内存域被踩,可在OHOS_Image.map文件中找到该全局变量所在的地址,并且特别注意该地址之前最近被使用的变量,有极大概率是前面的变量(尤其数组类型的或会被强转成其他类型的变量)在使用的过程中内存越界,破坏了这个全局变量。