http://bugs.winehq.org/show_bug.cgi?id=24101
--- Comment #31 from Ken Thomases ken@codeweavers.com 2010-09-11 03:48:03 CDT --- Created an attachment (id=30697) --> (http://bugs.winehq.org/attachment.cgi?id=30697) Version of dtruss which tracks file descriptors
I was inspired by this bug to put together something I've been thinking about for a while. It's a dtrace-based script for tracking file descriptors.
It's built from the dtruss script that ships with Mac OS X. The important change is that I've added a -F option to focus the tracing on file descriptors. This limits the tracing to those syscalls which open/create or close fds. It also reports the affected fd in the output.
One useful way to invoke it is: sudo dtruss -lsF -n wine >&/tmp/foo.log
The -l includes PID & TID in output. I have modified this to include a call sequence number within a thread. That's useful because DTrace reports data out of order. (Each CPU core fills its own buffer. When it's full, it sends it to userland and starts another. So, the data from a given core is in order with respect to itself, but may be out of order with respect to other cores.)
The -s includes stack traces for each call.
The "-n wine" traces processes whose executable name starts with "wine".
The -F restricts tracing to syscalls related to file descriptors. That includes those that open or create them (open(), dup(), socketpair(), etc.), the close() call, setting or clearing close-on-exec with fcntl(), and calls which implicitly duplicate or close them (execve() for close-on-exec fds, fork(), exit(), etc.).
For this bug, I have also made -F report syscalls which encounter EBADF, EPIPE, EMFILE, and ENFILE.
Fds are printed as <pid>:<fd> (e.g. 6502:11) so that the same fd in different processes can be easily distinguished. If something interesting happens to a particular fd, you can search for that pattern to find what opened or closed it. However, you might not find it that easily. For example, if an fd was inherited by a child process from its parent, to find the creation point you'd have to find the fork() to identify the parent and then look for the fd with respect to that pid.
Harder still is when an fd is received via recvmsg. The script does trace the fds sent by sendmsg, but it is not necessarily straightforward to identify which sendmsg was responsible for a given recvmsg. One potential solution might be to add a timestamp to the tracing. Dtruss supports that to some extent (-d), but I'm not sure the timestamp it uses is coherent across processes, threads, and CPU cores. I saw some weird results. I tried to add the ability to use a different timestamp, but the resulting program exceeded DTrace's limits.
Anyway, I hope it helps.