diff --git a/arch/arm/arm/src/los_exc.c b/arch/arm/arm/src/los_exc.c index e31305f4a7bcfcf961bd8923a329c100240d7869..5d11862a7840eb47dd573f49475e44261f933158 100644 --- a/arch/arm/arm/src/los_exc.c +++ b/arch/arm/arm/src/los_exc.c @@ -1,3 +1,53 @@ +/*! + * @file los_exc.c + * @brief 异常接管主文件 + * @link + * @verbatim + 基本概念 + 异常接管是操作系统对运行期间发生的异常情况(芯片硬件异常)进行处理的一系列动作, + 例如打印异常发生时当前函数的调用栈信息、CPU现场信息、任务的堆栈情况等。 + + 异常接管作为一种调测手段,可以在系统发生异常时给用户提供有用的异常信息,譬如异常类型、 + 发生异常时的系统状态等,方便用户定位分析问题。 + + 异常接管,在系统发生异常时的处理动作为:显示异常发生时正在运行的任务信息 + (包括任务名、任务号、堆栈大小等),以及CPU现场等信息。 + + 运作机制 + 每个函数都有自己的栈空间,称为栈帧。调用函数时,会创建子函数的栈帧, + 同时将函数入参、局部变量、寄存器入栈。栈帧从高地址向低地址生长。 + + 以ARM32 CPU架构为例,每个栈帧中都会保存PC、LR、SP和FP寄存器的历史值。 + ARM处理器中的R13被用作SP + + 堆栈分析 + LR寄存器(Link Register),链接寄存器,指向函数的返回地址。 + R11:可以用作通用寄存器,在开启特定编译选项时可以用作帧指针寄存器FP,用来实现栈回溯功能。 + GNU编译器(gcc)默认将R11作为存储变量的通用寄存器,因而默认情况下无法使用FP的栈回溯功能。 + 为支持调用栈解析功能,需要在编译参数中添加-fno-omit-frame-pointer选项,提示编译器将R11作为FP使用。 + FP寄存器(Frame Point),帧指针寄存器,指向当前函数的父函数的栈帧起始地址。利用该寄存器可以得到父函数的栈帧, + 从栈帧中获取父函数的FP,就可以得到祖父函数的栈帧,以此类推,可以追溯程序调用栈,得到函数间的调用关系。 + 当系统发生异常时,系统打印异常函数的栈帧中保存的寄存器内容,以及父函数、祖父函数的 + 栈帧中的LR、FP寄存器内容,用户就可以据此追溯函数间的调用关系,定位异常原因。 + 异常接管对系统运行期间发生的芯片硬件异常进行处理,不同芯片的异常类型存在差异,具体异常类型可以查看芯片手册。 + + 异常接管一般的定位步骤如下: + 打开编译后生成的镜像反汇编(asm)文件。 + 搜索PC指针(指向当前正在执行的指令)在asm中的位置,找到发生异常的函数。 + 根据LR值查找异常函数的父函数。 + 重复步骤3,得到函数间的调用关系,找到异常原因。 + + 注意事项 + 要查看调用栈信息,必须添加编译选项宏-fno-omit-frame-pointer支持stack frame,否则编译时FP寄存器是关闭的。 + + 参考 + http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/%E7%94%A8%E6%88%B7%E6%80%81%E5%BC%82%E5%B8%B8%E4%BF%A1%E6%81%AF%E8%AF%B4%E6%98%8E.html + @endverbatim + + * @version + * @author weharmonyos.com + * @date 2021-11-20 + */ /* * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. @@ -61,52 +111,6 @@ #ifdef LOSCFG_FS_VFS #include "console.h" #endif -/** -* @file los_exc.c -* @brief 软定时器主文件 -* @details -* @attention @verbatim -基本概念 - 异常接管是操作系统对运行期间发生的异常情况(芯片硬件异常)进行处理的一系列动作, - 例如打印异常发生时当前函数的调用栈信息、CPU现场信息、任务的堆栈情况等。 - - 异常接管作为一种调测手段,可以在系统发生异常时给用户提供有用的异常信息,譬如异常类型、 - 发生异常时的系统状态等,方便用户定位分析问题。 - - 异常接管,在系统发生异常时的处理动作为:显示异常发生时正在运行的任务信息 - (包括任务名、任务号、堆栈大小等),以及CPU现场等信息。 - -运作机制 - 每个函数都有自己的栈空间,称为栈帧。调用函数时,会创建子函数的栈帧, - 同时将函数入参、局部变量、寄存器入栈。栈帧从高地址向低地址生长。 - - 以ARM32 CPU架构为例,每个栈帧中都会保存PC、LR、SP和FP寄存器的历史值。 - ARM处理器中的R13被用作SP - -堆栈分析 - LR寄存器(Link Register),链接寄存器,指向函数的返回地址。 - R11:可以用作通用寄存器,在开启特定编译选项时可以用作帧指针寄存器FP,用来实现栈回溯功能。 - GNU编译器(gcc)默认将R11作为存储变量的通用寄存器,因而默认情况下无法使用FP的栈回溯功能。 - 为支持调用栈解析功能,需要在编译参数中添加-fno-omit-frame-pointer选项,提示编译器将R11作为FP使用。 - FP寄存器(Frame Point),帧指针寄存器,指向当前函数的父函数的栈帧起始地址。利用该寄存器可以得到父函数的栈帧, - 从栈帧中获取父函数的FP,就可以得到祖父函数的栈帧,以此类推,可以追溯程序调用栈,得到函数间的调用关系。 - 当系统发生异常时,系统打印异常函数的栈帧中保存的寄存器内容,以及父函数、祖父函数的 - 栈帧中的LR、FP寄存器内容,用户就可以据此追溯函数间的调用关系,定位异常原因。 - 异常接管对系统运行期间发生的芯片硬件异常进行处理,不同芯片的异常类型存在差异,具体异常类型可以查看芯片手册。 - -异常接管一般的定位步骤如下: - 打开编译后生成的镜像反汇编(asm)文件。 - 搜索PC指针(指向当前正在执行的指令)在asm中的位置,找到发生异常的函数。 - 根据LR值查找异常函数的父函数。 - 重复步骤3,得到函数间的调用关系,找到异常原因。 - -注意事项 - 要查看调用栈信息,必须添加编译选项宏-fno-omit-frame-pointer支持stack frame,否则编译时FP寄存器是关闭的。 - -参考 - http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/%E7%94%A8%E6%88%B7%E6%80%81%E5%BC%82%E5%B8%B8%E4%BF%A1%E6%81%AF%E8%AF%B4%E6%98%8E.html -* @endverbatim - */ #ifdef LOSCFG_BLACKBOX #include "los_blackbox.h" diff --git a/kernel/extended/trace/los_trace.c b/kernel/extended/trace/los_trace.c index cb00f8dd4364c4e18584ed923eabaa798e2c3f81..369a61f7415bdc0730c1e7054dae70a7331a5fa5 100644 --- a/kernel/extended/trace/los_trace.c +++ b/kernel/extended/trace/los_trace.c @@ -1,3 +1,30 @@ +/*! + * @file los_trace.c + * @brief + * @link kernel-small-debug-trace http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-debug-trace.html @endlink + @verbatim + 基本概念 + Trace调测旨在帮助开发者获取内核的运行流程,各个模块、任务的执行顺序,从而可以辅助开发者定位一些时序问题 + 或者了解内核的代码运行过程。 + + 运行机制 + 内核提供一套Hook框架,将Hook点预埋在各个模块的主要流程中, 在内核启动初期完成Trace功能的初始化, + 并注册Trace的处理函数到Hook中。 + + 当系统触发到一个Hook点时,Trace模块会对输入信息进行封装,添加Trace帧头信息,包含事件类型、 + 运行的cpuid、运行的任务id、运行的相对时间戳等信息; + + Trace提供2种工作模式,离线模式和在线模式。 + 在线模式需要配合IDE使用,实时将trace frame记录发送给IDE,IDE端进行解析并可视化展示。 + 离线模式会将trace frame记录到预先申请好的循环buffer中。如果循环buffer记录的frame过多则可能出现翻转, + 会覆盖之前的记录,故保持记录的信息始终是最新的信息。Trace循环buffer的数据可以通过shell命令导出进行详细分析, + 导出信息已按照时间戳信息完成排序。 + @endverbatim + * @image html https://gitee.com/weharmonyos/resources/raw/master/80/trace.png + * @version + * @author weharmonyos.com + * @date 2021-11-20 + */ /* * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. @@ -239,7 +266,7 @@ STATIC UINT32 OsCreateTraceAgentTask(VOID) return ret; } #endif - +/// 跟踪模块初始化 STATIC UINT32 OsTraceInit(VOID) { UINT32 ret; @@ -291,7 +318,7 @@ STATIC UINT32 OsTraceInit(VOID) LOS_ERREND: return ret; } - +/// 启动Trace UINT32 LOS_TraceStart(VOID) { UINT32 intSave; @@ -320,7 +347,7 @@ START_END: TRACE_UNLOCK(intSave); return ret; } - +/// 停止Trace(跟踪) VOID LOS_TraceStop(VOID) { UINT32 intSave; @@ -336,12 +363,12 @@ VOID LOS_TraceStop(VOID) STOP_END: TRACE_UNLOCK(intSave); } - +/// 设置事件掩码,仅记录某些模块的事件 VOID LOS_TraceEventMaskSet(UINT32 mask) { g_traceMask = mask & EVENT_MASK; } - +/// 输出Trace缓冲区数据 VOID LOS_TraceRecordDump(BOOL toClient) { if (g_traceState != TRACE_STOPED) { @@ -350,12 +377,12 @@ VOID LOS_TraceRecordDump(BOOL toClient) } OsTraceRecordDump(toClient); } - +/// 获取Trace缓冲区的首地址 OfflineHead *LOS_TraceRecordGet(VOID) { return OsTraceRecordGet(); } - +/// 清除Trace缓冲区中的事件 VOID LOS_TraceReset(VOID) { if (g_traceState == TRACE_UNINIT) { @@ -365,7 +392,7 @@ VOID LOS_TraceReset(VOID) OsTraceReset(); } - +/// 注册过滤特定中断号事件的钩子函数 VOID LOS_TraceHwiFilterHookReg(TRACE_HWI_FILTER_HOOK hook) { UINT32 intSave; diff --git a/kernel/include/los_trace.h b/kernel/include/los_trace.h index cfe3069c30614cae353616da910fabc0ab555fee..6634dd4ac6724d6ad88c613b059a3e6d570cbf00 100644 --- a/kernel/include/los_trace.h +++ b/kernel/include/los_trace.h @@ -104,13 +104,13 @@ extern "C" { /** * @ingroup los_trace - * Trace state. + * Trace state. | 跟踪状态 */ enum TraceState { - TRACE_UNINIT = 0, /**< trace isn't inited */ - TRACE_INITED, /**< trace is inited but not started yet */ - TRACE_STARTED, /**< trace is started and system is tracing */ - TRACE_STOPED, /**< trace is stopped */ + TRACE_UNINIT = 0, /**< trace isn't inited | 未初始化*/ + TRACE_INITED, /**< trace is inited but not started yet | 已初始化但未开始*/ + TRACE_STARTED, /**< trace is started and system is tracing | 跟踪进行中...*/ + TRACE_STOPED, /**< trace is stopped | 跟踪结束*/ }; /** @@ -119,16 +119,16 @@ enum TraceState { * module's trace mask. */ typedef enum { - TRACE_SYS_FLAG = 0x10, - TRACE_HWI_FLAG = 0x20, - TRACE_TASK_FLAG = 0x40, - TRACE_SWTMR_FLAG = 0x80, - TRACE_MEM_FLAG = 0x100, - TRACE_QUE_FLAG = 0x200, - TRACE_EVENT_FLAG = 0x400, - TRACE_SEM_FLAG = 0x800, - TRACE_MUX_FLAG = 0x1000, - TRACE_IPC_FLAG = 0x2000, + TRACE_SYS_FLAG = 0x10, ///< 跟踪系统 + TRACE_HWI_FLAG = 0x20, ///< 跟踪硬中断 + TRACE_TASK_FLAG = 0x40, ///< 跟踪任务/线程 + TRACE_SWTMR_FLAG = 0x80, ///< 跟踪软件定时器 + TRACE_MEM_FLAG = 0x100, ///< 跟踪内存 + TRACE_QUE_FLAG = 0x200, ///< 跟踪队列 + TRACE_EVENT_FLAG = 0x400, ///< 跟踪事件 + TRACE_SEM_FLAG = 0x800, ///< 跟踪信号量 + TRACE_MUX_FLAG = 0x1000, ///< 跟踪互斥量 + TRACE_IPC_FLAG = 0x2000, ///< 跟踪IPC TRACE_MAX_FLAG = 0x80000000, TRACE_USER_DEFAULT_FLAG = 0xFFFFFFF0, @@ -144,7 +144,7 @@ typedef enum { * trace_module_flag number * */ -typedef enum { +typedef enum { //跟进模块的具体事件 /* 0x10~0x1F */ SYS_ERROR = TRACE_SYS_FLAG | 0, SYS_START = TRACE_SYS_FLAG | 1, @@ -228,24 +228,24 @@ typedef enum { * struct to store the trace config information. */ typedef struct { - UINT32 bigLittleEndian; /**< big little endian flag */ - UINT32 clockFreq; /**< system clock frequency */ - UINT32 version; /**< trace version */ + UINT32 bigLittleEndian; /**< big little endian flag | 大小端标记*/ + UINT32 clockFreq; /**< system clock frequency | 系统时钟频率*/ + UINT32 version; /**< trace version | 跟踪版本*/ } TraceBaseHeaderInfo; /** * @ingroup los_trace - * struct to store the event infomation + * struct to store the event infomation | 保存跟踪事件的信息 */ typedef struct { - UINT32 eventType; /**< event type */ - UINT32 curTask; /**< current running task */ - UINT32 curPid; /**< current running processID */ - UINT64 curTime; /**< current timestamp */ - UINTPTR identity; /**< subject of the event description */ -#ifdef LOSCFG_TRACE_FRAME_CORE_MSG + UINT32 eventType; /**< event type | 事件类型*/ + UINT32 curTask; /**< current running task | 当前任务ID*/ + UINT32 curPid; /**< current running processID | 当前进程ID*/ + UINT64 curTime; /**< current timestamp | 时间戳*/ + UINTPTR identity; /**< subject of the event description | 描述事件*/ +#ifdef LOSCFG_TRACE_FRAME_CORE_MSG //跟踪CPU信息 struct CoreStatus { - UINT32 cpuId : 8, /**< cpuid */ + UINT32 cpuId : 8, /**< cpuid | CPU 核 ID*/ hwiActive : 4, /**< whether is in hwi response */ taskLockCnt : 4, /**< task lock count */ paramCount : 4, /**< event frame params' number */ @@ -415,10 +415,15 @@ extern TRACE_EVENT_HOOK g_traceEventHook; /** * @ingroup los_trace - * @brief Trace static code stub. + * @brief Trace static code stub. | 标准插桩 * * @par Description: * This API is used to instrument trace code stub in source code, to track events. + + \n 1. 相比简易插桩,支持动态过滤事件和参数裁剪,但使用上需要用户按规则来扩展。 + \n 2. TYPE用于设置具体的事件类型,可以在头文件los_trace.h中的enum LOS_TRACE_TYPE中自定义事件类型。定义方法和规则可以参考其他事件类型。 + \n 3. IDENTITY和Params的类型及含义同简易插桩。 + * @attention * None. * @@ -446,10 +451,14 @@ extern TRACE_EVENT_HOOK g_traceEventHook; /** * @ingroup los_trace - * @brief Trace static easier user-defined code stub. + * @brief Trace static easier user-defined code stub. | 简易插桩 * * @par Description: * This API is used to instrument user-defined trace code stub in source code, to track events simply. + \n 1. 一句话插桩,用户在目标源代码中插入该接口即可。 + \n 2. TYPE有效取值范围为[0, 0xF],表示不同的事件类型,不同取值表示的含义由用户自定义。 + \n 3. IDENTITY类型UINTPTR,表示事件操作的主体对象。 + \n 4. Params类型UINTPTR,表示事件的参数。 * @attention * None. * @@ -461,7 +470,7 @@ extern TRACE_EVENT_HOOK g_traceEventHook; * @par Dependency: * */ -#define LOS_TRACE_EASY(TYPE, IDENTITY, ...) \ +#define LOS_TRACE_EASY(TYPE, IDENTITY, ...) \ do { \ UINTPTR _inner[] = {0, ##__VA_ARGS__}; \ UINTPTR _n = sizeof(_inner) / sizeof(UINTPTR); \ diff --git a/zzz/git/push.sh b/zzz/git/push.sh index c74c5c7403824ee22cbe7c8b4b8e00df2bd3c80a..672de504d0f4c24ee1ffe9562599a1f846e21c4c 100644 --- a/zzz/git/push.sh +++ b/zzz/git/push.sh @@ -1,5 +1,5 @@ git add -A -git commit -m ' 动态(堆)内存部分注解, 采用 tlsf 算法 +git commit -m ' 注解trace模块,其用于跟踪内核各模块运行细节 百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码 鸿蒙研究站 | http://weharmonyos.com (国内) | https://weharmony.github.io (国外)