class="hide-preCode-box">

函数OsExcMsgDumpInit代码定义在components\exchook\los_exc_info.c,代码如下所示。⑴处的OS_SYS_MEM_NUM来自kernel\include\los_config.h配置文件,在记录内存信息时,会记录每个内存块内存节点的信息,该配置数值表示可以记录的内存块内存节点的数量。

⑵处的g_excMsgArray是个字节数组用于存储异常信息,g_excContent是执行字节数组的指针,存储异常信息时该指针不断指向字节数组的后面的位置。⑶处开始的代码调用OsExcRegister()函数分别设置上下文、任务、队列、中断、任务切换、内存等异常信息转储函数。具体的异常信息转储函数在后文分析。⑷处代码为中断异常类型注册异常钩子函数OsExcMsgDump()

VOID OsExcMsgDumpInit(VOID)
{
    g_excQueueMaxNum = LOSCFG_BASE_IPC_QUEUE_LIMIT;
⑴  g_excMemMaxNum = OS_SYS_MEM_NUM;
⑵  g_excContent = (VOID *)g_excMsgArray;

⑶  OsExcRegister(OS_EXC_TYPE_CONTEXT, OsExcContentGet, NULL);
    OsExcRegister(OS_EXC_TYPE_TSK, OsExcTaskMsgGet, &g_taskMaxNum);
#if (LOSCFG_BASE_IPC_QUEUE == 1)
    OsExcRegister(OS_EXC_TYPE_QUE, OsExcQueueMsgGet, &g_excQueueMaxNum);
#endif
    OsExcRegister(OS_EXC_TYPE_NVIC, OsExcSaveIntStatus, NULL);
#if (LOSCFG_BASE_CORE_EXC_TSK_SWITCH == 1)
    OsExcRegister(OS_EXC_TYPE_TSK_SWITCH, OsExcTskSwitchMsgGet, &g_taskSwitchInfo);
#endif
    OsExcRegister(OS_EXC_TYPE_MEM, OsExcMemMsgGet, &g_excMemMaxNum);

⑷  (VOID)LOS_RegExcHook(EXC_INTERRUPT, (ExcHookFn)OsExcMsgDump);
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

3、中断异常钩子函数OsExcMsgDump

函数OsExcMsgDump()是注册的对应中断异常类型的异常钩子函数。当发生中断异常时,会执行该函数转储异常信息到g_excMsgArray数组,转储前执行⑴把该内存区域初始化为0xFF。⑵处把转储区的前4个字节存储异常信息的大小,然后g_excContent指针往后移动4个字节。然后遍历g_excArray[]异常信息转储函数数组循环执行,会依次都各类信息转储到g_excMsgArray数组。转储信息后执行⑷把指定区域设置异常信息类型的最大值,然后g_excContent指针往后移动4个字节。

STATIC VOID OsExcMsgDump(VOID)
{
    UINT32 index;

    /* Ignore the return code when matching CSEC rule 6.6(4). */
⑴  (VOID)memset_s(g_excMsgArray, g_excArraySize, EXC_MSG_ARRAY_INIT_VALUE, g_excArraySize);

⑵  *((UINT32 *)g_excContent) = MAX_EXC_MEM_SIZE;  /* The total length of exception information. */
    g_excContent = (UINT8 *)g_excContent + sizeof(UINT32);

    for (index = 0; index < OS_EXC_TYPE_MAX; index++) {
        if (!g_excArray[index].valid) {
            continue;
        }
⑶      g_excArray[index].fnExcInfoCb(g_excArray[index].type, g_excArray[index].arg);
    }

⑷  *((UINT32 *)g_excContent) = OS_EXC_TYPE_MAX;
    g_excContent = (UINT8 *)g_excContent + sizeof(UINT32);
    return;
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

4、支持的异常信息转储函数

从枚举类型ExcInfoType,可以得知支持转储的异常信息有6类,对应的转储函数在VOID OsExcMsgDumpInit(VOID)函数中进行注册。我们挑2个简单看下这些转储函数是如何工作。

4.1 OsExcContentGet上下文转储

上下文转储是第一块要转储的信息,保存异常上下文信息。⑴处获取存储区域的结束地址。⑵处存储异常信息类型,然后g_excContent指针往后移动4个字节。⑶处存储信息大小,然后g_excContent指针往后移动4个字节。⑷处把g_excInfo异常信息复制到存储区域当前指向的位置,其中excContentEnd - (UINTPTR)g_excContent用于保证复制不会越界溢出,然后继续后移指针。⑸处转储上下文信息,然后继续后移指针,完成上下文信息转储。

STATIC UINT32 OsExcContentGet(UINT32 type, VOID *arg)
{
⑴  UINTPTR excContentEnd = MAX_EXC_MEM_SIZE + (UINTPTR)g_excMsgArray;
    errno_t ret;

    (VOID)arg;

    /* save exception info */
⑵  *((UINT32 *)g_excContent) = type;
    g_excContent = (UINT8 *)g_excContent + sizeof(UINT32);
⑶  *((UINT32 *)g_excContent) = sizeof(ExcInfo) + sizeof(EXC_CONTEXT_S);
    g_excContent = (UINT8 *)g_excContent + sizeof(UINT32);

⑷  ret = memcpy_s((VOID *)g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (VOID *)&g_excInfo, sizeof(ExcInfo));
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + sizeof(ExcInfo);

⑸  ret = memcpy_s((VOID *)g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   g_excInfo.context, sizeof(EXC_CONTEXT_S));
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + sizeof(EXC_CONTEXT_S);

    return LOS_OK;
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

4.2 OsExcSaveIntStatus中断寄存器信息转储

OsExcSaveIntStatus()函数用于转储中断寄存器的数据,⑴、⑵和⑶和其他转储函数类似,分别是获取存储区域的结束地址,设置类型和大小信息,并后移g_excContent指针。⑷处的OS_NVIC_SETENA_BASE定义在kernel\arch\arm\cortex-m7\gcc\los_arch_interrupt.h,是Interrupt enable register中断使能寄存器的地址,它的大小由OS_NVIC_INT_ENABLE_SIZE定义。后续的代码分别转储其他中断寄存器,比如Interrupt Set-Pending Registers中断设置请求寄存器的地址OS_NVIC_SETPEND_BASEInterrupt Active Bit Register中断活跃寄存器的地址OS_NVIC_INT_ACT_BASEInterrupt Priority Register中断优先级寄存器的地址OS_NVIC_PRI_BASE,这些中断寄存器可以查看官网 了解更多。

⑸处的代码是System Handler Priority Register系统处理优先级寄存器的地址OS_NVIC_EXCPRI_BASE,⑹处是System Handler Control and State Register系统处理控制和状态寄存器的地址OS_NVIC_SHCSR、⑺处是Interrupt Control and State Register中断控制和状态寄存器的地址OS_NVIC_INT_CTRL,有关这些寄存器的信息可以访问官网https://developer.arm.com/documentation/ddi0489/f/system-control/register-summary。

STATIC UINT32 OsExcSaveIntStatus(UINT32 type, VOID *arg)
{
    UINT32 ret;
⑴  UINTPTR excContentEnd = (UINTPTR)MAX_INT_INFO_SIZE + (UINTPTR)g_excContent;

    (VOID)arg;

⑵  *((UINT32 *)g_excContent) = type;
    g_excContent = (UINT8 *)g_excContent + sizeof(UINT32);

⑶  *((UINT32 *)g_excContent) = EXC_INT_STATUS_LEN;
    g_excContent = (UINT8 *)g_excContent + sizeof(UINT32);
    /* save IRQ ENABLE reg group */
⑷  ret = memcpy_s(g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (const VOID *)OS_NVIC_SETENA_BASE, OS_NVIC_INT_ENABLE_SIZE);
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + OS_NVIC_INT_ENABLE_SIZE;

    /* save IRQ PEND reg group */
    ret = memcpy_s(g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (const VOID *)OS_NVIC_SETPEND_BASE, OS_NVIC_INT_PEND_SIZE);
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + OS_NVIC_INT_PEND_SIZE;

    /* save IRQ ACTIVE reg group */
    ret = memcpy_s(g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (const VOID *)OS_NVIC_INT_ACT_BASE, OS_NVIC_INT_ACT_SIZE);
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + OS_NVIC_INT_ACT_SIZE;

    /* save IRQ Priority reg group */
    ret = memcpy_s(g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (const VOID *)OS_NVIC_PRI_BASE, OS_NVIC_INT_PRI_SIZE);
    g_excContent = (UINT8 *)g_excContent + OS_NVIC_INT_PRI_SIZE;

    /* save Exception Priority reg group */
⑸  ret = memcpy_s(g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (const VOID *)OS_NVIC_EXCPRI_BASE, OS_NVIC_EXCPRI_SIZE);
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + OS_NVIC_EXCPRI_SIZE;

    /* save IRQ Handler & SHCSR */
⑹  ret = memcpy_s(g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (const VOID *)OS_NVIC_SHCSR, OS_NVIC_SHCSR_SIZE);
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + OS_NVIC_SHCSR_SIZE;

    /* save IRQ Control & ICSR */
⑺  ret = memcpy_s(g_excContent, excContentEnd - (UINTPTR)g_excContent,
                   (const VOID *)OS_NVIC_INT_CTRL, OS_NVIC_INT_CTRL_SIZE);
    if (ret != EOK) {
        return LOS_NOK;
    }
    g_excContent = (UINT8 *)g_excContent + OS_NVIC_INT_CTRL_SIZE;

    return LOS_OK;
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

小结

本文介绍了异常信息的转储区域分布情况,介绍异常信息如何初始化,并介绍了两个主要的异常信息转储函数。

如果大家想更加深入的学习 OpenHarmony 开发的内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:

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

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

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

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

在这里插入图片描述

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

data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/maniuT/article/details/139532625","extend1":"pc","ab":"new"}">> id="blogExtensionBox" style="width:400px;margin:auto;margin-top:12px" class="blog-extension-box"> class="blog_extension blog_extension_type2" id="blog_extension"> class="extension_official" data-report-click="{"spm":"1001.2101.3001.6471"}" data-report-view="{"spm":"1001.2101.3001.6471"}"> class="blog_extension_card_left"> class="blog_extension_card_cont"> 鸿蒙开发学习资料领取!!! class="blog_extension_card_cont_r"> 微信名片
注:本文转载自blog.csdn.net的沧海一笑-dj的文章"https://blog.csdn.net/dengjin20104042056/article/details/98347939"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接

评论记录:

未查询到任何数据!