xref: /aosp_15_r20/external/bcc/examples/tracing/stack_buildid_example.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1#!/usr/bin/python
2#
3# An example usage of stack_build_id
4# Most of the code here is borrowed from tools/profile.py
5#
6# Steps for using this code
7# 1) Start ping program in one terminal eg invocation: ping google.com -i0.001
8# 2) Change the path of libc specified in b.add_module() below
9# 3) Invoke the script as 'python stack_buildid_example.py'
10# 4) o/p of the tool is as shown below
11#  python example/tracing/stack_buildid_example.py
12#    sendto
13#    -                ping (5232)
14#        2
15#
16# REQUIRES: Linux 4.17+ (BPF_BUILD_ID support)
17# Licensed under the Apache License, Version 2.0 (the "License")
18# 03-Jan-2019  Vijay Nag
19
20from __future__ import print_function
21from bcc import BPF, PerfType, PerfSWConfig
22from sys import stderr
23from time import sleep
24import argparse
25import signal
26import os
27import subprocess
28import errno
29import multiprocessing
30import ctypes as ct
31
32def Get_libc_path():
33  # A small helper function that returns full path
34  # of libc in the system
35  cmd = 'cat /proc/self/maps | grep libc | awk \'{print $6}\' | uniq'
36  output = subprocess.check_output(cmd, shell=True)
37  if not isinstance(output, str):
38    output = output.decode()
39  return output.split('\n')[0]
40
41bpf_text = """
42#include <uapi/linux/ptrace.h>
43#include <uapi/linux/bpf_perf_event.h>
44#include <linux/sched.h>
45
46struct key_t {
47    u32 pid;
48    int user_stack_id;
49    char name[TASK_COMM_LEN];
50};
51BPF_HASH(counts, struct key_t);
52BPF_STACK_TRACE_BUILDID(stack_traces, 128);
53
54int do_perf_event(struct bpf_perf_event_data *ctx) {
55    u32 pid = bpf_get_current_pid_tgid() >> 32;
56
57    // create map key
58    struct key_t key = {.pid = pid};
59    bpf_get_current_comm(&key.name, sizeof(key.name));
60
61    key.user_stack_id = stack_traces.get_stackid(&ctx->regs, BPF_F_USER_STACK);
62
63    if (key.user_stack_id >= 0) {
64      counts.increment(key);
65    }
66    return 0;
67}
68"""
69
70b = BPF(text=bpf_text)
71b.attach_perf_event(ev_type=PerfType.SOFTWARE,
72    ev_config=PerfSWConfig.CPU_CLOCK, fn_name="do_perf_event",
73    sample_period=0, sample_freq=49, cpu=0)
74
75# Add the list of libraries/executables to the build sym cache for sym resolution
76# Change the libc path if it is different on a different machine.
77# libc.so and ping are added here so that any symbols pertaining to
78# libc or ping are resolved. More executables/libraries can be added here.
79b.add_module(Get_libc_path())
80b.add_module("/usr/sbin/sshd")
81b.add_module("/bin/ping")
82counts = b.get_table("counts")
83stack_traces = b.get_table("stack_traces")
84duration = 2
85
86def signal_handler(signal, frame):
87  print()
88
89try:
90    sleep(duration)
91except KeyboardInterrupt:
92    # as cleanup can take some time, trap Ctrl-C:
93    signal.signal(signal.SIGINT, signal.SIG_IGN)
94
95user_stack=[]
96for k,v in sorted(counts.items(), key=lambda counts: counts[1].value):
97  user_stack = [] if k.user_stack_id < 0 else \
98      stack_traces.walk(k.user_stack_id)
99
100  user_stack=list(user_stack)
101  for addr in user_stack:
102    print("    %s" % b.sym(addr, k.pid).decode('utf-8', 'replace'))
103  print("    %-16s %s (%d)" % ("-", k.name.decode('utf-8', 'replace'), k.pid))
104  print("        %d\n" % v.value)
105
106