Home | History | Annotate | Download | only in old
      1 #!/usr/bin/python
      2 # @lint-avoid-python-3-compatibility-imports
      3 #
      4 # statsnoop Trace stat() syscalls.
      5 #           For Linux, uses BCC, eBPF. Embedded C.
      6 #
      7 # USAGE: statsnoop [-h] [-t] [-x] [-p PID]
      8 #
      9 # Copyright 2016 Netflix, Inc.
     10 # Licensed under the Apache License, Version 2.0 (the "License")
     11 #
     12 # 08-Feb-2016   Brendan Gregg   Created this.
     13 
     14 from __future__ import print_function
     15 from bcc import BPF
     16 import argparse
     17 
     18 # arguments
     19 examples = """examples:
     20     ./statsnoop           # trace all stat() syscalls
     21     ./statsnoop -t        # include timestamps
     22     ./statsnoop -x        # only show failed stats
     23     ./statsnoop -p 181    # only trace PID 181
     24 """
     25 parser = argparse.ArgumentParser(
     26     description="Trace stat() syscalls",
     27     formatter_class=argparse.RawDescriptionHelpFormatter,
     28     epilog=examples)
     29 parser.add_argument("-t", "--timestamp", action="store_true",
     30     help="include timestamp on output")
     31 parser.add_argument("-x", "--failed", action="store_true",
     32     help="only show failed stats")
     33 parser.add_argument("-p", "--pid",
     34     help="trace this PID only")
     35 args = parser.parse_args()
     36 debug = 0
     37 
     38 # define BPF program
     39 bpf_text = """
     40 #include <uapi/linux/ptrace.h>
     41 
     42 BPF_HASH(args_filename, u32, const char *);
     43 
     44 int trace_entry(struct pt_regs *ctx, const char __user *filename)
     45 {
     46     u32 pid = bpf_get_current_pid_tgid();
     47 
     48     FILTER
     49     args_filename.update(&pid, &filename);
     50 
     51     return 0;
     52 };
     53 
     54 int trace_return(struct pt_regs *ctx)
     55 {
     56     const char **filenamep;
     57     int ret = ctx->ax;
     58     u32 pid = bpf_get_current_pid_tgid();
     59 
     60     filenamep = args_filename.lookup(&pid);
     61     if (filenamep == 0) {
     62         // missed entry
     63         return 0;
     64     }
     65 
     66     bpf_trace_printk("%d %s\\n", ret, *filenamep);
     67     args_filename.delete(&pid);
     68 
     69     return 0;
     70 }
     71 """
     72 if args.pid:
     73     bpf_text = bpf_text.replace('FILTER',
     74         'if (pid != %s) { return 0; }' % args.pid)
     75 else:
     76     bpf_text = bpf_text.replace('FILTER', '')
     77 if debug:
     78     print(bpf_text)
     79 
     80 # initialize BPF
     81 b = BPF(text=bpf_text)
     82 b.attach_kprobe(event="sys_stat", fn_name="trace_entry")
     83 b.attach_kprobe(event="sys_statfs", fn_name="trace_entry")
     84 b.attach_kprobe(event="sys_newstat", fn_name="trace_entry")
     85 b.attach_kretprobe(event="sys_stat", fn_name="trace_return")
     86 b.attach_kretprobe(event="sys_statfs", fn_name="trace_return")
     87 b.attach_kretprobe(event="sys_newstat", fn_name="trace_return")
     88 
     89 # header
     90 if args.timestamp:
     91     print("%-14s" % ("TIME(s)"), end="")
     92 print("%-6s %-16s %4s %3s %s" % ("PID", "COMM", "FD", "ERR", "PATH"))
     93 
     94 start_ts = 0
     95 
     96 # format output
     97 while 1:
     98     (task, pid, cpu, flags, ts, msg) = b.trace_fields()
     99     (ret_s, filename) = msg.split(" ", 1)
    100 
    101     ret = int(ret_s)
    102     if (args.failed and (ret >= 0)):
    103         continue
    104 
    105     # split return value into FD and errno columns
    106     if ret >= 0:
    107         fd_s = ret
    108         err = 0
    109     else:
    110         fd_s = "-1"
    111         err = - ret
    112 
    113     # print columns
    114     if args.timestamp:
    115         if start_ts == 0:
    116             start_ts = ts
    117         print("%-14.9f" % (ts - start_ts), end="")
    118     print("%-6d %-16s %4s %3s %s" % (pid, task, fd_s, err, filename))
    119