blob: a56a691c3986d77ae4addbb86468000aa3eb95a4 [file] [log] [blame]
Sasha Goldshtein38847f02016-02-22 02:19:24 -08001#!/usr/bin/env python
2#
3# trace Trace a function and print a trace message based on its
4# parameters, with an optional filter.
5#
Sasha Goldshtein49d50ba2016-12-19 10:17:38 +00006# usage: trace [-h] [-p PID] [-L TID] [-v] [-Z STRING_SIZE] [-S]
7# [-M MAX_EVENTS] [-T] [-t] [-K] [-U] [-I header]
Mark Draytonaa6c9162016-11-03 15:36:29 +00008# probe [probe ...]
Sasha Goldshteinfd60d552016-03-01 12:15:34 -08009#
Sasha Goldshtein38847f02016-02-22 02:19:24 -080010# Licensed under the Apache License, Version 2.0 (the "License")
11# Copyright (C) 2016 Sasha Goldshtein.
12
Teng Qinc200b6c2017-12-16 00:15:55 -080013from __future__ import print_function
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +030014from bcc import BPF, USDT
Teng Qin6b0ed372016-09-29 21:30:13 -070015from functools import partial
Sasha Goldshtein38847f02016-02-22 02:19:24 -080016from time import sleep, strftime
17import argparse
18import re
19import ctypes as ct
20import os
21import traceback
22import sys
23
Sasha Goldshtein38847f02016-02-22 02:19:24 -080024class Probe(object):
25 probe_count = 0
Sasha Goldshteinf4797b02016-10-17 01:44:56 -070026 streq_index = 0
Sasha Goldshtein38847f02016-02-22 02:19:24 -080027 max_events = None
28 event_count = 0
29 first_ts = 0
Teng Qinc200b6c2017-12-16 00:15:55 -080030 print_time = False
Sasha Goldshtein38847f02016-02-22 02:19:24 -080031 use_localtime = True
Teng Qinc200b6c2017-12-16 00:15:55 -080032 time_field = False
33 print_cpu = False
Mark Draytonaa6c9162016-11-03 15:36:29 +000034 tgid = -1
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070035 pid = -1
Mark Drayton5f5687e2017-02-20 18:13:03 +000036 page_cnt = None
Sasha Goldshtein38847f02016-02-22 02:19:24 -080037
38 @classmethod
39 def configure(cls, args):
40 cls.max_events = args.max_events
Sasha Goldshtein49d50ba2016-12-19 10:17:38 +000041 cls.print_time = args.timestamp or args.time
42 cls.use_localtime = not args.timestamp
Teng Qinc200b6c2017-12-16 00:15:55 -080043 cls.time_field = cls.print_time and (not cls.use_localtime)
44 cls.print_cpu = args.print_cpu
Sasha Goldshtein60c41922017-02-09 04:19:53 -050045 cls.first_ts = BPF.monotonic_time()
Mark Draytonaa6c9162016-11-03 15:36:29 +000046 cls.tgid = args.tgid or -1
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070047 cls.pid = args.pid or -1
Mark Drayton5f5687e2017-02-20 18:13:03 +000048 cls.page_cnt = args.buffer_pages
Sasha Goldshtein38847f02016-02-22 02:19:24 -080049
Teng Qin6b0ed372016-09-29 21:30:13 -070050 def __init__(self, probe, string_size, kernel_stack, user_stack):
Sasha Goldshtein69e361a2016-09-27 19:40:00 +030051 self.usdt = None
Sasha Goldshteinf4797b02016-10-17 01:44:56 -070052 self.streq_functions = ""
Sasha Goldshtein38847f02016-02-22 02:19:24 -080053 self.raw_probe = probe
54 self.string_size = string_size
Teng Qin6b0ed372016-09-29 21:30:13 -070055 self.kernel_stack = kernel_stack
56 self.user_stack = user_stack
Sasha Goldshtein38847f02016-02-22 02:19:24 -080057 Probe.probe_count += 1
58 self._parse_probe()
59 self.probe_num = Probe.probe_count
60 self.probe_name = "probe_%s_%d" % \
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070061 (self._display_function(), self.probe_num)
Paul Chaignon956ca1c2017-03-04 20:07:56 +010062 self.probe_name = re.sub(r'[^A-Za-z0-9_]', '_',
63 self.probe_name)
Sasha Goldshtein38847f02016-02-22 02:19:24 -080064
65 def __str__(self):
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070066 return "%s:%s:%s FLT=%s ACT=%s/%s" % (self.probe_type,
67 self.library, self._display_function(), self.filter,
Sasha Goldshtein38847f02016-02-22 02:19:24 -080068 self.types, self.values)
69
70 def is_default_action(self):
71 return self.python_format == ""
72
73 def _bail(self, error):
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070074 raise ValueError("error in probe '%s': %s" %
Sasha Goldshtein38847f02016-02-22 02:19:24 -080075 (self.raw_probe, error))
76
77 def _parse_probe(self):
78 text = self.raw_probe
79
Sasha Goldshtein23e72b82017-01-17 08:49:36 +000080 # There might be a function signature preceding the actual
81 # filter/print part, or not. Find the probe specifier first --
82 # it ends with either a space or an open paren ( for the
83 # function signature part.
84 # opt. signature
85 # probespec | rest
86 # --------- ---------- --
87 (spec, sig, rest) = re.match(r'([^ \t\(]+)(\([^\(]*\))?(.*)',
88 text).groups()
Sasha Goldshtein38847f02016-02-22 02:19:24 -080089
Sasha Goldshtein23e72b82017-01-17 08:49:36 +000090 self._parse_spec(spec)
Paul Chaignon956ca1c2017-03-04 20:07:56 +010091 # Remove the parens
92 self.signature = sig[1:-1] if sig else None
Sasha Goldshtein23e72b82017-01-17 08:49:36 +000093 if self.signature and self.probe_type in ['u', 't']:
94 self._bail("USDT and tracepoint probes can't have " +
95 "a function signature; use arg1, arg2, " +
96 "... instead")
97
98 text = rest.lstrip()
Sasha Goldshtein38847f02016-02-22 02:19:24 -080099 # If we now have a (, wait for the balanced closing ) and that
100 # will be the predicate
101 self.filter = None
102 if len(text) > 0 and text[0] == "(":
103 balance = 1
104 for i in range(1, len(text)):
105 if text[i] == "(":
106 balance += 1
107 if text[i] == ")":
108 balance -= 1
109 if balance == 0:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300110 self._parse_filter(text[:i + 1])
111 text = text[i + 1:]
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800112 break
113 if self.filter is None:
114 self._bail("unmatched end of predicate")
115
116 if self.filter is None:
117 self.filter = "1"
118
119 # The remainder of the text is the printf action
120 self._parse_action(text.lstrip())
121
122 def _parse_spec(self, spec):
123 parts = spec.split(":")
124 # Two special cases: 'func' means 'p::func', 'lib:func' means
125 # 'p:lib:func'. Other combinations need to provide an empty
126 # value between delimiters, e.g. 'r::func' for a kretprobe on
127 # the function func.
128 if len(parts) == 1:
129 parts = ["p", "", parts[0]]
130 elif len(parts) == 2:
131 parts = ["p", parts[0], parts[1]]
132 if len(parts[0]) == 0:
133 self.probe_type = "p"
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700134 elif parts[0] in ["p", "r", "t", "u"]:
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800135 self.probe_type = parts[0]
136 else:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700137 self._bail("probe type must be '', 'p', 't', 'r', " +
138 "or 'u', but got '%s'" % parts[0])
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800139 if self.probe_type == "t":
140 self.tp_category = parts[1]
141 self.tp_event = parts[2]
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800142 self.library = "" # kernel
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300143 self.function = "" # from TRACEPOINT_PROBE
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700144 elif self.probe_type == "u":
vkhromov5a2b39e2017-07-14 20:42:29 +0100145 self.library = ':'.join(parts[1:-1])
146 self.usdt_name = parts[-1]
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700147 self.function = "" # no function, just address
148 # We will discover the USDT provider by matching on
149 # the USDT name in the specified library
150 self._find_usdt_probe()
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800151 else:
vkhromov5a2b39e2017-07-14 20:42:29 +0100152 self.library = ':'.join(parts[1:-1])
153 self.function = parts[-1]
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800154
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700155 def _find_usdt_probe(self):
Sasha Goldshteindd045362016-11-13 05:07:38 -0800156 target = Probe.pid if Probe.pid and Probe.pid != -1 \
157 else Probe.tgid
Mark Draytonaa6c9162016-11-03 15:36:29 +0000158 self.usdt = USDT(path=self.library, pid=target)
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300159 for probe in self.usdt.enumerate_probes():
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700160 if probe.name == self.usdt_name:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300161 return # Found it, will enable later
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700162 self._bail("unrecognized USDT probe %s" % self.usdt_name)
163
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800164 def _parse_filter(self, filt):
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700165 self.filter = self._rewrite_expr(filt)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800166
167 def _parse_types(self, fmt):
168 for match in re.finditer(
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300169 r'[^%]%(s|u|d|llu|lld|hu|hd|x|llx|c|K|U)', fmt):
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800170 self.types.append(match.group(1))
171 fmt = re.sub(r'([^%]%)(u|d|llu|lld|hu|hd)', r'\1d', fmt)
172 fmt = re.sub(r'([^%]%)(x|llx)', r'\1x', fmt)
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700173 fmt = re.sub('%K|%U', '%s', fmt)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800174 self.python_format = fmt.strip('"')
175
176 def _parse_action(self, action):
177 self.values = []
178 self.types = []
179 self.python_format = ""
180 if len(action) == 0:
181 return
182
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800183 action = action.strip()
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700184 match = re.search(r'(\".*?\"),?(.*)', action)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800185 if match is None:
186 self._bail("expected format string in \"s")
187
188 self.raw_format = match.group(1)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800189 self._parse_types(self.raw_format)
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700190 for part in re.split('(?<!"),', match.group(2)):
191 part = self._rewrite_expr(part)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800192 if len(part) > 0:
193 self.values.append(part)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800194
195 aliases = {
Naveen N. Rao4afa96a2016-05-03 14:54:21 +0530196 "retval": "PT_REGS_RC(ctx)",
197 "arg1": "PT_REGS_PARM1(ctx)",
198 "arg2": "PT_REGS_PARM2(ctx)",
199 "arg3": "PT_REGS_PARM3(ctx)",
200 "arg4": "PT_REGS_PARM4(ctx)",
201 "arg5": "PT_REGS_PARM5(ctx)",
202 "arg6": "PT_REGS_PARM6(ctx)",
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800203 "$uid": "(unsigned)(bpf_get_current_uid_gid() & 0xffffffff)",
204 "$gid": "(unsigned)(bpf_get_current_uid_gid() >> 32)",
205 "$pid": "(unsigned)(bpf_get_current_pid_tgid() & 0xffffffff)",
206 "$tgid": "(unsigned)(bpf_get_current_pid_tgid() >> 32)",
207 "$cpu": "bpf_get_smp_processor_id()"
208 }
209
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700210 def _generate_streq_function(self, string):
211 fname = "streq_%d" % Probe.streq_index
212 Probe.streq_index += 1
213 self.streq_functions += """
Sasha Goldshteinb9aec342017-01-16 18:41:22 +0000214static inline bool %s(char const *ignored, uintptr_t str) {
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700215 char needle[] = %s;
216 char haystack[sizeof(needle)];
217 bpf_probe_read(&haystack, sizeof(haystack), (void *)str);
Sasha Goldshteindcf16752017-01-17 07:40:57 +0000218 for (int i = 0; i < sizeof(needle) - 1; ++i) {
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700219 if (needle[i] != haystack[i]) {
220 return false;
221 }
222 }
223 return true;
224}
225 """ % (fname, string)
226 return fname
227
228 def _rewrite_expr(self, expr):
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800229 for alias, replacement in Probe.aliases.items():
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700230 # For USDT probes, we replace argN values with the
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300231 # actual arguments for that probe obtained using
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300232 # bpf_readarg_N macros emitted at BPF construction.
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700233 if alias.startswith("arg") and self.probe_type == "u":
234 continue
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800235 expr = expr.replace(alias, replacement)
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700236 matches = re.finditer('STRCMP\\(("[^"]+\\")', expr)
237 for match in matches:
238 string = match.group(1)
239 fname = self._generate_streq_function(string)
240 expr = expr.replace("STRCMP", fname, 1)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800241 return expr
242
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300243 p_type = {"u": ct.c_uint, "d": ct.c_int,
244 "llu": ct.c_ulonglong, "lld": ct.c_longlong,
245 "hu": ct.c_ushort, "hd": ct.c_short,
246 "x": ct.c_uint, "llx": ct.c_ulonglong, "c": ct.c_ubyte,
247 "K": ct.c_ulonglong, "U": ct.c_ulonglong}
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800248
249 def _generate_python_field_decl(self, idx, fields):
250 field_type = self.types[idx]
251 if field_type == "s":
252 ptype = ct.c_char * self.string_size
253 else:
254 ptype = Probe.p_type[field_type]
255 fields.append(("v%d" % idx, ptype))
256
257 def _generate_python_data_decl(self):
258 self.python_struct_name = "%s_%d_Data" % \
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700259 (self._display_function(), self.probe_num)
Teng Qinc200b6c2017-12-16 00:15:55 -0800260 fields = []
261 if self.time_field:
262 fields.append(("timestamp_ns", ct.c_ulonglong))
263 if self.print_cpu:
264 fields.append(("cpu", ct.c_int))
265 fields.extend([
Mark Draytonaa6c9162016-11-03 15:36:29 +0000266 ("tgid", ct.c_uint),
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800267 ("pid", ct.c_uint),
268 ("comm", ct.c_char * 16) # TASK_COMM_LEN
Teng Qinc200b6c2017-12-16 00:15:55 -0800269 ])
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800270 for i in range(0, len(self.types)):
271 self._generate_python_field_decl(i, fields)
Teng Qin6b0ed372016-09-29 21:30:13 -0700272 if self.kernel_stack:
273 fields.append(("kernel_stack_id", ct.c_int))
274 if self.user_stack:
275 fields.append(("user_stack_id", ct.c_int))
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800276 return type(self.python_struct_name, (ct.Structure,),
277 dict(_fields_=fields))
278
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300279 c_type = {"u": "unsigned int", "d": "int",
280 "llu": "unsigned long long", "lld": "long long",
281 "hu": "unsigned short", "hd": "short",
282 "x": "unsigned int", "llx": "unsigned long long",
283 "c": "char", "K": "unsigned long long",
284 "U": "unsigned long long"}
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800285 fmt_types = c_type.keys()
286
287 def _generate_field_decl(self, idx):
288 field_type = self.types[idx]
289 if field_type == "s":
290 return "char v%d[%d];\n" % (idx, self.string_size)
291 if field_type in Probe.fmt_types:
292 return "%s v%d;\n" % (Probe.c_type[field_type], idx)
293 self._bail("unrecognized format specifier %s" % field_type)
294
295 def _generate_data_decl(self):
296 # The BPF program will populate values into the struct
297 # according to the format string, and the Python program will
298 # construct the final display string.
299 self.events_name = "%s_events" % self.probe_name
300 self.struct_name = "%s_data_t" % self.probe_name
Teng Qin6b0ed372016-09-29 21:30:13 -0700301 self.stacks_name = "%s_stacks" % self.probe_name
302 stack_table = "BPF_STACK_TRACE(%s, 1024);" % self.stacks_name \
303 if (self.kernel_stack or self.user_stack) else ""
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800304 data_fields = ""
305 for i, field_type in enumerate(self.types):
306 data_fields += " " + \
307 self._generate_field_decl(i)
Teng Qinc200b6c2017-12-16 00:15:55 -0800308 time_str = "u64 timestamp_ns;" if self.time_field else ""
309 cpu_str = "int cpu;" if self.print_cpu else ""
Teng Qin6b0ed372016-09-29 21:30:13 -0700310 kernel_stack_str = " int kernel_stack_id;" \
311 if self.kernel_stack else ""
312 user_stack_str = " int user_stack_id;" \
313 if self.user_stack else ""
314
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800315 text = """
316struct %s
317{
Teng Qinc200b6c2017-12-16 00:15:55 -0800318%s
319%s
Mark Draytonaa6c9162016-11-03 15:36:29 +0000320 u32 tgid;
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800321 u32 pid;
322 char comm[TASK_COMM_LEN];
323%s
Teng Qin6b0ed372016-09-29 21:30:13 -0700324%s
325%s
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800326};
327
328BPF_PERF_OUTPUT(%s);
Teng Qin6b0ed372016-09-29 21:30:13 -0700329%s
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800330"""
Teng Qinc200b6c2017-12-16 00:15:55 -0800331 return text % (self.struct_name, time_str, cpu_str, data_fields,
Teng Qin6b0ed372016-09-29 21:30:13 -0700332 kernel_stack_str, user_stack_str,
333 self.events_name, stack_table)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800334
335 def _generate_field_assign(self, idx):
336 field_type = self.types[idx]
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300337 expr = self.values[idx].strip()
338 text = ""
339 if self.probe_type == "u" and expr[0:3] == "arg":
Sasha Goldshtein3a5256f2017-02-20 15:42:57 +0000340 arg_index = int(expr[3])
341 arg_ctype = self.usdt.get_probe_arg_ctype(
342 self.usdt_name, arg_index - 1)
343 text = (" %s %s = 0;\n" +
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300344 " bpf_usdt_readarg(%s, ctx, &%s);\n") \
Sasha Goldshtein3a5256f2017-02-20 15:42:57 +0000345 % (arg_ctype, expr, expr[3], expr)
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300346
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800347 if field_type == "s":
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300348 return text + """
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800349 if (%s != 0) {
350 bpf_probe_read(&__data.v%d, sizeof(__data.v%d), (void *)%s);
351 }
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300352 """ % (expr, idx, idx, expr)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800353 if field_type in Probe.fmt_types:
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300354 return text + " __data.v%d = (%s)%s;\n" % \
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800355 (idx, Probe.c_type[field_type], expr)
356 self._bail("unrecognized field type %s" % field_type)
357
Teng Qin0615bff2016-09-28 08:19:40 -0700358 def _generate_usdt_filter_read(self):
359 text = ""
Sasha Goldshteinb6300922017-01-16 18:43:11 +0000360 if self.probe_type != "u":
361 return text
362 for arg, _ in Probe.aliases.items():
363 if not (arg.startswith("arg") and
364 (arg in self.filter)):
365 continue
366 arg_index = int(arg.replace("arg", ""))
367 arg_ctype = self.usdt.get_probe_arg_ctype(
Sasha Goldshteindcf16752017-01-17 07:40:57 +0000368 self.usdt_name, arg_index - 1)
Sasha Goldshteinb6300922017-01-16 18:43:11 +0000369 if not arg_ctype:
370 self._bail("Unable to determine type of {} "
371 "in the filter".format(arg))
372 text += """
Teng Qin0615bff2016-09-28 08:19:40 -0700373 {} {}_filter;
374 bpf_usdt_readarg({}, ctx, &{}_filter);
Sasha Goldshteinb6300922017-01-16 18:43:11 +0000375 """.format(arg_ctype, arg, arg_index, arg)
376 self.filter = self.filter.replace(
377 arg, "{}_filter".format(arg))
Teng Qin0615bff2016-09-28 08:19:40 -0700378 return text
379
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700380 def generate_program(self, include_self):
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800381 data_decl = self._generate_data_decl()
Sasha Goldshteinb6300922017-01-16 18:43:11 +0000382 if Probe.pid != -1:
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800383 pid_filter = """
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800384 if (__pid != %d) { return 0; }
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300385 """ % Probe.pid
Sasha Goldshteinb6300922017-01-16 18:43:11 +0000386 # uprobes can have a built-in tgid filter passed to
387 # attach_uprobe, hence the check here -- for kprobes, we
388 # need to do the tgid test by hand:
Mark Draytonaa6c9162016-11-03 15:36:29 +0000389 elif len(self.library) == 0 and Probe.tgid != -1:
390 pid_filter = """
391 if (__tgid != %d) { return 0; }
392 """ % Probe.tgid
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800393 elif not include_self:
394 pid_filter = """
Mark Draytonaa6c9162016-11-03 15:36:29 +0000395 if (__tgid == %d) { return 0; }
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300396 """ % os.getpid()
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800397 else:
398 pid_filter = ""
399
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700400 prefix = ""
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700401 signature = "struct pt_regs *ctx"
Sasha Goldshtein23e72b82017-01-17 08:49:36 +0000402 if self.signature:
403 signature += ", " + self.signature
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700404
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800405 data_fields = ""
406 for i, expr in enumerate(self.values):
407 data_fields += self._generate_field_assign(i)
408
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300409 if self.probe_type == "t":
410 heading = "TRACEPOINT_PROBE(%s, %s)" % \
411 (self.tp_category, self.tp_event)
412 ctx_name = "args"
413 else:
414 heading = "int %s(%s)" % (self.probe_name, signature)
415 ctx_name = "ctx"
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300416
Teng Qinc200b6c2017-12-16 00:15:55 -0800417 time_str = """
418 __data.timestamp_ns = bpf_ktime_get_ns();""" if self.time_field else ""
419 cpu_str = """
420 __data.cpu = bpf_get_smp_processor_id();""" if self.print_cpu else ""
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300421 stack_trace = ""
422 if self.user_stack:
423 stack_trace += """
424 __data.user_stack_id = %s.get_stackid(
425 %s, BPF_F_REUSE_STACKID | BPF_F_USER_STACK
426 );""" % (self.stacks_name, ctx_name)
427 if self.kernel_stack:
428 stack_trace += """
429 __data.kernel_stack_id = %s.get_stackid(
430 %s, BPF_F_REUSE_STACKID
431 );""" % (self.stacks_name, ctx_name)
432
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300433 text = heading + """
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800434{
Mark Draytonaa6c9162016-11-03 15:36:29 +0000435 u64 __pid_tgid = bpf_get_current_pid_tgid();
436 u32 __tgid = __pid_tgid >> 32;
437 u32 __pid = __pid_tgid; // implicit cast to u32 for bottom half
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800438 %s
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800439 %s
Teng Qin0615bff2016-09-28 08:19:40 -0700440 %s
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800441 if (!(%s)) return 0;
442
443 struct %s __data = {0};
Teng Qinc200b6c2017-12-16 00:15:55 -0800444 %s
445 %s
Mark Draytonaa6c9162016-11-03 15:36:29 +0000446 __data.tgid = __tgid;
447 __data.pid = __pid;
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800448 bpf_get_current_comm(&__data.comm, sizeof(__data.comm));
449%s
Teng Qin6b0ed372016-09-29 21:30:13 -0700450%s
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300451 %s.perf_submit(%s, &__data, sizeof(__data));
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800452 return 0;
453}
454"""
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300455 text = text % (pid_filter, prefix,
Teng Qin0615bff2016-09-28 08:19:40 -0700456 self._generate_usdt_filter_read(), self.filter,
Teng Qinc200b6c2017-12-16 00:15:55 -0800457 self.struct_name, time_str, cpu_str, data_fields,
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300458 stack_trace, self.events_name, ctx_name)
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700459
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700460 return self.streq_functions + data_decl + "\n" + text
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800461
462 @classmethod
463 def _time_off_str(cls, timestamp_ns):
464 return "%.6f" % (1e-9 * (timestamp_ns - cls.first_ts))
465
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800466 def _display_function(self):
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700467 if self.probe_type == 'p' or self.probe_type == 'r':
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800468 return self.function
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700469 elif self.probe_type == 'u':
470 return self.usdt_name
471 else: # self.probe_type == 't'
472 return self.tp_event
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800473
Mark Draytonaa6c9162016-11-03 15:36:29 +0000474 def print_stack(self, bpf, stack_id, tgid):
Teng Qin6b0ed372016-09-29 21:30:13 -0700475 if stack_id < 0:
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700476 print(" %d" % stack_id)
477 return
Teng Qin6b0ed372016-09-29 21:30:13 -0700478
479 stack = list(bpf.get_table(self.stacks_name).walk(stack_id))
480 for addr in stack:
Sasha Goldshtein1e34f4e2017-02-09 00:21:49 -0500481 print(" %s" % (bpf.sym(addr, tgid,
Sasha Goldshtein01553852017-02-09 03:58:09 -0500482 show_module=True, show_offset=True)))
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700483
Mark Draytonaa6c9162016-11-03 15:36:29 +0000484 def _format_message(self, bpf, tgid, values):
485 # Replace each %K with kernel sym and %U with user sym in tgid
Rafael Fonsecaaee5ecf2017-02-08 16:14:31 +0100486 kernel_placeholders = [i for i, t in enumerate(self.types)
487 if t == 'K']
488 user_placeholders = [i for i, t in enumerate(self.types)
489 if t == 'U']
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700490 for kp in kernel_placeholders:
Sasha Goldshtein01553852017-02-09 03:58:09 -0500491 values[kp] = bpf.ksym(values[kp], show_offset=True)
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700492 for up in user_placeholders:
Sasha Goldshtein1e34f4e2017-02-09 00:21:49 -0500493 values[up] = bpf.sym(values[up], tgid,
Sasha Goldshtein01553852017-02-09 03:58:09 -0500494 show_module=True, show_offset=True)
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700495 return self.python_format % tuple(values)
Teng Qin6b0ed372016-09-29 21:30:13 -0700496
497 def print_event(self, bpf, cpu, data, size):
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800498 # Cast as the generated structure type and display
499 # according to the format string in the probe.
500 event = ct.cast(data, ct.POINTER(self.python_struct)).contents
501 values = map(lambda i: getattr(event, "v%d" % i),
502 range(0, len(self.values)))
Mark Draytonaa6c9162016-11-03 15:36:29 +0000503 msg = self._format_message(bpf, event.tgid, values)
Teng Qinc200b6c2017-12-16 00:15:55 -0800504 if Probe.print_time:
Sasha Goldshtein49d50ba2016-12-19 10:17:38 +0000505 time = strftime("%H:%M:%S") if Probe.use_localtime else \
506 Probe._time_off_str(event.timestamp_ns)
Teng Qinc200b6c2017-12-16 00:15:55 -0800507 print("%-8s " % time[:8], end="")
508 if Probe.print_cpu:
509 print("%-3s " % event.cpu, end="")
510 print("%-7d %-7d %-15s %-16s %s" %
511 (event.tgid, event.pid, event.comm.decode(),
512 self._display_function(), msg))
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800513
Teng Qin6b0ed372016-09-29 21:30:13 -0700514 if self.kernel_stack:
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700515 self.print_stack(bpf, event.kernel_stack_id, -1)
Mark Draytonaa6c9162016-11-03 15:36:29 +0000516 if self.user_stack:
517 self.print_stack(bpf, event.user_stack_id, event.tgid)
Teng Qin6b0ed372016-09-29 21:30:13 -0700518 if self.user_stack or self.kernel_stack:
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700519 print("")
Teng Qin6b0ed372016-09-29 21:30:13 -0700520
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800521 Probe.event_count += 1
522 if Probe.max_events is not None and \
523 Probe.event_count >= Probe.max_events:
524 exit()
525
526 def attach(self, bpf, verbose):
527 if len(self.library) == 0:
528 self._attach_k(bpf)
529 else:
530 self._attach_u(bpf)
531 self.python_struct = self._generate_python_data_decl()
Teng Qin6b0ed372016-09-29 21:30:13 -0700532 callback = partial(self.print_event, bpf)
Mark Drayton5f5687e2017-02-20 18:13:03 +0000533 bpf[self.events_name].open_perf_buffer(callback,
534 page_cnt=self.page_cnt)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800535
536 def _attach_k(self, bpf):
537 if self.probe_type == "r":
538 bpf.attach_kretprobe(event=self.function,
539 fn_name=self.probe_name)
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300540 elif self.probe_type == "p":
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800541 bpf.attach_kprobe(event=self.function,
542 fn_name=self.probe_name)
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300543 # Note that tracepoints don't need an explicit attach
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800544
545 def _attach_u(self, bpf):
546 libpath = BPF.find_library(self.library)
547 if libpath is None:
548 # This might be an executable (e.g. 'bash')
Sasha Goldshteinec679712016-10-04 18:33:36 +0300549 libpath = BPF.find_exe(self.library)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800550 if libpath is None or len(libpath) == 0:
551 self._bail("unable to find library %s" % self.library)
552
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700553 if self.probe_type == "u":
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300554 pass # Was already enabled by the BPF constructor
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700555 elif self.probe_type == "r":
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800556 bpf.attach_uretprobe(name=libpath,
557 sym=self.function,
558 fn_name=self.probe_name,
Sasha Goldshteinb6300922017-01-16 18:43:11 +0000559 pid=Probe.tgid)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800560 else:
561 bpf.attach_uprobe(name=libpath,
562 sym=self.function,
563 fn_name=self.probe_name,
Sasha Goldshteinb6300922017-01-16 18:43:11 +0000564 pid=Probe.tgid)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800565
566class Tool(object):
Mark Drayton5f5687e2017-02-20 18:13:03 +0000567 DEFAULT_PERF_BUFFER_PAGES = 64
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800568 examples = """
569EXAMPLES:
570
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800571trace do_sys_open
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800572 Trace the open syscall and print a default trace message when entered
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800573trace 'do_sys_open "%s", arg2'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800574 Trace the open syscall and print the filename being opened
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800575trace 'sys_read (arg3 > 20000) "read %d bytes", arg3'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800576 Trace the read syscall and print a message for reads >20000 bytes
Sasha Goldshtein23e72b82017-01-17 08:49:36 +0000577trace 'r::do_sys_open "%llx", retval'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800578 Trace the return from the open syscall and print the return value
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800579trace 'c:open (arg2 == 42) "%s %d", arg1, arg2'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800580 Trace the open() call from libc only if the flags (arg2) argument is 42
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800581trace 'c:malloc "size = %d", arg1'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800582 Trace malloc calls and print the size being allocated
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800583trace 'p:c:write (arg1 == 1) "writing %d bytes to STDOUT", arg3'
584 Trace the write() call from libc to monitor writes to STDOUT
Mark Draytonaa6c9162016-11-03 15:36:29 +0000585trace 'r::__kmalloc (retval == 0) "kmalloc failed!"'
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800586 Trace returns from __kmalloc which returned a null pointer
Mark Draytonaa6c9162016-11-03 15:36:29 +0000587trace 'r:c:malloc (retval) "allocated = %x", retval'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800588 Trace returns from malloc and print non-NULL allocated buffers
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300589trace 't:block:block_rq_complete "sectors=%d", args->nr_sector'
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800590 Trace the block_rq_complete kernel tracepoint and print # of tx sectors
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700591trace 'u:pthread:pthread_create (arg4 != 0)'
592 Trace the USDT probe pthread_create when its 4th argument is non-zero
Sasha Goldshtein23e72b82017-01-17 08:49:36 +0000593trace 'p::SyS_nanosleep(struct timespec *ts) "sleep for %lld ns", ts->tv_nsec'
594 Trace the nanosleep syscall and print the sleep duration in ns
Yonghong Songf4470dc2017-12-13 14:12:13 -0800595trace -I 'linux/fs.h' \\
596 'p::uprobe_register(struct inode *inode) "a_ops = %llx", inode->i_mapping->a_ops'
597 Trace the uprobe_register inode mapping ops, and the symbol can be found
598 in /proc/kallsyms
599trace -I 'kernel/sched/sched.h' \\
600 'p::__account_cfs_rq_runtime(struct cfs_rq *cfs_rq) "%d", cfs_rq->runtime_remaining'
601 Trace the cfs scheduling runqueue remaining runtime. The struct cfs_rq is defined
602 in kernel/sched/sched.h which is in kernel source tree and not in kernel-devel
603 package. So this command needs to run at the kernel source tree root directory
604 so that the added header file can be found by the compiler.
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800605"""
606
607 def __init__(self):
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300608 parser = argparse.ArgumentParser(description="Attach to " +
609 "functions and print trace messages.",
610 formatter_class=argparse.RawDescriptionHelpFormatter,
611 epilog=Tool.examples)
Mark Drayton5f5687e2017-02-20 18:13:03 +0000612 parser.add_argument("-b", "--buffer-pages", type=int,
613 default=Tool.DEFAULT_PERF_BUFFER_PAGES,
614 help="number of pages to use for perf_events ring buffer "
615 "(default: %(default)d)")
Mark Draytonaa6c9162016-11-03 15:36:29 +0000616 # we'll refer to the userspace concepts of "pid" and "tid" by
617 # their kernel names -- tgid and pid -- inside the script
618 parser.add_argument("-p", "--pid", type=int, metavar="PID",
619 dest="tgid", help="id of the process to trace (optional)")
Sasha Goldshtein49d50ba2016-12-19 10:17:38 +0000620 parser.add_argument("-L", "--tid", type=int, metavar="TID",
Mark Draytonaa6c9162016-11-03 15:36:29 +0000621 dest="pid", help="id of the thread to trace (optional)")
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800622 parser.add_argument("-v", "--verbose", action="store_true",
623 help="print resulting BPF program code before executing")
624 parser.add_argument("-Z", "--string-size", type=int,
625 default=80, help="maximum size to read from strings")
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300626 parser.add_argument("-S", "--include-self",
627 action="store_true",
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800628 help="do not filter trace's own pid from the trace")
629 parser.add_argument("-M", "--max-events", type=int,
630 help="number of events to print before quitting")
Sasha Goldshtein49d50ba2016-12-19 10:17:38 +0000631 parser.add_argument("-t", "--timestamp", action="store_true",
632 help="print timestamp column (offset from trace start)")
633 parser.add_argument("-T", "--time", action="store_true",
634 help="print time column")
Teng Qinc200b6c2017-12-16 00:15:55 -0800635 parser.add_argument("-C", "--print_cpu", action="store_true",
636 help="print CPU id")
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300637 parser.add_argument("-K", "--kernel-stack",
638 action="store_true", help="output kernel stack trace")
639 parser.add_argument("-U", "--user-stack",
640 action="store_true", help="output user stack trace")
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800641 parser.add_argument(metavar="probe", dest="probes", nargs="+",
642 help="probe specifier (see examples)")
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300643 parser.add_argument("-I", "--include", action="append",
644 metavar="header",
ShelbyFrancesf5dbbdb2017-02-08 05:56:52 +0300645 help="additional header files to include in the BPF program "
Yonghong Songf4470dc2017-12-13 14:12:13 -0800646 "as either full path, "
647 "or relative to current working directory, "
648 "or relative to default kernel header search path")
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800649 self.args = parser.parse_args()
Mark Draytonaa6c9162016-11-03 15:36:29 +0000650 if self.args.tgid and self.args.pid:
Yonghong Songf4470dc2017-12-13 14:12:13 -0800651 parser.error("only one of -p and -L may be specified")
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800652
653 def _create_probes(self):
654 Probe.configure(self.args)
655 self.probes = []
656 for probe_spec in self.args.probes:
657 self.probes.append(Probe(
Teng Qin6b0ed372016-09-29 21:30:13 -0700658 probe_spec, self.args.string_size,
659 self.args.kernel_stack, self.args.user_stack))
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800660
661 def _generate_program(self):
662 self.program = """
663#include <linux/ptrace.h>
664#include <linux/sched.h> /* For TASK_COMM_LEN */
665
666"""
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300667 for include in (self.args.include or []):
ShelbyFrancesf5dbbdb2017-02-08 05:56:52 +0300668 if include.startswith((".", "/")):
669 include = os.path.abspath(include)
670 self.program += "#include \"%s\"\n" % include
671 else:
672 self.program += "#include <%s>\n" % include
Sasha Goldshteinb950d6f2016-03-21 04:06:15 -0700673 self.program += BPF.generate_auto_includes(
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800674 map(lambda p: p.raw_probe, self.probes))
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800675 for probe in self.probes:
676 self.program += probe.generate_program(
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700677 self.args.include_self)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800678
679 if self.args.verbose:
680 print(self.program)
681
682 def _attach_probes(self):
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300683 usdt_contexts = []
684 for probe in self.probes:
685 if probe.usdt:
686 # USDT probes must be enabled before the BPF object
687 # is initialized, because that's where the actual
688 # uprobe is being attached.
689 probe.usdt.enable_probe(
690 probe.usdt_name, probe.probe_name)
Sasha Goldshteinf733cac2016-10-04 18:39:01 +0300691 if self.args.verbose:
692 print(probe.usdt.get_text())
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300693 usdt_contexts.append(probe.usdt)
694 self.bpf = BPF(text=self.program, usdt_contexts=usdt_contexts)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800695 for probe in self.probes:
696 if self.args.verbose:
697 print(probe)
698 probe.attach(self.bpf, self.args.verbose)
699
700 def _main_loop(self):
701 all_probes_trivial = all(map(Probe.is_default_action,
702 self.probes))
703
704 # Print header
Sasha Goldshtein49d50ba2016-12-19 10:17:38 +0000705 if self.args.timestamp or self.args.time:
Teng Qinc200b6c2017-12-16 00:15:55 -0800706 print("%-8s " % "TIME", end="");
707 if self.args.print_cpu:
708 print("%-3s " % "CPU", end="");
709 print("%-7s %-7s %-15s %-16s %s" %
710 ("PID", "TID", "COMM", "FUNC",
711 "-" if not all_probes_trivial else ""))
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800712
713 while True:
714 self.bpf.kprobe_poll()
715
716 def run(self):
717 try:
718 self._create_probes()
719 self._generate_program()
720 self._attach_probes()
721 self._main_loop()
722 except:
Sasha Goldshtein2febc292017-02-13 20:25:32 -0500723 exc_info = sys.exc_info()
724 sys_exit = exc_info[0] is SystemExit
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800725 if self.args.verbose:
726 traceback.print_exc()
Sasha Goldshtein2febc292017-02-13 20:25:32 -0500727 elif not sys_exit:
728 print(exc_info[1])
729 exit(0 if sys_exit else 1)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800730
731if __name__ == "__main__":
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300732 Tool().run()