blob: a91a5168d30d62bd09ca92e378de61e577ca305d [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
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +030013from bcc import BPF, USDT
Teng Qin6b0ed372016-09-29 21:30:13 -070014from functools import partial
Sasha Goldshtein38847f02016-02-22 02:19:24 -080015from time import sleep, strftime
16import argparse
17import re
18import ctypes as ct
19import os
20import traceback
21import sys
22
Sasha Goldshtein38847f02016-02-22 02:19:24 -080023class Probe(object):
24 probe_count = 0
Sasha Goldshteinf4797b02016-10-17 01:44:56 -070025 streq_index = 0
Sasha Goldshtein38847f02016-02-22 02:19:24 -080026 max_events = None
27 event_count = 0
28 first_ts = 0
29 use_localtime = True
Mark Draytonaa6c9162016-11-03 15:36:29 +000030 tgid = -1
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070031 pid = -1
Mark Drayton5f5687e2017-02-20 18:13:03 +000032 page_cnt = None
Sasha Goldshtein38847f02016-02-22 02:19:24 -080033
34 @classmethod
35 def configure(cls, args):
36 cls.max_events = args.max_events
Sasha Goldshtein49d50ba2016-12-19 10:17:38 +000037 cls.print_time = args.timestamp or args.time
38 cls.use_localtime = not args.timestamp
Sasha Goldshtein60c41922017-02-09 04:19:53 -050039 cls.first_ts = BPF.monotonic_time()
Mark Draytonaa6c9162016-11-03 15:36:29 +000040 cls.tgid = args.tgid or -1
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070041 cls.pid = args.pid or -1
Mark Drayton5f5687e2017-02-20 18:13:03 +000042 cls.page_cnt = args.buffer_pages
Sasha Goldshtein38847f02016-02-22 02:19:24 -080043
Teng Qin6b0ed372016-09-29 21:30:13 -070044 def __init__(self, probe, string_size, kernel_stack, user_stack):
Sasha Goldshtein69e361a2016-09-27 19:40:00 +030045 self.usdt = None
Sasha Goldshteinf4797b02016-10-17 01:44:56 -070046 self.streq_functions = ""
Sasha Goldshtein38847f02016-02-22 02:19:24 -080047 self.raw_probe = probe
48 self.string_size = string_size
Teng Qin6b0ed372016-09-29 21:30:13 -070049 self.kernel_stack = kernel_stack
50 self.user_stack = user_stack
Sasha Goldshtein38847f02016-02-22 02:19:24 -080051 Probe.probe_count += 1
52 self._parse_probe()
53 self.probe_num = Probe.probe_count
54 self.probe_name = "probe_%s_%d" % \
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070055 (self._display_function(), self.probe_num)
Paul Chaignon956ca1c2017-03-04 20:07:56 +010056 self.probe_name = re.sub(r'[^A-Za-z0-9_]', '_',
57 self.probe_name)
Sasha Goldshtein38847f02016-02-22 02:19:24 -080058
59 def __str__(self):
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070060 return "%s:%s:%s FLT=%s ACT=%s/%s" % (self.probe_type,
61 self.library, self._display_function(), self.filter,
Sasha Goldshtein38847f02016-02-22 02:19:24 -080062 self.types, self.values)
63
64 def is_default_action(self):
65 return self.python_format == ""
66
67 def _bail(self, error):
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070068 raise ValueError("error in probe '%s': %s" %
Sasha Goldshtein38847f02016-02-22 02:19:24 -080069 (self.raw_probe, error))
70
71 def _parse_probe(self):
72 text = self.raw_probe
73
Sasha Goldshtein23e72b82017-01-17 08:49:36 +000074 # There might be a function signature preceding the actual
75 # filter/print part, or not. Find the probe specifier first --
76 # it ends with either a space or an open paren ( for the
77 # function signature part.
78 # opt. signature
79 # probespec | rest
80 # --------- ---------- --
81 (spec, sig, rest) = re.match(r'([^ \t\(]+)(\([^\(]*\))?(.*)',
82 text).groups()
Sasha Goldshtein38847f02016-02-22 02:19:24 -080083
Sasha Goldshtein23e72b82017-01-17 08:49:36 +000084 self._parse_spec(spec)
Paul Chaignon956ca1c2017-03-04 20:07:56 +010085 # Remove the parens
86 self.signature = sig[1:-1] if sig else None
Sasha Goldshtein23e72b82017-01-17 08:49:36 +000087 if self.signature and self.probe_type in ['u', 't']:
88 self._bail("USDT and tracepoint probes can't have " +
89 "a function signature; use arg1, arg2, " +
90 "... instead")
91
92 text = rest.lstrip()
Sasha Goldshtein38847f02016-02-22 02:19:24 -080093 # If we now have a (, wait for the balanced closing ) and that
94 # will be the predicate
95 self.filter = None
96 if len(text) > 0 and text[0] == "(":
97 balance = 1
98 for i in range(1, len(text)):
99 if text[i] == "(":
100 balance += 1
101 if text[i] == ")":
102 balance -= 1
103 if balance == 0:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300104 self._parse_filter(text[:i + 1])
105 text = text[i + 1:]
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800106 break
107 if self.filter is None:
108 self._bail("unmatched end of predicate")
109
110 if self.filter is None:
111 self.filter = "1"
112
113 # The remainder of the text is the printf action
114 self._parse_action(text.lstrip())
115
116 def _parse_spec(self, spec):
117 parts = spec.split(":")
118 # Two special cases: 'func' means 'p::func', 'lib:func' means
119 # 'p:lib:func'. Other combinations need to provide an empty
120 # value between delimiters, e.g. 'r::func' for a kretprobe on
121 # the function func.
122 if len(parts) == 1:
123 parts = ["p", "", parts[0]]
124 elif len(parts) == 2:
125 parts = ["p", parts[0], parts[1]]
126 if len(parts[0]) == 0:
127 self.probe_type = "p"
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700128 elif parts[0] in ["p", "r", "t", "u"]:
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800129 self.probe_type = parts[0]
130 else:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700131 self._bail("probe type must be '', 'p', 't', 'r', " +
132 "or 'u', but got '%s'" % parts[0])
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800133 if self.probe_type == "t":
134 self.tp_category = parts[1]
135 self.tp_event = parts[2]
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800136 self.library = "" # kernel
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300137 self.function = "" # from TRACEPOINT_PROBE
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700138 elif self.probe_type == "u":
vkhromov5a2b39e2017-07-14 20:42:29 +0100139 self.library = ':'.join(parts[1:-1])
140 self.usdt_name = parts[-1]
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700141 self.function = "" # no function, just address
142 # We will discover the USDT provider by matching on
143 # the USDT name in the specified library
144 self._find_usdt_probe()
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800145 else:
vkhromov5a2b39e2017-07-14 20:42:29 +0100146 self.library = ':'.join(parts[1:-1])
147 self.function = parts[-1]
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800148
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700149 def _find_usdt_probe(self):
Sasha Goldshteindd045362016-11-13 05:07:38 -0800150 target = Probe.pid if Probe.pid and Probe.pid != -1 \
151 else Probe.tgid
Mark Draytonaa6c9162016-11-03 15:36:29 +0000152 self.usdt = USDT(path=self.library, pid=target)
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300153 for probe in self.usdt.enumerate_probes():
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700154 if probe.name == self.usdt_name:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300155 return # Found it, will enable later
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700156 self._bail("unrecognized USDT probe %s" % self.usdt_name)
157
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800158 def _parse_filter(self, filt):
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700159 self.filter = self._rewrite_expr(filt)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800160
161 def _parse_types(self, fmt):
162 for match in re.finditer(
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300163 r'[^%]%(s|u|d|llu|lld|hu|hd|x|llx|c|K|U)', fmt):
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800164 self.types.append(match.group(1))
165 fmt = re.sub(r'([^%]%)(u|d|llu|lld|hu|hd)', r'\1d', fmt)
166 fmt = re.sub(r'([^%]%)(x|llx)', r'\1x', fmt)
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700167 fmt = re.sub('%K|%U', '%s', fmt)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800168 self.python_format = fmt.strip('"')
169
170 def _parse_action(self, action):
171 self.values = []
172 self.types = []
173 self.python_format = ""
174 if len(action) == 0:
175 return
176
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800177 action = action.strip()
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700178 match = re.search(r'(\".*?\"),?(.*)', action)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800179 if match is None:
180 self._bail("expected format string in \"s")
181
182 self.raw_format = match.group(1)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800183 self._parse_types(self.raw_format)
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700184 for part in re.split('(?<!"),', match.group(2)):
185 part = self._rewrite_expr(part)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800186 if len(part) > 0:
187 self.values.append(part)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800188
189 aliases = {
Naveen N. Rao4afa96a2016-05-03 14:54:21 +0530190 "retval": "PT_REGS_RC(ctx)",
191 "arg1": "PT_REGS_PARM1(ctx)",
192 "arg2": "PT_REGS_PARM2(ctx)",
193 "arg3": "PT_REGS_PARM3(ctx)",
194 "arg4": "PT_REGS_PARM4(ctx)",
195 "arg5": "PT_REGS_PARM5(ctx)",
196 "arg6": "PT_REGS_PARM6(ctx)",
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800197 "$uid": "(unsigned)(bpf_get_current_uid_gid() & 0xffffffff)",
198 "$gid": "(unsigned)(bpf_get_current_uid_gid() >> 32)",
199 "$pid": "(unsigned)(bpf_get_current_pid_tgid() & 0xffffffff)",
200 "$tgid": "(unsigned)(bpf_get_current_pid_tgid() >> 32)",
201 "$cpu": "bpf_get_smp_processor_id()"
202 }
203
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700204 def _generate_streq_function(self, string):
205 fname = "streq_%d" % Probe.streq_index
206 Probe.streq_index += 1
207 self.streq_functions += """
Sasha Goldshteinb9aec342017-01-16 18:41:22 +0000208static inline bool %s(char const *ignored, uintptr_t str) {
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700209 char needle[] = %s;
210 char haystack[sizeof(needle)];
211 bpf_probe_read(&haystack, sizeof(haystack), (void *)str);
Sasha Goldshteindcf16752017-01-17 07:40:57 +0000212 for (int i = 0; i < sizeof(needle) - 1; ++i) {
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700213 if (needle[i] != haystack[i]) {
214 return false;
215 }
216 }
217 return true;
218}
219 """ % (fname, string)
220 return fname
221
222 def _rewrite_expr(self, expr):
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800223 for alias, replacement in Probe.aliases.items():
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700224 # For USDT probes, we replace argN values with the
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300225 # actual arguments for that probe obtained using
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300226 # bpf_readarg_N macros emitted at BPF construction.
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700227 if alias.startswith("arg") and self.probe_type == "u":
228 continue
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800229 expr = expr.replace(alias, replacement)
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700230 matches = re.finditer('STRCMP\\(("[^"]+\\")', expr)
231 for match in matches:
232 string = match.group(1)
233 fname = self._generate_streq_function(string)
234 expr = expr.replace("STRCMP", fname, 1)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800235 return expr
236
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300237 p_type = {"u": ct.c_uint, "d": ct.c_int,
238 "llu": ct.c_ulonglong, "lld": ct.c_longlong,
239 "hu": ct.c_ushort, "hd": ct.c_short,
240 "x": ct.c_uint, "llx": ct.c_ulonglong, "c": ct.c_ubyte,
241 "K": ct.c_ulonglong, "U": ct.c_ulonglong}
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800242
243 def _generate_python_field_decl(self, idx, fields):
244 field_type = self.types[idx]
245 if field_type == "s":
246 ptype = ct.c_char * self.string_size
247 else:
248 ptype = Probe.p_type[field_type]
249 fields.append(("v%d" % idx, ptype))
250
251 def _generate_python_data_decl(self):
252 self.python_struct_name = "%s_%d_Data" % \
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700253 (self._display_function(), self.probe_num)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800254 fields = [
255 ("timestamp_ns", ct.c_ulonglong),
Mark Draytonaa6c9162016-11-03 15:36:29 +0000256 ("tgid", ct.c_uint),
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800257 ("pid", ct.c_uint),
258 ("comm", ct.c_char * 16) # TASK_COMM_LEN
259 ]
260 for i in range(0, len(self.types)):
261 self._generate_python_field_decl(i, fields)
Teng Qin6b0ed372016-09-29 21:30:13 -0700262 if self.kernel_stack:
263 fields.append(("kernel_stack_id", ct.c_int))
264 if self.user_stack:
265 fields.append(("user_stack_id", ct.c_int))
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800266 return type(self.python_struct_name, (ct.Structure,),
267 dict(_fields_=fields))
268
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300269 c_type = {"u": "unsigned int", "d": "int",
270 "llu": "unsigned long long", "lld": "long long",
271 "hu": "unsigned short", "hd": "short",
272 "x": "unsigned int", "llx": "unsigned long long",
273 "c": "char", "K": "unsigned long long",
274 "U": "unsigned long long"}
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800275 fmt_types = c_type.keys()
276
277 def _generate_field_decl(self, idx):
278 field_type = self.types[idx]
279 if field_type == "s":
280 return "char v%d[%d];\n" % (idx, self.string_size)
281 if field_type in Probe.fmt_types:
282 return "%s v%d;\n" % (Probe.c_type[field_type], idx)
283 self._bail("unrecognized format specifier %s" % field_type)
284
285 def _generate_data_decl(self):
286 # The BPF program will populate values into the struct
287 # according to the format string, and the Python program will
288 # construct the final display string.
289 self.events_name = "%s_events" % self.probe_name
290 self.struct_name = "%s_data_t" % self.probe_name
Teng Qin6b0ed372016-09-29 21:30:13 -0700291 self.stacks_name = "%s_stacks" % self.probe_name
292 stack_table = "BPF_STACK_TRACE(%s, 1024);" % self.stacks_name \
293 if (self.kernel_stack or self.user_stack) else ""
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800294 data_fields = ""
295 for i, field_type in enumerate(self.types):
296 data_fields += " " + \
297 self._generate_field_decl(i)
298
Teng Qin6b0ed372016-09-29 21:30:13 -0700299 kernel_stack_str = " int kernel_stack_id;" \
300 if self.kernel_stack else ""
301 user_stack_str = " int user_stack_id;" \
302 if self.user_stack else ""
303
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800304 text = """
305struct %s
306{
307 u64 timestamp_ns;
Mark Draytonaa6c9162016-11-03 15:36:29 +0000308 u32 tgid;
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800309 u32 pid;
310 char comm[TASK_COMM_LEN];
311%s
Teng Qin6b0ed372016-09-29 21:30:13 -0700312%s
313%s
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800314};
315
316BPF_PERF_OUTPUT(%s);
Teng Qin6b0ed372016-09-29 21:30:13 -0700317%s
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800318"""
Teng Qin6b0ed372016-09-29 21:30:13 -0700319 return text % (self.struct_name, data_fields,
320 kernel_stack_str, user_stack_str,
321 self.events_name, stack_table)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800322
323 def _generate_field_assign(self, idx):
324 field_type = self.types[idx]
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300325 expr = self.values[idx].strip()
326 text = ""
327 if self.probe_type == "u" and expr[0:3] == "arg":
Sasha Goldshtein3a5256f2017-02-20 15:42:57 +0000328 arg_index = int(expr[3])
329 arg_ctype = self.usdt.get_probe_arg_ctype(
330 self.usdt_name, arg_index - 1)
331 text = (" %s %s = 0;\n" +
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300332 " bpf_usdt_readarg(%s, ctx, &%s);\n") \
Sasha Goldshtein3a5256f2017-02-20 15:42:57 +0000333 % (arg_ctype, expr, expr[3], expr)
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300334
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800335 if field_type == "s":
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300336 return text + """
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800337 if (%s != 0) {
338 bpf_probe_read(&__data.v%d, sizeof(__data.v%d), (void *)%s);
339 }
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300340 """ % (expr, idx, idx, expr)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800341 if field_type in Probe.fmt_types:
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300342 return text + " __data.v%d = (%s)%s;\n" % \
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800343 (idx, Probe.c_type[field_type], expr)
344 self._bail("unrecognized field type %s" % field_type)
345
Teng Qin0615bff2016-09-28 08:19:40 -0700346 def _generate_usdt_filter_read(self):
347 text = ""
Sasha Goldshteinb6300922017-01-16 18:43:11 +0000348 if self.probe_type != "u":
349 return text
350 for arg, _ in Probe.aliases.items():
351 if not (arg.startswith("arg") and
352 (arg in self.filter)):
353 continue
354 arg_index = int(arg.replace("arg", ""))
355 arg_ctype = self.usdt.get_probe_arg_ctype(
Sasha Goldshteindcf16752017-01-17 07:40:57 +0000356 self.usdt_name, arg_index - 1)
Sasha Goldshteinb6300922017-01-16 18:43:11 +0000357 if not arg_ctype:
358 self._bail("Unable to determine type of {} "
359 "in the filter".format(arg))
360 text += """
Teng Qin0615bff2016-09-28 08:19:40 -0700361 {} {}_filter;
362 bpf_usdt_readarg({}, ctx, &{}_filter);
Sasha Goldshteinb6300922017-01-16 18:43:11 +0000363 """.format(arg_ctype, arg, arg_index, arg)
364 self.filter = self.filter.replace(
365 arg, "{}_filter".format(arg))
Teng Qin0615bff2016-09-28 08:19:40 -0700366 return text
367
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700368 def generate_program(self, include_self):
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800369 data_decl = self._generate_data_decl()
Sasha Goldshteinb6300922017-01-16 18:43:11 +0000370 if Probe.pid != -1:
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800371 pid_filter = """
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800372 if (__pid != %d) { return 0; }
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300373 """ % Probe.pid
Sasha Goldshteinb6300922017-01-16 18:43:11 +0000374 # uprobes can have a built-in tgid filter passed to
375 # attach_uprobe, hence the check here -- for kprobes, we
376 # need to do the tgid test by hand:
Mark Draytonaa6c9162016-11-03 15:36:29 +0000377 elif len(self.library) == 0 and Probe.tgid != -1:
378 pid_filter = """
379 if (__tgid != %d) { return 0; }
380 """ % Probe.tgid
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800381 elif not include_self:
382 pid_filter = """
Mark Draytonaa6c9162016-11-03 15:36:29 +0000383 if (__tgid == %d) { return 0; }
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300384 """ % os.getpid()
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800385 else:
386 pid_filter = ""
387
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700388 prefix = ""
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700389 signature = "struct pt_regs *ctx"
Sasha Goldshtein23e72b82017-01-17 08:49:36 +0000390 if self.signature:
391 signature += ", " + self.signature
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700392
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800393 data_fields = ""
394 for i, expr in enumerate(self.values):
395 data_fields += self._generate_field_assign(i)
396
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300397 if self.probe_type == "t":
398 heading = "TRACEPOINT_PROBE(%s, %s)" % \
399 (self.tp_category, self.tp_event)
400 ctx_name = "args"
401 else:
402 heading = "int %s(%s)" % (self.probe_name, signature)
403 ctx_name = "ctx"
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300404
405 stack_trace = ""
406 if self.user_stack:
407 stack_trace += """
408 __data.user_stack_id = %s.get_stackid(
409 %s, BPF_F_REUSE_STACKID | BPF_F_USER_STACK
410 );""" % (self.stacks_name, ctx_name)
411 if self.kernel_stack:
412 stack_trace += """
413 __data.kernel_stack_id = %s.get_stackid(
414 %s, BPF_F_REUSE_STACKID
415 );""" % (self.stacks_name, ctx_name)
416
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300417 text = heading + """
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800418{
Mark Draytonaa6c9162016-11-03 15:36:29 +0000419 u64 __pid_tgid = bpf_get_current_pid_tgid();
420 u32 __tgid = __pid_tgid >> 32;
421 u32 __pid = __pid_tgid; // implicit cast to u32 for bottom half
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800422 %s
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800423 %s
Teng Qin0615bff2016-09-28 08:19:40 -0700424 %s
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800425 if (!(%s)) return 0;
426
427 struct %s __data = {0};
428 __data.timestamp_ns = bpf_ktime_get_ns();
Mark Draytonaa6c9162016-11-03 15:36:29 +0000429 __data.tgid = __tgid;
430 __data.pid = __pid;
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800431 bpf_get_current_comm(&__data.comm, sizeof(__data.comm));
432%s
Teng Qin6b0ed372016-09-29 21:30:13 -0700433%s
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300434 %s.perf_submit(%s, &__data, sizeof(__data));
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800435 return 0;
436}
437"""
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300438 text = text % (pid_filter, prefix,
Teng Qin0615bff2016-09-28 08:19:40 -0700439 self._generate_usdt_filter_read(), self.filter,
Teng Qin6b0ed372016-09-29 21:30:13 -0700440 self.struct_name, data_fields,
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300441 stack_trace, self.events_name, ctx_name)
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700442
Sasha Goldshteinf4797b02016-10-17 01:44:56 -0700443 return self.streq_functions + data_decl + "\n" + text
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800444
445 @classmethod
446 def _time_off_str(cls, timestamp_ns):
447 return "%.6f" % (1e-9 * (timestamp_ns - cls.first_ts))
448
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800449 def _display_function(self):
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700450 if self.probe_type == 'p' or self.probe_type == 'r':
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800451 return self.function
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700452 elif self.probe_type == 'u':
453 return self.usdt_name
454 else: # self.probe_type == 't'
455 return self.tp_event
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800456
Mark Draytonaa6c9162016-11-03 15:36:29 +0000457 def print_stack(self, bpf, stack_id, tgid):
Teng Qin6b0ed372016-09-29 21:30:13 -0700458 if stack_id < 0:
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700459 print(" %d" % stack_id)
460 return
Teng Qin6b0ed372016-09-29 21:30:13 -0700461
462 stack = list(bpf.get_table(self.stacks_name).walk(stack_id))
463 for addr in stack:
Sasha Goldshtein1e34f4e2017-02-09 00:21:49 -0500464 print(" %s" % (bpf.sym(addr, tgid,
Sasha Goldshtein01553852017-02-09 03:58:09 -0500465 show_module=True, show_offset=True)))
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700466
Mark Draytonaa6c9162016-11-03 15:36:29 +0000467 def _format_message(self, bpf, tgid, values):
468 # Replace each %K with kernel sym and %U with user sym in tgid
Rafael Fonsecaaee5ecf2017-02-08 16:14:31 +0100469 kernel_placeholders = [i for i, t in enumerate(self.types)
470 if t == 'K']
471 user_placeholders = [i for i, t in enumerate(self.types)
472 if t == 'U']
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700473 for kp in kernel_placeholders:
Sasha Goldshtein01553852017-02-09 03:58:09 -0500474 values[kp] = bpf.ksym(values[kp], show_offset=True)
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700475 for up in user_placeholders:
Sasha Goldshtein1e34f4e2017-02-09 00:21:49 -0500476 values[up] = bpf.sym(values[up], tgid,
Sasha Goldshtein01553852017-02-09 03:58:09 -0500477 show_module=True, show_offset=True)
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700478 return self.python_format % tuple(values)
Teng Qin6b0ed372016-09-29 21:30:13 -0700479
480 def print_event(self, bpf, cpu, data, size):
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800481 # Cast as the generated structure type and display
482 # according to the format string in the probe.
483 event = ct.cast(data, ct.POINTER(self.python_struct)).contents
484 values = map(lambda i: getattr(event, "v%d" % i),
485 range(0, len(self.values)))
Mark Draytonaa6c9162016-11-03 15:36:29 +0000486 msg = self._format_message(bpf, event.tgid, values)
Sasha Goldshtein49d50ba2016-12-19 10:17:38 +0000487 if not Probe.print_time:
488 print("%-6d %-6d %-12s %-16s %s" %
Rafael F78948e42017-03-26 14:54:25 +0200489 (event.tgid, event.pid, event.comm.decode(),
Sasha Goldshtein49d50ba2016-12-19 10:17:38 +0000490 self._display_function(), msg))
491 else:
492 time = strftime("%H:%M:%S") if Probe.use_localtime else \
493 Probe._time_off_str(event.timestamp_ns)
494 print("%-8s %-6d %-6d %-12s %-16s %s" %
Paul Chaignon897c6862017-10-07 11:52:05 +0200495 (time[:8], event.tgid, event.pid,
496 event.comm.decode(), self._display_function(), msg))
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800497
Teng Qin6b0ed372016-09-29 21:30:13 -0700498 if self.kernel_stack:
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700499 self.print_stack(bpf, event.kernel_stack_id, -1)
Mark Draytonaa6c9162016-11-03 15:36:29 +0000500 if self.user_stack:
501 self.print_stack(bpf, event.user_stack_id, event.tgid)
Teng Qin6b0ed372016-09-29 21:30:13 -0700502 if self.user_stack or self.kernel_stack:
Sasha Goldshteinaccd4cf2016-10-11 07:56:13 -0700503 print("")
Teng Qin6b0ed372016-09-29 21:30:13 -0700504
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800505 Probe.event_count += 1
506 if Probe.max_events is not None and \
507 Probe.event_count >= Probe.max_events:
508 exit()
509
510 def attach(self, bpf, verbose):
511 if len(self.library) == 0:
512 self._attach_k(bpf)
513 else:
514 self._attach_u(bpf)
515 self.python_struct = self._generate_python_data_decl()
Teng Qin6b0ed372016-09-29 21:30:13 -0700516 callback = partial(self.print_event, bpf)
Mark Drayton5f5687e2017-02-20 18:13:03 +0000517 bpf[self.events_name].open_perf_buffer(callback,
518 page_cnt=self.page_cnt)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800519
520 def _attach_k(self, bpf):
521 if self.probe_type == "r":
522 bpf.attach_kretprobe(event=self.function,
523 fn_name=self.probe_name)
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300524 elif self.probe_type == "p":
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800525 bpf.attach_kprobe(event=self.function,
526 fn_name=self.probe_name)
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300527 # Note that tracepoints don't need an explicit attach
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800528
529 def _attach_u(self, bpf):
530 libpath = BPF.find_library(self.library)
531 if libpath is None:
532 # This might be an executable (e.g. 'bash')
Sasha Goldshteinec679712016-10-04 18:33:36 +0300533 libpath = BPF.find_exe(self.library)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800534 if libpath is None or len(libpath) == 0:
535 self._bail("unable to find library %s" % self.library)
536
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700537 if self.probe_type == "u":
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300538 pass # Was already enabled by the BPF constructor
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700539 elif self.probe_type == "r":
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800540 bpf.attach_uretprobe(name=libpath,
541 sym=self.function,
542 fn_name=self.probe_name,
Sasha Goldshteinb6300922017-01-16 18:43:11 +0000543 pid=Probe.tgid)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800544 else:
545 bpf.attach_uprobe(name=libpath,
546 sym=self.function,
547 fn_name=self.probe_name,
Sasha Goldshteinb6300922017-01-16 18:43:11 +0000548 pid=Probe.tgid)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800549
550class Tool(object):
Mark Drayton5f5687e2017-02-20 18:13:03 +0000551 DEFAULT_PERF_BUFFER_PAGES = 64
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800552 examples = """
553EXAMPLES:
554
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800555trace do_sys_open
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800556 Trace the open syscall and print a default trace message when entered
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800557trace 'do_sys_open "%s", arg2'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800558 Trace the open syscall and print the filename being opened
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800559trace 'sys_read (arg3 > 20000) "read %d bytes", arg3'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800560 Trace the read syscall and print a message for reads >20000 bytes
Sasha Goldshtein23e72b82017-01-17 08:49:36 +0000561trace 'r::do_sys_open "%llx", retval'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800562 Trace the return from the open syscall and print the return value
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800563trace 'c:open (arg2 == 42) "%s %d", arg1, arg2'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800564 Trace the open() call from libc only if the flags (arg2) argument is 42
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800565trace 'c:malloc "size = %d", arg1'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800566 Trace malloc calls and print the size being allocated
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800567trace 'p:c:write (arg1 == 1) "writing %d bytes to STDOUT", arg3'
568 Trace the write() call from libc to monitor writes to STDOUT
Mark Draytonaa6c9162016-11-03 15:36:29 +0000569trace 'r::__kmalloc (retval == 0) "kmalloc failed!"'
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800570 Trace returns from __kmalloc which returned a null pointer
Mark Draytonaa6c9162016-11-03 15:36:29 +0000571trace 'r:c:malloc (retval) "allocated = %x", retval'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800572 Trace returns from malloc and print non-NULL allocated buffers
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300573trace 't:block:block_rq_complete "sectors=%d", args->nr_sector'
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800574 Trace the block_rq_complete kernel tracepoint and print # of tx sectors
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700575trace 'u:pthread:pthread_create (arg4 != 0)'
576 Trace the USDT probe pthread_create when its 4th argument is non-zero
Sasha Goldshtein23e72b82017-01-17 08:49:36 +0000577trace 'p::SyS_nanosleep(struct timespec *ts) "sleep for %lld ns", ts->tv_nsec'
578 Trace the nanosleep syscall and print the sleep duration in ns
Yonghong Songf4470dc2017-12-13 14:12:13 -0800579trace -I 'linux/fs.h' \\
580 'p::uprobe_register(struct inode *inode) "a_ops = %llx", inode->i_mapping->a_ops'
581 Trace the uprobe_register inode mapping ops, and the symbol can be found
582 in /proc/kallsyms
583trace -I 'kernel/sched/sched.h' \\
584 'p::__account_cfs_rq_runtime(struct cfs_rq *cfs_rq) "%d", cfs_rq->runtime_remaining'
585 Trace the cfs scheduling runqueue remaining runtime. The struct cfs_rq is defined
586 in kernel/sched/sched.h which is in kernel source tree and not in kernel-devel
587 package. So this command needs to run at the kernel source tree root directory
588 so that the added header file can be found by the compiler.
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800589"""
590
591 def __init__(self):
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300592 parser = argparse.ArgumentParser(description="Attach to " +
593 "functions and print trace messages.",
594 formatter_class=argparse.RawDescriptionHelpFormatter,
595 epilog=Tool.examples)
Mark Drayton5f5687e2017-02-20 18:13:03 +0000596 parser.add_argument("-b", "--buffer-pages", type=int,
597 default=Tool.DEFAULT_PERF_BUFFER_PAGES,
598 help="number of pages to use for perf_events ring buffer "
599 "(default: %(default)d)")
Mark Draytonaa6c9162016-11-03 15:36:29 +0000600 # we'll refer to the userspace concepts of "pid" and "tid" by
601 # their kernel names -- tgid and pid -- inside the script
602 parser.add_argument("-p", "--pid", type=int, metavar="PID",
603 dest="tgid", help="id of the process to trace (optional)")
Sasha Goldshtein49d50ba2016-12-19 10:17:38 +0000604 parser.add_argument("-L", "--tid", type=int, metavar="TID",
Mark Draytonaa6c9162016-11-03 15:36:29 +0000605 dest="pid", help="id of the thread to trace (optional)")
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800606 parser.add_argument("-v", "--verbose", action="store_true",
607 help="print resulting BPF program code before executing")
608 parser.add_argument("-Z", "--string-size", type=int,
609 default=80, help="maximum size to read from strings")
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300610 parser.add_argument("-S", "--include-self",
611 action="store_true",
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800612 help="do not filter trace's own pid from the trace")
613 parser.add_argument("-M", "--max-events", type=int,
614 help="number of events to print before quitting")
Sasha Goldshtein49d50ba2016-12-19 10:17:38 +0000615 parser.add_argument("-t", "--timestamp", action="store_true",
616 help="print timestamp column (offset from trace start)")
617 parser.add_argument("-T", "--time", action="store_true",
618 help="print time column")
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300619 parser.add_argument("-K", "--kernel-stack",
620 action="store_true", help="output kernel stack trace")
621 parser.add_argument("-U", "--user-stack",
622 action="store_true", help="output user stack trace")
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800623 parser.add_argument(metavar="probe", dest="probes", nargs="+",
624 help="probe specifier (see examples)")
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300625 parser.add_argument("-I", "--include", action="append",
626 metavar="header",
ShelbyFrancesf5dbbdb2017-02-08 05:56:52 +0300627 help="additional header files to include in the BPF program "
Yonghong Songf4470dc2017-12-13 14:12:13 -0800628 "as either full path, "
629 "or relative to current working directory, "
630 "or relative to default kernel header search path")
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800631 self.args = parser.parse_args()
Mark Draytonaa6c9162016-11-03 15:36:29 +0000632 if self.args.tgid and self.args.pid:
Yonghong Songf4470dc2017-12-13 14:12:13 -0800633 parser.error("only one of -p and -L may be specified")
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800634
635 def _create_probes(self):
636 Probe.configure(self.args)
637 self.probes = []
638 for probe_spec in self.args.probes:
639 self.probes.append(Probe(
Teng Qin6b0ed372016-09-29 21:30:13 -0700640 probe_spec, self.args.string_size,
641 self.args.kernel_stack, self.args.user_stack))
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800642
643 def _generate_program(self):
644 self.program = """
645#include <linux/ptrace.h>
646#include <linux/sched.h> /* For TASK_COMM_LEN */
647
648"""
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300649 for include in (self.args.include or []):
ShelbyFrancesf5dbbdb2017-02-08 05:56:52 +0300650 if include.startswith((".", "/")):
651 include = os.path.abspath(include)
652 self.program += "#include \"%s\"\n" % include
653 else:
654 self.program += "#include <%s>\n" % include
Sasha Goldshteinb950d6f2016-03-21 04:06:15 -0700655 self.program += BPF.generate_auto_includes(
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800656 map(lambda p: p.raw_probe, self.probes))
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800657 for probe in self.probes:
658 self.program += probe.generate_program(
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700659 self.args.include_self)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800660
661 if self.args.verbose:
662 print(self.program)
663
664 def _attach_probes(self):
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300665 usdt_contexts = []
666 for probe in self.probes:
667 if probe.usdt:
668 # USDT probes must be enabled before the BPF object
669 # is initialized, because that's where the actual
670 # uprobe is being attached.
671 probe.usdt.enable_probe(
672 probe.usdt_name, probe.probe_name)
Sasha Goldshteinf733cac2016-10-04 18:39:01 +0300673 if self.args.verbose:
674 print(probe.usdt.get_text())
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300675 usdt_contexts.append(probe.usdt)
676 self.bpf = BPF(text=self.program, usdt_contexts=usdt_contexts)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800677 for probe in self.probes:
678 if self.args.verbose:
679 print(probe)
680 probe.attach(self.bpf, self.args.verbose)
681
682 def _main_loop(self):
683 all_probes_trivial = all(map(Probe.is_default_action,
684 self.probes))
685
686 # Print header
Sasha Goldshtein49d50ba2016-12-19 10:17:38 +0000687 if self.args.timestamp or self.args.time:
688 print("%-8s %-6s %-6s %-12s %-16s %s" %
689 ("TIME", "PID", "TID", "COMM", "FUNC",
690 "-" if not all_probes_trivial else ""))
691 else:
692 print("%-6s %-6s %-12s %-16s %s" %
693 ("PID", "TID", "COMM", "FUNC",
694 "-" if not all_probes_trivial else ""))
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800695
696 while True:
697 self.bpf.kprobe_poll()
698
699 def run(self):
700 try:
701 self._create_probes()
702 self._generate_program()
703 self._attach_probes()
704 self._main_loop()
705 except:
Sasha Goldshtein2febc292017-02-13 20:25:32 -0500706 exc_info = sys.exc_info()
707 sys_exit = exc_info[0] is SystemExit
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800708 if self.args.verbose:
709 traceback.print_exc()
Sasha Goldshtein2febc292017-02-13 20:25:32 -0500710 elif not sys_exit:
711 print(exc_info[1])
712 exit(0 if sys_exit else 1)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800713
714if __name__ == "__main__":
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300715 Tool().run()