Linux strace 命令实战示例

LinuxLinuxBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

介绍

在本实验中,我们将探索 Linux 的 strace 命令,并学习如何使用它来跟踪和监控运行进程所进行的系统调用。strace 命令是一个强大的工具,能够提供对程序内部运作的宝贵洞察,这对于调试和排查问题至关重要。我们将首先介绍 strace 命令,然后深入探讨如何跟踪系统调用,最后探索如何使用 strace 进行进程调试。通过本实验,你将掌握在 Linux 系统管理和开发任务中有效使用 strace 命令的技能。

Linux 命令速查表


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL linux(("Linux")) -.-> linux/BasicSystemCommandsGroup(["Basic System Commands"]) linux(("Linux")) -.-> linux/BasicFileOperationsGroup(["Basic File Operations"]) linux(("Linux")) -.-> linux/SystemInformationandMonitoringGroup(["System Information and Monitoring"]) linux/BasicSystemCommandsGroup -.-> linux/sleep("Execution Delaying") linux/BasicFileOperationsGroup -.-> linux/ls("Content Listing") linux/SystemInformationandMonitoringGroup -.-> linux/time("Command Timing") subgraph Lab Skills linux/sleep -.-> lab-422933{{"Linux strace 命令实战示例"}} linux/ls -.-> lab-422933{{"Linux strace 命令实战示例"}} linux/time -.-> lab-422933{{"Linux strace 命令实战示例"}} end

strace 命令介绍

在这一步中,我们将探索 strace 命令,这是 Linux 中一个强大的工具,允许你跟踪和监控运行进程所进行的系统调用。系统调用是进程与操作系统之间的接口,理解它们对于调试和排查问题至关重要。

让我们从安装 strace 包开始:

sudo apt-get update
sudo apt-get install -y strace

示例输出:

Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  libunwind8
Suggested packages:
  fakeroot
The following NEW packages will be installed:
  libunwind8 strace
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 292 kB of archives.
After this operation, 1,054 kB of additional disk space will be used.
Do you want to continue? [Y/n] Y
...

现在,让我们尝试使用 strace 命令来跟踪一个简单的程序。我们将以 ls 命令为例:

strace ls

示例输出:

execve("/usr/bin/ls", ["ls"], 0x7ffee4f7a0f0 /* 23 vars */) = 0
brk(NULL)                               = 0x55b7d6c23000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
...

输出显示了 ls 命令进行的系统调用序列,包括用于执行命令的 execve、用于分配内存的 brk、用于检查文件权限的 access,以及用于打开动态链接器缓存文件的 openat

通过分析 strace 的输出,你可以深入了解程序如何与操作系统交互,这对于调试和理解程序行为非常有帮助。

使用 strace 跟踪系统调用

在这一步中,我们将深入探讨如何使用 strace 命令来跟踪运行进程所进行的系统调用。

让我们首先创建一个简单的 Python 脚本,用于跟踪:

cat > ~/project/example.py << EOF
import time

print("Hello, World!")
time.sleep(5)
EOF

现在,让我们使用 strace 跟踪这个脚本的执行:

strace python ~/project/example.py

示例输出:

execve("/usr/bin/python", ["python", "/home/labex/project/example.py"], 0x7ffee4f7a0f0 /* 23 vars */) = 0
brk(NULL)                               = 0x55b7d6c23000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
...
write(1, "Hello, World!\n", 14)         = 14
time(NULL)                              = 1618304400
nanosleep({5, 0}, NULL)                 = 0
exit_group(0)                           = ?
+++ exited with 0 +++

输出显示了 Python 脚本进行的系统调用序列,包括用于执行 Python 解释器的 execve、用于输出 "Hello, World!" 消息的 write、用于获取当前时间的 time,以及用于暂停脚本 5 秒的 nanosleep

你可以使用 strace 输出来了解你的程序如何与操作系统交互,并识别任何潜在问题或性能瓶颈。

让我们尝试另一个例子,这次使用一些附加选项跟踪 ls 命令的执行:

strace -c ls -l ~/project

示例输出:

total 4
-rw-r--r-- 1 labex labex 59 Apr 12 13:33 example.py
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 45.45    0.000005           5         1           execve
 27.27    0.000003           3         1           brk
  9.09    0.000001           1         1           access
  9.09    0.000001           1         1           openat
  9.09    0.000001           1         1           close
  0.00    0.000000           0         4           read
  0.00    0.000000           0         2           fstat
  0.00    0.000000           0         1           mmap
  0.00    0.000000           0         1           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         2           ioctl
  0.00    0.000000           0         1           statfs
  0.00    0.000000           0         1           access
  0.00    0.000000           0         2           newfstatat
  0.00    0.000000           0         2           close
------ ----------- ----------- --------- --------- ----------------
100.00    0.000011                    22           total

在这个例子中,我们使用了 -c 选项来获取 ls 命令进行的系统调用摘要。输出显示了每个系统调用所花费的时间百分比、调用次数以及错误次数。

这些信息对于识别性能瓶颈或理解程序行为非常有用。

使用 strace 调试进程

在这一步中,我们将学习如何使用 strace 命令调试运行中的进程并识别潜在问题。

让我们首先创建一个简单的 C 程序,用于调试:

cat > ~/project/example.c << EOF
#include <stdio.h>
#include <unistd.h>

int main() {
    printf("Hello, World!\n");
    sleep(5);
    return 0;
}
EOF

现在,编译程序并使用 strace 运行它:

gcc -o ~/project/example ~/project/example.c
strace ~/project/example

示例输出:

execve("/home/labex/project/example", ["/home/labex/project/example"], 0x7ffee4f7a0f0 /* 23 vars */) = 0
brk(NULL)                               = 0x55b7d6c23000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
...
write(1, "Hello, World!\n", 14)         = 14
time(NULL)                              = 1618304400
sleep(5)                                = 5
exit_group(0)                           = ?
+++ exited with 0 +++

输出显示了 C 程序进行的系统调用序列,包括用于执行程序的 execve、用于输出 "Hello, World!" 消息的 write,以及用于暂停程序 5 秒的 sleep

现在,假设我们想要调试程序中的某个问题。我们可以使用 strace 来识别问题。例如,假设程序没有将预期的输出写入文件。我们可以跟踪与文件相关的系统调用来查看发生了什么:

strace -e trace=file ~/project/example

示例输出:

execve("/home/labex/project/example", ["/home/labex/project/example"], 0x7ffee4f7a0f0 /* 23 vars */) = 0
write(1, "Hello, World!\n", 14)         = 14
time(NULL)                              = 1618304400
sleep(5)                                = 5
exit_group(0)                           = ?
+++ exited with 0 +++

输出显示程序没有进行任何与文件相关的系统调用,这表明问题与文件操作无关。

通过使用 strace 跟踪特定的系统调用或整体系统调用活动,你通常可以识别程序问题的根本原因,并更有效地进行调试。

总结

在本实验中,我们探索了强大的 Linux strace 命令,它允许我们跟踪和监控运行进程所进行的系统调用。我们首先介绍了 strace 命令并将其安装到系统中。接着,我们使用 strace 跟踪了简单的 ls 命令所进行的系统调用,深入了解了程序如何与操作系统交互。随后,我们进一步深入使用 strace 跟踪系统调用,创建了一个简单的 Python 脚本并观察了其进行的系统调用序列。通过分析 strace 的输出,我们可以更好地理解程序行为,并调试可能出现的问题。

Linux 命令速查表