diff --git a/target-i386/translate.c b/target-i386/translate.c
index b54a823..02a93a4 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -32,6 +32,32 @@
 #define GEN_HELPER 1
 #include "helper.h"
 
+#if defined(CONFIG_INSTRUMENT)
+static inline void
+mem_exchange (void * tmp, void * start1, size_t size1,
+              void * start2, size_t size2)
+{
+    memcpy(tmp      , start2, size2);
+    memcpy(tmp+size2, start1, size1);
+    memcpy(start1   , tmp   , size1+size2);
+}
+#endif
+
+
+/* tracking of register usage */
+#if defined(CONFIG_INSTRUMENT)
+struct DisasContext;
+/* Have current context always accessible */
+struct DisasContext * instr_disas = NULL;
+#endif
+
+#define INSTR_REGS_SET_GP(s, r) INSTR_REGS_SET(instr_disas->instr_regs_ ##s, r)
+/* TODO: access to env->regs in helper functions */
+/* TODO: not tracking register sets for: eflags, segments, floating point,
+ *       crX, ...
+ */
+
+
 #define PREFIX_REPZ   0x01
 #define PREFIX_REPNZ  0x02
 #define PREFIX_LOCK   0x04
@@ -116,6 +142,11 @@ typedef struct DisasContext {
     int cpuid_ext_features;
     int cpuid_ext2_features;
     int cpuid_ext3_features;
+#if defined(CONFIG_INSTRUMENT)
+    /* temporal vars for FETCH instrumentation */
+    instr_regs_t instr_regs_used;
+    instr_regs_t instr_regs_defined;
+#endif
 } DisasContext;
 
 static void gen_eob(DisasContext *s);
@@ -281,9 +312,13 @@ static inline void gen_op_mov_reg_v(int ot, int reg, TCGv t0)
         tmp = tcg_temp_new();
         tcg_gen_ext8u_tl(tmp, t0);
         if (reg < 4 X86_64_DEF( || reg >= 8 || x86_64_hregs)) {
+            INSTR_REGS_SET_GP(used, reg);
+            INSTR_REGS_SET_GP(defined, reg);
             tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xff);
             tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], tmp);
         } else {
+            INSTR_REGS_SET_GP(used, reg - 4);
+            INSTR_REGS_SET_GP(defined, reg - 4);
             tcg_gen_shli_tl(tmp, tmp, 8);
             tcg_gen_andi_tl(cpu_regs[reg - 4], cpu_regs[reg - 4], ~0xff00);
             tcg_gen_or_tl(cpu_regs[reg - 4], cpu_regs[reg - 4], tmp);
@@ -293,6 +328,8 @@ static inline void gen_op_mov_reg_v(int ot, int reg, TCGv t0)
     case OT_WORD:
         tmp = tcg_temp_new();
         tcg_gen_ext16u_tl(tmp, t0);
+        INSTR_REGS_SET_GP(used, reg);
+        INSTR_REGS_SET_GP(defined, reg);
         tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xffff);
         tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], tmp);
         tcg_temp_free(tmp);
@@ -301,10 +338,12 @@ static inline void gen_op_mov_reg_v(int ot, int reg, TCGv t0)
     case OT_LONG:
         /* For x86_64, this sets the higher half of register to zero.
            For i386, this is equivalent to a mov. */
+        INSTR_REGS_SET_GP(defined, reg);
         tcg_gen_ext32u_tl(cpu_regs[reg], t0);
         break;
 #ifdef TARGET_X86_64
     case OT_QUAD:
+        INSTR_REGS_SET_GP(defined, reg);
         tcg_gen_mov_tl(cpu_regs[reg], t0);
         break;
 #endif
@@ -329,6 +368,8 @@ static inline void gen_op_mov_reg_A0(int size, int reg)
     case 0:
         tmp = tcg_temp_new();
         tcg_gen_ext16u_tl(tmp, cpu_A0);
+        INSTR_REGS_SET_GP(used, reg);
+        INSTR_REGS_SET_GP(defined, reg);
         tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xffff);
         tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], tmp);
         tcg_temp_free(tmp);
@@ -337,10 +378,12 @@ static inline void gen_op_mov_reg_A0(int size, int reg)
     case 1:
         /* For x86_64, this sets the higher half of register to zero.
            For i386, this is equivalent to a mov. */
+        INSTR_REGS_SET_GP(defined, reg);
         tcg_gen_ext32u_tl(cpu_regs[reg], cpu_A0);
         break;
 #ifdef TARGET_X86_64
     case 2:
+        INSTR_REGS_SET_GP(defined, reg);
         tcg_gen_mov_tl(cpu_regs[reg], cpu_A0);
         break;
 #endif
@@ -354,12 +397,14 @@ static inline void gen_op_mov_v_reg(int ot, TCGv t0, int reg)
         if (reg < 4 X86_64_DEF( || reg >= 8 || x86_64_hregs)) {
             goto std_case;
         } else {
+            INSTR_REGS_SET_GP(used, reg - 4);
             tcg_gen_shri_tl(t0, cpu_regs[reg - 4], 8);
             tcg_gen_ext8u_tl(t0, t0);
         }
         break;
     default:
     std_case:
+        INSTR_REGS_SET_GP(used, reg);
         tcg_gen_mov_tl(t0, cpu_regs[reg]);
         break;
     }
@@ -372,6 +417,7 @@ static inline void gen_op_mov_TN_reg(int ot, int t_index, int reg)
 
 static inline void gen_op_movl_A0_reg(int reg)
 {
+    INSTR_REGS_SET_GP(used, reg);
     tcg_gen_mov_tl(cpu_A0, cpu_regs[reg]);
 }
 
@@ -414,12 +460,16 @@ static inline void gen_op_add_reg_im(int size, int reg, int32_t val)
 {
     switch(size) {
     case 0:
+        INSTR_REGS_SET_GP(used, reg);
+        INSTR_REGS_SET_GP(defined, reg);
         tcg_gen_addi_tl(cpu_tmp0, cpu_regs[reg], val);
         tcg_gen_ext16u_tl(cpu_tmp0, cpu_tmp0);
         tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xffff);
         tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0);
         break;
     case 1:
+        INSTR_REGS_SET_GP(used, reg);
+        INSTR_REGS_SET_GP(defined, reg);
         tcg_gen_addi_tl(cpu_tmp0, cpu_regs[reg], val);
         /* For x86_64, this sets the higher half of register to zero.
            For i386, this is equivalent to a nop. */
@@ -428,6 +478,8 @@ static inline void gen_op_add_reg_im(int size, int reg, int32_t val)
         break;
 #ifdef TARGET_X86_64
     case 2:
+        INSTR_REGS_SET_GP(used, reg);
+        INSTR_REGS_SET_GP(defined, reg);
         tcg_gen_addi_tl(cpu_regs[reg], cpu_regs[reg], val);
         break;
 #endif
@@ -438,12 +490,16 @@ static inline void gen_op_add_reg_T0(int size, int reg)
 {
     switch(size) {
     case 0:
+        INSTR_REGS_SET_GP(used, reg);
+        INSTR_REGS_SET_GP(defined, reg);
         tcg_gen_add_tl(cpu_tmp0, cpu_regs[reg], cpu_T[0]);
         tcg_gen_ext16u_tl(cpu_tmp0, cpu_tmp0);
         tcg_gen_andi_tl(cpu_regs[reg], cpu_regs[reg], ~0xffff);
         tcg_gen_or_tl(cpu_regs[reg], cpu_regs[reg], cpu_tmp0);
         break;
     case 1:
+        INSTR_REGS_SET_GP(used, reg);
+        INSTR_REGS_SET_GP(defined, reg);
         tcg_gen_add_tl(cpu_tmp0, cpu_regs[reg], cpu_T[0]);
         /* For x86_64, this sets the higher half of register to zero.
            For i386, this is equivalent to a nop. */
@@ -452,6 +508,8 @@ static inline void gen_op_add_reg_T0(int size, int reg)
         break;
 #ifdef TARGET_X86_64
     case 2:
+        INSTR_REGS_SET_GP(used, reg);
+        INSTR_REGS_SET_GP(defined, reg);
         tcg_gen_add_tl(cpu_regs[reg], cpu_regs[reg], cpu_T[0]);
         break;
 #endif
@@ -465,6 +523,7 @@ static inline void gen_op_set_cc_op(int32_t val)
 
 static inline void gen_op_addl_A0_reg_sN(int shift, int reg)
 {
+    INSTR_REGS_SET_GP(used, reg);
     tcg_gen_mov_tl(cpu_tmp0, cpu_regs[reg]);
     if (shift != 0)
         tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, shift);
@@ -502,11 +561,13 @@ static inline void gen_op_addq_A0_seg(int reg)
 
 static inline void gen_op_movq_A0_reg(int reg)
 {
+    INSTR_REGS_SET_GP(used, reg);
     tcg_gen_mov_tl(cpu_A0, cpu_regs[reg]);
 }
 
 static inline void gen_op_addq_A0_reg_sN(int shift, int reg)
 {
+    INSTR_REGS_SET_GP(used, reg);
     tcg_gen_mov_tl(cpu_tmp0, cpu_regs[reg]);
     if (shift != 0)
         tcg_gen_shli_tl(cpu_tmp0, cpu_tmp0, shift);
@@ -707,6 +768,7 @@ static void gen_exts(int ot, TCGv reg)
 
 static inline void gen_op_jnz_ecx(int size, int label1)
 {
+    INSTR_REGS_SET_GP(used, R_ECX);
     tcg_gen_mov_tl(cpu_tmp0, cpu_regs[R_ECX]);
     gen_extu(size + 1, cpu_tmp0);
     tcg_gen_brcondi_tl(TCG_COND_NE, cpu_tmp0, 0, label1);
@@ -714,6 +776,7 @@ static inline void gen_op_jnz_ecx(int size, int label1)
 
 static inline void gen_op_jz_ecx(int size, int label1)
 {
+    INSTR_REGS_SET_GP(used, R_ECX);
     tcg_gen_mov_tl(cpu_tmp0, cpu_regs[R_ECX]);
     gen_extu(size + 1, cpu_tmp0);
     tcg_gen_brcondi_tl(TCG_COND_EQ, cpu_tmp0, 0, label1);
@@ -4090,6 +4153,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
     target_ulong next_eip, tval;
     int rex_w, rex_r;
 
+#if defined(CONFIG_INSTRUMENT)
+    uint16_t * instr_gen_opc_ptr = gen_opc_ptr;
+    TCGArg * instr_gen_opparam_ptr = gen_opparam_ptr;
+#endif
+
     if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP)))
         tcg_gen_debug_insn_start(pc_start);
     s->pc = pc_start;
@@ -4105,6 +4173,10 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
     x86_64_hregs = 0;
 #endif
     s->rip_offset = 0; /* for relative ip address */
+#if defined(CONFIG_INSTRUMENT)
+    s->instr_regs_used = 0;
+    s->instr_regs_defined = 0;
+#endif
 
 #if defined(CONFIG_BACKDOOR)
     if (ldub_code(s->pc) == 0x0f &&  ldub_code(s->pc + 1) == 0x04) {
@@ -4118,6 +4190,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
             break;
         case 0x01:                      /* i8 v */
             cmd = tcg_const_i32(ldub_code(s->pc + 3));
+            INSTR_REGS_SET_GP(used, R_EAX);
             gen_helper_backdoor_i8_v(cmd, cpu_regs[R_EAX]);
             break;
         default:
@@ -4901,6 +4974,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
                 rm = 0; /* avoid warning */
             }
             label1 = gen_new_label();
+            INSTR_REGS_SET_GP(used, R_EAX);
             tcg_gen_sub_tl(t2, cpu_regs[R_EAX], t0);
             gen_extu(ot, t2);
             tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1);
@@ -5476,6 +5550,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
             val = ldub_code(s->pc++);
             tcg_gen_movi_tl(cpu_T3, val);
         } else {
+            INSTR_REGS_SET_GP(used, R_ECX);
             tcg_gen_mov_tl(cpu_T3, cpu_regs[R_ECX]);
         }
         gen_shiftd_rm_T1_T3(s, ot, opreg, op);
@@ -6386,6 +6461,7 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
                 /* XXX: specific Intel behaviour ? */
                 l1 = gen_new_label();
                 gen_jcc1(s, s->cc_op, b ^ 1, l1);
+                INSTR_REGS_SET_GP(defined, reg);
                 tcg_gen_mov_tl(cpu_regs[reg], t0);
                 gen_set_label(l1);
                 tcg_gen_ext32u_tl(cpu_regs[reg], cpu_regs[reg]);
@@ -7666,6 +7742,36 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
 backdoor_done:
 #endif
 
+#if defined(CONFIG_INSTRUMENT)
+    {
+        uint16_t * old_gen_opc_ptr = gen_opc_ptr;
+        TCGArg * old_gen_opparam_ptr = gen_opparam_ptr;
+
+        INSTR_GEN_FETCH(TUL, pc_start,
+                        I32, s->pc - pc_start,
+                        REGS, s->instr_regs_used,
+                        REGS, s->instr_regs_defined);
+
+        /* Move TCG code generated by instrumentation callback */
+
+        if (old_gen_opc_ptr != gen_opc_ptr) {
+            typeof(*gen_opc_ptr) tmp[OPC_BUF_SIZE];
+            mem_exchange(tmp, instr_gen_opc_ptr,
+                         (old_gen_opc_ptr - instr_gen_opc_ptr) * sizeof(*gen_opc_ptr),
+                         old_gen_opc_ptr,
+                         (gen_opc_ptr - old_gen_opc_ptr) * sizeof(*gen_opc_ptr));
+        }
+
+        if (old_gen_opparam_ptr != gen_opparam_ptr) {
+            typeof(*gen_opparam_ptr) tmp[OPPARAM_BUF_SIZE];
+            mem_exchange(tmp, instr_gen_opparam_ptr,
+                         (old_gen_opparam_ptr - instr_gen_opparam_ptr) * sizeof(*gen_opparam_ptr),
+                         old_gen_opparam_ptr,
+                         (gen_opparam_ptr - old_gen_opparam_ptr) * sizeof(*gen_opparam_ptr));
+        }
+    }
+#endif
+
     /* lock generation */
     if (s->prefix & PREFIX_LOCK)
         gen_helper_unlock();
@@ -7812,6 +7918,9 @@ static inline void gen_intermediate_code_internal(CPUState *env,
                     || (flags & HF_SOFTMMU_MASK)
 #endif
                     );
+#if defined(CONFIG_INSTRUMENT)
+    instr_disas = dc;
+#endif
 #if 0
     /* check addseg logic */
     if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32))
@@ -7930,6 +8039,10 @@ static inline void gen_intermediate_code_internal(CPUState *env,
         tb->size = pc_ptr - pc_start;
         tb->icount = num_insns;
     }
+
+#if defined(CONFIG_INSTRUMENT)
+    instr_disas = NULL;
+#endif
 }
 
 void gen_intermediate_code(CPUState *env, TranslationBlock *tb)
