Home | History | Annotate | Download | only in tools
      1 #!/usr/bin/python
      2 #
      3 # bpflist   Display processes currently using BPF programs and maps,
      4 #           pinned BPF programs and maps, and enabled probes.
      5 #
      6 # USAGE: bpflist [-v]
      7 #
      8 # Idea by Brendan Gregg.
      9 #
     10 # Copyright 2017, Sasha Goldshtein
     11 # Licensed under the Apache License, Version 2.0
     12 #
     13 # 09-Mar-2017   Sasha Goldshtein   Created this.
     14 
     15 from bcc import BPF, USDT
     16 import argparse
     17 import re
     18 import os
     19 import subprocess
     20 
     21 examples = """examples:
     22     bpflist     # display all processes currently using BPF
     23     bpflist -v  # also count kprobes/uprobes
     24     bpflist -vv # display kprobes/uprobes and count them
     25 """
     26 parser = argparse.ArgumentParser(
     27     description="Display processes currently using BPF programs and maps",
     28     formatter_class=argparse.RawDescriptionHelpFormatter,
     29     epilog=examples)
     30 parser.add_argument("-v", "--verbosity", action="count", default=0,
     31     help="count and display kprobes/uprobes as well")
     32 args = parser.parse_args()
     33 
     34 def comm_for_pid(pid):
     35     try:
     36         return open("/proc/%d/comm" % pid).read().strip()
     37     except:
     38         return "[unknown]"
     39 
     40 counts = {}
     41 
     42 def parse_probes(typ):
     43     if args.verbosity > 1:
     44         print("open %ss:" % typ)
     45     for probe in open("/sys/kernel/debug/tracing/%s_events" % typ):
     46         # Probes opened by bcc have a specific pattern that includes the pid
     47         # of the requesting process.
     48         match = re.search('_bcc_(\\d+)\\s', probe)
     49         if match:
     50             pid = int(match.group(1))
     51             counts[(pid, typ)] = counts.get((pid, typ), 0) + 1
     52         if args.verbosity > 1:
     53             print(probe.strip())
     54     if args.verbosity > 1:
     55         print("")
     56 
     57 if args.verbosity > 0:
     58     parse_probes("kprobe")
     59     parse_probes("uprobe")
     60 
     61 def find_bpf_fds(pid):
     62     root = '/proc/%d/fd' % pid
     63     for fd in os.listdir(root):
     64         try:
     65             link = os.readlink(os.path.join(root, fd))
     66         except OSError:
     67             continue
     68         match = re.match('.*bpf-(\\w+)', link)
     69         if match:
     70             tup = (pid, match.group(1))
     71             counts[tup] = counts.get(tup, 0) + 1
     72 
     73 for pdir in os.listdir('/proc'):
     74     if re.match('\\d+', pdir):
     75         try:
     76             find_bpf_fds(int(pdir))
     77         except OSError:
     78             continue
     79 print("%-6s %-16s %-8s %s" % ("PID", "COMM", "TYPE", "COUNT"))
     80 for (pid, typ), count in sorted(counts.items(), key=lambda t: t[0][0]):
     81     comm = comm_for_pid(pid)
     82     print("%-6d %-16s %-8s %-4d" % (pid, comm, typ, count))
     83