鸿蒙轻内核M核源码分析系列十七(1) 异常钩子函数类型介绍

459 篇文章 3 订阅
348 篇文章 3 订阅

本文中所涉及的源码,以OpenHarmony LiteOS-M内核为例,均可以在开源站点 https://gitee.com/openharmony/kernel_liteos_m  获取。鸿蒙轻内核异常钩子模块代码主要在components\exchook目录下。


1、异常钩子类型枚举EXC_TYPE

在文件utils\los_debug.h定义异常钩子类型枚举EXC_TYPE。EXC_REBOOT用于标记系统重启时的钩子函数,发生重启时调用注册的重启钩子函数;EXC_ASSERT用于标记断言函数,发生断言时调用注册的断言钩子函数;EXC_STACKOVERFLOW用于标记任务栈溢出钩子函数,发生任务栈溢出时调用注册的任务栈溢出钩子函数;EXC_INTERRUPT用于标记中断异常时的钩子函数,发生中断异常时调用注册的中断异常钩子函数。

typedef enum {
    EXC_REBOOT,
    EXC_ASSERT,
    EXC_STACKOVERFLOW,
    EXC_INTERRUPT,
    EXC_TYPE_END
} EXC_TYPE;

2、如何注册和执行异常钩子函数

本节我们先看下如何调用和注册异常钩子函数,异常钩子函数的注册和调用的函数API定义在utils\los_debug.c,代码如下。
⑴处定义的函数OsExcHookRegister用于注册异常钩子函数到全局变量g_excHook。它的传入的参数ExcHookFn excHookFn是个异常钩子函数,这个钩子函数是定义在文件components\exchook\los_exchook.c中的STATIC VOID DoExcHook(EXC_TYPE excType)后文会详细分析。另外,从代码上可以看出异常钩子函数只有一个,也只能注册一次。
⑵处定义的异常钩子执行函数OsDoExcHook,根据传入的枚举类型EXC_TYPE来判断执行什么类型的异常钩子函数。

可以看出这2个函数都是内部函数,用函数OsExcHookRegister注册的也是全局的异常钩子函数,它实质上对应的其实是个异常钩子函数数组。后文会分析如何通过定义在components\exchook\los_exchook.cLOS_RegExcHook函数如何分别注册不同类型的异常钩子函数。下文也会详细分析其他对外函数如何调用OsDoExcHook来处理异常。

⑴  VOID OsExcHookRegister(ExcHookFn excHookFn)
    {
        UINT32 intSave = LOS_IntLock();
        if (!g_excHook) {
            g_excHook = excHookFn;
        }
        LOS_IntRestore(intSave);
    }

⑵  VOID OsDoExcHook(EXC_TYPE excType)
    {
        UINT32 intSave = LOS_IntLock();
        if (g_excHook) {
            g_excHook(excType);
        }
        LOS_IntRestore(intSave);
    }

3、使用异常钩子函数的操作

我们从上文知道,注册的全局异常钩子函数只有一个,那就是全局异常钩子函数变量g_excHook,它根据不同的异常钩子类型来分别处理。我们看下具体如何异常钩子函数的,关于全局异常钩子函数底层的细节后文会详细分析。

3.1 重启LOS_Reboot

该函数可以在发生系统重启异常时调用,程序僵死在此处等待看门狗watchdog等。⑴处根据参数类型EXC_REBOOT调用对应的重启异常钩子函数。需要在系统初始化时执行LOS_RegExcHook(EXC_REBOOT, (ExcHookFn)YourRebootFunction)注册异常钩子函数,才能执行重启异常钩子函数。YourRebootFunction需要自行定义实现在系统重启异常时执行什么操作。如果没有注册过重启钩子函数则跳过不执行任何操作。

LITE_OS_SEC_TEXT_INIT VOID LOS_Reboot(VOID)
{
⑴  OsDoExcHook(EXC_REBOOT);
    HalSysExit();
}

2.2 断言LOS_ASSERT

该函数可以用于验证函数的参数合法性,该函数宏定义在文件utils\los_debug.h。可以看出,如果设置的打印级别数值太低,时不支持断言功能的。如⑴处代码所示,该函数宏需要一个参数judge。如果参数为假时会执行⑵处的代码,根据参数类型EXC_ASSERT调用对应的断言异常钩子函数。需要在系统初始化时执行LOS_RegExcHook(EXC_ASSERT, (ExcHookFn)YourAssertFunction)注册异常钩子函数,才能执行断言异常钩子函数。YourAssertFunction需要自行定义实现在断言异常时执行什么操作。如果没有注册过断言钩子函数则跳过不执行任何操作。LOS_ASSERT后续的⑶处的代码会关闭中断,打印断言错误信息ASSERT ERROR...

#if PRINT_LEVEL < LOG_ERR_LEVEL
#define LOS_ASSERT(judge)
#else
#define LOS_ASSERT(judge)                                                          \
    do {                                                                           \
⑴      if ((judge) == 0) {                                                        \
⑵          OsDoExcHook(EXC_ASSERT);                                               \
⑶          (VOID)LOS_IntLock();                                                   \
            PRINT_ERR("ASSERT ERROR! %s, %d, %s\n", __FILE__, __LINE__, __func__); \
            while (1) { }                                                          \
        }                                                                          \
    } while (0)
#endif

2.3 任务栈溢出OsDoExcHook(EXC_STACKOVERFLOW)

任务栈溢出OsDoExcHook(EXC_STACKOVERFLOW)OsHandleRunTaskStackOverflow函数和OsHandleNewTaskStackOverflow函数调用,这2个函数定义在文件kernel\src\los_task.c,分别在当前运行任务,要调度运行的新任务发生任务栈溢出时调用。当执行到⑴、⑵处的代码时,根据参数类型EXC_STACKOVERFLOW调用对应的异常钩子函数。需要在系统初始化时执行LOS_RegExcHook(EXC_STACKOVERFLOW, (ExcHookFn)YourStackOverflowFunction)注册异常钩子函数,才能执行异常钩子函数。YourStackOverflowFunction需要自行定义实现在任务栈溢出异常时执行什么操作。如果没有注册过钩子函数则跳过不执行任何操作。

LITE_OS_SEC_TEXT STATIC VOID OsHandleRunTaskStackOverflow(VOID)
{
    PRINT_ERR("CURRENT task ID: %s:%d stack overflow!\n",
              g_losTask.runTask->taskName, g_losTask.runTask->taskID);
⑴  OsDoExcHook(EXC_STACKOVERFLOW);
}
......
LITE_OS_SEC_TEXT STATIC VOID OsHandleNewTaskStackOverflow(VOID)
{
    ......
    tmp = g_losTask.runTask;
    g_losTask.runTask = g_losTask.newTask;
⑵  OsDoExcHook(EXC_STACKOVERFLOW);
    g_losTask.runTask = tmp;
}

2.4 中断异常HalExcHandleEntry

该函数在发生中断异常时汇编代码中调用执行,用于处于系统异常,该函数宏定义在不同芯片架构实现的文件los_interrupt.c中,如kernel\arch\arm\cortex-m7\gcc\los_interrupt.c。处理系统中断异常时,执行到⑴处代码时,会根据参数类型EXC_INTERRUPT调用对应的异常钩子函数。和上述几个异常类型的钩子函数不一样,中断异常钩子函数不需要用户来注册,内核已经注册了中断异常钩子函数。相应的代码在文件components\exchook\los_exc_info.c中,注册代码语句为(VOID)LOS_RegExcHook(EXC_INTERRUPT, (ExcHookFn)OsExcMsgDump);,当发生系统中断异常时会调用(ExcHookFn)OsExcMsgDump函数,后文会详细分析都包含哪些异常信息。

LITE_OS_SEC_TEXT_INIT VOID HalExcHandleEntry(UINT32 excType, UINT32 faultAddr, UINT32 pid, EXC_CONTEXT_S *excBufAddr)
{
    ......
⑴  OsDoExcHook(EXC_INTERRUPT);
    OsExcInfoDisplay(&g_excInfo);
    HalSysExit();
}

小结

本文介绍了异常钩子函数的注册函数OsExcHookRegister和异常钩子函数的调用函数OsDoExcHook,以及介绍了支持的异常钩子函数类型等。

如果想更深入的学习 OpenHarmony (鸿蒙南向)全栈开发的内容,可以参考以下学习文档:

OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy

《OpenHarmony源码解析》:https://qr18.cn/CgxrRy

  • 搭建开发环境
  • Windows 开发环境的搭建
  • Ubuntu 开发环境搭建
  • Linux 与 Windows 之间的文件共享
  • ……

系统架构分析:https://qr18.cn/CgxrRy

  • 构建子系统
  • 启动流程
  • 子系统
  • 分布式任务调度子系统
  • 分布式通信子系统
  • 驱动子系统
  • ……

OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy

OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy

写在最后

  • 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
  • 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:https://gitee.com/MNxiaona/733GH

在这里插入图片描述

  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值