Ubuntu 22.04 strace 安装与命令参数详解

strace(strace 5.16)在 Ubuntu 22.04(x86_64)上的系统调用跟踪全参数实测与故障注入诊断实践。

Linux 系统监控与诊断straceUbuntu 22.042026/10/06

Ubuntu 22.04 strace 安装与命令参数详解

目标:掌握 strace 对程序发起的所有系统调用进行跟踪与统计的方法。本文档在 Ubuntu 22.04(x86_64)真实环境中实测通过,逐一验证了 -c / -e trace=各class / -f / -ff -o / -p / -o / -s / -T / -t -tt -ttt / -r / -y -yy / -z -Z / -i / -v / -x / -k / -e inject / -e signal / -b / -D / --seccomp-bpf / -A 等参数的完整行为与真实输出。

一、环境信息

  • 操作系统:Ubuntu 22.04(x86_64)
  • 工具版本:strace 5.16(软件包版本 strace_5.16-0ubuntu3_amd64,strace --version 实测读取)
  • 主机名:mon-ubuntu2204(cat /etc/hostname 实测输出)
  • 安装来源仓库:Ubuntu jammy main 仓库(http://archive.ubuntu.com/ubuntu jammy)
  • 动态库加载目录:/lib/x86_64-linux-gnu/(glibc / libselinux 等)
  • 编译特性:stack-trace=libunwind stack-demangle m32-mpers mx32-mpers
  • 说明:本环境日志未直接给出 CPU 核数与内网 IP(可运行 nproc / ip addr 补充),其余环境字段均来自实测日志。

二、工具概览

strace(System Tracer)是一个运行于用户态的标准系统调用跟踪工具:它通过内核的 ptrace(process trace)机制介入目标进程,在每次系统调用进入与返回时各切换一次运行上下文,把调用名、参数、返回值、耗时与错误码逐条打印出来。基于此,它可用于:

  • 排查程序启动失败/崩溃的根因(如缺失动态库、权限不足、打开文件失败);
  • 定位配置文件加载路径、摸清程序真实 I/O 行为;
  • 用 -c 统计各系统调用次数与耗时占比,快速定位热点;
  • 用 -e inject 故障注入伪造系统调用返回值,做故障演练;
  • 配合 -ff -o 跟踪多进程,用 -t/-r/-T 查看时间维度。

strace 只跟踪系统调用(面向内核的接口),不跟踪用户态库函数调用(那是 ltrace 的职责),两者常配合使用。

三、在线安装

strace 是 Ubuntu 官方软件库自带的系统工具。先更新软件源索引,再安装:

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

安装完成后用 dpkg -l 复核包版本:

ii  strace         5.16-0ubuntu3                amd64        System call tracer

由于当前环境已内置 strace,重复执行 apt-get install 会得到 "已是最大版本" 的提示(同类工具 ltrace/sysstat 实测为 already the newest version)。版本验证:

strace --version
strace -- version 5.16
Copyright (c) 1991-2022 The strace developers <https://strace.io>.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Optional features enabled: stack-trace=libunwind stack-demangle m32-mpers mx32-mpers

四、离线安装

在无法连通公网的内网环境,可先在可联网机器下载 deb 包再离线安装。用 apt-get download 直接抓取 strace 的主包:

mkdir -p /root/offline-bundle
cd /root/offline-bundle
apt-get download strace
ls -l /root/offline-bundle/strace_5.16-0ubuntu3_amd64.deb

若需连同所有依赖一并带走,可用 --download-only 把整包集下载到指定目录(实测示例节选):

Get:7 http://archive.ubuntu.com/ubuntu jammy/universe amd64 nmon amd64 16n+debian-1 [69.3 kB]
Get:8 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 sysstat amd64 12.5.2-2ubuntu0.2 [487 kB]
Fetched 1848 kB in 2s (861 kB/s)
Download complete and in download only mode

离线包目录清单(包含 strace 的 deb):

9
1.8M	/root/offline-bundle
atop_2.7.1-1_amd64.deb
glances_3.2.4.2+dfsg-1_all.deb
htop_3.0.5-7build2_amd64.deb
iotop_0.6-24-g733f3f8-1.1ubuntu0.1_amd64.deb
ltrace_0.7.3-6.1ubuntu6.22.04.1_amd64.deb
nmon_16n+debian-1_amd64.deb
strace_5.16-0ubuntu3_amd64.deb
sysstat_12.5.2-2ubuntu0.2_amd64.deb

离线安装(dpkg -i 重装输出与此同型,实测示例为 htop):

sudo dpkg -i /root/offline-bundle/strace_5.16-0ubuntu3_amd64.deb
Preparing to unpack htop_3.0.5-7build2_amd64.deb ...
Unpacking htop (3.0.5-7build2) over (3.0.5-7build2) ...
Setting up htop (3.0.5-7build2) ...
Processing triggers for mailcap (3.70+nmu1ubuntu1.22.04.1) ...

离线安装完成后同样用 strace --version(输出见「三」)验证 5.16 版本生效。

💡 说明:apt-get download 所得为单个主包,离线环境还需配套依赖;--download-only 可一次性备齐全部依赖包。

五、全部命令参数实测

5.1 strace --version 查看版本与编译特性

参数/作用:-V/--version → 查看 strace 版本号及编译时可用的特性(栈回溯、符号反修饰、m32/mx32 兼容模式等)。

strace --version

输出见「三」,版本 5.16。结尾特性行为后续 -k(内核栈)等参数是否可用提供依据。

5.2 strace ls / 默认全量跟踪

参数/作用:不带参数 → 跟踪目标程序发起的所有系统调用,逐条打印。

strace ls / 2>&1 | head -n 12
execve("/usr/bin/ls", ["ls", "/"], 0x7fff7dbefe28 /* 7 vars */) = 0
brk(NULL)                               = 0x64bb0aa18000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffcd784dc30) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x70b08f2ab000
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
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=13588, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 13588, PROT_READ, MAP_PRIVATE, 3, 0) = 0x70b08f2a7000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libselinux.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\0\0\0\0\0\0\0\0"..., 832) = 832
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=166280, ...}, AT_EMPTY_PATH) = 0

(节选前 12 行。)注意现代 Ubuntu 22.04 的 coreutils 9.x 使用 newfstatat/openat/AT_EMPTY_PATH,而不是旧的 stat/fstat。

5.3 strace -c ls / 系统调用汇总统计

参数/作用:-c → 不逐条打印,改为输出统计汇总表(时间占比、总耗时、每次耗时、调用次数、出错次数、调用名)。

strace -c ls /
 10.02    0.000177          25         7           mprotect
  8.32    0.000147          73         2           getdents64
  8.04    0.000142          23         6           openat
  5.26    0.000093          18         5           read
  5.21    0.000092          11         8           close
  5.09    0.000090          12         7           newfstatat
  4.02    0.000071          23         3           brk
  3.51    0.000062          31         2         2 access
  2.89    0.000051          12         4           pread64
  2.32    0.000041          20         2         2 statfs
  2.04    0.000036          18         2         2 ioctl
  1.81    0.000032          32         1           munmap
  1.47    0.000026          26         1           statx
  1.41    0.000025          25         1           write
  1.41    0.000025          25         1           prlimit64
  1.36    0.000024          24         1           getrandom
  1.19    0.000021          21         1           rseq
  1.08    0.000019           9         2         1 arch_prctl
  1.02    0.000018          18         1           set_tid_address
  0.96    0.000017          17         1           set_robust_list
------ ----------- ----------- --------- --------- ----------------
100.00    0.001767          23        76         7 total

💡 说明:第 4 列 calls、第 5 列 errors(出错次数)。本次共 76 次成功调用、7 次出错。

5.4 strace -c -w ls / 含系统时间汇总

参数/作用:-c -w → 与 -c 类似,但用时基于系统调用在系统态花费的时间(system time)而非墙钟时间。

strace -c -w ls /
  3.12    0.000044          44         1           write
  2.01    0.000029           7         4           pread64
  1.94    0.000028          13         2         1 arch_prctl
  1.69    0.000024          12         2         2 statfs
  1.18    0.000017          16         1           munmap
  0.99    0.000014           7         2         2 ioctl
  0.64    0.000009           9         1           statx
  0.55    0.000008           7         1           prlimit64
  0.51    0.000007           7         1           getrandom
  0.50    0.000007           7         1           rseq
  0.50    0.000007           7         1           set_tid_address
  0.49    0.000007           6         1           set_robust_list
------ ----------- ----------- --------- --------- ----------------
100.00    0.001427          18        76         7 total

💡 说明:-w 更贴近 CPU 忙于该系统调用的真实开销,常用于剔除 I/O 等待的干扰。

5.5 strace -e trace=openat cat /etc/hostname 指定单个系统调用

参数/作用:-e trace=openat → 只跟踪名为 openat 的系统调用。

strace -e trace=openat cat /etc/hostname
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3
mon-ubuntu2204
+++ exited with 0 +++

从三行 openat 可清晰看到程序打开 ld.so.cache、libc.so.6,最终打开并读取 /etc/hostname。

5.6 strace -e trace=%file cat /etc/hostname 文件类调用集

参数/作用:-e trace=%file → 跟踪所有与文件操作相关的调用(openat、access、newfstatat 等)。

strace -e trace=%file cat /etc/hostname
execve("/usr/bin/cat", ["cat", "/etc/hostname"], 0x7ffed74aba28 /* 7 vars */) = 0
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
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=13588, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2220400, ...}, AT_EMPTY_PATH) = 0
newfstatat(1, "", {st_mode=S_IFIFO|0600, st_size=0, ...}, AT_EMPTY_PATH) = 0
openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=15, ...}, AT_EMPTY_PATH) = 0
mon-ubuntu2204

5.7 strace -e trace=%network python3 网络类调用集

参数/作用:-e trace=%network → 只跟踪 socket、bind、connect 等网络相关调用。用 python3 建一个 127.0.0.1:0 的 TCP socket 演示。

strace -e trace=%network python3 -c "import socket; s=socket.socket(); s.bind(('127.0.0.1',0))"
socket(AF_INET, SOCK_STREAM|SOCK_CLOEXEC, IPPROTO_IP) = 3
bind(3, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr("127.0.0.1")}, 16) = 0
+++ exited with 0 +++

5.8 strace -f -e trace=%process 进程管理类调用集

参数/作用:-f → 跟踪子进程;-e trace=%process → 只跟踪 execve、fork、clone、wait4 等进程管理类调用。

strace -f -e trace=%process sh -c "ls / >/dev/null"
execve("/usr/bin/sh", ["sh", "-c", "ls / >/dev/null"], 0x7ffff371a608 /* 7 vars */) = 0
vfork(strace: Process 11225 attached
 <unfinished ...>
[pid 11225] execve("/usr/bin/ls", ["ls", "/"], 0x5fd0362547b0 /* 7 vars */ <unfinished ...>
[pid 11224] <... vfork resumed>)        = 11225
[pid 11224] wait4(-1,  <unfinished ...>
[pid 11225] <... execve resumed>)       = 0
[pid 11225] exit_group(0)               = ?
[pid 11225] +++ exited with 0 +++
<... wait4 resumed>[{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 11225

[pid NNNN] 前缀清晰区分出父(11224)/子(11225)进程各自的调用。

5.9 strace -e trace=%desc 文件描述符类调用集

参数/作用:-e trace=%desc → 只跟踪 fd 相关调用(openat、close、read、write、mmap、pread64 等)。

strace -e trace=%desc cat /etc/hostname 2>&1 | head -n 12
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x75ec61a0d000
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=13588, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 13588, PROT_READ, MAP_PRIVATE, 3, 0) = 0x75ec61a09000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0P\237\2\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
pread64(3, "\4\0\0\0 \0\0\0\5\0\0\0GNU\0\2\0\0\300\4\0\0\0\3\0\0\0\0\0\0\0"..., 48, 848) = 48
pread64(3, "\4\0\0\0\24\0\0\0\3\0\0\0GNU\0jl\265\250\17\325\345\273[\363\256\252\21\32\335\230"..., 68, 896) = 68
newfstatat(3, "", {st_mode=S_IFREG|0755, st_size=2220400, ...}, AT_EMPTY_PATH) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784

5.10 strace -e trace=%memory 内存管理类调用集

参数/作用:-e trace=%memory → 只跟踪 brk、mmap、mprotect、mremap 等内存映射类调用。

strace -e trace=%memory cat /etc/hostname
brk(NULL)                               = 0x5a678b511000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x71d22d992000
mmap(NULL, 13588, PROT_READ, MAP_PRIVATE, 3, 0) = 0x71d22d98e000
mmap(NULL, 177672, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x71d22d962000
mprotect(0x71d22d968000, 139264, PROT_NONE) = 0
mmap(0x71d22d968000, 106496, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x6000) = 0x71d22d968000
mmap(0x71d22d982000, 28672, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x20000) = 0x71d22d982000
mmap(0x71d22d98a000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x27000) = 0x71d22d98a000

5.11 strace -f 跟踪子进程(fork/clone 可见)

参数/作用:-f → 跟踪目标及其 fork/clone 出的所有子进程;管道示例中 sh → echo / cat 皆为子进程。

strace -f sh -c "echo hi | cat"
execve("/usr/bin/sh", ["sh", "-c", "echo hi | cat"], 0x7ffc37652438 /* 7 vars */) = 0
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x715233eeaa10) = 11245
[pid 11245] write(1, "hi\n", 3 <unfinished ...>
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLDstrace: Process 11246 attached
[pid 11246] execve("/usr/bin/cat", ["cat"], 0x603c201ec790 /* 7 vars */ <unfinished ...>
[pid 11246] <... execve resumed>)       = 0
[pid 11246] write(1, "hi\n", 3hi

clone 返回值 11245、11246 即新子进程的 PID,随后的 [pid NNNN] 前缀标明每条调用属于哪个进程。

5.12 strace -ff -o 前缀 每进程独立文件

参数/作用:-ff -o <前缀> → 为每个被跟踪进程单独写一个 前缀.<pid> 文件,避免多进程输出互相穿插。

strace -ff -o /root/.stx-. sh -c "echo hi | cat"
ls -l /root/.stx-*
hi
-rw-r--r-- 1 root root 5312 Oct  6 05:09 /root/.stx-.11251
-rw-r--r-- 1 root root  286 Oct  6 05:09 /root/.stx-.11252
-rw-r--r-- 1 root root 3441 Oct  6 05:09 /root/.stx-.11253

查看第一个文件起始内容:

execve("/usr/bin/sh", ["sh", "-c", "echo hi | cat"], 0x7ffc16da8628 /* 7 vars */) = 0
brk(NULL)                               = 0x6106f4ebb000
arch_prctl(0x3001 /* ARCH_??? */, 0x7fffc1360bf0) = -1 EINVAL (Invalid argument)

5.13 strace -p PID 附加运行中的进程

参数/作用:-p PID → 附加到一个已在运行、尚未结束的进程上,实时观察其调用,Ctrl-C 后显示 detach。

strace -p 11260
strace: Process 11260 attached
restart_syscall(<... resuming interrupted read ...>strace: Process 11260 detached
 <detached ...>

⚠️ 注意:附加只读型调试一般不需额外权限,但跟踪他人进程(非 root 拥有)通常需要相同 uid 或 root。

5.14 strace -o file 输出重定向到文件

参数/作用:-o <file> → 把跟踪输出写入指定文件而非 stderr,实测 -o /tmp/strace.out。

strace -o /tmp/strace.out ls /
head -n 5 /tmp/strace.out
execve("/usr/bin/ls", ["ls", "/"], 0x7ffdc714d228 /* 7 vars */) = 0
brk(NULL)                               = 0x640fd608f000
arch_prctl(0x3001 /* ARCH_??? */, 0x7ffd1bcc5c10) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7907c8062000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)

(节选前 5 行。)

5.15 strace -s 8 字符串截断为 8 字符

参数/作用:-s <n> → 限制被打印字符串的最大长度为 n 字节,默认 32;设 8 后长路径只显示前 8 字节。

strace -s 8 -e trace=openat cat /etc/hostname
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3
mon-ubuntu2204

5.16 strace -T 显示每次调用耗时

参数/作用:-T → 在每个系统调用后追加 <> 形式的调用耗时(秒)。

strace -T -e trace=openat cat /etc/hostname
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 <0.000107>
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 <0.000059>
openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3 <0.000056>
mon-ubuntu2204
+++ exited with 0 +++

三次 openat 均耗时约 0.0001 s,据此可定位单次调用的时间热点。

5.17 strace -t / -tt / -ttt 三级时间戳精度

参数/作用:-t → 打印时:分:秒;-tt → 含微秒;-ttt → 打印自 epoch 起的微秒数。

strace -t -e trace=openat cat /etc/hostname
05:09:06 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
05:09:06 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
strace -tt -e trace=openat cat /etc/hostname
05:09:06.766799 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
05:09:06.767680 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
strace -ttt -e trace=openat cat /etc/hostname
1791263346.778212 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
1791263346.779243 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3

5.18 strace -r 相对时间戳(相邻调用间隔)

参数/作用:-r → 打印每条调用相对上一条调用的时间间隔(秒)。

strace -r -e trace=openat cat /etc/hostname
     0.000000 openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
     0.000641 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
     0.004129 openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3
mon-ubuntu2204

5.19 strace -yy 解码 fd(含 socket/管道路径)

参数/作用:-yy → 除路径外还打印被引用对象的详细属性(设备号、类型、inode),对 socket/管道同样解码。

strace -yy -e trace=write sh -c "echo ok >/dev/null"
write(1</dev/null<char 1:3>>, "ok\n", 3) = 3
+++ exited with 0 +++

</dev/null<char 1:3>> 表明 fd 1 指向 /dev/null,其字符设备主/次号为 1:3。

5.20 strace -y 简化 fd 解码(仅路径)

参数/作用:-y → 在 fd 后附带打开的目标对象路径,信息较 -yy 简略。

strace -y -e trace=write sh -c "echo ok >/dev/null"
write(1</dev/null>, "ok\n", 3)          = 3
+++ exited with 0 +++

5.21 strace -z 只显示成功的调用

参数/作用:-z → 仅输出返回成功的系统调用,失败的被过滤掉,适合聚焦正常路径。

strace -z -e trace=openat cat /etc/hostname
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3
mon-ubuntu2204

5.22 strace -Z 只显示失败的调用

参数/作用:-Z → 与 -z 相反,只输出失败的调用,错误定位利器。

strace -Z cat /etc/nonexist
openat(AT_FDCWD, "/etc/nonexist", O_RDONLY) = -1 ENOENT (No such file or directory)
cat: /etc/nonexist: No such file or directory
+++ exited with 1 +++

-Z 下其它成功调用全部被过滤,一眼定位到失败点 openat 与错误码 ENOENT。

5.23 strace -i 显示指令指针

参数/作用:-i → 在每条调用前打印发生该系统调用时 CPU 的指令指针(指令地址),便于结合反汇编定位调用点。

strace -i -e trace=openat cat /etc/hostname
[00007dabb005fb18] openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
[00007dabb005fb18] openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
[00007dabaff1e68b] openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3

5.24 strace -v 完整结构体展开

参数/作用:-v → 不缩写打印结构体(如 stat 结构),把所有字段完整展开。现代 coreutils 9.x 走 newfstatat,配合 -e trace=newfstatat 可看到完整 stat 内容。

strace -v -e trace=newfstatat cat /etc/hostname
newfstatat(3, "", {st_dev=makedev(0, 0x123), st_ino=25447460, st_mode=S_IFREG|0644, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=32, st_size=13588, st_atime=1791261640 /* 2026-10-06T04:40:40.687734349+0000 */, st_atime_nsec=687734349, st_mtime=1791261640 /* 2026-10-06T04:40:40.672734280+0000 */, st_mtime_nsec=672734280, st_ctime=1791261640 /* 2026-10-06T04:40:40.674734289+0000 */, st_ctime_nsec=674734289}, AT_EMPTY_PATH) = 0
newfstatat(3, "", {st_dev=makedev(0, 0x123), st_ino=25449669, st_mode=S_IFREG|0755, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=4344, st_size=2220400, st_atime=1791260808 /* 2026-10-06T04:26:48.429069777+0000 */, st_atime_nsec=429069777, st_mtime=1788445204 /* 2026-09-03T14:20:04+0000 */, st_mtime_nsec=0, st_ctime=1791260808 /* 2026-10-06T04:26:48.392068908+0000 */, st_ctime_nsec=392068908}, AT_EMPTY_PATH) = 0
newfstatat(1, "", {st_dev=makedev(0, 0xe), st_ino=38744377, st_mode=S_IFIFO|0600, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=0, st_size=0, st_atime=1791263564 /* 2026-10-06T05:12:44.226461279+0000 */, st_atime_nsec=226461279, st_mtime=1791263564 /* 2026-10-06T05:12:44.226461279+0000 */, st_mtime_nsec=226461279, st_ctime=1791263564 /* 2026-10-06T05:12:44.226461279+0000 */, st_ctime_nsec=226461279}, AT_EMPTY_PATH) = 0
newfstatat(3, "", {st_dev=makedev(0x8, 0x3), st_ino=19005877, st_mode=S_IFREG|0644, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=8, st_size=15, st_atime=1791263343 /* 2026-10-06T05:09:03.498189459+0000 */, st_atime_nsec=498189459, st_mtime=1791260573 /* 2026-10-06T04:22:53.328055753+0000 */, st_mtime_nsec=328055753, st_ctime=1791263564 /* 2026-10-06T05:12:44.076458650+0000 */, st_ctime_nsec=76458650}, AT_EMPTY_PATH) = 0

💡 说明:普通 strace ls / 的 -v 输出较为简略;本项目补测用例(fix)确认 Ubuntu 22.04 coreutils 走 newfstatat,展开可见设备号、inode、权限、大小、各时间戳与纳秒字段。

5.25 strace -x 非 ASCII 字符串十六进制输出

参数/作用:-x → 把字符串中的非 ASCII 字符以转义形式(UTF-8 十六进制)打印,方便比较携带不可打印字符的路径/数据。先创建中文文件名再对照。

echo hi > /root/中文测试.txt
strace -e trace=openat cat /root/中文测试.txt
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/root/\344\270\255\346\226\207\346\265\213\350\257\225.txt", O_RDONLY) = 3
strace -x -e trace=openat cat "/root/中文测试.txt"
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "\x2f\x72\x6f\x6f\x74\x2f\xe4\xb8\xad\xe6\x96\x87\xe6\xb5\x8b\xe8\xaf\x95\x2e\x74\x78\x74", O_RDONLY) = 3

💡 说明:不加 -x 时输出 UTF-8 原文(/root/中文测试.txt),但终端已把其字节显示为八进制转义;加 -x 后统一为 \x 十六进制,便于机器可读比较。

5.26 strace -k 每次调用打印内核栈

参数/作用:-k → 在每个系统调用下打印该调用点的栈回溯(符号+偏移+地址),定位调用来源于哪个库/函数。

strace -k -e trace=openat cat /etc/hostname
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x9748) [0x26b18]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_rtld_di_serinfo+0x26ca) [0xd62a]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_deallocate_tls+0x2148) [0x16bb8]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(__nptl_change_stack_perm+0x57d2) [0xa982]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_debug_state+0x195) [0x3495]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_exception+0x6a) [0x1d34a]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_debug_state+0x97c) [0x3c7c]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x5fd0) [0x233a0]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x246c) [0x1f83c]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x41c8) [0x21598]
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x2ec8) [0x20298]
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
 > /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2(_dl_catch_error+0x9748) [0x26b18]

(节选。)栈帧均来自动态链接器 ld-linux-x86-64.so.2,说明这些 openat 发生在程序动态装载库的阶段。

5.27 strace -e inject=read:error=EIO 故障注入

参数/作用:-e inject=<调用>:error=<errno> → 人为让指定系统调用按给定 errno 失败,用于故障演练。注意参数名是 error= 而非 errno=。

strace -e inject=read:error=EIO cat /etc/hostname
execve("/usr/bin/cat", ["cat", "/etc/hostname"], 0x7ffd38697668 /* 6 vars */) = 0
brk(NULL)                               = 0x631bd7225000
arch_prctl(0x3001 /* ARCH_??? */, 0x7fff20fb78b0) = -1 EINVAL (Invalid argument)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7d1bb8a6d000
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
newfstatat(3, "", {st_mode=S_IFREG|0644, st_size=13588, ...}, AT_EMPTY_PATH) = 0
mmap(NULL, 13588, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7d1bb8a69000
close(3)                                = 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, 0x7fff20fb6c38, 832)            = -1 EIO (Input/output error) (INJECTED)
close(3)                                = 0

加载动态库时的 read 被注入失败,返回 -1 EIO 并明确标注 (INJECTED)。若误写 error= 为 errno=(见「六」),会直接报参数非法。

5.28 strace -e signal=SIGALRM 信号过滤

参数/作用:-e signal=<信号> → 只跟踪指定信号(信号到达与处理,非系统调用);配合自触发 SIGALRM 演示。

strace -e signal=SIGALRM sh -c 'kill -ALRM $$; sleep 1'
--- SIGALRM {si_signo=SIGALRM, si_code=SI_USER, si_pid=11361, si_uid=0} ---
+++ killed by SIGALRM +++

可以看到进程收到 SIGALRM,默认处置为终止。

5.29 strace -c -S calls ls / 汇总按调用次数排序

参数/作用:-S <排序键> → 与 -c 配合按指定字段排序;calls 即按调用次数从多到少排序(默认按时间)。汇总段在输出末尾,常用 | tail 截取。

strace -c -S calls ls / 2>&1 | tail -n 15
  3.50    0.000015           7         2         2 statfs
  0.23    0.000001           0         2         1 arch_prctl
 26.34    0.000113          56         2           getdents64
  5.13    0.000022          22         1           write
  2.56    0.000011          11         1           munmap
  0.00    0.000000           0         1           execve
  0.47    0.000002           2         1           set_tid_address
  0.47    0.000002           2         1           set_robust_list
  0.47    0.000002           2         1           prlimit64
  0.47    0.000002           2         1           getrandom
  0.70    0.000003           3         1           statx
  0.47    0.000002           2         1           rseq
------ ----------- ----------- --------- --------- ----------------
100.00    0.000429           5        76         7 total

(末尾汇总段;getdents64 56 次为最高频调用。)主测试日志中普通 -c -S calls 的目录名部分未纳入汇总表,补测用例确认应取末尾 total 段。

5.30 strace -b execve execve 时自动分离

参数/作用:-b <系统调用> → 在指定 syscall 处自动断开(detach)跟踪,通常用于 execve 后不再跟踪被替换的程序。

strace -b execve sh -c "ls / >/dev/null"
execve("/usr/bin/sh", ["sh", "-c", "ls / >/dev/null"], 0x7ffcd1430f20 /* 7 vars */) = 0
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=11374, si_uid=0, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

5.31 strace -D tracer 与 tracee 分离运行

参数/作用:-D → 让被跟踪程序作为独立进程运行(tracer 作为其父进程的一个独立子进程),互不阻塞、脱离退出。

strace -D ls /
strace: Process 11376 attached
bin
boot

(节选。)ls / 正常运行输出目录,strace 仅做观察、随后自行分离。

5.32 strace --seccomp-bpf seccomp 加速过滤

参数/作用:--seccomp-bpf → 用内核 seccomp BPF 过滤加速跟踪(显著降低 ptrace 开销),但需要 -f 跟随子进程配合。

strace --seccomp-bpf -e trace=openat cat /etc/hostname
strace: --seccomp-bpf cannot be used without -f/--follow-forks, disabling
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, "/etc/hostname", O_RDONLY) = 3

未带 -f 时报告无法使用并自动禁用该优化,但跟踪仍正常进行。

5.33 strace -A -o file 追加输出模式

参数/作用:-A → 配合 -o 以追加(append)方式写入文件,而不是覆盖,适合多次运行累积日志。用行数验证递增。

strace -A -o /tmp/strace.txt true
wc -l < /tmp/strace.txt
strace -A -o /tmp/strace.txt true
wc -l < /tmp/strace.txt
首次写入行数: 1
追加后行数: 2

第一次写入 1 行,追加第二次后变 2 行,证明 -A 未覆盖旧内容而是继续追加。

六、常见问题与真实行为

① -e inject=read:errno=EIO 报错:参数名必须是 error= 现象:运行 strace -e inject=read:errno=EIO cat /etc/hostname 直接报:

strace: invalid inject argument 'read:errno=EIO'

原因:strace 5.16 的 inject 故障注入用 error=<errno|succeed|return=值> 指定注入结果,不存在 errno= 这个键。 解决:改为 strace -e inject=read:error=EIO ...,即可看到 read(...) = -1 EIO (Input/output error) (INJECTED)(见 5.27)。

② 现代 coreutils 走 newfstatat,早期工具走 stat/fstat 现象:Ubuntu 22.04 自带 coreutils 9.x,strace ls / 默认输出里是 newfstatat/openat/AT_EMPTY_PATH。 原因/定位:coreutils 9.x 改用更原子化、支持 AT_EMPTY_PATH 的 newfstatat,-v 展开可见完整 stat 结构(见 5.24)。 解决:无需处理;只是同一命令在不同 coreutils 版本下输出调用不同,排查时留意。(CentOS 8 coreutils 8.x 仍用 stat/fstat,详见 CentOS 版文档「六」。)

③ -x 打印非 ASCII 字符串为十六进制 现象:中文文件名 /root/中文测试.txt 在 -x 下以 \x2f\x72\x6f... 十六进制转义显示。 原因/定位:strace 会把不可打印/非 ASCII 字节转义;UTF-8 汉字 中文测试 对应 \xe4\xb8\xad\xe6\x96\x87...。 解决:需要人类可读时去掉 -x,需要机器可比较/精确匹配路径时加 -x(见 5.25)。

④ -c -S calls 的汇总段在末尾,需用 tail 截取 现象:初始实测中 -c -S calls 只看到目录名列表,未看到排序汇总。 原因/定位:汇总表打印在标准错误输出的末尾,夹在程序自身输出之后,未翻页即被忽略。 解决:用 strace -c -S calls ls / 2>&1 | tail -n 15 捕获末尾 total 段(见 5.29)。

⑤ -A -o 追加模式:行数递增验证 现象:首次 -A -o 写入 1 行,再执行一次后变成 2 行。 原因/定位:-A 以追加方式打开输出文件,不截断旧内容。 解决:确认即可,常用于多轮采集累积到同一文件(见 5.33)。

⑥ --seccomp-bpf 需 -f 配合,否则自动禁用 现象:不带 -f 时输出 --seccomp-bpf cannot be used without -f/--follow-forks, disabling。 原因/定位:seccomp 加速依赖对所有 fork 进程的统一过滤路径,未开启 -f 时无法成立。 解决:需要该优化时加 -f,否则接受自动禁用(见 5.32)。

七、命令与参数速查表

参数/命令含义实测说明/默认值
strace <cmd>默认全量跟踪打印每个系统调用;默认 -s 32、无时间戳
-c汇总统计各调用列:时间%/耗时/calls/errors;本机 ls / 共 76 成功 + 7 出错
-c -w汇总按系统时间(sys time)统计剔除了 I/O 等待的墙钟干扰
-e trace=<syscall>只跟踪指定单个调用实测 openat
-e trace=%file文件类调用集openat/access/newfstatat 等
-e trace=%network网络类调用集socket/bind/connect 等
-e trace=%process进程类调用集execve/vfork/wait4 等
-e trace=%desc文件描述符类调用集openat/close/read 等
-e trace=%memory内存类调用集brk/mmap/mprotect 等
-f跟踪子进程clone/fork 产生 [pid N] 前缀
-ff -o <前缀>每进程独立文件生成 <前缀>.<pid>
-p <pid>附加运行中进程显示 attached/detached
-o <file>输出到文件实测 /tmp/strace.out
-s <n>字符串截断长度默认 32,实测 8
-T显示每次调用耗时追加 <0.000xxx> 秒
-t / -tt / -ttt时间戳;微秒;epoch 微秒三级精度可选
-r相邻调用相对时间秒级小数
-yy【详细】解码 fd 归属含设备类型/号,如 <char 1:3>
-y解码 fd 路径如 write(1</dev/null>...)
-z只显示成功调用失败被过滤
-Z只显示失败调用聚焦错误,如 ENOENT
-i显示指令指针地址[00007dab...]
-v完整展开结构体配合 newfstatat 见全字段 stat
-x非 ASCII 字符串十六进制中文路径转 \xe4...
-k打印内核/调用栈Ubuntu 用 libunwind 回溯
-e inject=...:error=<e>故障注入失败码参数名 error= 而非 errno=;输出含 (INJECTED)
-e signal=<sig>只跟踪信号如 SIGALRM
-S calls汇总按调用次数排序配合 -c,汇总在末尾用 tail
-b <syscall>在指定调用处分离实测 -b execve
-Dtracer 与 tracee 分离运行tracee 独立、自行退出
--seccomp-bpfseccomp 加速过滤需 -f,否则自动禁用
-A追加模式(配合 -o)实测 1 行→2 行递增

八、卸载方式

strace 为系统自带工具,如需完全移除(含配置文件)使用 purge:

sudo apt-get remove -y strace
# 如需连配置文件一并清除:
sudo apt-get purge -y strace
sudo apt-get autoremove -y
Ubuntu 22.04 strace 安装与命令参数详解 - Quzuo