xref: /aosp_15_r20/external/bcc/tools/filelife.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python
2*387f9dfdSAndroid Build Coastguard Worker# @lint-avoid-python-3-compatibility-imports
3*387f9dfdSAndroid Build Coastguard Worker#
4*387f9dfdSAndroid Build Coastguard Worker# filelife    Trace the lifespan of short-lived files.
5*387f9dfdSAndroid Build Coastguard Worker#             For Linux, uses BCC, eBPF. Embedded C.
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker# This traces the creation and deletion of files, providing information
8*387f9dfdSAndroid Build Coastguard Worker# on who deleted the file, the file age, and the file name. The intent is to
9*387f9dfdSAndroid Build Coastguard Worker# provide information on short-lived files, for debugging or performance
10*387f9dfdSAndroid Build Coastguard Worker# analysis.
11*387f9dfdSAndroid Build Coastguard Worker#
12*387f9dfdSAndroid Build Coastguard Worker# USAGE: filelife [-h] [-p PID]
13*387f9dfdSAndroid Build Coastguard Worker#
14*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc.
15*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
16*387f9dfdSAndroid Build Coastguard Worker#
17*387f9dfdSAndroid Build Coastguard Worker# 08-Feb-2015   Brendan Gregg   Created this.
18*387f9dfdSAndroid Build Coastguard Worker# 17-Feb-2016   Allan McAleavy updated for BPF_PERF_OUTPUT
19*387f9dfdSAndroid Build Coastguard Worker# 13-Nov-2022   Rong Tao        Check btf struct field for CO-RE and add vfs_open()
20*387f9dfdSAndroid Build Coastguard Worker
21*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
22*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
23*387f9dfdSAndroid Build Coastguard Workerimport argparse
24*387f9dfdSAndroid Build Coastguard Workerfrom time import strftime
25*387f9dfdSAndroid Build Coastguard Worker
26*387f9dfdSAndroid Build Coastguard Worker# arguments
27*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
28*387f9dfdSAndroid Build Coastguard Worker    ./filelife           # trace lifecycle of file(create->remove)
29*387f9dfdSAndroid Build Coastguard Worker    ./filelife -p 181    # only trace PID 181
30*387f9dfdSAndroid Build Coastguard Worker"""
31*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
32*387f9dfdSAndroid Build Coastguard Worker    description="Trace lifecycle of file",
33*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
34*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
35*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid",
36*387f9dfdSAndroid Build Coastguard Worker    help="trace this PID only")
37*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("--ebpf", action="store_true",
38*387f9dfdSAndroid Build Coastguard Worker    help=argparse.SUPPRESS)
39*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args()
40*387f9dfdSAndroid Build Coastguard Workerdebug = 0
41*387f9dfdSAndroid Build Coastguard Worker
42*387f9dfdSAndroid Build Coastguard Worker# define BPF program
43*387f9dfdSAndroid Build Coastguard Workerbpf_text = """
44*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
45*387f9dfdSAndroid Build Coastguard Worker#include <linux/fs.h>
46*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h>
47*387f9dfdSAndroid Build Coastguard Worker
48*387f9dfdSAndroid Build Coastguard Workerstruct data_t {
49*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
50*387f9dfdSAndroid Build Coastguard Worker    u64 delta;
51*387f9dfdSAndroid Build Coastguard Worker    char comm[TASK_COMM_LEN];
52*387f9dfdSAndroid Build Coastguard Worker    char fname[DNAME_INLINE_LEN];
53*387f9dfdSAndroid Build Coastguard Worker};
54*387f9dfdSAndroid Build Coastguard Worker
55*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(birth, struct dentry *);
56*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(events);
57*387f9dfdSAndroid Build Coastguard Worker
58*387f9dfdSAndroid Build Coastguard Workerstatic int probe_dentry(struct pt_regs *ctx, struct dentry *dentry)
59*387f9dfdSAndroid Build Coastguard Worker{
60*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid() >> 32;
61*387f9dfdSAndroid Build Coastguard Worker    FILTER
62*387f9dfdSAndroid Build Coastguard Worker
63*387f9dfdSAndroid Build Coastguard Worker    u64 ts = bpf_ktime_get_ns();
64*387f9dfdSAndroid Build Coastguard Worker    birth.update(&dentry, &ts);
65*387f9dfdSAndroid Build Coastguard Worker
66*387f9dfdSAndroid Build Coastguard Worker    return 0;
67*387f9dfdSAndroid Build Coastguard Worker}
68*387f9dfdSAndroid Build Coastguard Worker
69*387f9dfdSAndroid Build Coastguard Worker// trace file creation time
70*387f9dfdSAndroid Build Coastguard WorkerTRACE_CREATE_FUNC
71*387f9dfdSAndroid Build Coastguard Worker{
72*387f9dfdSAndroid Build Coastguard Worker    return probe_dentry(ctx, dentry);
73*387f9dfdSAndroid Build Coastguard Worker};
74*387f9dfdSAndroid Build Coastguard Worker
75*387f9dfdSAndroid Build Coastguard Worker// trace file security_inode_create time
76*387f9dfdSAndroid Build Coastguard Workerint trace_security_inode_create(struct pt_regs *ctx, struct inode *dir,
77*387f9dfdSAndroid Build Coastguard Worker        struct dentry *dentry)
78*387f9dfdSAndroid Build Coastguard Worker{
79*387f9dfdSAndroid Build Coastguard Worker    return probe_dentry(ctx, dentry);
80*387f9dfdSAndroid Build Coastguard Worker};
81*387f9dfdSAndroid Build Coastguard Worker
82*387f9dfdSAndroid Build Coastguard Worker// trace file open time
83*387f9dfdSAndroid Build Coastguard Workerint trace_open(struct pt_regs *ctx, struct path *path, struct file *file)
84*387f9dfdSAndroid Build Coastguard Worker{
85*387f9dfdSAndroid Build Coastguard Worker    struct dentry *dentry = path->dentry;
86*387f9dfdSAndroid Build Coastguard Worker
87*387f9dfdSAndroid Build Coastguard Worker    if (!(file->f_mode & FMODE_CREATED)) {
88*387f9dfdSAndroid Build Coastguard Worker        return 0;
89*387f9dfdSAndroid Build Coastguard Worker    }
90*387f9dfdSAndroid Build Coastguard Worker
91*387f9dfdSAndroid Build Coastguard Worker    return probe_dentry(ctx, dentry);
92*387f9dfdSAndroid Build Coastguard Worker};
93*387f9dfdSAndroid Build Coastguard Worker
94*387f9dfdSAndroid Build Coastguard Worker// trace file deletion and output details
95*387f9dfdSAndroid Build Coastguard WorkerTRACE_UNLINK_FUNC
96*387f9dfdSAndroid Build Coastguard Worker{
97*387f9dfdSAndroid Build Coastguard Worker    struct data_t data = {};
98*387f9dfdSAndroid Build Coastguard Worker    u32 pid = bpf_get_current_pid_tgid() >> 32;
99*387f9dfdSAndroid Build Coastguard Worker
100*387f9dfdSAndroid Build Coastguard Worker    FILTER
101*387f9dfdSAndroid Build Coastguard Worker
102*387f9dfdSAndroid Build Coastguard Worker    u64 *tsp, delta;
103*387f9dfdSAndroid Build Coastguard Worker    tsp = birth.lookup(&dentry);
104*387f9dfdSAndroid Build Coastguard Worker    if (tsp == 0) {
105*387f9dfdSAndroid Build Coastguard Worker        return 0;   // missed create
106*387f9dfdSAndroid Build Coastguard Worker    }
107*387f9dfdSAndroid Build Coastguard Worker
108*387f9dfdSAndroid Build Coastguard Worker    delta = (bpf_ktime_get_ns() - *tsp) / 1000000;
109*387f9dfdSAndroid Build Coastguard Worker    birth.delete(&dentry);
110*387f9dfdSAndroid Build Coastguard Worker
111*387f9dfdSAndroid Build Coastguard Worker    struct qstr d_name = dentry->d_name;
112*387f9dfdSAndroid Build Coastguard Worker    if (d_name.len == 0)
113*387f9dfdSAndroid Build Coastguard Worker        return 0;
114*387f9dfdSAndroid Build Coastguard Worker
115*387f9dfdSAndroid Build Coastguard Worker    if (bpf_get_current_comm(&data.comm, sizeof(data.comm)) == 0) {
116*387f9dfdSAndroid Build Coastguard Worker        data.pid = pid;
117*387f9dfdSAndroid Build Coastguard Worker        data.delta = delta;
118*387f9dfdSAndroid Build Coastguard Worker        bpf_probe_read_kernel(&data.fname, sizeof(data.fname), d_name.name);
119*387f9dfdSAndroid Build Coastguard Worker    }
120*387f9dfdSAndroid Build Coastguard Worker
121*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &data, sizeof(data));
122*387f9dfdSAndroid Build Coastguard Worker
123*387f9dfdSAndroid Build Coastguard Worker    return 0;
124*387f9dfdSAndroid Build Coastguard Worker}
125*387f9dfdSAndroid Build Coastguard Worker"""
126*387f9dfdSAndroid Build Coastguard Worker
127*387f9dfdSAndroid Build Coastguard Workertrace_create_text_1="""
128*387f9dfdSAndroid Build Coastguard Workerint trace_create(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry)
129*387f9dfdSAndroid Build Coastguard Worker"""
130*387f9dfdSAndroid Build Coastguard Workertrace_create_text_2="""
131*387f9dfdSAndroid Build Coastguard Workerint trace_create(struct pt_regs *ctx, struct user_namespace *mnt_userns,
132*387f9dfdSAndroid Build Coastguard Worker        struct inode *dir, struct dentry *dentry)
133*387f9dfdSAndroid Build Coastguard Worker"""
134*387f9dfdSAndroid Build Coastguard Workertrace_create_text_3="""
135*387f9dfdSAndroid Build Coastguard Workerint trace_create(struct pt_regs *ctx, struct mnt_idmap *idmap,
136*387f9dfdSAndroid Build Coastguard Worker        struct inode *dir, struct dentry *dentry)
137*387f9dfdSAndroid Build Coastguard Worker"""
138*387f9dfdSAndroid Build Coastguard Worker
139*387f9dfdSAndroid Build Coastguard Workertrace_unlink_text_1="""
140*387f9dfdSAndroid Build Coastguard Workerint trace_unlink(struct pt_regs *ctx, struct inode *dir, struct dentry *dentry)
141*387f9dfdSAndroid Build Coastguard Worker"""
142*387f9dfdSAndroid Build Coastguard Workertrace_unlink_text_2="""
143*387f9dfdSAndroid Build Coastguard Workerint trace_unlink(struct pt_regs *ctx, struct user_namespace *mnt_userns,
144*387f9dfdSAndroid Build Coastguard Worker        struct inode *dir, struct dentry *dentry)
145*387f9dfdSAndroid Build Coastguard Worker"""
146*387f9dfdSAndroid Build Coastguard Workertrace_unlink_text_3="""
147*387f9dfdSAndroid Build Coastguard Workerint trace_unlink(struct pt_regs *ctx, struct mnt_idmap *idmap,
148*387f9dfdSAndroid Build Coastguard Worker        struct inode *dir, struct dentry *dentry)
149*387f9dfdSAndroid Build Coastguard Worker"""
150*387f9dfdSAndroid Build Coastguard Worker
151*387f9dfdSAndroid Build Coastguard Workerif args.pid:
152*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER',
153*387f9dfdSAndroid Build Coastguard Worker        'if (pid != %s) { return 0; }' % args.pid)
154*387f9dfdSAndroid Build Coastguard Workerelse:
155*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER', '')
156*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf:
157*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
158*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
159*387f9dfdSAndroid Build Coastguard Worker        exit()
160*387f9dfdSAndroid Build Coastguard Worker
161*387f9dfdSAndroid Build Coastguard Workerif BPF.kernel_struct_has_field(b'renamedata', b'new_mnt_idmap') == 1:
162*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('TRACE_CREATE_FUNC', trace_create_text_3)
163*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('TRACE_UNLINK_FUNC', trace_unlink_text_3)
164*387f9dfdSAndroid Build Coastguard Workerelif BPF.kernel_struct_has_field(b'renamedata', b'old_mnt_userns') == 1:
165*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('TRACE_CREATE_FUNC', trace_create_text_2)
166*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('TRACE_UNLINK_FUNC', trace_unlink_text_2)
167*387f9dfdSAndroid Build Coastguard Workerelse:
168*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('TRACE_CREATE_FUNC', trace_create_text_1)
169*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('TRACE_UNLINK_FUNC', trace_unlink_text_1)
170*387f9dfdSAndroid Build Coastguard Worker
171*387f9dfdSAndroid Build Coastguard Worker# initialize BPF
172*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text)
173*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_create", fn_name="trace_create")
174*387f9dfdSAndroid Build Coastguard Worker# newer kernels may don't fire vfs_create, call vfs_open instead:
175*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_open", fn_name="trace_open")
176*387f9dfdSAndroid Build Coastguard Worker# newer kernels (say, 4.8) may don't fire vfs_create, so record (or overwrite)
177*387f9dfdSAndroid Build Coastguard Worker# the timestamp in security_inode_create():
178*387f9dfdSAndroid Build Coastguard Workerif BPF.get_kprobe_functions(b"security_inode_create"):
179*387f9dfdSAndroid Build Coastguard Worker    b.attach_kprobe(event="security_inode_create", fn_name="trace_security_inode_create")
180*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event="vfs_unlink", fn_name="trace_unlink")
181*387f9dfdSAndroid Build Coastguard Worker
182*387f9dfdSAndroid Build Coastguard Worker# header
183*387f9dfdSAndroid Build Coastguard Workerprint("%-8s %-7s %-16s %-7s %s" % ("TIME", "PID", "COMM", "AGE(s)", "FILE"))
184*387f9dfdSAndroid Build Coastguard Worker
185*387f9dfdSAndroid Build Coastguard Worker# process event
186*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size):
187*387f9dfdSAndroid Build Coastguard Worker    event = b["events"].event(data)
188*387f9dfdSAndroid Build Coastguard Worker    print("%-8s %-7d %-16s %-7.2f %s" % (strftime("%H:%M:%S"), event.pid,
189*387f9dfdSAndroid Build Coastguard Worker        event.comm.decode('utf-8', 'replace'), float(event.delta) / 1000,
190*387f9dfdSAndroid Build Coastguard Worker        event.fname.decode('utf-8', 'replace')))
191*387f9dfdSAndroid Build Coastguard Worker
192*387f9dfdSAndroid Build Coastguard Workerb["events"].open_perf_buffer(print_event)
193*387f9dfdSAndroid Build Coastguard Workerwhile 1:
194*387f9dfdSAndroid Build Coastguard Worker    try:
195*387f9dfdSAndroid Build Coastguard Worker        b.perf_buffer_poll()
196*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
197*387f9dfdSAndroid Build Coastguard Worker        exit()
198