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

简介: 一个更方便定位系统异常死机的方法——AliOS Things的诊断调试组件

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

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

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

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

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

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

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

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

2、诊断调试组件简介
诊断调试包含的内容很多,前面我们介绍过一些调试命令。

本文我们重点介绍的是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会做哪些事呢?

3、AliOS Things的异常log到底是啥样
直接上HaaS100输出的log

> > !!!!!!!!!! Exception  !!!!!!!!!!
========== Regs info  ==========  异常现场寄存器信息
R0      0x00000000
R1      0x34027F20
R2      0x34027F30
R3      0x340251B4
R4      0xFFFFFFFF
R5      0x00000000
R6      0x2C0D2C72
R7      0x00000001
R8      0x2C0D2C86
R9      0x2C0D236B
R10     0x00000000
R11     0x00000000
R12     0x0000C000
LR      0x1C5D6CC3
PC      0x1C5D6CC2
xPSR    0x61000000
SP      0x34025118
EXC_RET 0xFFFFFFBC
EXC_NUM 0x00000006
PRIMASK 0x00000000
FLTMASK 0x00000000
BASEPRI 0x00000000
CFSR    0x01000000
HFSR    0x00000000
MMFAR   0xE000ED34
BFAR    0xE000ED38
AFSR    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       Stack      StackSize (MinFree)
--------------------------------------------------------------------------
dyn_mem_proc_task    PEND     0x00000006 0x2004B938 0x00000400(0x0000035C)
idle_task            RDY      0x0000003D 0x2004BE0C 0x00001000(0x00000F94)
DEFAULT-WORKQUEUE    PEND     0x00000014 0x2004F1E8 0x00000C00(0x00000B7C)
timer_task           PEND     0x00000005 0x2004D0D8 0x00002000(0x00001F48)
main                 SLP      0x00000021 0x2015A000 0x00005000(0x000044C4)
transq_msg           PEND     0x0000001F 0x3469A4C4 0x00001000(0x00000680)
apps_recover         SLP      0x00000021 0x2004A588 0x00001000(0x00000F64)
temp_main            SLP      0x00000021 0x346A15D8 0x00001000(0x00000F80)
main_task            SLP      0x00000020 0x34002668 0x00020000(0x0001F6C4)
cli                  RDY      0x0000003C 0x340232D0 0x00002000(0x0000180C)
ulog                 PEND     0x0000003C 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
------------------------------------------------------------------
0x2004FDE8 0x000001E0 0x00000000 0x00000000 0x000001E0 timer_task          
0x34025420 0x00001400 0x00000000 0x00000000 0x00001400 ulog
 
=========== Sem Info ===========  AliOS Things kernel semphore使用信息
--------------------------------------------
SemAddr    Count      PeakCount  TaskWaiting
--------------------------------------------
0x2004CF60 0x00000000 0x00000000 dyn_mem_proc_task   
0x2004F1B8 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:224
 
proc_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:290
 
cli_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、开发者技术支持
如需更多技术支持,可加入钉钉开发者群,或者关注微信公众号
image.png

相关文章
|
存储 网络协议 物联网
AliOS Things组件功能介绍(一)
AliOS Things组件功能介绍(一)
270 0
|
JSON IDE 测试技术
使用Airtest对iOS进行自动化的常见问题答疑
使用Airtest对iOS进行自动化的常见问题答疑
688 0
|
IDE 物联网 开发工具
安装IDE并下载AliOS Things代码 引导流程
安装IDE并下载AliOS Things代码 引导流程
安装IDE并下载AliOS Things代码 引导流程
|
Web App开发 分布式计算 监控
七款Debug工具推荐:iOS开发必备的调试利器
在开发应用的时候,我们会碰到各种各样的bug,我们想要更好地了解到底发生了什么。然而不可预期的调试工作,总会浪费我们大量时间。本文介绍了七款诊断调试工具,可以从可以帮助我们对代码、UI界面等进行调试
1562 0
七款Debug工具推荐:iOS开发必备的调试利器
|
算法 AliOS-Things 物联网
HaaS100开发调试系列 之 定位AliOS Things内存及Crash问题
本文主要说开发调试过程中经常遇到的内存问题。
HaaS100开发调试系列 之 定位AliOS Things内存及Crash问题
|
物联网 Shell Linux
一文轻松入门HaaS100诊断调试系统_AliOS Things 3.3
AliOS Things 自带了调试诊断功能,提供了常见的CLI调试命令(可输入help查看)。
一文轻松入门HaaS100诊断调试系统_AliOS Things 3.3
|
物联网 API 开发工具
如何用SystemView分析AliOS Things
SystemView 是一个用于分析嵌入式系统性能的工具。SystemView可以分析系统中有哪些中断、任务执行了,以及它们的先后关系。 可以完整的深入观察一个应用程序运行时的行为,它揭示了在任务运行中发生了什么,哪个中断触发了任务切换,中断和任务调用了哪个底层系统的API函数。
如何用SystemView分析AliOS Things
|
物联网 API 调度
AliOS Things 新版文档库上线啦
为了更好的服务开发者,提高开发AliOS Things应用的效率,在2021年4月30日AliOS Things 3.3.0版本开源同时,我们推出了近40万字的AliOS Things新版文档库。新版文档库秉承简单、易懂、方便、提效的原则,提供层次清晰的目录结构、丰富详实的说明内容、简单易用的贡献文档接口以及多个访问入口等新特性。
AliOS Things 新版文档库上线啦
|
监控 物联网 测试技术
|
监控 IDE 物联网
结合AliOS Things谈嵌入式系统通用问题定位方法(2):内核相关基础
内核提供的任务创建接口,会存在参数指定当前任务创建完立即运行还是需要显示调用start运行,需要注意。如果在创建任务时指定了立即执行,而在创建任务后去设置任务参数,可能是不生效的。(尤其posix的pthread接口经常遇到这种问题)
结合AliOS Things谈嵌入式系统通用问题定位方法(2):内核相关基础
下一篇
无影云桌面