1#!/usr/bin/env python
2#
3# tplist    Display kernel tracepoints or USDT probes and their formats.
4#
5# USAGE:    tplist [-p PID] [-l LIB] [-v] [filter]
6#
7# Licensed under the Apache License, Version 2.0 (the "License")
8# Copyright (C) 2016 Sasha Goldshtein.
9
10import argparse
11import fnmatch
12import os
13import re
14import sys
15
16from bcc import USDT
17
18trace_root = "/sys/kernel/debug/tracing"
19event_root = os.path.join(trace_root, "events")
20
21parser = argparse.ArgumentParser(
22        description="Display kernel tracepoints or USDT probes " +
23                    "and their formats.",
24        formatter_class=argparse.RawDescriptionHelpFormatter)
25parser.add_argument("-p", "--pid", type=int, default=None,
26        help="List USDT probes in the specified process")
27parser.add_argument("-l", "--lib", default="",
28        help="List USDT probes in the specified library or executable")
29parser.add_argument("-v", dest="verbosity", action="count", default=0,
30        help="Increase verbosity level (print variables, arguments, etc.)")
31parser.add_argument(dest="filter", nargs="?",
32        help="A filter that specifies which probes/tracepoints to print")
33args = parser.parse_args()
34
35def print_tpoint_format(category, event):
36        fmt = open(os.path.join(event_root, category, event, "format")) \
37              .readlines()
38        for line in fmt:
39                match = re.search(r'field:([^;]*);', line)
40                if match is None:
41                        continue
42                parts = match.group(1).split()
43                field_name = parts[-1:][0]
44                field_type = " ".join(parts[:-1])
45                if field_name.startswith("common_"):
46                        continue
47                print("    %s %s;" % (field_type, field_name))
48
49def print_tpoint(category, event):
50        tpoint = "%s:%s" % (category, event)
51        if not args.filter or fnmatch.fnmatch(tpoint, args.filter):
52                print(tpoint)
53                if args.verbosity > 0:
54                        print_tpoint_format(category, event)
55
56def print_tracepoints():
57        for category in os.listdir(event_root):
58                cat_dir = os.path.join(event_root, category)
59                if not os.path.isdir(cat_dir):
60                        continue
61                for event in os.listdir(cat_dir):
62                        evt_dir = os.path.join(cat_dir, event)
63                        if os.path.isdir(evt_dir):
64                                print_tpoint(category, event)
65
66def print_usdt_argument_details(location):
67        for idx in range(0, location.num_arguments):
68                arg = location.get_argument(idx)
69                print("    argument #%d %s" % (idx + 1, arg))
70
71def print_usdt_details(probe):
72        if args.verbosity > 0:
73                print(probe)
74                if args.verbosity > 1:
75                        for idx in range(0, probe.num_locations):
76                                loc = probe.get_location(idx)
77                                print("  location #%d %s" % (idx + 1, loc))
78                                print_usdt_argument_details(loc)
79                else:
80                        print("  %d location(s)" % probe.num_locations)
81                        print("  %d argument(s)" % probe.num_arguments)
82        else:
83                print("%s %s:%s" %
84                      (probe.bin_path, probe.provider, probe.name))
85
86def print_usdt(pid, lib):
87        reader = USDT(path=lib, pid=pid)
88        probes_seen = []
89        for probe in reader.enumerate_probes():
90                probe_name = probe.short_name()
91                if not args.filter or fnmatch.fnmatch(probe_name, args.filter):
92                        if probe_name in probes_seen:
93                                continue
94                        probes_seen.append(probe_name)
95                        print_usdt_details(probe)
96
97if __name__ == "__main__":
98        try:
99                if args.pid or args.lib != "":
100                        print_usdt(args.pid, args.lib)
101                else:
102                        print_tracepoints()
103        except:
104                if sys.exc_info()[0] is not SystemExit:
105                        print(sys.exc_info()[1])
106