blob: cdc3c42bec5ea511ad789194f798c76ca84f0f31 [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#
8# The current implementation uses an unrolled loop for x86_64, and was written
9# as a proof of concept. This implementation should be replaced in the future
10# with an appropriate bpf_ call, when available.
11#
12# The stack depth is limited to 10 (+1 for the current instruction pointer).
13# This could be tunable in a future version.
14#
15# Copyright 2016 Netflix, Inc.
16# Licensed under the Apache License, Version 2.0 (the "License")
17#
18# 12-Jan-2016 Brendan Gregg Created this.
19
20from __future__ import print_function
21from bcc import BPF
22import argparse
Vicent Marti592414e2016-03-27 18:22:03 +020023import re
Brendan Gregg38cef482016-01-15 17:26:30 -080024
25# arguments
26examples = """examples:
27 ./stacksnoop ext4_sync_fs # print kernel stack traces for ext4_sync_fs
28 ./stacksnoop -s ext4_sync_fs # ... also show symbol offsets
29 ./stacksnoop -v ext4_sync_fs # ... show extra columns
30 ./stacksnoop -p 185 ext4_sync_fs # ... only when PID 185 is on-CPU
31"""
32parser = argparse.ArgumentParser(
33 description="Trace and print kernel stack traces for a kernel function",
34 formatter_class=argparse.RawDescriptionHelpFormatter,
35 epilog=examples)
36parser.add_argument("-p", "--pid",
37 help="trace this PID only")
38parser.add_argument("-s", "--offset", action="store_true",
39 help="show address offsets")
40parser.add_argument("-v", "--verbose", action="store_true",
41 help="print more fields")
42parser.add_argument("function",
43 help="kernel function name")
44args = parser.parse_args()
45function = args.function
46offset = args.offset
47verbose = args.verbose
48debug = 0
49
50# define BPF program
51bpf_text = """
52#include <uapi/linux/ptrace.h>
53
Vicent Marti592414e2016-03-27 18:22:03 +020054BPF_STACK_TRACE(stack_traces, 128)
Brendan Gregg38cef482016-01-15 17:26:30 -080055
56void trace_stack(struct pt_regs *ctx) {
57 FILTER
Vicent Marti592414e2016-03-27 18:22:03 +020058 int stack_id = stack_traces.get_stackid(ctx, BPF_F_REUSE_STACKID);
59 if (stack_id >= 0)
60 bpf_trace_printk("stack_id=%d\\n", stack_id);
61}
Brendan Gregg38cef482016-01-15 17:26:30 -080062"""
63if args.pid:
64 bpf_text = bpf_text.replace('FILTER',
65 ('u32 pid; pid = bpf_get_current_pid_tgid(); ' +
Mark Draytonab133d22016-03-04 00:51:20 -080066 'if (pid != %s) { return; }') % (args.pid))
Brendan Gregg38cef482016-01-15 17:26:30 -080067else:
68 bpf_text = bpf_text.replace('FILTER', '')
69if debug:
70 print(bpf_text)
71
72# initialize BPF
73b = BPF(text=bpf_text)
74b.attach_kprobe(event=function, fn_name="trace_stack")
75matched = b.num_open_kprobes()
76if matched == 0:
77 print("Function \"%s\" not found. Exiting." % function)
78 exit()
79
Vicent Marti592414e2016-03-27 18:22:03 +020080stack_traces = b.get_table("stack_traces")
81msg_regexp = re.compile("stack_id=(\d+)")
82
Brendan Gregg38cef482016-01-15 17:26:30 -080083# header
84if verbose:
Vicent Marti592414e2016-03-27 18:22:03 +020085 print("%-18s %-12s %-6s %-3s %s" % ("TIME(s)", "COMM", "PID", "CPU", "SYSCALL"))
Brendan Gregg38cef482016-01-15 17:26:30 -080086else:
Vicent Marti592414e2016-03-27 18:22:03 +020087 print("%-18s %s" % ("TIME(s)", "SYSCALL"))
Brendan Gregg38cef482016-01-15 17:26:30 -080088
89# format output
90while 1:
91 (task, pid, cpu, flags, ts, msg) = b.trace_fields()
Vicent Marti592414e2016-03-27 18:22:03 +020092 m = msg_regexp.match(msg)
93 if m:
94 if verbose:
95 print("%-18.9f %-12.12s %-6d %-3d %s" % (ts, task, pid, cpu, function))
Brendan Gregg38cef482016-01-15 17:26:30 -080096 else:
Vicent Marti592414e2016-03-27 18:22:03 +020097 print("%-18.9f %s" % (ts, function))
98
99 stack_id = int(m.group(1))
100 for addr in stack_traces.walk(stack_id):
101 sym = b.ksymaddr(addr) if offset else b.ksym(addr)
102 print("\t%016x %s" % (addr, sym))
103
104 print()