From 952c018efe6d7b32cc4f240ba660a3b6c93c0c9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= Date: Fri, 30 Aug 2019 13:22:54 +0100 Subject: [PATCH] src: rewrite systemtap probe generator in Python MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As part of a goal to eliminate Perl from libvirt build tools, rewrite the dtrace2systemtap.pl tool in Python. This was a straight conversion, manually going line-by-line to change the syntax from Perl to Python. Thus the overall structure of the file and approach is the same. The "--with-modules" flag was dropped because this functionality is not implicitly always enabled. Tested-by: Cole Robinson Reviewed-by: Ján Tomko Signed-off-by: Daniel P. Berrangé --- Makefile.am | 1 + scripts/dtrace2systemtap.py | 143 ++++++++++++++++++++++++++++++++++++ src/Makefile.am | 10 +-- src/dtrace2systemtap.pl | 130 -------------------------------- 4 files changed, 147 insertions(+), 137 deletions(-) create mode 100755 scripts/dtrace2systemtap.py delete mode 100755 src/dtrace2systemtap.pl diff --git a/Makefile.am b/Makefile.am index fc8dcadaf3..0a5a19538d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -50,6 +50,7 @@ EXTRA_DIST = \ scripts/check-aclperms.py \ scripts/check-symfile.py \ scripts/check-symsorting.py \ + scripts/dtrace2systemtap.py \ scripts/header-ifdef.py \ scripts/minimize-po.py \ scripts/mock-noinline.py \ diff --git a/scripts/dtrace2systemtap.py b/scripts/dtrace2systemtap.py new file mode 100755 index 0000000000..922713e599 --- /dev/null +++ b/scripts/dtrace2systemtap.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python +# +# Copyright (C) 2011-2019 Red Hat, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library 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 +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library. If not, see +# . +# +# +# Generate a set of systemtap probe definitions corresponding to +# DTrace probe markers in libvirt.so +# +# python dtrace2systemtap.py probes.d > libvirt_probes.stp +# + +from __future__ import print_function + +import re +import sys + +file = None +filelist = [] +files = {} + +bindir = sys.argv[1] +sbindir = sys.argv[2] +libdir = sys.argv[3] +dtrace = sys.argv[4] + +probe = None +args = None + +# Read the DTraceprobes definition + +with open(dtrace, "r") as fh: + lineno = 0 + for line in fh: + lineno = lineno + 1 + line = line.strip() + if line == "": + continue + if line.find("provider ") != -1 and line.find("{") != -1: + continue + if line.find("};") != -1: + continue + + if line.startswith("#"): + m = re.search(r'''^\#\s*file:\s*(\S+)$''', line) + if m is not None: + file = m.group(1) + filelist.append(file) + files[file] = {"prefix": None, "probes": []} + continue + + m = re.search(r'''^\#\s*prefix:\s*(\S+)$''', line) + if m is not None: + files[file]["prefix"] = m.group(1) + continue + + m = re.search(r'''^\#\s*binary:\s*(\S+)$''', line) + if m is not None: + files[file]["binary"] = m.group(1) + continue + + m = re.search(r'''^\#\s*module:\s*(\S+)$''', line) + if m is not None: + files[file]["module"] = m.group(1) + + # ignore unknown comments + else: + m = re.search(r'''probe\s+([a-zA-Z0-9_]+)\((.*?)(\);)?$''', line) + if m is not None: + probe = m.group(1) + args = m.group(2) + if m.group(3) is not None: + files[file]["probes"].append([probe, args]) + probe = None + args = None + elif probe is not None: + m = re.search(r'''^(.*?)(\);)?$''', line) + if m is not None: + args = args + m.group(1) + if m.group(2) is not None: + files[file]["probes"].append([probe, args]) + probe = None + args = None + else: + raise Exception("unexpected data %s on line %d" % + (line, lineno)) + else: + raise Exception("unexpected data %s on line %d" % + (line, lineno)) + +# Write out the SystemTap probes +for file in filelist: + prefix = files[file]["prefix"] + probes = files[file]["probes"] + + print("# %s\n" % file) + for probe in probes: + name = probe[0] + args = probe[1] + + pname = name.replace(prefix + "_", "libvirt." + prefix + ".") + + binary = libdir + "/libvirt.so" + if "binary" in files[file]: + binary = sbindir + "/" + files[file]["binary"] + if "module" in files[file]: + binary = libdir + "/" + files[file]["module"] + + print("probe %s = process(\"%s\").mark(\"%s\") {" % + (pname, binary, name)) + + argbits = args.split(",") + for idx in range(len(argbits)): + arg = argbits[idx] + isstr = False + if arg.find("char *") != -1: + isstr = True + + m = re.search(r'''^.*\s\*?(\S+)$''', arg) + if m is not None: + arg = m.group(1) + else: + raise Exception("Malformed arg %s" % arg) + + if isstr: + print(" %s = user_string($arg%d);" % (arg, idx + 1)) + else: + print(" %s = $arg%d;" % (arg, idx + 1)) + print("}\n") + print("") diff --git a/src/Makefile.am b/src/Makefile.am index 438ed744c5..83c31cc92b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -527,7 +527,6 @@ if WITH_DTRACE_PROBES libvirt_la_BUILT_LIBADD += libvirt_probes.lo libvirt_la_DEPENDENCIES += libvirt_probes.lo libvirt_probes.o nodist_libvirt_la_SOURCES = libvirt_probes.h -DTRACE2SYSTEMTAP_FLAGS = --with-modules BUILT_SOURCES += libvirt_probes.h libvirt_probes.stp libvirt_functions.stp @@ -562,10 +561,10 @@ RPC_PROBE_FILES += $(srcdir)/rpc/virnetprotocol.x \ libvirt_functions.stp: $(RPC_PROBE_FILES) $(srcdir)/rpc/gensystemtap.pl $(AM_V_GEN)$(PERL) -w $(srcdir)/rpc/gensystemtap.pl $(RPC_PROBE_FILES) > $@ -%_probes.stp: %_probes.d $(srcdir)/dtrace2systemtap.pl \ +%_probes.stp: %_probes.d $(top_srcdir)/scripts/dtrace2systemtap.py \ $(top_builddir)/config.status - $(AM_V_GEN)$(PERL) -w $(srcdir)/dtrace2systemtap.pl \ - $(DTRACE2SYSTEMTAP_FLAGS) $(bindir) $(sbindir) $(libdir) $< > $@ + $(AM_V_GEN)$(RUNUTF8) $(PYTHON) $(top_srcdir)/scripts/dtrace2systemtap.py \ + $(bindir) $(sbindir) $(libdir) $< > $@ CLEANFILES += libvirt_probes.h libvirt_probes.o libvirt_probes.lo \ libvirt_functions.stp libvirt_probes.stp @@ -686,9 +685,6 @@ endif LIBVIRT_INIT_SCRIPT_SYSTEMD endif WITH_LIBVIRTD -EXTRA_DIST += dtrace2systemtap.pl - - if WITH_LIBVIRTD libexec_PROGRAMS += libvirt_iohelper libvirt_iohelper_SOURCES = $(UTIL_IO_HELPER_SOURCES) diff --git a/src/dtrace2systemtap.pl b/src/dtrace2systemtap.pl deleted file mode 100755 index c5fce248b4..0000000000 --- a/src/dtrace2systemtap.pl +++ /dev/null @@ -1,130 +0,0 @@ -#!/usr/bin/env perl -# -# Copyright (C) 2011-2012 Red Hat, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library 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 -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library. If not, see -# . -# -# -# Generate a set of systemtap probe definitions corresponding to -# DTrace probe markers in libvirt.so -# -# perl dtrace2systemtap.pl probes.d > libvirt_probes.stp -# - -use strict; -use warnings; - -my $file; -my @files; -my %files; - -my $with_modules = 0; -if ($ARGV[0] eq "--with-modules") { - # set if we want to honor the "module" setting in the .d file - $with_modules = 1; - shift @ARGV; -} - -my $bindir = shift @ARGV; -my $sbindir = shift @ARGV; -my $libdir = shift @ARGV; - -my $probe; -my $args; - -# Read the DTraceprobes definition -while (<>) { - next if m,^\s*$,; - - next if /^\s*provider\s+\w+\s*{\s*$/; - next if /^\s*};\s*$/; - - if (m,^\s*\#,) { - if (m,^\s*\#\s*file:\s*(\S+)\s*$,) { - $file = $1; - push @files, $file; - $files{$file} = { prefix => undef, probes => [] }; - } elsif (m,^\s*\#\s*prefix:\s*(\S+)\s*$,) { - $files{$file}->{prefix} = $1; - } elsif (m,^\s*\#\s*binary:\s*(\S+)\s*$,) { - $files{$file}->{binary} = $1; - } elsif (m,^\s*\#\s*module:\s*(\S+)\s*$,) { - $files{$file}->{module} = $1; - } else { - # ignore unknown comments - } - } else { - if (m,\s*probe\s+([a-zA-Z0-9_]+)\((.*?)(\);)?$,) { - $probe = $1; - $args = $2; - if ($3) { - push @{$files{$file}->{probes}}, [$probe, $args]; - $probe = $args = undef; - } - } elsif ($probe) { - if (m,^(.*?)(\);)?$,) { - $args .= $1; - if ($2) { - push @{$files{$file}->{probes}}, [$probe, $args]; - $probe = $args = undef; - } - } else { - die "unexpected data $_ on line $."; - } - } else { - die "unexpected data $_ on line $."; - } - } -} - -# Write out the SystemTap probes -foreach my $file (@files) { - my $prefix = $files{$file}->{prefix}; - my @probes = @{$files{$file}->{probes}}; - - print "# $file\n\n"; - foreach my $probe (@probes) { - my $name = $probe->[0]; - my $args = $probe->[1]; - - my $pname = $name; - $pname =~ s/${prefix}_/libvirt.$prefix./; - - my $binary = "$libdir/libvirt.so"; - if (exists $files{$file}->{binary}) { - $binary = $sbindir . "/" . $files{$file}->{binary}; - } - if ($with_modules && exists $files{$file}->{module}) { - $binary = $libdir . "/" . $files{$file}->{module}; - } - - print "probe $pname = process(\"$binary\").mark(\"$name\") {\n"; - - my @args = split /,/, $args; - for (my $i = 0 ; $i <= $#args ; $i++) { - my $arg = $args[$i]; - my $isstr = $arg =~ /char\s+\*/; - $arg =~ s/^.*\s\*?(\S+)$/$1/; - - if ($isstr) { - print " $arg = user_string(\$arg", $i + 1, ");\n"; - } else { - print " $arg = \$arg", $i + 1, ";\n"; - } - } - print "}\n\n"; - } - print "\n"; -}