xref: /aosp_15_r20/external/bcc/tools/filegone.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/python
2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports
3*387f9dfdSAndroid Build Coastguard Worker#
4*387f9dfdSAndroid Build Coastguard Worker# filegone    Trace why file gone (deleted or renamed).
5*387f9dfdSAndroid Build Coastguard Worker#             For Linux, uses BCC, eBPF. Embedded C.
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker# USAGE: filegone [-h] [-p PID]
8*387f9dfdSAndroid Build Coastguard Worker#
9*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
10*387f9dfdSAndroid Build Coastguard Worker#
11*387f9dfdSAndroid Build Coastguard Worker# 08-Nov-2022 Curu. modified from filelife
12*387f9dfdSAndroid Build Coastguard Worker# 19-Nov-2022 Rong Tao Check btf struct field instead of KERNEL_VERSION macro.
13*387f9dfdSAndroid Build Coastguard Worker
14*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
15*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
16*387f9dfdSAndroid Build Coastguard Workerimport argparse
17*387f9dfdSAndroid Build Coastguard Workerfrom time import strftime
18*387f9dfdSAndroid Build Coastguard Worker
19*387f9dfdSAndroid Build Coastguard Worker# arguments
20*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
21*387f9dfdSAndroid Build Coastguard Worker    ./filegone           # trace all file gone events
22*387f9dfdSAndroid Build Coastguard Worker    ./filegone -p 181    # only trace PID 181
23*387f9dfdSAndroid Build Coastguard Worker"""
24*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
25*387f9dfdSAndroid Build Coastguard Worker    description="Trace why file gone (deleted or renamed)",
26*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
27*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
28*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid",
29*387f9dfdSAndroid Build Coastguard Worker    help="trace this PID only")
30*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
31*387f9dfdSAndroid Build Coastguard Worker    help=argparse.SUPPRESS)
32*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
33*387f9dfdSAndroid Build Coastguard Workerdebug = 0
34*387f9dfdSAndroid Build Coastguard Worker
35*387f9dfdSAndroid Build Coastguard Worker# define BPF program
36*387f9dfdSAndroid Build Coastguard Workerbpf_text = """
37*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
38*387f9dfdSAndroid Build Coastguard Worker#include <linux/fs.h>
39*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h>
40*387f9dfdSAndroid Build Coastguard Worker
41*387f9dfdSAndroid Build Coastguard Workerstruct data_t {
42*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
43*387f9dfdSAndroid Build Coastguard Worker    u8 action;
44*387f9dfdSAndroid Build Coastguard Worker    char comm[TASK_COMM_LEN];
45*387f9dfdSAndroid Build Coastguard Worker    char fname[DNAME_INLINE_LEN];
46*387f9dfdSAndroid Build Coastguard Worker    char fname2[DNAME_INLINE_LEN];
47*387f9dfdSAndroid Build Coastguard Worker};
48*387f9dfdSAndroid Build Coastguard Worker
49*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(events);
50*387f9dfdSAndroid Build Coastguard Worker
51*387f9dfdSAndroid Build Coastguard Worker// trace file deletion and output details
52*387f9dfdSAndroid Build Coastguard WorkerTRACE_VFS_UNLINK_FUNC
53*387f9dfdSAndroid Build Coastguard Worker{
54*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid() >> 32;
55*387f9dfdSAndroid Build Coastguard Worker
56*387f9dfdSAndroid Build Coastguard Worker    FILTER
57*387f9dfdSAndroid Build Coastguard Worker
58*387f9dfdSAndroid Build Coastguard Worker    struct data_t data = {};
59*387f9dfdSAndroid Build Coastguard Worker    struct qstr d_name = dentry->d_name;
60*387f9dfdSAndroid Build Coastguard Worker    if (d_name.len == 0)
61*387f9dfdSAndroid Build Coastguard Worker        return 0;
62*387f9dfdSAndroid Build Coastguard Worker
63*387f9dfdSAndroid Build Coastguard Worker    bpf_get_current_comm(&data.comm, sizeof(data.comm));
64*387f9dfdSAndroid Build Coastguard Worker    data.pid = pid;
65*387f9dfdSAndroid Build Coastguard Worker    data.action = 'D';
66*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read(&data.fname, sizeof(data.fname), d_name.name);
67*387f9dfdSAndroid Build Coastguard Worker
68*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &data, sizeof(data));
69*387f9dfdSAndroid Build Coastguard Worker
70*387f9dfdSAndroid Build Coastguard Worker    return 0;
71*387f9dfdSAndroid Build Coastguard Worker}
72*387f9dfdSAndroid Build Coastguard Worker
73*387f9dfdSAndroid Build Coastguard Worker// trace file rename
74*387f9dfdSAndroid Build Coastguard WorkerTRACE_VFS_RENAME_FUNC
75*387f9dfdSAndroid Build Coastguard Worker
76*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid() >> 32;
77*387f9dfdSAndroid Build Coastguard Worker
78*387f9dfdSAndroid Build Coastguard Worker    FILTER
79*387f9dfdSAndroid Build Coastguard Worker
80*387f9dfdSAndroid Build Coastguard Worker    struct data_t data = {};
81*387f9dfdSAndroid Build Coastguard Worker    struct qstr s_name = old_dentry->d_name;
82*387f9dfdSAndroid Build Coastguard Worker    struct qstr d_name = new_dentry->d_name;
83*387f9dfdSAndroid Build Coastguard Worker    if (s_name.len == 0 || d_name.len == 0)
84*387f9dfdSAndroid Build Coastguard Worker        return 0;
85*387f9dfdSAndroid Build Coastguard Worker
86*387f9dfdSAndroid Build Coastguard Worker    bpf_get_current_comm(&data.comm, sizeof(data.comm));
87*387f9dfdSAndroid Build Coastguard Worker    data.pid = pid;
88*387f9dfdSAndroid Build Coastguard Worker    data.action = 'R';
89*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read(&data.fname, sizeof(data.fname), s_name.name);
90*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read(&data.fname2, sizeof(data.fname), d_name.name);
91*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &data, sizeof(data));
92*387f9dfdSAndroid Build Coastguard Worker
93*387f9dfdSAndroid Build Coastguard Worker    return 0;
94*387f9dfdSAndroid Build Coastguard Worker}
95*387f9dfdSAndroid Build Coastguard Worker"""
96*387f9dfdSAndroid Build Coastguard Worker
97*387f9dfdSAndroid Build Coastguard Workerbpf_vfs_rename_text_old="""
98*387f9dfdSAndroid Build Coastguard Workerint trace_rename(struct pt_regs *ctx, struct inode *old_dir, struct dentry *old_dentry,
99*387f9dfdSAndroid Build Coastguard Workerstruct inode *new_dir, struct dentry *new_dentry)
100*387f9dfdSAndroid Build Coastguard Worker{
101*387f9dfdSAndroid Build Coastguard Worker"""
102*387f9dfdSAndroid Build Coastguard Workerbpf_vfs_rename_text_new="""
103*387f9dfdSAndroid Build Coastguard Workerint trace_rename(struct pt_regs *ctx, struct renamedata *rd)
104*387f9dfdSAndroid Build Coastguard Worker{
105*387f9dfdSAndroid Build Coastguard Worker    struct dentry *old_dentry = rd->old_dentry;
106*387f9dfdSAndroid Build Coastguard Worker    struct dentry *new_dentry = rd->new_dentry;
107*387f9dfdSAndroid Build Coastguard Worker"""
108*387f9dfdSAndroid Build Coastguard Worker
109*387f9dfdSAndroid Build Coastguard Workerbpf_vfs_unlink_text_1="""
110*387f9dfdSAndroid Build Coastguard Workerint trace_unlink(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry)
111*387f9dfdSAndroid Build Coastguard Worker"""
112*387f9dfdSAndroid Build Coastguard Workerbpf_vfs_unlink_text_2="""
113*387f9dfdSAndroid Build Coastguard Workerint trace_unlink(struct pt_regs *ctx, struct user_namespace *ns, struct inode *dir, struct dentry *dentry)
114*387f9dfdSAndroid Build Coastguard Worker"""
115*387f9dfdSAndroid Build Coastguard Workerbpf_vfs_unlink_text_3="""
116*387f9dfdSAndroid Build Coastguard Workerint trace_unlink(struct pt_regs *ctx, struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry)
117*387f9dfdSAndroid Build Coastguard Worker"""
118*387f9dfdSAndroid Build Coastguard Worker
119*387f9dfdSAndroid Build Coastguard Workerdef action2str(action):
120*387f9dfdSAndroid Build Coastguard Worker    if chr(action) == 'D':
121*387f9dfdSAndroid Build Coastguard Worker        action_str = "DELETE"
122*387f9dfdSAndroid Build Coastguard Worker    else:
123*387f9dfdSAndroid Build Coastguard Worker        action_str = "RENAME"
124*387f9dfdSAndroid Build Coastguard Worker    return action_str
125*387f9dfdSAndroid Build Coastguard Worker
126*387f9dfdSAndroid Build Coastguard Workerif args.pid:
127*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER',
128*387f9dfdSAndroid Build Coastguard Worker        'if (pid != %s) { return 0; }' % args.pid)
129*387f9dfdSAndroid Build Coastguard Workerelse:
130*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER', '')
131*387f9dfdSAndroid Build Coastguard Worker
132*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf:
133*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
134*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
135*387f9dfdSAndroid Build Coastguard Worker        exit()
136*387f9dfdSAndroid Build Coastguard Worker
137*387f9dfdSAndroid Build Coastguard Worker# check 'struct renamedata' exist or not
138*387f9dfdSAndroid Build Coastguard Workerif BPF.kernel_struct_has_field(b'renamedata', b'new_mnt_idmap') == 1:
139*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('TRACE_VFS_RENAME_FUNC', bpf_vfs_rename_text_new)
140*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('TRACE_VFS_UNLINK_FUNC', bpf_vfs_unlink_text_3)
141*387f9dfdSAndroid Build Coastguard Workerelif BPF.kernel_struct_has_field("renamedata", "old_mnt_userns") == 1:
142*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('TRACE_VFS_RENAME_FUNC', bpf_vfs_rename_text_new)
143*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('TRACE_VFS_UNLINK_FUNC', bpf_vfs_unlink_text_2)
144*387f9dfdSAndroid Build Coastguard Workerelse:
145*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('TRACE_VFS_RENAME_FUNC', bpf_vfs_rename_text_old)
146*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('TRACE_VFS_UNLINK_FUNC', bpf_vfs_unlink_text_1)
147*387f9dfdSAndroid Build Coastguard Worker
148*387f9dfdSAndroid Build Coastguard Worker# initialize BPF
149*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text)
150*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_unlink", fn_name="trace_unlink")
151*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_rmdir", fn_name="trace_unlink")
152*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_rename", fn_name="trace_rename")
153*387f9dfdSAndroid Build Coastguard Worker
154*387f9dfdSAndroid Build Coastguard Worker# header
155*387f9dfdSAndroid Build Coastguard Workerprint("%-8s %-7s %-16s %6s %s" % ("TIME", "PID", "COMM", "ACTION", "FILE"))
156*387f9dfdSAndroid Build Coastguard Worker
157*387f9dfdSAndroid Build Coastguard Worker# process event
158*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size):
159*387f9dfdSAndroid Build Coastguard Worker    event = b["events"].event(data)
160*387f9dfdSAndroid Build Coastguard Worker    action_str = action2str(event.action)
161*387f9dfdSAndroid Build Coastguard Worker    file_str = event.fname.decode('utf-8', 'replace')
162*387f9dfdSAndroid Build Coastguard Worker    if action_str == "RENAME":
163*387f9dfdSAndroid Build Coastguard Worker        file_str = "%s > %s" % (file_str, event.fname2.decode('utf-8', 'replace'))
164*387f9dfdSAndroid Build Coastguard Worker    print("%-8s %-7d %-16s %6s %s" % (strftime("%H:%M:%S"), event.pid,
165*387f9dfdSAndroid Build Coastguard Worker        event.comm.decode('utf-8', 'replace'), action_str, file_str))
166*387f9dfdSAndroid Build Coastguard Worker
167*387f9dfdSAndroid Build Coastguard Workerb["events"].open_perf_buffer(print_event)
168*387f9dfdSAndroid Build Coastguard Workerwhile 1:
169*387f9dfdSAndroid Build Coastguard Worker    try:
170*387f9dfdSAndroid Build Coastguard Worker        b.perf_buffer_poll()
171*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
172*387f9dfdSAndroid Build Coastguard Worker        exit()
173