MTK异常LOG深入探讨

 MTK异常LOG深入探讨

 

开篇序言:此篇意在对异常LOG有一个总体上面的了解。异常的LOG有很多信息,但是对不同的异常,需要看的LOG却不一样。刚接触MTK平台之时,我也犯过这样的错误:就是这么多的异常LOG,我应该怎样看?非把自己弄得昏头转向不可。待此篇结束之后,小弟会根据不同的异常情况,选取一些典型的例子,给大家演示怎样去看异常LOG。小弟不才,希望能抛砖引玉,望各位高手多多指教。


出现异常的时候,正如上一篇小弟写的《MTK异常流程处理》所述,会把异常信息写在一个structure中。这个structure的定义为:

typedef struct ex_exception_log_t
{
    EX_HEADER_T header;                //记录异常类型、异常发生时间
    kal_char sw_version[EX_SWVER_LEN]; //版本号
    EX_ENVINFO_T envinfo;              //一些重要寄存器和内存信息
    EX_DIAGNOSISINFO_T diaginfo;       //系统状态
    EX_CONTENT_T content;              //异常信息主要内容
} EX_LOG_T;

 

1、EX_HEADER_T header;

typedef struct ex_exception_record_header_t
{
    exception_type ex_type;
    kal_uint8 ex_nvram;
    kal_uint16 ex_serial_num;
} EX_HEADER_T;

 

exception_type ex_type;是异常类型,MTK系统中共有8种异常的类型,在小弟《MTK异常错误类型》一篇中有消息的介绍。

kal_uint8 ex_nvram;大家看看nvram_write_exception这个函数就会明白。NVRAM中有10项记录异常错误信息。若此变量的值为0xff,则表明该项没有写过,可以往此项记录异常错误信息。

kal_uint16 ex_serial_num;每次出现异常,ex_serial_num都会加1。因此,对于这个值,10个NVRAM项中,后面的应该比前面的大。正如小弟的《MTK异常处理流程》所述,NVRAM中10项是循环去写的。那么怎样判断已经循环了一圈?就是靠ex_serial_num的值去判断。假如当前项比前一项ex_serial_num小,证明循环了一圈。可以放心把这一项写上冲掉,写上新的异常信息。

 

2、kal_char sw_version[EX_SWVER_LEN];

这个不用说了,就是我们维护的版本号。

 

3、EX_ENVINFO_T envinfo;

typedef struct ex_environment_info_t
{
    boot_mode_type boot_mode;
    ex_rtc_struct rtc;
    kal_char execution_unit[EX_UNIT_NAME_LEN];
    kal_uint8 status;
    kal_uint8 pad[2];
    kal_uint32 stack_ptr;
    kal_uint32 stack_dump[EX_STACK_DUMP_LEN];
    kal_uint16 ext_queue_pending_cnt;
    kal_uint32 ext_queue_pending[EX_QUEUE_TRACK];
    kal_uint32 interrupt_mask[2];
    kal_uint32 processing_lisr;
    kal_uint32 lr;
} EX_ENVINFO_T;

 

boot_mode_type boot_mode;标识是什么模式开机,是按power键开机,还是RTC开机,还是USB开机,还是充电开机等等

ex_rtc_struct rtc;从RTC的寄存器中读出时间

kal_char execution_unit[EX_UNIT_NAME_LEN];记录出现异常时,当前的task

kal_uint8 status;记录出现异常时,当前task的状态

kal_uint8 pad[2];好像是保留值

kal_uint32 stack_ptr;异常出现时的SP值

kal_uint32 stack_dump[EX_STACK_DUMP_LEN];以上面的stack_ptr作为栈顶,搜索10个像是函数的地址,这些地址可以通过build目录中的sym文件猜测函数的调用关系。但这10个地址不一定准确,需要靠人脑去判断是否为正确的函数地址

kal_uint16 ext_queue_pending_cnt;当前task的外部队列中,残留还没有被处理的消息个数

kal_uint32 ext_queue_pending[EX_QUEUE_TRACK];当前task的外部队列中,残留还没有被处理的消息ID

kal_uint32 interrupt_mask[2];中断屏蔽寄存器值
kal_uint32 processing_lisr;假如lisr正在执行,这里会记录lisr正在运行的地址

kal_uint32 lr;异常发生时的lr寄存器的值


4、EX_DIAGNOSISINFO_T diaginfo;

typedef struct ex_diagnosis_info_t
{
    EX_DIAGNOSIS_T diagnosis;
    kal_char owner[EX_UNIT_NAME_LEN];
    kal_uint8 pad[3];
    kal_uint32 timing_check[EX_TIMING_CHECK_LEN];
} EX_DIAGNOSISINFO_T;

 

EX_DIAGNOSIS_T diagnosis;异常情况出现时,会检查系统是否已经有问题。比如说中断向量表是否被踩,stack是否被爆掉。所以假如这里不是显示health,则需要先解决系统的问题。

kal_char owner[EX_UNIT_NAME_LEN];假如出现了stack爆掉的情况,会显示哪个task或者hisr的名字

kal_uint8 pad[3];不知道有什么用,像是保留

kal_uint32 timing_check[EX_TIMING_CHECK_LEN];还不知道有什么用

 

5、EX_CONTENT_T content;

typedef union
{
    EX_FATALERR_T fatalerr;
    EX_ASSERTFAIL_T assert;
} EX_CONTENT_T;

这是一个联合体,假如是fatal error,则会填入fatal error的信息。假如是assert,则会填入assert的信息。(- -!有点罗嗦,抱歉!)

 

6、EX_FATALERR_T fatalerr;

typedef struct ex_fatalerror_t
{
    EX_FATALERR_CODE_T error_code;
    EX_DESCRIPTION_T description;
    EX_ANALYSIS_T analysis;
    EX_GUIDELINE_T guideline;
    union
    {
        EX_CTRLBUFF_T ctrl_buff;
        EX_TASKINFO_T task_info[EX_MAX_TASK_DUMP];
        EX_CPU_REG_T cpu_reg;
    } info;
} EX_FATALERR_T;

 

EX_FATALERR_CODE_T error_code;出现fatal error的时候,会记录error code1和error code2。这两个值特别重要,因为可以知道出现fatal error大概原因。从而选择不同的分析方法。

EX_DESCRIPTION_T description;我猜测是出现fatal error时,还可以输出一些附加信息。

EX_ANALYSIS_T analysis;与EX_DESCRIPTION_T description;变量一样。我猜测是出现fatal error时,还可以输出一些附加信息。

EX_GUIDELINE_T guideline;与EX_DESCRIPTION_T description;变量一样。我猜测是出现fatal error时,还可以输出一些附加信息。

 

EX_CTRLBUFF_T ctrl_buff;假如control buffer有问题,则会记录control buffer的一些信息。

typedef struct
{
    kal_uint32 ex_ctrlbuf_size;
    kal_uint32 ex_ctrlbuf_num;

    EX_CTRLBUFF_INFO_T ex_ctrlbuf_top;

    EX_CTRLBUFF_INFO_T ex_ctrlbuf_second;

    EX_CTRLBUFF_INFO_T ex_ctrlbuf_third; 

    EX_CTRLBUFF_OWNER_T ex_monitor[3];
    kal_uint32 ex_reserved[2];  /* reserved */
} EX_CTRLBUFF_T;

kal_uint32 ex_ctrlbuf_size; control buffer的大小

kal_uint32 ex_ctrlbuf_num; control buffer的数量

EX_CTRLBUFF_INFO_T ex_ctrlbuf_top;

EX_CTRLBUFF_INFO_T ex_ctrlbuf_second;

EX_CTRLBUFF_INFO_T ex_ctrlbuf_third; 

control buffer出错时,有两种错误。一种是buffer数量太少,不足够被申请;另外一种是buffer里面的数据被踩坏。对于两种错误,这3个变量的意义都不一样。对于第一种错误,ex_ctrlbuf_top记录排名第一位申请最多buffer的模块的一些信息,ex_ctrlbuf_second记录排名第二多,ex_ctrlbuf_third记录排名第三多的信息:

typedef struct
{
    kal_char ex_his_owner[8];

    kal_char ex_his_source[16];
    kal_uint32 ex_his_line;

    kal_uint32 ex_his_count;   
} EX_CTRLBUFF_HISTORY_T;

kal_char ex_his_owner[8];申请control buffer的模块

kal_char ex_his_source[16];申请control buffer的文件名
kal_uint32 ex_his_line;申请control buffer的地方在文件中第几行

kal_uint32 ex_his_count;申请control buffer的数量

对于第二种错误,ex_ctrlbuf_second记录被写坏的buffer的信息。ex_ctrlbuf_top是被踩坏的buffer的前一个buffer的信息。ex_ctrlbuf_third是被踩坏的buffer的后一个buffer的信息。

typedef struct
{
    kal_uint32 ex_buf_NU_header1;

    kal_uint32 ex_buf_NU_header2; 
    kal_uint32 ex_buf_KAL_header1;

    kal_uint32 ex_buf_KAL_header2;
    kal_uint32 ex_buf_KAL_header3;

    kal_uint32 ex_buf_poolID;     
    kal_uint32 ex_buf_KAL_footer1;
    kal_uint32 ex_buf_KAL_footer2;        
} EX_CTRLBUFF_COMMON_T;

kal_uint32 ex_buf_NU_header1;假如buffer被申请出去了,这里是NULL。假如没被分配,这里记录下一个还未被分配的buffer的指针

kal_uint32 ex_buf_NU_header2;control buffer的ID

kal_uint32 ex_buf_KAL_header1;control buffer头部的一个标记“0xF1F1F1F1”,假如buffer被踩,这个标记会写成另外一个值

kal_uint32 ex_buf_KAL_header2;该control buffer是被哪个模块申请

kal_uint32 ex_buf_KAL_header3;control buffer的ID

kal_uint32 ex_buf_poolID;control buffer pool的ID

kal_uint32 ex_buf_KAL_footer1;觉得没有什么用

kal_uint32 ex_buf_KAL_footer2;底部的一个标记“0xF2F2F2F2”,假如buffer被踩或者buffer溢出时,这个标记会写成另外一个值

 

EX_TASKINFO_T task_info[EX_MAX_TASK_DUMP];

当task出现错误时,例如外部队列爆掉就会输出task的信息:

typedef struct
{
    kal_char ex_task_name[8];

    kal_char ex_task_stack_gp[8];

    kal_uint32 ex_task_cur_status;  

    EX_QUEUE_T ex_task_external_q;  
    EX_QUEUE_T ex_task_internal_q;   
    kal_uint32 ex_reserved;          

} EX_TASKINFO_T;

kal_char ex_task_name[8];task的名字

kal_char ex_task_stack_gp[8];每个task的堆栈的最顶部都会有一个标记“STACKEND”。假如堆栈爆了,会把这个标记写坏。所以可以从这个标记判断堆栈是否坏掉

kal_uint32 ex_task_cur_status;task当前的状态

EX_QUEUE_T ex_task_external_q;task外部队列的消息的信息

typedef struct
{
    kal_uint8 ex_q_src_mod;
    kal_uint8 ex_q_count;

    kal_uint16 ex_q_msg_id;
    kal_uint16 ex_q_cur_mes_no;

    kal_uint16 ex_q_config_entry;
} EX_QUEUE_T;

kal_uint8 ex_q_src_mod;队列中若有相同的消息,这里记录发送消息的模块名字
kal_uint8 ex_q_count;队列中若有相同的消息,相同消息的数量

kal_uint16 ex_q_msg_id;队列中若有相同的消息,显示该消息的ID

kal_uint16 ex_q_cur_mes_no;当前外部队列中有一共有多少信息

kal_uint16 ex_q_config_entry;队列最大可以容纳多少个消息

 

EX_CPU_REG_T cpu_reg;假如发生了CPU触发的异常,则会把CPU寄存器的信息记录在这个structure中

 

7、EX_ASSERTFAIL_T assert;

typedef struct ex_assert_fail_t
{
    kal_char filename[EX_ASSERTFAIL_FILENAME_LEN];
    kal_uint32 linenumber;
    kal_uint32 parameters[3];
    kal_uint8 dump[EX_ASSERTFAIL_DUMP_LEN];
    kal_uint8 guard[EX_GUARD_LEN];
} EX_ASSERTFAIL_T;

kal_char filename[EX_ASSERTFAIL_FILENAME_LEN];出现assert时候的文件名

kal_uint32 linenumber;出现assert的地方在文件的第几行

kal_uint32 parameters[3];EX_ASSERT可以输出3个变量信息,会记录在这里

kal_uint8 dump[EX_ASSERTFAIL_DUMP_LEN];EX_ASSERT_DUMP会输出10个buffer的信息,指针会记录在这里
kal_uint8 guard[EX_GUARD_LEN];这个不知道作用是什么

本文来自:我爱研发网(52RD.com) - R&D大本营
详细出处:http://www.52rd.com/Blog/Detail_RD.Blog_mastervon_24767.html

阅读更多
个人分类: 专业技术文章
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭