lcc/pylcc/pytool/filelife.py (39 lines of code) (raw):

# -*- coding: utf-8 -*- # cython:language_level=3 """ ------------------------------------------------- File Name: filelife Description : Author : liaozhaoyan date: 2021/11/6 ------------------------------------------------- Change Activity: 2021/11/6: ------------------------------------------------- """ __author__ = 'liaozhaoyan' import argparse from time import strftime from pylcc.lbcBase import ClbcBase, CeventThread bpfProg = r""" #include "lbc.h" #define TASK_COMM_LEN 16 #define DNAME_INLINE_LEN 32 struct data_t { u32 pid; u64 delta; char comm[TASK_COMM_LEN]; char fname[DNAME_INLINE_LEN]; }; LBC_HASH(birth, struct dentry *, u64, 1024); LBC_PERF_OUTPUT(events, struct data_t, 128); // trace file creation time SEC("kprobe/vfs_create") int j_vfs_create(struct pt_regs *ctx) { u32 pid = bpf_get_current_pid_tgid() >> 32; struct dentry *dentry = (struct dentry *)PT_REGS_PARM2(ctx); FILTER u64 ts = bpf_ktime_get_ns(); bpf_map_update_elem(&birth, &dentry, &ts, BPF_ANY); return 0; }; SEC("kprobe/security_inode_create") int j_security_inode_create(struct pt_regs *ctx) { u32 pid = bpf_get_current_pid_tgid() >> 32; struct dentry *dentry = (struct dentry *)PT_REGS_PARM2(ctx); FILTER u64 ts = bpf_ktime_get_ns(); bpf_map_update_elem(&birth, &dentry, &ts, BPF_ANY); return 0; }; // trace file deletion and output details SEC("kprobe/vfs_unlink") int j_vfs_unlink(struct pt_regs *ctx) { struct data_t data = {}; u32 pid = bpf_get_current_pid_tgid() >> 32; struct dentry *dentry = (struct dentry *)PT_REGS_PARM2(ctx); FILTER u64 *tsp, delta; tsp = bpf_map_lookup_elem(&birth, &dentry); if (tsp == 0) { return 0; // missed create } delta = (bpf_ktime_get_ns() - *tsp) / 1000000; struct qstr d_name; d_name = BPF_CORE_READ(dentry, d_name); if (d_name.len == 0) return 0; if (bpf_get_current_comm(&data.comm, sizeof(data.comm)) == 0) { data.pid = pid; data.delta = delta; bpf_probe_read_kernel(&data.fname, sizeof(data.fname), d_name.name); } bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &data, sizeof(data)); return 0; } char _license[] SEC("license") = "GPL"; """ class CfileLife(ClbcBase): def __init__(self): super(CfileLife, self).__init__("filelife", bpf_str=bpfProg) print("%-8s %-6s %-16s %-7s %s" % ("TIME", "PID", "COMM", "AGE(s)", "FILE")) def _cb(self, cpu, e): print("%-8s %-6d %-16s %-7.2f %s" % (strftime("%H:%M:%S"), e.pid, e.comm, float(e.delta) / 1000, e.fname)) def loop(self): CeventThread(self, 'events', self._cb) self.waitInterrupt() if __name__ == "__main__": # arguments examples = """examples: ./filelife # trace all stat() syscalls ./filelife -p 181 # only trace PID 181 """ parser = argparse.ArgumentParser( description="Trace stat() syscalls", formatter_class=argparse.RawDescriptionHelpFormatter, epilog=examples) parser.add_argument("-p", "--pid", help="trace this PID only") parser.add_argument("--ebpf", action="store_true", help=argparse.SUPPRESS) args = parser.parse_args() debug = 0 if args.pid: bpfProg = bpfProg.replace('FILTER', 'if (pid != %s) { return 0; }' % args.pid) else: bpfProg = bpfProg.replace('FILTER', '') if debug or args.ebpf: print(bpfProg) if args.ebpf: exit() f = CfileLife() f.loop()