嵌入式软件开发调试问题常用方法级案例分析

1. 常用调试工具介绍

  • 网络问题调试工具:tcpdump
  • 有源码情况下调试:arm-linux-gnueabihf-gdb + arm-linux-gnueabihf-gdbserver
  • 系统调用调试:strace
  • 类任务管理器工具:mpstat,pidstat

2. 逐个工具介绍

2.1 网络问题调试工具:tcpdump

语法:

tcpdump [-adeflnNOpqStvx][-c<数据包数目>][-dd][-ddd][-F<表达文件>][-i<网络界面>][-r<数据包文件>][-s<数据包大小>][-tt][-T<数据包类型>][-vv][-w<数据包文件>][输出数据栏位]

简单的例子:

以下都以抓取eth1这网卡的数据为例:

抓取包含10.10.10.122的数据包

tcpdump -i eth1 -XXXvvvnn host 10.10.10.122

抓取包含10.10.10.0/24网段的数据包

tcpdump -i eth1 -XXXvvvnn net 10.10.10.0/24
tcpdump -i eth1 -XXXvvvnn net 10.10.10.0 mask 255.255.255.0

抓取包含端口22的数据包

tcpdump -i eth1 -XXXvvvnn port 22

抓取udp协议的数据包

tcpdump -i eth1 -XXXvvvnn udp

抓取arp协议的数据包

tcpdump -i eth1 -XXXvvvnn arp

抓取源ip是10.10.10.122的数据包

tcpdump -i eth1 -XXXvvvnn src host 10.10.10.122

抓取目标ip是10.10.10.122的数据包

tcpdump -i eth1 -XXXvvvnn dst host 10.10.10.122

抓取源端口是22的数据包

tcpdump -i eth1 -XXXvvvnn src port 22

抓取源ip是10.10.10.253且目的端口是22的数据包

tcpdump -i eth1 -XXXvvvnn src host 10.10.10.122 and dst port 22

抓取源ip是10.10.10.122或者端口是22的数据包

tcpdump -i eth1 -XXXvvvnn src host 10.10.10.122 or port 22

抓取源ip是10.10.10.122且端口不是22的数据包

tcpdump -i eth1 -XXXvvvnn src host 10.10.10.122 and not port 22

过滤抓取mac地址是某个具体的mac地址、协议类型是arp的数据包

tcpdump -i eth1 ether src host 00:0c:29:2f:a7:50 and arp

具体参数含义:

  • a 尝试将网络和广播地址转换成名称。
  • c<数据包数目> 收到指定的数据包数目后,就停止进行倾倒操作。
  • d 把编译过的数据包编码转换成可阅读的格式,并倾倒到标准输出。
  • dd 把编译过的数据包编码转换成C语言的格式,并倾倒到标准输出。
  • ddd 把编译过的数据包编码转换成十进制数字的格式,并倾倒到标准输出。
  • e 在每列倾倒资料上显示连接层级的文件头。
  • f 用数字显示网际网络地址。
  • F<表达文件> 指定内含表达方式的文件。
  • i<网络界面> 使用指定的网络截面送出数据包。
  • l 使用标准输出列的缓冲区。
  • n 不把主机的网络地址转换成名字。
  • N 不列出域名。
  • O 不将数据包编码最佳化。
  • p 不让网络界面进入混杂模式。
  • q 快速输出,仅列出少数的传输协议信息。
  • r<数据包文件> 从指定的文件读取数据包数据。
  • s<数据包大小> 设置每个数据包的大小。
  • S 用绝对而非相对数值列出TCP关联数。
  • t 在每列倾倒资料上不显示时间戳记。
  • tt 在每列倾倒资料上显示未经格式化的时间戳记。
  • T<数据包类型> 强制将表达方式所指定的数据包转译成设置的数据包类型。
  • v 详细显示指令执行过程。
  • vv 更详细显示指令执行过程。
  • x 用十六进制字码列出数据包资料。
  • w<数据包文件> 把数据包数据写入指定的文件。

2.2 有源码情况下调试:arm-linux-gnueabihf-gdb + arm-linux-gnueabihf-gdbserver

具体分析文章详见: 基于VSCode的嵌入式开发的Windows平台可视化代码调试方法

2.3 系统调用调试:strace

strace作用介绍

strace是用来跟踪用户空间进程的系统调用和信号的,在进入strace使用的主题之前,我们的先理解什么是系统调用。

关于系统调用:

按*中的解释,在计算机中,系统调用(英语:system call),又称为系统呼叫,指运行在用户空间的程序向操作系统内核请求需要更高权限运行的服务。

系统调用提供用户程序与操作系统之间的接口。操作系统的进程空间分为用户空间和内核空间:

操作系统内核直接运行在硬件上,提供设备管理、内存管理、任务调度等功能。

用户空间通过API请求内核空间的服务来完成其功能——内核提供给用户空间的这些API, 就是系统调用。

strace的使用模式

我们回到strace的使用上来。strace有两种运行模式

通过strace启动程序

一种是通过它启动要跟踪的进程。用法很简单,在原本的命令前加上strace即可。比如我们要跟踪 “ls -lh /var/log/messages” 这个命令的执行,可以这样:

strace ls -lh /var/log/messages

通过strace连接到正在运行的程序(更加常用的场景)

另外一种运行模式,是跟踪已经在运行的进程,在不中断进程执行的情况下,理解它在干嘛。 这种情况,给strace传递个-p pid 选项即可。

strace -p 17553

完成跟踪时,按ctrl + C 结束strace即可。

strace有一些选项可以调整其行为,我们这里介绍下其中几个比较常用的,然后通过示例讲解其实际应用效果。

strace的常用选项

strace常用选项:

从一个示例命令来看:

strace -tt -T -v -f -e trace=file -o /data/log/strace.log -s 1024 -p 23489
  • tt 在每行输出的前面,显示毫秒级别的时间
  • T 显示每次系统调用所花费的时间
  • v 对于某些相关调用,把完整的环境变量,文件stat结构等打出来。
  • f 跟踪目标进程,以及目标进程创建的所有子进程
  • e 控制要跟踪的事件和跟踪行为,比如指定要跟踪的系统调用名称
  • o 把strace的输出单独写到指定的文件
  • s 当系统调用的某个参数是字符串时,最多输出指定长度的内容,默认是32个字节
  • p 指定要跟踪的进程pid, 要同时跟踪多个pid, 重复多次-p选项即可。

strace用来分析系统调用占用统计

strace还可以用来统计某段时间内系统调用的占用时间统计,使用strace的c选项,然后统计一段时间后ctrl + C退出后即可观察结果,这里给个例子:

 ./strace -cp 631
./strace: Process 631 attached
^C./strace: Process 631 detached
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 88.52    8.640000         691     12489       408 futex
  4.41    0.430000         153      2802           gettimeofday
  4.10    0.400000         214      1862           ioctl
  0.92    0.090000         391       230           epoll_wait
  0.92    0.090000         105       855           clock_gettime
  0.82    0.080000         200       399       354 write
  0.20    0.020000          51       385           timerfd_settime
  0.10    0.010000         222        45           shmat
  0.00    0.000000           0        46           read
  0.00    0.000000           0        46           epoll_ctl
  0.00    0.000000           0        45           shmdt
------ ----------- ----------- --------- --------- ----------------
100.00    9.760000         508     19204       762 total

2.4 类任务管理器工具:pidstat,mpstat

pidstat

pidstat是sysstat工具的一个命令,用于监控全部或指定进程的cpu、内存、线程、设备IO等系统资源的占用情况。pidstat首次运行时显示自系统启动开始的各项统计信息,之后运行pidstat将显示自上次运行该命令以后的统计信息。用户可以通过指定统计的次数和时间来获得所需的统计信息。

使用案例

pidstat [ 选项 ] [ <时间间隔> ] [ <次数> ]
  • u:默认的参数,显示各个进程的cpu使用统计
  • r:显示各个进程的内存使用统计
  • d:显示各个进程的IO使用情况
  • p:指定进程号
  • w:显示每个进程的上下文切换情况
  • t:显示选择任务的线程的统计信息外的额外信息
  • T { TASK | CHILD | ALL }
    这个选项指定了pidstat监控的。TASK表示报告独立的task,CHILD关键字表示报告进程下所有线程统计信息。ALL表示报告独立的task和task下面的所有线程。
    注意:task和子线程的全局的统计信息和pidstat选项无关。这些统计信息不会对应到当前的统计间隔,这些统计信息只有在子线程kill或者完成的时候才会被收集。
  • V:版本号
  • h:在一行上显示了所有活动,这样其他程序可以容易解析。
  • I:在SMP环境,表示任务的CPU使用率/内核数量
  • l:显示命令名和所有参数

举个栗子:


./pidstat -p 631 -rduwt -T ALL
Linux 2.6.39 (TSC)      02/02/21        _armv5tejl_     (1 CPU)

03:27:13      UID      TGID       TID    %usr %system  %guest   %wait    %CPU   CPU  Command
03:27:13        0       631         -    1.80    4.76    0.00    0.00    6.55     0  XXXXXXXX
03:27:13        0         -       631    0.38    1.13    0.00    0.00    1.51     0  |__XXXXXXXX
03:27:13        0         -       635    0.40    0.99    0.00    0.00    1.39     0  |__XXXXXXXX
03:27:13        0         -       636    0.38    1.01    0.00    0.00    1.40     0  |__XXXXXXXX
03:27:13        0         -       637    0.38    1.03    0.00    0.00    1.41     0  |__XXXXXXXX
03:27:13        0         -       638    0.00    0.00    0.00    0.00    0.00     0  |__XXXXXXXX
03:27:13        0         -       639    0.09    0.30    0.00    0.00    0.39     0  |__XXXXXXXX
03:27:13        0         -       640    0.00    0.00    0.00    0.00    0.00     0  |__XXXXXXXX
03:27:13        0         -       641    0.04    0.16    0.00    0.00    0.20     0  |__XXXXXXXX
03:27:13        0         -       642    0.12    0.13    0.00    0.00    0.25     0  |__XXXXXXXX
03:27:13        0         -       677    0.00    0.00    0.00    0.00    0.00     0  |__XXXXXXXX

03:27:13      UID      TGID       TID    usr-ms system-ms  guest-ms  Command
03:27:13        0       631         -     58930    155930         0  XXXXXXXX
03:27:13        0         -       631     12520     36910         0  |__XXXXXXXX
03:27:13        0         -       635     13150     32400         0  |__XXXXXXXX
03:27:13        0         -       636     12600     33260         0  |__XXXXXXXX
03:27:13        0         -       637     12520     33850         0  |__XXXXXXXX
03:27:13        0         -       638         0        90         0  |__XXXXXXXX
03:27:13        0         -       639      2790      9900         0  |__XXXXXXXX
03:27:13        0         -       640         0         0         0  |__XXXXXXXX
03:27:13        0         -       641      1250      5390         0  |__XXXXXXXX
03:27:13        0         -       642      4070      4140         0  |__XXXXXXXX
03:27:13        0         -       677        20         0         0  |__XXXXXXXX

03:27:13      UID      TGID       TID  minflt/s  majflt/s     VSZ     RSS   %MEM  Command
03:27:13        0       631         -      1.30      0.00   79944    3636   2.92  XXXXXXXX
03:27:13        0         -       631      0.53      0.00   79944    3636   2.92  |__XXXXXXXX
03:27:13        0         -       635      0.26      0.00   79944    3636   2.92  |__XXXXXXXX
03:27:13        0         -       636      0.24      0.00   79944    3636   2.92  |__XXXXXXXX
03:27:13        0         -       637      0.24      0.00   79944    3636   2.92  |__XXXXXXXX
03:27:13        0         -       638      0.00      0.00   79944    3636   2.92  |__XXXXXXXX
03:27:13        0         -       639      0.01      0.00   79944    3636   2.92  |__XXXXXXXX
03:27:13        0         -       640      0.00      0.00   79944    3636   2.92  |__XXXXXXXX
03:27:13        0         -       641      0.00      0.00   79944    3636   2.92  |__XXXXXXXX
03:27:13        0         -       642      0.01      0.00   79944    3636   2.92  |__XXXXXXXX
03:27:13        0         -       677      0.00      0.00   79944    3636   2.92  |__XXXXXXXX

03:27:13      UID      TGID       TID minflt-nr majflt-nr  Command
03:27:13        0       631         -      4266        14  XXXXXXXX
03:27:13        0         -       631      1740         9  |__XXXXXXXX
03:27:13        0         -       635       865         0  |__XXXXXXXX
03:27:13        0         -       636       779         0  |__XXXXXXXX
03:27:13        0         -       637       800         1  |__XXXXXXXX
03:27:13        0         -       638         6         0  |__XXXXXXXX
03:27:13        0         -       639        42         2  |__XXXXXXXX
03:27:13        0         -       640         2         0  |__XXXXXXXX
03:27:13        0         -       641        14         2  |__XXXXXXXX
03:27:13        0         -       642        18         0  |__XXXXXXXX
03:27:13        0         -       677         0         0  |__XXXXXXXX

03:27:13      UID      TGID       TID   kB_rd/s   kB_wr/s kB_ccwr/s iodelay  Command
03:27:13        0       631         -     -1.00     -1.00     -1.00       0  XXXXXXXX
03:27:13        0         -       631     -1.00     -1.00     -1.00       0  |__XXXXXXXX
03:27:13        0         -       635     -1.00     -1.00     -1.00       0  |__XXXXXXXX
03:27:13        0         -       636     -1.00     -1.00     -1.00       0  |__XXXXXXXX
03:27:13        0         -       637     -1.00     -1.00     -1.00       0  |__XXXXXXXX
03:27:13        0         -       638     -1.00     -1.00     -1.00       0  |__XXXXXXXX
03:27:13        0         -       639     -1.00     -1.00     -1.00       0  |__XXXXXXXX
03:27:13        0         -       640     -1.00     -1.00     -1.00       0  |__XXXXXXXX
03:27:13        0         -       641     -1.00     -1.00     -1.00       0  |__XXXXXXXX
03:27:13        0         -       642     -1.00     -1.00     -1.00       0  |__XXXXXXXX
03:27:13        0         -       677     -1.00     -1.00     -1.00       0  |__XXXXXXXX

03:27:13      UID      TGID       TID   cswch/s nvcswch/s  Command
03:27:13        0       631         -     71.49      1.67  XXXXXXXX
03:27:13        0         -       631     71.49      1.67  |__XXXXXXXX
03:27:13        0         -       635     60.30      1.69  |__XXXXXXXX
03:27:13        0         -       636     60.13      1.64  |__XXXXXXXX
03:27:13        0         -       637     60.82      1.67  |__XXXXXXXX
03:27:13        0         -       638      0.07      0.00  |__XXXXXXXX
03:27:13        0         -       639      4.45      0.58  |__XXXXXXXX
03:27:13        0         -       640      0.00      0.00  |__XXXXXXXX
03:27:13        0         -       641     23.33      0.19  |__XXXXXXXX
03:27:13        0         -       642      2.43      1.68  |__XXXXXXXX
03:27:13        0         -       677      0.50      0.00  |__XXXXXXXX


注意: 此命令中可以详细的观察到每个线程的状态,对于异常线程,配合gdbserver可以达到快速定位的效果。

mpstat

这个命令啥特殊用法,就是个高级版本的top,第一个参数表示间隔多少秒记录一次,第二个参数是记录多少次。

./mpstat 1 10
Linux 2.6.39 (TSC)      02/02/21        _armv5tejl_     (1 CPU)

03:35:13     CPU    %usr   %nice    %sys %iowait    %irq   %soft  %steal  %guest  %gnice   %idle
03:35:14     all    6.00    0.00   11.00    0.00    0.00   22.00    0.00    0.00    0.00   61.00
03:35:15     all    4.00    0.00    9.00    0.00    0.00   21.00    0.00    0.00    0.00   66.00
03:35:16     all    1.00    0.00   13.00    0.00    0.00   18.00    0.00    0.00    0.00   68.00
03:35:17     all    5.00    0.00    9.00    0.00    0.00   26.00    0.00    0.00    0.00   60.00
03:35:18     all    6.00    0.00    3.00    0.00    0.00   27.00    0.00    0.00    0.00   64.00
03:35:19     all    6.00    0.00    2.00    0.00    0.00   26.00    0.00    0.00    0.00   66.00
03:35:20     all    6.00    0.00    5.00    0.00    0.00   28.00    0.00    0.00    0.00   61.00
03:35:21     all    5.00    0.00   10.00    0.00    0.00   21.00    0.00    0.00    0.00   64.00
03:35:22     all    7.00    0.00    6.00    0.00    0.00   20.00    0.00    0.00    0.00   67.00
03:35:23     all    5.00    0.00   12.00    0.00    0.00   22.00    0.00    0.00    0.00   61.00
Average:     all    5.10    0.00    8.00    0.00    0.00   23.10    0.00    0.00    0.00   63.80

  • %user 在internal时间段里,用户态的CPU时间(%),不包含nice值为负进程 (usr/total)*100
  • %nice 在internal时间段里,nice值为负进程的CPU时间(%) (nice/total)*100
  • %sys 在internal时间段里,内核时间(%) (system/total)*100
  • %iowait 在internal时间段里,硬盘IO等待时间(%) (iowait/total)*100
  • %irq 在internal时间段里,硬中断时间(%) (irq/total)*100
  • %soft 在internal时间段里,软中断时间(%) (softirq/total)*100
  • %idle 在internal时间段里,CPU除去等待磁盘IO操作外的因为任何原因而空闲的时间闲置时间(%) (idle/total)*100
上一篇:Greedy Gift Takers


下一篇:CodeForces - 76A:Gift (最小生成树 解决单调性问题是思想)