xref: /aosp_15_r20/external/bcc/tools/statsnoop.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# statsnoop Trace stat() syscalls.
5*387f9dfdSAndroid Build Coastguard Worker#           For Linux, uses BCC, eBPF. Embedded C.
6*387f9dfdSAndroid Build Coastguard Worker#
7*387f9dfdSAndroid Build Coastguard Worker# USAGE: statsnoop [-h] [-t] [-x] [-p PID]
8*387f9dfdSAndroid Build Coastguard Worker#
9*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc.
10*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
11*387f9dfdSAndroid Build Coastguard Worker#
12*387f9dfdSAndroid Build Coastguard Worker# 08-Feb-2016   Brendan Gregg   Created this.
13*387f9dfdSAndroid Build Coastguard Worker# 17-Feb-2016   Allan McAleavy  updated for BPF_PERF_OUTPUT
14*387f9dfdSAndroid Build Coastguard Worker# 29-Nov-2022   Rocky Xing      Added stat() variants.
15*387f9dfdSAndroid Build Coastguard Worker
16*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function
17*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF
18*387f9dfdSAndroid Build Coastguard Workerimport argparse
19*387f9dfdSAndroid Build Coastguard Worker
20*387f9dfdSAndroid Build Coastguard Worker# arguments
21*387f9dfdSAndroid Build Coastguard Workerexamples = """examples:
22*387f9dfdSAndroid Build Coastguard Worker    ./statsnoop           # trace all stat() syscalls
23*387f9dfdSAndroid Build Coastguard Worker    ./statsnoop -t        # include timestamps
24*387f9dfdSAndroid Build Coastguard Worker    ./statsnoop -x        # only show failed stats
25*387f9dfdSAndroid Build Coastguard Worker    ./statsnoop -p 181    # only trace PID 181
26*387f9dfdSAndroid Build Coastguard Worker"""
27*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser(
28*387f9dfdSAndroid Build Coastguard Worker    description="Trace stat() syscalls",
29*387f9dfdSAndroid Build Coastguard Worker    formatter_class=argparse.RawDescriptionHelpFormatter,
30*387f9dfdSAndroid Build Coastguard Worker    epilog=examples)
31*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-t", "--timestamp", action="store_true",
32*387f9dfdSAndroid Build Coastguard Worker    help="include timestamp on output")
33*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-x", "--failed", action="store_true",
34*387f9dfdSAndroid Build Coastguard Worker    help="only show failed stats")
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 <uapi/linux/limits.h>
46*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h>
47*387f9dfdSAndroid Build Coastguard Worker
48*387f9dfdSAndroid Build Coastguard Workerstruct val_t {
49*387f9dfdSAndroid Build Coastguard Worker    const char *fname;
50*387f9dfdSAndroid Build Coastguard Worker};
51*387f9dfdSAndroid Build Coastguard Worker
52*387f9dfdSAndroid Build Coastguard Workerstruct data_t {
53*387f9dfdSAndroid Build Coastguard Worker    u32 pid;
54*387f9dfdSAndroid Build Coastguard Worker    u64 ts_ns;
55*387f9dfdSAndroid Build Coastguard Worker    int ret;
56*387f9dfdSAndroid Build Coastguard Worker    char comm[TASK_COMM_LEN];
57*387f9dfdSAndroid Build Coastguard Worker    char fname[NAME_MAX];
58*387f9dfdSAndroid Build Coastguard Worker};
59*387f9dfdSAndroid Build Coastguard Worker
60*387f9dfdSAndroid Build Coastguard WorkerBPF_HASH(infotmp, u32, struct val_t);
61*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(events);
62*387f9dfdSAndroid Build Coastguard Worker
63*387f9dfdSAndroid Build Coastguard Workerstatic int trace_entry(struct pt_regs *ctx, const char __user *filename)
64*387f9dfdSAndroid Build Coastguard Worker{
65*387f9dfdSAndroid Build Coastguard Worker    struct val_t val = {};
66*387f9dfdSAndroid Build Coastguard Worker    u64 pid_tgid = bpf_get_current_pid_tgid();
67*387f9dfdSAndroid Build Coastguard Worker    u32 pid = pid_tgid >> 32;
68*387f9dfdSAndroid Build Coastguard Worker    u32 tid = (u32)pid_tgid;
69*387f9dfdSAndroid Build Coastguard Worker
70*387f9dfdSAndroid Build Coastguard Worker    FILTER
71*387f9dfdSAndroid Build Coastguard Worker    val.fname = filename;
72*387f9dfdSAndroid Build Coastguard Worker    infotmp.update(&tid, &val);
73*387f9dfdSAndroid Build Coastguard Worker
74*387f9dfdSAndroid Build Coastguard Worker    return 0;
75*387f9dfdSAndroid Build Coastguard Worker};
76*387f9dfdSAndroid Build Coastguard Worker
77*387f9dfdSAndroid Build Coastguard Workerint syscall__stat_entry(struct pt_regs *ctx, const char __user *filename)
78*387f9dfdSAndroid Build Coastguard Worker{
79*387f9dfdSAndroid Build Coastguard Worker    return trace_entry(ctx, filename);
80*387f9dfdSAndroid Build Coastguard Worker}
81*387f9dfdSAndroid Build Coastguard Worker
82*387f9dfdSAndroid Build Coastguard Workerint syscall__statx_entry(struct pt_regs *ctx, int dfd, const char __user *filename)
83*387f9dfdSAndroid Build Coastguard Worker{
84*387f9dfdSAndroid Build Coastguard Worker    return trace_entry(ctx, filename);
85*387f9dfdSAndroid Build Coastguard Worker}
86*387f9dfdSAndroid Build Coastguard Worker
87*387f9dfdSAndroid Build Coastguard Workerint trace_return(struct pt_regs *ctx)
88*387f9dfdSAndroid Build Coastguard Worker{
89*387f9dfdSAndroid Build Coastguard Worker    u64 pid_tgid = bpf_get_current_pid_tgid();
90*387f9dfdSAndroid Build Coastguard Worker    u32 tid = (u32)pid_tgid;
91*387f9dfdSAndroid Build Coastguard Worker    struct val_t *valp;
92*387f9dfdSAndroid Build Coastguard Worker
93*387f9dfdSAndroid Build Coastguard Worker    valp = infotmp.lookup(&tid);
94*387f9dfdSAndroid Build Coastguard Worker    if (valp == 0) {
95*387f9dfdSAndroid Build Coastguard Worker        // missed entry
96*387f9dfdSAndroid Build Coastguard Worker        return 0;
97*387f9dfdSAndroid Build Coastguard Worker    }
98*387f9dfdSAndroid Build Coastguard Worker
99*387f9dfdSAndroid Build Coastguard Worker    struct data_t data = {.pid = pid_tgid >> 32};
100*387f9dfdSAndroid Build Coastguard Worker    bpf_probe_read_user(&data.fname, sizeof(data.fname), (void *)valp->fname);
101*387f9dfdSAndroid Build Coastguard Worker    bpf_get_current_comm(&data.comm, sizeof(data.comm));
102*387f9dfdSAndroid Build Coastguard Worker    data.ts_ns = bpf_ktime_get_ns();
103*387f9dfdSAndroid Build Coastguard Worker    data.ret = PT_REGS_RC(ctx);
104*387f9dfdSAndroid Build Coastguard Worker
105*387f9dfdSAndroid Build Coastguard Worker    events.perf_submit(ctx, &data, sizeof(data));
106*387f9dfdSAndroid Build Coastguard Worker    infotmp.delete(&tid);
107*387f9dfdSAndroid Build Coastguard Worker
108*387f9dfdSAndroid Build Coastguard Worker    return 0;
109*387f9dfdSAndroid Build Coastguard Worker}
110*387f9dfdSAndroid Build Coastguard Worker"""
111*387f9dfdSAndroid Build Coastguard Workerif args.pid:
112*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER',
113*387f9dfdSAndroid Build Coastguard Worker        'if (pid != %s) { return 0; }' % args.pid)
114*387f9dfdSAndroid Build Coastguard Workerelse:
115*387f9dfdSAndroid Build Coastguard Worker    bpf_text = bpf_text.replace('FILTER', '')
116*387f9dfdSAndroid Build Coastguard Workerif debug or args.ebpf:
117*387f9dfdSAndroid Build Coastguard Worker    print(bpf_text)
118*387f9dfdSAndroid Build Coastguard Worker    if args.ebpf:
119*387f9dfdSAndroid Build Coastguard Worker        exit()
120*387f9dfdSAndroid Build Coastguard Worker
121*387f9dfdSAndroid Build Coastguard Worker# initialize BPF
122*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text)
123*387f9dfdSAndroid Build Coastguard Worker
124*387f9dfdSAndroid Build Coastguard Worker# for POSIX compliance, all architectures implement these
125*387f9dfdSAndroid Build Coastguard Worker# system calls but the name of the actual entry point may
126*387f9dfdSAndroid Build Coastguard Worker# be different for which we must check if the entry points
127*387f9dfdSAndroid Build Coastguard Worker# actually exist before attaching the probes
128*387f9dfdSAndroid Build Coastguard Workerdef try_attach_syscall_probes(syscall):
129*387f9dfdSAndroid Build Coastguard Worker    syscall_fnname = b.get_syscall_fnname(syscall)
130*387f9dfdSAndroid Build Coastguard Worker    if BPF.ksymname(syscall_fnname) != -1:
131*387f9dfdSAndroid Build Coastguard Worker        if syscall in ["statx", "fstatat64", "newfstatat"]:
132*387f9dfdSAndroid Build Coastguard Worker            b.attach_kprobe(event=syscall_fnname, fn_name="syscall__statx_entry")
133*387f9dfdSAndroid Build Coastguard Worker        else:
134*387f9dfdSAndroid Build Coastguard Worker            b.attach_kprobe(event=syscall_fnname, fn_name="syscall__stat_entry")
135*387f9dfdSAndroid Build Coastguard Worker        b.attach_kretprobe(event=syscall_fnname, fn_name="trace_return")
136*387f9dfdSAndroid Build Coastguard Worker
137*387f9dfdSAndroid Build Coastguard Workertry_attach_syscall_probes("stat")
138*387f9dfdSAndroid Build Coastguard Workertry_attach_syscall_probes("statx")
139*387f9dfdSAndroid Build Coastguard Workertry_attach_syscall_probes("statfs")
140*387f9dfdSAndroid Build Coastguard Workertry_attach_syscall_probes("newstat")
141*387f9dfdSAndroid Build Coastguard Workertry_attach_syscall_probes("newlstat")
142*387f9dfdSAndroid Build Coastguard Workertry_attach_syscall_probes("fstatat64")
143*387f9dfdSAndroid Build Coastguard Workertry_attach_syscall_probes("newfstatat")
144*387f9dfdSAndroid Build Coastguard Worker
145*387f9dfdSAndroid Build Coastguard Workerstart_ts = 0
146*387f9dfdSAndroid Build Coastguard Workerprev_ts = 0
147*387f9dfdSAndroid Build Coastguard Workerdelta = 0
148*387f9dfdSAndroid Build Coastguard Worker
149*387f9dfdSAndroid Build Coastguard Worker# header
150*387f9dfdSAndroid Build Coastguard Workerif args.timestamp:
151*387f9dfdSAndroid Build Coastguard Worker    print("%-14s" % ("TIME(s)"), end="")
152*387f9dfdSAndroid Build Coastguard Workerprint("%-7s %-16s %4s %3s %s" % ("PID", "COMM", "FD", "ERR", "PATH"))
153*387f9dfdSAndroid Build Coastguard Worker
154*387f9dfdSAndroid Build Coastguard Worker# process event
155*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size):
156*387f9dfdSAndroid Build Coastguard Worker    event = b["events"].event(data)
157*387f9dfdSAndroid Build Coastguard Worker    global start_ts
158*387f9dfdSAndroid Build Coastguard Worker    global prev_ts
159*387f9dfdSAndroid Build Coastguard Worker    global delta
160*387f9dfdSAndroid Build Coastguard Worker    global cont
161*387f9dfdSAndroid Build Coastguard Worker
162*387f9dfdSAndroid Build Coastguard Worker    # split return value into FD and errno columns
163*387f9dfdSAndroid Build Coastguard Worker    if event.ret >= 0:
164*387f9dfdSAndroid Build Coastguard Worker        if args.failed:
165*387f9dfdSAndroid Build Coastguard Worker            return
166*387f9dfdSAndroid Build Coastguard Worker        fd_s = event.ret
167*387f9dfdSAndroid Build Coastguard Worker        err = 0
168*387f9dfdSAndroid Build Coastguard Worker    else:
169*387f9dfdSAndroid Build Coastguard Worker        fd_s = -1
170*387f9dfdSAndroid Build Coastguard Worker        err = - event.ret
171*387f9dfdSAndroid Build Coastguard Worker
172*387f9dfdSAndroid Build Coastguard Worker    if start_ts == 0:
173*387f9dfdSAndroid Build Coastguard Worker        start_ts = event.ts_ns
174*387f9dfdSAndroid Build Coastguard Worker
175*387f9dfdSAndroid Build Coastguard Worker    if args.timestamp:
176*387f9dfdSAndroid Build Coastguard Worker        print("%-14.9f" % (float(event.ts_ns - start_ts) / 1000000000), end="")
177*387f9dfdSAndroid Build Coastguard Worker
178*387f9dfdSAndroid Build Coastguard Worker    print("%-7d %-16s %4d %3d %s" % (event.pid,
179*387f9dfdSAndroid Build Coastguard Worker        event.comm.decode('utf-8', 'replace'), fd_s, err,
180*387f9dfdSAndroid Build Coastguard Worker        event.fname.decode('utf-8', 'replace')))
181*387f9dfdSAndroid Build Coastguard Worker
182*387f9dfdSAndroid Build Coastguard Worker# loop with callback to print_event
183*387f9dfdSAndroid Build Coastguard Workerb["events"].open_perf_buffer(print_event, page_cnt=64)
184*387f9dfdSAndroid Build Coastguard Workerwhile 1:
185*387f9dfdSAndroid Build Coastguard Worker    try:
186*387f9dfdSAndroid Build Coastguard Worker        b.perf_buffer_poll()
187*387f9dfdSAndroid Build Coastguard Worker    except KeyboardInterrupt:
188*387f9dfdSAndroid Build Coastguard Worker        exit()
189