简介

strace(System Trace)是Linux系统中一个功能强大的调试工具,用于跟踪用户空间进程对系统调用的执行情况。它可以记录每个系统调用的入口和退出参数、返回值以及耗费的时间,帮助程序员和运维人员分析程序行为、排查性能问题和调试程序故障。

工作原理

strace通过ptrace系统调用来实现对进程的跟踪。ptrace允许一个进程(称为跟踪者)附加到另一个进程(称为被跟踪者),并监视其执行行为。strace使用ptrace来捕获被跟踪进程的系统调用,并将相关信息记录到日志文件中。

常用选项

选项

说明

-c

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

-d

输出strace关于标准错误的调试信息。

-e expr

只跟踪与expr匹配的系统调用。expr可以是系统调用的名称或数字ID。

-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。

运维案例

案例一:分析程序性能瓶颈

使用strace可以分析程序执行过程中每个系统调用的耗时,从而识别性能瓶颈。例如,以下命令可以跟踪ls命令的系统调用,并统计每个系统调用的执行时间:

strace -c ls
  • 1.

输出结果类似如下:

...
= 0 <read> (10, 1024)  = 1024
= 0 <read> (10, 1024)  = 1024
= 0 <read> (10, 1024)  = 1024
= 0 <read> (10, 1024)  = 1024
= 0 <read> (10, 1024)  = 1024
= 0 <read> (10, 1024)  = 1024
= 0 <read> (10, 1024)  = 1024
= 0 <read> (10, 1024)  = 1024
= 0 <read> (10, 1024)  = 1024
= 0 <read> (10, 1024)  = 1024
--- strace: Process 12345 finished ---
10013 calls in 0.047605 (47.600µs) real time
10013 syscalls in 0.047501 (47.501µs) user time
0.000000 (0.000µs) child user time
0.000000 (0.000µs) child user time
0.000000 (0.000µs) sibling user time
0.000000 (0.000µs) sibling user time
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

从上面的输出结果中,我们可以看到,read系统调用是ls命令执行过程中耗时最多的系统调用。这可能是因为文件系统比较繁忙,导致read系统调用需要等待较长时间。

为了进一步分析性能瓶颈,我们可以使用以下命令来跟踪ls命令的每个文件读取操作:

strace -e trace=read -c ls
  • 1.

输出结果类似如下:

...
= 0 <read> (5, 4096) = 4096
= 0 <read> (5, 4096) = 4096
= 0 <read> (5, 4096) = 4096
= 0 <read> (5, 4096) = 4096
= 0 <read> (5, 4096) = 4096
= 0 <read> (5, 4096) = 4096
= 0 <read> (5, 4096) = 4096
= 0 <read> (5, 4096) = 4096
= 0 <read> (5, 4096) = 4096
= 0 <read> (5, 4096) = 4096
--- strace: Process 12345 finished ---
10013 calls in 0.047605 (47.600µs) real time
10013 syscalls in 0.047501 (47.501µs) user time
0.000000 (0.000µs) child user time
0.000000 (0.000µs) child user time
0.000000 (0.000µs) sibling user time
0.000000 (0.000µs) sibling user time
0.000000 (0.000µs) voluntary context switches
0.000000 (0.000µs) involuntary context switches
--- strace: Process 12345 finished ---
10013 calls in 0.047605 (47.600µs) real time
10013 syscalls in 0.047501 (47.501µs) user time
0.000000 (0.000µs) child user time
0.000000 (0.000µs) child user time
0.000000 (0.000µs) sibling user time
0.000000 (0.000µs) sibling user time
0.000000 (0.000µs) voluntary context switches
0.000000 (0.000µs) involuntary context switches
  • 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.

从上面的输出结果中,我们可以看到,每个文件读取操作的耗时都比较接近。这说明,ls命令的性能瓶颈主要体现在文件系统I/O上。

为了进一步优化ls命令的性能,我们可以尝试以下方法:

  • 使用更快的文件系统,例如SSD。
  • 调整文件系统的缓存设置。
  • 减少文件系统的碎片化。

案例二:排查程序故障

strace可以帮助程序员排查程序故障,例如识别程序崩溃或错误的原因。例如,以下命令可以跟踪./myprogram程序的系统调用,并输出详细的调试信息:

strace -d ./myprogram
  • 1.

输出结果类似如下:

...
strace: Setting thread 1 to 0x1fff0000
strace: Attaching to process 12345
= 0 <open> ("/etc/passwd", O_RDONLY)  = 3
= 0 <read> (3, 1024)   = 1024
= 0 <read> (3, 1024)   = 813
= 0 <read> (3, 1024)   = 1024
= 0 <read> (3, 1024)   = 1024
= 0 <read> (3, 1024)   = 1024
= 0 <close> (3)      = 0
= 0 <open> ("/etc/group", O_RDONLY)  = 4
= 0 <read> (4, 1024)   = 1024
= 0 <read> (4, 1024)   = 1024
= 0 <close> (4)      = 0
= 0 <exit_group> (-1) = ?
strace: Process 12345 detached with status -1
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

从上面的输出结果中可以看到,程序在打开/etc/group文件时发生了错误(返回值为-1)。这可能是由于文件不存在或权限不足导致的。程序员可以根据这些信息进一步排查故障。

以下是一些具体的排查步骤:

  1. 检查/etc/group文件是否存在。如果不存在,则需要创建该文件。
  2. 检查/etc/group文件的权限。如果权限不足,则需要修改权限。
  3. 如果/etc/group文件存在且权限正确,则需要检查程序代码是否正确。

案例三:分析系统安全问题

strace还可以用于分析系统安全问题,例如识别可疑的系统调用或文件操作。例如,以下命令可以跟踪所有由用户root执行的系统调用:

strace -u root
  • 1.

输出结果类似如下:

...
= 0 <open> ("/etc/shadow", O_RDONLY)  = 3
= 0 <read> (3, 1024)   = 1024
= 0 <close> (3)      = 0
= 0 <open> ("/etc/passwd", O_RDONLY)  = 3
= 0 <read> (3, 1024)   = 1024
= 0 <close> (3)      = 0
= 0 <open> ("/var/log/syslog", O_WRONLY | O_APPEND | O_CREAT, 0664) = 4
= 0 <write> (4, "2024-07-04 16:22:19 UTC: root: LOGIN (ROOT) ON tty1\n", 56) = 56
= 0 <close> (4)      = 0
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

从上面的输出结果中,我们可以看到,用户root打开并读取了/etc/shadow/etc/passwd文件,并向/var/log/syslog文件中写入了一条日志记录。如果这些操作是异常的,则可能表明系统存在安全风险。

以下是一些具体的分析步骤:

  1. 检查/etc/shadow/etc/passwd文件的修改时间。如果修改时间异常,则需要进一步调查。
  2. 检查/var/log/syslog文件中的日志记录。如果发现可疑的日志记录,则需要进一步调查。
  3. 使用其他安全工具来扫描系统,例如auditdossec

总结

strace是一个功能强大的调试工具,可以用于分析程序行为、排查性能问题和调试程序故障。它也是一个有效的安全工具,可以用于分析系统安全问题。运维人员和程序员可以根据自己的需求选择不同的strace使用方法,以解决各种问题。

注意:

  • strace可能会对程序的性能造成一定的影響,因此在使用strace进行调试时,应尽量减少对程序的干扰。
  • strace可能会输出大量的信息,因此在使用strace时,应使用适当的选项和参数来过滤和筛选输出信息。