@@ -354,12 +354,12 @@ else
trace.h: trace.h-timestamp
endif
trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --backend=$(TRACE_BACKEND) -h < $< > $@," GEN trace.h")
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=h --backend=$(TRACE_BACKEND) < $< > $@," GEN trace.h")
@cmp -s $@ trace.h || cp $@ trace.h
trace.c: trace.c-timestamp
trace.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --backend=$(TRACE_BACKEND) -c < $< > $@," GEN trace.c")
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=c --backend=$(TRACE_BACKEND) < $< > $@," GEN trace.c")
@cmp -s $@ trace.c || cp $@ trace.c
trace.o: trace.c $(GENERATED_HEADERS)
@@ -372,7 +372,7 @@ trace-dtrace.h: trace-dtrace.dtrace
# rule file. So we use '.dtrace' instead
trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
- $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --backend=$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace")
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=d --backend=$(TRACE_BACKEND) < $< > $@," GEN trace-dtrace.dtrace")
@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
@@ -53,11 +53,12 @@ endif
$(QEMU_PROG).stp:
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py \
+ --format=stap \
--backend=$(TRACE_BACKEND) \
--binary=$(bindir)/$(QEMU_PROG) \
--target-arch=$(TARGET_ARCH) \
--target-type=$(TARGET_TYPE) \
- --stap < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).stp")
+ < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).stp")
else
stap:
endif
@@ -11,33 +11,109 @@
import sys
import getopt
-def usage():
- print "Tracetool: Generate tracing code for trace events file on stdin"
- print "Usage:"
- print sys.argv[0], " --backend=[nop|simple|stderr|dtrace|ust] [-h|-c|-d|--stap]"
- print '''
-Backends:
- --nop Tracing disabled
- --simple Simple built-in backend
- --stderr Stderr built-in backend
- --dtrace DTrace/SystemTAP backend
- --ust LTTng User Space Tracing backend
-
-Output formats:
- -h Generate .h file
- -c Generate .c file
- -d Generate .d file (DTrace only)
- --stap Generate .stp file (DTrace with SystemTAP only)
-Options:
- --binary [path] Full path to QEMU binary
- --target-arch [arch] QEMU emulator target arch
- --target-type [type] QEMU emulator target type ('system' or 'user')
- --probe-prefix [prefix] Prefix for dtrace probe names
- (default: qemu-targettype-targetarch)
-'''
- sys.exit(1)
+######################################################################
+# format auto-registration
+
+class _Tag:
+ pass
+
+_formats = {}
+
+BEGIN = _Tag()
+END = _Tag()
+_DESCR = _Tag()
+
+def for_format(format_, when, descr = None):
+ """Decorator for format generator functions."""
+
+ if when is not BEGIN and when is not END:
+ raise ValueError("Invalid 'when' tag")
+ if format_ in _formats and when in _formats[format_]:
+ raise ValueError("Format '%s' already set for given 'when' tag" % format_)
+
+ if format_ not in _formats:
+ _formats[format_] = {}
+ if descr is not None:
+ if _DESCR in _formats[format_]:
+ raise ValueError("Description already set")
+ _formats[format_][_DESCR] = descr
+
+ def func(f):
+ _formats[format_][when] = f
+ return f
+ return func
+
+def get_format(format_, when):
+ """Get a format generator function."""
+
+ def nop(*args, **kwargs):
+ pass
+ if format_ in _formats and when in _formats[format_]:
+ return _formats[format_][when]
+ else:
+ return nop
+
+def get_format_descr(format_):
+ """Get the description of a format generator."""
+
+ if format_ in _formats and _DESCR in _formats[format_]:
+ return _formats[format_][_DESCR]
+ else:
+ return ""
+
+
+
+######################################################################
+# backend auto-registration and format compatibility
+
+_backends = {}
+
+def for_backend(backend, format_, descr = None):
+ if backend not in _backends:
+ _backends[backend] = {}
+ if format_ in _backends[backend]:
+ raise ValueError("Backend '%s' already set for backend '%s'" % (backend, format_))
+ if format_ not in _formats:
+ raise ValueError("Unknown format '%s'" % format_)
+
+ if descr is not None:
+ if _DESCR in _backends[backend]:
+ raise ValueError("Description already set")
+ _backends[backend][_DESCR] = descr
+
+ def func(f):
+ _backends[backend][format_] = f
+ return f
+ return func
+
+def get_backend(format_, backend):
+ if backend not in _backends:
+ raise ValueError("Unknown backend '%s'" % backend)
+ if format_ not in _formats:
+ raise ValueError("Unknown format '%s'" % format_)
+ if format_ not in _backends[backend]:
+ raise ValueError("Format '%s' not supported with backend '%s'" % (format_, backend))
+ return _backends[backend][format_]
+
+def get_backend_descr(backend):
+ """Get the description of a backend."""
+
+ if backend in _backends and _DESCR in _backends[backend]:
+ return _backends[backend][_DESCR]
+ else:
+ return ""
+
+
+
+######################################################################
+# formats
+
+##################################################
+# format: h
+
+@for_format("h", BEGIN, "Generate .h file")
def trace_h_begin(events):
print '''#ifndef TRACE_H
#define TRACE_H
@@ -46,12 +122,27 @@ def trace_h_begin(events):
#include "qemu-common.h"'''
+@for_format("h", END)
def trace_h_end(events):
print '#endif /* TRACE_H */'
+
+##################################################
+# format: c
+
+@for_format("c", BEGIN, "Generate .c file")
def trace_c_begin(events):
print '/* This file is autogenerated by tracetool, do not edit. */'
+
+
+######################################################################
+# backends
+
+##################################################
+# backend: nop
+
+@for_backend("nop", "h", "Tracing disabled")
def nop_h(events):
print
for event in events:
@@ -62,13 +153,16 @@ def nop_h(events):
'name': event.name,
'args': event.args
}
- return
+@for_backend("nop", "c")
def nop_c(events):
- # nop, reqd for converters
- return
+ pass
+
+##################################################
+# backend: simple
+@for_backend("simple", "h", "Simple built-in backend")
def simple_h(events):
print '#include "trace/simple.h"'
print
@@ -81,8 +175,7 @@ def simple_h(events):
print '#define NR_TRACE_EVENTS %d' % len(events)
print 'extern TraceEvent trace_list[NR_TRACE_EVENTS];'
- return
-
+@for_backend("simple", "c")
def simple_c(events):
rec_off = 0
print '#include "trace.h"'
@@ -164,8 +257,11 @@ def simple_c(events):
'''
- return
+##################################################
+# backend: stderr
+
+@for_backend("stderr", "h", "Stderr built-in backend")
def stderr_h(events):
print '''#include <stdio.h>
#include "trace/stderr.h"
@@ -192,6 +288,7 @@ static inline void trace_%(name)s(%(args)s)
print
print '#define NR_TRACE_EVENTS %d' % len(events)
+@for_backend("stderr", "c")
def stderr_c(events):
print '''#include "trace.h"
@@ -204,6 +301,11 @@ TraceEvent trace_list[] = {
print
print '};'
+
+##################################################
+# backend: ust
+
+@for_backend("ust", "h", "LTTng User Space Tracing backend")
def ust_h(events):
print '''#include <ust/tracepoint.h>
#undef mutex_lock
@@ -227,8 +329,8 @@ _DECLARE_TRACEPOINT_NOARGS(ust_%(name)s);
'name': event.name,
}
print
- return
+@for_backend("ust", "c")
def ust_c(events):
print '''#include <ust/marker.h>
#undef mutex_lock
@@ -274,8 +376,11 @@ static void __attribute__((constructor)) trace_init(void)
}
print '}'
- return
+##################################################
+# backend: dtrace
+
+@for_backend("dtrace", "h", "DTrace/SystemTAP backend")
def dtrace_h(events):
print '#include "trace-dtrace.h"'
print
@@ -292,9 +397,16 @@ def dtrace_h(events):
'argnames': ", ".join(event.args.names()),
}
+@for_backend("dtrace", "c")
def dtrace_c(events):
- return # No need for function definitions in dtrace backend
+ pass
+
+
+@for_format("d", BEGIN, "Generate .d file (DTrace probes)")
+def trace_d_begin(events):
+ print '/* This file is autogenerated by tracetool, do not edit. */'
+@for_backend("dtrace", "d")
def dtrace_d(events):
print 'provider qemu {'
for event in events:
@@ -315,9 +427,27 @@ def dtrace_d(events):
print '};'
return
+@for_backend("nop", "d")
def dtrace_nop_d(events):
pass
+
+@for_format("stap", BEGIN, "Generate .stp file (SystemTAP tapsets)")
+def trace_stap_begin(events):
+ global probeprefix
+ if binary == "":
+ print '--binary is required for SystemTAP tapset generator'
+ sys.exit(1)
+ if ((probeprefix == "") and (targettype == "")):
+ print '--target-type is required for SystemTAP tapset generator'
+ sys.exit(1)
+ if ((probeprefix == "") and (targetarch == "")):
+ print '--target-arch is required for SystemTAP tapset generator'
+ sys.exit(1)
+ if probeprefix == "":
+ probeprefix = 'qemu.' + targettype + '.' + targetarch
+ print '/* This file is autogenerated by tracetool, do not edit. */'
+
def dtrace_stp(events):
for event in events:
# Define prototype for probe arguments
@@ -343,82 +473,11 @@ probe %(probeprefix)s.%(name)s = process("%(binary)s").mark("%(name)s")
def dtrace_nop_stp(events):
pass
-def trace_stap_begin(events):
- global probeprefix
- if backend != "dtrace":
- print 'SystemTAP tapset generator not applicable to %s backend' % backend
- sys.exit(1)
- if binary == "":
- print '--binary is required for SystemTAP tapset generator'
- sys.exit(1)
- if ((probeprefix == "") and (targettype == "")):
- print '--target-type is required for SystemTAP tapset generator'
- sys.exit(1)
- if ((probeprefix == "") and (targetarch == "")):
- print '--target-arch is required for SystemTAP tapset generator'
- sys.exit(1)
- if probeprefix == "":
- probeprefix = 'qemu.' + targettype + '.' + targetarch
- print '/* This file is autogenerated by tracetool, do not edit. */'
-
-def trace_d_begin(events):
- if backend != 'dtrace':
- print 'DTrace probe generator not applicable to %s backend' % backend
- sys.exit(1)
- print '/* This file is autogenerated by tracetool, do not edit. */'
-# Registry of backends and their converter functions
-converters = {
- 'simple': {
- 'h': simple_h,
- 'c': simple_c,
- },
-
- 'nop': {
- 'h': nop_h,
- 'c': nop_c,
- 'd': dtrace_nop_d,
- 'stap': dtrace_nop_stp,
- },
-
- 'stderr': {
- 'h': stderr_h,
- 'c': stderr_c,
- },
-
- 'dtrace': {
- 'h': dtrace_h,
- 'c': dtrace_c,
- 'd': dtrace_d,
- 'stap': dtrace_stp
- },
-
- 'ust': {
- 'h': ust_h,
- 'c': ust_c,
- },
-
-}
-
-# Trace file header and footer code generators
-formats = {
- 'h': {
- 'begin': trace_h_begin,
- 'end': trace_h_end,
- },
- 'c': {
- 'begin': trace_c_begin,
- },
- 'd': {
- 'begin': trace_d_begin,
- },
- 'stap': {
- 'begin': trace_stap_begin,
- },
-}
-
+######################################################################
# Event arguments
+
def type_is_string(type_):
strtype = ('const char*', 'char*', 'const char *', 'char *')
return type_.startswith(strtype)
@@ -459,7 +518,11 @@ class Arguments:
res = ""
return res
+
+
+######################################################################
# A trace event
+
import re
cre = re.compile("((?P<props>.*)\s+)?(?P<name>[^(\s]+)\((?P<args>[^)]*)\)\s*(?P<fmt>\".*)?")
@@ -490,34 +553,54 @@ def read_events(fobj):
res.append(Event(line))
return res
+
+######################################################################
+# Main
+
+format_ = ""
backend = ""
-output = ""
binary = ""
targettype = ""
targetarch = ""
probeprefix = ""
+def usage():
+ print "Tracetool: Generate tracing code for trace events file on stdin"
+ print "Usage:"
+ print sys.argv[0], " --format=<format> --backend=<backend>"
+ print
+ print "Output formats:"
+ for f in _formats:
+ print " %-10s %s" % (f, get_format_descr(f))
+ print
+ print "Backends:"
+ for b in _backends:
+ print " %-10s %s" % (b, get_backend_descr(b))
+ print """
+Options:
+ --binary [path] Full path to QEMU binary
+ --target-arch [arch] QEMU emulator target arch
+ --target-type [type] QEMU emulator target type ('system' or 'user')
+ --probe-prefix [prefix] Prefix for dtrace probe names
+ (default: qemu-targettype-targetarch)
+"""
+
+ sys.exit(1)
+
def main():
- global backend, output, binary, targettype, targetarch, probeprefix
- supported_backends = ["simple", "nop", "stderr", "dtrace", "ust"]
- short_options = "hcd"
- long_options = ["stap", "backend=", "binary=", "target-arch=", "target-type=", "probe-prefix=", "list-backends", "check-backend"]
+ global format_, backend, binary, targettype, targetarch, probeprefix
+
+ long_options = ["stap", "format=", "backend=", "binary=", "target-arch=", "target-type=", "probe-prefix=", "list-backends", "check-backend"]
try:
- opts, args = getopt.getopt(sys.argv[1:], short_options, long_options)
+ opts, args = getopt.getopt(sys.argv[1:], "", long_options)
except getopt.GetoptError, err:
# print help information and exit:
print str(err) # will print something like "option -a not recognized"
usage()
sys.exit(2)
for opt, arg in opts:
- if opt == '-h':
- output = 'h'
- elif opt == '-c':
- output = 'c'
- elif opt == '-d':
- output = 'd'
- elif opt == '--stap':
- output = 'stap'
+ if opt == '--format':
+ format_ = arg
elif opt == '--backend':
backend = arg
elif opt == '--binary':
@@ -529,30 +612,40 @@ def main():
elif opt == '--probe-prefix':
probeprefix = arg
elif opt == '--list-backends':
- print 'simple, nop, stderr, dtrace'
+ print ', '.join(_backends)
sys.exit(0)
elif opt == "--check-backend":
- if any(backend in s for s in supported_backends):
+ if backend in _backends:
sys.exit(0)
else:
sys.exit(1)
else:
- #assert False, "unhandled option"
print "unhandled option: ", opt
usage()
- if backend == "" or output == "":
+ if format_ not in _formats:
+ print "Unknown format: %s" % format_
+ print
+ usage()
+ if backend not in _backends:
+ print "Unknown backend: %s" % backend
+ print
usage()
- sys.exit(0)
events = read_events(sys.stdin)
- if 'begin' in formats[output]:
- formats[output]['begin'](events)
- converters[backend][output]([ e for e in events if 'disable' not in e.properties ])
- converters['nop'][output]([ e for e in events if 'disable' in e.properties ])
- if 'end' in formats[output]:
- formats[output]['end'](events)
+ try:
+ # just force format/backend compatibility check
+ bfun = get_backend(format_, backend)
+ bnop = get_backend(format_, "nop")
+ except Exception as e:
+ sys.stderr.write(str(e) + "\n\n")
+ usage()
+
+ get_format(format_, BEGIN)(events)
+ bfun([ e for e in events if "disable" not in e.properties ])
+ bnop([ e for e in events if "disable" in e.properties ])
+ get_format(format_, END)(events)
if __name__ == "__main__":
main()
Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- Makefile.objs | 6 - Makefile.target | 3 scripts/tracetool.py | 357 ++++++++++++++++++++++++++++++++------------------ 3 files changed, 230 insertions(+), 136 deletions(-)