diff --git a/MAINTAINERS b/MAINTAINERS
index 922945c920..cce37e797f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -553,6 +553,8 @@ Tracing
 M: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
 S: Maintained
 F: trace/
+F: scripts/tracetool.py
+F: scripts/tracetool/
 F: docs/tracing.txt
 T: git://github.com/stefanha/qemu.git tracing
 
diff --git a/Makefile.objs b/Makefile.objs
index 5c3bcdaa39..6d6f24d9d3 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -378,12 +378,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 --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,sh $(SRC_PATH)/scripts/tracetool --$(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)
@@ -396,7 +396,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 --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)
diff --git a/Makefile.target b/Makefile.target
index 84951a09ec..a0540cd663 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -59,12 +59,13 @@ TARGET_TYPE=system
 endif
 
 $(QEMU_PROG).stp: $(SRC_PATH)/trace-events
-	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool \
-		--$(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")
+	$(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) \
+		< $(SRC_PATH)/trace-events > $(QEMU_PROG).stp,"  GEN   $(QEMU_PROG).stp")
 else
 stap:
 endif
diff --git a/configure b/configure
index 2d62d12796..03b49f6b70 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"
@@ -2670,7 +2670,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 7b1c142b67..0000000000
--- a/scripts/tracetool
+++ /dev/null
@@ -1,666 +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"
-
-    if (echo "$args" | grep "[ *]next\($\|[, ]\)" > /dev/null 2>&1); then
-        echo -e "\n#error 'next' is a bad argument name (clash with systemtap keyword)\n "
-    fi
-}
-
-# 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
-}
-
-linetod_nop()
-{
-    # Used when "disabled" events are processed
-    return
-}
-
-linetostap_nop()
-{
-    # Used when "disabled" events are processed
-    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 | LC_ALL=C tr '[a-z]' '[A-Z]'`
-
-    # 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
-        # postfix reserved words with '_'
-        case "$arg" in
-            limit|in|next|self)
-                arg="${arg}_"
-                ;;
-        esac
-        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 | LC_ALL=C tr '[a-z]' '[A-Z]')
-            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 0000000000..cacfd99b62
--- /dev/null
+++ b/scripts/tracetool.py
@@ -0,0 +1,138 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Command-line wrapper for the tracetool machinery.
+"""
+
+__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha@linux.vnet.ibm.com"
+
+
+import sys
+import getopt
+
+from tracetool import error_write, out
+import tracetool.backend
+import tracetool.format
+
+
+_SCRIPT = ""
+
+def error_opt(msg = None):
+    if msg is not None:
+        error_write("Error: " + msg + "\n")
+
+    backend_descr = "\n".join([ "    %-15s %s" % (n, d)
+                                for n,d in tracetool.backend.get_list() ])
+    format_descr = "\n".join([ "    %-15s %s" % (n, d)
+                               for n,d in tracetool.format.get_list() ])
+    error_write("""\
+Usage: %(script)s --format=<format> --backend=<backend> [<options>]
+
+Backends:
+%(backends)s
+
+Formats:
+%(formats)s
+
+Options:
+    --help                   This help message.
+    --list-backends          Print list of available backends.
+    --check-backend          Check if the given backend is valid.
+    --binary <path>          Full path to QEMU binary.
+    --target-type <type>     QEMU emulator target type ('system' or 'user').
+    --target-arch <arch>     QEMU emulator target arch.
+    --probe-prefix <prefix>  Prefix for dtrace probe names
+                             (default: qemu-<target-type>-<target-arch>).\
+""" % {
+            "script" : _SCRIPT,
+            "backends" : backend_descr,
+            "formats" : format_descr,
+            })
+
+    if msg is None:
+        sys.exit(0)
+    else:
+        sys.exit(1)
+
+
+def main(args):
+    global _SCRIPT
+    _SCRIPT = args[0]
+
+    long_opts  = [ "backend=", "format=", "help", "list-backends", "check-backend" ]
+    long_opts += [ "binary=", "target-type=", "target-arch=", "probe-prefix=" ]
+
+    try:
+        opts, args = getopt.getopt(args[1:], "", long_opts)
+    except getopt.GetoptError as err:
+        error_opt(str(err))
+
+    check_backend = False
+    arg_backend = ""
+    arg_format = ""
+    binary = None
+    target_type = None
+    target_arch = None
+    probe_prefix = None
+    for opt, arg in opts:
+        if opt == "--help":
+            error_opt()
+
+        elif opt == "--backend":
+            arg_backend = arg
+        elif opt == "--format":
+            arg_format = arg
+
+        elif opt == "--list-backends":
+            backends = tracetool.backend.get_list()
+            out(", ".join([ b for b,_ in backends ]))
+            sys.exit(0)
+        elif opt == "--check-backend":
+            check_backend = True
+
+        elif opt == "--binary":
+            binary = arg
+        elif opt == '--target-type':
+            target_type = arg
+        elif opt == '--target-arch':
+            target_arch = arg
+        elif opt == '--probe-prefix':
+            probe_prefix = arg
+
+        else:
+            error_opt("unhandled option: %s" % opt)
+
+    if arg_backend is None:
+        error_opt("backend not set")
+
+    if check_backend:
+        if tracetool.backend.exists(arg_backend):
+            sys.exit(0)
+        else:
+            sys.exit(1)
+
+    if arg_format == "stap":
+        if binary is None:
+            error_opt("--binary is required for SystemTAP tapset generator")
+        if probe_prefix is None and target_type is None:
+            error_opt("--target-type is required for SystemTAP tapset generator")
+        if probe_prefix is None and target_arch is None:
+            error_opt("--target-arch is required for SystemTAP tapset generator")
+
+        if probe_prefix is None:
+            probe_prefix = ".".join([ "qemu", target_type, target_arch ])
+
+    try:
+        tracetool.generate(sys.stdin, arg_format, arg_backend,
+                           binary = binary, probe_prefix = probe_prefix)
+    except tracetool.TracetoolError as e:
+        error_opt(str(e))
+
+if __name__ == "__main__":
+    main(sys.argv)
diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py
new file mode 100644
index 0000000000..74fe21b226
--- /dev/null
+++ b/scripts/tracetool/__init__.py
@@ -0,0 +1,271 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Machinery for generating tracing-related intermediate files.
+"""
+
+__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha@linux.vnet.ibm.com"
+
+
+import re
+import sys
+
+import tracetool.format
+import tracetool.backend
+
+
+def error_write(*lines):
+    """Write a set of error lines."""
+    sys.stderr.writelines("\n".join(lines) + "\n")
+
+def error(*lines):
+    """Write a set of error lines and exit."""
+    error_write(*lines)
+    sys.exit(1)
+
+
+def out(*lines, **kwargs):
+    """Write a set of output lines.
+
+    You can use kwargs as a shorthand for mapping variables when formating all
+    the strings in lines.
+    """
+    lines = [ l % kwargs for l in lines ]
+    sys.stdout.writelines("\n".join(lines) + "\n")
+
+
+class Arguments:
+    """Event arguments description."""
+
+    def __init__(self, args):
+        """
+        Parameters
+        ----------
+        args :
+            List of (type, name) tuples.
+        """
+        self._args = args
+
+    @staticmethod
+    def build(arg_str):
+        """Build and Arguments instance from an argument string.
+
+        Parameters
+        ----------
+        arg_str : str
+            String describing the event arguments.
+        """
+        res = []
+        for arg in arg_str.split(","):
+            arg = arg.strip()
+            parts = arg.split()
+            head, sep, tail = parts[-1].rpartition("*")
+            parts = parts[:-1]
+            if tail == "void":
+                assert len(parts) == 0 and sep == ""
+                continue
+            arg_type = " ".join(parts + [ " ".join([head, sep]).strip() ]).strip()
+            res.append((arg_type, tail))
+        return Arguments(res)
+
+    def __iter__(self):
+        """Iterate over the (type, name) pairs."""
+        return iter(self._args)
+
+    def __len__(self):
+        """Number of arguments."""
+        return len(self._args)
+
+    def __str__(self):
+        """String suitable for declaring function arguments."""
+        if len(self._args) == 0:
+            return "void"
+        else:
+            return ", ".join([ " ".join([t, n]) for t,n in self._args ])
+
+    def __repr__(self):
+        """Evaluable string representation for this object."""
+        return "Arguments(\"%s\")" % str(self)
+
+    def names(self):
+        """List of argument names."""
+        return [ name for _, name in self._args ]
+
+    def types(self):
+        """List of argument types."""
+        return [ type_ for type_, _ in self._args ]
+
+
+class Event(object):
+    """Event description.
+
+    Attributes
+    ----------
+    name : str
+        The event name.
+    fmt : str
+        The event format string.
+    properties : set(str)
+        Properties of the event.
+    args : Arguments
+        The event arguments.
+    """
+
+    _CRE = re.compile("((?P<props>.*)\s+)?(?P<name>[^(\s]+)\((?P<args>[^)]*)\)\s*(?P<fmt>\".*)?")
+
+    _VALID_PROPS = set(["disable"])
+
+    def __init__(self, name, props, fmt, args):
+        """
+        Parameters
+        ----------
+        name : string
+            Event name.
+        props : list of str
+            Property names.
+        fmt : str
+            Event printing format.
+        args : Arguments
+            Event arguments.
+        """
+        self.name = name
+        self.properties = props
+        self.fmt = fmt
+        self.args = args
+
+        unknown_props = set(self.properties) - self._VALID_PROPS
+        if len(unknown_props) > 0:
+            raise ValueError("Unknown properties: %s" % ", ".join(unknown_props))
+
+    @staticmethod
+    def build(line_str):
+        """Build an Event instance from a string.
+
+        Parameters
+        ----------
+        line_str : str
+            Line describing the event.
+        """
+        m = Event._CRE.match(line_str)
+        assert m is not None
+        groups = m.groupdict('')
+
+        name = groups["name"]
+        props = groups["props"].split()
+        fmt = groups["fmt"]
+        args = Arguments.build(groups["args"])
+
+        return Event(name, props, fmt, args)
+
+    def __repr__(self):
+        """Evaluable string representation for this object."""
+        return "Event('%s %s(%s) %s')" % (" ".join(self.properties),
+                                          self.name,
+                                          self.args,
+                                          self.fmt)
+
+def _read_events(fobj):
+    res = []
+    for line in fobj:
+        if not line.strip():
+            continue
+        if line.lstrip().startswith('#'):
+            continue
+        res.append(Event.build(line))
+    return res
+
+
+class TracetoolError (Exception):
+    """Exception for calls to generate."""
+    pass
+
+
+def try_import(mod_name, attr_name = None, attr_default = None):
+    """Try to import a module and get an attribute from it.
+
+    Parameters
+    ----------
+    mod_name : str
+        Module name.
+    attr_name : str, optional
+        Name of an attribute in the module.
+    attr_default : optional
+        Default value if the attribute does not exist in the module.
+
+    Returns
+    -------
+    A pair indicating whether the module could be imported and the module or
+    object or attribute value.
+    """
+    try:
+        module = __import__(mod_name, fromlist=["__package__"])
+        if attr_name is None:
+            return True, module
+        return True, getattr(module, str(attr_name), attr_default)
+    except ImportError:
+        return False, None
+
+
+def generate(fevents, format, backend,
+             binary = None, probe_prefix = None):
+    """Generate the output for the given (format, backend) pair.
+
+    Parameters
+    ----------
+    fevents : file
+        Event description file.
+    format : str
+        Output format name.
+    backend : str
+        Output backend name.
+    binary : str or None
+        See tracetool.backend.dtrace.BINARY.
+    probe_prefix : str or None
+        See tracetool.backend.dtrace.PROBEPREFIX.
+    """
+    # fix strange python error (UnboundLocalError tracetool)
+    import tracetool
+
+    format = str(format)
+    if len(format) is 0:
+        raise TracetoolError("format not set")
+    mformat = format.replace("-", "_")
+    if not tracetool.format.exists(mformat):
+        raise TracetoolError("unknown format: %s" % format)
+
+    backend = str(backend)
+    if len(backend) is 0:
+        raise TracetoolError("backend not set")
+    mbackend = backend.replace("-", "_")
+    if not tracetool.backend.exists(mbackend):
+        raise TracetoolError("unknown backend: %s" % backend)
+
+    if not tracetool.backend.compatible(mbackend, mformat):
+        raise TracetoolError("backend '%s' not compatible with format '%s'" %
+                             (backend, format))
+
+    import tracetool.backend.dtrace
+    tracetool.backend.dtrace.BINARY = binary
+    tracetool.backend.dtrace.PROBEPREFIX = probe_prefix
+
+    events = _read_events(fevents)
+
+    if backend == "nop":
+        ( e.properies.add("disable") for e in events )
+
+    tracetool.format.generate_begin(mformat, events)
+    tracetool.backend.generate("nop", format,
+                               [ e
+                                 for e in events
+                                 if "disable" in e.properties ])
+    tracetool.backend.generate(backend, format,
+                               [ e
+                                 for e in events
+                                 if "disable" not in e.properties ])
+    tracetool.format.generate_end(mformat, events)
diff --git a/scripts/tracetool/backend/__init__.py b/scripts/tracetool/backend/__init__.py
new file mode 100644
index 0000000000..34b7ed8081
--- /dev/null
+++ b/scripts/tracetool/backend/__init__.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Backend management.
+
+
+Creating new backends
+---------------------
+
+A new backend named 'foo-bar' corresponds to Python module
+'tracetool/backend/foo_bar.py'.
+
+A backend module should provide a docstring, whose first non-empty line will be
+considered its short description.
+
+All backends must generate their contents through the 'tracetool.out' routine.
+
+
+Backend functions
+-----------------
+
+======== =======================================================================
+Function Description
+======== =======================================================================
+<format> Called to generate the format- and backend-specific code for each of
+         the specified events. If the function does not exist, the backend is
+         considered not compatible with the given format.
+======== =======================================================================
+"""
+
+__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha@linux.vnet.ibm.com"
+
+
+import pkgutil
+
+import tracetool
+
+
+def get_list():
+    """Get a list of (name, description) pairs."""
+    res = [("nop", "Tracing disabled.")]
+    for _, modname, _ in pkgutil.iter_modules(tracetool.backend.__path__):
+        module = tracetool.try_import("tracetool.backend." + modname)
+
+        # just in case; should never fail unless non-module files are put there
+        if not module[0]:
+            continue
+        module = module[1]
+
+        doc = module.__doc__
+        if doc is None:
+            doc = ""
+        doc = doc.strip().split("\n")[0]
+
+        name = modname.replace("_", "-")
+        res.append((name, doc))
+    return res
+
+
+def exists(name):
+    """Return whether the given backend exists."""
+    if len(name) == 0:
+        return False
+    if name == "nop":
+        return True
+    name = name.replace("-", "_")
+    return tracetool.try_import("tracetool.backend." + name)[1]
+
+
+def compatible(backend, format):
+    """Whether a backend is compatible with the given format."""
+    if not exists(backend):
+        raise ValueError("unknown backend: %s" % backend)
+
+    backend = backend.replace("-", "_")
+    format = format.replace("-", "_")
+
+    if backend == "nop":
+        return True
+    else:
+        func = tracetool.try_import("tracetool.backend." + backend,
+                                    format, None)[1]
+        return func is not None
+
+
+def _empty(events):
+    pass
+
+def generate(backend, format, events):
+    """Generate the per-event output for the given (backend, format) pair."""
+    if not compatible(backend, format):
+        raise ValueError("backend '%s' not compatible with format '%s'" %
+                         (backend, format))
+
+    backend = backend.replace("-", "_")
+    format = format.replace("-", "_")
+
+    if backend == "nop":
+        func = tracetool.try_import("tracetool.format." + format,
+                                    "nop", _empty)[1]
+    else:
+        func = tracetool.try_import("tracetool.backend." + backend,
+                                    format, None)[1]
+
+    func(events)
diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py
new file mode 100644
index 0000000000..9cab75cde8
--- /dev/null
+++ b/scripts/tracetool/backend/dtrace.py
@@ -0,0 +1,97 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+DTrace/SystemTAP backend.
+"""
+
+__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+PROBEPREFIX = None
+
+def _probeprefix():
+    if PROBEPREFIX is None:
+        raise ValueError("you must set PROBEPREFIX")
+    return PROBEPREFIX
+
+
+BINARY = None
+
+def _binary():
+    if BINARY is None:
+        raise ValueError("you must set BINARY")
+    return BINARY
+
+
+def c(events):
+    pass
+
+
+def h(events):
+    out('#include "trace-dtrace.h"',
+        '')
+
+    for e in events:
+        out('static inline void trace_%(name)s(%(args)s) {',
+            '    QEMU_%(uppername)s(%(argnames)s);',
+            '}',
+            name = e.name,
+            args = e.args,
+            uppername = e.name.upper(),
+            argnames = ", ".join(e.args.names()),
+            )
+
+
+def d(events):
+    out('provider qemu {')
+
+    for e in events:
+        args = str(e.args)
+
+        # DTrace provider syntax expects foo() for empty
+        # params, not foo(void)
+        if args == 'void':
+            args = ''
+
+        # Define prototype for probe arguments
+        out('',
+            'probe %(name)s(%(args)s);',
+            name = e.name,
+            args = args,
+            )
+
+    out('',
+        '};')
+
+
+def stap(events):
+    for e in events:
+        # Define prototype for probe arguments
+        out('probe %(probeprefix)s.%(name)s = process("%(binary)s").mark("%(name)s")',
+            '{',
+            probeprefix = _probeprefix(),
+            name = e.name,
+            binary = _binary(),
+            )
+
+        i = 1
+        if len(e.args) > 0:
+            for name in e.args.names():
+                # Append underscore to reserved keywords
+                if name in ('limit', 'in', 'next', 'self'):
+                    name += '_'
+                out('  %s = $arg%d;' % (name, i))
+                i += 1
+
+        out('}')
+
+    out()
diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py
new file mode 100644
index 0000000000..fbb5717c66
--- /dev/null
+++ b/scripts/tracetool/backend/simple.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Simple built-in backend.
+"""
+
+__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def c(events):
+    out('#include "trace.h"',
+        '',
+        'TraceEvent trace_list[] = {')
+
+    for e in events:
+        out('{.tp_name = "%(name)s", .state=0},',
+            name = e.name,
+            )
+
+    out('};')
+
+def h(events):
+    out('#include "trace/simple.h"',
+        '')
+
+    for num, e in enumerate(events):
+        if len(e.args):
+            argstr = e.args.names()
+            arg_prefix = ', (uint64_t)(uintptr_t)'
+            cast_args = arg_prefix + arg_prefix.join(argstr)
+            simple_args = (str(num) + cast_args)
+        else:
+            simple_args = str(num)
+
+        out('static inline void trace_%(name)s(%(args)s)',
+            '{',
+            '    trace%(argc)d(%(trace_args)s);',
+            '}',
+            name = e.name,
+            args = e.args,
+            argc = len(e.args),
+            trace_args = simple_args,
+            )
+
+    out('#define NR_TRACE_EVENTS %d' % len(events))
+    out('extern TraceEvent trace_list[NR_TRACE_EVENTS];')
diff --git a/scripts/tracetool/backend/stderr.py b/scripts/tracetool/backend/stderr.py
new file mode 100644
index 0000000000..917fde7c15
--- /dev/null
+++ b/scripts/tracetool/backend/stderr.py
@@ -0,0 +1,56 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Stderr built-in backend.
+"""
+
+__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def c(events):
+    out('#include "trace.h"',
+        '',
+        'TraceEvent trace_list[] = {')
+
+    for e in events:
+        out('{.tp_name = "%(name)s", .state=0},',
+            name = e.name,
+            )
+
+    out('};')
+
+def h(events):
+    out('#include <stdio.h>',
+        '#include "trace/stderr.h"',
+        '',
+        'extern TraceEvent trace_list[];')
+
+    for num, e in enumerate(events):
+        argnames = ", ".join(e.args.names())
+        if len(e.args) > 0:
+            argnames = ", " + argnames
+
+        out('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 = e.name,
+            args = e.args,
+            event_num = num,
+            fmt = e.fmt,
+            argnames = argnames,
+            )
+
+    out('',
+        '#define NR_TRACE_EVENTS %d' % len(events))
diff --git a/scripts/tracetool/backend/ust.py b/scripts/tracetool/backend/ust.py
new file mode 100644
index 0000000000..31a2ff0404
--- /dev/null
+++ b/scripts/tracetool/backend/ust.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+LTTng User Space Tracing backend.
+"""
+
+__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def c(events):
+    out('#include <ust/marker.h>',
+        '#undef mutex_lock',
+        '#undef mutex_unlock',
+        '#undef inline',
+        '#undef wmb',
+        '#include "trace.h"')
+
+    for e in events:
+        argnames = ", ".join(e.args.names())
+        if len(e.args) > 0:
+            argnames = ', ' + argnames
+
+            out('DEFINE_TRACE(ust_%(name)s);',
+                '',
+                'static void ust_%(name)s_probe(%(args)s)',
+                '{',
+                '    trace_mark(ust, %(name)s, %(fmt)s%(argnames)s);',
+                '}',
+                name = e.name,
+                args = e.args,
+                fmt = e.fmt,
+                argnames = argnames,
+                )
+
+        else:
+            out('DEFINE_TRACE(ust_%(name)s);',
+                '',
+                'static void ust_%(name)s_probe(%(args)s)',
+                '{',
+                '    trace_mark(ust, %(name)s, UST_MARKER_NOARGS);',
+                '}',
+                name = e.name,
+                args = e.args,
+                )
+
+    # register probes
+    out('',
+        'static void __attribute__((constructor)) trace_init(void)',
+        '{')
+
+    for e in events:
+        out('    register_trace_ust_%(name)s(ust_%(name)s_probe);',
+            name = e.name,
+            )
+
+    out('}')
+
+
+def h(events):
+    out('#include <ust/tracepoint.h>',
+        '#undef mutex_lock',
+        '#undef mutex_unlock',
+        '#undef inline',
+        '#undef wmb')
+
+    for e in events:
+        if len(e.args) > 0:
+            out('DECLARE_TRACE(ust_%(name)s, TP_PROTO(%(args)s), TP_ARGS(%(argnames)s));',
+                '#define trace_%(name)s trace_ust_%(name)s',
+                name = e.name,
+                args = e.args,
+                argnames = ", ".join(e.args.names()),
+                )
+
+        else:
+            out('_DECLARE_TRACEPOINT_NOARGS(ust_%(name)s);',
+                '#define trace_%(name)s trace_ust_%(name)s',
+                name = e.name,
+                )
+
+    out()
diff --git a/scripts/tracetool/format/__init__.py b/scripts/tracetool/format/__init__.py
new file mode 100644
index 0000000000..0e4baf0e56
--- /dev/null
+++ b/scripts/tracetool/format/__init__.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Format management.
+
+
+Creating new formats
+--------------------
+
+A new format named 'foo-bar' corresponds to Python module
+'tracetool/format/foo_bar.py'.
+
+A format module should provide a docstring, whose first non-empty line will be
+considered its short description.
+
+All formats must generate their contents through the 'tracetool.out' routine.
+
+
+Format functions
+----------------
+
+All the following functions are optional, and no output will be generated if
+they do not exist.
+
+======== =======================================================================
+Function Description
+======== =======================================================================
+begin    Called to generate the format-specific file header.
+end      Called to generate the format-specific file footer.
+nop      Called to generate the per-event contents when the event is disabled or
+         the selected backend is 'nop'.
+======== =======================================================================
+"""
+
+__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha@linux.vnet.ibm.com"
+
+
+import pkgutil
+
+import tracetool
+
+
+def get_list():
+    """Get a list of (name, description) pairs."""
+    res = []
+    for _, modname, _ in pkgutil.iter_modules(tracetool.format.__path__):
+        module = tracetool.try_import("tracetool.format." + modname)
+
+        # just in case; should never fail unless non-module files are put there
+        if not module[0]:
+            continue
+        module = module[1]
+
+        doc = module.__doc__
+        if doc is None:
+            doc = ""
+        doc = doc.strip().split("\n")[0]
+
+        name = modname.replace("_", "-")
+        res.append((name, doc))
+    return res
+
+
+def exists(name):
+    """Return whether the given format exists."""
+    if len(name) == 0:
+        return False
+    name = name.replace("-", "_")
+    return tracetool.try_import("tracetool.format." + name)[1]
+
+
+def _empty(events):
+    pass
+
+def generate_begin(name, events):
+    """Generate the header of the format-specific file."""
+    if not exists(name):
+        raise ValueError("unknown format: %s" % name)
+
+    name = name.replace("-", "_")
+    func = tracetool.try_import("tracetool.format." + name,
+                                "begin", _empty)[1]
+    func(events)
+
+def generate_end(name, events):
+    """Generate the footer of the format-specific file."""
+    if not exists(name):
+        raise ValueError("unknown format: %s" % name)
+
+    name = name.replace("-", "_")
+    func = tracetool.try_import("tracetool.format." + name,
+                                "end", _empty)[1]
+    func(events)
diff --git a/scripts/tracetool/format/c.py b/scripts/tracetool/format/c.py
new file mode 100644
index 0000000000..35555aee1f
--- /dev/null
+++ b/scripts/tracetool/format/c.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .c file.
+"""
+
+__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+    out('/* This file is autogenerated by tracetool, do not edit. */')
diff --git a/scripts/tracetool/format/d.py b/scripts/tracetool/format/d.py
new file mode 100644
index 0000000000..a2d594773c
--- /dev/null
+++ b/scripts/tracetool/format/d.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .d file (DTrace only).
+"""
+
+__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+    out('/* This file is autogenerated by tracetool, do not edit. */')
diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py
new file mode 100644
index 0000000000..6ffb3c2f4e
--- /dev/null
+++ b/scripts/tracetool/format/h.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .h file.
+"""
+
+__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+    out('/* This file is autogenerated by tracetool, do not edit. */',
+        '',
+        '#ifndef TRACE_H',
+        '#define TRACE_H',
+        '',
+        '#include "qemu-common.h"')
+
+def end(events):
+    for e in events:
+        if "disable" in e.properties:
+            enabled = 0
+        else:
+            enabled = 1
+        out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled))
+    out('',
+        '#endif /* TRACE_H */')
+
+def nop(events):
+    for e in events:
+        out('',
+            'static inline void trace_%(name)s(%(args)s)',
+            '{',
+            '}',
+            name = e.name,
+            args = e.args,
+            )
diff --git a/scripts/tracetool/format/stap.py b/scripts/tracetool/format/stap.py
new file mode 100644
index 0000000000..50a4c69954
--- /dev/null
+++ b/scripts/tracetool/format/stap.py
@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .stp file (DTrace with SystemTAP only).
+"""
+
+__author__     = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__  = "Copyright 2012, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__    = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__      = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+    out('/* This file is autogenerated by tracetool, do not edit. */')