600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > HaaS100开发调试系列 之 使用AliOS Things诊断调试组件定位Bug

HaaS100开发调试系列 之 使用AliOS Things诊断调试组件定位Bug

时间:2023-11-13 17:06:07

相关推荐

HaaS100开发调试系列 之 使用AliOS Things诊断调试组件定位Bug

1、背景

在嵌入式开发中,我们经常遇到的一个问题是:写代码一个不小心,就制造了一个bug,C语言中bug的威力大家也心知肚明——可以直接把系统搞挂!

即大家常见的系统死机、系统重启等等;而问题的来源或者根因,又常常使得我们束手无策,只好采用“打印”大法,一遍遍的加printf。

而每次改代码又要经历痛苦的“编译-烧写-运行-复现”这个过程,不知不觉,一天过去了,bug还没解。

所以我们经常想,要是系统能直接告诉我们bug在哪、是什么错误导致的就好了,直接改代码分分钟搞定,可以节省很多开发时间!

这也是我们常用一些仿真器(如JLINK)的原因,系统挂死后可以挂上仿真器,查看PC在哪,通过bt查看调用栈等来帮助我们定位。

而这又对硬件有了一定的要求——要能支持仿真器连接,有时还要开发者折腾一下环境。

我们的HaaS100虽然也支持硬件连接仿真器(参考上一篇帖子:HaaS100开发调试系列 之 如何使用J-Link仿真器调试代码)。

这里我们告知大家一个更方便定位系统异常死机的方法——AliOS Things的诊断调试组件

2、诊断调试组件简介

诊断调试包含的内容很多,前面我们介绍过一些调试命令,参见文章《一文轻松入门HaaS100诊断调试系统》。

本文我们重点介绍的是AliOS Things的诊断调试组件是怎么帮助解决代码bug的。

诊断调试组件可以缩短bug定位时间。

如果一个bug出现导致系统异常后,用户可以不用连仿真器、不用加打印、不用打开gdb单步调试的情况下,可以快速找到bug原因。

或者帮助用户指出可能的异常点,进而修复以节省开发时间。

举例说明:

代码中访问了非法内存(比如:在不可写的地址处写了数据,如访问了0地址)导致系统奔溃,AliOS Things诊断调试组件可以记录访问非法内存时的pc值,告诉用户挂在了哪一行;代码跑飞了(pc=0),AliOS Things诊断调试组件记录了函数调用的栈,并根据栈向上回溯可以找到A->B->C的函数调用过程,与仿真器中bt命令类似;用户内存申请时malloc 失败,AliOS Things诊断调试组件可以记录用户此时申请了多少内存、此时系统还有多少内存可以供申请、用户是在哪个任务中申请的内存、从系统启动开始内存的申请情况等信息,这些信息可以帮助开发者定位是否有内存泄漏的情况。......

AliOS Things的诊断调试组件可以干很多事,后面我们会陆续推出文章来介绍。

今天我们只看一个问题——bug产生了,系统异常挂死了,那么AliOS Things会做哪些事呢?

简单一句话回答,输出重要的log帮助大家定位问题,这也是AliOS Things的诊断调试组件最重要的部分。

3、AliOS Things的异常log到底是啥样

直接上HaaS100输出的log

!!!!!!!!!! Exception !!!!!!!!!!========== Regs info ========== 异常现场寄存器信息R00x00000000R10x34027F20R20x34027F30R30x340251B4R40xFFFFFFFFR50x00000000R60x2C0D2C72R70x00000001R80x2C0D2C86R90x2C0D236BR100x00000000R110x00000000R120x0000C000LR0x1C5D6CC3PC0x1C5D6CC2xPSR 0x61000000SP0x34025118EXC_RET 0xFFFFFFBCEXC_NUM 0x00000006PRIMASK 0x00000000FLTMASK 0x00000000BASEPRI 0x00000000CFSR 0x01000000HFSR 0x00000000MMFAR 0xE000ED34BFAR 0xE000ED38AFSR 0x00000000========== Stack info ========== 异常现场栈信息stack(0x34025118): 0x34027D20 0x340251B4 0x00000000 0x34022F98 stack(0x34025128): 0x00000000 0x34682380 0x1C5D6BBD 0x00000005 stack(0x34025138): 0x00000006 0x1C5D621F 0x00000003 0x2C0D2A0C stack(0x34025148): 0x340230C4 0x00000013 0x34682280 0x00000000 stack(0x34025158): 0x000000F7 0x00000005 0x00000003 0x00000000 stack(0x34025168): 0x00000000 0x00000000 0x00000001 0x34682380 stack(0x34025178): 0x34022F98 0x0000000B 0x34022FA8 0x00000000 stack(0x34025188): 0x000000F6 0x00000001 0x2C0D294D 0x1C5D63D3 stack(0x34025198): 0x00000000 0x2C0D1BD0 0x00000000 0x0D000000 stack(0x340251A8): 0x78300070 0x66666666 0x66666666 0x00003100 stack(0x340251B8): 0x00000000 0x00000000 0x00000000 0x00000000 stack(0x340251C8): 0x00000000 0x00000000 0x00000000 0x00000000 stack(0x340251D8): 0x00000000 0x00000000 0x00000000 0x00000000 stack(0x340251E8): 0x00000000 0x00000000 0x00000000 0x00000000 stack(0x340251F8): 0x00000000 0x00000000 0x00000000 0x00000000 stack(0x34025208): 0x00000000 0x00000000 0x00000000 0x00000000 ========== Call stack ========== 栈回溯信息,可以得出函数调用过程backtrace : 0x1C5D6CC2 backtrace : 0x1C5D621C backtrace : 0x1C5D63CE backtrace : ^task entry^========== Heap Info ========== 系统此时的内存信息,可以看出内存申请了多少,还剩多少---------------------------------------------------------------------------[HEAP]| TotalSz | FreeSz| UsedSz| MinFreeSz | MaxFreeBlkSz || 0x00680000 | 0x0065A300 | 0x00025D00 | 0x00659E20 | 0x0065A300 |---------------------------------------------------------------------------========== Task Info ========== 系统当前任务状态信息,可以看出任务栈是否过小--------------------------------------------------------------------------TaskName State Prio StackStackSize (MinFree)--------------------------------------------------------------------------dyn_mem_proc_task PEND0x00000006 0xB938 0x00000400(0x0000035C)idle_task RDY0x0000003D 0xBE0C 0x00001000(0x00000F94)DEFAULT-WORKQUEUE PEND0x00000014 0xF1E8 0x00000C00(0x00000B7C)timer_task PEND0x00000005 0xD0D8 0x00002000(0x00001F48)main SLP0x00000021 0xA000 0x00005000(0x000044C4)transq_msg PEND0x0000001F 0x3469A4C4 0x00001000(0x00000680)apps_recover SLP0x00000021 0xA588 0x00001000(0x00000F64)temp_main SLP0x00000021 0x346A15D8 0x00001000(0x00000F80)main_task SLP0x00000020 0x34002668 0x00020000(0x0001F6C4)cli RDY0x0000003C 0x340232D0 0x00002000(0x0000180C)ulog PEND0x0000003C 0x34026890 0x00000C00(0x00000A58)========== Queue Info ========== AliOS Things kernel queue使用信息-------------------------------------------------------QueAddr TotalSize PeakNum CurrNum TaskWaiting-------------------------------------------------------======== Buf Queue Info ======== AliOS Things kernel buf queue使用信息------------------------------------------------------------------BufQueAddr TotalSize PeakNum CurrNum MinFreeSz TaskWaiting------------------------------------------------------------------0xFDE8 0x000001E0 0x00000000 0x00000000 0x000001E0 timer_task0x34025420 0x00001400 0x00000000 0x00000000 0x00001400 ulog=========== Sem Info =========== AliOS Things kernel semphore使用信息--------------------------------------------SemAddr CountPeakCount TaskWaiting--------------------------------------------0xCF60 0x00000000 0x00000000 dyn_mem_proc_task 0xF1B8 0x00000000 0x00000000 DEFAULT-WORKQUEUE 0x340023A0 0x00000001 0x00000001 0x34002478 0x00000000 0x00000000 0x340025D0 0x00000001 0x00000001 0x34682C34 0x00000000 0x00000000 0x34682C58 0x00000000 0x00000000 0x340275B0 0x00000000 0x00000000 !!!!!!!!!! dump end !!!!!!!!!!

3.1、Log分析

上面的log是在HaaS100上产生系统异常后,由AliOS Things输出的log。log可以分为:

异常现场寄存器:跟arch相关的通用寄存器和一些特殊寄存器信息;异常栈信息:产生异常的任务的栈信息;栈回溯信息:产生异常的调用栈,类似仿真器中的bt命令,这个是异常log中最重要的部分;内存信息:系统此时的内存状态,对于定位一些内存泄漏问题比较有用;任务信息:系统当前的任务状态信息,对于定位任务栈溢出问题比较有用;内核信息:包含了kernel 中的queue、buf_queue 和 sem状态。

log中所示的内存包含了很多内核相关的内容,后续我们也会推出文章来介绍AliOS Things的内核。

3.2、如何打开诊断调试组件

用户只需要在aos.mk里包含debug组件,重新编译烧录上电即可。

$(NAME)_COMPONENTS += debug

3.3、如何产生一个系统异常

理论上任何一个系统异常后,都会出现类似上面的log,如果开发者对产生系统异常感兴趣,可以使用下面的简单方法:

m 0xffffffff 1

即使用系统提供的cli 命令,改写系统位于0xfffffff出的内存值为1,地址0xfffffff在HaaS100上为不可写的区域,改写这个值可以触发系统异常,打印出上面的log。

使用cli命令的方法可以参考另外一篇文章《一文轻松入门HaaS100诊断调试系统》

3.4、调用栈的价值

调用栈的信息输出是AliOS Things诊断调试组件的核心,我们通过上面的命令产生异常后,使用toolchain自带的arm-none-eabi-addr2line 命令对上面log中的call stack调用栈中的地址进行解析,使用方法是:

arm-none-eabi-addr2line -pfiCe xxx.elf addr

以log中输出的call stack地址为例

./build/compiler/gcc-arm-none-eabi/Linux64/bin/arm-none-eabi-addr2line -pfiCe out/debug_demo@haas100/binary/debug_demo@haas100.elf 0x1C5D6CC2 0x1C5D621C 0x1C5D63CE

可以解析出调用栈所对应的代码位置,如:

pmem_cmd at /workspace/hass/AliOS-Things/core/cli/cli_default_command.c:224proc_onecmd at /workspace/hass/AliOS-Things/core/cli/cli.c:173(inlined by) cli_handle_input at /workspace/hass/AliOS-Things/core/cli/cli.c:290cli_main at /workspace/hass/AliOS-Things/core/cli/cli.c:781

我们可以清楚看到发生异常的函数调用过程,并且指出了函数代码的路径和行号。

cli_main -- > proc_onecmd ---> pmem_cmd

4、笔者的话

大家有没有觉得,通过这个方法定位Bug,让异常发生的位置一目了然,我们快速找到这行代码后修改,分分钟解决了这个Bug。又可以开心的继续干活了!

不过,AliOS Things诊断调试组件只是尽可能的帮助大家节省解Bug的时间,而有些Bug的产生并不会导致系统异常,但会给系统埋下不稳定的伏笔,这个时候再好的诊断工具也没用了。

大家还是要多修炼写代码内功,不产生bug才是我们的追求!

5、开发者技术支持

如需更多技术支持,可加入钉钉开发者群,或者关注微信公众号

更多技术与解决方案介绍,请访问阿里云AIoT首页/

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。