blob: b810126ec7e5b391da21a8402fda63dc113c8a41 [file] [log] [blame]
Alexey Ivanovcc01a9c2019-01-16 09:50:46 -08001#!/usr/bin/python
Sasha Goldshtein85384852016-02-12 01:29:39 -08002#
Sasha Goldshtein7df65da2016-02-14 05:12:27 -08003# argdist Trace a function and display a distribution of its
Sasha Goldshteinfd60d552016-03-01 12:15:34 -08004# parameter values as a histogram or frequency count.
Sasha Goldshtein85384852016-02-12 01:29:39 -08005#
Sasha Goldshtein4725a722016-10-18 20:54:47 +03006# USAGE: argdist [-h] [-p PID] [-z STRING_SIZE] [-i INTERVAL] [-n COUNT] [-v]
7# [-c] [-T TOP] [-C specifier] [-H specifier] [-I header]
Sasha Goldshtein85384852016-02-12 01:29:39 -08008#
9# Licensed under the Apache License, Version 2.0 (the "License")
10# Copyright (C) 2016 Sasha Goldshtein.
11
Sumanth Korikkar306080b2020-04-27 04:37:23 -050012from bcc import BPF, USDT, StrcmpRewrite
Sasha Goldshtein85384852016-02-12 01:29:39 -080013from time import sleep, strftime
14import argparse
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080015import re
Sasha Goldshteinc9551302016-02-21 02:21:46 -080016import traceback
Sasha Goldshteinfd60d552016-03-01 12:15:34 -080017import os
Sasha Goldshteinc9551302016-02-21 02:21:46 -080018import sys
Sasha Goldshtein85384852016-02-12 01:29:39 -080019
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070020class Probe(object):
Sasha Goldshtein85384852016-02-12 01:29:39 -080021 next_probe_index = 0
Sasha Goldshteinc8f752f2016-10-17 02:18:43 -070022 streq_index = 0
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010023 aliases = {"$PID": "(bpf_get_current_pid_tgid() >> 32)"}
Sasha Goldshtein5e4e1f42016-02-12 06:52:19 -080024
25 def _substitute_aliases(self, expr):
26 if expr is None:
27 return expr
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070028 for alias, subst in Probe.aliases.items():
Sasha Goldshtein5e4e1f42016-02-12 06:52:19 -080029 expr = expr.replace(alias, subst)
30 return expr
Sasha Goldshtein85384852016-02-12 01:29:39 -080031
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080032 def _parse_signature(self):
33 params = map(str.strip, self.signature.split(','))
34 self.param_types = {}
35 for param in params:
36 # If the type is a pointer, the * can be next to the
37 # param name. Other complex types like arrays are not
38 # supported right now.
39 index = param.rfind('*')
40 index = index if index != -1 else param.rfind(' ')
Sasha Goldshteinf41ae862016-10-19 01:14:30 +030041 param_type = param[0:index + 1].strip()
42 param_name = param[index + 1:].strip()
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080043 self.param_types[param_name] = param_type
Sumanth Korikkar306080b2020-04-27 04:37:23 -050044 # Maintain list of user params. Then later decide to
Sumanth Korikkar7f6066d2020-05-20 10:49:56 -050045 # switch to bpf_probe_read_kernel or bpf_probe_read_user.
Sumanth Korikkar306080b2020-04-27 04:37:23 -050046 if "__user" in param_type.split():
47 self.probe_user_list.add(param_name)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080048
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070049 def _generate_entry(self):
50 self.entry_probe_func = self.probe_func_name + "_entry"
51 text = """
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080052int PROBENAME(struct pt_regs *ctx SIGNATURE)
53{
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010054 u64 __pid_tgid = bpf_get_current_pid_tgid();
55 u32 __pid = __pid_tgid; // lower 32 bits
56 u32 __tgid = __pid_tgid >> 32; // upper 32 bits
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080057 PID_FILTER
58 COLLECT
59 return 0;
60}
61"""
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080062 text = text.replace("PROBENAME", self.entry_probe_func)
63 text = text.replace("SIGNATURE",
64 "" if len(self.signature) == 0 else ", " + self.signature)
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010065 text = text.replace("PID_FILTER", self._generate_pid_filter())
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080066 collect = ""
67 for pname in self.args_to_probe:
Sasha Goldshteine3501152016-02-13 03:56:29 -080068 param_hash = self.hashname_prefix + pname
69 if pname == "__latency":
70 collect += """
71u64 __time = bpf_ktime_get_ns();
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010072%s.update(&__pid, &__time);
Sasha Goldshteinf41ae862016-10-19 01:14:30 +030073 """ % param_hash
Sasha Goldshteine3501152016-02-13 03:56:29 -080074 else:
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010075 collect += "%s.update(&__pid, &%s);\n" % \
Sasha Goldshteine3501152016-02-13 03:56:29 -080076 (param_hash, pname)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080077 text = text.replace("COLLECT", collect)
78 return text
79
80 def _generate_entry_probe(self):
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080081 # Any $entry(name) expressions result in saving that argument
82 # when entering the function.
83 self.args_to_probe = set()
84 regex = r"\$entry\((\w+)\)"
Sasha Goldshteincc27edf2016-02-14 03:49:01 -080085 for expr in self.exprs:
86 for arg in re.finditer(regex, expr):
87 self.args_to_probe.add(arg.group(1))
Sasha Goldshteine3501152016-02-13 03:56:29 -080088 for arg in re.finditer(regex, self.filter):
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080089 self.args_to_probe.add(arg.group(1))
Sasha Goldshteincc27edf2016-02-14 03:49:01 -080090 if any(map(lambda expr: "$latency" in expr, self.exprs)) or \
91 "$latency" in self.filter:
Sasha Goldshteine3501152016-02-13 03:56:29 -080092 self.args_to_probe.add("__latency")
93 self.param_types["__latency"] = "u64" # nanoseconds
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080094 for pname in self.args_to_probe:
95 if pname not in self.param_types:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +030096 raise ValueError("$entry(%s): no such param" %
97 arg)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080098
99 self.hashname_prefix = "%s_param_" % self.probe_hash_name
100 text = ""
101 for pname in self.args_to_probe:
102 # Each argument is stored in a separate hash that is
103 # keyed by pid.
104 text += "BPF_HASH(%s, u32, %s);\n" % \
105 (self.hashname_prefix + pname,
106 self.param_types[pname])
107 text += self._generate_entry()
108 return text
109
110 def _generate_retprobe_prefix(self):
111 # After we're done here, there are __%s_val variables for each
112 # argument we needed to probe using $entry(name), and they all
113 # have values (which isn't necessarily the case if we missed
114 # the method entry probe).
Rafael Fonsecaaf236e72017-02-15 17:28:26 +0100115 text = ""
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800116 self.param_val_names = {}
117 for pname in self.args_to_probe:
118 val_name = "__%s_val" % pname
119 text += "%s *%s = %s.lookup(&__pid);\n" % \
120 (self.param_types[pname], val_name,
121 self.hashname_prefix + pname)
122 text += "if (%s == 0) { return 0 ; }\n" % val_name
123 self.param_val_names[pname] = val_name
124 return text
125
126 def _replace_entry_exprs(self):
127 for pname, vname in self.param_val_names.items():
Sasha Goldshteine3501152016-02-13 03:56:29 -0800128 if pname == "__latency":
129 entry_expr = "$latency"
130 val_expr = "(bpf_ktime_get_ns() - *%s)" % vname
131 else:
132 entry_expr = "$entry(%s)" % pname
133 val_expr = "(*%s)" % vname
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800134 for i in range(0, len(self.exprs)):
135 self.exprs[i] = self.exprs[i].replace(
136 entry_expr, val_expr)
Sasha Goldshteine3501152016-02-13 03:56:29 -0800137 self.filter = self.filter.replace(entry_expr,
138 val_expr)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800139
140 def _attach_entry_probe(self):
141 if self.is_user:
142 self.bpf.attach_uprobe(name=self.library,
143 sym=self.function,
144 fn_name=self.entry_probe_func,
145 pid=self.pid or -1)
146 else:
147 self.bpf.attach_kprobe(event=self.function,
148 fn_name=self.entry_probe_func)
149
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800150 def _bail(self, error):
151 raise ValueError("error parsing probe '%s': %s" %
152 (self.raw_spec, error))
153
154 def _validate_specifier(self):
155 # Everything after '#' is the probe label, ignore it
156 spec = self.raw_spec.split('#')[0]
157 parts = spec.strip().split(':')
158 if len(parts) < 3:
159 self._bail("at least the probe type, library, and " +
160 "function signature must be specified")
161 if len(parts) > 6:
162 self._bail("extraneous ':'-separated parts detected")
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700163 if parts[0] not in ["r", "p", "t", "u"]:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300164 self._bail("probe type must be 'p', 'r', 't', or 'u'" +
165 " but got '%s'" % parts[0])
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000166 if re.match(r"\S+\(.*\)", parts[2]) is None:
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800167 self._bail(("function signature '%s' has an invalid " +
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800168 "format") % parts[2])
169
170 def _parse_expr_types(self, expr_types):
171 if len(expr_types) == 0:
172 self._bail("no expr types specified")
173 self.expr_types = expr_types.split(',')
174
175 def _parse_exprs(self, exprs):
176 if len(exprs) == 0:
177 self._bail("no exprs specified")
178 self.exprs = exprs.split(',')
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800179
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000180 def _make_valid_identifier(self, ident):
181 return re.sub(r'[^A-Za-z0-9_]', '_', ident)
182
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300183 def __init__(self, tool, type, specifier):
184 self.usdt_ctx = None
Sasha Goldshteinc8f752f2016-10-17 02:18:43 -0700185 self.streq_functions = ""
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300186 self.pid = tool.args.pid
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300187 self.cumulative = tool.args.cumulative or False
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800188 self.raw_spec = specifier
Sumanth Korikkar306080b2020-04-27 04:37:23 -0500189 self.probe_user_list = set()
190 self.bin_cmp = False
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800191 self._validate_specifier()
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800192
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800193 spec_and_label = specifier.split('#')
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800194 self.label = spec_and_label[1] \
195 if len(spec_and_label) == 2 else None
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800196
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800197 parts = spec_and_label[0].strip().split(':')
Sasha Goldshtein85384852016-02-12 01:29:39 -0800198 self.type = type # hist or freq
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800199 self.probe_type = parts[0]
Sasha Goldshtein85384852016-02-12 01:29:39 -0800200 fparts = parts[2].split('(')
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800201 self.function = fparts[0].strip()
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800202 if self.probe_type == "t":
203 self.library = "" # kernel
204 self.tp_category = parts[1]
205 self.tp_event = self.function
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700206 elif self.probe_type == "u":
207 self.library = parts[1]
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000208 self.probe_func_name = self._make_valid_identifier(
Paul Chaignon956ca1c2017-03-04 20:07:56 +0100209 "%s_probe%d" %
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000210 (self.function, Probe.next_probe_index))
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300211 self._enable_usdt_probe()
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800212 else:
213 self.library = parts[1]
214 self.is_user = len(self.library) > 0
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800215 self.signature = fparts[1].strip()[:-1]
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800216 self._parse_signature()
217
218 # If the user didn't specify an expression to probe, we probe
219 # the retval in a ret probe, or simply the value "1" otherwise.
Sasha Goldshtein85384852016-02-12 01:29:39 -0800220 self.is_default_expr = len(parts) < 5
221 if not self.is_default_expr:
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800222 self._parse_expr_types(parts[3])
223 self._parse_exprs(parts[4])
224 if len(self.exprs) != len(self.expr_types):
225 self._bail("mismatched # of exprs and types")
226 if self.type == "hist" and len(self.expr_types) > 1:
227 self._bail("histograms can only have 1 expr")
Sasha Goldshtein85384852016-02-12 01:29:39 -0800228 else:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800229 if not self.probe_type == "r" and self.type == "hist":
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800230 self._bail("histograms must have expr")
231 self.expr_types = \
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800232 ["u64" if not self.probe_type == "r" else "int"]
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800233 self.exprs = \
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800234 ["1" if not self.probe_type == "r" else "$retval"]
Sasha Goldshteine3501152016-02-13 03:56:29 -0800235 self.filter = "" if len(parts) != 6 else parts[5]
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800236 self._substitute_exprs()
237
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800238 # Do we need to attach an entry probe so that we can collect an
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800239 # argument that is required for an exit (return) probe?
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800240 def check(expr):
241 keywords = ["$entry", "$latency"]
242 return any(map(lambda kw: kw in expr, keywords))
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800243 self.entry_probe_required = self.probe_type == "r" and \
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800244 (any(map(check, self.exprs)) or check(self.filter))
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800245
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000246 self.probe_func_name = self._make_valid_identifier(
Paul Chaignon956ca1c2017-03-04 20:07:56 +0100247 "%s_probe%d" %
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000248 (self.function, Probe.next_probe_index))
249 self.probe_hash_name = self._make_valid_identifier(
Paul Chaignon956ca1c2017-03-04 20:07:56 +0100250 "%s_hash%d" %
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000251 (self.function, Probe.next_probe_index))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700252 Probe.next_probe_index += 1
253
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300254 def _enable_usdt_probe(self):
255 self.usdt_ctx = USDT(path=self.library, pid=self.pid)
256 self.usdt_ctx.enable_probe(
257 self.function, self.probe_func_name)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800258
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800259 def _substitute_exprs(self):
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800260 def repl(expr):
261 expr = self._substitute_aliases(expr)
Sumanth Korikkar306080b2020-04-27 04:37:23 -0500262 rdict = StrcmpRewrite.rewrite_expr(expr,
263 self.bin_cmp, self.library,
264 self.probe_user_list, self.streq_functions,
265 Probe.streq_index)
266 expr = rdict["expr"]
267 self.streq_functions = rdict["streq_functions"]
268 Probe.streq_index = rdict["probeid"]
Naveen N. Rao4afa96a2016-05-03 14:54:21 +0530269 return expr.replace("$retval", "PT_REGS_RC(ctx)")
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800270 for i in range(0, len(self.exprs)):
271 self.exprs[i] = repl(self.exprs[i])
272 self.filter = repl(self.filter)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800273
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800274 def _is_string(self, expr_type):
275 return expr_type == "char*" or expr_type == "char *"
Sasha Goldshtein85384852016-02-12 01:29:39 -0800276
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800277 def _generate_hash_field(self, i):
278 if self._is_string(self.expr_types[i]):
279 return "struct __string_t v%d;\n" % i
280 else:
281 return "%s v%d;\n" % (self.expr_types[i], i)
282
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300283 def _generate_usdt_arg_assignment(self, i):
284 expr = self.exprs[i]
285 if self.probe_type == "u" and expr[0:3] == "arg":
Sasha Goldshtein3a5256f2017-02-20 15:42:57 +0000286 arg_index = int(expr[3])
287 arg_ctype = self.usdt_ctx.get_probe_arg_ctype(
288 self.function, arg_index - 1)
289 return (" %s %s = 0;\n" +
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300290 " bpf_usdt_readarg(%s, ctx, &%s);\n") \
Sasha Goldshtein3a5256f2017-02-20 15:42:57 +0000291 % (arg_ctype, expr, expr[3], expr)
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300292 else:
293 return ""
294
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800295 def _generate_field_assignment(self, i):
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300296 text = self._generate_usdt_arg_assignment(i)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800297 if self._is_string(self.expr_types[i]):
Sumanth Korikkar306080b2020-04-27 04:37:23 -0500298 if self.is_user or \
299 self.exprs[i] in self.probe_user_list:
300 probe_readfunc = "bpf_probe_read_user"
301 else:
Sumanth Korikkar7f6066d2020-05-20 10:49:56 -0500302 probe_readfunc = "bpf_probe_read_kernel"
Sumanth Korikkar306080b2020-04-27 04:37:23 -0500303 return (text + " %s(&__key.v%d.s," +
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700304 " sizeof(__key.v%d.s), (void *)%s);\n") % \
Sumanth Korikkar306080b2020-04-27 04:37:23 -0500305 (probe_readfunc, i, i, self.exprs[i])
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800306 else:
Brendan Gregg4f88a942016-07-22 17:11:51 -0700307 return text + " __key.v%d = %s;\n" % \
308 (i, self.exprs[i])
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800309
310 def _generate_hash_decl(self):
311 if self.type == "hist":
312 return "BPF_HISTOGRAM(%s, %s);" % \
313 (self.probe_hash_name, self.expr_types[0])
314 else:
315 text = "struct %s_key_t {\n" % self.probe_hash_name
316 for i in range(0, len(self.expr_types)):
317 text += self._generate_hash_field(i)
318 text += "};\n"
319 text += "BPF_HASH(%s, struct %s_key_t, u64);\n" % \
320 (self.probe_hash_name, self.probe_hash_name)
321 return text
322
323 def _generate_key_assignment(self):
324 if self.type == "hist":
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300325 return self._generate_usdt_arg_assignment(0) + \
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300326 ("%s __key = %s;\n" %
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300327 (self.expr_types[0], self.exprs[0]))
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800328 else:
329 text = "struct %s_key_t __key = {};\n" % \
330 self.probe_hash_name
331 for i in range(0, len(self.exprs)):
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800332 text += self._generate_field_assignment(i)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800333 return text
334
335 def _generate_hash_update(self):
336 if self.type == "hist":
zcy80242fb2021-07-02 00:12:32 +0800337 return "%s.atomic_increment(bpf_log2l(__key));" % \
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800338 self.probe_hash_name
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800339 else:
zcy80242fb2021-07-02 00:12:32 +0800340 return "%s.atomic_increment(__key);" % \
341 self.probe_hash_name
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800342
343 def _generate_pid_filter(self):
344 # Kernel probes need to explicitly filter pid, because the
345 # attach interface doesn't support pid filtering
346 if self.pid is not None and not self.is_user:
Rafael Fonsecaaf236e72017-02-15 17:28:26 +0100347 return "if (__tgid != %d) { return 0; }" % self.pid
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800348 else:
349 return ""
350
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800351 def generate_text(self):
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800352 program = ""
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700353 probe_text = """
354DATA_DECL
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300355 """ + (
356 "TRACEPOINT_PROBE(%s, %s)" %
357 (self.tp_category, self.tp_event)
358 if self.probe_type == "t"
359 else "int PROBENAME(struct pt_regs *ctx SIGNATURE)") + """
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700360{
Rafael Fonsecaaf236e72017-02-15 17:28:26 +0100361 u64 __pid_tgid = bpf_get_current_pid_tgid();
362 u32 __pid = __pid_tgid; // lower 32 bits
363 u32 __tgid = __pid_tgid >> 32; // upper 32 bits
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700364 PID_FILTER
365 PREFIX
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700366 KEY_EXPR
Akilesh Kailashb8269aa2020-05-11 11:54:26 -0700367 if (!(FILTER)) return 0;
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700368 COLLECT
369 return 0;
370}
371"""
372 prefix = ""
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700373 signature = ""
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800374
375 # If any entry arguments are probed in a ret probe, we need
376 # to generate an entry probe to collect them
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800377 if self.entry_probe_required:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800378 program += self._generate_entry_probe()
379 prefix += self._generate_retprobe_prefix()
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800380 # Replace $entry(paramname) with a reference to the
381 # value we collected when entering the function:
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800382 self._replace_entry_exprs()
383
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300384 if self.probe_type == "p" and len(self.signature) > 0:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700385 # Only entry uprobes/kprobes can have user-specified
386 # signatures. Other probes force it to ().
387 signature = ", " + self.signature
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800388
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300389 program += probe_text.replace("PROBENAME",
390 self.probe_func_name)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800391 program = program.replace("SIGNATURE", signature)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800392 program = program.replace("PID_FILTER",
393 self._generate_pid_filter())
394
395 decl = self._generate_hash_decl()
396 key_expr = self._generate_key_assignment()
397 collect = self._generate_hash_update()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800398 program = program.replace("DATA_DECL", decl)
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800399 program = program.replace("KEY_EXPR", key_expr)
Sasha Goldshteine3501152016-02-13 03:56:29 -0800400 program = program.replace("FILTER",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800401 "1" if len(self.filter) == 0 else self.filter)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800402 program = program.replace("COLLECT", collect)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800403 program = program.replace("PREFIX", prefix)
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700404
Sasha Goldshteinc8f752f2016-10-17 02:18:43 -0700405 return self.streq_functions + program
Sasha Goldshtein85384852016-02-12 01:29:39 -0800406
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700407 def _attach_u(self):
408 libpath = BPF.find_library(self.library)
409 if libpath is None:
Sasha Goldshteinec679712016-10-04 18:33:36 +0300410 libpath = BPF.find_exe(self.library)
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700411 if libpath is None or len(libpath) == 0:
Sasha Goldshtein5a1d2e32016-03-30 08:14:44 -0700412 self._bail("unable to find library %s" % self.library)
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700413
Brendan Gregg4f88a942016-07-22 17:11:51 -0700414 if self.probe_type == "r":
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700415 self.bpf.attach_uretprobe(name=libpath,
416 sym=self.function,
417 fn_name=self.probe_func_name,
418 pid=self.pid or -1)
419 else:
420 self.bpf.attach_uprobe(name=libpath,
421 sym=self.function,
422 fn_name=self.probe_func_name,
423 pid=self.pid or -1)
424
425 def _attach_k(self):
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300426 if self.probe_type == "t":
427 pass # Nothing to do for tracepoints
428 elif self.probe_type == "r":
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700429 self.bpf.attach_kretprobe(event=self.function,
430 fn_name=self.probe_func_name)
431 else:
432 self.bpf.attach_kprobe(event=self.function,
433 fn_name=self.probe_func_name)
434
Sasha Goldshtein85384852016-02-12 01:29:39 -0800435 def attach(self, bpf):
436 self.bpf = bpf
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300437 if self.probe_type == "u":
438 return
Sasha Goldshtein85384852016-02-12 01:29:39 -0800439 if self.is_user:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700440 self._attach_u()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800441 else:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700442 self._attach_k()
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800443 if self.entry_probe_required:
444 self._attach_entry_probe()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800445
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800446 def _v2s(self, v):
447 # Most fields can be converted with plain str(), but strings
448 # are wrapped in a __string_t which has an .s field
449 if "__string_t" in type(v).__name__:
450 return str(v.s)
451 return str(v)
452
453 def _display_expr(self, i):
454 # Replace ugly latency calculation with $latency
455 expr = self.exprs[i].replace(
456 "(bpf_ktime_get_ns() - *____latency_val)", "$latency")
457 # Replace alias values back with the alias name
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700458 for alias, subst in Probe.aliases.items():
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800459 expr = expr.replace(subst, alias)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800460 # Replace retval expression with $retval
Naveen N. Rao4afa96a2016-05-03 14:54:21 +0530461 expr = expr.replace("PT_REGS_RC(ctx)", "$retval")
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800462 # Replace ugly (*__param_val) expressions with param name
463 return re.sub(r"\(\*__(\w+)_val\)", r"\1", expr)
464
465 def _display_key(self, key):
466 if self.is_default_expr:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800467 if not self.probe_type == "r":
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800468 return "total calls"
469 else:
470 return "retval = %s" % str(key.v0)
471 else:
472 # The key object has v0, ..., vk fields containing
473 # the values of the expressions from self.exprs
474 def str_i(i):
475 key_i = self._v2s(getattr(key, "v%d" % i))
476 return "%s = %s" % \
477 (self._display_expr(i), key_i)
478 return ", ".join(map(str_i, range(0, len(self.exprs))))
479
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800480 def display(self, top):
Sasha Goldshtein85384852016-02-12 01:29:39 -0800481 data = self.bpf.get_table(self.probe_hash_name)
482 if self.type == "freq":
Sasha Goldshteine3501152016-02-13 03:56:29 -0800483 print(self.label or self.raw_spec)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800484 print("\t%-10s %s" % ("COUNT", "EVENT"))
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300485 sdata = sorted(data.items(), key=lambda p: p[1].value)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800486 if top is not None:
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300487 sdata = sdata[-top:]
488 for key, value in sdata:
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800489 # Print some nice values if the user didn't
490 # specify an expression to probe
Sasha Goldshtein85384852016-02-12 01:29:39 -0800491 if self.is_default_expr:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800492 if not self.probe_type == "r":
Sasha Goldshtein85384852016-02-12 01:29:39 -0800493 key_str = "total calls"
494 else:
495 key_str = "retval = %s" % \
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800496 self._v2s(key.v0)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800497 else:
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800498 key_str = self._display_key(key)
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300499 print("\t%-10s %s" %
Sasha Goldshtein85384852016-02-12 01:29:39 -0800500 (str(value.value), key_str))
501 elif self.type == "hist":
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800502 label = self.label or (self._display_expr(0)
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300503 if not self.is_default_expr else "retval")
Sasha Goldshtein85384852016-02-12 01:29:39 -0800504 data.print_log2_hist(val_type=label)
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300505 if not self.cumulative:
506 data.clear()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800507
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700508 def __str__(self):
509 return self.label or self.raw_spec
510
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800511class Tool(object):
512 examples = """
Sasha Goldshtein85384852016-02-12 01:29:39 -0800513Probe specifier syntax:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700514 {p,r,t,u}:{[library],category}:function(signature)[:type[,type...]:expr[,expr...][:filter]][#label]
Sasha Goldshtein85384852016-02-12 01:29:39 -0800515Where:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300516 p,r,t,u -- probe at function entry, function exit, kernel
517 tracepoint, or USDT probe
Sasha Goldshteine3501152016-02-13 03:56:29 -0800518 in exit probes: can use $retval, $entry(param), $latency
Sasha Goldshtein85384852016-02-12 01:29:39 -0800519 library -- the library that contains the function
520 (leave empty for kernel functions)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800521 category -- the category of the kernel tracepoint (e.g. net, sched)
522 function -- the function name to trace (or tracepoint name)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800523 signature -- the function's parameters, as in the C header
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800524 type -- the type of the expression to collect (supports multiple)
525 expr -- the expression to collect (supports multiple)
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800526 filter -- the filter that is applied to collected values
527 label -- the label for this probe in the resulting output
Sasha Goldshtein85384852016-02-12 01:29:39 -0800528
529EXAMPLES:
530
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800531argdist -H 'p::__kmalloc(u64 size):u64:size'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800532 Print a histogram of allocation sizes passed to kmalloc
533
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800534argdist -p 1005 -C 'p:c:malloc(size_t size):size_t:size:size==16'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800535 Print a frequency count of how many times process 1005 called malloc
536 with an allocation size of 16 bytes
537
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800538argdist -C 'r:c:gets():char*:(char*)$retval#snooped strings'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800539 Snoop on all strings returned by gets()
540
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800541argdist -H 'r::__kmalloc(size_t size):u64:$latency/$entry(size)#ns per byte'
Sasha Goldshteine3501152016-02-13 03:56:29 -0800542 Print a histogram of nanoseconds per byte from kmalloc allocations
543
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300544argdist -C 'p::__kmalloc(size_t sz, gfp_t flags):size_t:sz:flags&GFP_ATOMIC'
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800545 Print frequency count of kmalloc allocation sizes that have GFP_ATOMIC
546
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800547argdist -p 1005 -C 'p:c:write(int fd):int:fd' -T 5
Sasha Goldshtein85384852016-02-12 01:29:39 -0800548 Print frequency counts of how many times writes were issued to a
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800549 particular file descriptor number, in process 1005, but only show
550 the top 5 busiest fds
Sasha Goldshtein85384852016-02-12 01:29:39 -0800551
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800552argdist -p 1005 -H 'r:c:read()'
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800553 Print a histogram of results (sizes) returned by read() in process 1005
Sasha Goldshtein85384852016-02-12 01:29:39 -0800554
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800555argdist -C 'r::__vfs_read():u32:$PID:$latency > 100000'
Sasha Goldshteine3501152016-02-13 03:56:29 -0800556 Print frequency of reads by process where the latency was >0.1ms
557
muahao852e19b2018-08-22 01:17:36 +0800558argdist -H 'r::__vfs_read(void *file, void *buf, size_t count):size_t:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300559 $entry(count):$latency > 1000000'
Sasha Goldshteine3501152016-02-13 03:56:29 -0800560 Print a histogram of read sizes that were longer than 1ms
561
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800562argdist -H \\
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800563 'p:c:write(int fd, const void *buf, size_t count):size_t:count:fd==1'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800564 Print a histogram of buffer sizes passed to write() across all
565 processes, where the file descriptor was 1 (STDOUT)
566
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800567argdist -C 'p:c:fork()#fork calls'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800568 Count fork() calls in libc across all processes
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800569 Can also use funccount.py, which is easier and more flexible
Sasha Goldshtein85384852016-02-12 01:29:39 -0800570
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300571argdist -H 't:block:block_rq_complete():u32:args->nr_sector'
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800572 Print histogram of number of sectors in completing block I/O requests
573
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300574argdist -C 't:irq:irq_handler_entry():int:args->irq'
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800575 Aggregate interrupts by interrupt request (IRQ)
576
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700577argdist -C 'u:pthread:pthread_start():u64:arg2' -p 1337
578 Print frequency of function addresses used as a pthread start function,
579 relying on the USDT pthread_start probe in process 1337
580
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300581argdist -H 'p:c:sleep(u32 seconds):u32:seconds' \\
582 -H 'p:c:nanosleep(struct timespec *req):long:req->tv_nsec'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800583 Print histograms of sleep() and nanosleep() parameter values
584
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800585argdist -p 2780 -z 120 \\
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800586 -C 'p:c:write(int fd, char* buf, size_t len):char*:buf:fd==1'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800587 Spy on writes to STDOUT performed by process 2780, up to a string size
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800588 of 120 characters
Yonghong Songf4470dc2017-12-13 14:12:13 -0800589
590argdist -I 'kernel/sched/sched.h' \\
591 -C 'p::__account_cfs_rq_runtime(struct cfs_rq *cfs_rq):s64:cfs_rq->runtime_remaining'
592 Trace on the cfs scheduling runqueue remaining runtime. The struct cfs_rq is defined
593 in kernel/sched/sched.h which is in kernel source tree and not in kernel-devel
594 package. So this command needs to run at the kernel source tree root directory
595 so that the added header file can be found by the compiler.
Sasha Goldshtein85384852016-02-12 01:29:39 -0800596"""
597
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800598 def __init__(self):
599 parser = argparse.ArgumentParser(description="Trace a " +
600 "function and display a summary of its parameter values.",
601 formatter_class=argparse.RawDescriptionHelpFormatter,
602 epilog=Tool.examples)
603 parser.add_argument("-p", "--pid", type=int,
604 help="id of the process to trace (optional)")
605 parser.add_argument("-z", "--string-size", default=80,
606 type=int,
607 help="maximum string size to read from char* arguments")
608 parser.add_argument("-i", "--interval", default=1, type=int,
Akilesh Kailash89967192018-05-18 13:36:54 -0700609 help="output interval, in seconds (default 1 second)")
610 parser.add_argument("-d", "--duration", type=int,
611 help="total duration of trace, in seconds")
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800612 parser.add_argument("-n", "--number", type=int, dest="count",
613 help="number of outputs")
614 parser.add_argument("-v", "--verbose", action="store_true",
615 help="print resulting BPF program code before executing")
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300616 parser.add_argument("-c", "--cumulative", action="store_true",
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300617 help="do not clear histograms and freq counts at " +
618 "each interval")
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800619 parser.add_argument("-T", "--top", type=int,
620 help="number of top results to show (not applicable to " +
621 "histograms)")
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300622 parser.add_argument("-H", "--histogram", action="append",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800623 dest="histspecifier", metavar="specifier",
624 help="probe specifier to capture histogram of " +
625 "(see examples below)")
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300626 parser.add_argument("-C", "--count", action="append",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800627 dest="countspecifier", metavar="specifier",
628 help="probe specifier to capture count of " +
629 "(see examples below)")
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300630 parser.add_argument("-I", "--include", action="append",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800631 metavar="header",
ShelbyFrancesf5dbbdb2017-02-08 05:56:52 +0300632 help="additional header files to include in the BPF program "
Yonghong Songf4470dc2017-12-13 14:12:13 -0800633 "as either full path, "
634 "or relative to relative to current working directory, "
635 "or relative to default kernel header search path")
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800636 self.args = parser.parse_args()
Brendan Gregg4f88a942016-07-22 17:11:51 -0700637 self.usdt_ctx = None
Sasha Goldshtein85384852016-02-12 01:29:39 -0800638
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700639 def _create_probes(self):
640 self.probes = []
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800641 for specifier in (self.args.countspecifier or []):
Brendan Gregg4f88a942016-07-22 17:11:51 -0700642 self.probes.append(Probe(self, "freq", specifier))
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800643 for histspecifier in (self.args.histspecifier or []):
Brendan Gregg4f88a942016-07-22 17:11:51 -0700644 self.probes.append(Probe(self, "hist", histspecifier))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700645 if len(self.probes) == 0:
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800646 print("at least one specifier is required")
Sasha Goldshteinf7ab4432017-02-13 18:46:49 -0500647 exit(1)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800648
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800649 def _generate_program(self):
650 bpf_source = """
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800651struct __string_t { char s[%d]; };
652
653#include <uapi/linux/ptrace.h>
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800654 """ % self.args.string_size
655 for include in (self.args.include or []):
ShelbyFrancesf5dbbdb2017-02-08 05:56:52 +0300656 if include.startswith((".", "/")):
657 include = os.path.abspath(include)
658 bpf_source += "#include \"%s\"\n" % include
659 else:
660 bpf_source += "#include <%s>\n" % include
661
Sasha Goldshteinb950d6f2016-03-21 04:06:15 -0700662 bpf_source += BPF.generate_auto_includes(
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700663 map(lambda p: p.raw_spec, self.probes))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700664 for probe in self.probes:
665 bpf_source += probe.generate_text()
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800666 if self.args.verbose:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300667 for text in [probe.usdt_ctx.get_text()
668 for probe in self.probes
669 if probe.usdt_ctx]:
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300670 print(text)
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800671 print(bpf_source)
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300672 usdt_contexts = [probe.usdt_ctx
673 for probe in self.probes if probe.usdt_ctx]
674 self.bpf = BPF(text=bpf_source, usdt_contexts=usdt_contexts)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800675
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800676 def _attach(self):
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700677 for probe in self.probes:
678 probe.attach(self.bpf)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800679 if self.args.verbose:
yonghong-song6070dcb2018-06-22 14:23:29 -0700680 print("open uprobes: %s" % list(self.bpf.uprobe_fds.keys()))
681 print("open kprobes: %s" % list(self.bpf.kprobe_fds.keys()))
Sasha Goldshtein85384852016-02-12 01:29:39 -0800682
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800683 def _main_loop(self):
684 count_so_far = 0
Akilesh Kailash89967192018-05-18 13:36:54 -0700685 seconds = 0
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800686 while True:
687 try:
688 sleep(self.args.interval)
Akilesh Kailash89967192018-05-18 13:36:54 -0700689 seconds += self.args.interval
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800690 except KeyboardInterrupt:
691 exit()
692 print("[%s]" % strftime("%H:%M:%S"))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700693 for probe in self.probes:
694 probe.display(self.args.top)
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800695 count_so_far += 1
696 if self.args.count is not None and \
697 count_so_far >= self.args.count:
698 exit()
Akilesh Kailash89967192018-05-18 13:36:54 -0700699 if self.args.duration and \
700 seconds >= self.args.duration:
701 exit()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800702
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800703 def run(self):
704 try:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700705 self._create_probes()
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800706 self._generate_program()
707 self._attach()
708 self._main_loop()
709 except:
Sasha Goldshteinf7ab4432017-02-13 18:46:49 -0500710 exc_info = sys.exc_info()
711 sys_exit = exc_info[0] is SystemExit
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800712 if self.args.verbose:
713 traceback.print_exc()
Sasha Goldshteinf7ab4432017-02-13 18:46:49 -0500714 elif not sys_exit:
715 print(exc_info[1])
716 exit(0 if sys_exit else 1)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800717
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800718if __name__ == "__main__":
719 Tool().run()