4 # Copyright (C) 2019 Red Hat, Inc
6 # QEMU SystemTap Trace Tool
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, see <http://www.gnu.org/licenses/>.
29 def probe_prefix(binary
):
30 dirname
, filename
= os
.path
.split(binary
)
31 return re
.sub("-", ".", filename
) + ".log"
35 for path
in os
.environ
["PATH"].split(os
.pathsep
):
36 if os
.path
.exists(os
.path
.join(path
, binary
)):
37 return os
.path
.join(path
, binary
)
39 print("Unable to find '%s' in $PATH" % binary
)
43 def tapset_dir(binary
):
44 dirname
, filename
= os
.path
.split(binary
)
46 thisfile
= which(binary
)
48 thisfile
= os
.path
.realpath(binary
)
49 if not os
.path
.exists(thisfile
):
50 print("Unable to find '%s'" % thisfile
)
53 basedir
= os
.path
.split(thisfile
)[0]
54 tapset
= os
.path
.join(basedir
, "..", "share", "systemtap", "tapset")
55 return os
.path
.realpath(tapset
)
58 def tapset_env(tapset_dir
):
59 tenv
= copy
.copy(os
.environ
)
60 tenv
["SYSTEMTAP_TAPSET"] = tapset_dir
64 prefix
= probe_prefix(args
.binary
)
65 tapsets
= tapset_dir(args
.binary
)
68 print("Using tapset dir '%s' for binary '%s'" % (tapsets
, args
.binary
))
71 for probe
in args
.probes
:
72 probes
.append("probe %s.%s {}" % (prefix
, probe
))
74 print("At least one probe pattern must be specified")
77 script
= " ".join(probes
)
79 print("Compiling script '%s'" % script
)
80 script
= """probe begin { print("Running script, <Ctrl>-c to quit\\n") } """ + script
82 # We request an 8MB buffer, since the stap default 1MB buffer
83 # can be easily overflowed by frequently firing QEMU traces
84 stapargs
= ["stap", "-s", "8"]
85 if args
.pid
is not None:
86 stapargs
.extend(["-x", args
.pid
])
87 stapargs
.extend(["-e", script
])
88 subprocess
.call(stapargs
, env
=tapset_env(tapsets
))
92 tapsets
= tapset_dir(args
.binary
)
95 print("Using tapset dir '%s' for binary '%s'" % (tapsets
, args
.binary
))
97 def print_probes(verbose
, name
):
98 prefix
= probe_prefix(args
.binary
)
99 offset
= len(prefix
) + 1
100 script
= prefix
+ "." + name
103 print("Listing probes with name '%s'" % script
)
104 proc
= subprocess
.Popen(["stap", "-l", script
],
105 stdout
=subprocess
.PIPE
,
106 universal_newlines
=True,
107 env
=tapset_env(tapsets
))
108 out
, err
= proc
.communicate()
109 if proc
.returncode
!= 0:
110 print("No probes found, are the tapsets installed in %s" % tapset_dir(args
.binary
))
113 for line
in out
.splitlines():
114 if line
.startswith(prefix
):
115 print("%s" % line
[offset
:])
117 if len(args
.probes
) == 0:
118 print_probes(args
.verbose
, "*")
120 for probe
in args
.probes
:
121 print_probes(args
.verbose
, probe
)
125 parser
= argparse
.ArgumentParser(description
="QEMU SystemTap trace tool")
126 parser
.add_argument("-v", "--verbose", help="Print verbose progress info",
129 subparser
= parser
.add_subparsers(help="commands")
130 subparser
.required
= True
131 subparser
.dest
= "command"
133 runparser
= subparser
.add_parser("run", help="Run a trace session",
134 formatter_class
=argparse
.RawDescriptionHelpFormatter
,
137 To watch all trace points on the qemu-system-x86_64 binary:
139 %(argv0)s run qemu-system-x86_64
141 To only watch the trace points matching the qio* and qcrypto* patterns
143 %(argv0)s run qemu-system-x86_64 'qio*' 'qcrypto*'
144 """ % {"argv0": sys
.argv
[0]})
145 runparser
.set_defaults(func
=cmd_run
)
146 runparser
.add_argument("--pid", "-p", dest
="pid",
147 help="Restrict tracing to a specific process ID")
148 runparser
.add_argument("binary", help="QEMU system or user emulator binary")
149 runparser
.add_argument("probes", help="Probe names or wildcards",
150 nargs
=argparse
.REMAINDER
)
152 listparser
= subparser
.add_parser("list", help="List probe points",
153 formatter_class
=argparse
.RawDescriptionHelpFormatter
,
156 To list all trace points on the qemu-system-x86_64 binary:
158 %(argv0)s list qemu-system-x86_64
160 To only list the trace points matching the qio* and qcrypto* patterns
162 %(argv0)s list qemu-system-x86_64 'qio*' 'qcrypto*'
163 """ % {"argv0": sys
.argv
[0]})
164 listparser
.set_defaults(func
=cmd_list
)
165 listparser
.add_argument("binary", help="QEMU system or user emulator binary")
166 listparser
.add_argument("probes", help="Probe names or wildcards",
167 nargs
=argparse
.REMAINDER
)
169 args
= parser
.parse_args()
174 if __name__
== '__main__':