linux调试工具strace,gdb
strace 用于跟踪系统调用和信号。
strace 是一个集诊断、调试、统计于一体的工具,我们可以使用 strace 跟踪程序的系统调用和信号传递分析程序,以解决问题或了解程序工作过程。当然 strace 与专业的调试工具比如说 gdb 之类的是没法相比的,因为它不是一个专业的调试器。
strace 最简单的用法是执行一个指定的命令,命令结束之后它也就退出了。在命令执行的过程中,strace 会记录和解析进程所有的系统调用以及接收到的信号值。
strace怎么用?
既然strace是用来跟踪用户空间进程的系统调用和信号的,在进入strace使用的主题之前,我们的先理解什么是系统调用。
关于系统调用:
按维基百科中的解释,在计算机中,系统调用(英语:system call),又称为系统呼叫,指运行在用户空间的程序向操作系统内核请求需要更高权限运行的服务。
系统调用提供用户程序与操作系统之间的接口。操作系统的进程空间分为用户空间和内核空间:
- 操作系统内核直接运行在硬件上,提供设备管理、内存管理、任务调度等功能。
- 用户空间通过API请求内核空间的服务来完成其功能——内核提供给用户空间的这些API, 就是系统调用。
在Linux系统上,应用代码通过glibc库封装的函数,间接使用系统调用。
Linux内核目前有300多个系统调用,详细的列表可以通过syscalls手册页查看。这些系统调用主要分为几类:
1
2
3
4
5
6
7
|
文件和设备访问类 比如open/close/read/write/chmod等
进程管理类 fork/clone/execve/exit/getpid等
信号类 signal/sigaction/kill 等
内存管理 brk/mmap/mlock等
进程间通信IPC shmget/semget * 信号量,共享内存,消息队列等
网络通信 socket/connect/sendto/sendmsg 等
其他
|
熟悉Linux系统调用/系统编程,能够让我们在使用strace时得心应手。不过,对于运维的问题定位来说,知道strace这个工具,会查系统调用手册,就差不多够了。
想要深入了解的同学,建议阅读《Linux系统编程》, 《Unix环境高级编程》等书籍。
我们回到strace的使用上来。strace有两种运行模式。
一种是通过它启动要跟踪的进程。用法很简单,在原本的命令前加上strace即可。比如我们要跟踪 "ls -lh /var/log/messages" 这个命令的执行,可以这样:
1
|
strace ls -lh /var/log/messages
|
另外一种运行模式,是跟踪已经在运行的进程,在不中断进程执行的情况下,理解它在干嘛。 这种情况,给strace传递个-p pid 选项即可。
比如,有个在运行的some_server服务,第一步,查看pid:
1
2
|
pidof some_server
17553
|
得到其pid 17553然后就可以用strace跟踪其执行:
1
|
strace -p 17553
|
完成跟踪时,按ctrl + C 结束strace即可。
strace有一些选项可以调整其行为,我们这里介绍下其中几个比较常用的,然后通过示例讲解其实际应用效果。
strace常用选项:
从一个示例命令来看:
1
|
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选项即可。
通过 gcc 编译,默认生成名为 a.out 的可执行程序。
gcc main.c
(1)追踪系统调用。
strace -o strace.out ./a.out
输入 4 然后回车生成 strace 的输出文件 strace.out,
GDB
gcc -g -o hello hello.c
gdb hello
带参数
(gdb) set args a b c
gdb调试命令(最常用的)
run : 程序第一次执行,到第一个断点位置暂停。如果没有断点,则一直执行程序直至完成
run 后面可以加上参数,作为主函数main的参数
run 可简写为 r
start : 进入逐行调试模式, 不会一次性执行完整个程序
step : 一次执行一行语句, 遇到函数调用将进入函数
step 可简写为 s
next : 一次执行一行语句,但遇到函数调用不进入
next 可简写为 n
return 或 finish : 单步进入函数后,直接跳出函数
bt : 查看堆栈信息, 可以查看到段错误发生的行号
list : 查看当前行附近的所有代码(默认显示10行)
list 5, 10 : 显示当前文件 5 到 10 行的内容
list test.c : 5, 10 : 显示test.c文件的 5 到 10 行的内容
list main : 显示main函数周围的代码
list test.c function : 显示test.c文件中函数function周围代码
list 可简写为 l
break : 设置断点
break main : 可以给一个函数设置断点
break 12 : 可以为当前文件的某一行设置断点
break test.c 12 : 给源文件test.c 的第12行设置断点
break 可简写为 b
info breakPoint : 查看所有断点信息(断点位置,断点编号...)
可简写为 i b
delete : 删除断点
delete 4 : 删除断点号为4的断点
delete : 即不指定断点编号,则删除所有断点
delete 可简写为 d
continue : 继续执行运行程序,到下一个断点暂停 或 watch 变量对象变量改变时暂停
continue 可简写为 c
print : 查看某个变量的内容
print a : 输出变量a的值
print 可简写为 p
watch : 监控一个变量,当变量发生改变时,程序会停止
watch a : 监控变量a,如果a的值发生了改变,则程序暂停
后台进程调试:
将指定进程链接进入gdb调试:
gdb -p + PID : 可以进入正在运行的后台程序的调试模式
pID 指的是进程的ID
attach + PID : 在gdb内部命令环境进入一个后台进程的调试模式
解除当前链接进gdb的进程:
detach
多线程调试:
info thread : 查看所有线程信息(线程编号... 其中标识*指的是当前调试的线程)
thread + 线程编号 : 可以切换调试线程
shell
Shell本身提供一些调试方法选项:
基本写法: sh [-nxv] 脚本名字
参数:
-n,读一遍脚本中的命令但不执行,用于检查脚本中的语法错误。
-v,一边执行脚本,一边将执行过的脚本命令打印到标准输出。
-x,提供跟踪执行信息,将执行的每一条命令和结果依次打印出来。
tcpdump:网络数据采集分析工具
tcpdump使用
tcpdump的参数介绍
-a 将网络地址和广播地址转变成名字
-d 将匹配信息包的代码以人们能够理解的汇编格式给出
-dd 将匹配信息包的代码以c语言程序段的格式给出
-ddd 将匹配信息包的代码以十进制的形式给出
-D 显示所有可用网络接口的列表
-e 在输出行打印出数据链路层的头部信息
-f 将外部的Internet地址以数字的形式打印出来
-l 使标准输出变为缓冲行形式
-L 列出指定网络接口所支持的数据链路层的类型后退出
-n 不把网络地址转换成名字,即不做反向域名解析
-q 简洁地打印输出。即打印很少的协议相关信息, 从而输出行都比较简短
-t 在每行的输出中不输出时间
-tt 在每行的输出中会输出时间戳
-ttt 输出每两行打印的时间间隔(以毫秒为单位)
-tttt 在每行打印的时间戳之前添加日期的打印(此种选项,输出的时间最直观)
-v 产生详细的输出. 比如包的TTL,id标识,数据包长度,以及IP包的一些选项。同时它还会打开一些附加的包完整性检测,比如对IP或ICMP包头部的校验和。
-vv 产生比-v更详细的输出. 比如NFS回应包中的附加域将会被打印, SMB数据包也会被完全解码。
-vvv 产生比-vv更详细的输出。比如 telent 时所使用的SB, SE 选项将会被打印, 如果telnet同时使用的是图形界面,其相应的图形选项将会以16进制的方式打印出来
-c 在收到指定的包的数目后,tcpdump就会停止
-F 从指定的文件中读取表达式,忽略其它的表达式
-i 指定监听的网络接口
-r 从指定的文件中读取包(这些包一般通过-w选项产生)
-w 直接将数据报写入文件中,并不分析和打印出来
-T 将监听到的包直接解释为指定的类型的报文,常见的类型有rpc (远程过程调用)和snmp(简单 网络管理协议)
-s tcpdump 默认只会截取前 `96` 字节的内容,要想截取所有的报文内容,可以使用 `-s number`, `number` 就是你要截取的报文字节数,如果是 0 的话,表示截取报文全部内容。
-S seq ack 使用绝对序列号,而不是相对序列号
-Z 后接用户名,在抓包时会受到权限的限制。如果以root用户启动tcpdump,tcpdump将会有超级用户权限
常用命令
tcpdump -i eth0 #捕获指定接口(网卡)的数据包 可通过 netstat -i查看网卡设备
tcpdump -i eth0 -c 3 #捕获指定个数的数据包(3个数据包)
tcpdump -A -i eth0 #用ASCII码格式输出捕获的数据包
tcpdump -D #显示可用的系统接口
tcpdump -XX -i eth0 #用十六进制和ASCII码格式显示捕获的数据包
tcpdump -w tempDump.pcap -i eth0 #把捕获的数据包写入到一个.pcap后缀的文件中
tcpdump -r tempDump.pcap #读取捕获数据包文件的内容
tcpdump -n -i eth0 # 单个 n 表示不解析域名,直接显示 IP
tcpdump -i eth0 tcp #捕获TCP类型的数据包
tcpdump -i eth0 port 22 #捕获指定端口(这里是22)的数据包
tcpdump -i eth0 src 源ip地址 #捕获请求源是 192.169.12.101 的数据包
tcpdump -i eth0 dst 目标ip地址 #捕获指定目的IP的数据包
tcpdump -i eth6 dst host 目标ip地址 and port 8800 -w data.pcap #抓取指定网卡,指定IP和端口的数据包 并写入到data.pcap文件中
tcpdump host 192.168.12.101 and 192.168.1.201 -w out & #后台抓取两主机之间的数据
tcpdump -nn 单个 n 表示不解析域名,直接显示 IP;两个 n 表示不解析域名和端口。这样不仅方便查看 IP 和端口号,而且在抓取大量数据时非常高效,因为域名解析会降低抓取速度
netstat工具简介和使用
netstat是一个监控TCP/IP网络的非常有用的工具,它可以显示路由表、网络连接以及每一个网络接口设备的状态信息。netstat用于显示与IP、TCP、UDP和ICMP协议相关的统计数据,一般用于检验本机各端口的网络连接情况。
- 参数解释
-a: (all) 显示所有活动中的网络连接和机器正在监听的 TCP/UDP 端口
-r: (route): 显示路由表
-n: 以数字方式显示,禁用反向域名解析,加快查询速度
(默认是不带-n参数的,如果带了-n 输出将会很快,但是只有数字类型的ip,域名是没法看到的,如果不带-n将会看到域名(如有域名的话))
-t: (tcp) 显示tcp连接
-u: (udp) 显示udp连接
-l: (Listen) 只显示监听状态的套接字
-p: 输出中显示 PID 和进程名称
-s: 显示所有端口的统计信息
-i: 查看网卡接口信息
- 输出列名解释
Proto:显示连接使用的协议。
Recv-Q:发送队列
Send-Q:接收队列
Local Address:本地地址:端口。
Foreign Address:外部地址:端口。
state:显示套接口当前的状态。
- 常用命令
netstat -at #查看当前已经建立的tcp连接
netstat -au #列出所有 udp 端口
netstat -lt #只列出所有监听中的 tcp类型的 端口
netstat -lu #只列出所有监听中的 udp类型的端口
netstat -antp #查看所有已经建立的tcp连接,并且域名以数字形式显示
netstat -tupl #查看所有监听的tcp和udp及进程名信息(udp不能监听,但可以查看是否在占用)
netstat -s #显示所有端口的统计信息
netstat -st 或 -su #显示 TCP 或 UDP 端口的统计信息
netstat -i #查看网卡接口信息
netstat -tulnp |grep nginx #查看nginx服务的网络信息
参考:https://www.cnblogs.com/liulianzhen99/articles/17883421.html