blob: 8f1ce893b767ae66ad345bac2652965cd99f077f [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#
6# USAGE: trace [-h] [-p PID] [-v] [-Z STRING_SIZE] [-S] [-M MAX_EVENTS] [-o]
7# probe [probe ...]
Sasha Goldshteinfd60d552016-03-01 12:15:34 -08008#
Sasha Goldshtein38847f02016-02-22 02:19:24 -08009# Licensed under the Apache License, Version 2.0 (the "License")
10# Copyright (C) 2016 Sasha Goldshtein.
11
12from bcc import BPF
13from time import sleep, strftime
14import argparse
15import re
16import ctypes as ct
Sasha Goldshteinfd60d552016-03-01 12:15:34 -080017import multiprocessing
Sasha Goldshtein38847f02016-02-22 02:19:24 -080018import os
19import traceback
20import sys
21
22class Time(object):
23 # BPF timestamps come from the monotonic clock. To be able to filter
24 # and compare them from Python, we need to invoke clock_gettime.
25 # Adapted from http://stackoverflow.com/a/1205762
26 CLOCK_MONOTONIC_RAW = 4 # see <linux/time.h>
27
28 class timespec(ct.Structure):
29 _fields_ = [
30 ('tv_sec', ct.c_long),
31 ('tv_nsec', ct.c_long)
32 ]
33
34 librt = ct.CDLL('librt.so.1', use_errno=True)
35 clock_gettime = librt.clock_gettime
36 clock_gettime.argtypes = [ct.c_int, ct.POINTER(timespec)]
37
38 @staticmethod
39 def monotonic_time():
40 t = Time.timespec()
41 if Time.clock_gettime(
42 Time.CLOCK_MONOTONIC_RAW, ct.pointer(t)) != 0:
43 errno_ = ct.get_errno()
44 raise OSError(errno_, os.strerror(errno_))
45 return t.tv_sec * 1e9 + t.tv_nsec
46
Sasha Goldshteinfd60d552016-03-01 12:15:34 -080047class Perf(object):
48 class perf_event_attr(ct.Structure):
49 _fields_ = [
50 ('type', ct.c_uint),
51 ('size', ct.c_uint),
52 ('config', ct.c_ulong),
53 ('sample_period', ct.c_ulong),
54 ('sample_type', ct.c_ulong),
55 ('IGNORE1', ct.c_ulong),
56 ('IGNORE2', ct.c_ulong),
57 ('wakeup_events', ct.c_uint),
58 ('IGNORE3', ct.c_uint),
59 ('IGNORE4', ct.c_ulong),
60 ('IGNORE5', ct.c_ulong),
61 ('IGNORE6', ct.c_ulong),
62 ('IGNORE7', ct.c_uint),
63 ('IGNORE8', ct.c_int),
64 ('IGNORE9', ct.c_ulong),
65 ('IGNORE10', ct.c_uint),
66 ('IGNORE11', ct.c_uint)
67 ]
68
69 NR_PERF_EVENT_OPEN = 298
70 PERF_TYPE_TRACEPOINT = 2
71 PERF_SAMPLE_RAW = 1024
72 PERF_FLAG_FD_CLOEXEC = 8
73 PERF_EVENT_IOC_SET_FILTER = 1074275334
74 PERF_EVENT_IOC_ENABLE = 9216
75
76 libc = ct.CDLL('libc.so.6', use_errno=True)
77 syscall = libc.syscall # not declaring vararg types
78 ioctl = libc.ioctl # not declaring vararg types
79
80 @staticmethod
81 def _open_for_cpu(cpu, attr):
82 pfd = Perf.syscall(Perf.NR_PERF_EVENT_OPEN, ct.byref(attr),
83 -1, cpu, -1, Perf.PERF_FLAG_FD_CLOEXEC)
84 if pfd < 0:
85 errno_ = ct.get_errno()
86 raise OSError(errno_, os.strerror(errno_))
87 if Perf.ioctl(pfd, Perf.PERF_EVENT_IOC_SET_FILTER,
88 "common_pid == -17") < 0:
89 errno_ = ct.get_errno()
90 raise OSError(errno_, os.strerror(errno_))
91 if Perf.ioctl(pfd, Perf.PERF_EVENT_IOC_ENABLE, 0) < 0:
92 errno_ = ct.get_errno()
93 raise OSError(errno_, os.strerror(errno_))
94
95 @staticmethod
96 def perf_event_open(tpoint_id):
97 attr = Perf.perf_event_attr()
98 attr.config = tpoint_id
99 attr.type = Perf.PERF_TYPE_TRACEPOINT
100 attr.sample_type = Perf.PERF_SAMPLE_RAW
101 attr.sample_period = 1
102 attr.wakeup_events = 1
103 for cpu in range(0, multiprocessing.cpu_count()):
104 Perf._open_for_cpu(cpu, attr)
105
106class Tracepoint(object):
107 tracepoints_enabled = 0
108 trace_root = "/sys/kernel/debug/tracing"
109 event_root = os.path.join(trace_root, "events")
110
111 @staticmethod
112 def generate_decl():
113 if Tracepoint.tracepoints_enabled == 0:
114 return ""
115 return "\nBPF_HASH(__trace_di, u64, u64);\n"
116
117 @staticmethod
118 def generate_entry_probe():
119 if Tracepoint.tracepoints_enabled == 0:
120 return ""
121 return """
122int __trace_entry_update(struct pt_regs *ctx)
123{
124 u64 tid = bpf_get_current_pid_tgid();
125 u64 val = ctx->di;
126 __trace_di.update(&tid, &val);
127 return 0;
128}
129"""
130
131 @staticmethod
132 def enable_tracepoint(category, event):
133 tp_id = Tracepoint.get_tpoint_id(category, event)
134 if tp_id == -1:
135 raise ValueError("no such tracepoint found: %s:%s" %
136 (category, event))
137 Perf.perf_event_open(tp_id)
138 Tracepoint.tracepoints_enabled += 1
139
140 @staticmethod
141 def get_tpoint_id(category, event):
142 evt_dir = os.path.join(Tracepoint.event_root, category, event)
143 try:
144 return int(
145 open(os.path.join(evt_dir, "id")).read().strip())
146 except:
147 return -1
148
149 @staticmethod
150 def get_tpoint_format(category, event):
151 evt_dir = os.path.join(Tracepoint.event_root, category, event)
152 try:
153 return open(os.path.join(evt_dir, "format")).readlines()
154 except:
155 return ""
156
157 @staticmethod
158 def attach(bpf):
159 if Tracepoint.tracepoints_enabled > 0:
160 bpf.attach_kprobe(event="tracing_generic_entry_update",
161 fn_name="__trace_entry_update")
162
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800163class Probe(object):
164 probe_count = 0
165 max_events = None
166 event_count = 0
167 first_ts = 0
168 use_localtime = True
169
170 @classmethod
171 def configure(cls, args):
172 cls.max_events = args.max_events
173 cls.use_localtime = not args.offset
174 cls.first_ts = Time.monotonic_time()
175
176 def __init__(self, probe, string_size):
177 self.raw_probe = probe
178 self.string_size = string_size
179 Probe.probe_count += 1
180 self._parse_probe()
181 self.probe_num = Probe.probe_count
182 self.probe_name = "probe_%s_%d" % \
183 (self.function, self.probe_num)
184
185 def __str__(self):
186 return "%s:%s`%s FLT=%s ACT=%s/%s" % (self.probe_type,
187 self.library, self.function, self.filter,
188 self.types, self.values)
189
190 def is_default_action(self):
191 return self.python_format == ""
192
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800193 def _generate_tpoint_entry_struct_fields(self):
194 format_lines = Tracepoint.get_tpoint_format(self.tp_category,
195 self.tp_event)
196 text = ""
197 for line in format_lines:
198 match = re.search(r'field:([^;]*);.*size:(\d+);', line)
199 if match is None:
200 continue
201 parts = match.group(1).split()
202 field_name = parts[-1:][0]
203 field_type = " ".join(parts[:-1])
204 field_size = int(match.group(2))
205 if "__data_loc" in field_type:
206 continue
207 if field_name.startswith("common_"):
208 continue
209 text += " %s %s;\n" % (field_type, field_name)
210 return text
211
212 def _generate_tpoint_entry_struct(self):
213 text = """
214struct %s {
215 u64 __do_not_use__;
216%s
217};
218 """
219 self.tp_entry_struct_name = self.probe_name + \
220 "_trace_entry"
221 fields = self._generate_tpoint_entry_struct_fields()
222 return text % (self.tp_entry_struct_name, fields)
223
224 def _generate_tpoint_entry_prefix(self):
225 text = """
226 u64 tid = bpf_get_current_pid_tgid();
227 u64 *di = __trace_di.lookup(&tid);
228 if (di == 0) { return 0; }
229 struct %s tp = {};
230 bpf_probe_read(&tp, sizeof(tp), (void *)*di);
231 """ % self.tp_entry_struct_name
232 return text
233
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800234 def _bail(self, error):
235 raise ValueError("error parsing probe '%s': %s" %
236 (self.raw_probe, error))
237
238 def _parse_probe(self):
239 text = self.raw_probe
240
241 # Everything until the first space is the probe specifier
242 first_space = text.find(' ')
243 spec = text[:first_space] if first_space >= 0 else text
244 self._parse_spec(spec)
245 if first_space >= 0:
246 text = text[first_space:].lstrip()
247 else:
248 text = ""
249
250 # If we now have a (, wait for the balanced closing ) and that
251 # will be the predicate
252 self.filter = None
253 if len(text) > 0 and text[0] == "(":
254 balance = 1
255 for i in range(1, len(text)):
256 if text[i] == "(":
257 balance += 1
258 if text[i] == ")":
259 balance -= 1
260 if balance == 0:
261 self._parse_filter(text[:i+1])
262 text = text[i+1:]
263 break
264 if self.filter is None:
265 self._bail("unmatched end of predicate")
266
267 if self.filter is None:
268 self.filter = "1"
269
270 # The remainder of the text is the printf action
271 self._parse_action(text.lstrip())
272
273 def _parse_spec(self, spec):
274 parts = spec.split(":")
275 # Two special cases: 'func' means 'p::func', 'lib:func' means
276 # 'p:lib:func'. Other combinations need to provide an empty
277 # value between delimiters, e.g. 'r::func' for a kretprobe on
278 # the function func.
279 if len(parts) == 1:
280 parts = ["p", "", parts[0]]
281 elif len(parts) == 2:
282 parts = ["p", parts[0], parts[1]]
283 if len(parts[0]) == 0:
284 self.probe_type = "p"
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800285 elif parts[0] in ["p", "r", "t"]:
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800286 self.probe_type = parts[0]
287 else:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800288 self._bail("expected '', 'p', 't', or 'r', got '%s'" %
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800289 parts[0])
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800290 if self.probe_type == "t":
291 self.tp_category = parts[1]
292 self.tp_event = parts[2]
293 Tracepoint.enable_tracepoint(self.tp_category,
294 self.tp_event)
295 self.library = "" # kernel
296 self.function = "perf_trace_%s" % self.tp_event
297 else:
298 self.library = parts[1]
299 self.function = parts[2]
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800300
301 def _parse_filter(self, filt):
302 self.filter = self._replace_args(filt)
303
304 def _parse_types(self, fmt):
305 for match in re.finditer(
306 r'[^%]%(s|u|d|llu|lld|hu|hd|x|llx|c)', fmt):
307 self.types.append(match.group(1))
308 fmt = re.sub(r'([^%]%)(u|d|llu|lld|hu|hd)', r'\1d', fmt)
309 fmt = re.sub(r'([^%]%)(x|llx)', r'\1x', fmt)
310 self.python_format = fmt.strip('"')
311
312 def _parse_action(self, action):
313 self.values = []
314 self.types = []
315 self.python_format = ""
316 if len(action) == 0:
317 return
318
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800319 action = action.strip()
320 match = re.search(r'(\".*\"),?(.*)', action)
321 if match is None:
322 self._bail("expected format string in \"s")
323
324 self.raw_format = match.group(1)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800325 self._parse_types(self.raw_format)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800326 for part in match.group(2).split(','):
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800327 part = self._replace_args(part)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800328 if len(part) > 0:
329 self.values.append(part)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800330
331 aliases = {
332 "retval": "ctx->ax",
333 "arg1": "ctx->di",
334 "arg2": "ctx->si",
335 "arg3": "ctx->dx",
336 "arg4": "ctx->cx",
337 "arg5": "ctx->r8",
338 "arg6": "ctx->r9",
339 "$uid": "(unsigned)(bpf_get_current_uid_gid() & 0xffffffff)",
340 "$gid": "(unsigned)(bpf_get_current_uid_gid() >> 32)",
341 "$pid": "(unsigned)(bpf_get_current_pid_tgid() & 0xffffffff)",
342 "$tgid": "(unsigned)(bpf_get_current_pid_tgid() >> 32)",
343 "$cpu": "bpf_get_smp_processor_id()"
344 }
345
346 def _replace_args(self, expr):
347 for alias, replacement in Probe.aliases.items():
348 expr = expr.replace(alias, replacement)
349 return expr
350
351 p_type = { "u": ct.c_uint, "d": ct.c_int,
352 "llu": ct.c_ulonglong, "lld": ct.c_longlong,
353 "hu": ct.c_ushort, "hd": ct.c_short,
354 "x": ct.c_uint, "llx": ct.c_ulonglong,
355 "c": ct.c_ubyte }
356
357 def _generate_python_field_decl(self, idx, fields):
358 field_type = self.types[idx]
359 if field_type == "s":
360 ptype = ct.c_char * self.string_size
361 else:
362 ptype = Probe.p_type[field_type]
363 fields.append(("v%d" % idx, ptype))
364
365 def _generate_python_data_decl(self):
366 self.python_struct_name = "%s_%d_Data" % \
367 (self.function, self.probe_num)
368 fields = [
369 ("timestamp_ns", ct.c_ulonglong),
370 ("pid", ct.c_uint),
371 ("comm", ct.c_char * 16) # TASK_COMM_LEN
372 ]
373 for i in range(0, len(self.types)):
374 self._generate_python_field_decl(i, fields)
375 return type(self.python_struct_name, (ct.Structure,),
376 dict(_fields_=fields))
377
378 c_type = { "u": "unsigned int", "d": "int",
379 "llu": "unsigned long long", "lld": "long long",
380 "hu": "unsigned short", "hd": "short",
381 "x": "unsigned int", "llx": "unsigned long long",
382 "c": "char" }
383 fmt_types = c_type.keys()
384
385 def _generate_field_decl(self, idx):
386 field_type = self.types[idx]
387 if field_type == "s":
388 return "char v%d[%d];\n" % (idx, self.string_size)
389 if field_type in Probe.fmt_types:
390 return "%s v%d;\n" % (Probe.c_type[field_type], idx)
391 self._bail("unrecognized format specifier %s" % field_type)
392
393 def _generate_data_decl(self):
394 # The BPF program will populate values into the struct
395 # according to the format string, and the Python program will
396 # construct the final display string.
397 self.events_name = "%s_events" % self.probe_name
398 self.struct_name = "%s_data_t" % self.probe_name
399
400 data_fields = ""
401 for i, field_type in enumerate(self.types):
402 data_fields += " " + \
403 self._generate_field_decl(i)
404
405 text = """
406struct %s
407{
408 u64 timestamp_ns;
409 u32 pid;
410 char comm[TASK_COMM_LEN];
411%s
412};
413
414BPF_PERF_OUTPUT(%s);
415"""
416 return text % (self.struct_name, data_fields, self.events_name)
417
418 def _generate_field_assign(self, idx):
419 field_type = self.types[idx]
420 expr = self.values[idx]
421 if field_type == "s":
422 return """
423 if (%s != 0) {
424 bpf_probe_read(&__data.v%d, sizeof(__data.v%d), (void *)%s);
425 }
426""" % (expr, idx, idx, expr)
427 # return ("bpf_probe_read(&__data.v%d, " + \
428 # "sizeof(__data.v%d), (char*)%s);\n") % (idx, idx, expr)
429 # return ("__builtin_memcpy(&__data.v%d, (void *)%s, " + \
430 # "sizeof(__data.v%d));\n") % (idx, expr, idx)
431 if field_type in Probe.fmt_types:
432 return " __data.v%d = (%s)%s;\n" % \
433 (idx, Probe.c_type[field_type], expr)
434 self._bail("unrecognized field type %s" % field_type)
435
436 def generate_program(self, pid, include_self):
437 data_decl = self._generate_data_decl()
438 self.pid = pid
439 # kprobes don't have built-in pid filters, so we have to add
440 # it to the function body:
441 if len(self.library) == 0 and pid != -1:
442 pid_filter = """
443 u32 __pid = bpf_get_current_pid_tgid();
444 if (__pid != %d) { return 0; }
445""" % pid
446 elif not include_self:
447 pid_filter = """
448 u32 __pid = bpf_get_current_pid_tgid();
449 if (__pid == %d) { return 0; }
450""" % os.getpid()
451 else:
452 pid_filter = ""
453
454 data_fields = ""
455 for i, expr in enumerate(self.values):
456 data_fields += self._generate_field_assign(i)
457
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800458 prefix = ""
459 if self.probe_type == "t":
460 data_decl += self._generate_tpoint_entry_struct()
461 prefix = self._generate_tpoint_entry_prefix()
462
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800463 text = """
464int %s(struct pt_regs *ctx)
465{
466 %s
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800467 %s
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800468 if (!(%s)) return 0;
469
470 struct %s __data = {0};
471 __data.timestamp_ns = bpf_ktime_get_ns();
472 __data.pid = bpf_get_current_pid_tgid();
473 bpf_get_current_comm(&__data.comm, sizeof(__data.comm));
474%s
475 %s.perf_submit(ctx, &__data, sizeof(__data));
476 return 0;
477}
478"""
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800479 text = text % (self.probe_name, pid_filter, prefix,
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800480 self.filter, self.struct_name,
481 data_fields, self.events_name)
482
483 return data_decl + "\n" + text
484
485 @classmethod
486 def _time_off_str(cls, timestamp_ns):
487 return "%.6f" % (1e-9 * (timestamp_ns - cls.first_ts))
488
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800489 auto_includes = {
490 "linux/time.h" : ["time"],
491 "linux/fs.h" : ["fs", "file"],
492 "linux/blkdev.h" : ["bio", "request"],
493 "linux/slab.h" : ["alloc"],
494 "linux/netdevice.h" : ["sk_buff"]
495 }
496
497 @classmethod
498 def generate_auto_includes(cls, probes):
499 headers = ""
500 for header, keywords in cls.auto_includes.items():
501 for keyword in keywords:
502 for probe in probes:
503 if keyword in probe:
504 headers += "#include <%s>\n" \
505 % header
506 return headers
507
508 def _display_function(self):
509 if self.probe_type != 't':
510 return self.function
511 else:
512 return self.function.replace("perf_trace_", "")
513
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800514 def print_event(self, cpu, data, size):
515 # Cast as the generated structure type and display
516 # according to the format string in the probe.
517 event = ct.cast(data, ct.POINTER(self.python_struct)).contents
518 values = map(lambda i: getattr(event, "v%d" % i),
519 range(0, len(self.values)))
520 msg = self.python_format % tuple(values)
521 time = strftime("%H:%M:%S") if Probe.use_localtime else \
522 Probe._time_off_str(event.timestamp_ns)
523 print("%-8s %-6d %-12s %-16s %s" % \
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800524 (time[:8], event.pid, event.comm[:12],
525 self._display_function(), msg))
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800526
527 Probe.event_count += 1
528 if Probe.max_events is not None and \
529 Probe.event_count >= Probe.max_events:
530 exit()
531
532 def attach(self, bpf, verbose):
533 if len(self.library) == 0:
534 self._attach_k(bpf)
535 else:
536 self._attach_u(bpf)
537 self.python_struct = self._generate_python_data_decl()
538 bpf[self.events_name].open_perf_buffer(self.print_event)
539
540 def _attach_k(self, bpf):
541 if self.probe_type == "r":
542 bpf.attach_kretprobe(event=self.function,
543 fn_name=self.probe_name)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800544 elif self.probe_type == "p" or self.probe_type == "t":
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800545 bpf.attach_kprobe(event=self.function,
546 fn_name=self.probe_name)
547
548 def _attach_u(self, bpf):
549 libpath = BPF.find_library(self.library)
550 if libpath is None:
551 # This might be an executable (e.g. 'bash')
552 with os.popen("/usr/bin/which %s 2>/dev/null" %
553 self.library) as w:
554 libpath = w.read().strip()
555 if libpath is None or len(libpath) == 0:
556 self._bail("unable to find library %s" % self.library)
557
558 if self.probe_type == "r":
559 bpf.attach_uretprobe(name=libpath,
560 sym=self.function,
561 fn_name=self.probe_name,
562 pid=self.pid)
563 else:
564 bpf.attach_uprobe(name=libpath,
565 sym=self.function,
566 fn_name=self.probe_name,
567 pid=self.pid)
568
569class Tool(object):
570 examples = """
571EXAMPLES:
572
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800573trace do_sys_open
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800574 Trace the open syscall and print a default trace message when entered
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800575trace 'do_sys_open "%s", arg2'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800576 Trace the open syscall and print the filename being opened
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800577trace 'sys_read (arg3 > 20000) "read %d bytes", arg3'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800578 Trace the read syscall and print a message for reads >20000 bytes
579trace 'r::do_sys_return "%llx", retval'
580 Trace the return from the open syscall and print the return value
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800581trace 'c:open (arg2 == 42) "%s %d", arg1, arg2'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800582 Trace the open() call from libc only if the flags (arg2) argument is 42
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800583trace 'c:malloc "size = %d", arg1'
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800584 Trace malloc calls and print the size being allocated
Sasha Goldshtein8acd0152016-02-22 02:25:03 -0800585trace 'p:c:write (arg1 == 1) "writing %d bytes to STDOUT", arg3'
586 Trace the write() call from libc to monitor writes to STDOUT
587trace 'r::__kmalloc (retval == 0) "kmalloc failed!"
588 Trace returns from __kmalloc which returned a null pointer
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800589trace 'r:c:malloc (retval) "allocated = %p", retval
590 Trace returns from malloc and print non-NULL allocated buffers
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800591trace 't:block:block_rq_complete "sectors=%d", tp.nr_sector'
592 Trace the block_rq_complete kernel tracepoint and print # of tx sectors
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800593"""
594
595 def __init__(self):
596 parser = argparse.ArgumentParser(description=
597 "Attach to functions and print trace messages.",
598 formatter_class=argparse.RawDescriptionHelpFormatter,
599 epilog=Tool.examples)
600 parser.add_argument("-p", "--pid", type=int,
601 help="id of the process to trace (optional)")
602 parser.add_argument("-v", "--verbose", action="store_true",
603 help="print resulting BPF program code before executing")
604 parser.add_argument("-Z", "--string-size", type=int,
605 default=80, help="maximum size to read from strings")
606 parser.add_argument("-S", "--include-self", action="store_true",
607 help="do not filter trace's own pid from the trace")
608 parser.add_argument("-M", "--max-events", type=int,
609 help="number of events to print before quitting")
610 parser.add_argument("-o", "--offset", action="store_true",
611 help="use relative time from first traced message")
612 parser.add_argument(metavar="probe", dest="probes", nargs="+",
613 help="probe specifier (see examples)")
614 self.args = parser.parse_args()
615
616 def _create_probes(self):
617 Probe.configure(self.args)
618 self.probes = []
619 for probe_spec in self.args.probes:
620 self.probes.append(Probe(
621 probe_spec, self.args.string_size))
622
623 def _generate_program(self):
624 self.program = """
625#include <linux/ptrace.h>
626#include <linux/sched.h> /* For TASK_COMM_LEN */
627
628"""
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800629 self.program += Probe.generate_auto_includes(
630 map(lambda p: p.raw_probe, self.probes))
631 self.program += Tracepoint.generate_decl()
632 self.program += Tracepoint.generate_entry_probe()
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800633 for probe in self.probes:
634 self.program += probe.generate_program(
635 self.args.pid or -1, self.args.include_self)
636
637 if self.args.verbose:
638 print(self.program)
639
640 def _attach_probes(self):
641 self.bpf = BPF(text=self.program)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800642 Tracepoint.attach(self.bpf)
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800643 for probe in self.probes:
644 if self.args.verbose:
645 print(probe)
646 probe.attach(self.bpf, self.args.verbose)
647
648 def _main_loop(self):
649 all_probes_trivial = all(map(Probe.is_default_action,
650 self.probes))
651
652 # Print header
653 print("%-8s %-6s %-12s %-16s %s" % \
654 ("TIME", "PID", "COMM", "FUNC",
655 "-" if not all_probes_trivial else ""))
656
657 while True:
658 self.bpf.kprobe_poll()
659
660 def run(self):
661 try:
662 self._create_probes()
663 self._generate_program()
664 self._attach_probes()
665 self._main_loop()
666 except:
667 if self.args.verbose:
668 traceback.print_exc()
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800669 elif sys.exc_type is not SystemExit:
Sasha Goldshtein38847f02016-02-22 02:19:24 -0800670 print(sys.exc_value)
671
672if __name__ == "__main__":
673 Tool().run()