strace 手册

如果能了解程序的每行代码是如何执行的,程序在运行时便了无秘密可言,是谓程序的可观察性。在我09年最早接触strace的时候,可观察性的概念还没有流行起来。使用至今,虽然systemtap,bpf等先进工具不断涌现,但它仍是首选,因为太简单易用。

strace是个诊断,教学,调试工具,最简单的用法是通过strace启动程序 strace command args ,如果程序已启动,可以 strace -p <pid> 。strace 拦截并记录程序发出的 系统调用 以及程序收到的 信号 ,打印每个系统调用的名称,参数,返回值到标准错误。

1 strace 的用途

  1. 无源码即可了解程序的机制。例如,通过观察 strace ip addr 使用了哪些系统调用,可以了解如何编程获取机器IP。
  2. 正常和异常对比。例如,通过对比 strace cp data data.1strace cp -a data data.2 可以看看为啥有时 cp -a 才能正常工作。
  3. 性能问题。例如,通过观察关键系统调用的时间间隔,是否符合预期,可以判断性能问题,锁是不是太大了,网络是不是太慢等。
  4. 了解程序正在干啥。有时候程序既不退出,也不打印输出,完全不知道它在忙啥,可以用strace看看。

1.1 strace 的机制

程序的运行离不开操作系统,而系统调用正是操作系统和应用的边界,通过观察边界的行为,进而了解程序的行为。

2 strace 的输出

2.1 输出格式

每行包含了系统调用名称,被括号包围的参数,以及返回值,例如strace cat /dev/null 的输出包括 open("/dev/null", O_RDONLY) = 3 。当错误发生时(通常返回-1),会包含额外的错误码和错误字符串,例如 open("/notexist", O_RDONLY) = -1 ENOENT (No such file or directory)

收到信号会打印信号名称,以及解码后的siginfo结构,例如 sleep 666 被 SIGINT 中断后,打印:

sigsuspend([] <unfinished ...>
--- SIGINT {si_signo=SIGINT, si_code=SI_USER, si_pid=...} ---
+++ killed by SIGINT +++

2.2 未完成的系统调用

如果系统调用正在执行,同时另一个系统调用被其它线程调用(strace 可以同时跟踪多个线程),strace会保留调用的顺序,同时标记该系统调用为 unfinished ,当该系统调用返回时,会被标记为 resumed

[pid 28772] select(4, [3], NULL, NULL, NULL <unfinished ...>
[pid 28779] clock_gettime(CLOCK_REALTIME, {1130322148, 939977000}) = 0
[pid 28772] <... select resumed>   = 1 (in [3])

可重启系统调用被信号中断后,打印略有不同,因为操作系统会立即重启该系统调用。

read(0, 0x7ffff72cf5cf, 1)       = ? ERESTARTSYS (To be restarted)
--- SIGALARM ... ---
rt_sigreturn(0xe)                = 0
read(0, "", 1)                   = 0

2.3 参数的输出

很多时候函数参数都是数字、指针,在输出时,strace尽量讲这些不可读的内容转成有意义的字符串。

输出时参数会被尽量转成符号。例如,执行strace重定向 >>xyzzy 时输出 open("xyzzy", O_WRONLY|O_APPEND|O_CREAT, 0666) = 3 这里 open 的第二个参数被逆向转成宏,第三个参数被转成8进制。(熟悉C的同学了解,二进制程序里,这些参数都是数字,宏是源码里的东西,可见strace做了很多可读性的转换)。

结构体指针会被解引用,打印成接近源码的形式,例如,strace ls -l /dev/null 时输出 lstat("/dev/null", {st_mode=S_IFCHR|0666, st_rdev=makedev(0x1,0x3), ...}) = 0 ,这里第二个参数 struct stat 的指针,存放返回值,输出时尽量可读。如果系统调用失败了,指针不会被解引用。

字符指针打印成C字符串,默认打印32个,超过部分用省略号代替。

3 strace的参数

3.1 常用的参数

-p pid 用于trace运行中的程序, CTRL-C 退出trace。

-f 连同trace的子进程一起trace。

-s strsize 指定输出字符串时的最大长度,默认32。

3.2 性能用途方面的参数

-r 打印两次系统调用之间的相对时间

-t 打印系统调用的时间

-tt 打印系统调用的时间,包含毫秒数据

-ttt 打印系统调用的时间,以 秒.毫秒 的形式

Author: zhengzhiyong

Created: 2020-11-12 四 07:06

Validate