从 strace 日志中过滤掉失败的系统调用

Nat*_*ver 6 system-calls strace

我可以运行strace类似的命令sleep 1 并查看它正在访问哪些文件,如下所示:

strace -e trace=file -o strace.log sleep 1
Run Code Online (Sandbox Code Playgroud)

然而,在我的机器上,许多调用的返回值为-1,表明该文件不存在。例如:

$ grep '= -1 ENOENT' strace.log | head
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.UTF-8/LC_IDENTIFICATION", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.UTF-8/LC_MEASUREMENT", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.UTF-8/LC_TELEPHONE", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.UTF-8/LC_ADDRESS", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.UTF-8/LC_NAME", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
open("/usr/lib/locale/en_US.UTF-8/LC_PAPER", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
Run Code Online (Sandbox Code Playgroud)

我对不存在的文件并不真正感兴趣,我想知道进程实际找到并读取了哪些文件。除了 之外grep -v '=-1 ENOENT',我怎样才能可靠地过滤掉失败的呼叫?

附录

我很惊讶地发现,strace自 2002 年以来,该功能已以标志的形式出现-z,它是 的别名,自版本 5.2 ( 2019-07-12-e status=successful ) 起功能齐全,自版本 5.6 ( 2020- )起也可用04-07)。--successful-only

-z自版本 5.2 起也可用,该标志是 的补充-Z,它是 的别名-e status=failed,自版本 5.6 起可用--failed-only

-z标志首次在 2002 年的提交中添加,并在版本 4.5.18 ( 2008-08-28 ) 中发布,但从未被记录在案因为它无法正常工作。

相关链接:

Ste*_*itt 4

除了对输出进行后处理之外strace,\xe2\x80\x99t 中没有任何可用于忽略失败的系统调用的东西strace。添加\xe2\x80\x99不会太难,syscall_exiting_trace看看syscall.c.

\n\n

如果您\xe2\x80\x99d 宁愿追求后处理角度,Ole Tange已经以比您\xe2\x80\x99 可能到达这里更全面的方式为您解决了这个问题:该tracefile工具将运行strace并过滤以易于阅读的方式输出您\xe2\x80\x99 所需的信息。有关详细信息,请参阅列出程序访问的文件该问题的另一个答案列出了其他可能的方法,包括我认为非常有用的LoggedFS 。

\n\n

另一种选择是使用SystemTap;例如

\n\n
#!/usr/bin/env stap\n\nglobal stored_filename, stored_path\n\nprobe syscall.open {\n  stored_filename = filename\n}\n\nprobe syscall.open.return {\n  if (execname() == "cat" && $return >= 0) {\n    printf("opened %s\\n", stored_filename)\n  }\n}\n\nprobe syscall.openat {\n  stored_filename = filename\n  stored_path = dfd_str\n}\n\nprobe syscall.openat.return {\n  if (execname() == "cat" && $return >= 0) {\n    printf("opened %s in %s\\n", stored_filename, stored_path)\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

将显示任何进程成功打开的任何文件的名称cat

\n