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