| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 1 | #!/usr/bin/python | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 2 | # @lint-avoid-python-3-compatibility-imports | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 3 | # | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 4 | # opensnoop Trace open() syscalls. | 
|  | 5 | #           For Linux, uses BCC, eBPF. Embedded C. | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 6 | # | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 7 | # USAGE: opensnoop [-h] [-T] [-x] [-p PID] [-t TID] [-n NAME] | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 8 | # | 
|  | 9 | # Copyright (c) 2015 Brendan Gregg. | 
|  | 10 | # Licensed under the Apache License, Version 2.0 (the "License") | 
|  | 11 | # | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 12 | # 17-Sep-2015   Brendan Gregg   Created this. | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 13 | # 29-Apr-2016   Allan McAleavy  Updated for BPF_PERF_OUTPUT. | 
|  | 14 | # 08-Oct-2016   Dina Goldshtein Support filtering by PID and TID. | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 15 |  | 
|  | 16 | from __future__ import print_function | 
|  | 17 | from bcc import BPF | 
|  | 18 | import argparse | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 19 | import ctypes as ct | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 20 |  | 
|  | 21 | # arguments | 
|  | 22 | examples = """examples: | 
|  | 23 | ./opensnoop           # trace all open() syscalls | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 24 | ./opensnoop -T        # include timestamps | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 25 | ./opensnoop -x        # only show failed opens | 
|  | 26 | ./opensnoop -p 181    # only trace PID 181 | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 27 | ./opensnoop -t 123    # only trace TID 123 | 
| KarimAllah Ahmed | 765dfe2 | 2016-09-10 12:01:07 +0200 | [diff] [blame] | 28 | ./opensnoop -n main   # only print process names containing "main" | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 29 | """ | 
|  | 30 | parser = argparse.ArgumentParser( | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 31 | description="Trace open() syscalls", | 
|  | 32 | formatter_class=argparse.RawDescriptionHelpFormatter, | 
|  | 33 | epilog=examples) | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 34 | parser.add_argument("-T", "--timestamp", action="store_true", | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 35 | help="include timestamp on output") | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 36 | parser.add_argument("-x", "--failed", action="store_true", | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 37 | help="only show failed opens") | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 38 | parser.add_argument("-p", "--pid", | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 39 | help="trace this PID only") | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 40 | parser.add_argument("-t", "--tid", | 
|  | 41 | help="trace this TID only") | 
| KarimAllah Ahmed | 765dfe2 | 2016-09-10 12:01:07 +0200 | [diff] [blame] | 42 | parser.add_argument("-n", "--name", | 
|  | 43 | help="only print process names containing this name") | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 44 | args = parser.parse_args() | 
|  | 45 | debug = 0 | 
|  | 46 |  | 
|  | 47 | # define BPF program | 
|  | 48 | bpf_text = """ | 
|  | 49 | #include <uapi/linux/ptrace.h> | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 50 | #include <uapi/linux/limits.h> | 
|  | 51 | #include <linux/sched.h> | 
|  | 52 |  | 
|  | 53 | struct val_t { | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 54 | u64 id; | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 55 | u64 ts; | 
|  | 56 | char comm[TASK_COMM_LEN]; | 
|  | 57 | const char *fname; | 
|  | 58 | }; | 
|  | 59 |  | 
|  | 60 | struct data_t { | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 61 | u64 id; | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 62 | u64 ts; | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 63 | int ret; | 
|  | 64 | char comm[TASK_COMM_LEN]; | 
|  | 65 | char fname[NAME_MAX]; | 
|  | 66 | }; | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 67 |  | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 68 | BPF_HASH(infotmp, u64, struct val_t); | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 69 | BPF_PERF_OUTPUT(events); | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 70 |  | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 71 | int trace_entry(struct pt_regs *ctx, const char __user *filename) | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 72 | { | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 73 | struct val_t val = {}; | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 74 | u64 id = bpf_get_current_pid_tgid(); | 
|  | 75 | u32 pid = id >> 32; // PID is higher part | 
|  | 76 | u32 tid = id;       // Cast and get the lower part | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 77 |  | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 78 | FILTER | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 79 | if (bpf_get_current_comm(&val.comm, sizeof(val.comm)) == 0) { | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 80 | val.id = id; | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 81 | val.ts = bpf_ktime_get_ns(); | 
|  | 82 | val.fname = filename; | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 83 | infotmp.update(&id, &val); | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 84 | } | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 85 |  | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 86 | return 0; | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 87 | }; | 
|  | 88 |  | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 89 | int trace_return(struct pt_regs *ctx) | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 90 | { | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 91 | u64 id = bpf_get_current_pid_tgid(); | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 92 | struct val_t *valp; | 
|  | 93 | struct data_t data = {}; | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 94 |  | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 95 | u64 tsp = bpf_ktime_get_ns(); | 
|  | 96 |  | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 97 | valp = infotmp.lookup(&id); | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 98 | if (valp == 0) { | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 99 | // missed entry | 
|  | 100 | return 0; | 
|  | 101 | } | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 102 | bpf_probe_read(&data.comm, sizeof(data.comm), valp->comm); | 
|  | 103 | bpf_probe_read(&data.fname, sizeof(data.fname), (void *)valp->fname); | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 104 | data.id = valp->id; | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 105 | data.ts = tsp / 1000; | 
| Naveen N. Rao | 4afa96a | 2016-05-03 14:54:21 +0530 | [diff] [blame] | 106 | data.ret = PT_REGS_RC(ctx); | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 107 |  | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 108 | events.perf_submit(ctx, &data, sizeof(data)); | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 109 | infotmp.delete(&id); | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 110 |  | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 111 | return 0; | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 112 | } | 
|  | 113 | """ | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 114 | if args.tid:  # TID trumps PID | 
|  | 115 | bpf_text = bpf_text.replace('FILTER', | 
|  | 116 | 'if (tid != %s) { return 0; }' % args.tid) | 
|  | 117 | elif args.pid: | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 118 | bpf_text = bpf_text.replace('FILTER', | 
|  | 119 | 'if (pid != %s) { return 0; }' % args.pid) | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 120 | else: | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 121 | bpf_text = bpf_text.replace('FILTER', '') | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 122 | if debug: | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 123 | print(bpf_text) | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 124 |  | 
|  | 125 | # initialize BPF | 
|  | 126 | b = BPF(text=bpf_text) | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 127 | b.attach_kprobe(event="sys_open", fn_name="trace_entry") | 
|  | 128 | b.attach_kretprobe(event="sys_open", fn_name="trace_return") | 
|  | 129 |  | 
|  | 130 | TASK_COMM_LEN = 16    # linux/sched.h | 
|  | 131 | NAME_MAX = 255        # linux/limits.h | 
|  | 132 |  | 
|  | 133 | class Data(ct.Structure): | 
|  | 134 | _fields_ = [ | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 135 | ("id", ct.c_ulonglong), | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 136 | ("ts", ct.c_ulonglong), | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 137 | ("ret", ct.c_int), | 
|  | 138 | ("comm", ct.c_char * TASK_COMM_LEN), | 
|  | 139 | ("fname", ct.c_char * NAME_MAX) | 
|  | 140 | ] | 
|  | 141 |  | 
| KarimAllah Ahmed | a17d1e8 | 2016-09-10 12:00:32 +0200 | [diff] [blame] | 142 | initial_ts = 0 | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 143 |  | 
|  | 144 | # header | 
|  | 145 | if args.timestamp: | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 146 | print("%-14s" % ("TIME(s)"), end="") | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 147 | print("%-6s %-16s %4s %3s %s" % | 
|  | 148 | ("TID" if args.tid else "PID", "COMM", "FD", "ERR", "PATH")) | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 149 |  | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 150 | # process event | 
|  | 151 | def print_event(cpu, data, size): | 
|  | 152 | event = ct.cast(data, ct.POINTER(Data)).contents | 
| KarimAllah Ahmed | a17d1e8 | 2016-09-10 12:00:32 +0200 | [diff] [blame] | 153 | global initial_ts | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 154 |  | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 155 | # split return value into FD and errno columns | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 156 | if event.ret >= 0: | 
|  | 157 | fd_s = event.ret | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 158 | err = 0 | 
|  | 159 | else: | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 160 | fd_s = -1 | 
|  | 161 | err = - event.ret | 
| Brendan Gregg | bedd150 | 2015-09-17 21:52:52 -0700 | [diff] [blame] | 162 |  | 
| KarimAllah Ahmed | a17d1e8 | 2016-09-10 12:00:32 +0200 | [diff] [blame] | 163 | if not initial_ts: | 
|  | 164 | initial_ts = event.ts | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 165 |  | 
| KarimAllah Ahmed | a17d1e8 | 2016-09-10 12:00:32 +0200 | [diff] [blame] | 166 | if args.failed and (event.ret >= 0): | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 167 | return | 
|  | 168 |  | 
| KarimAllah Ahmed | 765dfe2 | 2016-09-10 12:01:07 +0200 | [diff] [blame] | 169 | if args.name and args.name not in event.comm: | 
|  | 170 | return | 
|  | 171 |  | 
| Alexei Starovoitov | bdf0773 | 2016-01-14 10:09:20 -0800 | [diff] [blame] | 172 | if args.timestamp: | 
| KarimAllah Ahmed | a17d1e8 | 2016-09-10 12:00:32 +0200 | [diff] [blame] | 173 | delta = event.ts - initial_ts | 
|  | 174 | print("%-14.9f" % (float(delta) / 1000000), end="") | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 175 |  | 
| Dina Goldshtein | 99a3bc8 | 2016-10-10 21:37:36 +0300 | [diff] [blame] | 176 | print("%-6d %-16s %4d %3d %s" % | 
|  | 177 | (event.id & 0xffffffff if args.tid else event.id >> 32, | 
|  | 178 | event.comm, fd_s, err, event.fname)) | 
| mcaleavya | 3c446c7 | 2016-04-29 13:38:51 +0100 | [diff] [blame] | 179 |  | 
|  | 180 | # loop with callback to print_event | 
|  | 181 | b["events"].open_perf_buffer(print_event) | 
|  | 182 | while 1: | 
|  | 183 | b.kprobe_poll() |