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