106 lines
3.0 KiB
Python
Executable File
106 lines
3.0 KiB
Python
Executable File
#!/usr/bin/python
|
|
#
|
|
# An example usage of stack_build_id
|
|
# Most of the code here is borrowed from tools/profile.py
|
|
#
|
|
# Steps for using this code
|
|
# 1) Start ping program in one terminal eg invocation: ping google.com -i0.001
|
|
# 2) Change the path of libc specified in b.add_module() below
|
|
# 3) Invoke the script as 'python stack_buildid_example.py'
|
|
# 4) o/p of the tool is as shown below
|
|
# python example/tracing/stack_buildid_example.py
|
|
# sendto
|
|
# - ping (5232)
|
|
# 2
|
|
#
|
|
# REQUIRES: Linux 4.17+ (BPF_BUILD_ID support)
|
|
# Licensed under the Apache License, Version 2.0 (the "License")
|
|
# 03-Jan-2019 Vijay Nag
|
|
|
|
from __future__ import print_function
|
|
from bcc import BPF, PerfType, PerfSWConfig
|
|
from sys import stderr
|
|
from time import sleep
|
|
import argparse
|
|
import signal
|
|
import os
|
|
import subprocess
|
|
import errno
|
|
import multiprocessing
|
|
import ctypes as ct
|
|
|
|
def Get_libc_path():
|
|
# A small helper function that returns full path
|
|
# of libc in the system
|
|
cmd = 'cat /proc/self/maps | grep libc | awk \'{print $6}\' | uniq'
|
|
output = subprocess.check_output(cmd, shell=True)
|
|
if not isinstance(output, str):
|
|
output = output.decode()
|
|
return output.split('\n')[0]
|
|
|
|
bpf_text = """
|
|
#include <uapi/linux/ptrace.h>
|
|
#include <uapi/linux/bpf_perf_event.h>
|
|
#include <linux/sched.h>
|
|
|
|
struct key_t {
|
|
u32 pid;
|
|
int user_stack_id;
|
|
char name[TASK_COMM_LEN];
|
|
};
|
|
BPF_HASH(counts, struct key_t);
|
|
BPF_STACK_TRACE_BUILDID(stack_traces, 128);
|
|
|
|
int do_perf_event(struct bpf_perf_event_data *ctx) {
|
|
u32 pid = bpf_get_current_pid_tgid() >> 32;
|
|
|
|
// create map key
|
|
struct key_t key = {.pid = pid};
|
|
bpf_get_current_comm(&key.name, sizeof(key.name));
|
|
|
|
key.user_stack_id = stack_traces.get_stackid(&ctx->regs, BPF_F_USER_STACK);
|
|
|
|
if (key.user_stack_id >= 0) {
|
|
counts.increment(key);
|
|
}
|
|
return 0;
|
|
}
|
|
"""
|
|
|
|
b = BPF(text=bpf_text)
|
|
b.attach_perf_event(ev_type=PerfType.SOFTWARE,
|
|
ev_config=PerfSWConfig.CPU_CLOCK, fn_name="do_perf_event",
|
|
sample_period=0, sample_freq=49, cpu=0)
|
|
|
|
# Add the list of libraries/executables to the build sym cache for sym resolution
|
|
# Change the libc path if it is different on a different machine.
|
|
# libc.so and ping are added here so that any symbols pertaining to
|
|
# libc or ping are resolved. More executables/libraries can be added here.
|
|
b.add_module(Get_libc_path())
|
|
b.add_module("/usr/sbin/sshd")
|
|
b.add_module("/bin/ping")
|
|
counts = b.get_table("counts")
|
|
stack_traces = b.get_table("stack_traces")
|
|
duration = 2
|
|
|
|
def signal_handler(signal, frame):
|
|
print()
|
|
|
|
try:
|
|
sleep(duration)
|
|
except KeyboardInterrupt:
|
|
# as cleanup can take some time, trap Ctrl-C:
|
|
signal.signal(signal.SIGINT, signal.SIG_IGN)
|
|
|
|
user_stack=[]
|
|
for k,v in sorted(counts.items(), key=lambda counts: counts[1].value):
|
|
user_stack = [] if k.user_stack_id < 0 else \
|
|
stack_traces.walk(k.user_stack_id)
|
|
|
|
user_stack=list(user_stack)
|
|
for addr in user_stack:
|
|
print(" %s" % b.sym(addr, k.pid).decode('utf-8', 'replace'))
|
|
print(" %-16s %s (%d)" % ("-", k.name.decode('utf-8', 'replace'), k.pid))
|
|
print(" %d\n" % v.value)
|
|
|