xref: /qemu/scripts/qemu-trace-stap (revision 62dd1048c0bd628d5811d22cbfbdbf7053b2c5bf)
1*62dd1048SDaniel P. Berrangé#!/usr/bin/python
2*62dd1048SDaniel P. Berrangé# -*- python -*-
3*62dd1048SDaniel P. Berrangé#
4*62dd1048SDaniel P. Berrangé# Copyright (C) 2019 Red Hat, Inc
5*62dd1048SDaniel P. Berrangé#
6*62dd1048SDaniel P. Berrangé# QEMU SystemTap Trace Tool
7*62dd1048SDaniel P. Berrangé#
8*62dd1048SDaniel P. Berrangé# This program is free software; you can redistribute it and/or modify
9*62dd1048SDaniel P. Berrangé# it under the terms of the GNU General Public License as published by
10*62dd1048SDaniel P. Berrangé# the Free Software Foundation; either version 2 of the License, or
11*62dd1048SDaniel P. Berrangé# (at your option) any later version.
12*62dd1048SDaniel P. Berrangé#
13*62dd1048SDaniel P. Berrangé# This program is distributed in the hope that it will be useful,
14*62dd1048SDaniel P. Berrangé# but WITHOUT ANY WARRANTY; without even the implied warranty of
15*62dd1048SDaniel P. Berrangé# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*62dd1048SDaniel P. Berrangé# GNU General Public License for more details.
17*62dd1048SDaniel P. Berrangé#
18*62dd1048SDaniel P. Berrangé# You should have received a copy of the GNU General Public License
19*62dd1048SDaniel P. Berrangé# along with this program; if not, see <http://www.gnu.org/licenses/>.
20*62dd1048SDaniel P. Berrangé
21*62dd1048SDaniel P. Berrangéfrom __future__ import print_function
22*62dd1048SDaniel P. Berrangé
23*62dd1048SDaniel P. Berrangéimport argparse
24*62dd1048SDaniel P. Berrangéimport copy
25*62dd1048SDaniel P. Berrangéimport os.path
26*62dd1048SDaniel P. Berrangéimport re
27*62dd1048SDaniel P. Berrangéimport subprocess
28*62dd1048SDaniel P. Berrangéimport sys
29*62dd1048SDaniel P. Berrangé
30*62dd1048SDaniel P. Berrangé
31*62dd1048SDaniel P. Berrangédef probe_prefix(binary):
32*62dd1048SDaniel P. Berrangé    dirname, filename = os.path.split(binary)
33*62dd1048SDaniel P. Berrangé    return re.sub("-", ".", filename) + ".log"
34*62dd1048SDaniel P. Berrangé
35*62dd1048SDaniel P. Berrangé
36*62dd1048SDaniel P. Berrangédef which(binary):
37*62dd1048SDaniel P. Berrangé    for path in os.environ["PATH"].split(os.pathsep):
38*62dd1048SDaniel P. Berrangé        if os.path.exists(os.path.join(path, binary)):
39*62dd1048SDaniel P. Berrangé                return os.path.join(path, binary)
40*62dd1048SDaniel P. Berrangé
41*62dd1048SDaniel P. Berrangé    print("Unable to find '%s' in $PATH" % binary)
42*62dd1048SDaniel P. Berrangé    sys.exit(1)
43*62dd1048SDaniel P. Berrangé
44*62dd1048SDaniel P. Berrangé
45*62dd1048SDaniel P. Berrangédef tapset_dir(binary):
46*62dd1048SDaniel P. Berrangé    dirname, filename = os.path.split(binary)
47*62dd1048SDaniel P. Berrangé    if dirname == '':
48*62dd1048SDaniel P. Berrangé        thisfile = which(binary)
49*62dd1048SDaniel P. Berrangé    else:
50*62dd1048SDaniel P. Berrangé        thisfile = os.path.realpath(binary)
51*62dd1048SDaniel P. Berrangé        if not os.path.exists(thisfile):
52*62dd1048SDaniel P. Berrangé            print("Unable to find '%s'" % thisfile)
53*62dd1048SDaniel P. Berrangé            sys.exit(1)
54*62dd1048SDaniel P. Berrangé
55*62dd1048SDaniel P. Berrangé    basedir = os.path.split(thisfile)[0]
56*62dd1048SDaniel P. Berrangé    tapset = os.path.join(basedir, "..", "share", "systemtap", "tapset")
57*62dd1048SDaniel P. Berrangé    return os.path.realpath(tapset)
58*62dd1048SDaniel P. Berrangé
59*62dd1048SDaniel P. Berrangé
60*62dd1048SDaniel P. Berrangédef tapset_env(tapset_dir):
61*62dd1048SDaniel P. Berrangé    tenv = copy.copy(os.environ)
62*62dd1048SDaniel P. Berrangé    tenv["SYSTEMTAP_TAPSET"] = tapset_dir
63*62dd1048SDaniel P. Berrangé    return tenv
64*62dd1048SDaniel P. Berrangé
65*62dd1048SDaniel P. Berrangédef cmd_run(args):
66*62dd1048SDaniel P. Berrangé    prefix = probe_prefix(args.binary)
67*62dd1048SDaniel P. Berrangé    tapsets = tapset_dir(args.binary)
68*62dd1048SDaniel P. Berrangé
69*62dd1048SDaniel P. Berrangé    if args.verbose:
70*62dd1048SDaniel P. Berrangé        print("Using tapset dir '%s' for binary '%s'" % (tapsets, args.binary))
71*62dd1048SDaniel P. Berrangé
72*62dd1048SDaniel P. Berrangé    probes = []
73*62dd1048SDaniel P. Berrangé    for probe in args.probes:
74*62dd1048SDaniel P. Berrangé        probes.append("probe %s.%s {}" % (prefix, probe))
75*62dd1048SDaniel P. Berrangé    if len(probes) == 0:
76*62dd1048SDaniel P. Berrangé        print("At least one probe pattern must be specified")
77*62dd1048SDaniel P. Berrangé        sys.exit(1)
78*62dd1048SDaniel P. Berrangé
79*62dd1048SDaniel P. Berrangé    script = " ".join(probes)
80*62dd1048SDaniel P. Berrangé    if args.verbose:
81*62dd1048SDaniel P. Berrangé        print("Compiling script '%s'" % script)
82*62dd1048SDaniel P. Berrangé        script = """probe begin { print("Running script, <Ctrl>-c to quit\\n") } """ + script
83*62dd1048SDaniel P. Berrangé
84*62dd1048SDaniel P. Berrangé    # We request an 8MB buffer, since the stap default 1MB buffer
85*62dd1048SDaniel P. Berrangé    # can be easily overflowed by frequently firing QEMU traces
86*62dd1048SDaniel P. Berrangé    stapargs = ["stap", "-s", "8"]
87*62dd1048SDaniel P. Berrangé    if args.pid is not None:
88*62dd1048SDaniel P. Berrangé        stapargs.extend(["-x", args.pid])
89*62dd1048SDaniel P. Berrangé    stapargs.extend(["-e", script])
90*62dd1048SDaniel P. Berrangé    subprocess.call(stapargs, env=tapset_env(tapsets))
91*62dd1048SDaniel P. Berrangé
92*62dd1048SDaniel P. Berrangé
93*62dd1048SDaniel P. Berrangédef cmd_list(args):
94*62dd1048SDaniel P. Berrangé    tapsets = tapset_dir(args.binary)
95*62dd1048SDaniel P. Berrangé
96*62dd1048SDaniel P. Berrangé    if args.verbose:
97*62dd1048SDaniel P. Berrangé        print("Using tapset dir '%s' for binary '%s'" % (tapsets, args.binary))
98*62dd1048SDaniel P. Berrangé
99*62dd1048SDaniel P. Berrangé    def print_probes(verbose, name):
100*62dd1048SDaniel P. Berrangé        prefix = probe_prefix(args.binary)
101*62dd1048SDaniel P. Berrangé        offset = len(prefix) + 1
102*62dd1048SDaniel P. Berrangé        script = prefix + "." + name
103*62dd1048SDaniel P. Berrangé
104*62dd1048SDaniel P. Berrangé        if verbose:
105*62dd1048SDaniel P. Berrangé            print("Listing probes with name '%s'" % script)
106*62dd1048SDaniel P. Berrangé        proc = subprocess.Popen(["stap", "-l", script],
107*62dd1048SDaniel P. Berrangé                                stdout=subprocess.PIPE, env=tapset_env(tapsets))
108*62dd1048SDaniel P. Berrangé        out, err = proc.communicate()
109*62dd1048SDaniel P. Berrangé        if proc.returncode != 0:
110*62dd1048SDaniel P. Berrangé            print("No probes found, are the tapsets installed in %s" % tapset_dir(args.binary))
111*62dd1048SDaniel P. Berrangé            sys.exit(1)
112*62dd1048SDaniel P. Berrangé
113*62dd1048SDaniel P. Berrangé        for line in out.splitlines():
114*62dd1048SDaniel P. Berrangé            if line.startswith(prefix):
115*62dd1048SDaniel P. Berrangé                print("%s" % line[offset:])
116*62dd1048SDaniel P. Berrangé
117*62dd1048SDaniel P. Berrangé    if len(args.probes) == 0:
118*62dd1048SDaniel P. Berrangé        print_probes(args.verbose, "*")
119*62dd1048SDaniel P. Berrangé    else:
120*62dd1048SDaniel P. Berrangé        for probe in args.probes:
121*62dd1048SDaniel P. Berrangé            print_probes(args.verbose, probe)
122*62dd1048SDaniel P. Berrangé
123*62dd1048SDaniel P. Berrangé
124*62dd1048SDaniel P. Berrangédef main():
125*62dd1048SDaniel P. Berrangé    parser = argparse.ArgumentParser(description="QEMU SystemTap trace tool")
126*62dd1048SDaniel P. Berrangé    parser.add_argument("-v", "--verbose", help="Print verbose progress info",
127*62dd1048SDaniel P. Berrangé                        action='store_true')
128*62dd1048SDaniel P. Berrangé
129*62dd1048SDaniel P. Berrangé    subparser = parser.add_subparsers(help="commands")
130*62dd1048SDaniel P. Berrangé    subparser.required = True
131*62dd1048SDaniel P. Berrangé    subparser.dest = "command"
132*62dd1048SDaniel P. Berrangé
133*62dd1048SDaniel P. Berrangé    runparser = subparser.add_parser("run", help="Run a trace session",
134*62dd1048SDaniel P. Berrangé                                     formatter_class=argparse.RawDescriptionHelpFormatter,
135*62dd1048SDaniel P. Berrangé                                     epilog="""
136*62dd1048SDaniel P. Berrangé
137*62dd1048SDaniel P. BerrangéTo watch all trace points on the qemu-system-x86_64 binary:
138*62dd1048SDaniel P. Berrangé
139*62dd1048SDaniel P. Berrangé   %(argv0)s run qemu-system-x86_64
140*62dd1048SDaniel P. Berrangé
141*62dd1048SDaniel P. BerrangéTo only watch the trace points matching the qio* and qcrypto* patterns
142*62dd1048SDaniel P. Berrangé
143*62dd1048SDaniel P. Berrangé   %(argv0)s run qemu-system-x86_64 'qio*' 'qcrypto*'
144*62dd1048SDaniel P. Berrangé""" % {"argv0": sys.argv[0]})
145*62dd1048SDaniel P. Berrangé    runparser.set_defaults(func=cmd_run)
146*62dd1048SDaniel P. Berrangé    runparser.add_argument("--pid", "-p", dest="pid",
147*62dd1048SDaniel P. Berrangé                           help="Restrict tracing to a specific process ID")
148*62dd1048SDaniel P. Berrangé    runparser.add_argument("binary", help="QEMU system or user emulator binary")
149*62dd1048SDaniel P. Berrangé    runparser.add_argument("probes", help="Probe names or wildcards",
150*62dd1048SDaniel P. Berrangé                           nargs=argparse.REMAINDER)
151*62dd1048SDaniel P. Berrangé
152*62dd1048SDaniel P. Berrangé    listparser = subparser.add_parser("list", help="List probe points",
153*62dd1048SDaniel P. Berrangé                                      formatter_class=argparse.RawDescriptionHelpFormatter,
154*62dd1048SDaniel P. Berrangé                                      epilog="""
155*62dd1048SDaniel P. Berrangé
156*62dd1048SDaniel P. BerrangéTo list all trace points on the qemu-system-x86_64 binary:
157*62dd1048SDaniel P. Berrangé
158*62dd1048SDaniel P. Berrangé   %(argv0)s list qemu-system-x86_64
159*62dd1048SDaniel P. Berrangé
160*62dd1048SDaniel P. BerrangéTo only list the trace points matching the qio* and qcrypto* patterns
161*62dd1048SDaniel P. Berrangé
162*62dd1048SDaniel P. Berrangé   %(argv0)s list qemu-system-x86_64 'qio*' 'qcrypto*'
163*62dd1048SDaniel P. Berrangé""" % {"argv0": sys.argv[0]})
164*62dd1048SDaniel P. Berrangé    listparser.set_defaults(func=cmd_list)
165*62dd1048SDaniel P. Berrangé    listparser.add_argument("binary", help="QEMU system or user emulator binary")
166*62dd1048SDaniel P. Berrangé    listparser.add_argument("probes", help="Probe names or wildcards",
167*62dd1048SDaniel P. Berrangé                            nargs=argparse.REMAINDER)
168*62dd1048SDaniel P. Berrangé
169*62dd1048SDaniel P. Berrangé    args = parser.parse_args()
170*62dd1048SDaniel P. Berrangé
171*62dd1048SDaniel P. Berrangé    args.func(args)
172*62dd1048SDaniel P. Berrangé    sys.exit(0)
173*62dd1048SDaniel P. Berrangé
174*62dd1048SDaniel P. Berrangéif __name__ == '__main__':
175*62dd1048SDaniel P. Berrangé    main()
176