xref: /aosp_15_r20/external/bcc/tools/argdist.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/env python
2*387f9dfdSAndroid Build Coastguard Worker#
3*387f9dfdSAndroid Build Coastguard Worker# argdist   Trace a function and display a distribution of its
4*387f9dfdSAndroid Build Coastguard Worker#           parameter values as a histogram or frequency count.
5*387f9dfdSAndroid Build Coastguard Worker#
6*387f9dfdSAndroid Build Coastguard Worker# USAGE: argdist [-h] [-p PID] [-z STRING_SIZE] [-i INTERVAL] [-n COUNT] [-v]
7*387f9dfdSAndroid Build Coastguard Worker#                [-c] [-T TOP] [-C specifier] [-H specifier] [-I header]
8*387f9dfdSAndroid Build Coastguard Worker#                [-t TID]
9*387f9dfdSAndroid Build Coastguard Worker#
10*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License")
11*387f9dfdSAndroid Build Coastguard Worker# Copyright (C) 2016 Sasha Goldshtein.
12*387f9dfdSAndroid Build Coastguard Worker
13*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF, USDT, StrcmpRewrite
14*387f9dfdSAndroid Build Coastguard Workerfrom time import sleep, strftime
15*387f9dfdSAndroid Build Coastguard Workerimport argparse
16*387f9dfdSAndroid Build Coastguard Workerimport re
17*387f9dfdSAndroid Build Coastguard Workerimport traceback
18*387f9dfdSAndroid Build Coastguard Workerimport os
19*387f9dfdSAndroid Build Coastguard Workerimport sys
20*387f9dfdSAndroid Build Coastguard Worker
21*387f9dfdSAndroid Build Coastguard Workerclass Probe(object):
22*387f9dfdSAndroid Build Coastguard Worker        next_probe_index = 0
23*387f9dfdSAndroid Build Coastguard Worker        streq_index = 0
24*387f9dfdSAndroid Build Coastguard Worker        aliases = {"$PID": "(bpf_get_current_pid_tgid() >> 32)", "$COMM": "&val.name"}
25*387f9dfdSAndroid Build Coastguard Worker
26*387f9dfdSAndroid Build Coastguard Worker        def _substitute_aliases(self, expr):
27*387f9dfdSAndroid Build Coastguard Worker                if expr is None:
28*387f9dfdSAndroid Build Coastguard Worker                        return expr
29*387f9dfdSAndroid Build Coastguard Worker                for alias, subst in Probe.aliases.items():
30*387f9dfdSAndroid Build Coastguard Worker                        expr = expr.replace(alias, subst)
31*387f9dfdSAndroid Build Coastguard Worker                return expr
32*387f9dfdSAndroid Build Coastguard Worker
33*387f9dfdSAndroid Build Coastguard Worker        def _parse_signature(self):
34*387f9dfdSAndroid Build Coastguard Worker                params = map(str.strip, self.signature.split(','))
35*387f9dfdSAndroid Build Coastguard Worker                self.param_types = {}
36*387f9dfdSAndroid Build Coastguard Worker                for param in params:
37*387f9dfdSAndroid Build Coastguard Worker                        # If the type is a pointer, the * can be next to the
38*387f9dfdSAndroid Build Coastguard Worker                        # param name. Other complex types like arrays are not
39*387f9dfdSAndroid Build Coastguard Worker                        # supported right now.
40*387f9dfdSAndroid Build Coastguard Worker                        index = param.rfind('*')
41*387f9dfdSAndroid Build Coastguard Worker                        index = index if index != -1 else param.rfind(' ')
42*387f9dfdSAndroid Build Coastguard Worker                        param_type = param[0:index + 1].strip()
43*387f9dfdSAndroid Build Coastguard Worker                        param_name = param[index + 1:].strip()
44*387f9dfdSAndroid Build Coastguard Worker                        self.param_types[param_name] = param_type
45*387f9dfdSAndroid Build Coastguard Worker                        # Maintain list of user params. Then later decide to
46*387f9dfdSAndroid Build Coastguard Worker                        # switch to bpf_probe_read_kernel or bpf_probe_read_user.
47*387f9dfdSAndroid Build Coastguard Worker                        if "__user" in param_type.split():
48*387f9dfdSAndroid Build Coastguard Worker                                self.probe_user_list.add(param_name)
49*387f9dfdSAndroid Build Coastguard Worker
50*387f9dfdSAndroid Build Coastguard Worker        def _generate_entry(self):
51*387f9dfdSAndroid Build Coastguard Worker                self.entry_probe_func = self.probe_func_name + "_entry"
52*387f9dfdSAndroid Build Coastguard Worker                text = """
53*387f9dfdSAndroid Build Coastguard Workerint PROBENAME(struct pt_regs *ctx SIGNATURE)
54*387f9dfdSAndroid Build Coastguard Worker{
55*387f9dfdSAndroid Build Coastguard Worker        u64 __pid_tgid = bpf_get_current_pid_tgid();
56*387f9dfdSAndroid Build Coastguard Worker        u32 __pid      = __pid_tgid;        // lower 32 bits
57*387f9dfdSAndroid Build Coastguard Worker        u32 __tgid     = __pid_tgid >> 32;  // upper 32 bits
58*387f9dfdSAndroid Build Coastguard Worker        PID_FILTER
59*387f9dfdSAndroid Build Coastguard Worker        TID_FILTER
60*387f9dfdSAndroid Build Coastguard Worker        COLLECT
61*387f9dfdSAndroid Build Coastguard Worker        return 0;
62*387f9dfdSAndroid Build Coastguard Worker}
63*387f9dfdSAndroid Build Coastguard Worker"""
64*387f9dfdSAndroid Build Coastguard Worker                text = text.replace("PROBENAME", self.entry_probe_func)
65*387f9dfdSAndroid Build Coastguard Worker                text = text.replace("SIGNATURE",
66*387f9dfdSAndroid Build Coastguard Worker                     "" if len(self.signature) == 0 else ", " + self.signature)
67*387f9dfdSAndroid Build Coastguard Worker                text = text.replace("PID_FILTER", self._generate_pid_filter())
68*387f9dfdSAndroid Build Coastguard Worker                text = text.replace("TID_FILTER", self._generate_tid_filter())
69*387f9dfdSAndroid Build Coastguard Worker                collect = ""
70*387f9dfdSAndroid Build Coastguard Worker                for pname in self.args_to_probe:
71*387f9dfdSAndroid Build Coastguard Worker                        param_hash = self.hashname_prefix + pname
72*387f9dfdSAndroid Build Coastguard Worker                        if pname == "__latency":
73*387f9dfdSAndroid Build Coastguard Worker                                collect += """
74*387f9dfdSAndroid Build Coastguard Workeru64 __time = bpf_ktime_get_ns();
75*387f9dfdSAndroid Build Coastguard Worker%s.update(&__pid, &__time);
76*387f9dfdSAndroid Build Coastguard Worker                        """ % param_hash
77*387f9dfdSAndroid Build Coastguard Worker                        else:
78*387f9dfdSAndroid Build Coastguard Worker                                collect += "%s.update(&__pid, &%s);\n" % \
79*387f9dfdSAndroid Build Coastguard Worker                                           (param_hash, pname)
80*387f9dfdSAndroid Build Coastguard Worker                text = text.replace("COLLECT", collect)
81*387f9dfdSAndroid Build Coastguard Worker                return text
82*387f9dfdSAndroid Build Coastguard Worker
83*387f9dfdSAndroid Build Coastguard Worker        def _generate_entry_probe(self):
84*387f9dfdSAndroid Build Coastguard Worker                # Any $entry(name) expressions result in saving that argument
85*387f9dfdSAndroid Build Coastguard Worker                # when entering the function.
86*387f9dfdSAndroid Build Coastguard Worker                self.args_to_probe = set()
87*387f9dfdSAndroid Build Coastguard Worker                regex = r"\$entry\((\w+)\)"
88*387f9dfdSAndroid Build Coastguard Worker                for expr in self.exprs:
89*387f9dfdSAndroid Build Coastguard Worker                        for arg in re.finditer(regex, expr):
90*387f9dfdSAndroid Build Coastguard Worker                                self.args_to_probe.add(arg.group(1))
91*387f9dfdSAndroid Build Coastguard Worker                for arg in re.finditer(regex, self.filter):
92*387f9dfdSAndroid Build Coastguard Worker                        self.args_to_probe.add(arg.group(1))
93*387f9dfdSAndroid Build Coastguard Worker                if any(map(lambda expr: "$latency" in expr, self.exprs)) or \
94*387f9dfdSAndroid Build Coastguard Worker                   "$latency" in self.filter:
95*387f9dfdSAndroid Build Coastguard Worker                        self.args_to_probe.add("__latency")
96*387f9dfdSAndroid Build Coastguard Worker                        self.param_types["__latency"] = "u64"    # nanoseconds
97*387f9dfdSAndroid Build Coastguard Worker                for pname in self.args_to_probe:
98*387f9dfdSAndroid Build Coastguard Worker                        if pname not in self.param_types:
99*387f9dfdSAndroid Build Coastguard Worker                                raise ValueError("$entry(%s): no such param" %
100*387f9dfdSAndroid Build Coastguard Worker                                                 arg)
101*387f9dfdSAndroid Build Coastguard Worker
102*387f9dfdSAndroid Build Coastguard Worker                self.hashname_prefix = "%s_param_" % self.probe_hash_name
103*387f9dfdSAndroid Build Coastguard Worker                text = ""
104*387f9dfdSAndroid Build Coastguard Worker                for pname in self.args_to_probe:
105*387f9dfdSAndroid Build Coastguard Worker                        # Each argument is stored in a separate hash that is
106*387f9dfdSAndroid Build Coastguard Worker                        # keyed by pid.
107*387f9dfdSAndroid Build Coastguard Worker                        text += "BPF_HASH(%s, u32, %s);\n" % \
108*387f9dfdSAndroid Build Coastguard Worker                             (self.hashname_prefix + pname,
109*387f9dfdSAndroid Build Coastguard Worker                              self.param_types[pname])
110*387f9dfdSAndroid Build Coastguard Worker                text += self._generate_entry()
111*387f9dfdSAndroid Build Coastguard Worker                return text
112*387f9dfdSAndroid Build Coastguard Worker
113*387f9dfdSAndroid Build Coastguard Worker        def _generate_retprobe_prefix(self):
114*387f9dfdSAndroid Build Coastguard Worker                # After we're done here, there are __%s_val variables for each
115*387f9dfdSAndroid Build Coastguard Worker                # argument we needed to probe using $entry(name), and they all
116*387f9dfdSAndroid Build Coastguard Worker                # have values (which isn't necessarily the case if we missed
117*387f9dfdSAndroid Build Coastguard Worker                # the method entry probe).
118*387f9dfdSAndroid Build Coastguard Worker                text = ""
119*387f9dfdSAndroid Build Coastguard Worker                self.param_val_names = {}
120*387f9dfdSAndroid Build Coastguard Worker                for pname in self.args_to_probe:
121*387f9dfdSAndroid Build Coastguard Worker                        val_name = "__%s_val" % pname
122*387f9dfdSAndroid Build Coastguard Worker                        text += "%s *%s = %s.lookup(&__pid);\n" % \
123*387f9dfdSAndroid Build Coastguard Worker                                (self.param_types[pname], val_name,
124*387f9dfdSAndroid Build Coastguard Worker                                 self.hashname_prefix + pname)
125*387f9dfdSAndroid Build Coastguard Worker                        text += "if (%s == 0) { return 0 ; }\n" % val_name
126*387f9dfdSAndroid Build Coastguard Worker                        self.param_val_names[pname] = val_name
127*387f9dfdSAndroid Build Coastguard Worker                return text
128*387f9dfdSAndroid Build Coastguard Worker
129*387f9dfdSAndroid Build Coastguard Worker        def _generate_comm_prefix(self):
130*387f9dfdSAndroid Build Coastguard Worker                text = """
131*387f9dfdSAndroid Build Coastguard Workerstruct val_t {
132*387f9dfdSAndroid Build Coastguard Worker        u32 pid;
133*387f9dfdSAndroid Build Coastguard Worker        char name[sizeof(struct __string_t)];
134*387f9dfdSAndroid Build Coastguard Worker};
135*387f9dfdSAndroid Build Coastguard Workerstruct val_t val = {.pid = (bpf_get_current_pid_tgid() >> 32) };
136*387f9dfdSAndroid Build Coastguard Workerbpf_get_current_comm(&val.name, sizeof(val.name));
137*387f9dfdSAndroid Build Coastguard Worker        """
138*387f9dfdSAndroid Build Coastguard Worker                return text
139*387f9dfdSAndroid Build Coastguard Worker
140*387f9dfdSAndroid Build Coastguard Worker        def _replace_entry_exprs(self):
141*387f9dfdSAndroid Build Coastguard Worker                for pname, vname in self.param_val_names.items():
142*387f9dfdSAndroid Build Coastguard Worker                        if pname == "__latency":
143*387f9dfdSAndroid Build Coastguard Worker                                entry_expr = "$latency"
144*387f9dfdSAndroid Build Coastguard Worker                                val_expr = "(bpf_ktime_get_ns() - *%s)" % vname
145*387f9dfdSAndroid Build Coastguard Worker                        else:
146*387f9dfdSAndroid Build Coastguard Worker                                entry_expr = "$entry(%s)" % pname
147*387f9dfdSAndroid Build Coastguard Worker                                val_expr = "(*%s)" % vname
148*387f9dfdSAndroid Build Coastguard Worker                        for i in range(0, len(self.exprs)):
149*387f9dfdSAndroid Build Coastguard Worker                                self.exprs[i] = self.exprs[i].replace(
150*387f9dfdSAndroid Build Coastguard Worker                                                entry_expr, val_expr)
151*387f9dfdSAndroid Build Coastguard Worker                        self.filter = self.filter.replace(entry_expr,
152*387f9dfdSAndroid Build Coastguard Worker                                                          val_expr)
153*387f9dfdSAndroid Build Coastguard Worker
154*387f9dfdSAndroid Build Coastguard Worker        def _attach_entry_probe(self):
155*387f9dfdSAndroid Build Coastguard Worker                if self.is_user:
156*387f9dfdSAndroid Build Coastguard Worker                        self.bpf.attach_uprobe(name=self.library,
157*387f9dfdSAndroid Build Coastguard Worker                                               sym=self.function,
158*387f9dfdSAndroid Build Coastguard Worker                                               fn_name=self.entry_probe_func,
159*387f9dfdSAndroid Build Coastguard Worker                                               pid=self.pid or -1)
160*387f9dfdSAndroid Build Coastguard Worker                else:
161*387f9dfdSAndroid Build Coastguard Worker                        self.bpf.attach_kprobe(event=self.function,
162*387f9dfdSAndroid Build Coastguard Worker                                               fn_name=self.entry_probe_func)
163*387f9dfdSAndroid Build Coastguard Worker
164*387f9dfdSAndroid Build Coastguard Worker        def _bail(self, error):
165*387f9dfdSAndroid Build Coastguard Worker                raise ValueError("error parsing probe '%s': %s" %
166*387f9dfdSAndroid Build Coastguard Worker                                 (self.raw_spec, error))
167*387f9dfdSAndroid Build Coastguard Worker
168*387f9dfdSAndroid Build Coastguard Worker        def _validate_specifier(self):
169*387f9dfdSAndroid Build Coastguard Worker                # Everything after '#' is the probe label, ignore it
170*387f9dfdSAndroid Build Coastguard Worker                spec = self.raw_spec.split('#')[0]
171*387f9dfdSAndroid Build Coastguard Worker                parts = spec.strip().split(':')
172*387f9dfdSAndroid Build Coastguard Worker                if len(parts) < 3:
173*387f9dfdSAndroid Build Coastguard Worker                        self._bail("at least the probe type, library, and " +
174*387f9dfdSAndroid Build Coastguard Worker                                   "function signature must be specified")
175*387f9dfdSAndroid Build Coastguard Worker                if len(parts) > 6:
176*387f9dfdSAndroid Build Coastguard Worker                        self._bail("extraneous ':'-separated parts detected")
177*387f9dfdSAndroid Build Coastguard Worker                if parts[0] not in ["r", "p", "t", "u"]:
178*387f9dfdSAndroid Build Coastguard Worker                        self._bail("probe type must be 'p', 'r', 't', or 'u'" +
179*387f9dfdSAndroid Build Coastguard Worker                                   " but got '%s'" % parts[0])
180*387f9dfdSAndroid Build Coastguard Worker                if re.match(r"\S+\(.*\)", parts[2]) is None:
181*387f9dfdSAndroid Build Coastguard Worker                        self._bail(("function signature '%s' has an invalid " +
182*387f9dfdSAndroid Build Coastguard Worker                                    "format") % parts[2])
183*387f9dfdSAndroid Build Coastguard Worker
184*387f9dfdSAndroid Build Coastguard Worker        def _parse_expr_types(self, expr_types):
185*387f9dfdSAndroid Build Coastguard Worker                if len(expr_types) == 0:
186*387f9dfdSAndroid Build Coastguard Worker                        self._bail("no expr types specified")
187*387f9dfdSAndroid Build Coastguard Worker                self.expr_types = expr_types.split(',')
188*387f9dfdSAndroid Build Coastguard Worker
189*387f9dfdSAndroid Build Coastguard Worker        def _parse_exprs(self, exprs):
190*387f9dfdSAndroid Build Coastguard Worker                if len(exprs) == 0:
191*387f9dfdSAndroid Build Coastguard Worker                        self._bail("no exprs specified")
192*387f9dfdSAndroid Build Coastguard Worker                self.exprs = exprs.split(',')
193*387f9dfdSAndroid Build Coastguard Worker
194*387f9dfdSAndroid Build Coastguard Worker        def _make_valid_identifier(self, ident):
195*387f9dfdSAndroid Build Coastguard Worker                return re.sub(r'[^A-Za-z0-9_]', '_', ident)
196*387f9dfdSAndroid Build Coastguard Worker
197*387f9dfdSAndroid Build Coastguard Worker        def __init__(self, tool, type, specifier):
198*387f9dfdSAndroid Build Coastguard Worker                self.usdt_ctx = None
199*387f9dfdSAndroid Build Coastguard Worker                self.streq_functions = ""
200*387f9dfdSAndroid Build Coastguard Worker                self.pid = tool.args.pid
201*387f9dfdSAndroid Build Coastguard Worker                self.tid = tool.args.tid
202*387f9dfdSAndroid Build Coastguard Worker                self.cumulative = tool.args.cumulative or False
203*387f9dfdSAndroid Build Coastguard Worker                self.raw_spec = specifier
204*387f9dfdSAndroid Build Coastguard Worker                self.probe_user_list = set()
205*387f9dfdSAndroid Build Coastguard Worker                self.bin_cmp = False
206*387f9dfdSAndroid Build Coastguard Worker                self._validate_specifier()
207*387f9dfdSAndroid Build Coastguard Worker
208*387f9dfdSAndroid Build Coastguard Worker                spec_and_label = specifier.split('#')
209*387f9dfdSAndroid Build Coastguard Worker                self.label = spec_and_label[1] \
210*387f9dfdSAndroid Build Coastguard Worker                             if len(spec_and_label) == 2 else None
211*387f9dfdSAndroid Build Coastguard Worker
212*387f9dfdSAndroid Build Coastguard Worker                parts = spec_and_label[0].strip().split(':')
213*387f9dfdSAndroid Build Coastguard Worker                self.type = type    # hist or freq
214*387f9dfdSAndroid Build Coastguard Worker                self.probe_type = parts[0]
215*387f9dfdSAndroid Build Coastguard Worker                fparts = parts[2].split('(')
216*387f9dfdSAndroid Build Coastguard Worker                self.function = fparts[0].strip()
217*387f9dfdSAndroid Build Coastguard Worker                if self.probe_type == "t":
218*387f9dfdSAndroid Build Coastguard Worker                        self.library = ""       # kernel
219*387f9dfdSAndroid Build Coastguard Worker                        self.tp_category = parts[1]
220*387f9dfdSAndroid Build Coastguard Worker                        self.tp_event = self.function
221*387f9dfdSAndroid Build Coastguard Worker                elif self.probe_type == "u":
222*387f9dfdSAndroid Build Coastguard Worker                        self.library = parts[1]
223*387f9dfdSAndroid Build Coastguard Worker                        self.probe_func_name = self._make_valid_identifier(
224*387f9dfdSAndroid Build Coastguard Worker                                "%s_probe%d" %
225*387f9dfdSAndroid Build Coastguard Worker                                (self.function, Probe.next_probe_index))
226*387f9dfdSAndroid Build Coastguard Worker                        self._enable_usdt_probe()
227*387f9dfdSAndroid Build Coastguard Worker                else:
228*387f9dfdSAndroid Build Coastguard Worker                        self.library = parts[1]
229*387f9dfdSAndroid Build Coastguard Worker                self.is_user = len(self.library) > 0
230*387f9dfdSAndroid Build Coastguard Worker                self.signature = fparts[1].strip()[:-1]
231*387f9dfdSAndroid Build Coastguard Worker                self._parse_signature()
232*387f9dfdSAndroid Build Coastguard Worker
233*387f9dfdSAndroid Build Coastguard Worker                # If the user didn't specify an expression to probe, we probe
234*387f9dfdSAndroid Build Coastguard Worker                # the retval in a ret probe, or simply the value "1" otherwise.
235*387f9dfdSAndroid Build Coastguard Worker                self.is_default_expr = len(parts) < 5
236*387f9dfdSAndroid Build Coastguard Worker                if not self.is_default_expr:
237*387f9dfdSAndroid Build Coastguard Worker                        self._parse_expr_types(parts[3])
238*387f9dfdSAndroid Build Coastguard Worker                        self._parse_exprs(parts[4])
239*387f9dfdSAndroid Build Coastguard Worker                        if len(self.exprs) != len(self.expr_types):
240*387f9dfdSAndroid Build Coastguard Worker                                self._bail("mismatched # of exprs and types")
241*387f9dfdSAndroid Build Coastguard Worker                        if self.type == "hist" and len(self.expr_types) > 1:
242*387f9dfdSAndroid Build Coastguard Worker                                self._bail("histograms can only have 1 expr")
243*387f9dfdSAndroid Build Coastguard Worker                else:
244*387f9dfdSAndroid Build Coastguard Worker                        if not self.probe_type == "r" and self.type == "hist":
245*387f9dfdSAndroid Build Coastguard Worker                                self._bail("histograms must have expr")
246*387f9dfdSAndroid Build Coastguard Worker                        self.expr_types = \
247*387f9dfdSAndroid Build Coastguard Worker                          ["u64" if not self.probe_type == "r" else "int"]
248*387f9dfdSAndroid Build Coastguard Worker                        self.exprs = \
249*387f9dfdSAndroid Build Coastguard Worker                          ["1" if not self.probe_type == "r" else "$retval"]
250*387f9dfdSAndroid Build Coastguard Worker                self.filter = "" if len(parts) != 6 else parts[5]
251*387f9dfdSAndroid Build Coastguard Worker                self._substitute_exprs()
252*387f9dfdSAndroid Build Coastguard Worker
253*387f9dfdSAndroid Build Coastguard Worker                # Do we need to attach an entry probe so that we can collect an
254*387f9dfdSAndroid Build Coastguard Worker                # argument that is required for an exit (return) probe?
255*387f9dfdSAndroid Build Coastguard Worker                def check(expr):
256*387f9dfdSAndroid Build Coastguard Worker                        keywords = ["$entry", "$latency"]
257*387f9dfdSAndroid Build Coastguard Worker                        return any(map(lambda kw: kw in expr, keywords))
258*387f9dfdSAndroid Build Coastguard Worker                self.entry_probe_required = self.probe_type == "r" and \
259*387f9dfdSAndroid Build Coastguard Worker                        (any(map(check, self.exprs)) or check(self.filter))
260*387f9dfdSAndroid Build Coastguard Worker
261*387f9dfdSAndroid Build Coastguard Worker                self.probe_func_name = self._make_valid_identifier(
262*387f9dfdSAndroid Build Coastguard Worker                        "%s_probe%d" %
263*387f9dfdSAndroid Build Coastguard Worker                        (self.function, Probe.next_probe_index))
264*387f9dfdSAndroid Build Coastguard Worker                self.probe_hash_name = self._make_valid_identifier(
265*387f9dfdSAndroid Build Coastguard Worker                        "%s_hash%d" %
266*387f9dfdSAndroid Build Coastguard Worker                        (self.function, Probe.next_probe_index))
267*387f9dfdSAndroid Build Coastguard Worker                Probe.next_probe_index += 1
268*387f9dfdSAndroid Build Coastguard Worker
269*387f9dfdSAndroid Build Coastguard Worker        def _enable_usdt_probe(self):
270*387f9dfdSAndroid Build Coastguard Worker                self.usdt_ctx = USDT(path=self.library, pid=self.pid)
271*387f9dfdSAndroid Build Coastguard Worker                self.usdt_ctx.enable_probe(
272*387f9dfdSAndroid Build Coastguard Worker                        self.function, self.probe_func_name)
273*387f9dfdSAndroid Build Coastguard Worker
274*387f9dfdSAndroid Build Coastguard Worker        def _substitute_exprs(self):
275*387f9dfdSAndroid Build Coastguard Worker                def repl(expr):
276*387f9dfdSAndroid Build Coastguard Worker                        expr = self._substitute_aliases(expr)
277*387f9dfdSAndroid Build Coastguard Worker                        rdict = StrcmpRewrite.rewrite_expr(expr,
278*387f9dfdSAndroid Build Coastguard Worker                                self.bin_cmp, self.library,
279*387f9dfdSAndroid Build Coastguard Worker                                self.probe_user_list, self.streq_functions,
280*387f9dfdSAndroid Build Coastguard Worker                                Probe.streq_index)
281*387f9dfdSAndroid Build Coastguard Worker                        expr = rdict["expr"]
282*387f9dfdSAndroid Build Coastguard Worker                        self.streq_functions = rdict["streq_functions"]
283*387f9dfdSAndroid Build Coastguard Worker                        Probe.streq_index = rdict["probeid"]
284*387f9dfdSAndroid Build Coastguard Worker                        return expr.replace("$retval", "PT_REGS_RC(ctx)")
285*387f9dfdSAndroid Build Coastguard Worker                for i in range(0, len(self.exprs)):
286*387f9dfdSAndroid Build Coastguard Worker                        self.exprs[i] = repl(self.exprs[i])
287*387f9dfdSAndroid Build Coastguard Worker                self.filter = repl(self.filter)
288*387f9dfdSAndroid Build Coastguard Worker
289*387f9dfdSAndroid Build Coastguard Worker        def _is_string(self, expr_type):
290*387f9dfdSAndroid Build Coastguard Worker                return expr_type == "char*" or expr_type == "char *"
291*387f9dfdSAndroid Build Coastguard Worker
292*387f9dfdSAndroid Build Coastguard Worker        def _generate_hash_field(self, i):
293*387f9dfdSAndroid Build Coastguard Worker                if self._is_string(self.expr_types[i]):
294*387f9dfdSAndroid Build Coastguard Worker                        return "struct __string_t v%d;\n" % i
295*387f9dfdSAndroid Build Coastguard Worker                else:
296*387f9dfdSAndroid Build Coastguard Worker                        return "%s v%d;\n" % (self.expr_types[i], i)
297*387f9dfdSAndroid Build Coastguard Worker
298*387f9dfdSAndroid Build Coastguard Worker        def _generate_usdt_arg_assignment(self, i):
299*387f9dfdSAndroid Build Coastguard Worker                expr = self.exprs[i]
300*387f9dfdSAndroid Build Coastguard Worker                if self.probe_type == "u" and expr[0:3] == "arg":
301*387f9dfdSAndroid Build Coastguard Worker                        arg_index = int(expr[3])
302*387f9dfdSAndroid Build Coastguard Worker                        arg_ctype = self.usdt_ctx.get_probe_arg_ctype(
303*387f9dfdSAndroid Build Coastguard Worker                                self.function, arg_index - 1)
304*387f9dfdSAndroid Build Coastguard Worker                        return ("        %s %s = 0;\n" +
305*387f9dfdSAndroid Build Coastguard Worker                                "        bpf_usdt_readarg(%s, ctx, &%s);\n") \
306*387f9dfdSAndroid Build Coastguard Worker                                % (arg_ctype, expr, expr[3], expr)
307*387f9dfdSAndroid Build Coastguard Worker                else:
308*387f9dfdSAndroid Build Coastguard Worker                        return ""
309*387f9dfdSAndroid Build Coastguard Worker
310*387f9dfdSAndroid Build Coastguard Worker        def _generate_field_assignment(self, i):
311*387f9dfdSAndroid Build Coastguard Worker                text = self._generate_usdt_arg_assignment(i)
312*387f9dfdSAndroid Build Coastguard Worker                if self._is_string(self.expr_types[i]):
313*387f9dfdSAndroid Build Coastguard Worker                        if self.is_user or \
314*387f9dfdSAndroid Build Coastguard Worker                            self.exprs[i] in self.probe_user_list:
315*387f9dfdSAndroid Build Coastguard Worker                                probe_readfunc = "bpf_probe_read_user"
316*387f9dfdSAndroid Build Coastguard Worker                        else:
317*387f9dfdSAndroid Build Coastguard Worker                                probe_readfunc = "bpf_probe_read_kernel"
318*387f9dfdSAndroid Build Coastguard Worker                        return (text + "        %s(&__key.v%d.s," +
319*387f9dfdSAndroid Build Coastguard Worker                                " sizeof(__key.v%d.s), (void *)%s);\n") % \
320*387f9dfdSAndroid Build Coastguard Worker                                (probe_readfunc, i, i, self.exprs[i])
321*387f9dfdSAndroid Build Coastguard Worker                else:
322*387f9dfdSAndroid Build Coastguard Worker                        return text + "        __key.v%d = %s;\n" % \
323*387f9dfdSAndroid Build Coastguard Worker                               (i, self.exprs[i])
324*387f9dfdSAndroid Build Coastguard Worker
325*387f9dfdSAndroid Build Coastguard Worker        def _generate_hash_decl(self):
326*387f9dfdSAndroid Build Coastguard Worker                if self.type == "hist":
327*387f9dfdSAndroid Build Coastguard Worker                        return "BPF_HISTOGRAM(%s, %s);" % \
328*387f9dfdSAndroid Build Coastguard Worker                               (self.probe_hash_name, self.expr_types[0])
329*387f9dfdSAndroid Build Coastguard Worker                else:
330*387f9dfdSAndroid Build Coastguard Worker                        text = "struct %s_key_t {\n" % self.probe_hash_name
331*387f9dfdSAndroid Build Coastguard Worker                        for i in range(0, len(self.expr_types)):
332*387f9dfdSAndroid Build Coastguard Worker                                text += self._generate_hash_field(i)
333*387f9dfdSAndroid Build Coastguard Worker                        text += "};\n"
334*387f9dfdSAndroid Build Coastguard Worker                        text += "BPF_HASH(%s, struct %s_key_t, u64);\n" % \
335*387f9dfdSAndroid Build Coastguard Worker                                (self.probe_hash_name, self.probe_hash_name)
336*387f9dfdSAndroid Build Coastguard Worker                        return text
337*387f9dfdSAndroid Build Coastguard Worker
338*387f9dfdSAndroid Build Coastguard Worker        def _generate_key_assignment(self):
339*387f9dfdSAndroid Build Coastguard Worker                if self.type == "hist":
340*387f9dfdSAndroid Build Coastguard Worker                        return self._generate_usdt_arg_assignment(0) + \
341*387f9dfdSAndroid Build Coastguard Worker                               ("%s __key = %s;\n" %
342*387f9dfdSAndroid Build Coastguard Worker                                (self.expr_types[0], self.exprs[0]))
343*387f9dfdSAndroid Build Coastguard Worker                else:
344*387f9dfdSAndroid Build Coastguard Worker                        text = "struct %s_key_t __key = {};\n" % \
345*387f9dfdSAndroid Build Coastguard Worker                                self.probe_hash_name
346*387f9dfdSAndroid Build Coastguard Worker                        for i in range(0, len(self.exprs)):
347*387f9dfdSAndroid Build Coastguard Worker                                text += self._generate_field_assignment(i)
348*387f9dfdSAndroid Build Coastguard Worker                        return text
349*387f9dfdSAndroid Build Coastguard Worker
350*387f9dfdSAndroid Build Coastguard Worker        def _generate_hash_update(self):
351*387f9dfdSAndroid Build Coastguard Worker                if self.type == "hist":
352*387f9dfdSAndroid Build Coastguard Worker                        return "%s.atomic_increment(bpf_log2l(__key));" % \
353*387f9dfdSAndroid Build Coastguard Worker                                self.probe_hash_name
354*387f9dfdSAndroid Build Coastguard Worker                else:
355*387f9dfdSAndroid Build Coastguard Worker                        return "%s.atomic_increment(__key);" % \
356*387f9dfdSAndroid Build Coastguard Worker                                self.probe_hash_name
357*387f9dfdSAndroid Build Coastguard Worker
358*387f9dfdSAndroid Build Coastguard Worker        def _generate_pid_filter(self):
359*387f9dfdSAndroid Build Coastguard Worker                # Kernel probes need to explicitly filter pid, because the
360*387f9dfdSAndroid Build Coastguard Worker                # attach interface doesn't support pid filtering
361*387f9dfdSAndroid Build Coastguard Worker                if self.pid is not None and not self.is_user:
362*387f9dfdSAndroid Build Coastguard Worker                        return "if (__tgid != %d) { return 0; }" % self.pid
363*387f9dfdSAndroid Build Coastguard Worker                else:
364*387f9dfdSAndroid Build Coastguard Worker                        return ""
365*387f9dfdSAndroid Build Coastguard Worker
366*387f9dfdSAndroid Build Coastguard Worker        def _generate_tid_filter(self):
367*387f9dfdSAndroid Build Coastguard Worker                if self.tid is not None and not self.is_user:
368*387f9dfdSAndroid Build Coastguard Worker                        return "if (__pid != %d) { return 0; }" % self.tid
369*387f9dfdSAndroid Build Coastguard Worker                else:
370*387f9dfdSAndroid Build Coastguard Worker                        return ""
371*387f9dfdSAndroid Build Coastguard Worker
372*387f9dfdSAndroid Build Coastguard Worker        def generate_text(self):
373*387f9dfdSAndroid Build Coastguard Worker                program = ""
374*387f9dfdSAndroid Build Coastguard Worker                probe_text = """
375*387f9dfdSAndroid Build Coastguard WorkerDATA_DECL
376*387f9dfdSAndroid Build Coastguard Worker                """ + (
377*387f9dfdSAndroid Build Coastguard Worker                    "TRACEPOINT_PROBE(%s, %s)" %
378*387f9dfdSAndroid Build Coastguard Worker                    (self.tp_category, self.tp_event)
379*387f9dfdSAndroid Build Coastguard Worker                    if self.probe_type == "t"
380*387f9dfdSAndroid Build Coastguard Worker                    else "int PROBENAME(struct pt_regs *ctx SIGNATURE)") + """
381*387f9dfdSAndroid Build Coastguard Worker{
382*387f9dfdSAndroid Build Coastguard Worker        u64 __pid_tgid = bpf_get_current_pid_tgid();
383*387f9dfdSAndroid Build Coastguard Worker        u32 __pid      = __pid_tgid;        // lower 32 bits
384*387f9dfdSAndroid Build Coastguard Worker        u32 __tgid     = __pid_tgid >> 32;  // upper 32 bits
385*387f9dfdSAndroid Build Coastguard Worker        PID_FILTER
386*387f9dfdSAndroid Build Coastguard Worker        TID_FILTER
387*387f9dfdSAndroid Build Coastguard Worker        PREFIX
388*387f9dfdSAndroid Build Coastguard Worker        KEY_EXPR
389*387f9dfdSAndroid Build Coastguard Worker        if (!(FILTER)) return 0;
390*387f9dfdSAndroid Build Coastguard Worker        COLLECT
391*387f9dfdSAndroid Build Coastguard Worker        return 0;
392*387f9dfdSAndroid Build Coastguard Worker}
393*387f9dfdSAndroid Build Coastguard Worker"""
394*387f9dfdSAndroid Build Coastguard Worker                prefix = ""
395*387f9dfdSAndroid Build Coastguard Worker                signature = ""
396*387f9dfdSAndroid Build Coastguard Worker
397*387f9dfdSAndroid Build Coastguard Worker                # If any entry arguments are probed in a ret probe, we need
398*387f9dfdSAndroid Build Coastguard Worker                # to generate an entry probe to collect them
399*387f9dfdSAndroid Build Coastguard Worker                if self.entry_probe_required:
400*387f9dfdSAndroid Build Coastguard Worker                        program += self._generate_entry_probe()
401*387f9dfdSAndroid Build Coastguard Worker                        prefix += self._generate_retprobe_prefix()
402*387f9dfdSAndroid Build Coastguard Worker                        # Replace $entry(paramname) with a reference to the
403*387f9dfdSAndroid Build Coastguard Worker                        # value we collected when entering the function:
404*387f9dfdSAndroid Build Coastguard Worker                        self._replace_entry_exprs()
405*387f9dfdSAndroid Build Coastguard Worker
406*387f9dfdSAndroid Build Coastguard Worker                if self.probe_type == "p" and len(self.signature) > 0:
407*387f9dfdSAndroid Build Coastguard Worker                        # Only entry uprobes/kprobes can have user-specified
408*387f9dfdSAndroid Build Coastguard Worker                        # signatures. Other probes force it to ().
409*387f9dfdSAndroid Build Coastguard Worker                        signature = ", " + self.signature
410*387f9dfdSAndroid Build Coastguard Worker
411*387f9dfdSAndroid Build Coastguard Worker                # If COMM is specified prefix with code to get process name
412*387f9dfdSAndroid Build Coastguard Worker                if self.exprs.count(self.aliases['$COMM']):
413*387f9dfdSAndroid Build Coastguard Worker                        prefix += self._generate_comm_prefix()
414*387f9dfdSAndroid Build Coastguard Worker
415*387f9dfdSAndroid Build Coastguard Worker                program += probe_text.replace("PROBENAME",
416*387f9dfdSAndroid Build Coastguard Worker                                              self.probe_func_name)
417*387f9dfdSAndroid Build Coastguard Worker                program = program.replace("SIGNATURE", signature)
418*387f9dfdSAndroid Build Coastguard Worker                program = program.replace("PID_FILTER",
419*387f9dfdSAndroid Build Coastguard Worker                                          self._generate_pid_filter())
420*387f9dfdSAndroid Build Coastguard Worker                program = program.replace("TID_FILTER",
421*387f9dfdSAndroid Build Coastguard Worker                                          self._generate_tid_filter())
422*387f9dfdSAndroid Build Coastguard Worker
423*387f9dfdSAndroid Build Coastguard Worker                decl = self._generate_hash_decl()
424*387f9dfdSAndroid Build Coastguard Worker                key_expr = self._generate_key_assignment()
425*387f9dfdSAndroid Build Coastguard Worker                collect = self._generate_hash_update()
426*387f9dfdSAndroid Build Coastguard Worker                program = program.replace("DATA_DECL", decl)
427*387f9dfdSAndroid Build Coastguard Worker                program = program.replace("KEY_EXPR", key_expr)
428*387f9dfdSAndroid Build Coastguard Worker                program = program.replace("FILTER",
429*387f9dfdSAndroid Build Coastguard Worker                        "1" if len(self.filter) == 0 else self.filter)
430*387f9dfdSAndroid Build Coastguard Worker                program = program.replace("COLLECT", collect)
431*387f9dfdSAndroid Build Coastguard Worker                program = program.replace("PREFIX", prefix)
432*387f9dfdSAndroid Build Coastguard Worker
433*387f9dfdSAndroid Build Coastguard Worker                return self.streq_functions + program
434*387f9dfdSAndroid Build Coastguard Worker
435*387f9dfdSAndroid Build Coastguard Worker        def _attach_u(self):
436*387f9dfdSAndroid Build Coastguard Worker                libpath = BPF.find_library(self.library)
437*387f9dfdSAndroid Build Coastguard Worker                if libpath is None:
438*387f9dfdSAndroid Build Coastguard Worker                        libpath = BPF.find_exe(self.library)
439*387f9dfdSAndroid Build Coastguard Worker                if libpath is None or len(libpath) == 0:
440*387f9dfdSAndroid Build Coastguard Worker                        self._bail("unable to find library %s" % self.library)
441*387f9dfdSAndroid Build Coastguard Worker
442*387f9dfdSAndroid Build Coastguard Worker                if self.probe_type == "r":
443*387f9dfdSAndroid Build Coastguard Worker                        self.bpf.attach_uretprobe(name=libpath,
444*387f9dfdSAndroid Build Coastguard Worker                                                  sym=self.function,
445*387f9dfdSAndroid Build Coastguard Worker                                                  fn_name=self.probe_func_name,
446*387f9dfdSAndroid Build Coastguard Worker                                                  pid=self.pid or -1)
447*387f9dfdSAndroid Build Coastguard Worker                else:
448*387f9dfdSAndroid Build Coastguard Worker                        self.bpf.attach_uprobe(name=libpath,
449*387f9dfdSAndroid Build Coastguard Worker                                               sym=self.function,
450*387f9dfdSAndroid Build Coastguard Worker                                               fn_name=self.probe_func_name,
451*387f9dfdSAndroid Build Coastguard Worker                                               pid=self.pid or -1)
452*387f9dfdSAndroid Build Coastguard Worker
453*387f9dfdSAndroid Build Coastguard Worker        def _attach_k(self):
454*387f9dfdSAndroid Build Coastguard Worker                if self.probe_type == "t":
455*387f9dfdSAndroid Build Coastguard Worker                        pass    # Nothing to do for tracepoints
456*387f9dfdSAndroid Build Coastguard Worker                elif self.probe_type == "r":
457*387f9dfdSAndroid Build Coastguard Worker                        self.bpf.attach_kretprobe(event=self.function,
458*387f9dfdSAndroid Build Coastguard Worker                                             fn_name=self.probe_func_name)
459*387f9dfdSAndroid Build Coastguard Worker                else:
460*387f9dfdSAndroid Build Coastguard Worker                        self.bpf.attach_kprobe(event=self.function,
461*387f9dfdSAndroid Build Coastguard Worker                                          fn_name=self.probe_func_name)
462*387f9dfdSAndroid Build Coastguard Worker
463*387f9dfdSAndroid Build Coastguard Worker        def attach(self, bpf):
464*387f9dfdSAndroid Build Coastguard Worker                self.bpf = bpf
465*387f9dfdSAndroid Build Coastguard Worker                if self.probe_type == "u":
466*387f9dfdSAndroid Build Coastguard Worker                        return
467*387f9dfdSAndroid Build Coastguard Worker                if self.is_user:
468*387f9dfdSAndroid Build Coastguard Worker                        self._attach_u()
469*387f9dfdSAndroid Build Coastguard Worker                else:
470*387f9dfdSAndroid Build Coastguard Worker                        self._attach_k()
471*387f9dfdSAndroid Build Coastguard Worker                if self.entry_probe_required:
472*387f9dfdSAndroid Build Coastguard Worker                        self._attach_entry_probe()
473*387f9dfdSAndroid Build Coastguard Worker
474*387f9dfdSAndroid Build Coastguard Worker        def _v2s(self, v):
475*387f9dfdSAndroid Build Coastguard Worker                # Most fields can be converted with plain str(), but strings
476*387f9dfdSAndroid Build Coastguard Worker                # are wrapped in a __string_t which has an .s field
477*387f9dfdSAndroid Build Coastguard Worker                if "__string_t" in type(v).__name__:
478*387f9dfdSAndroid Build Coastguard Worker                        return str(v.s)
479*387f9dfdSAndroid Build Coastguard Worker                return str(v)
480*387f9dfdSAndroid Build Coastguard Worker
481*387f9dfdSAndroid Build Coastguard Worker        def _display_expr(self, i):
482*387f9dfdSAndroid Build Coastguard Worker                # Replace ugly latency calculation with $latency
483*387f9dfdSAndroid Build Coastguard Worker                expr = self.exprs[i].replace(
484*387f9dfdSAndroid Build Coastguard Worker                        "(bpf_ktime_get_ns() - *____latency_val)", "$latency")
485*387f9dfdSAndroid Build Coastguard Worker                # Replace alias values back with the alias name
486*387f9dfdSAndroid Build Coastguard Worker                for alias, subst in Probe.aliases.items():
487*387f9dfdSAndroid Build Coastguard Worker                        expr = expr.replace(subst, alias)
488*387f9dfdSAndroid Build Coastguard Worker                # Replace retval expression with $retval
489*387f9dfdSAndroid Build Coastguard Worker                expr = expr.replace("PT_REGS_RC(ctx)", "$retval")
490*387f9dfdSAndroid Build Coastguard Worker                # Replace ugly (*__param_val) expressions with param name
491*387f9dfdSAndroid Build Coastguard Worker                return re.sub(r"\(\*__(\w+)_val\)", r"\1", expr)
492*387f9dfdSAndroid Build Coastguard Worker
493*387f9dfdSAndroid Build Coastguard Worker        def _display_key(self, key):
494*387f9dfdSAndroid Build Coastguard Worker                if self.is_default_expr:
495*387f9dfdSAndroid Build Coastguard Worker                        if not self.probe_type == "r":
496*387f9dfdSAndroid Build Coastguard Worker                                return "total calls"
497*387f9dfdSAndroid Build Coastguard Worker                        else:
498*387f9dfdSAndroid Build Coastguard Worker                                return "retval = %s" % str(key.v0)
499*387f9dfdSAndroid Build Coastguard Worker                else:
500*387f9dfdSAndroid Build Coastguard Worker                        # The key object has v0, ..., vk fields containing
501*387f9dfdSAndroid Build Coastguard Worker                        # the values of the expressions from self.exprs
502*387f9dfdSAndroid Build Coastguard Worker                        def str_i(i):
503*387f9dfdSAndroid Build Coastguard Worker                                key_i = self._v2s(getattr(key, "v%d" % i))
504*387f9dfdSAndroid Build Coastguard Worker                                return "%s = %s" % \
505*387f9dfdSAndroid Build Coastguard Worker                                        (self._display_expr(i), key_i)
506*387f9dfdSAndroid Build Coastguard Worker                        return ", ".join(map(str_i, range(0, len(self.exprs))))
507*387f9dfdSAndroid Build Coastguard Worker
508*387f9dfdSAndroid Build Coastguard Worker        def display(self, top):
509*387f9dfdSAndroid Build Coastguard Worker                data = self.bpf.get_table(self.probe_hash_name)
510*387f9dfdSAndroid Build Coastguard Worker                if self.type == "freq":
511*387f9dfdSAndroid Build Coastguard Worker                        print(self.label or self.raw_spec)
512*387f9dfdSAndroid Build Coastguard Worker                        print("\t%-10s %s" % ("COUNT", "EVENT"))
513*387f9dfdSAndroid Build Coastguard Worker                        sdata = sorted(data.items(), key=lambda p: p[1].value)
514*387f9dfdSAndroid Build Coastguard Worker                        if top is not None:
515*387f9dfdSAndroid Build Coastguard Worker                                sdata = sdata[-top:]
516*387f9dfdSAndroid Build Coastguard Worker                        for key, value in sdata:
517*387f9dfdSAndroid Build Coastguard Worker                                # Print some nice values if the user didn't
518*387f9dfdSAndroid Build Coastguard Worker                                # specify an expression to probe
519*387f9dfdSAndroid Build Coastguard Worker                                if self.is_default_expr:
520*387f9dfdSAndroid Build Coastguard Worker                                        if not self.probe_type == "r":
521*387f9dfdSAndroid Build Coastguard Worker                                                key_str = "total calls"
522*387f9dfdSAndroid Build Coastguard Worker                                        else:
523*387f9dfdSAndroid Build Coastguard Worker                                                key_str = "retval = %s" % \
524*387f9dfdSAndroid Build Coastguard Worker                                                          self._v2s(key.v0)
525*387f9dfdSAndroid Build Coastguard Worker                                else:
526*387f9dfdSAndroid Build Coastguard Worker                                        key_str = self._display_key(key)
527*387f9dfdSAndroid Build Coastguard Worker                                print("\t%-10s %s" %
528*387f9dfdSAndroid Build Coastguard Worker                                      (str(value.value), key_str))
529*387f9dfdSAndroid Build Coastguard Worker                elif self.type == "hist":
530*387f9dfdSAndroid Build Coastguard Worker                        label = self.label or (self._display_expr(0)
531*387f9dfdSAndroid Build Coastguard Worker                                if not self.is_default_expr else "retval")
532*387f9dfdSAndroid Build Coastguard Worker                        data.print_log2_hist(val_type=label)
533*387f9dfdSAndroid Build Coastguard Worker                if not self.cumulative:
534*387f9dfdSAndroid Build Coastguard Worker                        data.clear()
535*387f9dfdSAndroid Build Coastguard Worker
536*387f9dfdSAndroid Build Coastguard Worker        def __str__(self):
537*387f9dfdSAndroid Build Coastguard Worker                return self.label or self.raw_spec
538*387f9dfdSAndroid Build Coastguard Worker
539*387f9dfdSAndroid Build Coastguard Workerclass Tool(object):
540*387f9dfdSAndroid Build Coastguard Worker        examples = """
541*387f9dfdSAndroid Build Coastguard WorkerProbe specifier syntax:
542*387f9dfdSAndroid Build Coastguard Worker        {p,r,t,u}:{[library],category}:function(signature):type[,type...]:expr[,expr...][:filter]][#label]
543*387f9dfdSAndroid Build Coastguard WorkerWhere:
544*387f9dfdSAndroid Build Coastguard Worker        p,r,t,u    -- probe at function entry, function exit, kernel
545*387f9dfdSAndroid Build Coastguard Worker                      tracepoint, or USDT probe
546*387f9dfdSAndroid Build Coastguard Worker                      in exit probes: can use $retval, $entry(param), $latency
547*387f9dfdSAndroid Build Coastguard Worker        library    -- the library that contains the function
548*387f9dfdSAndroid Build Coastguard Worker                      (leave empty for kernel functions)
549*387f9dfdSAndroid Build Coastguard Worker        category   -- the category of the kernel tracepoint (e.g. net, sched)
550*387f9dfdSAndroid Build Coastguard Worker        function   -- the function name to trace (or tracepoint name)
551*387f9dfdSAndroid Build Coastguard Worker        signature  -- the function's parameters, as in the C header
552*387f9dfdSAndroid Build Coastguard Worker        type       -- the type of the expression to collect (supports multiple)
553*387f9dfdSAndroid Build Coastguard Worker        expr       -- the expression to collect (supports multiple)
554*387f9dfdSAndroid Build Coastguard Worker        filter     -- the filter that is applied to collected values
555*387f9dfdSAndroid Build Coastguard Worker        label      -- the label for this probe in the resulting output
556*387f9dfdSAndroid Build Coastguard Worker
557*387f9dfdSAndroid Build Coastguard WorkerEXAMPLES:
558*387f9dfdSAndroid Build Coastguard Worker
559*387f9dfdSAndroid Build Coastguard Workerargdist -H 'p::__kmalloc(u64 size):u64:size'
560*387f9dfdSAndroid Build Coastguard Worker        Print a histogram of allocation sizes passed to kmalloc
561*387f9dfdSAndroid Build Coastguard Worker
562*387f9dfdSAndroid Build Coastguard Workerargdist -p 1005 -C 'p:c:malloc(size_t size):size_t:size:size==16'
563*387f9dfdSAndroid Build Coastguard Worker        Print a frequency count of how many times process 1005 called malloc
564*387f9dfdSAndroid Build Coastguard Worker        with an allocation size of 16 bytes
565*387f9dfdSAndroid Build Coastguard Worker
566*387f9dfdSAndroid Build Coastguard Workerargdist -C 'r:c:gets():char*:(char*)$retval#snooped strings'
567*387f9dfdSAndroid Build Coastguard Worker        Snoop on all strings returned by gets()
568*387f9dfdSAndroid Build Coastguard Worker
569*387f9dfdSAndroid Build Coastguard Workerargdist -H 'r::__kmalloc(size_t size):u64:$latency/$entry(size)#ns per byte'
570*387f9dfdSAndroid Build Coastguard Worker        Print a histogram of nanoseconds per byte from kmalloc allocations
571*387f9dfdSAndroid Build Coastguard Worker
572*387f9dfdSAndroid Build Coastguard Workerargdist -C 'p::__kmalloc(size_t sz, gfp_t flags):size_t:sz:flags&GFP_ATOMIC'
573*387f9dfdSAndroid Build Coastguard Worker        Print frequency count of kmalloc allocation sizes that have GFP_ATOMIC
574*387f9dfdSAndroid Build Coastguard Worker
575*387f9dfdSAndroid Build Coastguard Workerargdist -p 1005 -C 'p:c:write(int fd):int:fd' -T 5
576*387f9dfdSAndroid Build Coastguard Worker        Print frequency counts of how many times writes were issued to a
577*387f9dfdSAndroid Build Coastguard Worker        particular file descriptor number, in process 1005, but only show
578*387f9dfdSAndroid Build Coastguard Worker        the top 5 busiest fds
579*387f9dfdSAndroid Build Coastguard Worker
580*387f9dfdSAndroid Build Coastguard Workerargdist -p 1005 -H 'r:c:read()'
581*387f9dfdSAndroid Build Coastguard Worker        Print a histogram of results (sizes) returned by read() in process 1005
582*387f9dfdSAndroid Build Coastguard Worker
583*387f9dfdSAndroid Build Coastguard Workerargdist -C 'r::__vfs_read():u32:$PID:$latency > 100000'
584*387f9dfdSAndroid Build Coastguard Worker        Print frequency of reads by process where the latency was >0.1ms
585*387f9dfdSAndroid Build Coastguard Worker
586*387f9dfdSAndroid Build Coastguard Workerargdist -C 'r::__vfs_read():u32:$COMM:$latency > 100000'
587*387f9dfdSAndroid Build Coastguard Worker        Print frequency of reads by process name where the latency was >0.1ms
588*387f9dfdSAndroid Build Coastguard Worker
589*387f9dfdSAndroid Build Coastguard Workerargdist -H 'r::__vfs_read(void *file, void *buf, size_t count):size_t:
590*387f9dfdSAndroid Build Coastguard Worker            $entry(count):$latency > 1000000'
591*387f9dfdSAndroid Build Coastguard Worker        Print a histogram of read sizes that were longer than 1ms
592*387f9dfdSAndroid Build Coastguard Worker
593*387f9dfdSAndroid Build Coastguard Workerargdist -H \\
594*387f9dfdSAndroid Build Coastguard Worker        'p:c:write(int fd, const void *buf, size_t count):size_t:count:fd==1'
595*387f9dfdSAndroid Build Coastguard Worker        Print a histogram of buffer sizes passed to write() across all
596*387f9dfdSAndroid Build Coastguard Worker        processes, where the file descriptor was 1 (STDOUT)
597*387f9dfdSAndroid Build Coastguard Worker
598*387f9dfdSAndroid Build Coastguard Workerargdist -C 'p:c:fork()#fork calls'
599*387f9dfdSAndroid Build Coastguard Worker        Count fork() calls in libc across all processes
600*387f9dfdSAndroid Build Coastguard Worker        Can also use funccount.py, which is easier and more flexible
601*387f9dfdSAndroid Build Coastguard Worker
602*387f9dfdSAndroid Build Coastguard Workerargdist -H 't:block:block_rq_complete():u32:args->nr_sector'
603*387f9dfdSAndroid Build Coastguard Worker        Print histogram of number of sectors in completing block I/O requests
604*387f9dfdSAndroid Build Coastguard Worker
605*387f9dfdSAndroid Build Coastguard Workerargdist -C 't:irq:irq_handler_entry():int:args->irq'
606*387f9dfdSAndroid Build Coastguard Worker        Aggregate interrupts by interrupt request (IRQ)
607*387f9dfdSAndroid Build Coastguard Worker
608*387f9dfdSAndroid Build Coastguard Workerargdist -C 'u:pthread:pthread_start():u64:arg2' -p 1337
609*387f9dfdSAndroid Build Coastguard Worker        Print frequency of function addresses used as a pthread start function,
610*387f9dfdSAndroid Build Coastguard Worker        relying on the USDT pthread_start probe in process 1337
611*387f9dfdSAndroid Build Coastguard Worker
612*387f9dfdSAndroid Build Coastguard Workerargdist -H 'p:c:sleep(u32 seconds):u32:seconds' \\
613*387f9dfdSAndroid Build Coastguard Worker        -H 'p:c:nanosleep(struct timespec *req):long:req->tv_nsec'
614*387f9dfdSAndroid Build Coastguard Worker        Print histograms of sleep() and nanosleep() parameter values
615*387f9dfdSAndroid Build Coastguard Worker
616*387f9dfdSAndroid Build Coastguard Workerargdist -p 2780 -z 120 \\
617*387f9dfdSAndroid Build Coastguard Worker        -C 'p:c:write(int fd, char* buf, size_t len):char*:buf:fd==1'
618*387f9dfdSAndroid Build Coastguard Worker        Spy on writes to STDOUT performed by process 2780, up to a string size
619*387f9dfdSAndroid Build Coastguard Worker        of 120 characters
620*387f9dfdSAndroid Build Coastguard Worker
621*387f9dfdSAndroid Build Coastguard Workerargdist -I 'kernel/sched/sched.h' \\
622*387f9dfdSAndroid Build Coastguard Worker        -C 'p::__account_cfs_rq_runtime(struct cfs_rq *cfs_rq):s64:cfs_rq->runtime_remaining'
623*387f9dfdSAndroid Build Coastguard Worker        Trace on the cfs scheduling runqueue remaining runtime. The struct cfs_rq is defined
624*387f9dfdSAndroid Build Coastguard Worker        in kernel/sched/sched.h which is in kernel source tree and not in kernel-devel
625*387f9dfdSAndroid Build Coastguard Worker        package.  So this command needs to run at the kernel source tree root directory
626*387f9dfdSAndroid Build Coastguard Worker        so that the added header file can be found by the compiler.
627*387f9dfdSAndroid Build Coastguard Worker"""
628*387f9dfdSAndroid Build Coastguard Worker
629*387f9dfdSAndroid Build Coastguard Worker        def __init__(self):
630*387f9dfdSAndroid Build Coastguard Worker                parser = argparse.ArgumentParser(description="Trace a " +
631*387f9dfdSAndroid Build Coastguard Worker                  "function and display a summary of its parameter values.",
632*387f9dfdSAndroid Build Coastguard Worker                  formatter_class=argparse.RawDescriptionHelpFormatter,
633*387f9dfdSAndroid Build Coastguard Worker                  epilog=Tool.examples)
634*387f9dfdSAndroid Build Coastguard Worker                parser.add_argument("-p", "--pid", type=int,
635*387f9dfdSAndroid Build Coastguard Worker                  help="id of the process to trace (optional)")
636*387f9dfdSAndroid Build Coastguard Worker                parser.add_argument("-t", "--tid", type=int,
637*387f9dfdSAndroid Build Coastguard Worker                  help="id of the thread to trace (optional)")
638*387f9dfdSAndroid Build Coastguard Worker                parser.add_argument("-z", "--string-size", default=80,
639*387f9dfdSAndroid Build Coastguard Worker                  type=int,
640*387f9dfdSAndroid Build Coastguard Worker                  help="maximum string size to read from char* arguments")
641*387f9dfdSAndroid Build Coastguard Worker                parser.add_argument("-i", "--interval", default=1, type=int,
642*387f9dfdSAndroid Build Coastguard Worker                  help="output interval, in seconds (default 1 second)")
643*387f9dfdSAndroid Build Coastguard Worker                parser.add_argument("-d", "--duration", type=int,
644*387f9dfdSAndroid Build Coastguard Worker                  help="total duration of trace, in seconds")
645*387f9dfdSAndroid Build Coastguard Worker                parser.add_argument("-n", "--number", type=int, dest="count",
646*387f9dfdSAndroid Build Coastguard Worker                  help="number of outputs")
647*387f9dfdSAndroid Build Coastguard Worker                parser.add_argument("-v", "--verbose", action="store_true",
648*387f9dfdSAndroid Build Coastguard Worker                  help="print resulting BPF program code before executing")
649*387f9dfdSAndroid Build Coastguard Worker                parser.add_argument("-c", "--cumulative", action="store_true",
650*387f9dfdSAndroid Build Coastguard Worker                  help="do not clear histograms and freq counts at " +
651*387f9dfdSAndroid Build Coastguard Worker                       "each interval")
652*387f9dfdSAndroid Build Coastguard Worker                parser.add_argument("-T", "--top", type=int,
653*387f9dfdSAndroid Build Coastguard Worker                  help="number of top results to show (not applicable to " +
654*387f9dfdSAndroid Build Coastguard Worker                  "histograms)")
655*387f9dfdSAndroid Build Coastguard Worker                parser.add_argument("-H", "--histogram", action="append",
656*387f9dfdSAndroid Build Coastguard Worker                  dest="histspecifier", metavar="specifier",
657*387f9dfdSAndroid Build Coastguard Worker                  help="probe specifier to capture histogram of " +
658*387f9dfdSAndroid Build Coastguard Worker                  "(see examples below)")
659*387f9dfdSAndroid Build Coastguard Worker                parser.add_argument("-C", "--count", action="append",
660*387f9dfdSAndroid Build Coastguard Worker                  dest="countspecifier", metavar="specifier",
661*387f9dfdSAndroid Build Coastguard Worker                  help="probe specifier to capture count of " +
662*387f9dfdSAndroid Build Coastguard Worker                  "(see examples below)")
663*387f9dfdSAndroid Build Coastguard Worker                parser.add_argument("-I", "--include", action="append",
664*387f9dfdSAndroid Build Coastguard Worker                  metavar="header",
665*387f9dfdSAndroid Build Coastguard Worker                  help="additional header files to include in the BPF program "
666*387f9dfdSAndroid Build Coastguard Worker                       "as either full path, "
667*387f9dfdSAndroid Build Coastguard Worker                       "or relative to relative to current working directory, "
668*387f9dfdSAndroid Build Coastguard Worker                       "or relative to default kernel header search path")
669*387f9dfdSAndroid Build Coastguard Worker                parser.add_argument("--ebpf", action="store_true",
670*387f9dfdSAndroid Build Coastguard Worker                  help=argparse.SUPPRESS)
671*387f9dfdSAndroid Build Coastguard Worker                self.args = parser.parse_args()
672*387f9dfdSAndroid Build Coastguard Worker                self.usdt_ctx = None
673*387f9dfdSAndroid Build Coastguard Worker
674*387f9dfdSAndroid Build Coastguard Worker        def _create_probes(self):
675*387f9dfdSAndroid Build Coastguard Worker                self.probes = []
676*387f9dfdSAndroid Build Coastguard Worker                for specifier in (self.args.countspecifier or []):
677*387f9dfdSAndroid Build Coastguard Worker                        self.probes.append(Probe(self, "freq", specifier))
678*387f9dfdSAndroid Build Coastguard Worker                for histspecifier in (self.args.histspecifier or []):
679*387f9dfdSAndroid Build Coastguard Worker                        self.probes.append(Probe(self, "hist", histspecifier))
680*387f9dfdSAndroid Build Coastguard Worker                if len(self.probes) == 0:
681*387f9dfdSAndroid Build Coastguard Worker                        print("at least one specifier is required")
682*387f9dfdSAndroid Build Coastguard Worker                        exit(1)
683*387f9dfdSAndroid Build Coastguard Worker
684*387f9dfdSAndroid Build Coastguard Worker        def _generate_program(self):
685*387f9dfdSAndroid Build Coastguard Worker                bpf_source = """
686*387f9dfdSAndroid Build Coastguard Workerstruct __string_t { char s[%d]; };
687*387f9dfdSAndroid Build Coastguard Worker
688*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h>
689*387f9dfdSAndroid Build Coastguard Worker                """ % self.args.string_size
690*387f9dfdSAndroid Build Coastguard Worker                for include in (self.args.include or []):
691*387f9dfdSAndroid Build Coastguard Worker                        if include.startswith((".", "/")):
692*387f9dfdSAndroid Build Coastguard Worker                                include = os.path.abspath(include)
693*387f9dfdSAndroid Build Coastguard Worker                                bpf_source += "#include \"%s\"\n" % include
694*387f9dfdSAndroid Build Coastguard Worker                        else:
695*387f9dfdSAndroid Build Coastguard Worker                                bpf_source += "#include <%s>\n" % include
696*387f9dfdSAndroid Build Coastguard Worker
697*387f9dfdSAndroid Build Coastguard Worker                bpf_source += BPF.generate_auto_includes(
698*387f9dfdSAndroid Build Coastguard Worker                                map(lambda p: p.raw_spec, self.probes))
699*387f9dfdSAndroid Build Coastguard Worker                for probe in self.probes:
700*387f9dfdSAndroid Build Coastguard Worker                        bpf_source += probe.generate_text()
701*387f9dfdSAndroid Build Coastguard Worker                if self.args.verbose:
702*387f9dfdSAndroid Build Coastguard Worker                        for text in [probe.usdt_ctx.get_text()
703*387f9dfdSAndroid Build Coastguard Worker                                     for probe in self.probes
704*387f9dfdSAndroid Build Coastguard Worker                                     if probe.usdt_ctx]:
705*387f9dfdSAndroid Build Coastguard Worker                            print(text)
706*387f9dfdSAndroid Build Coastguard Worker                if self.args.verbose or self.args.ebpf:
707*387f9dfdSAndroid Build Coastguard Worker                    print(bpf_source)
708*387f9dfdSAndroid Build Coastguard Worker                    if self.args.ebpf:
709*387f9dfdSAndroid Build Coastguard Worker                        exit()
710*387f9dfdSAndroid Build Coastguard Worker                usdt_contexts = [probe.usdt_ctx
711*387f9dfdSAndroid Build Coastguard Worker                                 for probe in self.probes if probe.usdt_ctx]
712*387f9dfdSAndroid Build Coastguard Worker                self.bpf = BPF(text=bpf_source, usdt_contexts=usdt_contexts)
713*387f9dfdSAndroid Build Coastguard Worker
714*387f9dfdSAndroid Build Coastguard Worker        def _attach(self):
715*387f9dfdSAndroid Build Coastguard Worker                for probe in self.probes:
716*387f9dfdSAndroid Build Coastguard Worker                        probe.attach(self.bpf)
717*387f9dfdSAndroid Build Coastguard Worker                if self.args.verbose:
718*387f9dfdSAndroid Build Coastguard Worker                        print("open uprobes: %s" % list(self.bpf.uprobe_fds.keys()))
719*387f9dfdSAndroid Build Coastguard Worker                        print("open kprobes: %s" % list(self.bpf.kprobe_fds.keys()))
720*387f9dfdSAndroid Build Coastguard Worker
721*387f9dfdSAndroid Build Coastguard Worker        def _main_loop(self):
722*387f9dfdSAndroid Build Coastguard Worker                count_so_far = 0
723*387f9dfdSAndroid Build Coastguard Worker                seconds = 0
724*387f9dfdSAndroid Build Coastguard Worker                while True:
725*387f9dfdSAndroid Build Coastguard Worker                        try:
726*387f9dfdSAndroid Build Coastguard Worker                                sleep(self.args.interval)
727*387f9dfdSAndroid Build Coastguard Worker                                seconds += self.args.interval
728*387f9dfdSAndroid Build Coastguard Worker                        except KeyboardInterrupt:
729*387f9dfdSAndroid Build Coastguard Worker                                exit()
730*387f9dfdSAndroid Build Coastguard Worker                        print("[%s]" % strftime("%H:%M:%S"))
731*387f9dfdSAndroid Build Coastguard Worker                        for probe in self.probes:
732*387f9dfdSAndroid Build Coastguard Worker                                probe.display(self.args.top)
733*387f9dfdSAndroid Build Coastguard Worker                        count_so_far += 1
734*387f9dfdSAndroid Build Coastguard Worker                        if self.args.count is not None and \
735*387f9dfdSAndroid Build Coastguard Worker                           count_so_far >= self.args.count:
736*387f9dfdSAndroid Build Coastguard Worker                                exit()
737*387f9dfdSAndroid Build Coastguard Worker                        if self.args.duration and \
738*387f9dfdSAndroid Build Coastguard Worker                           seconds >= self.args.duration:
739*387f9dfdSAndroid Build Coastguard Worker                                exit()
740*387f9dfdSAndroid Build Coastguard Worker
741*387f9dfdSAndroid Build Coastguard Worker        def run(self):
742*387f9dfdSAndroid Build Coastguard Worker                try:
743*387f9dfdSAndroid Build Coastguard Worker                        self._create_probes()
744*387f9dfdSAndroid Build Coastguard Worker                        self._generate_program()
745*387f9dfdSAndroid Build Coastguard Worker                        self._attach()
746*387f9dfdSAndroid Build Coastguard Worker                        self._main_loop()
747*387f9dfdSAndroid Build Coastguard Worker                except:
748*387f9dfdSAndroid Build Coastguard Worker                        exc_info = sys.exc_info()
749*387f9dfdSAndroid Build Coastguard Worker                        sys_exit = exc_info[0] is SystemExit
750*387f9dfdSAndroid Build Coastguard Worker                        if self.args.verbose:
751*387f9dfdSAndroid Build Coastguard Worker                                traceback.print_exc()
752*387f9dfdSAndroid Build Coastguard Worker                        elif not sys_exit:
753*387f9dfdSAndroid Build Coastguard Worker                                print(exc_info[1])
754*387f9dfdSAndroid Build Coastguard Worker                        exit(0 if sys_exit else 1)
755*387f9dfdSAndroid Build Coastguard Worker
756*387f9dfdSAndroid Build Coastguard Workerif __name__ == "__main__":
757*387f9dfdSAndroid Build Coastguard Worker        Tool().run()
758