OpenHarmony(鸿蒙南向开发)——轻量系统内核(LiteOS-M)【异常调测】

news2024/11/23 19:35:04

往期知识点记录:

  • 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总
  • 鸿蒙(OpenHarmony)南向开发保姆级知识点汇总~
  • 持续更新中……

基本概念

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
  1. 使用示例中有问题的代码,编译、运行工程,在串口终端中查看异常信息输出。示例代码模拟异常代码,实际产品开发时使用异常调测机制定位异常问题。

本示例演示异常输出,包含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      = 4
    ThrdPid   = 5
    Phase     = exc in task
    FaultAddr = 0xfffffffc
    Current task info:
    Task name = Example_Exc
    Task ID   = 5
    Task SP   = 0x210549bc
    Task ST   = 0x21053a00
    Task SS   = 0x1000
    Exception reg dump:
    PC        = 0x2101c61a
    LR        = 0x2101c64d
    SP        = 0x210549a8
    R0        = 0x4
    R1        = 0xa
    R2        = 0x0
    R3        = 0xffffffff
    R4        = 0x2103fb20
    R5        = 0x5050505
    R6        = 0x6060606
    R7        = 0x210549a8
    R8        = 0x8080808
    R9        = 0x9090909
    R10       = 0x10101010
    R11       = 0x11111111
    R12       = 0x0
    PriMask   = 0x0
    xPSR      = 0x41000000
    ----- backtrace start -----
    backtrace 0 -- lr = 0x2101c64c
    backtrace 1 -- lr = 0x2101c674
    backtrace 2 -- lr = 0x2101c696
    backtrace 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_Task
       1       31     Ready     0x500      0x44 0x210478e4 0x21047428         0 0xffff     0.0       0.0      0.0  0x2101a9c9 IdleCore000
       2        5  PendTime    0x6000      0xd4 0x2104e8f4 0x210489c8         0 0xffff     5.7       5.7      0.0  0x21016149 tcpip_thread
       3        3      Pend    0x1000     0x488 0x2104f90c 0x2104e9e8       0x1 0xffff     8.6       8.6      0.0  0x21016db5 ShellTaskEntry
       4       25     Ready    0x4000     0x460 0x21053964 0x2104f9f0         0 0xffff     9.0       8.9      0.0  0x2101c765 IT_TST_INI
       5        4   Running    0x1000     0x458 0x210549bc 0x21053a00         0 0xffff    76.5      76.6      0.0  0x2101c685 Example_Exc

    OS exception NVIC dump:
    interrupt enable register, base address: 0xe000e100, size: 0x20
    0x2001 0x0 0x0 0x0 0x0 0x0 0x0 0x0
    interrupt pending register, base address: 0xe000e200, size: 0x20
    0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
    interrupt active register, base address: 0xe000e300, size: 0x20
    0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
    interrupt priority register, base address: 0xe000e400, size: 0xf0
    0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
    0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
    0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
    0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0 0x0
    interrupt exception register, base address: 0xe000ed18, size: 0xc
    0x0 0x0 0xf0f00000
    interrupt shcsr register, base address: 0xe000ed24, size: 0x4
    0x70002
    interrupt control register, base address: 0xe000ed04, size: 0x4
    0x1000e805

    memory pools check:
    system heap memcheck over, all passed!
    memory pool check end!

    根据实际运行环境,上文中的数据会有差异,非固定结果

定位流程

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

  1. 确认编译时关掉优化选项,否则下述的描述内容可能被优化掉。

  2. 打开编译后生成的镜像反汇编(asm)文件。如果默认没有生成,可以使用objdump工具生成,命令为:

    arm-none-eabi-objdump -S -l XXX.elf
  1. 搜索PC指针(指向当前正在执行的指令)在asm中的位置,找到发生异常的函数。

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

    2101c60c <GetResultException0>:
    2101c60c:	b580      	push	{r7, lr}
    2101c60e:	b084      	sub	sp, #16
    2101c610:	af00      	add	r7, sp, #0
    2101c612:	4603      	mov	r3, r0
    2101c614:	80fb      	strh	r3, [r7, #6]
    2101c616:	f04f 33ff 	mov.w	r3, #4294967295	; 0xffffffff
    2101c61a:	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, r3
    2101c62a:	3710      	adds	r7, #16
    2101c62c:	46bd      	mov	sp, r7
    2101c62e:	bd80      	pop	{r7, pc}
    2101c630:	21025f90 	.word	0x21025f90
  1. 可以看到:

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

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

    2101c634 <GetResultException1>:
    2101c634:	b580      	push	{r7, lr}
    2101c636:	b082      	sub	sp, #8
    2101c638:	af00      	add	r7, sp, #0
    2101c63a:	4603      	mov	r3, r0
    2101c63c:	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, r3
    2101c648:	f7ff ffe0 	bl	2101c60c <GetResultException0>
    2101c64c:	4603      	mov	r3, r0
    2101c64e:	4618      	mov	r0, r3
    2101c650:	3708      	adds	r7, #8
    2101c652:	46bd      	mov	sp, r7
    2101c654:	bd80      	pop	{r7, pc}
    2101c656:	bf00      	nop
    2101c658:	21025fb0 	.word	0x21025fb0
  1. LR值2101c648上一行是bl 2101c60c ,此处调用了异常函数,调用异常函数的父函数为GetResultException1。

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

最后

经常有很多小伙伴抱怨说:不知道学习鸿蒙开发哪些技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?

为了能够帮助到大家能够有规划的学习,这里特别整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线,包含了鸿蒙开发必掌握的核心知识要点,内容有(ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等)鸿蒙(HarmonyOS NEXT)技术知识点。

在这里插入图片描述

《鸿蒙 (Harmony OS)开发学习手册》(共计892页):https://gitcode.com/HarmonyOS_MN/733GH/overview

如何快速入门?

1.基本概念
2.构建第一个ArkTS应用
3.……

鸿蒙开发面试真题(含参考答案):

在这里插入图片描述

《OpenHarmony源码解析》:

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……
  • 系统架构分析
  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

图片

OpenHarmony 设备开发学习手册:https://gitcode.com/HarmonyOS_MN/733GH/overview

图片
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【基础算法总结】字符串篇

目录 一&#xff0c;算法简介二&#xff0c;算法原理和代码实现14.最长公共前缀5.最长回文子串67.二进制求和43.字符串相乘 三&#xff0c;算法总结 一&#xff0c;算法简介 字符串 string 是一种数据结构&#xff0c;它一般和其他的算法结合在一起操作&#xff0c;比如和模拟&…

守护数据安全:.rmallox勒索病毒的防范与应对策略

导言 在当今这个数字化时代&#xff0c;网络空间已成为人们生活、工作和娱乐不可或缺的一部分。然而&#xff0c;随着互联网的普及和技术的飞速发展&#xff0c;网络安全问题也日益凸显&#xff0c;成为了一个全球性的挑战。其中&#xff0c;.rmallox勒索病毒作为一种恶意软件…

【linux】进程间的通信(一)

1. 了解进程通信 两个或者多个进程实现数据层面的交互 因为进程独立性的存在&#xff0c;导致进程通信成本较高&#xff08;通信需要成本&#xff09; 2. 进程间通信目的 进程间通信的本质是&#xff0c;让不同的进程看到同一份"资源"&#xff08;即同一份内存空…

基础算法之前缀和--Java实现(下)--LeetCode题解:-和为 K 的子数组 - 和可被 K 整除的子数组 -连续数组-矩阵区域和

这里是Themberfue 和为 K 的子数组 题目解析 返回子数组中所有元素的和等于给定k的个数。 算法讲解 这题好像是用滑动窗口解决&#xff0c;但其实不能&#xff0c;因为 nums 中的元素可能存在负数&#xff0c;就不能保证其单调性的性质。 用前缀和求也不易想到&#xff0c;…

Java编码方式:Base64编码与解码

1、Base64 算法介绍 Base64 是一种基于 64 个可打印字符来表示二进制数据的表示方法。它主要用于在不支持二进制数据的场合&#xff08;如电子邮件、URL、文件系统名等&#xff09;传输二进制数据。严格来说 Base64 并不是一种加密/解密算法&#xff0c;而是一种编码方式。Bas…

数据挖掘学习笔记:朴素贝叶斯 | Python复现

数据挖掘学习笔记&#xff1a;朴素贝叶斯 机器学习系列&#xff08;四&#xff09;&#xff1a;朴素贝叶斯&#xff08;华强买瓜版&#xff09; - yyxy的文章 - 知乎 十分钟&#xff0c;让你再也忘不掉贝叶斯分类 - VoidHaruhi的文章 - 知乎 《机器学习》&#xff08;西瓜书&am…

快速生成单元测试

1. Squaretest插件 2. 依赖 <dependency><groupId>junit</groupId>

Spring异步线程池的问题

今天看一视频&#xff0c;提到说 Spring默认的异步线程池比较简单&#xff0c;每次执行异步任务&#xff0c;都会新建一个线程进行处理&#xff0c;不会重复利用&#xff0c;所以在用Spring框架开发的时候&#xff0c;需要自定义异步线程池。第一次听到这个说法。遂开始百度。 …

迷你世界表白神器爱心脚本lua

--迷你世界专用爱心表达公式 local a,angle,count,id30,0,0,math.random(668, 681) -- 根据需要调整θ的遍历范围和步长 while true do angle angle0.01 local ra*(math.sin(angle)*(math.sqrt(math.abs(math.cos(angle)))/(math.sin(angle)1.4)-2)2) if r>10…

动手学深度学习59 双向循环神经网络

1. 双向循环神经网络 视频&#xff1a;https://www.bilibili.com/video/BV12X4y1c71W/?p2&spm_id_frompageDriver&vd_sourceeb04c9a33e87ceba9c9a2e5f09752ef8 课件&#xff1a;https://courses.d2l.ai/zh-v2/assets/pdfs/part-3_7.pdf 课本&#xff1a; https://zh-…

机器学习K近邻算法——分类问题K近邻算法示例

针对“数据8.1”&#xff0c;讲解分类问题的K近邻算法&#xff0c;以V1&#xff08;转型情况&#xff09;为响应变量&#xff0c;以V2&#xff08;存款规模&#xff09;、V3&#xff08;EVA&#xff09;、V4&#xff08;中间业务收入&#xff09;、V5&#xff08;员工人数&…

【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则

文章目录 C 继承详解&#xff1a;初阶理解与实战应用前言第一章&#xff1a;继承的基本概念与定义1.1 继承的概念1.2 继承的定义 第二章&#xff1a;继承中的访问权限2.1 基类成员在派生类中的访问权限2.2 基类与派生类对象的赋值转换2.2.1 派生类对象赋值给基类对象2.2.2 基类…

多端同步的收银系统源码

随着经济的不断发展&#xff0c;很多门店越来越趋向连锁品牌化&#xff0c;收银系统自然也成为很多连锁门店必不可少的软件工具。希望通过一套软件可以帮助门店解决门店线下销售、会员管理、连锁多门店管理、线下线上一体化、商品库存管理等难题实现降本增效&#xff0c;为了方…

MySQL连接查询:联合查询

先看我的表结构 emp表 联合查询的关键字&#xff08;union all, union&#xff09; 联合查询 基本语法 select 字段列表 表A union all select 字段列表 表B 例子&#xff1a;将薪资低于5000的员工&#xff0c; 和 年龄大于50 岁的员工全部查询出来 第一种 select * fr…

大模型微调技术之 LoRA:开启高效微调新时代

一、LoRA 简介 LoRA&#xff0c;即低秩适应&#xff08;Low-Rank Adaptation&#xff09;&#xff0c;是一种用于微调大型语言模型的技术&#xff0c;旨在以较小的计算资源和数据量实现模型的快速适应特定任务或领域。 LoRA 方法通过引入低秩近似的思想&#xff0c;对大型预训…

NFS共享文件系统(将文件目录挂载到别的机器上)

我们创建的磁盘是否都必须挂载到本机上&#xff1f;并不是。在 Linux 和其他操作系统中&#xff0c;有一种叫做 NFS&#xff08;网络文件系统&#xff09;的工具&#xff0c;它允许跨网络共享文件系统资源。通过使用 NFS&#xff0c;我们可以将多个客户端服务器的数据目录挂载到…

Java中常见的等待唤醒机制及实践

JDK自带的等待唤醒机制 在Java中&#xff0c;有一个JDK维度的等待唤醒机制。Object类的wait和notify,notifyAll 需要在synchronized同步代码块内并且对象必须获取到锁才能调用。否则会抛IllegalMonitorStateException异常。 当线程在尝试获取锁时失败&#xff0c;会被封装成节…

Mybatis-plus做了什么

Mybatis-plus做了什么 Mybatis回顾以前的方案Mybatis-plus 合集总览&#xff1a;Mybatis框架梳理 聊一下mybatis-plus。你是否有过疑问&#xff0c;Mybatis-plus中BaseMapper方法对应的SQL在哪里&#xff1f;它为啥会被越来越多人接受。在Mybatis已经足够灵活的情况下&…

《强烈推荐一个强大的书签管理工具》

在信息爆炸的时代&#xff0c;我们每天都会浏览大量的网页&#xff0c;收藏各种各样的书签。然而&#xff0c;随着书签数量的增加&#xff0c;管理起来也变得越来越困难。这时&#xff0c;一个强大的书签管理工具就显得尤为重要。今天&#xff0c;我要向大家推荐一款备受好评的…

EtherCAT学习笔记

文章目录 前言一、EtherCAT介绍二、EtherCA系统组成2.1 ESC(EtherCAT从站控制器)2.2 从站控制微处理器2.3 物理层器件2.4 其它应用层器件 三、EtherCAT数据帧结构3.1 寻址方式3.2 时钟3.3 通信模式 四、状态机和通信初始化五、应用层协议六、ESC概述6.1 EtherCAT从站控制芯片6.…