乐趣区

关于harmonyos:解读鸿蒙轻内核的监控器异常钩子函数

摘要: 本篇先介绍下反对的异样钩子函数的类型,异样钩子函数的注册、执行等外部操作 API 接口,并介绍下应用异样钩子函数的操作接口。

本文分享自华为云社区《鸿蒙轻内核 M 核源码剖析系列十七(1)异样钩子函数类型介绍》,作者:zhushy。

ExcHook 异样钩子模块是 OpenHarmony LiteOS- M 内核的一个可选组件,提供注册钩子函数 LOS_RegExcHook、解除注册钩子函数 LOS_UnRegExcHook 等操作接口。产生零碎时,反对保留异样上下文、工作信息、队列信息、中断寄存器状态、工作切换信息、内存调配等信息。因为异样钩子模块内容较多,咱们分为几篇进行剖析源码,别离介绍异样钩子函数的类型,如何注册和解除注册钩子函数,如何转储异样信息等。本篇先介绍下反对的异样钩子函数的类型,异样钩子函数的注册、执行等外部操作 API 接口,并介绍下应用异样钩子函数的操作接口。异样钩子函数的注册、执行,异样钩子类型定义在 utils\los_debug.h|.c。

本文中所波及的源码,以 OpenHarmony LiteOS- M 内核为例,均能够在开源站点 https://gitee.com/openharmony… 获取。鸿蒙轻内核异样钩子模块代码次要在 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.c 的 LOS_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();}

3.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

3.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;
}

3.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,以及介绍了反对的异样钩子函数类型等。

点击关注,第一工夫理解华为云陈腐技术~

退出移动版