基本概念

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在无法打印的场景,用该接口获取调用处的函数调用栈关系。

使用指导

开发流程
开启异常调测的典型流程如下:

  1. 配置异常接管相关宏。

需要在target_config.h头文件中修改配置:

配置项含义设置值
LOSCFG_BACKTRACE_DEPTH函数调用栈深度,默认15层15
LOSCFG_BACKTRACE_TYPE回溯栈类型:
0:表示关闭该功能;
1:表示支持Cortex-m系列硬件的函数调用栈解析;
2:表示用于Risc-v系列硬件的函数调用栈解析;
根据工具链类型设置1或2


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", result);return result;}UINT32 GetResultException1(UINT16 dividend){printf("Enter GetResultException1.\r\n");return GetResultException0(dividend);}UINT32 GetResultException2(UINT16 dividend){printf("Enter GetResultException2.\r\n");return GetResultException1(dividend);}UINT32 ExampleExc(VOID){UINT32 ret;printf("Enter Example_Exc Handler.\r\n");/* 模拟函数调用 */ret = GetResultException2(TSK_PRIOR);printf("Divided result =%u.\r\n", ret);printf("Exit Example_Exc Handler.\r\n");return ret;}/* 任务测试入口函数,创建一个会发生异常的任务 */UINT32 ExampleExcEntry(VOID){UINT32 ret;TSK_INIT_PARAM_S initParam = { 0 };/* 锁任务调度,防止新创建的任务比本任务高而发生调度 */LOS_TaskLock();printf("LOS_TaskLock() Success!\r\n");initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ExampleExc;initParam.usTaskPrio = TSK_PRIOR;initParam.pcName = "Example_Exc";initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;/* 创建高优先级任务,由于锁任务调度,任务创建成功后不会马上执行 */ret = LOS_TaskCreate(&g_taskExcId, &initParam);if (ret != LOS_OK) {LOS_TaskUnlock();printf("Example_Exc create Failed!\r\n");return LOS_NOK;}printf("Example_Exc create Success!\r\n");/* 解锁任务调度,此时会发生任务调度,执行就绪队列中最高优先级任务 */LOS_TaskUnlock();return LOS_OK;}


述代码串口终端输出异常信息如下:

    LOS_TaskLock() Success!Example_Exc create Success!Enter Example_Exc Handler.Enter GetResultException2.Enter GetResultException1.*************Exception Information**************Type      = 4ThrdPid   = 5Phase     = exc in taskFaultAddr = 0xfffffffcCurrent task info:Task name = Example_ExcTask ID   = 5Task SP   = 0x210549bcTask ST   = 0x21053a00Task SS   = 0x1000Exception reg dump:PC        = 0x2101c61aLR        = 0x2101c64dSP        = 0x210549a8R0        = 0x4R1        = 0xaR2        = 0x0R3        = 0xffffffffR4        = 0x2103fb20R5        = 0x5050505R6        = 0x6060606R7        = 0x210549a8R8        = 0x8080808R9        = 0x9090909R10       = 0x10101010R11       = 0x11111111R12       = 0x0PriMask   = 0x0xPSR      = 0x41000000----- backtrace start -----backtrace 0 -- lr = 0x2101c64cbacktrace 1 -- lr = 0x2101c674backtrace 2 -- lr = 0x2101c696backtrace 3 -- lr = 0x2101b1ec----- backtrace end -----TID  Priority   Status StackSize WaterLine StackPoint TopOfStack EventMask  SemID  CPUUSE CPUUSE10s CPUUSE1s   TaskEntry name---  -------- -------- --------- --------- ---------- ---------- --------- ------ ------- --------- --------  ---------- ----0        0      Pend    0x1000      0xdc 0x2104730c 0x210463e8         0 0xffff     0.0       0.0      0.0  0x2101a199 Swt_Task1       31     Ready     0x500      0x44 0x210478e4 0x21047428         0 0xffff     0.0       0.0      0.0  0x2101a9c9 IdleCore0002        5  PendTime    0x6000      0xd4 0x2104e8f4 0x210489c8         0 0xffff     5.7       5.7      0.0  0x21016149 tcpip_thread3        3      Pend    0x1000     0x488 0x2104f90c 0x2104e9e8       0x1 0xffff     8.6       8.6      0.0  0x21016db5 ShellTaskEntry4       25     Ready    0x4000     0x460 0x21053964 0x2104f9f0         0 0xffff     9.0       8.9      0.0  0x2101c765 IT_TST_INI5        4   Running    0x1000     0x458 0x210549bc 0x21053a00         0 0xffff    76.5      76.6      0.0  0x2101c685 Example_ExcOS exception NVIC dump:interrupt enable register, base address: 0xe000e100, size: 0x200x2001 0x0 0x0 0x0 0x0 0x0 0x0 0x0interrupt pending register, base address: 0xe000e200, size: 0x200x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0interrupt active register, base address: 0xe000e300, size: 0x200x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0interrupt priority register, base address: 0xe000e400, size: 0xf00x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x00x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x00x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x00x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0interrupt exception register, base address: 0xe000ed18, size: 0xc0x0 0x0 0xf0f00000interrupt shcsr register, base address: 0xe000ed24, size: 0x40x70002interrupt control register, base address: 0xe000ed04, size: 0x40x1000e805memory pools check:system heap memcheck over, all passed!memory pool check end!根据实际运行环境,上文中的数据会有差异,非固定结果

定位流程
异常接管一般的定位步骤如下:

  1. 确认编译时关掉优化选项,否则下述的描述内容可能被优化掉。
  2. 打开编译后生成的镜像反汇编(asm)文件。如果默认没有生成,可以使用objdump工具生成,命令为:
    arm-none-eabi-objdump -S -l XXX.elf


3. 搜索PC指针(指向当前正在执行的指令)在asm中的位置,找到发生异常的函数。
PC地址指向发生异常时程序正在执行的指令。在当前执行的二进制文件对应的asm文件中,查找PC值0x2101c61a,找到当前CPU正在执行的指令行,反汇编如下所示:

    2101c60c <GetResultException0>:2101c60c:	b580      	push	{r7, lr}2101c60e:	b084      	sub	sp, #162101c610:	af00      	add	r7, sp, #02101c612:	4603      	mov	r3, r02101c614:	80fb      	strh	r3, [r7, #6]2101c616:	f04f 33ff 	mov.w	r3, #4294967295	; 0xffffffff2101c61a:	681b      	ldr	r3, [r3, #0]2101c61c:	60fb      	str	r3, [r7, #12]2101c61e:	68f9      	ldr	r1, [r7, #12]2101c620:	4803      	ldr	r0, [pc, #12]	; (2101c630 <GetResultException0+0x24>)2101c622:	f001 f92b 	bl	2101d87c <printf>2101c626:	68fb      	ldr	r3, [r7, #12]2101c628:	4618      	mov	r0, r32101c62a:	3710      	adds	r7, #162101c62c:	46bd      	mov	sp, r72101c62e:	bd80      	pop	{r7, pc}2101c630:	21025f90 	.word	0x21025f90

4. 可以看到:

  1. 异常时CPU正在执行的指令是ldr r3, [r3, #0],其中r3取值为0xffffffff,导致发生非法地址异常。
  2. 异常发生在函数GetResultException0中。

5. 根据LR值查找异常函数的父函数。

包含LR值0x2101c64d的反汇编如下所示:

    2101c634 <GetResultException1>:2101c634:	b580      	push	{r7, lr}2101c636:	b082      	sub	sp, #82101c638:	af00      	add	r7, sp, #02101c63a:	4603      	mov	r3, r02101c63c:	80fb      	strh	r3, [r7, #6]2101c63e:	4806      	ldr	r0, [pc, #24]	; (2101c658 <GetResultException1+0x24>)2101c640:	f001 f91c 	bl	2101d87c <printf>2101c644:	88fb      	ldrh	r3, [r7, #6]2101c646:	4618      	mov	r0, r32101c648:	f7ff ffe0 	bl	2101c60c <GetResultException0>2101c64c:	4603      	mov	r3, r02101c64e:	4618      	mov	r0, r32101c650:	3708      	adds	r7, #82101c652:	46bd      	mov	sp, r72101c654:	bd80      	pop	{r7, pc}2101c656:	bf00      	nop2101c658:	21025fb0 	.word	0x21025fb0

6. LR值2101c648上一行是bl 2101c60c ,此处调用了异常函数,调用异常函数的父函数为GetResultException1。

7. 重复步骤3,解析异常信息中backtrace start至backtrace end之间的LR值,得到调用产生异常的函数调用栈关系,找到异常原因。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/86444.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/86444.shtml
英文地址,请注明出处:http://en.pswp.cn/web/86444.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法-堆排序

文章目录 整体架构流程技术细节小结 整体架构流程 大顶推&#xff1a;是构建一个完整的二叉树 大顶推&#xff1a;即父节点的值大于左右子树的值。 循环构建大顶推 在给定的数组&#xff0c;既可以明确树的高度。 在循环的时候&#xff0c;构建树的高度从lgn至0。即从堆低往堆…

【鸿蒙HarmonyOS Next App实战开发】二维码生成技术实现与解析

随着移动应用开发中对便捷交互体验的需求日益增长&#xff0c;二维码作为信息传递的重要载体&#xff0c;其生成与使用变得越来越普遍。本文将基于鸿蒙HarmonyOS应用开发框架&#xff0c;详细介绍如何实现一个功能完备的二维码生成器&#xff0c;并附上完整代码解析。 注意该实…

1 Studying《Is Parallel Programming Hard》6-9

目录 Chapter 6 Partitioning and Synchronization Design 6.1 分区练习 6.2 设计准则 6.3 同步粒度 6.4 并行快速路径 6.5 超越党派分歧 6.6 分区、并行和优化 Chapter 7 Locking 7.1 活命 7.2 锁的类型 7.3 锁定实施问题 7.4 基于锁的存在性保证 7.5 锁定&a…

Java练习题精选16-20

Java练习题精选16-20 一、第十六题二、第十七题三、第十八题四、第十九题五、第二十题一、第十六题 现有一个存放学生成绩的数组{66, 77, 88, 99},要求将该数组正序输出每个下标所对应的元素。 public class Test {public static void main(String[] args) {int<

新能源知识库(68)汽车电镀与蒸汽

汽车电镀是提升零部件耐磨性、抗腐蚀性和美观性的关键工艺&#xff0c;其流程根据基材&#xff08;金属或塑料&#xff09;和部件功能需求有所差异。 汽车电镀是以 基材特性和 功能需求为导向的精密工艺&#xff1a; ​金属件​&#xff1a;核心流程为 ​除油→酸洗→电镀→钝…

Veo 3 视频生成大模型完整操作教程(2025)

随着 AI 多模态能力的飞跃&#xff0c;Google DeepMind 发布的 Veo 3 成为了生成视频领域的一颗重磅炸弹。它不仅能够根据文本生成高质量的视频画面&#xff0c;还能同步生成对白、背景音和环境音&#xff0c;是目前最接近真正“AI 导演”的大模型。 本文将带你详细了解 Veo 3…

10【认识文件系统】

1 认识硬件——磁盘 1.1 物理构成 磁盘是计算机中唯一的机械设备&#xff0c;同时也是一种外部存储设备&#xff08;外设&#xff09;。早期的计算机通常配备的是机械硬盘&#xff08;HDD&#xff09;&#xff0c;依靠磁头和盘片的机械运动来进行数据的读写。但随着用户对计算…

Windows命令连接符的安全风险分析与防御策略

1. 命令连接符简介 在 Windows 的命令行环境&#xff08;CMD/PowerShell&#xff09;中&#xff0c;命令连接符用于在同一行执行多个命令&#xff0c;提高效率。然而&#xff0c;攻击者常利用这些符号构造恶意命令&#xff0c;绕过安全检测或执行多阶段攻击。 常见命令连接符…

大屏可视化制作指南

一、大屏可视化概述 &#xff08;一&#xff09;概念 大屏可视化是指通过大屏幕展示复杂数据的视觉呈现形式&#xff0c;它借助图形、图表、地图等元素&#xff0c;将海量数据以直观易懂的方式呈现出来&#xff0c;帮助用户快速理解数据背后的含义和价值。 &#xff08;二&a…

Halcon ——— OCR字符提取与多类型识别技术详解

工业视觉实战&#xff1a;OCR字符提取与多类型识别技术详解 在工业自动化领域&#xff0c;OCR字符提取是产品追溯、质量控制和信息读取的核心技术。本文将深入解析Halcon中OCR字符提取的全流程&#xff0c;重点解释核心算子参数&#xff0c;并提供完整的工业级代码实现。 一、O…

嵌入式项目:基于QT与Hi3861的物联网智能大棚集成控制系统

关键词&#xff1a;MQTT、物联网、QT、网络连接、远程控制 一、系统概述 本系统是一套完整的智能大棚监控解决方案&#xff0c;由两部分构成&#xff1a; 基于Hi3861的嵌入式硬件系统&#xff08;负责环境数据采集和设备控制&#xff09;基于Qt开发的跨平台控制软件&#xf…

揭开 Git 裸仓库的神秘面纱:`git clone --mirror` 详解与使用指南

大家好&#xff01;在使用 Git 进行版本控制时&#xff0c;我们最熟悉的莫过于那些带有工作目录的本地仓库了——我们在里面编辑文件、提交代码&#xff0c;然后推送到远程仓库。但有时候&#xff0c;我们可能会遇到一种特殊的仓库&#xff1a;裸仓库&#xff08;Bare Reposito…

opensuse安装rabbitmq

您好&#xff01;安装 RabbitMQ 消息队列是一个非常棒的选择&#xff0c;它是许多现代应用架构中的核心组件。 在 openSUSE Tumbleweed 上安装 RabbitMQ 主要有两种流行的方式&#xff1a;一种是使用系统的包管理器 zypper&#xff0c;另一种是使用 Docker 容器。我将为您详细…

超详细YOLOv8/11图像菜品分类全程概述:环境、数据准备、训练、验证/预测、onnx部署(c++/python)详解

文章目录 一、环境准备二、数据准备三、训练四、验证与预测五、模型部署 一、环境准备 我的都是在Linux系统下&#xff0c;训练部署的&#xff1b;模型训练之前&#xff0c;需要配置好环境&#xff0c;Anaconda、显卡驱动、cuda、cudnn、pytorch等&#xff1b; 参考&#xff1…

JUC:4.线程常见操作与两阶段终止模式

在线程中&#xff0c;wait()、join()、sleep()三个方法都是进行阻塞的方法。对应可以使用interrupt()方法进行打断&#xff0c;被打断后线程会抛出打断异常&#xff0c;但是不会修改IsInterrupt&#xff0c;也就是此时去调用IsInterrupted()方法后获得的实际上是false。 而当线…

分布式session解决方案

在实际项目中&#xff0c;前台代码部署在nginx中&#xff0c;后台服务内嵌了tomcat运行在不同的节点中&#xff0c;常见的架构如下&#xff1a; 在上述架构中&#xff0c;nginx转发前台请求&#xff0c;第一次登录后&#xff0c;将用户登录信息写入到一台服务session中&#xf…

UDP 缓冲区

UDP 有接收缓冲区&#xff0c;没有发送缓冲区 引申问题 1、为什么没有发送缓冲区&#xff1f; 直接引用原文 “因为 UDP 是不可靠的&#xff0c;它不必保存应用进程的数据拷贝&#xff0c;因此无需一个真正的发送缓冲区” 2、没有发送缓冲区的情况下&#xff0c;sendto 的数…

解密 C++ 中的左值(lvalue)与右值(rvalue)的核心内容

在 C 中&#xff0c;表达式&#xff08;expression&#xff09; 可以被归类为左值或右值。最简单的理解方式是&#xff1a; 左值&#xff08;lvalue&#xff09;&#xff1a; 能放在赋值号 左边的表达式&#xff0c;通常表示一个有名字、有内存地址、可以持续存在的对象。你可…

MATLAB(2)选择结构

选择结构又可以叫做分支结构&#xff0c;它根据给定的条件是否成立&#xff0c;决定程序运行的方向。在不同的条件下执行不同的操作。 MATLAB可以用来实现选择结构的语句有三种&#xff1a;if语句、switch语句、try语句。 一.if语句 1.if语句 1.1条件为矩阵的情况 if语句的…

Ehcache、Caffeine、Spring Cache、Redis、J2Cache、Memcached 和 Guava Cache 的主要区别

主流缓存技术 Ehcache、Caffeine、Spring Cache、Redis、J2Cache、Memcached 和 Guava Cache 的主要区别&#xff0c;涵盖其架构、功能、适用场景和优缺点等方面&#xff1a; Ehcache 类型: 本地缓存&#xff08;JVM 内存缓存&#xff09; 特点: 轻量级&#xff0c;运行在 JV…