xref: /aosp_15_r20/external/bcc/examples/tracing/stacksnoop.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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