blob: 83a66f369c6722646bd79aed5ad929787e11df06 [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]
zhenwei pi66773212021-09-06 18:28:16 +08008# [-t TID]
Sasha Goldshtein85384852016-02-12 01:29:39 -08009#
10# Licensed under the Apache License, Version 2.0 (the "License")
11# Copyright (C) 2016 Sasha Goldshtein.
12
Sumanth Korikkar306080b2020-04-27 04:37:23 -050013from bcc import BPF, USDT, StrcmpRewrite
Sasha Goldshtein85384852016-02-12 01:29:39 -080014from time import sleep, strftime
15import argparse
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080016import re
Sasha Goldshteinc9551302016-02-21 02:21:46 -080017import traceback
Sasha Goldshteinfd60d552016-03-01 12:15:34 -080018import os
Sasha Goldshteinc9551302016-02-21 02:21:46 -080019import sys
Sasha Goldshtein85384852016-02-12 01:29:39 -080020
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070021class Probe(object):
Sasha Goldshtein85384852016-02-12 01:29:39 -080022 next_probe_index = 0
Sasha Goldshteinc8f752f2016-10-17 02:18:43 -070023 streq_index = 0
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010024 aliases = {"$PID": "(bpf_get_current_pid_tgid() >> 32)"}
Sasha Goldshtein5e4e1f42016-02-12 06:52:19 -080025
26 def _substitute_aliases(self, expr):
27 if expr is None:
28 return expr
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070029 for alias, subst in Probe.aliases.items():
Sasha Goldshtein5e4e1f42016-02-12 06:52:19 -080030 expr = expr.replace(alias, subst)
31 return expr
Sasha Goldshtein85384852016-02-12 01:29:39 -080032
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080033 def _parse_signature(self):
34 params = map(str.strip, self.signature.split(','))
35 self.param_types = {}
36 for param in params:
37 # If the type is a pointer, the * can be next to the
38 # param name. Other complex types like arrays are not
39 # supported right now.
40 index = param.rfind('*')
41 index = index if index != -1 else param.rfind(' ')
Sasha Goldshteinf41ae862016-10-19 01:14:30 +030042 param_type = param[0:index + 1].strip()
43 param_name = param[index + 1:].strip()
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080044 self.param_types[param_name] = param_type
Sumanth Korikkar306080b2020-04-27 04:37:23 -050045 # Maintain list of user params. Then later decide to
Sumanth Korikkar7f6066d2020-05-20 10:49:56 -050046 # switch to bpf_probe_read_kernel or bpf_probe_read_user.
Sumanth Korikkar306080b2020-04-27 04:37:23 -050047 if "__user" in param_type.split():
48 self.probe_user_list.add(param_name)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080049
Sasha Goldshtein3e39a082016-03-24 08:39:47 -070050 def _generate_entry(self):
51 self.entry_probe_func = self.probe_func_name + "_entry"
52 text = """
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080053int PROBENAME(struct pt_regs *ctx SIGNATURE)
54{
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010055 u64 __pid_tgid = bpf_get_current_pid_tgid();
56 u32 __pid = __pid_tgid; // lower 32 bits
57 u32 __tgid = __pid_tgid >> 32; // upper 32 bits
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080058 PID_FILTER
zhenwei pi66773212021-09-06 18:28:16 +080059 TID_FILTER
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080060 COLLECT
61 return 0;
62}
63"""
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080064 text = text.replace("PROBENAME", self.entry_probe_func)
65 text = text.replace("SIGNATURE",
66 "" if len(self.signature) == 0 else ", " + self.signature)
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010067 text = text.replace("PID_FILTER", self._generate_pid_filter())
zhenwei pi66773212021-09-06 18:28:16 +080068 text = text.replace("TID_FILTER", self._generate_tid_filter())
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080069 collect = ""
70 for pname in self.args_to_probe:
Sasha Goldshteine3501152016-02-13 03:56:29 -080071 param_hash = self.hashname_prefix + pname
72 if pname == "__latency":
73 collect += """
74u64 __time = bpf_ktime_get_ns();
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010075%s.update(&__pid, &__time);
Sasha Goldshteinf41ae862016-10-19 01:14:30 +030076 """ % param_hash
Sasha Goldshteine3501152016-02-13 03:56:29 -080077 else:
Rafael Fonsecaaf236e72017-02-15 17:28:26 +010078 collect += "%s.update(&__pid, &%s);\n" % \
Sasha Goldshteine3501152016-02-13 03:56:29 -080079 (param_hash, pname)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080080 text = text.replace("COLLECT", collect)
81 return text
82
83 def _generate_entry_probe(self):
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080084 # Any $entry(name) expressions result in saving that argument
85 # when entering the function.
86 self.args_to_probe = set()
87 regex = r"\$entry\((\w+)\)"
Sasha Goldshteincc27edf2016-02-14 03:49:01 -080088 for expr in self.exprs:
89 for arg in re.finditer(regex, expr):
90 self.args_to_probe.add(arg.group(1))
Sasha Goldshteine3501152016-02-13 03:56:29 -080091 for arg in re.finditer(regex, self.filter):
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080092 self.args_to_probe.add(arg.group(1))
Sasha Goldshteincc27edf2016-02-14 03:49:01 -080093 if any(map(lambda expr: "$latency" in expr, self.exprs)) or \
94 "$latency" in self.filter:
Sasha Goldshteine3501152016-02-13 03:56:29 -080095 self.args_to_probe.add("__latency")
96 self.param_types["__latency"] = "u64" # nanoseconds
Sasha Goldshtein392d5c82016-02-12 11:14:20 -080097 for pname in self.args_to_probe:
98 if pname not in self.param_types:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +030099 raise ValueError("$entry(%s): no such param" %
100 arg)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800101
102 self.hashname_prefix = "%s_param_" % self.probe_hash_name
103 text = ""
104 for pname in self.args_to_probe:
105 # Each argument is stored in a separate hash that is
106 # keyed by pid.
107 text += "BPF_HASH(%s, u32, %s);\n" % \
108 (self.hashname_prefix + pname,
109 self.param_types[pname])
110 text += self._generate_entry()
111 return text
112
113 def _generate_retprobe_prefix(self):
114 # After we're done here, there are __%s_val variables for each
115 # argument we needed to probe using $entry(name), and they all
116 # have values (which isn't necessarily the case if we missed
117 # the method entry probe).
Rafael Fonsecaaf236e72017-02-15 17:28:26 +0100118 text = ""
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800119 self.param_val_names = {}
120 for pname in self.args_to_probe:
121 val_name = "__%s_val" % pname
122 text += "%s *%s = %s.lookup(&__pid);\n" % \
123 (self.param_types[pname], val_name,
124 self.hashname_prefix + pname)
125 text += "if (%s == 0) { return 0 ; }\n" % val_name
126 self.param_val_names[pname] = val_name
127 return text
128
129 def _replace_entry_exprs(self):
130 for pname, vname in self.param_val_names.items():
Sasha Goldshteine3501152016-02-13 03:56:29 -0800131 if pname == "__latency":
132 entry_expr = "$latency"
133 val_expr = "(bpf_ktime_get_ns() - *%s)" % vname
134 else:
135 entry_expr = "$entry(%s)" % pname
136 val_expr = "(*%s)" % vname
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800137 for i in range(0, len(self.exprs)):
138 self.exprs[i] = self.exprs[i].replace(
139 entry_expr, val_expr)
Sasha Goldshteine3501152016-02-13 03:56:29 -0800140 self.filter = self.filter.replace(entry_expr,
141 val_expr)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800142
143 def _attach_entry_probe(self):
144 if self.is_user:
145 self.bpf.attach_uprobe(name=self.library,
146 sym=self.function,
147 fn_name=self.entry_probe_func,
148 pid=self.pid or -1)
149 else:
150 self.bpf.attach_kprobe(event=self.function,
151 fn_name=self.entry_probe_func)
152
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800153 def _bail(self, error):
154 raise ValueError("error parsing probe '%s': %s" %
155 (self.raw_spec, error))
156
157 def _validate_specifier(self):
158 # Everything after '#' is the probe label, ignore it
159 spec = self.raw_spec.split('#')[0]
160 parts = spec.strip().split(':')
161 if len(parts) < 3:
162 self._bail("at least the probe type, library, and " +
163 "function signature must be specified")
164 if len(parts) > 6:
165 self._bail("extraneous ':'-separated parts detected")
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700166 if parts[0] not in ["r", "p", "t", "u"]:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300167 self._bail("probe type must be 'p', 'r', 't', or 'u'" +
168 " but got '%s'" % parts[0])
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000169 if re.match(r"\S+\(.*\)", parts[2]) is None:
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800170 self._bail(("function signature '%s' has an invalid " +
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800171 "format") % parts[2])
172
173 def _parse_expr_types(self, expr_types):
174 if len(expr_types) == 0:
175 self._bail("no expr types specified")
176 self.expr_types = expr_types.split(',')
177
178 def _parse_exprs(self, exprs):
179 if len(exprs) == 0:
180 self._bail("no exprs specified")
181 self.exprs = exprs.split(',')
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800182
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000183 def _make_valid_identifier(self, ident):
184 return re.sub(r'[^A-Za-z0-9_]', '_', ident)
185
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300186 def __init__(self, tool, type, specifier):
187 self.usdt_ctx = None
Sasha Goldshteinc8f752f2016-10-17 02:18:43 -0700188 self.streq_functions = ""
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300189 self.pid = tool.args.pid
zhenwei pi66773212021-09-06 18:28:16 +0800190 self.tid = tool.args.tid
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300191 self.cumulative = tool.args.cumulative or False
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800192 self.raw_spec = specifier
Sumanth Korikkar306080b2020-04-27 04:37:23 -0500193 self.probe_user_list = set()
194 self.bin_cmp = False
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800195 self._validate_specifier()
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800196
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800197 spec_and_label = specifier.split('#')
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800198 self.label = spec_and_label[1] \
199 if len(spec_and_label) == 2 else None
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800200
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800201 parts = spec_and_label[0].strip().split(':')
Sasha Goldshtein85384852016-02-12 01:29:39 -0800202 self.type = type # hist or freq
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800203 self.probe_type = parts[0]
Sasha Goldshtein85384852016-02-12 01:29:39 -0800204 fparts = parts[2].split('(')
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800205 self.function = fparts[0].strip()
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800206 if self.probe_type == "t":
207 self.library = "" # kernel
208 self.tp_category = parts[1]
209 self.tp_event = self.function
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700210 elif self.probe_type == "u":
211 self.library = parts[1]
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000212 self.probe_func_name = self._make_valid_identifier(
Paul Chaignon956ca1c2017-03-04 20:07:56 +0100213 "%s_probe%d" %
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000214 (self.function, Probe.next_probe_index))
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300215 self._enable_usdt_probe()
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800216 else:
217 self.library = parts[1]
218 self.is_user = len(self.library) > 0
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800219 self.signature = fparts[1].strip()[:-1]
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800220 self._parse_signature()
221
222 # If the user didn't specify an expression to probe, we probe
223 # the retval in a ret probe, or simply the value "1" otherwise.
Sasha Goldshtein85384852016-02-12 01:29:39 -0800224 self.is_default_expr = len(parts) < 5
225 if not self.is_default_expr:
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800226 self._parse_expr_types(parts[3])
227 self._parse_exprs(parts[4])
228 if len(self.exprs) != len(self.expr_types):
229 self._bail("mismatched # of exprs and types")
230 if self.type == "hist" and len(self.expr_types) > 1:
231 self._bail("histograms can only have 1 expr")
Sasha Goldshtein85384852016-02-12 01:29:39 -0800232 else:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800233 if not self.probe_type == "r" and self.type == "hist":
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800234 self._bail("histograms must have expr")
235 self.expr_types = \
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800236 ["u64" if not self.probe_type == "r" else "int"]
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800237 self.exprs = \
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800238 ["1" if not self.probe_type == "r" else "$retval"]
Sasha Goldshteine3501152016-02-13 03:56:29 -0800239 self.filter = "" if len(parts) != 6 else parts[5]
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800240 self._substitute_exprs()
241
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800242 # Do we need to attach an entry probe so that we can collect an
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800243 # argument that is required for an exit (return) probe?
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800244 def check(expr):
245 keywords = ["$entry", "$latency"]
246 return any(map(lambda kw: kw in expr, keywords))
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800247 self.entry_probe_required = self.probe_type == "r" and \
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800248 (any(map(check, self.exprs)) or check(self.filter))
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800249
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000250 self.probe_func_name = self._make_valid_identifier(
Paul Chaignon956ca1c2017-03-04 20:07:56 +0100251 "%s_probe%d" %
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000252 (self.function, Probe.next_probe_index))
253 self.probe_hash_name = self._make_valid_identifier(
Paul Chaignon956ca1c2017-03-04 20:07:56 +0100254 "%s_hash%d" %
Sasha Goldshtein3fa7ba12017-01-14 11:17:40 +0000255 (self.function, Probe.next_probe_index))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700256 Probe.next_probe_index += 1
257
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300258 def _enable_usdt_probe(self):
259 self.usdt_ctx = USDT(path=self.library, pid=self.pid)
260 self.usdt_ctx.enable_probe(
261 self.function, self.probe_func_name)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800262
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800263 def _substitute_exprs(self):
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800264 def repl(expr):
265 expr = self._substitute_aliases(expr)
Sumanth Korikkar306080b2020-04-27 04:37:23 -0500266 rdict = StrcmpRewrite.rewrite_expr(expr,
267 self.bin_cmp, self.library,
268 self.probe_user_list, self.streq_functions,
269 Probe.streq_index)
270 expr = rdict["expr"]
271 self.streq_functions = rdict["streq_functions"]
272 Probe.streq_index = rdict["probeid"]
Naveen N. Rao4afa96a2016-05-03 14:54:21 +0530273 return expr.replace("$retval", "PT_REGS_RC(ctx)")
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800274 for i in range(0, len(self.exprs)):
275 self.exprs[i] = repl(self.exprs[i])
276 self.filter = repl(self.filter)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800277
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800278 def _is_string(self, expr_type):
279 return expr_type == "char*" or expr_type == "char *"
Sasha Goldshtein85384852016-02-12 01:29:39 -0800280
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800281 def _generate_hash_field(self, i):
282 if self._is_string(self.expr_types[i]):
283 return "struct __string_t v%d;\n" % i
284 else:
285 return "%s v%d;\n" % (self.expr_types[i], i)
286
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300287 def _generate_usdt_arg_assignment(self, i):
288 expr = self.exprs[i]
289 if self.probe_type == "u" and expr[0:3] == "arg":
Sasha Goldshtein3a5256f2017-02-20 15:42:57 +0000290 arg_index = int(expr[3])
291 arg_ctype = self.usdt_ctx.get_probe_arg_ctype(
292 self.function, arg_index - 1)
293 return (" %s %s = 0;\n" +
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300294 " bpf_usdt_readarg(%s, ctx, &%s);\n") \
Sasha Goldshtein3a5256f2017-02-20 15:42:57 +0000295 % (arg_ctype, expr, expr[3], expr)
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300296 else:
297 return ""
298
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800299 def _generate_field_assignment(self, i):
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300300 text = self._generate_usdt_arg_assignment(i)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800301 if self._is_string(self.expr_types[i]):
Sumanth Korikkar306080b2020-04-27 04:37:23 -0500302 if self.is_user or \
303 self.exprs[i] in self.probe_user_list:
304 probe_readfunc = "bpf_probe_read_user"
305 else:
Sumanth Korikkar7f6066d2020-05-20 10:49:56 -0500306 probe_readfunc = "bpf_probe_read_kernel"
Sumanth Korikkar306080b2020-04-27 04:37:23 -0500307 return (text + " %s(&__key.v%d.s," +
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700308 " sizeof(__key.v%d.s), (void *)%s);\n") % \
Sumanth Korikkar306080b2020-04-27 04:37:23 -0500309 (probe_readfunc, i, i, self.exprs[i])
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800310 else:
Brendan Gregg4f88a942016-07-22 17:11:51 -0700311 return text + " __key.v%d = %s;\n" % \
312 (i, self.exprs[i])
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800313
314 def _generate_hash_decl(self):
315 if self.type == "hist":
316 return "BPF_HISTOGRAM(%s, %s);" % \
317 (self.probe_hash_name, self.expr_types[0])
318 else:
319 text = "struct %s_key_t {\n" % self.probe_hash_name
320 for i in range(0, len(self.expr_types)):
321 text += self._generate_hash_field(i)
322 text += "};\n"
323 text += "BPF_HASH(%s, struct %s_key_t, u64);\n" % \
324 (self.probe_hash_name, self.probe_hash_name)
325 return text
326
327 def _generate_key_assignment(self):
328 if self.type == "hist":
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300329 return self._generate_usdt_arg_assignment(0) + \
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300330 ("%s __key = %s;\n" %
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300331 (self.expr_types[0], self.exprs[0]))
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800332 else:
333 text = "struct %s_key_t __key = {};\n" % \
334 self.probe_hash_name
335 for i in range(0, len(self.exprs)):
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800336 text += self._generate_field_assignment(i)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800337 return text
338
339 def _generate_hash_update(self):
340 if self.type == "hist":
zcy80242fb2021-07-02 00:12:32 +0800341 return "%s.atomic_increment(bpf_log2l(__key));" % \
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800342 self.probe_hash_name
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800343 else:
zcy80242fb2021-07-02 00:12:32 +0800344 return "%s.atomic_increment(__key);" % \
345 self.probe_hash_name
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800346
347 def _generate_pid_filter(self):
348 # Kernel probes need to explicitly filter pid, because the
349 # attach interface doesn't support pid filtering
350 if self.pid is not None and not self.is_user:
Rafael Fonsecaaf236e72017-02-15 17:28:26 +0100351 return "if (__tgid != %d) { return 0; }" % self.pid
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800352 else:
353 return ""
354
zhenwei pi66773212021-09-06 18:28:16 +0800355 def _generate_tid_filter(self):
356 if self.tid is not None and not self.is_user:
357 return "if (__pid != %d) { return 0; }" % self.tid
358 else:
359 return ""
360
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800361 def generate_text(self):
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800362 program = ""
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700363 probe_text = """
364DATA_DECL
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300365 """ + (
366 "TRACEPOINT_PROBE(%s, %s)" %
367 (self.tp_category, self.tp_event)
368 if self.probe_type == "t"
369 else "int PROBENAME(struct pt_regs *ctx SIGNATURE)") + """
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700370{
Rafael Fonsecaaf236e72017-02-15 17:28:26 +0100371 u64 __pid_tgid = bpf_get_current_pid_tgid();
372 u32 __pid = __pid_tgid; // lower 32 bits
373 u32 __tgid = __pid_tgid >> 32; // upper 32 bits
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700374 PID_FILTER
zhenwei pi66773212021-09-06 18:28:16 +0800375 TID_FILTER
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700376 PREFIX
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700377 KEY_EXPR
Akilesh Kailashb8269aa2020-05-11 11:54:26 -0700378 if (!(FILTER)) return 0;
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700379 COLLECT
380 return 0;
381}
382"""
383 prefix = ""
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700384 signature = ""
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800385
386 # If any entry arguments are probed in a ret probe, we need
387 # to generate an entry probe to collect them
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800388 if self.entry_probe_required:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800389 program += self._generate_entry_probe()
390 prefix += self._generate_retprobe_prefix()
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800391 # Replace $entry(paramname) with a reference to the
392 # value we collected when entering the function:
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800393 self._replace_entry_exprs()
394
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300395 if self.probe_type == "p" and len(self.signature) > 0:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700396 # Only entry uprobes/kprobes can have user-specified
397 # signatures. Other probes force it to ().
398 signature = ", " + self.signature
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800399
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300400 program += probe_text.replace("PROBENAME",
401 self.probe_func_name)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800402 program = program.replace("SIGNATURE", signature)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800403 program = program.replace("PID_FILTER",
404 self._generate_pid_filter())
zhenwei pi66773212021-09-06 18:28:16 +0800405 program = program.replace("TID_FILTER",
406 self._generate_tid_filter())
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800407
408 decl = self._generate_hash_decl()
409 key_expr = self._generate_key_assignment()
410 collect = self._generate_hash_update()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800411 program = program.replace("DATA_DECL", decl)
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800412 program = program.replace("KEY_EXPR", key_expr)
Sasha Goldshteine3501152016-02-13 03:56:29 -0800413 program = program.replace("FILTER",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800414 "1" if len(self.filter) == 0 else self.filter)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800415 program = program.replace("COLLECT", collect)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800416 program = program.replace("PREFIX", prefix)
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700417
Sasha Goldshteinc8f752f2016-10-17 02:18:43 -0700418 return self.streq_functions + program
Sasha Goldshtein85384852016-02-12 01:29:39 -0800419
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700420 def _attach_u(self):
421 libpath = BPF.find_library(self.library)
422 if libpath is None:
Sasha Goldshteinec679712016-10-04 18:33:36 +0300423 libpath = BPF.find_exe(self.library)
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700424 if libpath is None or len(libpath) == 0:
Sasha Goldshtein5a1d2e32016-03-30 08:14:44 -0700425 self._bail("unable to find library %s" % self.library)
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700426
Brendan Gregg4f88a942016-07-22 17:11:51 -0700427 if self.probe_type == "r":
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700428 self.bpf.attach_uretprobe(name=libpath,
429 sym=self.function,
430 fn_name=self.probe_func_name,
431 pid=self.pid or -1)
432 else:
433 self.bpf.attach_uprobe(name=libpath,
434 sym=self.function,
435 fn_name=self.probe_func_name,
436 pid=self.pid or -1)
437
438 def _attach_k(self):
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300439 if self.probe_type == "t":
440 pass # Nothing to do for tracepoints
441 elif self.probe_type == "r":
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700442 self.bpf.attach_kretprobe(event=self.function,
443 fn_name=self.probe_func_name)
444 else:
445 self.bpf.attach_kprobe(event=self.function,
446 fn_name=self.probe_func_name)
447
Sasha Goldshtein85384852016-02-12 01:29:39 -0800448 def attach(self, bpf):
449 self.bpf = bpf
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300450 if self.probe_type == "u":
451 return
Sasha Goldshtein85384852016-02-12 01:29:39 -0800452 if self.is_user:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700453 self._attach_u()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800454 else:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700455 self._attach_k()
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800456 if self.entry_probe_required:
457 self._attach_entry_probe()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800458
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800459 def _v2s(self, v):
460 # Most fields can be converted with plain str(), but strings
461 # are wrapped in a __string_t which has an .s field
462 if "__string_t" in type(v).__name__:
463 return str(v.s)
464 return str(v)
465
466 def _display_expr(self, i):
467 # Replace ugly latency calculation with $latency
468 expr = self.exprs[i].replace(
469 "(bpf_ktime_get_ns() - *____latency_val)", "$latency")
470 # Replace alias values back with the alias name
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700471 for alias, subst in Probe.aliases.items():
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800472 expr = expr.replace(subst, alias)
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800473 # Replace retval expression with $retval
Naveen N. Rao4afa96a2016-05-03 14:54:21 +0530474 expr = expr.replace("PT_REGS_RC(ctx)", "$retval")
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800475 # Replace ugly (*__param_val) expressions with param name
476 return re.sub(r"\(\*__(\w+)_val\)", r"\1", expr)
477
478 def _display_key(self, key):
479 if self.is_default_expr:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800480 if not self.probe_type == "r":
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800481 return "total calls"
482 else:
483 return "retval = %s" % str(key.v0)
484 else:
485 # The key object has v0, ..., vk fields containing
486 # the values of the expressions from self.exprs
487 def str_i(i):
488 key_i = self._v2s(getattr(key, "v%d" % i))
489 return "%s = %s" % \
490 (self._display_expr(i), key_i)
491 return ", ".join(map(str_i, range(0, len(self.exprs))))
492
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800493 def display(self, top):
Sasha Goldshtein85384852016-02-12 01:29:39 -0800494 data = self.bpf.get_table(self.probe_hash_name)
495 if self.type == "freq":
Sasha Goldshteine3501152016-02-13 03:56:29 -0800496 print(self.label or self.raw_spec)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800497 print("\t%-10s %s" % ("COUNT", "EVENT"))
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300498 sdata = sorted(data.items(), key=lambda p: p[1].value)
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800499 if top is not None:
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300500 sdata = sdata[-top:]
501 for key, value in sdata:
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800502 # Print some nice values if the user didn't
503 # specify an expression to probe
Sasha Goldshtein85384852016-02-12 01:29:39 -0800504 if self.is_default_expr:
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800505 if not self.probe_type == "r":
Sasha Goldshtein85384852016-02-12 01:29:39 -0800506 key_str = "total calls"
507 else:
508 key_str = "retval = %s" % \
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800509 self._v2s(key.v0)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800510 else:
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800511 key_str = self._display_key(key)
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300512 print("\t%-10s %s" %
Sasha Goldshtein85384852016-02-12 01:29:39 -0800513 (str(value.value), key_str))
514 elif self.type == "hist":
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800515 label = self.label or (self._display_expr(0)
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300516 if not self.is_default_expr else "retval")
Sasha Goldshtein85384852016-02-12 01:29:39 -0800517 data.print_log2_hist(val_type=label)
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300518 if not self.cumulative:
519 data.clear()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800520
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700521 def __str__(self):
522 return self.label or self.raw_spec
523
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800524class Tool(object):
525 examples = """
Sasha Goldshtein85384852016-02-12 01:29:39 -0800526Probe specifier syntax:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700527 {p,r,t,u}:{[library],category}:function(signature)[:type[,type...]:expr[,expr...][:filter]][#label]
Sasha Goldshtein85384852016-02-12 01:29:39 -0800528Where:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300529 p,r,t,u -- probe at function entry, function exit, kernel
530 tracepoint, or USDT probe
Sasha Goldshteine3501152016-02-13 03:56:29 -0800531 in exit probes: can use $retval, $entry(param), $latency
Sasha Goldshtein85384852016-02-12 01:29:39 -0800532 library -- the library that contains the function
533 (leave empty for kernel functions)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800534 category -- the category of the kernel tracepoint (e.g. net, sched)
535 function -- the function name to trace (or tracepoint name)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800536 signature -- the function's parameters, as in the C header
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800537 type -- the type of the expression to collect (supports multiple)
538 expr -- the expression to collect (supports multiple)
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800539 filter -- the filter that is applied to collected values
540 label -- the label for this probe in the resulting output
Sasha Goldshtein85384852016-02-12 01:29:39 -0800541
542EXAMPLES:
543
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800544argdist -H 'p::__kmalloc(u64 size):u64:size'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800545 Print a histogram of allocation sizes passed to kmalloc
546
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800547argdist -p 1005 -C 'p:c:malloc(size_t size):size_t:size:size==16'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800548 Print a frequency count of how many times process 1005 called malloc
549 with an allocation size of 16 bytes
550
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800551argdist -C 'r:c:gets():char*:(char*)$retval#snooped strings'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800552 Snoop on all strings returned by gets()
553
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800554argdist -H 'r::__kmalloc(size_t size):u64:$latency/$entry(size)#ns per byte'
Sasha Goldshteine3501152016-02-13 03:56:29 -0800555 Print a histogram of nanoseconds per byte from kmalloc allocations
556
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300557argdist -C 'p::__kmalloc(size_t sz, gfp_t flags):size_t:sz:flags&GFP_ATOMIC'
Sasha Goldshtein7983d6b2016-02-13 23:14:18 -0800558 Print frequency count of kmalloc allocation sizes that have GFP_ATOMIC
559
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800560argdist -p 1005 -C 'p:c:write(int fd):int:fd' -T 5
Sasha Goldshtein85384852016-02-12 01:29:39 -0800561 Print frequency counts of how many times writes were issued to a
Sasha Goldshtein392d5c82016-02-12 11:14:20 -0800562 particular file descriptor number, in process 1005, but only show
563 the top 5 busiest fds
Sasha Goldshtein85384852016-02-12 01:29:39 -0800564
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800565argdist -p 1005 -H 'r:c:read()'
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800566 Print a histogram of results (sizes) returned by read() in process 1005
Sasha Goldshtein85384852016-02-12 01:29:39 -0800567
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800568argdist -C 'r::__vfs_read():u32:$PID:$latency > 100000'
Sasha Goldshteine3501152016-02-13 03:56:29 -0800569 Print frequency of reads by process where the latency was >0.1ms
570
muahao852e19b2018-08-22 01:17:36 +0800571argdist -H 'r::__vfs_read(void *file, void *buf, size_t count):size_t:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300572 $entry(count):$latency > 1000000'
Sasha Goldshteine3501152016-02-13 03:56:29 -0800573 Print a histogram of read sizes that were longer than 1ms
574
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800575argdist -H \\
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800576 'p:c:write(int fd, const void *buf, size_t count):size_t:count:fd==1'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800577 Print a histogram of buffer sizes passed to write() across all
578 processes, where the file descriptor was 1 (STDOUT)
579
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800580argdist -C 'p:c:fork()#fork calls'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800581 Count fork() calls in libc across all processes
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800582 Can also use funccount.py, which is easier and more flexible
Sasha Goldshtein85384852016-02-12 01:29:39 -0800583
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300584argdist -H 't:block:block_rq_complete():u32:args->nr_sector'
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800585 Print histogram of number of sectors in completing block I/O requests
586
Sasha Goldshtein376ae5c2016-10-04 19:49:57 +0300587argdist -C 't:irq:irq_handler_entry():int:args->irq'
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800588 Aggregate interrupts by interrupt request (IRQ)
589
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700590argdist -C 'u:pthread:pthread_start():u64:arg2' -p 1337
591 Print frequency of function addresses used as a pthread start function,
592 relying on the USDT pthread_start probe in process 1337
593
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300594argdist -H 'p:c:sleep(u32 seconds):u32:seconds' \\
595 -H 'p:c:nanosleep(struct timespec *req):long:req->tv_nsec'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800596 Print histograms of sleep() and nanosleep() parameter values
597
Sasha Goldshtein7df65da2016-02-14 05:12:27 -0800598argdist -p 2780 -z 120 \\
Sasha Goldshteined21adf2016-02-12 03:04:53 -0800599 -C 'p:c:write(int fd, char* buf, size_t len):char*:buf:fd==1'
Sasha Goldshtein85384852016-02-12 01:29:39 -0800600 Spy on writes to STDOUT performed by process 2780, up to a string size
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800601 of 120 characters
Yonghong Songf4470dc2017-12-13 14:12:13 -0800602
603argdist -I 'kernel/sched/sched.h' \\
604 -C 'p::__account_cfs_rq_runtime(struct cfs_rq *cfs_rq):s64:cfs_rq->runtime_remaining'
605 Trace on the cfs scheduling runqueue remaining runtime. The struct cfs_rq is defined
606 in kernel/sched/sched.h which is in kernel source tree and not in kernel-devel
607 package. So this command needs to run at the kernel source tree root directory
608 so that the added header file can be found by the compiler.
Sasha Goldshtein85384852016-02-12 01:29:39 -0800609"""
610
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800611 def __init__(self):
612 parser = argparse.ArgumentParser(description="Trace a " +
613 "function and display a summary of its parameter values.",
614 formatter_class=argparse.RawDescriptionHelpFormatter,
615 epilog=Tool.examples)
616 parser.add_argument("-p", "--pid", type=int,
617 help="id of the process to trace (optional)")
zhenwei pi66773212021-09-06 18:28:16 +0800618 parser.add_argument("-t", "--tid", type=int,
619 help="id of the thread to trace (optional)")
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800620 parser.add_argument("-z", "--string-size", default=80,
621 type=int,
622 help="maximum string size to read from char* arguments")
623 parser.add_argument("-i", "--interval", default=1, type=int,
Akilesh Kailash89967192018-05-18 13:36:54 -0700624 help="output interval, in seconds (default 1 second)")
625 parser.add_argument("-d", "--duration", type=int,
626 help="total duration of trace, in seconds")
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800627 parser.add_argument("-n", "--number", type=int, dest="count",
628 help="number of outputs")
629 parser.add_argument("-v", "--verbose", action="store_true",
630 help="print resulting BPF program code before executing")
Sasha Goldshteind2f47622016-10-04 18:40:15 +0300631 parser.add_argument("-c", "--cumulative", action="store_true",
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300632 help="do not clear histograms and freq counts at " +
633 "each interval")
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800634 parser.add_argument("-T", "--top", type=int,
635 help="number of top results to show (not applicable to " +
636 "histograms)")
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300637 parser.add_argument("-H", "--histogram", action="append",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800638 dest="histspecifier", metavar="specifier",
639 help="probe specifier to capture histogram of " +
640 "(see examples below)")
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300641 parser.add_argument("-C", "--count", action="append",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800642 dest="countspecifier", metavar="specifier",
643 help="probe specifier to capture count of " +
644 "(see examples below)")
Sasha Goldshtein4725a722016-10-18 20:54:47 +0300645 parser.add_argument("-I", "--include", action="append",
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800646 metavar="header",
ShelbyFrancesf5dbbdb2017-02-08 05:56:52 +0300647 help="additional header files to include in the BPF program "
Yonghong Songf4470dc2017-12-13 14:12:13 -0800648 "as either full path, "
649 "or relative to relative to current working directory, "
650 "or relative to default kernel header search path")
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800651 self.args = parser.parse_args()
Brendan Gregg4f88a942016-07-22 17:11:51 -0700652 self.usdt_ctx = None
Sasha Goldshtein85384852016-02-12 01:29:39 -0800653
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700654 def _create_probes(self):
655 self.probes = []
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800656 for specifier in (self.args.countspecifier or []):
Brendan Gregg4f88a942016-07-22 17:11:51 -0700657 self.probes.append(Probe(self, "freq", specifier))
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800658 for histspecifier in (self.args.histspecifier or []):
Brendan Gregg4f88a942016-07-22 17:11:51 -0700659 self.probes.append(Probe(self, "hist", histspecifier))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700660 if len(self.probes) == 0:
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800661 print("at least one specifier is required")
Sasha Goldshteinf7ab4432017-02-13 18:46:49 -0500662 exit(1)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800663
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800664 def _generate_program(self):
665 bpf_source = """
Sasha Goldshteincc27edf2016-02-14 03:49:01 -0800666struct __string_t { char s[%d]; };
667
668#include <uapi/linux/ptrace.h>
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800669 """ % self.args.string_size
670 for include in (self.args.include or []):
ShelbyFrancesf5dbbdb2017-02-08 05:56:52 +0300671 if include.startswith((".", "/")):
672 include = os.path.abspath(include)
673 bpf_source += "#include \"%s\"\n" % include
674 else:
675 bpf_source += "#include <%s>\n" % include
676
Sasha Goldshteinb950d6f2016-03-21 04:06:15 -0700677 bpf_source += BPF.generate_auto_includes(
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700678 map(lambda p: p.raw_spec, self.probes))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700679 for probe in self.probes:
680 bpf_source += probe.generate_text()
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800681 if self.args.verbose:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300682 for text in [probe.usdt_ctx.get_text()
683 for probe in self.probes
684 if probe.usdt_ctx]:
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300685 print(text)
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800686 print(bpf_source)
Sasha Goldshtein69e361a2016-09-27 19:40:00 +0300687 usdt_contexts = [probe.usdt_ctx
688 for probe in self.probes if probe.usdt_ctx]
689 self.bpf = BPF(text=bpf_source, usdt_contexts=usdt_contexts)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800690
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800691 def _attach(self):
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700692 for probe in self.probes:
693 probe.attach(self.bpf)
Sasha Goldshteinfd60d552016-03-01 12:15:34 -0800694 if self.args.verbose:
yonghong-song6070dcb2018-06-22 14:23:29 -0700695 print("open uprobes: %s" % list(self.bpf.uprobe_fds.keys()))
696 print("open kprobes: %s" % list(self.bpf.kprobe_fds.keys()))
Sasha Goldshtein85384852016-02-12 01:29:39 -0800697
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800698 def _main_loop(self):
699 count_so_far = 0
Akilesh Kailash89967192018-05-18 13:36:54 -0700700 seconds = 0
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800701 while True:
702 try:
703 sleep(self.args.interval)
Akilesh Kailash89967192018-05-18 13:36:54 -0700704 seconds += self.args.interval
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800705 except KeyboardInterrupt:
706 exit()
707 print("[%s]" % strftime("%H:%M:%S"))
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700708 for probe in self.probes:
709 probe.display(self.args.top)
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800710 count_so_far += 1
711 if self.args.count is not None and \
712 count_so_far >= self.args.count:
713 exit()
Akilesh Kailash89967192018-05-18 13:36:54 -0700714 if self.args.duration and \
715 seconds >= self.args.duration:
716 exit()
Sasha Goldshtein85384852016-02-12 01:29:39 -0800717
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800718 def run(self):
719 try:
Sasha Goldshtein3e39a082016-03-24 08:39:47 -0700720 self._create_probes()
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800721 self._generate_program()
722 self._attach()
723 self._main_loop()
724 except:
Sasha Goldshteinf7ab4432017-02-13 18:46:49 -0500725 exc_info = sys.exc_info()
726 sys_exit = exc_info[0] is SystemExit
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800727 if self.args.verbose:
728 traceback.print_exc()
Sasha Goldshteinf7ab4432017-02-13 18:46:49 -0500729 elif not sys_exit:
730 print(exc_info[1])
731 exit(0 if sys_exit else 1)
Sasha Goldshtein85384852016-02-12 01:29:39 -0800732
Sasha Goldshteinc9551302016-02-21 02:21:46 -0800733if __name__ == "__main__":
734 Tool().run()