美文网首页
openharmony:Backtrace异常调测

openharmony:Backtrace异常调测

作者: xEndLess | 来源:发表于2022-07-02 20:49 被阅读0次

当前openharmony针对stm32f407还没有在线调试功能。所以很有必要移植backtrace组件。不然查找BUG很是艰难。

1.Enable Backtrace

make menuconfig后,设置如下参数,并保存。

(Top) → Kernel
                                                                                               Huawei LiteOS Configuration
[*] Enable Extend Kernel (NEW)
[*]     Enable Backtrace      //选中
            Select Backtrace Type (1: Call stack analysis for cortex-m series by scanning the stack)  --->
(15) Backtrace depth (NEW)    /15
[ ] Enable C++ Support (NEW)
[*] Enable Signal (NEW)
[ ] Enable Cpup (NEW)
[ ] Enable Dynamic Link Feature (NEW)
[ ] Enable Power Management (NEW)
[ ] Enable Hook Feature (NEW)
[ ] Enable Low Memory Killer (NEW)
[ ] Enable Lite Memory Sanitizer (NEW)

hb build之后,报如下错误。

[OHOS ERROR] /home/xendless/tools/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.2.1/../../../../arm-none-eabi/bin/ld: obj/kernel/liteos_m/components/backtrace/backtrace.los_backtrace.o: in function `OsStackDataIsCodeAddr':
[OHOS ERROR] /home/xendless/openharmony/code-v3.1.1-Release/OpenHarmony/out/tunnel_box/tunnel/../../../kernel/liteos_m/components/backtrace/los_backtrace.c:48: undefined reference to `_stext'
[OHOS ERROR] /home/xendless/tools/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/bin/../lib/gcc/arm-none-eabi/11.2.1/../../../../arm-none-eabi/bin/ld: obj/kernel/liteos_m/components/backtrace/backtrace.los_backtrace.o: in function `OsInsIsBlOrBlx':
[OHOS ERROR] /home/xendless/openharmony/code-v3.1.1-Release/OpenHarmony/out/tunnel_box/tunnel/../../../kernel/liteos_m/components/backtrace/los_backtrace.c:117: undefined reference to `_sstack'
[OHOS ERROR] collect2: error: ld returned 1 exit status

没有定义_stext_sstack。看一下kernel/liteos_m/components/backtrace/los_backtrace.c 48行的代码。

/* This function is used to judge whether the data in the stack is a code section address.
   The default code section is only one, but there may be more than one. Modify the
   judgment condition to support multiple code sections. */
WEAK BOOL OsStackDataIsCodeAddr(UINTPTR value)
{
    if ((value >= CODE_START_ADDR) && (value < CODE_END_ADDR)) {
        return TRUE;
    }
    return FALSE;
}

CODE_START_ADDRCODE_END_ADDR,定义在kernel/liteos_m/components/backtrace/los_backtrace.h中。

#elif defined(__GNUC__)
/* The default code section start address */
#define CODE_SECTION_START      _stext
/* The default code section end address */
#define CODE_SECTION_END        _etext
/* The default C stack section start address */
#define CSTACK_SECTION_START    _sstack
/* The default C stack section end address */
#define CSTACK_SECTION_END      _estack

extern CHAR *CODE_SECTION_START;
extern CHAR *CODE_SECTION_END;
extern CHAR *CSTACK_SECTION_START;
extern CHAR *CSTACK_SECTION_END;

/* Default only one code section. In fact, there may be more than one.
   You can define more than one and redefine the OsStackDataIsCodeAddr function
   to support searching in multiple code sections */
#define CODE_START_ADDR     ((UINTPTR)&CODE_SECTION_START)
#define CODE_END_ADDR       ((UINTPTR)&CODE_SECTION_END)
#define CSTACK_START_ADDR   ((UINTPTR)&CSTACK_SECTION_START)
#define CSTACK_END_ADDR     ((UINTPTR)&CSTACK_SECTION_END)

2.然后需要在.ld文件中增加_estask_stext段。

/* Highest address of the user mode stack */
_sstack = 0x20000000;
_estack = 0x20020000;    /* end of RAM */

  /* The program code and other data goes into FLASH */
  .text :
  {
    . = ALIGN(4);
    _stext = .;
    *(.text)           /* .text sections (code) */
    *(.text*)          /* .text* sections (code) */
    *(.glue_7)         /* glue arm to thumb code */
    *(.glue_7t)        /* glue thumb to arm code */
    *(.eh_frame)
    ……
    __zinitcall_bsp_start = .;
    KEEP (*(.zinitcall.bsp0.init))
    KEEP (*(.zinitcall.bsp1.init))
    KEEP (*(.zinitcall.bsp2.init))
    KEEP (*(.zinitcall.bsp3.init))
    KEEP (*(.zinitcall.bsp4.init))
    __zinitcall_bsp_end = .;
    __zinitcall_device_start = .;
    KEEP (*(.zinitcall.device0.init))
    KEEP (*(.zinitcall.device1.init))
    KEEP (*(.zinitcall.device2.init))
    KEEP (*(.zinitcall.device3.init))
    KEEP (*(.zinitcall.device4.init))
    __zinitcall_device_end = .;
    __zinitcall_core_start = .;
    KEEP (*(.zinitcall.core0.init))
    KEEP (*(.zinitcall.core1.init))
    KEEP (*(.zinitcall.core2.init))
    KEEP (*(.zinitcall.core3.init))
    KEEP (*(.zinitcall.core4.init))
    __zinitcall_core_end = .;
    __zinitcall_sys_service_start = .;
    KEEP (*(.zinitcall.sys.service0.init))
    KEEP (*(.zinitcall.sys.service1.init))
    KEEP (*(.zinitcall.sys.service2.init))
    KEEP (*(.zinitcall.sys.service3.init))
    KEEP (*(.zinitcall.sys.service4.init))
    __zinitcall_sys_service_end = .;
    __zinitcall_sys_feature_start = .;
    KEEP (*(.zinitcall.sys.feature0.init))
    KEEP (*(.zinitcall.sys.feature1.init))
    KEEP (*(.zinitcall.sys.feature2.init))
    KEEP (*(.zinitcall.sys.feature3.init))
    KEEP (*(.zinitcall.sys.feature4.init))
    __zinitcall_sys_feature_end = .;
    __zinitcall_run_start = .;
    KEEP (*(.zinitcall.run0.init))
    KEEP (*(.zinitcall.run1.init))
    KEEP (*(.zinitcall.run2.init))
    KEEP (*(.zinitcall.run3.init))
    KEEP (*(.zinitcall.run4.init))
    __zinitcall_run_end = .;
    __zinitcall_app_service_start = .;
    KEEP (*(.zinitcall.app.service0.init))
    KEEP (*(.zinitcall.app.service1.init))
    KEEP (*(.zinitcall.app.service2.init))
    KEEP (*(.zinitcall.app.service3.init))
    KEEP (*(.zinitcall.app.service4.init))
    __zinitcall_app_service_end = .;
    __zinitcall_app_feature_start = .;
    KEEP (*(.zinitcall.app.feature0.init))
    KEEP (*(.zinitcall.app.feature1.init))
    KEEP (*(.zinitcall.app.feature2.init))
    KEEP (*(.zinitcall.app.feature3.init))
    KEEP (*(.zinitcall.app.feature4.init))
    __zinitcall_app_feature_end = .;
    __zinitcall_test_start = .;
    KEEP (*(.zinitcall.test0.init))
    KEEP (*(.zinitcall.test1.init))
    KEEP (*(.zinitcall.test2.init))
    KEEP (*(.zinitcall.test3.init))
    KEEP (*(.zinitcall.test4.init))
    __zinitcall_test_end = .;
    __zinitcall_exit_start = .;
    KEEP (*(.zinitcall.exit0.init))
    KEEP (*(.zinitcall.exit1.init))
    KEEP (*(.zinitcall.exit2.init))
    KEEP (*(.zinitcall.exit3.init))
    KEEP (*(.zinitcall.exit4.init))
    __zinitcall_exit_end = .;

    KEEP (*(.init))
    KEEP (*(.fini))

    . = ALIGN(4);
    _etext = .;        /* define a global symbols at end of code */
  } >FLASH

3.stm32f4xx_it.c增加如下代码。

/* USER CODE BEGIN EV */
extern void HalPendSV(void);
extern void OsTickHandler(void);
extern void HalExcHardFault(void);
extern void HalExcNMI(void);
extern void HalExcMemFault(void);
extern void HalExcBusFault(void);
extern void HalExcUsageFault(void);
extern void HalExcSvcCall(void);
/* USER CODE END EV */

/******************************************************************************/
/*           Cortex-M4 Processor Interruption and Exception Handlers          */
/******************************************************************************/
/**
  * @brief This function handles Non maskable interrupt.
  */
void NMI_Handler(void)
{
    HalExcNMI();
}

/**
  * @brief This function handles Hard fault interrupt.
  */
void HardFault_Handler(void)
{
    HalExcHardFault();
}

/**
  * @brief This function handles Memory management fault.
  */
void MemManage_Handler(void)
{
    HalExcMemFault();
}

/**
  * @brief This function handles Pre-fetch fault, memory access fault.
  */
void BusFault_Handler(void)
{
    HalExcBusFault();
}

/**
  * @brief This function handles Undefined instruction or illegal state.
  */
void UsageFault_Handler(void)
{
    HalExcUsageFault();
}

/**
  * @brief This function handles System service call via SWI instruction.
  */
void SVC_Handler(void)
{
    HalExcSvcCall();
}

/**
  * @brief This function handles Debug monitor.
  */
void DebugMon_Handler(void)
{

}

/**
  * @brief This function handles Pendable request for system service.
  */
void PendSV_Handler(void)
{
    HalPendSV();
}

/**
  * @brief This function handles System tick timer.
  */
void SysTick_Handler(void)
{
    OsTickHandler();
}

4.测试

在main.c中增加如下测试代码。

UINT32 g_taskExcId;
#define TSK_PRIOR 4

/* 模拟异常函数 */
    
UINT32 Get_Result_Exception_0(UINT16 dividend){
    UINT32 divisor = 0;
    UINT32 result = dividend / divisor;
    return result;
}

UINT32 Get_Result_Exception_1(UINT16 dividend){
    return Get_Result_Exception_0(dividend);
}

UINT32 Get_Result_Exception_2(UINT16 dividend){
    return Get_Result_Exception_1(dividend);
}

UINT32 Example_Exc(VOID)
{
    UINT32 ret;

    printf("Enter Example_Exc Handler.\r\n");

    /* 模拟函数调用 */
    ret = Get_Result_Exception_2(TSK_PRIOR);
    printf("Divided result =%u.\r\n", ret);

    printf("Exit Example_Exc Handler.\r\n");
    return ret;
}


/* 任务测试入口函数,创建一个会发生异常的任务 */
UINT32 Example_Exc_Entry(VOID)
{
    UINT32 ret;
    TSK_INIT_PARAM_S initParam;

    /* 锁任务调度,防止新创建的任务比本任务高而发生调度 */
    LOS_TaskLock();

    printf("LOS_TaskLock() Success!\r\n");

    initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)Example_Exc;
    initParam.usTaskPrio = TSK_PRIOR;
    initParam.pcName = "Example_Exc";
    initParam.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
    /* 创建高优先级任务,由于锁任务调度,任务创建成功后不会马上执行 */
    ret = LOS_TaskCreate(&g_taskExcId, &initParam);
    if (ret != LOS_OK) {
        LOS_TaskUnlock();

        printf("Example_Exc create Failed!\r\n");
        return LOS_NOK;
    }

    printf("Example_Exc create Success!\r\n");

    /* 解锁任务调度,此时会发生任务调度,执行就绪队列中最高优先级任务 */
    LOS_TaskUnlock();

    return LOS_OK;
}

测试运行结果如下:

*************Exception Information**************
Type      = 3345
ThrdPid   = 3
Phase     = exc in task
FaultAddr = 0xabababab
Current task info:
Task name = Example_Exc
Task ID   = 3
Task SP   = 00000204
Task ST   = 0x8
Task SS   = 0x2c8
Exception reg dump:
PC        = 0x4770
LR        = 0x8810f38c
SP        = 0x2d0
R0        = 0xf5b30370
R1        = 0xd1010f70
R2        = 0x8b10ecb1
R3        = 0x1ff0e8b1
R4        = 0xf403681b
R5        = 0xf5b30370
R6        = 0xd1010f70
R7        = 0x8b10ed20
R8        = 0x682e4d0d
R9        = 0x68686030
R10       = 0x68016028
R11       = 0x302cf8df
R12       = 0x8809f381
PriMask   = 0x1
xPSR      = 0xe000ed20
[ERR][Example_Exc]msp statck [0x20000000, 0x20020000], cur task stack [0x8, 0x2d0], cur sp(0x2d0) is overflow!
----- backtrace start -----
----- backtrace end -----

 TID  Priority   Status StackSize WaterLine StackPoint TopOfStack EventMask  SemID  TaskEntry name
 ---  -------- -------- --------- --------- ---------- ---------- --------- ------ ---------- ----
   0        0      Pend     0x2d0     0x164 0x20002af4 0x20002988         0 0xffff 0x8002e09 Swt_Task                        
   1       31     Ready     0x500      0xcc 0x2000309c 0x20002c68         0 0xffff 0x80032dd IdleCore000                     
   2        6     Ready    0x1000      0xcc 0x200040a4 0x20003170         0 0xffff 0x8005a61 taskSampleEntry1                
[ERR][Example_Exc]CURRENT task Example_Exc stack overflow!
   3        4   Running     0x2c80xffffffff      0x204        0x8         0 0xffff 0x8005a99 Example_Exc                     

关于如何根据打印信息定位问题,可以看openharmony官方文档异常调测

相关文章

网友评论

      本文标题:openharmony:Backtrace异常调测

      本文链接:https://www.haomeiwen.com/subject/jkxhbrtx.html