xiaobaoqiu Blog

Think More, Code Less

Strace

1.strace简介

strace用来跟踪进程执行时的系统调用和所接收的信号.

Linux下进程不能直接访问硬件设备,当进程需要访问硬件设备(比如读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通过系统调用访问硬件设备.strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间.

参数及意义如下,忽略了一些不大重要的(其实海报看一些没看懂的…):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
OPTIONS
       -c         计数,包括每个系统调用耗时,调用次数,错误次数.注意这里显示的时间是CPU花在内核上的时间.
       -D         跟踪程序作为被跟踪程序的子进程.
       -d          输出strace关于标准错误的调试信息
       -f          根据进程,包括其子进程(fork(2), vfork(2) and clone(2)这些系统调用)
       -ff         如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程号.
       -F          尝试跟踪vfork调用
       -h         帮助信息.
       -i          输出系统调用的入口指针
       -q         禁止输出attaching和detaching的信息
       -r          打印出每个系统调用的相对时间(相对于第一个系统调用)
       -t          在输出中的每一行前加上时间信息(时分秒)
       -tt         在输出中的每一行前加上时间信息,包含毫秒
       -ttt        微秒级输出,单位是秒(如1454483650.043891).
       -T          显示每个系统调用使用时间的百分比占比.
       -v          输出所有的系统调用.一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出.
       -V          版本信息
       -x          以十六进制形式输出非标准字符串(non-ASCII strings)
       -xx         所有字符串以十六进制形式输出
       -y          Print paths associated with file descriptor arguments.
       -a column   设置返回值的输出位置,默认为40
       -b syscall  当某个系统调用被调用,trace程序就会detach.当前只支持execve. 这个选项在trace多线程的时候十分有用(需要-f选项)
       -e expr     指定一个表达式,用来控制如何跟踪.表达式格式如下:

                             [qualifier=][!]value1[,value2]...

                   其中qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之,value是用来限定的符号或数字.默认的 qualifier是 trace.感叹号是否定符号.例如:
-eopen等价于 -e trace=open,表示只跟踪open调用.而-etrace!=open表示跟踪除了open以外的其他调用.

       -e trace=set   只跟踪指定的系统调用.例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all.
       -e trace=file   只跟踪有关文件操作的系统调用
       -e trace=process 只跟踪有关进程控制的系统调用.
       -e trace=network 只跟踪与网络有关的所有系统调用.
       -e trace=signal 只跟踪所有与系统信号有关的 系统调用
       -e trace=ipc 只跟踪所有与进程通讯有关的系统调用
       -e trace=desc 只跟踪所有与文件描述符有关的系统调用
       -e trace=memory 只跟踪所有与内存映射有关的系统调用
       -e signal=set 指定跟踪的系统信号.默认为all.如 signal=!SIGIO(或者signal=!io),表示不跟踪SIGIO信号.
       -o filename 将trace结果输出到文件
       -p pid      跟踪指定的进程pid
       -s strsize  指定输出的字符串的最大长度.默认为32.文件名一直全部输出.
       -S sortby   使用了-c选项的情况下的排序准则,可选包括time, calls, name, 和nothing,默认是time
       -u username 以username的UID和GID执行被跟踪的命令.

使用cheat可以看到strace通常使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
xiaobaoqiu@xiaobaoqiu:~$ cheat strace
# 基本使用
strace <command>

# 将trace结构写到文件,使用-o参数
strace -o strace.out <other switches> <command>

# 只trace open()这个系统调用
strace -e trace=open <command>

# trace所有会打开文件的系统调用
strace -e trace=file <command>

# trace所有和进程管理相关的系统调用,再查看一个进程的fork,wait和exec等步骤的时候很有用
strace -e trace=process <command>

# 当前进程fork出来的子进程也trace
strace -f <command>

# 每个系统调用计数,包括:调用时间,调用次数,错误次数
strace -c <command>

# trace某一个进程(可以指定多个pid)
strace -p <pid>

通常而言,我们使用-c选项找出最耗时的系统调用,再使用-e选项跟踪这个操作.

参考: 手把手教你用Strace诊断问题

2.strace使用Demo

一直很好奇top命令的数据从哪里获取的.我这里的前提我知道的一点:top的数据肯定是从proc/pid/下的某个文件中读取的,有这个前提我们就可以来跟踪top命令执行过程中有那些系统调用了,打开了什么文件等.

1
2
3
4
5
6
[baoqiu.xiao@Xxx ~]$ strace -o top.strace -e trace=open top

//找出1381这个进程的信息来源
[baoqiu.xiao@Xxx ~]$ grep 1381 top.strace 
open("/proc/1381/stat", O_RDONLY)       = 4
open("/proc/1381/statm", O_RDONLY)      = 4

从上面的strace中,我们知道,top的信息来源于两个文件,stat和statm.这两个文件的介绍参考上一篇博客: http://xiaobaoqiu.github.io/blog/2016/01/28/who-eat-jvms-memory/.

参考: 8 Options to Trace/Debug Programs using Linux strace Command

火丁笔记 strace