Signed-off-by: Harsh Prateek Bora <ha...@linux.vnet.ibm.com> Signed-off-by: Lluís Vilanova <vilan...@ac.upc.edu> --- Makefile.objs | 6 Makefile.target | 10 - configure | 4 scripts/tracetool | 648 -------------------------------------------------- scripts/tracetool.py | 533 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 543 insertions(+), 658 deletions(-) delete mode 100755 scripts/tracetool create mode 100755 scripts/tracetool.py
diff --git a/Makefile.objs b/Makefile.objs index 5f0b3f7..a718963 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -357,12 +357,12 @@ else trace.h: trace.h-timestamp endif trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak - $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --backend=$(TRACE_BACKEND) -h < $< > $@," 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,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@," GEN trace.c") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --backend=$(TRACE_BACKEND) -c < $< > $@," GEN trace.c") @cmp -s $@ trace.c || cp $@ trace.c trace.o: trace.c $(GENERATED_HEADERS) @@ -375,7 +375,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,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --backend=$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace") @cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS) diff --git a/Makefile.target b/Makefile.target index 1bd25a8..3e42e5a 100644 --- a/Makefile.target +++ b/Makefile.target @@ -59,11 +59,11 @@ TARGET_TYPE=system endif $(QEMU_PROG).stp: - $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool \ - --$(TRACE_BACKEND) \ - --binary $(bindir)/$(QEMU_PROG) \ - --target-arch $(TARGET_ARCH) \ - --target-type $(TARGET_TYPE) \ + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py \ + --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") else stap: diff --git a/configure b/configure index d7631ed..bea4a2c 100755 --- a/configure +++ b/configure @@ -1097,7 +1097,7 @@ echo " --disable-docs disable documentation build" echo " --disable-vhost-net disable vhost-net acceleration support" echo " --enable-vhost-net enable vhost-net acceleration support" echo " --enable-trace-backend=B Set trace backend" -echo " Available backends:" $("$source_path"/scripts/tracetool --list-backends) +echo " Available backends:" $($python "$source_path"/scripts/tracetool.py --list-backends) echo " --with-trace-file=NAME Full PATH,NAME of file to store traces" echo " Default:trace-<pid>" echo " --disable-spice disable spice" @@ -2654,7 +2654,7 @@ fi ########################################## # check if trace backend exists -sh "$source_path/scripts/tracetool" "--$trace_backend" --check-backend > /dev/null 2> /dev/null +$python "$source_path/scripts/tracetool.py" "--backend=$trace_backend" --check-backend > /dev/null 2> /dev/null if test "$?" -ne 0 ; then echo echo "Error: invalid trace backend" diff --git a/scripts/tracetool b/scripts/tracetool deleted file mode 100755 index 65bd0a1..0000000 --- a/scripts/tracetool +++ /dev/null @@ -1,648 +0,0 @@ -#!/bin/sh -# -# Code generator for trace events -# -# Copyright IBM, Corp. 2010 -# -# This work is licensed under the terms of the GNU GPL, version 2. See -# the COPYING file in the top-level directory. - -# Disable pathname expansion, makes processing text with '*' characters simpler -set -f - -usage() -{ - cat >&2 <<EOF -usage: $0 [--nop | --simple | --stderr | --ust | --dtrace] [-h | -c] -Generate tracing code for a file on stdin. - -Backends: - --nop Tracing disabled - --simple Simple built-in backend - --stderr Stderr built-in backend - --ust LTTng User Space Tracing backend - --dtrace DTrace/SystemTAP 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) - -EOF - exit 1 -} - -# Print a line without interpreting backslash escapes -# -# The built-in echo command may interpret backslash escapes without an option -# to disable this behavior. -puts() -{ - printf "%s\n" "$1" -} - -# Get the name of a trace event -get_name() -{ - local name - name=${1%%\(*} - echo "${name##* }" -} - -# Get the given property of a trace event -# 1: trace-events line -# 2: property name -# -> return 0 if property is present, or 1 otherwise -has_property() -{ - local props prop - props=${1%%\(*} - props=${props% *} - for prop in $props; do - if [ "$prop" = "$2" ]; then - return 0 - fi - done - return 1 -} - -# Get the argument list of a trace event, including types and names -get_args() -{ - local args - args=${1#*\(} - args=${args%%\)*} - echo "$args" -} - -# Get the argument name list of a trace event -get_argnames() -{ - local nfields field name sep - nfields=0 - sep="$2" - for field in $(get_args "$1"); do - nfields=$((nfields + 1)) - - # Drop pointer star - field=${field#\*} - - # Only argument names have commas at the end - name=${field%,} - test "$field" = "$name" && continue - - printf "%s%s " $name $sep - done - - # Last argument name - if [ "$nfields" -gt 1 ] - then - printf "%s" "$name" - fi -} - -# Get the number of arguments to a trace event -get_argc() -{ - local name argc - argc=0 - for name in $(get_argnames "$1", ","); do - argc=$((argc + 1)) - done - echo $argc -} - -# Get the format string including double quotes for a trace event -get_fmt() -{ - puts "${1#*)}" -} - -linetoh_begin_nop() -{ - return -} - -linetoh_nop() -{ - local name args - name=$(get_name "$1") - args=$(get_args "$1") - - # Define an empty function for the trace event - cat <<EOF -static inline void trace_$name($args) -{ -} -EOF -} - -linetoh_end_nop() -{ - return -} - -linetoc_begin_nop() -{ - return -} - -linetoc_nop() -{ - # No need for function definitions in nop backend - return -} - -linetoc_end_nop() -{ - return -} - -linetoh_begin_simple() -{ - cat <<EOF -#include "trace/simple.h" -EOF - - simple_event_num=0 -} - -cast_args_to_uint64_t() -{ - local arg - for arg in $(get_argnames "$1", ","); do - printf "%s" "(uint64_t)(uintptr_t)$arg" - done -} - -linetoh_simple() -{ - local name args argc trace_args - name=$(get_name "$1") - args=$(get_args "$1") - argc=$(get_argc "$1") - - trace_args="$simple_event_num" - if [ "$argc" -gt 0 ] - then - trace_args="$trace_args, $(cast_args_to_uint64_t "$1")" - fi - - cat <<EOF -static inline void trace_$name($args) -{ - trace$argc($trace_args); -} -EOF - - simple_event_num=$((simple_event_num + 1)) -} - -linetoh_end_simple() -{ - cat <<EOF -#define NR_TRACE_EVENTS $simple_event_num -extern TraceEvent trace_list[NR_TRACE_EVENTS]; -EOF -} - -linetoc_begin_simple() -{ - cat <<EOF -#include "trace.h" - -TraceEvent trace_list[] = { -EOF - simple_event_num=0 - -} - -linetoc_simple() -{ - local name - name=$(get_name "$1") - cat <<EOF -{.tp_name = "$name", .state=0}, -EOF - simple_event_num=$((simple_event_num + 1)) -} - -linetoc_end_simple() -{ - cat <<EOF -}; -EOF -} - -#STDERR -linetoh_begin_stderr() -{ - cat <<EOF -#include <stdio.h> -#include "trace/stderr.h" - -extern TraceEvent trace_list[]; -EOF - - stderr_event_num=0 -} - -linetoh_stderr() -{ - local name args argnames argc fmt - name=$(get_name "$1") - args=$(get_args "$1") - argnames=$(get_argnames "$1" ",") - argc=$(get_argc "$1") - fmt=$(get_fmt "$1") - - if [ "$argc" -gt 0 ]; then - argnames=", $argnames" - fi - - cat <<EOF -static inline void trace_$name($args) -{ - if (trace_list[$stderr_event_num].state != 0) { - fprintf(stderr, "$name " $fmt "\n" $argnames); - } -} -EOF - stderr_event_num=$((stderr_event_num + 1)) - -} - -linetoh_end_stderr() -{ - cat <<EOF -#define NR_TRACE_EVENTS $stderr_event_num -EOF -} - -linetoc_begin_stderr() -{ - cat <<EOF -#include "trace.h" - -TraceEvent trace_list[] = { -EOF - stderr_event_num=0 -} - -linetoc_stderr() -{ - local name - name=$(get_name "$1") - cat <<EOF -{.tp_name = "$name", .state=0}, -EOF - stderr_event_num=$(($stderr_event_num + 1)) -} - -linetoc_end_stderr() -{ - cat <<EOF -}; -EOF -} -#END OF STDERR - -# Clean up after UST headers which pollute the namespace -ust_clean_namespace() { - cat <<EOF -#undef mutex_lock -#undef mutex_unlock -#undef inline -#undef wmb -EOF -} - -linetoh_begin_ust() -{ - echo "#include <ust/tracepoint.h>" - ust_clean_namespace -} - -linetoh_ust() -{ - local name args argnames - name=$(get_name "$1") - args=$(get_args "$1") - argnames=$(get_argnames "$1", ",") - - cat <<EOF -DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames)); -#define trace_$name trace_ust_$name -EOF -} - -linetoh_end_ust() -{ - return -} - -linetoc_begin_ust() -{ - cat <<EOF -#include <ust/marker.h> -$(ust_clean_namespace) -#include "trace.h" -EOF -} - -linetoc_ust() -{ - local name args argnames fmt - name=$(get_name "$1") - args=$(get_args "$1") - argnames=$(get_argnames "$1", ",") - [ -z "$argnames" ] || argnames=", $argnames" - fmt=$(get_fmt "$1") - - cat <<EOF -DEFINE_TRACE(ust_$name); - -static void ust_${name}_probe($args) -{ - trace_mark(ust, $name, $fmt$argnames); -} -EOF - - # Collect names for later - names="$names $name" -} - -linetoc_end_ust() -{ - cat <<EOF -static void __attribute__((constructor)) trace_init(void) -{ -EOF - - for name in $names; do - cat <<EOF - register_trace_ust_$name(ust_${name}_probe); -EOF - done - - echo "}" -} - -linetoh_begin_dtrace() -{ - cat <<EOF -#include "trace-dtrace.h" -EOF -} - -linetoh_dtrace() -{ - local name args argnames nameupper - name=$(get_name "$1") - args=$(get_args "$1") - argnames=$(get_argnames "$1", ",") - - nameupper=`echo $name | tr '[:lower:]' '[:upper:]'` - - # Define an empty function for the trace event - cat <<EOF -static inline void trace_$name($args) { - QEMU_${nameupper}($argnames); -} -EOF -} - -linetoh_end_dtrace() -{ - return -} - -linetoc_begin_dtrace() -{ - return -} - -linetoc_dtrace() -{ - # No need for function definitions in dtrace backend - return -} - -linetoc_end_dtrace() -{ - return -} - -linetod_begin_dtrace() -{ - cat <<EOF -provider qemu { -EOF -} - -linetod_dtrace() -{ - local name args - name=$(get_name "$1") - args=$(get_args "$1") - - # DTrace provider syntax expects foo() for empty - # params, not foo(void) - if [ "$args" = "void" ]; then - args="" - fi - - # Define prototype for probe arguments - cat <<EOF - probe $name($args); -EOF -} - -linetod_end_dtrace() -{ - cat <<EOF -}; -EOF -} - -linetostap_begin_dtrace() -{ - return -} - -linetostap_dtrace() -{ - local i arg name args arglist - name=$(get_name "$1") - args=$(get_args "$1") - arglist=$(get_argnames "$1", "") - - # Define prototype for probe arguments - cat <<EOF -probe $probeprefix.$name = process("$binary").mark("$name") -{ -EOF - - i=1 - for arg in $arglist - do - # 'limit' is a reserved keyword - if [ "$arg" = "limit" ]; then - arg="_limit" - fi - cat <<EOF - $arg = \$arg$i; -EOF - i="$((i+1))" - done - - cat <<EOF -} -EOF -} - -linetostap_end_dtrace() -{ - return -} - -# Process stdin by calling begin, line, and end functions for the backend -convert() -{ - local begin process_line end str name NAME enabled - begin="lineto$1_begin_$backend" - process_line="lineto$1_$backend" - end="lineto$1_end_$backend" - - "$begin" - - while read -r str; do - # Skip comments and empty lines - test -z "${str%%#*}" && continue - - echo - # Process the line. The nop backend handles disabled lines. - if has_property "$str" "disable"; then - "lineto$1_nop" "$str" - enabled=0 - else - "$process_line" "$str" - enabled=1 - fi - if [ "$1" = "h" ]; then - name=$(get_name "$str") - NAME=$(echo $name | tr '[:lower:]' '[:upper:]') - echo "#define TRACE_${NAME}_ENABLED ${enabled}" - fi - done - - echo - "$end" -} - -tracetoh() -{ - cat <<EOF -#ifndef TRACE_H -#define TRACE_H - -/* This file is autogenerated by tracetool, do not edit. */ - -#include "qemu-common.h" -EOF - convert h - echo "#endif /* TRACE_H */" -} - -tracetoc() -{ - echo "/* This file is autogenerated by tracetool, do not edit. */" - convert c -} - -tracetod() -{ - if [ $backend != "dtrace" ]; then - echo "DTrace probe generator not applicable to $backend backend" - exit 1 - fi - echo "/* This file is autogenerated by tracetool, do not edit. */" - convert d -} - -tracetostap() -{ - if [ $backend != "dtrace" ]; then - echo "SystemTAP tapset generator not applicable to $backend backend" - exit 1 - fi - if [ -z "$binary" ]; then - echo "--binary is required for SystemTAP tapset generator" - exit 1 - fi - if [ -z "$probeprefix" -a -z "$targettype" ]; then - echo "--target-type is required for SystemTAP tapset generator" - exit 1 - fi - if [ -z "$probeprefix" -a -z "$targetarch" ]; then - echo "--target-arch is required for SystemTAP tapset generator" - exit 1 - fi - if [ -z "$probeprefix" ]; then - probeprefix="qemu.$targettype.$targetarch"; - fi - echo "/* This file is autogenerated by tracetool, do not edit. */" - convert stap -} - - -backend= -output= -binary= -targettype= -targetarch= -probeprefix= - - -until [ -z "$1" ] -do - case "$1" in - "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;; - - "--binary") shift ; binary="$1" ;; - "--target-arch") shift ; targetarch="$1" ;; - "--target-type") shift ; targettype="$1" ;; - "--probe-prefix") shift ; probeprefix="$1" ;; - - "-h" | "-c" | "-d") output="${1#-}" ;; - "--stap") output="${1#--}" ;; - - "--check-backend") exit 0 ;; # used by ./configure to test for backend - - "--list-backends") # used by ./configure to list available backends - echo "nop simple stderr ust dtrace" - exit 0 - ;; - - *) - usage;; - esac - shift -done - -if [ "$backend" = "" -o "$output" = "" ]; then - usage -fi - -gen="traceto$output" -"$gen" - -exit 0 diff --git a/scripts/tracetool.py b/scripts/tracetool.py new file mode 100755 index 0000000..91ae351 --- /dev/null +++ b/scripts/tracetool.py @@ -0,0 +1,533 @@ +#!/usr/bin/env python +# Code generator for trace events +# +# Copyright IBM, Corp. 2011 +# +# This work is licensed under the terms of the GNU GPL, version 2. See +# the COPYING file in the top-level directory. +# +# + +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) + +def get_name(line, sep='('): + head, sep, tail = line.partition(sep) + property, sep, name = head.rpartition(' ') + return name + +def get_properties(line, sep='('): + head, sep, tail = line.partition(sep) + property, sep, name = head.rpartition(' ') + return property.split() + +def get_args(line, sep1='(', sep2=')'): + head, sep1, tail = line.partition(sep1) + args, sep2, fmt_str = tail.partition(sep2) + return args + +def get_argnames(line, sep=','): + nfields = 0 + str = [] + args = get_args(line) + for field in args.split(): + nfields = nfields + 1 + # Drop pointer star + type, ptr, tail = field.partition('*') + if type != field: + field = tail + + name, sep, tail = field.partition(',') + + if name == field: + continue + str.append(name) + str.append(", ") + + if nfields > 1: + str.append(name) + return ''.join(str) + else: + return '' + +def get_argc(line): + argc = 0 + argnames = get_argnames(line) + if argnames: + for name in argnames.split(','): + argc = argc + 1 + return argc + +def get_fmt(line, sep=')'): + event, sep, fmt = line.partition(sep) + return fmt.rstrip('\n') + +def calc_sizeofargs(line): + args = get_args(line) + argc = get_argc(line) + str = [] + newstr = "" + if argc > 0: + str = args.split(',') + for elem in str: + if is_string(elem): #string + type, sep, var = elem.rpartition('*') + newstr = newstr+"4 + strlen("+var.lstrip()+") + " + else: + newstr = newstr + '8 + ' + newstr = newstr + '0' # takes care of last + + return newstr + + +def trace_h_begin(): + print '''#ifndef TRACE_H +#define TRACE_H + +/* This file is autogenerated by tracetool, do not edit. */ + +#include "qemu-common.h"''' + + +def trace_h_end(): + print '#endif /* TRACE_H */' + + +def trace_c_begin(): + print '/* This file is autogenerated by tracetool, do not edit. */' + +def trace_c_end(): + pass # nop, required for trace_gen + +def nop_h(events): + print + for event in events: + print '''static inline void trace_%(name)s(%(args)s) +{ +} +''' % { + 'name': event.name, + 'args': event.args +} + return + +def nop_c(events): + pass # nop, reqd for converters + +def simple_h(events): + print '#include "trace/simple.h"' + print + + for event in events: + if event.argc: + argstr = event.argnames.split() + arg_prefix = '(uint64_t)(uintptr_t)' + cast_args = arg_prefix + arg_prefix.join(argstr) + simple_args = (str(event.num) + ', ' + cast_args) + else: + simple_args = str(event.num) + + print '''static inline void trace_%(name)s(%(args)s) +{ + trace%(argc)d(%(trace_args)s); +}''' % { + 'name': event.name, + 'args': event.args, + 'argc': event.argc, + 'trace_args': simple_args +} + print + print '#define NR_TRACE_EVENTS %d' % (event.num + 1) + print 'extern TraceEvent trace_list[NR_TRACE_EVENTS];' + + +def is_string(arg): + strtype = ('const char*', 'char*', 'const char *', 'char *') + if arg.lstrip().startswith(strtype): + return True + else: + return False + +def simple_c(events): + print '#include "trace.h"' + print + print 'TraceEvent trace_list[] = {' + print + + for event in events: + print '{.tp_name = "%(name)s", .state=0},' % { + 'name': event.name, +} + print + print '};' + +def stderr_h(events): + print '''#include <stdio.h> +#include "trace/stderr.h" + +extern TraceEvent trace_list[];''' + for event in events: + argnames = event.argnames + if event.argc > 0: + argnames = ', ' + event.argnames + else: + argnames = '' + print ''' +static inline void trace_%(name)s(%(args)s) +{ + if (trace_list[%(event_num)s].state != 0) { + fprintf(stderr, "%(name)s " %(fmt)s "\\n" %(argnames)s); + } +}''' % { + 'name': event.name, + 'args': event.args, + 'event_num': event.num, + 'fmt': event.fmt, + 'argnames': argnames +} + print + print '#define NR_TRACE_EVENTS %d' % (event.num + 1) + +def stderr_c(events): + print '''#include "trace.h" + +TraceEvent trace_list[] = { +''' + for event in events: + print '{.tp_name = "%(name)s", .state=0},' % { + 'name': event.name +} + print + print '};' + +def ust_h(events): + print '''#include <ust/tracepoint.h> +#undef mutex_lock +#undef mutex_unlock +#undef inline +#undef wmb''' + + for event in events: + if event.argc > 0: + print ''' +DECLARE_TRACE(ust_%(name)s, TP_PROTO(%(args)s), TP_ARGS(%(argnames)s)); +#define trace_%(name)s trace_ust_%(name)s''' % { + 'name': event.name, + 'args': event.args, + 'argnames': event.argnames +} + else: + print ''' +_DECLARE_TRACEPOINT_NOARGS(ust_%(name)s); +#define trace_%(name)s trace_ust_%(name)s''' % { + 'name': event.name, +} + print + +def ust_c(events): + print '''#include <ust/marker.h> +#undef mutex_lock +#undef mutex_unlock +#undef inline +#undef wmb +#include "trace.h"''' + eventlist = list(events) + for event in eventlist: + argnames = event.argnames + if event.argc > 0: + argnames = ', ' + event.argnames + print ''' +DEFINE_TRACE(ust_%(name)s); + +static void ust_%(name)s_probe(%(args)s) +{ + trace_mark(ust, %(name)s, %(fmt)s%(argnames)s); +}''' % { + 'name': event.name, + 'args': event.args, + 'fmt': event.fmt, + 'argnames': argnames +} + else: + print ''' +DEFINE_TRACE(ust_%(name)s); + +static void ust_%(name)s_probe(%(args)s) +{ + trace_mark(ust, %(name)s, UST_MARKER_NOARGS); +}''' % { + 'name': event.name, + 'args': event.args, +} + + # register probes + print ''' +static void __attribute__((constructor)) trace_init(void) +{''' + for event in eventlist: + print ' register_trace_ust_%(name)s(ust_%(name)s_probe);' % { + 'name': event.name +} + print '}' + +def dtrace_h(events): + print '#include "trace-dtrace.h"' + print + for event in events: + print '''static inline void trace_%(name)s(%(args)s) { + QEMU_%(uppername)s(%(argnames)s); +} +''' % { + 'name': event.name, + 'args': event.args, + 'uppername': event.name.upper(), + 'argnames': event.argnames, +} + +def dtrace_c(events): + pass # No need for function definitions in dtrace backend + +def dtrace_d(events): + print 'provider qemu {' + for event in events: + args = event.args + + # DTrace provider syntax expects foo() for empty + # params, not foo(void) + if args == 'void': + args = '' + + # Define prototype for probe arguments + print ''' + probe %(name)s(%(args)s);''' % { + 'name': event.name, + 'args': args +} + print + print '};' + +def dtrace_stp(events): + for event in events: + # Define prototype for probe arguments + print ''' +probe %(probeprefix)s.%(name)s = process("%(binary)s").mark("%(name)s") +{''' % { + 'probeprefix': probeprefix, + 'name': event.name, + 'binary': binary +} + i = 1 + if event.argc > 0: + for arg in event.argnames.split(','): + # 'limit' is a reserved keyword + if arg == 'limit': + arg = '_limit' + print ' %s = $arg%d;' % (arg.lstrip(), i) + i += 1 + print '}' + print + +def trace_stap_begin(): + print '/* This file is autogenerated by tracetool, do not edit. */' + +def trace_stap_end(): + pass #nop, reqd for trace_gen + +def trace_d_begin(): + print '/* This file is autogenerated by tracetool, do not edit. */' + +def trace_d_end(): + pass #nop, reqd for trace_gen + + +# Registry of backends and their converter functions +converters = { + 'simple': { + 'h': simple_h, + 'c': simple_c, + }, + + 'nop': { + 'h': nop_h, + 'c': nop_c, + }, + + '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 +trace_gen = { + 'h': { + 'begin': trace_h_begin, + 'end': trace_h_end, + }, + 'c': { + 'begin': trace_c_begin, + 'end': trace_c_end, + }, + 'd': { + 'begin': trace_d_begin, + 'end': trace_d_end, + }, + 'stap': { + 'begin': trace_stap_begin, + 'end': trace_stap_end, + }, +} + +# A trace event +class Event(object): + def __init__(self, num, line): + self.num = num + self.args = get_args(line) + self.arglist = self.args.split(',') + self.name = get_name(line) + self.argc = get_argc(line) + self.argnames = get_argnames(line) + self.sizestr = calc_sizeofargs(line) + self.fmt = get_fmt(line) + self.properties = get_properties(line) + +# Generator that yields Event objects given a trace-events file object +def read_events(fobj): + event_num = 0 + for line in fobj: + if not line.strip(): + continue + if line.lstrip().startswith('#'): + continue + yield Event(event_num, line) + event_num += 1 + +binary = "" +probeprefix = "" + +def main(): + global binary, probeprefix + targettype = "" + targetarch = "" + backend = "" + 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"] + try: + opts, args = getopt.getopt(sys.argv[1:], short_options, 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' + elif opt == '--backend': + backend = arg + elif opt == '--binary': + binary = arg + elif opt == '--target-arch': + targetarch = arg + elif opt == '--target-type': + targettype = arg + elif opt == '--probe-prefix': + probeprefix = arg + elif opt == '--list-backends': + print 'simple, nop, stderr, dtrace, ust' + sys.exit(0) + elif opt == "--check-backend": + if backend in supported_backends: + sys.exit(0) + else: + sys.exit(1) + else: + #assert False, "unhandled option" + print "unhandled option: ", opt + usage() + + if backend == "" or output == "": + usage() + sys.exit(0) + + if backend != 'dtrace' and output == 'd': + print 'DTrace probe generator not applicable to %s backend' % backend + sys.exit(1) + + if output == 'stap': + 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 not probeprefix and not targettype: + print '--target-type is required for SystemTAP tapset generator' + sys.exit(1) + if not probeprefix and not targetarch: + print '--target-arch is required for SystemTAP tapset generator' + sys.exit(1) + if probeprefix == "": + probeprefix = 'qemu.' + targettype + '.' + targetarch + + disabled_events, enabled_events = [], [] + for e in read_events(sys.stdin): + if 'disable' in e.properties: + disabled_events.append(e) + else: + enabled_events.append(e) + + trace_gen[output]['begin']() + if output == 'h': # disabled events + converters['nop'][output](disabled_events) + converters[backend][output](enabled_events) + trace_gen[output]['end']() + +if __name__ == "__main__": + main() +