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