在 Debian(或其他 Linux)系统上监控 readdir(或其底层实现的 getdents / getdents64 系统调用)的调用情况,通常有几种不同层次、不同目的的做法。下面从常用到进阶给你一个比较完整的说明。
在 glibc 里,readdir(3) 是 用户态函数,底层实际使用的是:
getdents(32 位)getdents64(64 位)因此:
readdir:通常监控 getdents / getdents64readdir():需要用户态追踪(如 ltrace)strace -e trace=getdents,getdents64 -p <PID>
或者启动一个新进程:
strace -e trace=getdents,getdents64 ls /
示例输出:
getdents64(3, /* 18 entries */, 32768) = 496
getdents64(3, /* 0 entries */, 32768) = 0
fd 是关键:
strace -e trace=getdents,getdents64 -y ls /
输出示例:
getdents64(3</proc/self/fd>, /* 5 entries */, 32768) = 100
如果你想直接看到 readdir() 函数调用(而不是系统调用):
ltrace -e readdir ls /
⚠ 注意:
ltrace 对静态链接程序无效sudo apt install auditd
sudo auditctl -a always,exit -S getdents -S getdents64 -F arch=b64 -k readdir_monitor
sudo ausearch -k readdir_monitor
示例:
type=SYSCALL msg=audit(...): arch=c000003e syscall=217 success=yes
⚠ 注意:
sudo apt install bpftrace
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_getdents64 {
printf("pid=%d comm=%s fd=%d\n", pid, comm, args->fd);
}'
sudo bpftrace -e '
tracepoint:syscalls:sys_enter_getdents64 {
printf("pid=%d %s fd=%d\n", pid, comm, args->fd);
// 可结合 bpf_probe_read 读取 fd 对应路径(复杂)
}'
✅ 优点:
配合 strace 或 bpftrace,看到 fd 后:
ls -l /proc/<PID>/fd/<fd>
或:
readlink /proc/<PID>/fd/<fd>
如果你是开发者:
gdb ./your_program
break readdir
run
#define _GNU_SOURCE
#include <dirent.h>
#include <dlfcn.h>
#include <stdio.h>
struct dirent *readdir(DIR *dirp) {
static struct dirent *(*real_readdir)(DIR *) = NULL;
if (!real_readdir)
real_readdir = dlsym(RTLD_NEXT, "readdir");
struct dirent *entry = real_readdir(dirp);
if (entry)
fprintf(stderr, "readdir: %s\n", entry->d_name);
return entry;
}
编译:
gcc -shared -fPIC -o readdir_hook.so readdir_hook.c -ldl
使用:
LD_PRELOAD=./readdir_hook.so ls
| 方法 | 能看到什么 | 是否推荐 |
|---|---|---|
| strace | 系统调用级 | ✅✅✅ |
| ltrace | readdir 函数 | ✅ |
| auditd | 系统级审计 | ✅(安全) |
| bpftrace | 高性能系统级 | ✅✅✅ |
| gdb | 调试 | ✅ |
| LD_PRELOAD | 自定义拦截 | ✅(开发) |
你可以告诉我:
是想排查性能问题、做安全审计,还是调试自己的程序?