我正在尝试使用strace
来了解Erlang VM如何使用writev
。我对系统调用知之甚少,而且我正在努力理解我所看到的内容。
在this article中,作者展示了一个跟踪一个小的Erlang程序的例子,该程序写入文件,并看到如下系统调用:
writev(0x1A, 0x1A5405F8, 0x4)
他接着解释说,writev
被赋予了向量的内存地址,该向量包含更多的内存地址。据推测,操作系统然后从这些地址获取数据并将其放入文件中。
我自己尝试了作者的例子 - 在名为iex
的Elixir repl中运行相同的代码(在Ubunto 12.04 VM中),并按照以下方式进行跟踪:
# show me system calls for process 1166...
# ... and show long output if necessary (the -s flag)
# ... and also trace any child processes (the -f flag)
# ... and I only care about calls to writev (the -e flag)
# ... and capture standard error to a file (the >(tee ...))
strace -p 1166 -s 99999 -f -e writev 2> >(tee syscalls.txt)
然而,我得到的输出看起来像这样:
writev(11, [{"Hello ", 6}, {"&", 1}, {"amp;", 4}, {" Goodbye", 8}], 4) = 19
我将其读作:“到文件描述符11,写下以下4个字符串,每个字符串的长度,总共19个字节。”
但为什么我会看到实际的字符串值而不是内存地址?这是否暗示数据是以某种方式被复制而不是通过地址引用,或者我只是以某种方式错误地显示它?
当我writev
这个过程时,为什么我看不到strace
的内存地址?
答案 0 :(得分:1)
strace不断变得更好。现在,它不是记录一个短暂的数组地址,而是实际告诉您正在编写的内容,这会在您的日志中留下有用的信息。
你可以尝试使用旗帜进行预测,以便用-e verbose=!writev
来消除冗长 - 请注意根据你的外壳需要引用和/或逃避!
- (可能只是给出你支持你的短暂数组地址,就像你引用的例子一样)并用-e raw=writev
翻转原始显示,看看你得到了什么。
您还可以调查附加调试器并拦截writev
调用。这将让你四处寻找并检查从进程发送到内核的数据。 (如果您手头有dtrace
这样的动态跟踪实用程序,那么也可以让您做类似的事情,但不会停止这个世界。)