4
4
# opensnoop Trace open() syscalls.
5
5
# For Linux, uses BCC, eBPF. Embedded C.
6
6
#
7
- # USAGE: opensnoop [-h] [-t ] [-x] [-p PID]
7
+ # USAGE: opensnoop [-h] [-T ] [-x] [-p PID] [-t TID] [-n NAME ]
8
8
#
9
9
# Copyright (c) 2015 Brendan Gregg.
10
10
# Licensed under the Apache License, Version 2.0 (the "License")
11
11
#
12
12
# 17-Sep-2015 Brendan Gregg Created this.
13
- # 29-Apr-2016 Allan McAleavy updated for BPF_PERF_OUTPUT
13
+ # 29-Apr-2016 Allan McAleavy Updated for BPF_PERF_OUTPUT.
14
+ # 08-Oct-2016 Dina Goldshtein Support filtering by PID and TID.
14
15
15
16
from __future__ import print_function
16
17
from bcc import BPF
20
21
# arguments
21
22
examples = """examples:
22
23
./opensnoop # trace all open() syscalls
23
- ./opensnoop -t # include timestamps
24
+ ./opensnoop -T # include timestamps
24
25
./opensnoop -x # only show failed opens
25
26
./opensnoop -p 181 # only trace PID 181
27
+ ./opensnoop -t 123 # only trace TID 123
26
28
./opensnoop -n main # only print process names containing "main"
27
29
"""
28
30
parser = argparse .ArgumentParser (
29
31
description = "Trace open() syscalls" ,
30
32
formatter_class = argparse .RawDescriptionHelpFormatter ,
31
33
epilog = examples )
32
- parser .add_argument ("-t " , "--timestamp" , action = "store_true" ,
34
+ parser .add_argument ("-T " , "--timestamp" , action = "store_true" ,
33
35
help = "include timestamp on output" )
34
36
parser .add_argument ("-x" , "--failed" , action = "store_true" ,
35
37
help = "only show failed opens" )
36
38
parser .add_argument ("-p" , "--pid" ,
37
39
help = "trace this PID only" )
40
+ parser .add_argument ("-t" , "--tid" ,
41
+ help = "trace this TID only" )
38
42
parser .add_argument ("-n" , "--name" ,
39
43
help = "only print process names containing this name" )
40
44
args = parser .parse_args ()
47
51
#include <linux/sched.h>
48
52
49
53
struct val_t {
50
- u32 pid ;
54
+ u64 id ;
51
55
u64 ts;
52
56
char comm[TASK_COMM_LEN];
53
57
const char *fname;
54
58
};
55
59
56
60
struct data_t {
57
- u32 pid ;
61
+ u64 id ;
58
62
u64 ts;
59
63
int ret;
60
64
char comm[TASK_COMM_LEN];
61
65
char fname[NAME_MAX];
62
66
};
63
67
64
- BPF_HASH(args_filename, u32, const char *);
65
- BPF_HASH(infotmp, u32, struct val_t);
68
+ BPF_HASH(infotmp, u64, struct val_t);
66
69
BPF_PERF_OUTPUT(events);
67
70
68
71
int trace_entry(struct pt_regs *ctx, const char __user *filename)
69
72
{
70
73
struct val_t val = {};
71
- u32 pid = bpf_get_current_pid_tgid();
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
72
77
73
78
FILTER
74
79
if (bpf_get_current_comm(&val.comm, sizeof(val.comm)) == 0) {
75
- val.pid = bpf_get_current_pid_tgid() ;
80
+ val.id = id ;
76
81
val.ts = bpf_ktime_get_ns();
77
82
val.fname = filename;
78
- infotmp.update(&pid , &val);
83
+ infotmp.update(&id , &val);
79
84
}
80
85
81
86
return 0;
82
87
};
83
88
84
89
int trace_return(struct pt_regs *ctx)
85
90
{
86
- u32 pid = bpf_get_current_pid_tgid();
91
+ u64 id = bpf_get_current_pid_tgid();
87
92
struct val_t *valp;
88
93
struct data_t data = {};
89
94
90
95
u64 tsp = bpf_ktime_get_ns();
91
96
92
- valp = infotmp.lookup(&pid );
97
+ valp = infotmp.lookup(&id );
93
98
if (valp == 0) {
94
99
// missed entry
95
100
return 0;
96
101
}
97
102
bpf_probe_read(&data.comm, sizeof(data.comm), valp->comm);
98
103
bpf_probe_read(&data.fname, sizeof(data.fname), (void *)valp->fname);
99
- data.pid = valp->pid ;
104
+ data.id = valp->id ;
100
105
data.ts = tsp / 1000;
101
106
data.ret = PT_REGS_RC(ctx);
102
107
103
108
events.perf_submit(ctx, &data, sizeof(data));
104
- infotmp.delete(&pid);
105
- args_filename.delete(&pid);
109
+ infotmp.delete(&id);
106
110
107
111
return 0;
108
112
}
109
113
"""
110
- if args .pid :
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 :
111
118
bpf_text = bpf_text .replace ('FILTER' ,
112
119
'if (pid != %s) { return 0; }' % args .pid )
113
120
else :
125
132
126
133
class Data (ct .Structure ):
127
134
_fields_ = [
128
- ("pid " , ct .c_ulonglong ),
135
+ ("id " , ct .c_ulonglong ),
129
136
("ts" , ct .c_ulonglong ),
130
137
("ret" , ct .c_int ),
131
138
("comm" , ct .c_char * TASK_COMM_LEN ),
@@ -137,7 +144,8 @@ class Data(ct.Structure):
137
144
# header
138
145
if args .timestamp :
139
146
print ("%-14s" % ("TIME(s)" ), end = "" )
140
- print ("%-6s %-16s %4s %3s %s" % ("PID" , "COMM" , "FD" , "ERR" , "PATH" ))
147
+ print ("%-6s %-16s %4s %3s %s" %
148
+ ("TID" if args .tid else "PID" , "COMM" , "FD" , "ERR" , "PATH" ))
141
149
142
150
# process event
143
151
def print_event (cpu , data , size ):
@@ -165,8 +173,9 @@ def print_event(cpu, data, size):
165
173
delta = event .ts - initial_ts
166
174
print ("%-14.9f" % (float (delta ) / 1000000 ), end = "" )
167
175
168
- print ("%-6d %-16s %4d %3d %s" % (event .pid , event .comm ,
169
- fd_s , err , event .fname ))
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 ))
170
179
171
180
# loop with callback to print_event
172
181
b ["events" ].open_perf_buffer (print_event )
0 commit comments