Strace的介绍与使用

Strace简介

strace命令是一个集诊断、调试、统计于一体的工具,常用来跟踪进程执行时的系统调用和所接收的信号,我们可以用它来监控用户空间进程和内核的交互。如对应用程序的系统调用、信号传递与进程状态变更等进行跟踪与分析,以达到解决问题的目的。
strace常用来跟踪进程执行时的系统调用和接收的信号。 在Linux中,进程不能直接访问硬件设备,当进程需要访问硬件设备(比如,读取磁盘文件,接收网络数据等等)时,必须由用户态模式切换至内核态模式,通过系统调用访问硬件设备。strace可以跟踪到一个进程产生的系统调用,包括参数,返回值,执行消耗的时间。

strace安装

strace已在软件库中,可通过install直接安装。

 sudo apt-get install strace -y

strace使用

在ubuntu下运行 strace -h 命令就可以看到strace命令用法的介绍。

各个参数的含义

-c 统计每一系统调用的所执行的时间,次数和出错的次数等.
-d 输出strace关于标准错误的调试信息.
-f 跟踪由fork调用所产生的子进程.
-ff 如果提供-o filename,则所有进程的跟踪结果输出到相应的filename.pid中,pid是各进程的进程号.
-F 尝试跟踪vfork调用.在-f时,vfork不被跟踪.
-h 输出简要的帮助信息.
-i 输出系统调用的入口指针.
-q 禁止输出关于脱离的消息.
-r 打印出相对时间关于,,每一个系统调用.
-t 在输出中的每一行前加上时间信息.
-tt 在输出中的每一行前加上时间信息,微秒级.
-ttt 微秒级输出,以秒了表示时间.
-T 显示每一调用所耗的时间.
-v 输出所有的系统调用.一些调用关于环境变量,状态,输入输出等调用由于使用频繁,默认不输出.
-V 输出strace的版本信息.
-x 以十六进制形式输出非标准字符串
-xx 所有字符串以十六进制形式输出.

-a column
设置返回值的输出位置.默认 为40.
-e expr
指定一个表达式,用来控制如何跟踪.格式如下:
[qualifier=][!]value1[,value2]...
qualifier只能是 trace,abbrev,verbose,raw,signal,read,write其中之一.value是用来限定的符号或数字.默认的 qualifier是 trace.感叹号是否定符号.例如:
-eopen等价于 -e trace=open,表示只跟踪open调用.而-etrace!=open表示跟踪除了open以外的其他调用.有两个特殊的符号 all 和 none.
注意有些shell使用!来执行历史记录里的命令,所以要使用\\.
-e trace=set
只跟踪指定的系统 调用.例如:-e trace=open,close,rean,write表示只跟踪这四个系统调用.默认的为set=all.
-e trace=file
只跟踪有关文件操作的系统调用.
-e trace=process
只跟踪有关进程控制的系统调用.
-e trace=network
跟踪与网络有关的所有系统调用.
-e strace=signal
跟踪所有与系统信号有关的 系统调用
-e trace=ipc
跟踪所有与进程通讯有关的系统调用
-e abbrev=set
设定 strace输出的系统调用的结果集.-v 等与 abbrev=none.默认为abbrev=all.
-e raw=set
将指 定的系统调用的参数以十六进制显示.
-e signal=set
指定跟踪的系统信号.默认为all.如 signal=!SIGIO(或者signal=!io),表示不跟踪SIGIO信号.
-e read=set
输出从指定文件中读出 的数据.例如:
-e read=3,5
-e write=set
输出写入到指定文件中的数据.
-o filename
将strace的输出写入文件filename
-p pid
跟踪指定的进程pid.
-s strsize
指定输出的字符串的最大长度.默认为32.文件名一直全部输出.
-u username
以username 的UID和GID执行被跟踪的命令

strace的常用参数及示例

-c

统计每一系统调用的所执行的时间,次数和出错的次数等。

示例:打印执行uptime时系统系统调用的时间、次数、出错次数和syscall

# strace -c uptime

-d

显示有关标准错误的strace本身的一些调试输出。

-f

跟踪子进程,这些子进程是由于fork(2)系统调用而由当前跟踪的进程创建的。

-i
在系统调用时打印指令指针。

-t

跟踪的每一行都以时间为前缀。

-tt

如果给出两次,则打印时间将包括微秒。

-ttt

如果给定三次,则打印时间将包括微秒,并且前导部分将打印为自该**以来的秒数。

-T

显示花费在系统调用上的时间。这将记录每个系统调用的开始和结束之间的时间差。

-v

打印环境,统计信息,termios等调用的未缩写版本。这些结构在调用中非常常见,因此默认行为显示了结构成员的合理子集。使用此选项可获取所有详细信息。

-V

打印strace的版本号。

-e expr

限定表达式,用于修改要跟踪的事件或如何跟踪它们:

-e trace=set

仅跟踪指定的系统调用集。该-c选项用于确定哪些系统调用可能是跟踪有用有用。例如,trace=open,close,read,write表示仅跟踪这四个系统调用。

-e trace=file

跟踪所有以文件名作为参数的系统调用。

示例:打印执行ls时跟文件有关的系统调用。

# strace -e trace=file ls

-e trace=process

跟踪涉及过程管理的所有系统调用。这对于观察进程的派生,等待和执行步骤很有用。

-e trace=network

跟踪所有与网络相关的系统调用。

-e trace=signal

跟踪所有与信号相关的系统调用。

-e trace=ipc

跟踪所有与IPC相关的系统调用。

-o 文件名

将跟踪输出写入文件名而不是stderr。

-p pid

使用进程ID pid附加到该进程并开始跟踪。跟踪可以随时通过键盘中断信号(CTRL -C)终止。

-S 

按指定条件对-c选项打印的直方图输出进行排序。

示例:打印执行uname系统调用中calls的次数排序

# strace -fc -S calls uname

注:其他参数可以查看man手册

# man strace

基本用法

如下面的命令中,使用strace跟踪cp命令,看看它在复制文件时做了那些事情。

strace cp ~/.bashrc bashrc

得到如下结果:

execve("/bin/cp", ["cp", "/home/zhongyi/.bashrc", "bashrc"], 0x7ffcc7ed9f60 /* 50 vars */) = 0

strace输出中的每一行都包含:系统调用名称,括号中传递给系统调用的参数,系统调用返回值。

输出中看到的第一个系统调用是execve,该调用用于执行带有指定参数数组的程序。

  • "/bin/cp"表示我们要执行的文件的路径。
  • ["cp", "/home/zhongyi/.bashrc", "bashrc"],表示字符串数组,代表要传递给程序的参数,分别对应程序的名称(cp),源路(/home/zhongyi/.bashrc)和目标路径(bashrc)。
  • 0x7ffcc7ed9f60 /* 50 vars */,表示从调用过程继承了46个变量(在execve函数中,环境变量是从外部environ变量获取的)
  • 复制完成后,execve返回0,代表execve系统调用的返回值。发生错误时,返回非0。

简单一行命令

# 降低目标命令的速度并打印每个系统调用的详细信息:
strace command

# 降低目标 PID 的速度并打印每个系统调用的详细信息:
strace -p PID

# 降低目标 PID 及其任何新创建的子进程的速度,打印系统调用的详细信息:
strace -fp PID

# 降低目标 PID 的速度,记录系统调用,并打印一个总结:
strace -cp PID

#  降低目标 PID 的速度,并只打印 open() 系统调用:
strace -eopen -p PID

# 降低目标 PID 的速度,并只打印 open()  和 stat() 系统调用:
strace -eopen,stat -p PID

# 降低目标 PID 的速度,并只打印 connect()  和 accept() 系统调用:
strace -econnect,accept -p PID

# 降低目标命令的速度并查看它启动了哪些其它程序(也降低它们的速度):
strace -qfeexecve command

# 降低目标 PID 的速度并以(扭曲的)微秒分辨率打印纪元时间:
strace -ttt -p PID

# 降低目标 PID 的速度并以(扭曲的)微秒分辨率打印系统调用的持续时间:
strace -T -p PID

常用过滤表达式

-e <expr> 这个参数可以用来指定需要 trace 哪些事件,格式如下:

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

其中 qualifier 的值是 trace, abbrev, verbose, raw,
signal, read, write, fault, inject, or kvm 。默认是 trace

value 就是各种过滤条件了。
-e trace=<set> : <set> 是系统调用名称(默认是 trace=all ),比如 trace=open,close,read,write
-e trace=/<regex>: 可以通过这种方式来用正则表达式指定系统调用名称,支持的正则语法可以参考 regex(7) 。
-e trace=%file: 文件相关系统调用。
-e trace=%desc: 文件描述符相关。
-e trace=%process: 进程管理相关系统调用。
-e trace=%network: 网络相关。
-e trace=%signal: 信号相关。
-e trace=%ipc: IPC 相关。
-e trace=%memory: 内存 mapping 相关。
-e signal=<set>: <set> 是进程信号的名称(默认是 signal=all ),比如 -e signal=SIGTERM
-e read=<set>: 追踪指定 fd 上的数据并打印 hex 和 ascii 格式的数据, <set> 是 fd 比如:read=3,5
-e trace=read,getpid	只跟踪指定的系统调用
-e trace=!read	不跟踪read系统调用
-e trace=network	跟踪网络相关的系统调用
-e trace=signal	跟踪信号相关的系统调用
-e trace=ipc	跟踪IPC相关的系统调用

Strace实战示例

跟踪特定的系统调用

在使用strace时,有时,我们可能只希望跟踪特定的系统调用。在这种情况下,我们可以使用-e选项后跟一个表达式,该表达式指示应跟踪的系统调用。假设我们运行与上一个示例相同的命令,但是,我们只希望read系统调用显示在输出中。

zhongyi@ubuntu:~$ strace -e read cp ~/.bashrc bashrc
..............省略若干行......
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20b\0\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340\33\0\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260\20\0\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20\35\2\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0 \25\0\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\16\0\0\0\0\0\0"..., 832) = 832
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000b\0\0\0\0\0\0"..., 832) = 832
read(3, "nodev\tsysfs\nnodev\ttmpfs\nnodev\tbd"..., 1024) = 450
read(3, "", 1024)                       = 0
read(3, "# ~/.bashrc: executed by bash(1)"..., 131072) = 3771
read(3, "", 131072)                     = 0
+++ exited with 0 +++

该read系统调用有三个参数:

  • 3,表示文件描述符,与读取的文件相关联。
  • "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\20b\0\0\0\0\0\0"...,表示应读取文件的缓冲区。
  • 832,表示应读取的字节数。

读取成功后,该函数将返回从文件读取的字节数。

跟踪正在执行的程序

strace可以跟踪正在执行的程序。使用方法为 strace -p pid。要找到程序的pid,可以使用pidof命令,例如

strace -p pid of gnome-terminal-server
13075
1
2

将strace的输出保存到文件中

如果在启动strace时使用-o选项(的缩写--ouput),则可以将其输出重定向到文件,例如:

strace -p 13075 -o strace_output
strace: Process 13075 attached

执行命令后,会自动创建一个strace_output文件,并将strace的输出写进文件中。使用tail strace_output 可以查看文件的最后10行的内容。使用tail -f strace_output会在屏幕上实时更新写进文件的内容。

打印系统调用摘要

strace还可以显示指定进程的所有系统调用的摘要信息。例如:

strace -c cp ~/.bashrc bashrc

如图

常见系统调用

系统调用	它做了什么
read	从一个文件描述符(文件,socket)读取字节
write	向一个文件描述符(文件,socket)写入字节
open	打开一个文件(返回一个文件描述符)
close	关闭一个文件描述符
fork	创建一个新进程(当前进程被分叉)
exec	执行一个新程序
connect	连接到一个网络主机
accept	接受一个网络连接
stat	读取文件统计信息
ioctl	设置 I/O 属性,或其它杂项函数
mmap	将一个文件映射到进程内存地址空间
brk	    扩展堆指针
posted on 2022-05-12 22:00  skandbug  阅读(4107)  评论(0编辑  收藏  举报