菜鸟科技网

strace如何追踪Linux程序的系统调用?

strace 是一个强大的诊断、调试和分析 Linux 系统的工具,它的主要功能是跟踪和记录程序执行过程中所调用的系统调用以及它所接收到的信号

strace如何追踪Linux程序的系统调用?-图1
(图片来源网络,侵删)

什么是系统调用?

要理解 strace,首先要明白什么是系统调用

可以把 Linux 内核想象成一个操作系统的核心大脑,它管理着所有的硬件资源(CPU、内存、磁盘、网络等),用户程序(比如你的浏览器、文本编辑器)不能直接访问这些硬件,必须通过一种“请求”的方式让内核代为执行,这种“请求”就是系统调用

常见的系统调用包括:

  • 文件操作: open(), read(), write(), close(), lseek()
  • 进程控制: fork(), exec(), clone(), exit()
  • 网络通信: socket(), connect(), bind(), send(), recv()
  • 内存管理: brk(), mmap(), munmap()
  • 时间管理: clock_gettime(), time()

strace 就像一个“窃听器”,它拦截了用户程序和内核之间的所有这些“请求”和“响应”,并将其打印出来。

strace如何追踪Linux程序的系统调用?-图2
(图片来源网络,侵删)

strace 的主要用途

  • 调试程序: 当你的程序崩溃或行为异常时,strace 可以告诉你程序在崩溃前最后一次尝试做什么,一个程序无法打开文件,strace 会显示 open() 调用以及返回的错误码(如 ENOENT,表示文件不存在)。
  • 分析性能问题: 如果一个程序运行缓慢,strace 可以揭示瓶颈所在,一个程序可能在不断地进行磁盘 I/O(大量的 read()/write())或在网络上等待响应(大量的 connect()/read())。
  • 监控程序行为: 你可以清楚地看到程序在启动时加载了哪些配置文件(open() /etc/config),连接了哪些服务器(connect() 到某个 IP 地址),或者创建了哪些临时文件。
  • 学习 Linux 内核 API: 对于想深入了解 Linux 是如何工作的开发者来说,strace 是一个绝佳的学习工具,可以直观地看到系统调用的用法。

基本用法和常用选项

1 跟踪一个正在运行的进程

如果你想观察一个已经在运行的程序,可以使用 -p 选项,并附上进程 ID。

# 找到 Firefox 的进程 ID
ps aux | grep firefox
# 假设 PID 是 12345,跟踪它
sudo strace -p 12345

注意: 跟踪其他用户的进程通常需要 sudo 权限。

2 启动并跟踪一个新程序

这是最常见的用法,直接在 strace 后面跟上你想执行的命令。

# 跟踪 'ls -l' 命令的执行过程
strace ls -l

3 常用选项

选项 描述 示例
-c 统计模式:汇总所有系统调用的执行时间、次数等,并生成一个报表,非常适合性能分析。 strace -c ls -l
-f 跟踪子进程:如果程序创建了子进程,也一并跟踪。 strace -f ./my_script.sh
-F 跟踪 fork 出的子进程:与 -f 类似,但只跟踪 fork() 出来的直接子进程。
-o <file> 将输出重定向到文件,而不是打印到终端。 strace -o trace.log ls -l
-e expr 指定要跟踪的系统调用expr 可以是 trace=, signal=, abbrev=, verbose= 等。 strace -e trace=open,read ls -l (只跟踪 open 和 read)
-y 显示路径对应的符号链接 strace -y ls -l /etc/hosts
-s <num> 指定字符串的最大长度,默认是 32,有时候太短看不到完整内容。 strace -s 256 curl google.com
-v 详细模式:打印所有系统调用的原始参数,包括结构体和指针。
-tt 打印微秒级时间戳,在调试时非常有用,可以精确到微秒。 strace -tt ls -l
-T 打印每个系统调用的耗时 strace -T ls -l

实战示例

示例 1:调试一个找不到文件的程序

假设我们有一个脚本 test.sh

strace如何追踪Linux程序的系统调用?-图3
(图片来源网络,侵删)
#!/bin/bash
cat /non_existent_file.txt

给它执行权限后运行:

chmod +x test.sh
./test.sh

输出会是:cat: /non_existent_file.txt: No such file or directory

现在用 strace 来看看发生了什么:

strace -e trace=open,read,write ./test.sh

输出会类似这样:

open("/non_existent_file.txt", O_RDONLY) = -1 ENOENT (No such file or directory)
+++ exited with 127 +++

这里 strace 清晰地告诉我们,cat 程序尝试 open() 一个文件,但内核返回了错误码 ENOENT(No such file or directory),程序因此退出。

示例 2:分析一个网络程序的启动过程

我们想看看 ping 命令在启动时都做了什么,特别是网络相关的系统调用。

# 只跟踪网络相关的系统调用
strace -e trace=network ping google.com

输出中会包含大量类似这样的行:

socket(AF_INET, SOCK_RAW, IPPROTO_ICMP) = 3
setsockopt(3, SOL_SOCKET, SO_BROADCAST, [1], 4) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("172.217.16.238")}, 16) = 0
sendto(3, "E\x00\x00\x00U\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 20, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("172.217.16.238")}, 16) = 20
recvfrom(3, "E\x00\x00\x00U\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 84, 0, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("172.217.16.238")}, [16]) = 20

这告诉我们 ping 创建了一个原始套接字 (socket),设置了选项 (setsockopt),连接到目标地址 (connect),然后发送 (sendto) 和接收 (recvfrom) ICMP 数据包。

示例 3:性能分析

假设一个 my_slow_app 程序运行很慢,我们想找出瓶颈。

# 使用统计模式运行程序
strace -c ./my_slow_app

程序运行结束后,strace 会输出一个表格,类似下面这样:

% time     seconds   usecs/call     calls    errors syscall
------ ----------- --------- --------- --------- ----------------
 45.50    0.450000         450      1000           write
 30.20    0.302000         302      1000           read
 15.10    0.151000         151      1000           open
  9.20    0.092000          92      1000           futex
  0.00    0.000000           0         1           access
------ ----------- --------- --------- --------- ----------------
100.00    1.000000                 4001           total

从表中可以看出,write 系统调用占总执行时间的 45.5%,read 占 30.2%,这强烈暗示性能瓶颈在于 I/O 操作,特别是写操作,你可以据此去优化程序或存储系统。


高级技巧:与 strace 交互

strace 在运行时也可以接收一些信号来控制其行为:

  • SIGQUIT (Ctrl+): 打印当前正在执行的系统调用,然后继续执行。
  • SIGUSR1: 打印当前正在执行的系统调用,然后暂停 strace 的输出(但被跟踪的程序继续运行),再次发送 SIGUSR1 恢复输出。

这在程序运行时间很长,你想在某个特定时刻检查它在做什么时非常有用。


注意事项和替代工具

  • 性能开销: strace 会使程序运行得慢得多,因为它需要拦截和记录每一个系统调用。不要在生产性能敏感的环境中长时间使用 strace
  • 替代工具:
    • perf: 更现代、更强大的性能分析工具,不仅可以跟踪系统调用,还可以分析 CPU 缓存命中率、分支预测等更深层次的性能问题。
    • ltrace: 类似于 strace,但它跟踪的是库调用,即程序与 C 库(如 glibc)之间的交互,而不是与内核的交互,对于分析库函数的调用链非常有用。
    • systemtap / eBPF**: 更底层的、功能更强大的动态追踪框架,可以编写复杂的脚本来分析系统行为,但学习曲线也更陡峭。

strace 是每个 Linux 系统管理员和开发者的瑞士军刀,它简单、直接、无处不在,是诊断“黑盒”程序行为、调试棘手问题和分析性能问题的首选工具,掌握 strace,你就拥有了一把洞察程序与 Linux 内核交互的钥匙。

分享:
扫描分享到社交APP
上一篇
下一篇