123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- #!/usr/bin/python
- # -*- python -*-
- #
- # Copyright (C) 2019 Red Hat, Inc
- #
- # QEMU SystemTap Trace Tool
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, see <http://www.gnu.org/licenses/>.
- from __future__ import print_function
- import argparse
- import copy
- import os.path
- import re
- import subprocess
- import sys
- def probe_prefix(binary):
- dirname, filename = os.path.split(binary)
- return re.sub("-", ".", filename) + ".log"
- def which(binary):
- for path in os.environ["PATH"].split(os.pathsep):
- if os.path.exists(os.path.join(path, binary)):
- return os.path.join(path, binary)
- print("Unable to find '%s' in $PATH" % binary)
- sys.exit(1)
- def tapset_dir(binary):
- dirname, filename = os.path.split(binary)
- if dirname == '':
- thisfile = which(binary)
- else:
- thisfile = os.path.realpath(binary)
- if not os.path.exists(thisfile):
- print("Unable to find '%s'" % thisfile)
- sys.exit(1)
- basedir = os.path.split(thisfile)[0]
- tapset = os.path.join(basedir, "..", "share", "systemtap", "tapset")
- return os.path.realpath(tapset)
- def tapset_env(tapset_dir):
- tenv = copy.copy(os.environ)
- tenv["SYSTEMTAP_TAPSET"] = tapset_dir
- return tenv
- def cmd_run(args):
- prefix = probe_prefix(args.binary)
- tapsets = tapset_dir(args.binary)
- if args.verbose:
- print("Using tapset dir '%s' for binary '%s'" % (tapsets, args.binary))
- probes = []
- for probe in args.probes:
- probes.append("probe %s.%s {}" % (prefix, probe))
- if len(probes) == 0:
- print("At least one probe pattern must be specified")
- sys.exit(1)
- script = " ".join(probes)
- if args.verbose:
- print("Compiling script '%s'" % script)
- script = """probe begin { print("Running script, <Ctrl>-c to quit\\n") } """ + script
- # We request an 8MB buffer, since the stap default 1MB buffer
- # can be easily overflowed by frequently firing QEMU traces
- stapargs = ["stap", "-s", "8"]
- if args.pid is not None:
- stapargs.extend(["-x", args.pid])
- stapargs.extend(["-e", script])
- subprocess.call(stapargs, env=tapset_env(tapsets))
- def cmd_list(args):
- tapsets = tapset_dir(args.binary)
- if args.verbose:
- print("Using tapset dir '%s' for binary '%s'" % (tapsets, args.binary))
- def print_probes(verbose, name):
- prefix = probe_prefix(args.binary)
- offset = len(prefix) + 1
- script = prefix + "." + name
- if verbose:
- print("Listing probes with name '%s'" % script)
- proc = subprocess.Popen(["stap", "-l", script],
- stdout=subprocess.PIPE, env=tapset_env(tapsets))
- out, err = proc.communicate()
- if proc.returncode != 0:
- print("No probes found, are the tapsets installed in %s" % tapset_dir(args.binary))
- sys.exit(1)
- for line in out.splitlines():
- if line.startswith(prefix):
- print("%s" % line[offset:])
- if len(args.probes) == 0:
- print_probes(args.verbose, "*")
- else:
- for probe in args.probes:
- print_probes(args.verbose, probe)
- def main():
- parser = argparse.ArgumentParser(description="QEMU SystemTap trace tool")
- parser.add_argument("-v", "--verbose", help="Print verbose progress info",
- action='store_true')
- subparser = parser.add_subparsers(help="commands")
- subparser.required = True
- subparser.dest = "command"
- runparser = subparser.add_parser("run", help="Run a trace session",
- formatter_class=argparse.RawDescriptionHelpFormatter,
- epilog="""
- To watch all trace points on the qemu-system-x86_64 binary:
- %(argv0)s run qemu-system-x86_64
- To only watch the trace points matching the qio* and qcrypto* patterns
- %(argv0)s run qemu-system-x86_64 'qio*' 'qcrypto*'
- """ % {"argv0": sys.argv[0]})
- runparser.set_defaults(func=cmd_run)
- runparser.add_argument("--pid", "-p", dest="pid",
- help="Restrict tracing to a specific process ID")
- runparser.add_argument("binary", help="QEMU system or user emulator binary")
- runparser.add_argument("probes", help="Probe names or wildcards",
- nargs=argparse.REMAINDER)
- listparser = subparser.add_parser("list", help="List probe points",
- formatter_class=argparse.RawDescriptionHelpFormatter,
- epilog="""
- To list all trace points on the qemu-system-x86_64 binary:
- %(argv0)s list qemu-system-x86_64
- To only list the trace points matching the qio* and qcrypto* patterns
- %(argv0)s list qemu-system-x86_64 'qio*' 'qcrypto*'
- """ % {"argv0": sys.argv[0]})
- listparser.set_defaults(func=cmd_list)
- listparser.add_argument("binary", help="QEMU system or user emulator binary")
- listparser.add_argument("probes", help="Probe names or wildcards",
- nargs=argparse.REMAINDER)
- args = parser.parse_args()
- args.func(args)
- sys.exit(0)
- if __name__ == '__main__':
- main()
|