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

相关文章
|
IDE 数据可视化 Java
5款经典代码阅读器的使用方案对比
代码阅读是技术人的必备技能之一,高效地梳理代码能够极大程度上提高开发人员的工作效率,进一步为业务创造新价值。
16049 0
5款经典代码阅读器的使用方案对比
|
10月前
|
负载均衡 测试技术 调度
大模型分布式推理:张量并行与流水线并行技术
本文深入探讨大语言模型分布式推理的核心技术——张量并行与流水线并行。通过分析单GPU内存限制下的模型部署挑战,详细解析张量并行的矩阵分片策略、流水线并行的阶段划分机制,以及二者的混合并行架构。文章包含完整的分布式推理框架实现、通信优化策略和性能调优指南,为千亿参数大模型的分布式部署提供全面解决方案。
2745 4
阿里云百炼Coding Plan页面显示售罄,抢不到怎么办?附上攻略
阿里云百炼Coding Plan因需求火爆常显示“售罄”,官方实行每日9:30限量补货。抢购建议:提前5分钟蹲守,优先选择库存更充足的200元/月Pro版;Lite版竞争激烈,易秒光。工作日成功率更高。(239字)
|
存储 资源调度 Java
计算机基础(1)——计算机体系结构和组成
计算机(computer)俗称电脑,是现代一种用于高速计算的电子计算机器,可以进行数值计算,又可以进行逻辑计算,还具有存储记忆功能。是能够按照程序运行,自动、高速处理海量数据的现代化智能电子设备。 在过去的几十年里,计算机科学经历了令人瞩目的飞速发展。经历了电子管、晶体管、集成电路的世代发展,体积越来越小、性能越来越强,为人类带来了巨大的便利和变革,下面我们来回顾计算机的发展历程。
3972 5
计算机基础(1)——计算机体系结构和组成
|
Oracle 关系型数据库 Linux
MyEMS开源系统安装之CentOS/RHEL/Rocky/AlmaLinux/Oracle Linux
本指南介绍如何在CentOS/RHEL/Rocky/AlmaLinux/Oracle Linux服务器上部署MyEMS开源能源管理系统。内容涵盖系统准备、数据库配置、多个MyEMS服务(如myems-api、myems-admin、myems-modbus-tcp等)的安装与配置,以及Nginx服务器设置和防火墙规则调整。通过完成所有步骤,您将能够访问MyEMS Admin UI和Web UI,默认端口分别为8001和80,初始登录凭据已提供。
924 0
|
网络协议 算法 中间件
【总结】单片机重点知识总结记录之CMSIS详解(六)
【总结】单片机重点知识总结记录之CMSIS详解(六)
2123 0
|
机器学习/深度学习 人工智能 监控
视觉目标跟踪漫谈:从原理到应用
视觉目标跟踪 (visual object tracking) 是计算机视觉 (computer vision) 领域的一个重要研究问题。通常来说,视觉目标跟踪是在一个视频的后续帧中找到在当前帧中定义的感兴趣物体 (object of interest) 的过程,主要应用于一些需要目标空间位置以及外观(形状、颜色等)特性的视觉应用中。本文旨在对跟踪做一个尽量全面、细致和具有时效性的综述,研究跟踪的定义、应用、架构、算法以及评估等方面的内容。联合作者:图希,恬宁,崇北,昆虚,明烁。 文末福利:免费下载《15分钟开发视觉AI应用》电子书。
8853 0
视觉目标跟踪漫谈:从原理到应用
|
架构师 算法 测试技术
嵌入式系统软件架构设计(长篇深度好文)
嵌入式系统软件架构设计(长篇深度好文)
9505 3
|
数据可视化 测试技术 持续交付
Git Flow规范在工作中的使用流程
Git Flow规范在工作中的使用流程
686 0

热门文章

最新文章