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# The current implementation uses an unrolled loop for x86_64, and was written 9*387f9dfdSAndroid Build Coastguard Worker# as a proof of concept. This implementation should be replaced in the future 10*387f9dfdSAndroid Build Coastguard Worker# with an appropriate bpf_ call, when available. 11*387f9dfdSAndroid Build Coastguard Worker# 12*387f9dfdSAndroid Build Coastguard Worker# The stack depth is limited to 10 (+1 for the current instruction pointer). 13*387f9dfdSAndroid Build Coastguard Worker# This could be tunable in a future version. 14*387f9dfdSAndroid Build Coastguard Worker# 15*387f9dfdSAndroid Build Coastguard Worker# Copyright 2016 Netflix, Inc. 16*387f9dfdSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License") 17*387f9dfdSAndroid Build Coastguard Worker# 18*387f9dfdSAndroid Build Coastguard Worker# 12-Jan-2016 Brendan Gregg Created this. 19*387f9dfdSAndroid Build Coastguard Worker 20*387f9dfdSAndroid Build Coastguard Workerfrom __future__ import print_function 21*387f9dfdSAndroid Build Coastguard Workerfrom bcc import BPF 22*387f9dfdSAndroid Build Coastguard Workerimport argparse 23*387f9dfdSAndroid Build Coastguard Worker 24*387f9dfdSAndroid Build Coastguard Worker# arguments 25*387f9dfdSAndroid Build Coastguard Workerexamples = """examples: 26*387f9dfdSAndroid Build Coastguard Worker ./stacksnoop ext4_sync_fs # print kernel stack traces for ext4_sync_fs 27*387f9dfdSAndroid Build Coastguard Worker ./stacksnoop -s ext4_sync_fs # ... also show symbol offsets 28*387f9dfdSAndroid Build Coastguard Worker ./stacksnoop -v ext4_sync_fs # ... show extra columns 29*387f9dfdSAndroid Build Coastguard Worker ./stacksnoop -p 185 ext4_sync_fs # ... only when PID 185 is on-CPU 30*387f9dfdSAndroid Build Coastguard Worker""" 31*387f9dfdSAndroid Build Coastguard Workerparser = argparse.ArgumentParser( 32*387f9dfdSAndroid Build Coastguard Worker description="Trace and print kernel stack traces for a kernel function", 33*387f9dfdSAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter, 34*387f9dfdSAndroid Build Coastguard Worker epilog=examples) 35*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-p", "--pid", 36*387f9dfdSAndroid Build Coastguard Worker help="trace this PID only") 37*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-s", "--offset", action="store_true", 38*387f9dfdSAndroid Build Coastguard Worker help="show address offsets") 39*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("-v", "--verbose", action="store_true", 40*387f9dfdSAndroid Build Coastguard Worker help="print more fields") 41*387f9dfdSAndroid Build Coastguard Workerparser.add_argument("function", 42*387f9dfdSAndroid Build Coastguard Worker help="kernel function name") 43*387f9dfdSAndroid Build Coastguard Workerargs = parser.parse_args() 44*387f9dfdSAndroid Build Coastguard Workerfunction = args.function 45*387f9dfdSAndroid Build Coastguard Workeroffset = args.offset 46*387f9dfdSAndroid Build Coastguard Workerverbose = args.verbose 47*387f9dfdSAndroid Build Coastguard Workerdebug = 0 48*387f9dfdSAndroid Build Coastguard Worker 49*387f9dfdSAndroid Build Coastguard Worker# define BPF program 50*387f9dfdSAndroid Build Coastguard Workerbpf_text = """ 51*387f9dfdSAndroid Build Coastguard Worker#include <uapi/linux/ptrace.h> 52*387f9dfdSAndroid Build Coastguard Worker 53*387f9dfdSAndroid Build Coastguard Workerstatic int print_frame(u64 *bp, int *depth) { 54*387f9dfdSAndroid Build Coastguard Worker if (*bp) { 55*387f9dfdSAndroid Build Coastguard Worker // The following stack walker is x86_64 specific 56*387f9dfdSAndroid Build Coastguard Worker u64 ret = 0; 57*387f9dfdSAndroid Build Coastguard Worker if (bpf_probe_read(&ret, sizeof(ret), (void *)(*bp+8))) 58*387f9dfdSAndroid Build Coastguard Worker return 0; 59*387f9dfdSAndroid Build Coastguard Worker if (ret < __START_KERNEL_map) 60*387f9dfdSAndroid Build Coastguard Worker return 0; 61*387f9dfdSAndroid Build Coastguard Worker bpf_trace_printk("r%d: %llx\\n", *depth, ret); 62*387f9dfdSAndroid Build Coastguard Worker if (bpf_probe_read(bp, sizeof(*bp), (void *)*bp)) 63*387f9dfdSAndroid Build Coastguard Worker return 0; 64*387f9dfdSAndroid Build Coastguard Worker *depth += 1; 65*387f9dfdSAndroid Build Coastguard Worker return 1; 66*387f9dfdSAndroid Build Coastguard Worker } 67*387f9dfdSAndroid Build Coastguard Worker return 0; 68*387f9dfdSAndroid Build Coastguard Worker} 69*387f9dfdSAndroid Build Coastguard Worker 70*387f9dfdSAndroid Build Coastguard Workervoid trace_stack(struct pt_regs *ctx) { 71*387f9dfdSAndroid Build Coastguard Worker FILTER 72*387f9dfdSAndroid Build Coastguard Worker u64 bp = 0; 73*387f9dfdSAndroid Build Coastguard Worker int depth = 0; 74*387f9dfdSAndroid Build Coastguard Worker 75*387f9dfdSAndroid Build Coastguard Worker bpf_trace_printk("\\n"); 76*387f9dfdSAndroid Build Coastguard Worker if (ctx->ip) 77*387f9dfdSAndroid Build Coastguard Worker bpf_trace_printk("ip: %llx\\n", ctx->ip); 78*387f9dfdSAndroid Build Coastguard Worker bp = ctx->bp; 79*387f9dfdSAndroid Build Coastguard Worker 80*387f9dfdSAndroid Build Coastguard Worker // unrolled loop, 10 frames deep: 81*387f9dfdSAndroid Build Coastguard Worker if (!print_frame(&bp, &depth)) return; 82*387f9dfdSAndroid Build Coastguard Worker if (!print_frame(&bp, &depth)) return; 83*387f9dfdSAndroid Build Coastguard Worker if (!print_frame(&bp, &depth)) return; 84*387f9dfdSAndroid Build Coastguard Worker if (!print_frame(&bp, &depth)) return; 85*387f9dfdSAndroid Build Coastguard Worker if (!print_frame(&bp, &depth)) return; 86*387f9dfdSAndroid Build Coastguard Worker if (!print_frame(&bp, &depth)) return; 87*387f9dfdSAndroid Build Coastguard Worker if (!print_frame(&bp, &depth)) return; 88*387f9dfdSAndroid Build Coastguard Worker if (!print_frame(&bp, &depth)) return; 89*387f9dfdSAndroid Build Coastguard Worker if (!print_frame(&bp, &depth)) return; 90*387f9dfdSAndroid Build Coastguard Worker if (!print_frame(&bp, &depth)) return; 91*387f9dfdSAndroid Build Coastguard Worker}; 92*387f9dfdSAndroid Build Coastguard Worker""" 93*387f9dfdSAndroid Build Coastguard Workerif args.pid: 94*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER', 95*387f9dfdSAndroid Build Coastguard Worker ('u32 pid; pid = bpf_get_current_pid_tgid(); ' + 96*387f9dfdSAndroid Build Coastguard Worker 'if (pid != %s) { return; }') % (args.pid)) 97*387f9dfdSAndroid Build Coastguard Workerelse: 98*387f9dfdSAndroid Build Coastguard Worker bpf_text = bpf_text.replace('FILTER', '') 99*387f9dfdSAndroid Build Coastguard Workerif debug: 100*387f9dfdSAndroid Build Coastguard Worker print(bpf_text) 101*387f9dfdSAndroid Build Coastguard Worker 102*387f9dfdSAndroid Build Coastguard Worker# initialize BPF 103*387f9dfdSAndroid Build Coastguard Workerb = BPF(text=bpf_text) 104*387f9dfdSAndroid Build Coastguard Workerb.attach_kprobe(event=function, fn_name="trace_stack") 105*387f9dfdSAndroid Build Coastguard Workermatched = b.num_open_kprobes() 106*387f9dfdSAndroid Build Coastguard Workerif matched == 0: 107*387f9dfdSAndroid Build Coastguard Worker print("Function \"%s\" not found. Exiting." % function) 108*387f9dfdSAndroid Build Coastguard Worker exit() 109*387f9dfdSAndroid Build Coastguard Worker 110*387f9dfdSAndroid Build Coastguard Worker# header 111*387f9dfdSAndroid Build Coastguard Workerif verbose: 112*387f9dfdSAndroid Build Coastguard Worker print("%-18s %-12s %-6s %-3s %s" % ("TIME(s)", "COMM", "PID", "CPU", 113*387f9dfdSAndroid Build Coastguard Worker "STACK")) 114*387f9dfdSAndroid Build Coastguard Workerelse: 115*387f9dfdSAndroid Build Coastguard Worker print("%-18s %s" % ("TIME(s)", "STACK")) 116*387f9dfdSAndroid Build Coastguard Worker 117*387f9dfdSAndroid Build Coastguard Worker# format output 118*387f9dfdSAndroid Build Coastguard Workerwhile 1: 119*387f9dfdSAndroid Build Coastguard Worker (task, pid, cpu, flags, ts, msg) = b.trace_fields() 120*387f9dfdSAndroid Build Coastguard Worker if msg != "": 121*387f9dfdSAndroid Build Coastguard Worker (reg, addr) = msg.split(" ") 122*387f9dfdSAndroid Build Coastguard Worker ip = b.ksym(int(addr, 16), show_offset=offset) 123*387f9dfdSAndroid Build Coastguard Worker msg = msg + " " + ip 124*387f9dfdSAndroid Build Coastguard Worker if verbose: 125*387f9dfdSAndroid Build Coastguard Worker print("%-18.9f %-12.12s %-6d %-3d %s" % (ts, task, pid, cpu, msg)) 126*387f9dfdSAndroid Build Coastguard Worker else: 127*387f9dfdSAndroid Build Coastguard Worker print("%-18.9f %s" % (ts, msg)) 128