blob: e4bbb5179f08da33d47f4dcd69d98709a7faba15 [file] [log] [blame]
Brendan Gregg38cef482016-01-15 17:26:30 -08001#!/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#
Brendan Gregg38cef482016-01-15 17:26:30 -08008# 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
Mark Drayton266d6f62016-05-24 07:01:01 -070016import ctypes as ct
17import time
Brendan Gregg38cef482016-01-15 17:26:30 -080018
19# arguments
20examples = """examples:
21 ./stacksnoop ext4_sync_fs # print kernel stack traces for ext4_sync_fs
22 ./stacksnoop -s ext4_sync_fs # ... also show symbol offsets
23 ./stacksnoop -v ext4_sync_fs # ... show extra columns
24 ./stacksnoop -p 185 ext4_sync_fs # ... only when PID 185 is on-CPU
25"""
26parser = argparse.ArgumentParser(
27 description="Trace and print kernel stack traces for a kernel function",
28 formatter_class=argparse.RawDescriptionHelpFormatter,
29 epilog=examples)
30parser.add_argument("-p", "--pid",
31 help="trace this PID only")
32parser.add_argument("-s", "--offset", action="store_true",
33 help="show address offsets")
34parser.add_argument("-v", "--verbose", action="store_true",
35 help="print more fields")
36parser.add_argument("function",
37 help="kernel function name")
38args = parser.parse_args()
39function = args.function
40offset = args.offset
41verbose = args.verbose
42debug = 0
43
44# define BPF program
45bpf_text = """
46#include <uapi/linux/ptrace.h>
Mark Drayton266d6f62016-05-24 07:01:01 -070047#include <linux/sched.h>
48
49struct data_t {
50 u64 stack_id;
51 u32 pid;
52 char comm[TASK_COMM_LEN];
53};
Brendan Gregg38cef482016-01-15 17:26:30 -080054
Vicent Marti592414e2016-03-27 18:22:03 +020055BPF_STACK_TRACE(stack_traces, 128)
Mark Drayton266d6f62016-05-24 07:01:01 -070056BPF_PERF_OUTPUT(events);
Brendan Gregg38cef482016-01-15 17:26:30 -080057
58void trace_stack(struct pt_regs *ctx) {
Mark Drayton266d6f62016-05-24 07:01:01 -070059 u32 pid = bpf_get_current_pid_tgid();
Brendan Gregg38cef482016-01-15 17:26:30 -080060 FILTER
Mark Drayton266d6f62016-05-24 07:01:01 -070061 struct data_t data = {};
62 data.stack_id = stack_traces.get_stackid(ctx, BPF_F_REUSE_STACKID),
63 data.pid = pid;
64 bpf_get_current_comm(&data.comm, sizeof(data.comm));
65 events.perf_submit(ctx, &data, sizeof(data));
Vicent Marti592414e2016-03-27 18:22:03 +020066}
Brendan Gregg38cef482016-01-15 17:26:30 -080067"""
68if args.pid:
69 bpf_text = bpf_text.replace('FILTER',
Mark Drayton266d6f62016-05-24 07:01:01 -070070 'if (pid != %s) { return; }' % args.pid)
Brendan Gregg38cef482016-01-15 17:26:30 -080071else:
72 bpf_text = bpf_text.replace('FILTER', '')
73if debug:
74 print(bpf_text)
75
76# initialize BPF
77b = BPF(text=bpf_text)
78b.attach_kprobe(event=function, fn_name="trace_stack")
Mark Drayton266d6f62016-05-24 07:01:01 -070079
80TASK_COMM_LEN = 16 # linux/sched.h
81
82class Data(ct.Structure):
83 _fields_ = [
84 ("stack_id", ct.c_ulonglong),
85 ("pid", ct.c_uint),
86 ("comm", ct.c_char * TASK_COMM_LEN),
87 ]
88
Brendan Gregg38cef482016-01-15 17:26:30 -080089matched = b.num_open_kprobes()
90if matched == 0:
91 print("Function \"%s\" not found. Exiting." % function)
92 exit()
93
Vicent Marti592414e2016-03-27 18:22:03 +020094stack_traces = b.get_table("stack_traces")
Mark Drayton266d6f62016-05-24 07:01:01 -070095start_ts = time.time()
Vicent Marti592414e2016-03-27 18:22:03 +020096
Brendan Gregg38cef482016-01-15 17:26:30 -080097# header
98if verbose:
Mark Drayton266d6f62016-05-24 07:01:01 -070099 print("%-18s %-12s %-6s %-3s %s" %
100 ("TIME(s)", "COMM", "PID", "CPU", "FUNCTION"))
Brendan Gregg38cef482016-01-15 17:26:30 -0800101else:
Mark Drayton266d6f62016-05-24 07:01:01 -0700102 print("%-18s %s" % ("TIME(s)", "FUNCTION"))
Brendan Gregg38cef482016-01-15 17:26:30 -0800103
Mark Drayton266d6f62016-05-24 07:01:01 -0700104def print_event(cpu, data, size):
105 event = ct.cast(data, ct.POINTER(Data)).contents
106
107 ts = time.time() - start_ts
108
109 if verbose:
Sasha Goldshteinf41ae862016-10-19 01:14:30 +0300110 print("%-18.9f %-12.12s %-6d %-3d %s" %
Rafael F78948e42017-03-26 14:54:25 +0200111 (ts, event.comm.decode(), event.pid, cpu, function))
Mark Drayton266d6f62016-05-24 07:01:01 -0700112 else:
113 print("%-18.9f %s" % (ts, function))
114
115 for addr in stack_traces.walk(event.stack_id):
Sasha Goldshtein01553852017-02-09 03:58:09 -0500116 sym = b.ksym(addr, show_offset=offset)
Sasha Goldshtein2bf3ff32017-02-08 23:25:00 -0500117 print("\t%s" % sym)
Mark Drayton266d6f62016-05-24 07:01:01 -0700118
119 print()
120
121b["events"].open_perf_buffer(print_event)
Brendan Gregg38cef482016-01-15 17:26:30 -0800122while 1:
Mark Drayton266d6f62016-05-24 07:01:01 -0700123 b.kprobe_poll()