• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env 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 ctypes as ct
17import time
18
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>
47#include <linux/sched.h>
48
49struct data_t {
50    u64 stack_id;
51    u32 pid;
52    char comm[TASK_COMM_LEN];
53};
54
55BPF_STACK_TRACE(stack_traces, 128);
56BPF_PERF_OUTPUT(events);
57
58void trace_stack(struct pt_regs *ctx) {
59    u32 pid = bpf_get_current_pid_tgid();
60    FILTER
61    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));
66}
67"""
68if args.pid:
69    bpf_text = bpf_text.replace('FILTER',
70        'if (pid != %s) { return; }' % args.pid)
71else:
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")
79
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
89matched = b.num_open_kprobes()
90if matched == 0:
91    print("Function \"%s\" not found. Exiting." % function)
92    exit()
93
94stack_traces = b.get_table("stack_traces")
95start_ts = time.time()
96
97# header
98if verbose:
99    print("%-18s %-12s %-6s %-3s %s" %
100            ("TIME(s)", "COMM", "PID", "CPU", "FUNCTION"))
101else:
102    print("%-18s %s" % ("TIME(s)", "FUNCTION"))
103
104def 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:
110        print("%-18.9f %-12.12s %-6d %-3d %s" %
111              (ts, event.comm.decode(), event.pid, cpu, function))
112    else:
113        print("%-18.9f %s" % (ts, function))
114
115    for addr in stack_traces.walk(event.stack_id):
116        sym = b.ksym(addr, show_offset=offset)
117        print("\t%s" % sym)
118
119    print()
120
121b["events"].open_perf_buffer(print_event)
122while 1:
123    b.perf_buffer_poll()
124