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

5
我正在尝试调试在运行Debian 8.7的BeagleBone上的串口连接。为此,我用go编写了一个测试程序。由于没有得到预期的结果,因此我在测试程序上启动了strace。
果然,我希望看到的write系统调用并没有出现。我检查了我的源代码,它们一定存在。测试程序基本上是这样的:
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 

该程序会在标准错误输出中生成以下内容:
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...

我注意到并非所有写入stderr的内容都出现在strace输出中。其中会有一些第一个日志信息的运行,但没有第二个日志信息,这是根据上述算法不可能发生的情况。下面是通过在trace.log中使用grep过滤write命令而提取的输出片段。你可以看到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

我的源码和使用的Go库中都没有并发,也没有任何子进程的分叉。

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

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

有人能解释一下发生了什么吗?

我的命令行是:

strace -o trace.log -v ./serial-test --device /dev/ttyO2 --oscillator --delay 500
更新: 一位朋友建议添加一个-f标志,这似乎有所帮助。不清楚的是为什么,因为文档表明-f只有在调用fork()时才有用,在我的程序中没有这样的调用(事实上,在strace输出中也没有)。
好的,那么,手册还提到了clone()和Linux线程是用clone()创建的。go使用Linux线程,这就解释了这个问题。
1个回答

6
这归结于golang广泛使用线程,因此您需要使用strace -f标志来跟踪go为您创建的辅助线程。strace -f标志对于由fork()系统调用创建的子进程以及由clone()[和vfork()]创建的线程都是必需的。我的错误在于认为它仅适用于子进程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接