diff --git a/.gitignore b/.gitignore
index 406f75f..d47b586 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ trace.h
 trace.c
 trace-dtrace.h
 trace-dtrace.dtrace
+trace-tcg-helper.h
 *-timestamp
 *-softmmu
 *-darwin-user
diff --git a/Makefile b/Makefile
index 506db1b..516622a 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@ BUILD_DIR=$(CURDIR)
 
 GENERATED_HEADERS = config-host.h qemu-options.def
 
-GENERATED_HEADERS += trace.h
+GENERATED_HEADERS += trace.h trace-tcg-helper.h
 ifeq ($(TRACE_BACKEND),dtrace)
 GENERATED_HEADERS += trace-dtrace.h
 endif
diff --git a/Makefile.objs b/Makefile.objs
index d7a6539..8f97709 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -398,6 +398,15 @@ trace-obj-y += $(addprefix trace/, $(trace-nested-y))
 $(trace-obj-y): $(GENERATED_HEADERS)
 
 ######################################################################
+# trace tcg
+
+trace-tcg-helper.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
+	$(call quiet-command,sh $(SRC_PATH)/scripts/tracetool $(TRACETOOL_EXTRA) --tcg --tcg-h < $< > $@,"  GEN	$(TARGET_DIR)trace-tcg-helper.h")
+	@cmp -s $@ trace-tcg-helper.h || cp $@ trace-tcg-helper.h
+
+trace-tcg-helper.h: trace-tcg-helper.h-timestamp
+
+######################################################################
 # smartcard
 
 libcacard-y = cac.o event.o vcard.o vreader.o vcard_emul_nss.o vcard_emul_type.o card_7816.o
diff --git a/def-helper.h b/def-helper.h
index 8a822c7..c4fce2d 100644
--- a/def-helper.h
+++ b/def-helper.h
@@ -13,6 +13,11 @@
    helper.c, defining:
     GEN_HELPER 1 to produce op generation functions (gen_helper_*)
     GEN_HELPER 2 to do runtime registration helper functions.
+
+   After including this header the GEN_HELPER_MACRO will have the following
+   values:
+    1  : op generation functions were produced (GEN_HELPER was 1)
+    -1 : otherwise
  */
 
 #ifndef DEF_HELPER_H
@@ -142,6 +147,7 @@ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
 
 #undef GEN_HELPER
 #define GEN_HELPER -1
+#define GEN_HELPER_CODE -1
 
 #elif GEN_HELPER == 1
 /* Gen functions.  */
@@ -205,6 +211,7 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) dh_arg_decl(t1, 1
 
 #undef GEN_HELPER
 #define GEN_HELPER -1
+#define GEN_HELPER_CODE 1
 
 #elif GEN_HELPER == 2
 /* Register helpers.  */
@@ -226,6 +233,7 @@ DEF_HELPER_FLAGS_0(name, flags, ret)
 
 #undef GEN_HELPER
 #define GEN_HELPER -1
+#define GEN_HELPER_CODE -1
 
 #elif GEN_HELPER == -1
 /* Undefine macros.  */
@@ -236,5 +244,6 @@ DEF_HELPER_FLAGS_0(name, flags, ret)
 #undef DEF_HELPER_FLAGS_3
 #undef DEF_HELPER_FLAGS_4
 #undef GEN_HELPER
+#undef GEN_HELPER_CODE
 
 #endif
diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py
index f55e5e6..3476d6c 100755
--- a/scripts/simpletrace.py
+++ b/scripts/simpletrace.py
@@ -20,7 +20,7 @@ dropped_event_id = 0xfffffffffffffffe
 
 trace_fmt = '=QQQQQQQQ'
 trace_len = struct.calcsize(trace_fmt)
-event_re  = re.compile(r'(disable\s+)?([a-zA-Z0-9_]+)\(([^)]*)\).*')
+event_re  = re.compile(r'(disable\s+|tcg\s+|tcg-vcpu\s+)*([a-zA-Z0-9_]+)\(([^)]*)\).*')
 
 def parse_events(fobj):
     """Parse a trace-events file into {event_num: (name, arg1, ...)}."""
diff --git a/scripts/tracetool b/scripts/tracetool
index 1d8a637..5431f2d 100755
--- a/scripts/tracetool
+++ b/scripts/tracetool
@@ -13,7 +13,7 @@ set -f
 usage()
 {
     cat >&2 <<EOF
-usage: $0 [--nop | --simple | --stderr | --ust | --dtrace] [-h | -c]
+usage: $0 [--nop | --simple | --stderr | --ust | --dtrace | --tcg] [-h | -c]
 Generate tracing code for a file on stdin.
 
 Backends:
@@ -22,12 +22,14 @@ Backends:
   --stderr  Stderr built-in backend
   --ust     LTTng User Space Tracing backend
   --dtrace  DTrace/SystemTAP backend
+  --tcg     Intermediate TCG helper to real backend proxy
 
 Output formats:
-  -h     Generate .h file
-  -c     Generate .c file
-  -d     Generate .d file (DTrace only)
-  --stap Generate .stp file (DTrace with SystemTAP only)
+  -h      Generate .h file
+  -c      Generate .c file
+  -d      Generate .d file (DTrace only)
+  --stap  Generate .stp file (DTrace with SystemTAP only)
+  --tcg-h Generate trace-tcg-helper.h file (tcg only)
 
 Options:
   --binary       [path]    Full path to QEMU binary
@@ -218,13 +220,57 @@ host_type()
         "TCGv_i32") echo "uint32_t" ;;
         "TCGv_i64") echo "uint64_t" ;;
         "TCGv_ptr") echo "void *"   ;;
-        # force a fixed-size type in trace.{h,c}
-        # (ideally would use a host-specific type)
-        "TCGv")     echo "uint64_t" ;;
+        "TCGv")
+            if [ "$backend" = "tcg" ]; then
+                echo "target_ulong"
+            else
+                # force a fixed-size type in trace.{h,c}
+                # (ideally would use a host-specific type)
+                echo "uint64_t"
+            fi
+            ;;
         *)          echo "$1"       ;;
     esac
 }
 
+tcg_compat_type()
+{
+    case "$1" in
+        "uint8_t") echo "uint32_t" ;;
+        *)         echo "$1" ;;
+    esac
+}
+
+tcg_type()
+{
+    local tcg_compat_type
+    tcg_compat_type=`tcg_compat_type "$1"`
+    case "$tcg_compat_type" in
+        "uint32_t") echo "TCGv_i32" ;;
+        "uint64_t") echo "TCGv_i64" ;;
+        "void*")    echo "TCGv_ptr" ;;
+        "TCGv"*)    echo "$1"       ;;
+        *)          echo "Don't know how to translate type $1 into a TCG type" >&2
+                    exit 1
+                    ;;
+    esac
+}
+
+tcg_helper_decl_type()
+{
+    local type
+    type=`tcg_type "$1"`
+    case "$type" in
+        "TCGv")     echo "tl"  ;;
+        "TCGv_ptr") echo "ptr" ;;
+        "TCGv_i32") echo "i32" ;;
+        "TCGv_i64") echo "i64" ;;
+        *)          echo "Don't know how to translate type $1 into a TCG helper declaration type" >&2
+                    exit 1
+                    ;;
+    esac
+}
+
 
 # Get the argument name list of a trace event
 get_argnames()
@@ -662,6 +708,127 @@ linetostap_end_dtrace()
     return
 }
 
+linetotcg_h_nop()
+{
+    local has_tcg has_tcg_vcpu
+    has_property "$1" "tcg" && has_tcg=1
+    has_property "$1" "tcg-vcpu" && has_tcg_vcpu=1
+    if [ "$has_tcg" != "1" -a "$has_tcg_vcpu" != "1" ]; then
+        return
+    fi
+
+    local api
+    api=$(get_api_name "$1")
+
+    cat <<EOF
+#if GEN_HELPER_CODE == 1
+static inline void gen_helper_${api}($(get_args "$1"))
+{
+}
+#endif
+EOF
+}
+
+tcg_temp_new_type()
+{
+    local compat_type
+    compat_type=`tcg_compat_type "$1"`
+    case "$compat_type" in
+        "uint32_t") echo "tcg_const_i32" ;;
+        "uint64_t") echo "tcg_const_i64" ;;
+        "void *")   echo "tcg_cont_ptr" ;;
+        *) echo "" ;;
+    esac
+}
+
+tcg_temp_free_type()
+{
+    local compat_type
+    compat_type=`tcg_compat_type "$1"`
+    case "$compat_type" in
+        "uint32_t") echo "tcg_temp_free_i32" ;;
+        "uint64_t") echo "tcg_temp_free_i64" ;;
+        "void *")   echo "tcg_temp_free_ptr" ;;
+        # do nothing on non-temp values
+        *)          echo "tcg_temp_noop" ;;
+    esac
+}
+
+linetotcg_h_tcg()
+{
+    local has_tcg has_tcg_vcpu
+    has_property "$1" "tcg" && has_tcg=1
+    has_property "$1" "tcg-vcpu" && has_tcg_vcpu=1
+    if [ "$has_tcg" != "1" -a "$has_tcg_vcpu" != "1" ]; then
+        return
+    fi
+
+    local api argc
+    api=$(get_api_name "$1")
+    argc=$(get_argc "$1")
+
+    # TCG helper proxy declaration
+    local proxy_argtypes
+    if [ $argc -ne 0 ]; then
+        proxy_argtypes=$(get_argtypes "$1" tcg_helper_decl_type)
+        proxy_argtypes=", $proxy_argtypes"
+    fi
+    if [ "$has_tcg_vcpu" = "1" ]; then
+        if [ "$has_tcg" = "1" ]; then
+            echo "Cannot have both \"tcg\" and \"tcg-vcpu\" properties" >&2
+            exit 1
+        fi
+        echo "DEF_HELPER_$argc(${api}_proxy, void$proxy_argtypes)"
+    else
+        echo "DEF_HELPER_FLAGS_$argc(${api}_proxy, TCG_CALL_CONST, void$proxy_argtypes)"
+    fi
+
+    # mixed-type to TCG helper bridge
+    local argnames argname temps_names
+    local temps_tcg_new temps_argtypes temps_new
+    local temps_tcg_free temps_free
+    if [ $argc -ne 0 ]; then
+        argnames=$(get_argnames "$1" ",")
+        temps_names=""
+        for argname in $argnames; do
+            temps_names="${temps_names} __${argname}"
+        done
+
+        temps_tcg_new=$(get_argtypes "$1" tcg_temp_new_type)
+        temps_new=$(zip_lists "$temps_tcg_new" "$argnames" "%s(%s), ")
+        temps_new=$(zip_lists "$temps_names" "$temps_new" "%s =%s, ")
+        temps_argtypes=$(get_argtypes "$1" tcg_type)
+        temps_new=$(zip_lists "$temps_argtypes" "$temps_new" "%s %s;")
+
+        tcg_temp_free=$(get_argtypes "$1" tcg_temp_free_type)
+        temps_free=$(zip_lists "$tcg_temp_free" "$temps_names" "%s(%s);")
+    fi
+    cat <<EOF
+#if GEN_HELPER_CODE == 1
+static inline void gen_helper_${api}($(get_args "$1"))
+{
+    $temps_new
+    gen_helper_${api}_proxy($temps_names);
+    $temps_free
+}
+#endif
+EOF
+}
+
+linetotcg_h_begin_tcg()
+{
+    cat <<EOF
+/* This file is autogenerated by tracetool, do not edit. */
+
+#define tcg_temp_noop(v)
+EOF
+}
+
+linetotcg_h_end_tcg()
+{
+    return
+}
+
 # Process stdin by calling begin, line, and end functions for the backend
 convert()
 {
@@ -744,6 +911,20 @@ tracetostap()
     convert stap
 }
 
+tracetotcg_h()
+{
+    if [ $backend != "tcg" ]; then
+        echo "TCG helper generator not applicable to $backend backend" >&2
+        exit 1
+    fi
+    convert tcg_h
+    cat <<EOF
+#if GEN_HELPER_CODE == 1
+#include "trace.h"
+#endif
+EOF
+}
+
 
 backend=
 output=
@@ -756,7 +937,9 @@ probeprefix=
 until [ -z "$1" ]
 do
   case "$1" in
-    "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
+    "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace" | "--tcg")
+          backend="${1#--}"
+          ;;
 
     "--binary") shift ; binary="$1" ;;
     "--target-arch") shift ; targetarch="$1" ;;
@@ -765,6 +948,7 @@ do
 
     "-h" | "-c" | "-d") output="${1#-}" ;;
     "--stap") output="${1#--}" ;;
+    "--tcg-h") output="tcg_h" ;;
 
     "--check-backend") exit 0 ;; # used by ./configure to test for backend
 
