在 Linux 上,我肯定会使用strace
-- 它简单而强大。例如:
$ strace -o/tmp/blah -f -eopen,read bash -c "cat ciao.txt"
运行请求的命令(包括它产生的子进程,由于-f
)并留下/tmp/blah
(在我的例子中为 120 行)详细说明这些进程进行的所有打开和读取调用及其结果。
之后您确实需要进行一些处理,以根据需要仅提取成功读取的文件集;例如,使用 Python,您可以执行以下操作:
import re
linere = re.compile(r'^(\d+)\s+(\w+)\(([^)]+)\)\s+\=\s*(.*)$')
def main():
openfiles = dict()
filesread = set()
with open('/tmp/blah') as f:
for line in f:
mo = linere.match(line)
if mo is None:
print "Unmatched line %r" % line
pid, command, args, results = mo.groups()
if command == 'open':
fn = args.split(',', 1)[0].strip('"')
fd = results.split(' ', 1)[0]
openfiles[fd] = fn
elif command == 'read':
if results != '0':
fd = args.split(',', 1)[0]
filesread.add(openfiles[fd])
else:
print "Unknown command %r" % command
print sorted(filesread)
这有点过于简单了(您需要查看其他一些系统调用,例如dup
&c),但我希望能说明所需工作的要点。在我的示例中,这会发出:
['/lib/libc.so.6', '/lib/libdl.so.2', '/lib/libncurses.so.5',
'/proc/meminfo', '/proc/sys/kernel/ngroups_max',
'/usr/share/locale/locale.alias', 'ciao.txt']
所以它也算作“读取”那些为获取动态库而完成的操作,而不仅仅是“数据文件”......在系统调用级别,几乎没有什么区别。我想你可以过滤掉非数据文件,如果你需要的话。
我发现strace
这样的目的非常方便,如果我被要求在 Windows 上做同样的工作,我的第一次尝试是选择StraceNT——不是 100% 兼容的,当然底层的系统调用名称 &c 不同,但我想我可以解释我的 Python 代码中的这些差异(准备和执行strace
命令,以及对结果进行后处理)。
不幸的是,据我所知,其他一些 Unix 系统仅在您是 root (超级用户)时才提供这种功能 - 例如,在 Mac OS X 上,您需要通过sudo
才能执行诸如dtrace
和dtruss
;之类的跟踪实用程序。我不知道strace
Mac 的直接端口,也不知道没有 root 权限执行此类任务的其他方法。