嵌入式软件开发调试问题常用方法级案例分析
作者:互联网
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
标签:__,03,13,27,XXXXXXXX,0.00,案例,嵌入式软件,调试 来源: https://blog.csdn.net/aiyanzielf/article/details/113505006