为什么 strace 不记录我的所有系统调用?

jon*_*our 5 linux debian strace

我正在尝试在运行 Debian 8.7 的 BeagleBone 上调试串行连接。为此,我用 go 编写了一个测试程序。我没有得到预期的结果,所以我启动了测试程序 strace。

果然,我期望看到的写入系统调用不存在。我检查了我的源代码,它们肯定应该在那里。测试程序基本上是这样的:

loop:
   write a log message to stderr
   write a buffer of binary 0x00 to the serial port 
   write a different log message to stderr
   write a buffer of binary 0xff to the serial port 
Run Code Online (Sandbox Code Playgroud)

该程序在 stderr 上生成如下所示的输出:

2015/11/12 21:28:45 111...
2015/11/12 21:28:46 000...
2015/11/12 21:28:48 111...
2015/11/12 21:28:49 000...
2015/11/12 21:28:51 111...
2015/11/12 21:28:52 000...
2015/11/12 21:28:54 111...
2015/11/12 21:28:55 000...
2015/11/12 21:28:57 111...
2015/11/12 21:28:58 000...
2015/11/12 21:29:00 111...
2015/11/12 21:29:01 000...
2015/11/12 21:29:03 111...
2015/11/12 21:29:04 000...
2015/11/12 21:29:06 111...
2015/11/12 21:29:07 000...
2015/11/12 21:29:09 111...
2015/11/12 21:29:10 000...
2015/11/12 21:29:12 111...
2015/11/12 21:29:13 000...
2015/11/12 21:29:15 111...
2015/11/12 21:29:16 000...
2015/11/12 21:29:18 111...
2015/11/12 21:29:19 000...
2015/11/12 21:29:21 111...
Run Code Online (Sandbox Code Playgroud)

然后我观察到并非所有对 stderr 的写入都出现在 strace 输出中。将会运行第一条日志消息,而不会运行第二条日志消息,而上述算法不会发生这种情况。以下是输出的摘录,通过 greping trace.log 进行过滤以进行写入。正如您所看到的,strace 条目比 stderr 中的行少得多,这表明 strace 并未记录实际进行的所有系统调用。

write(2, "2015/11/12 21:28:46 000...\n", 27) = 27
write(2, "2015/11/12 21:28:49 000...\n", 27) = 27
write(2, "2015/11/12 21:28:52 000...\n", 27) = 27
write(2, "2015/11/12 21:28:55 000...\n", 27) = 27
write(2, "2015/11/12 21:28:58 000...\n", 27) = 27
write(2, "2015/11/12 21:29:01 000...\n", 27) = 27
write(2, "2015/11/12 21:29:04 000...\n", 27) = 27
write(2, "2015/11/12 21:29:07 000...\n", 27) = 27
write(2, "2015/11/12 21:29:12 111...\n", 27) = 27
write(2, "2015/11/12 21:29:15 111...\n", 27) = 27
write(2, "2015/11/12 21:29:18 111...\n", 27) = 27
write(2, "2015/11/12 21:29:21 111...\n", 27) = 27
Run Code Online (Sandbox Code Playgroud)

我的源代码或我正在使用的任何 go 库中没有并发性,也没有任何子进程的分叉。

我检查了 strace 手册页,似乎没有任何方法可以指定系统调用的统计采样,也没有迹象表明它不会记录所有调用,除非您指定了过滤表达式(我没有指定)。

我不知道针对串行端口的写入系统调用是否确实发生,但现在我不能信任 strace 输出,因为它没有向我显示我所知道的所有系统调用。

谁能解释一下发生了什么事吗?

我的命令行是:

strace -o trace.log -v ./serial-test --device /dev/ttyO2 --oscillator --delay 500
Run Code Online (Sandbox Code Playgroud)

更新:一位朋友建议添加一个 -f 标志,这似乎确实有帮助。不清楚的是为什么,因为文档表明 -f 仅在调用 fork() 的情况下有用,而我的程序中没有这些(或者实际上,在 strace 输出中)。

好的,所以,联机帮助页还引用了clone(),并且Linux 线程是使用clone() 创建的。go 使用 Linux 线程,所以这解释了这个问题。

jon*_*our 6

这归结为以下事实:golang 自由使用线程,因此您需要使用strace -fflag 来跟踪 go 代表您创建的辅助线程。

因此,系统调用创建的子进程以及[ 和]创建的线程都strace -f需要该标志。我的错误是认为它只需要子进程。fork()clone()vfork()