1*387f9dfdSAndroid Build Coastguard Worker#!/usr/bin/python 2*387f9dfdSAndroid Build Coastguard Worker# 3*387f9dfdSAndroid Build Coastguard Worker# stacksnoop Trace a kernel function and print all kernel stack traces. 4*387f9dfdSAndroid Build Coastguard Worker# For Linux, uses BCC, eBPF, and currently x86_64 only. Inline C. 5*387f9dfdSAndroid Build Coastguard Worker# 6*387f9dfdSAndroid Build Coastguard Worker# USAGE: stacksnoop [-h] [-p PID] [-s] [-v] function 7*387f9dfdSAndroid Build Coastguard Worker# 8*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc. 9*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 10*387f9dfdSAndroid Build Coastguard Worker# 11*387f9dfdSAndroid Build Coastguard Worker# 12-Jan-2016 Brendan Gregg Created this. 12*387f9dfdSAndroid Build Coastguard Worker 13*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 14*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 15*387f9dfdSAndroid Build Coastguard Workerimport argparse 16*387f9dfdSAndroid Build Coastguard Workerimport time 17*387f9dfdSAndroid Build Coastguard Worker 18*387f9dfdSAndroid Build Coastguard Worker# arguments 19*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 20*387f9dfdSAndroid Build Coastguard Worker ./stacksnoop ext4_sync_fs # print kernel stack traces for ext4_sync_fs 21*387f9dfdSAndroid Build Coastguard Worker ./stacksnoop -s ext4_sync_fs # ... also show symbol offsets 22*387f9dfdSAndroid Build Coastguard Worker ./stacksnoop -v ext4_sync_fs # ... show extra columns 23*387f9dfdSAndroid Build Coastguard Worker ./stacksnoop -p 185 ext4_sync_fs # ... only when PID 185 is on-CPU 24*387f9dfdSAndroid Build Coastguard Worker""" 25*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 26*387f9dfdSAndroid Build Coastguard Worker description="Trace and print kernel stack traces for a kernel function", 27*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 28*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 29*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", 30*387f9dfdSAndroid Build Coastguard Worker help="trace this PID only") 31*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-s", "--offset", action="store_true", 32*387f9dfdSAndroid Build Coastguard Worker help="show address offsets") 33*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-v", "--verbose", action="store_true", 34*387f9dfdSAndroid Build Coastguard Worker help="print more fields") 35*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("function", 36*387f9dfdSAndroid Build Coastguard Worker help="kernel function name") 37*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 38*387f9dfdSAndroid Build Coastguard Workerfunction = args.function 39*387f9dfdSAndroid Build Coastguard Workeroffset = args.offset 40*387f9dfdSAndroid Build Coastguard Workerverbose = args.verbose 41*387f9dfdSAndroid Build Coastguard Workerdebug = 0 42*387f9dfdSAndroid Build Coastguard Worker 43*387f9dfdSAndroid Build Coastguard Worker# define BPF program 44*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 45*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 46*387f9dfdSAndroid Build Coastguard Worker#include <linux/sched.h> 47*387f9dfdSAndroid Build Coastguard Worker 48*387f9dfdSAndroid Build Coastguard Workerstruct data_t { 49*387f9dfdSAndroid Build Coastguard Worker u64 stack_id; 50*387f9dfdSAndroid Build Coastguard Worker u32 pid; 51*387f9dfdSAndroid Build Coastguard Worker char comm[TASK_COMM_LEN]; 52*387f9dfdSAndroid Build Coastguard Worker}; 53*387f9dfdSAndroid Build Coastguard Worker 54*387f9dfdSAndroid Build Coastguard WorkerBPF_STACK_TRACE(stack_traces, 128); 55*387f9dfdSAndroid Build Coastguard WorkerBPF_PERF_OUTPUT(events); 56*387f9dfdSAndroid Build Coastguard Worker 57*387f9dfdSAndroid Build Coastguard Workervoid trace_stack(struct pt_regs *ctx) { 58*387f9dfdSAndroid Build Coastguard Worker u32 pid = bpf_get_current_pid_tgid() >> 32; 59*387f9dfdSAndroid Build Coastguard Worker FILTER 60*387f9dfdSAndroid Build Coastguard Worker struct data_t data = {}; 61*387f9dfdSAndroid Build Coastguard Worker data.stack_id = stack_traces.get_stackid(ctx, 0), 62*387f9dfdSAndroid Build Coastguard Worker data.pid = pid; 63*387f9dfdSAndroid Build Coastguard Worker bpf_get_current_comm(&data.comm, sizeof(data.comm)); 64*387f9dfdSAndroid Build Coastguard Worker events.perf_submit(ctx, &data, sizeof(data)); 65*387f9dfdSAndroid Build Coastguard Worker} 66*387f9dfdSAndroid Build Coastguard Worker""" 67*387f9dfdSAndroid Build Coastguard Workerif args.pid: 68*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER', 69*387f9dfdSAndroid Build Coastguard Worker 'if (pid != %s) { return; }' % args.pid) 70*387f9dfdSAndroid Build Coastguard Workerelse: 71*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER', '') 72*387f9dfdSAndroid Build Coastguard Workerif debug: 73*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 74*387f9dfdSAndroid Build Coastguard Worker 75*387f9dfdSAndroid Build Coastguard Worker# initialize BPF 76*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 77*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event=function, fn_name="trace_stack") 78*387f9dfdSAndroid Build Coastguard Worker 79*387f9dfdSAndroid Build Coastguard WorkerTASK_COMM_LEN = 16 # linux/sched.h 80*387f9dfdSAndroid Build Coastguard Worker 81*387f9dfdSAndroid Build Coastguard Workermatched = b.num_open_kprobes() 82*387f9dfdSAndroid Build Coastguard Workerif matched == 0: 83*387f9dfdSAndroid Build Coastguard Worker print("Function \"%s\" not found. Exiting." % function) 84*387f9dfdSAndroid Build Coastguard Worker exit() 85*387f9dfdSAndroid Build Coastguard Worker 86*387f9dfdSAndroid Build Coastguard Workerstack_traces = b.get_table("stack_traces") 87*387f9dfdSAndroid Build Coastguard Workerstart_ts = time.time() 88*387f9dfdSAndroid Build Coastguard Worker 89*387f9dfdSAndroid Build Coastguard Worker# header 90*387f9dfdSAndroid Build Coastguard Workerif verbose: 91*387f9dfdSAndroid Build Coastguard Worker print("%-18s %-12s %-6s %-3s %s" % 92*387f9dfdSAndroid Build Coastguard Worker ("TIME(s)", "COMM", "PID", "CPU", "FUNCTION")) 93*387f9dfdSAndroid Build Coastguard Workerelse: 94*387f9dfdSAndroid Build Coastguard Worker print("%-18s %s" % ("TIME(s)", "FUNCTION")) 95*387f9dfdSAndroid Build Coastguard Worker 96*387f9dfdSAndroid Build Coastguard Workerdef print_event(cpu, data, size): 97*387f9dfdSAndroid Build Coastguard Worker event = b["events"].event(data) 98*387f9dfdSAndroid Build Coastguard Worker 99*387f9dfdSAndroid Build Coastguard Worker ts = time.time() - start_ts 100*387f9dfdSAndroid Build Coastguard Worker 101*387f9dfdSAndroid Build Coastguard Worker if verbose: 102*387f9dfdSAndroid Build Coastguard Worker print("%-18.9f %-12.12s %-6d %-3d %s" % 103*387f9dfdSAndroid Build Coastguard Worker (ts, event.comm.decode('utf-8', 'replace'), event.pid, cpu, function)) 104*387f9dfdSAndroid Build Coastguard Worker else: 105*387f9dfdSAndroid Build Coastguard Worker print("%-18.9f %s" % (ts, function)) 106*387f9dfdSAndroid Build Coastguard Worker 107*387f9dfdSAndroid Build Coastguard Worker for addr in stack_traces.walk(event.stack_id): 108*387f9dfdSAndroid Build Coastguard Worker sym = b.ksym(addr, show_offset=offset).decode('utf-8', 'replace') 109*387f9dfdSAndroid Build Coastguard Worker print("\t%s" % sym) 110*387f9dfdSAndroid Build Coastguard Worker 111*387f9dfdSAndroid Build Coastguard Worker print() 112*387f9dfdSAndroid Build Coastguard Worker 113*387f9dfdSAndroid Build Coastguard Workerb["events"].open_perf_buffer(print_event) 114*387f9dfdSAndroid Build Coastguard Workerwhile 1: 115*387f9dfdSAndroid Build Coastguard Worker try: 116*387f9dfdSAndroid Build Coastguard Worker b.perf_buffer_poll() 117*387f9dfdSAndroid Build Coastguard Worker except KeyboardInterrupt: 118*387f9dfdSAndroid Build Coastguard Worker exit() 119