Patchwork [10/18] instrument: Dynamic per-CPU state of static instrumentation points

login
register
mail settings
Submitter =?utf-8?Q?Llu=C3=ADs?=
Date Oct. 19, 2010, 9:37 p.m.
Message ID <7da9a746029ba96a0c908da31ad3ff5e61893f60.1287772676.git.vilanova@ac.upc.edu>
Download mbox | patch
Permalink /patch/68961/
State New
Headers show

Comments

=?utf-8?Q?Llu=C3=ADs?= - Oct. 19, 2010, 9:37 p.m.
The user-provided implementation for instrumentation points can define and use
"instrumentation types" as the atomic unit of instrumentation point
(de)activation.

The set of "instrumentation types" is named as "instrumentation state" (just a
bitset, one bit per type), which can be independently controlled on each
emulated CPU.

Thus, during guest code translation, instrumentation points execute arbitrary
code, including generating new TCG code, which will be generated only for CPUs
with an instrumentation state that matches the instrumentation type requirements
of the user-provided instrumentation point implementation.

This is efficiently supported by having one translation block table for each
possible instrumentation state, such that code translations can be efficiently
reused even if the CPUs are constantly changing their instrumentation state.

The net effect is similar (in terms of avoiding TB flushes) to that of the
execution of TBs that are marked to be available only under certain CPU
privilege levels.

Note that for simplicity, every CPU state change flushes the virtual translation
block table of the afected CPU ('tb_jmp_cache'), but not the global physical
translation block table ('tb_phys_hash'), which is the one containing one set of
translations for each instrumentation state.

Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu>
---
 Makefile.target                                    |    8 ++-
 cpu-all.h                                          |    7 ++
 cpu-defs.h                                         |   24 ++++++
 cpu-exec.c                                         |    8 ++-
 cpus.c                                             |    8 ++
 exec-all.h                                         |    5 +-
 exec.c                                             |   50 +++++++++-----
 instrument/control.c                               |   74 ++++++++++++++++++++
 instrument/control.h                               |   44 ++++++++++++
 instrument/examples/dynprint/guest/test.c          |   12 +++
 instrument/examples/dynprint/host/backdoor.c       |    9 +++
 .../examples/dynprint/host/instrument-host.h       |    5 ++
 instrument/host-stub.h                             |   48 +++++++++++++
 instrument/host.h                                  |   31 ++++++++
 instrument/state.h                                 |   61 ++++++++++++++++
 qemu-common.h                                      |    4 +
 target-microblaze/translate.c                      |    6 ++
 17 files changed, 383 insertions(+), 21 deletions(-)
 create mode 100644 instrument/control.c
 create mode 100644 instrument/control.h
 create mode 100644 instrument/host-stub.h
 create mode 100644 instrument/host.h
 create mode 100644 instrument/state.h

Patch

diff --git a/Makefile.target b/Makefile.target
index 90867e7..72849b3 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -353,12 +353,18 @@  endif
 
 #########################################################
 # static instrumentation
+obj-$(CONFIG_INSTRUMENT) += instrument/control.o
+
 ifdef CONFIG_INSTRUMENT
 VPATH := $(VPATH):$(INSTRUMENT_PATH)
 
+INSTRUMENT_DIR = instrument
 LIBINSTRUMENT_LIB = libinstrument/libinstrument.a
 LIBINSTRUMENT_CLEAN = libinstrument-clean
 
+instrument:
+	$(call quiet-command, mkdir -p instrument, "  MKDIR $(TARGET_DIR)$@")
+
 libinstrument/Makefile:
 	$(call quiet-command, mkdir -p libinstrument, "  CREAT $(TARGET_DIR)$@")
 	$(call quiet-command, rm -f libinstrument/Makefile)
@@ -376,7 +382,7 @@  libinstrument-clean:
 endif
 
 
-$(QEMU_PROG)-prepare: $(GENERATED_HEADERS) $(LIBBACKDOOR_LIB) $(LIBINSTRUMENT_LIB) $(QEMU_PROG)
+$(QEMU_PROG)-prepare: $(GENERATED_HEADERS) $(LIBBACKDOOR_LIB) $(INSTRUMENT_DIR) $(LIBINSTRUMENT_LIB) $(QEMU_PROG)
 
 $(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) $(LIBBACKDOOR_LIB) $(LIBINSTRUMENT_LIB)
 	$(call LINK,$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)) $(LIBBACKDOOR_LIB) $(LIBINSTRUMENT_LIB)
diff --git a/cpu-all.h b/cpu-all.h
index 67a3266..1be1c60 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -22,6 +22,13 @@ 
 #include "qemu-common.h"
 #include "cpu-common.h"
 
+#if defined(CONFIG_INSTRUMENT)
+
+#include "instrument/control.h"
+#include "instrument/state.h"
+
+#endif  /* defined(CONFIG_INSTRUMENT) */
+
 /* some important defines:
  *
  * WORDS_ALIGNED : if defined, the host cpu can only make word aligned
diff --git a/cpu-defs.h b/cpu-defs.h
index 8d4bf86..f896844 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -147,6 +147,28 @@  typedef struct CPUWatchpoint {
     QTAILQ_ENTRY(CPUWatchpoint) entry;
 } CPUWatchpoint;
 
+
+#if defined(CONFIG_INSTRUMENT)
+#include "instrument-host.h"
+#include "instrument/state.h"
+
+/* Extra attributes for CPUState */
+#define INSTR_CPUState                                          \
+    /** Current instrumentation state. */                       \
+    instr_state_t instr_state;                                  \
+    /** Inidcate a pending instrumentation state change. */     \
+    instr_state_t instr_state_request;
+
+#else  /* defined(CONFIG_INSTRUMENT) */
+
+#include "instrument/host-stub.h"
+#include "instrument/state.h"
+
+#define INSTR_CPUState
+
+#endif  /* defined(CONFIG_INSTRUMENT) */
+
+
 #define CPU_TEMP_BUF_NLONGS 128
 #define CPU_COMMON                                                      \
     struct TranslationBlock *current_tb; /* currently executing TB  */  \
@@ -166,6 +188,8 @@  typedef struct CPUWatchpoint {
     /* buffer for temporaries in the code generator */                  \
     long temp_buf[CPU_TEMP_BUF_NLONGS];                                 \
                                                                         \
+    INSTR_CPUState;                                                     \
+                                                                        \
     int64_t icount_extra; /* Instructions until next timer event.  */   \
     /* Number of cycles left, with interrupt flag in high bit.          \
        This allows a single read-compare-cbranch-write sequence to test \
diff --git a/cpu-exec.c b/cpu-exec.c
index dbdfdcc..d925ee9 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -140,7 +140,7 @@  static TranslationBlock *tb_find_slow(target_ulong pc,
     phys_page1 = phys_pc & TARGET_PAGE_MASK;
     phys_page2 = -1;
     h = tb_phys_hash_func(phys_pc);
-    ptb1 = &tb_phys_hash[h];
+    ptb1 = &tb_phys_hash[INSTR_CURR_STATE][h];
     for(;;) {
         tb = *ptb1;
         if (!tb)
@@ -553,6 +553,12 @@  int cpu_exec(CPUState *env1)
                     env->exception_index = EXCP_INTERRUPT;
                     cpu_loop_exit();
                 }
+#if defined(CONFIG_INSTRUMENT)
+                if (unlikely(env->instr_state != env->instr_state_request)) {
+                    instr_cpu_do_state_change(env);
+                    next_tb = 0;
+                }
+#endif
 #if defined(DEBUG_DISAS) || defined(CONFIG_DEBUG_EXEC)
                 if (qemu_loglevel_mask(CPU_LOG_TB_CPU)) {
                     /* restore flags in standard format */
diff --git a/cpus.c b/cpus.c
index b09f5e3..47dc22d 100644
--- a/cpus.c
+++ b/cpus.c
@@ -256,6 +256,10 @@  void qemu_init_vcpu(void *_env)
 {
     CPUState *env = _env;
 
+#if defined(CONFIG_INSTRUMENT)
+    instr_init_vcpu(env);
+#endif
+
     env->nr_cores = smp_cores;
     env->nr_threads = smp_threads;
     if (kvm_enabled())
@@ -700,6 +704,10 @@  void qemu_init_vcpu(void *_env)
 {
     CPUState *env = _env;
 
+#if defined(CONFIG_INSTRUMENT)
+    instr_init_vcpu(env);
+#endif
+
     env->nr_cores = smp_cores;
     env->nr_threads = smp_threads;
     if (kvm_enabled())
diff --git a/exec-all.h b/exec-all.h
index 2ae09c5..35d2a57 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -158,6 +158,9 @@  struct TranslationBlock {
     struct TranslationBlock *jmp_next[2];
     struct TranslationBlock *jmp_first;
     uint32_t icount;
+#if defined(CONFIG_INSTRUMENT)
+    instr_state_t instr_state;
+#endif
 };
 
 static inline unsigned int tb_jmp_cache_hash_page(target_ulong pc)
@@ -189,7 +192,7 @@  void tb_link_page(TranslationBlock *tb,
                   tb_page_addr_t phys_pc, tb_page_addr_t phys_page2);
 void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr);
 
-extern TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
+extern TranslationBlock *tb_phys_hash[INSTR_STATE_COUNT][CODE_GEN_PHYS_HASH_SIZE];
 
 #if defined(USE_DIRECT_JUMP)
 
diff --git a/exec.c b/exec.c
index 516960a..24ade3c 100644
--- a/exec.c
+++ b/exec.c
@@ -81,7 +81,7 @@ 
 
 static TranslationBlock *tbs;
 static int code_gen_max_blocks;
-TranslationBlock *tb_phys_hash[CODE_GEN_PHYS_HASH_SIZE];
+TranslationBlock *tb_phys_hash[INSTR_STATE_COUNT][CODE_GEN_PHYS_HASH_SIZE];
 static int nb_tbs;
 /* any access to the tbs or the page table must use this lock */
 spinlock_t tb_lock = SPIN_LOCK_UNLOCKED;
@@ -713,7 +713,8 @@  void tb_flush(CPUState *env1)
         tb_flush_jmp_cache(env);
     }
 
-    memset (tb_phys_hash, 0, CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
+    memset (tb_phys_hash, 0,
+            INSTR_STATE_COUNT * CODE_GEN_PHYS_HASH_SIZE * sizeof (void *));
     page_flush_tb();
 
     code_gen_ptr = code_gen_buffer;
@@ -727,15 +728,18 @@  void tb_flush(CPUState *env1)
 static void tb_invalidate_check(target_ulong address)
 {
     TranslationBlock *tb;
+    instr_state_t s;
     int i;
     address &= TARGET_PAGE_MASK;
-    for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
-        for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
-            if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
-                  address >= tb->pc + tb->size)) {
-                printf("ERROR invalidate: address=" TARGET_FMT_lx
-                       " PC=%08lx size=%04x\n",
-                       address, (long)tb->pc, tb->size);
+    for (s = 0; s < INSTR_STATE_COUNT; s++) {
+        for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
+            for(tb = tb_phys_hash[s][i]; tb != NULL; tb = tb->phys_hash_next) {
+                if (!(address + TARGET_PAGE_SIZE <= tb->pc ||
+                      address >= tb->pc + tb->size)) {
+                    printf("ERROR invalidate: address=" TARGET_FMT_lx
+                           " PC=%08lx size=%04x\n",
+                           address, (long)tb->pc, tb->size);
+                }
             }
         }
     }
@@ -745,15 +749,18 @@  static void tb_invalidate_check(target_ulong address)
 static void tb_page_check(void)
 {
     TranslationBlock *tb;
+    instr_state_t s;
     int i, flags1, flags2;
 
-    for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
-        for(tb = tb_phys_hash[i]; tb != NULL; tb = tb->phys_hash_next) {
-            flags1 = page_get_flags(tb->pc);
-            flags2 = page_get_flags(tb->pc + tb->size - 1);
-            if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
-                printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
-                       (long)tb->pc, tb->size, flags1, flags2);
+    for(s = 0; s < INSTR_STATE_COUNT; s++) {
+        for(i = 0;i < CODE_GEN_PHYS_HASH_SIZE; i++) {
+            for(tb = tb_phys_hash[s][i]; tb != NULL; tb = tb->phys_hash_next) {
+                flags1 = page_get_flags(tb->pc);
+                flags2 = page_get_flags(tb->pc + tb->size - 1);
+                if ((flags1 & PAGE_WRITE) || (flags2 & PAGE_WRITE)) {
+                    printf("ERROR page flags: PC=%08lx size=%04x f1=%x f2=%x\n",
+                           (long)tb->pc, tb->size, flags1, flags2);
+                }
             }
         }
     }
@@ -839,7 +846,7 @@  void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr)
     /* remove the TB from the hash list */
     phys_pc = tb->page_addr[0] + (tb->pc & ~TARGET_PAGE_MASK);
     h = tb_phys_hash_func(phys_pc);
-    tb_remove(&tb_phys_hash[h], tb,
+    tb_remove(&tb_phys_hash[INSTR_TB_STATE(tb)][h], tb,
               offsetof(TranslationBlock, phys_hash_next));
 
     /* remove the TB from the page list */
@@ -964,6 +971,9 @@  TranslationBlock *tb_gen_code(CPUState *env,
     tb->cs_base = cs_base;
     tb->flags = flags;
     tb->cflags = cflags;
+#if defined(CONFIG_INSTRUMENT)
+    tb->instr_state = env->instr_state;
+#endif
     cpu_gen_code(env, tb, &code_gen_size);
     code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
 
@@ -1269,7 +1279,7 @@  void tb_link_page(TranslationBlock *tb,
     mmap_lock();
     /* add in the physical hash table */
     h = tb_phys_hash_func(phys_pc);
-    ptb = &tb_phys_hash[h];
+    ptb = &tb_phys_hash[INSTR_TB_STATE(tb)][h];
     tb->phys_hash_next = *ptb;
     *ptb = tb;
 
@@ -3139,6 +3149,8 @@  static void check_watchpoint(int offset, int len_mask, int flags)
                               "pc=%p", (void *)env->mem_io_pc);
                 }
                 cpu_restore_state(tb, env, env->mem_io_pc, NULL);
+                /* XXX: It is OK to invalidate only this TB (and not for all
+                 * states), as this is the one triggering the memory access */
                 tb_phys_invalidate(tb, -1);
                 if (wp->flags & BP_STOP_BEFORE_ACCESS) {
                     env->exception_index = EXCP_DEBUG;
@@ -4079,6 +4091,8 @@  void cpu_io_recompile(CPUState *env, void *retaddr)
     pc = tb->pc;
     cs_base = tb->cs_base;
     flags = tb->flags;
+    /* XXX: It is OK to invalidate only this TB (and not for all states), as
+     * this is the one triggering the memory access */
     tb_phys_invalidate(tb, -1);
     /* FIXME: In theory this could raise an exception.  In practice
        we have already translated the block once so it's probably ok.  */
diff --git a/instrument/control.c b/instrument/control.c
new file mode 100644
index 0000000..c2c7476
--- /dev/null
+++ b/instrument/control.c
@@ -0,0 +1,74 @@ 
+/*
+ * Dynamic control of instrumentation states.
+ *
+ *  Copyright (c) 2010 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+
+#include "exec-all.h"
+#include "instrument/control.h"
+
+
+void
+instr_enable_type (instr_type_t type)
+{
+    CPUState *cpu;
+    for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+        instr_cpu_enable_type(cpu, type);
+    }
+}
+
+void
+instr_disable_type (instr_type_t type)
+{
+    CPUState *cpu;
+    for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+        instr_cpu_disable_type(cpu, type);
+    }
+}
+
+void
+instr_cpu_enable_type (CPUState * cpu, instr_type_t type)
+{
+    cpu->instr_state_request |= (1 << type);
+}
+
+void
+instr_cpu_disable_type (CPUState * cpu, instr_type_t type)
+{
+    cpu->instr_state_request &= ~(1 << type);
+}
+
+void
+instr_cpu_do_state_change (CPUState * cpu)
+{
+    cpu->instr_state = cpu->instr_state_request;
+    tb_flush_jmp_cache(cpu);
+}
+
+void
+instr_init_vcpu (CPUState * cpu)
+{
+    int bits = sizeof(cpu->instr_state) * 8;
+    if (INSTR_TYPE_COUNT > bits) {
+        fprintf(stderr, "Can only support at most %d instrumentation types\n",
+                bits);
+        abort();
+    }
+    cpu->instr_state = 0;
+    cpu->instr_state_request = cpu->instr_state;
+}
diff --git a/instrument/control.h b/instrument/control.h
new file mode 100644
index 0000000..c4ee12c
--- /dev/null
+++ b/instrument/control.h
@@ -0,0 +1,44 @@ 
+/*
+ * Dynamic control of instrumentation states.
+ *
+ *  Copyright (c) 2010 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INSTRUMENT__CONTROL_H
+#define INSTRUMENT__CONTROL_H
+
+#include "instrument-host.h"
+
+/** Enable instrumentation for given type on all CPUs. */
+void instr_enable_type (instr_type_t type);
+/** Disable instrumentation for given type on all CPUs. */
+void instr_disable_type (instr_type_t type);
+
+/** Enable instrumentation for given type on given CPU. */
+void instr_cpu_enable_type (CPUState * cpu, instr_type_t type);
+/** Disable instrumentation for given type on given CPU. */
+void instr_cpu_disable_type (CPUState * cpu, instr_type_t type);
+
+
+/* Internal API */
+
+/** Apply instrumentation state changes. */
+void instr_cpu_do_state_change (CPUState * cpu);
+
+/** Initialize per-cpu insrumentation variables. */
+void instr_init_vcpu (CPUState * cpu);
+
+#endif /* INSTRUMENT__CONTROL_H */
diff --git a/instrument/examples/dynprint/guest/test.c b/instrument/examples/dynprint/guest/test.c
index 254ebcf..7ddd5be 100644
--- a/instrument/examples/dynprint/guest/test.c
+++ b/instrument/examples/dynprint/guest/test.c
@@ -19,6 +19,8 @@ 
 
 #include <stdio.h>
 
+#include "backdoor/guest.h"
+
 #define TOTAL_ITERS 100
 
 
@@ -27,13 +29,23 @@  main ()
 {
     int i;
 
+    BACKDOOR_i8(0x01);                  /* enable instrumentation */
+
     printf("start\n");
 
     for (i = 0; i < TOTAL_ITERS; i++) {
+        /* disable an iteration every 10 iterations */
+        if (i % 10 == 0) {
+            BACKDOOR_i8(0x00);
+        }
         printf("iteration\n");
+        if (i % 10 == 0) {
+            BACKDOOR_i8(0x01);
+        }
     }
 
     printf("stop\n");
 
+    BACKDOOR_i8(0x00);                  /* disable instrumentation */
     return 0;
 }
diff --git a/instrument/examples/dynprint/host/backdoor.c b/instrument/examples/dynprint/host/backdoor.c
index 7b4e883..27f612b 100644
--- a/instrument/examples/dynprint/host/backdoor.c
+++ b/instrument/examples/dynprint/host/backdoor.c
@@ -21,12 +21,21 @@ 
 
 #include "cpu.h"
 #include "helper.h"
+#include "instrument/control.h"
 
 
 void
 helper_backdoor_i8 (uint32_t imm)
 {
     switch (imm) {
+    case 0:
+        printf("backdoor: -%d\n", INSTR_TYPE_ENABLED);
+        instr_disable_type(INSTR_TYPE_ENABLED);
+        break;
+    case 1:
+        printf("backdoor: +%d\n", INSTR_TYPE_ENABLED);
+        instr_enable_type(INSTR_TYPE_ENABLED);
+        break;
     default:
         printf("Unexpected use of instrumentation backdoor\n");
         abort();
diff --git a/instrument/examples/dynprint/host/instrument-host.h b/instrument/examples/dynprint/host/instrument-host.h
index 9ede6af..92a4c14 100644
--- a/instrument/examples/dynprint/host/instrument-host.h
+++ b/instrument/examples/dynprint/host/instrument-host.h
@@ -24,6 +24,11 @@ 
 
 /* Instrumentation types */
 typedef enum {
+    INSTR_TYPE_ENABLED, /* Instrumentation enabled.
+                         * Using an instrumentation type for identifying a
+                         * global state of tracing is wasteful, but hey, this is
+                         * just an example.
+                         */
     INSTR_TYPE_COUNT    /* Total number of instrumentation types (mandatory) */
 } instr_type_t;
 
diff --git a/instrument/host-stub.h b/instrument/host-stub.h
new file mode 100644
index 0000000..4178559
--- /dev/null
+++ b/instrument/host-stub.h
@@ -0,0 +1,48 @@ 
+/*
+ * Stub for empty static instrumentation points.
+ *
+ *  Copyright (c) 2010 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INSTRUMENT__HOST_STUB_H
+#define INSTRUMENT__HOST_STUB_H
+
+/** Instrumentation types. */
+typedef enum {
+    INSTR_TYPE_COUNT   /**< Total number of instrumentation types (mandatory) */
+} instr_type_t;
+
+/* All instrumentation point macros follow a strict naming scheme:
+ *    INSTR_<when>_<point>
+ *
+ * - <point>
+ *   A name for a conceptual generic event.
+ *
+ * - <when>
+ *   Describes when the instrumentation point is invoked:
+ *
+ *   - GEN
+ *     Invoked at TB generation time. If information is to be used, it must be
+ *     so through the use of "instrument/generate.h".
+ *
+ *   - DO
+ *     Invoked at instruction emulation time. If information is to be used, it
+ *     must be so by simply providing extra code.
+ *
+ *   On all cases, the use of "instrument/state.h" is supported.
+ */
+
+#endif /* INSTRUMENT__HOST_STUB_H */
diff --git a/instrument/host.h b/instrument/host.h
new file mode 100644
index 0000000..cd120d0
--- /dev/null
+++ b/instrument/host.h
@@ -0,0 +1,31 @@ 
+/*
+ * Static instrumentation points.
+ *
+ *  Copyright (c) 2010 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INSTRUMENT__HOST_H
+#define INSTRUMENT__HOST_H
+
+#if defined(CONFIG_INSTRUMENT)
+/* user-provided definitions */
+#include "instrument-host.h"
+#else
+/* empty stub definitions */
+#include "instrument/host-stub.h"
+#endif
+
+#endif  /* INSTRUMENT__HOST_H */
diff --git a/instrument/state.h b/instrument/state.h
new file mode 100644
index 0000000..60221c1
--- /dev/null
+++ b/instrument/state.h
@@ -0,0 +1,61 @@ 
+/*
+ * Instrumentation state information.
+ *
+ *  Copyright (c) 2010 Lluís Vilanova <vilanova@ac.upc.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INSTRUMENT__STATE_H
+#define INSTRUMENT__STATE_H
+
+/** Instrumentation state. */
+typedef uint16_t instr_state_t;
+
+/** Number of available instrumentation states. */
+#define INSTR_STATE_COUNT (((instr_state_t)1) << INSTR_TYPE_COUNT)
+
+/** Get instrumentation state of current CPU.
+ * This macro will also work when instrumentation is not compiled in.
+ */
+#define INSTR_CURR_STATE INSTR_CPU_STATE(cpu_single_env)
+
+
+#if defined(CONFIG_INSTRUMENT)
+
+/** Check if given instrumentation type is enabled on current CPU. */
+#define INSTR_TYPE(type) (INSTR_CURR_STATE & (1 << INSTR_TYPE_ ##type))
+
+/** Check if given instrumentation type is enabled on given CPU. */
+#define INSTR_CPU_TYPE(cpu, type)                       \
+    (INSTR_CPU_STATE(cpu) & (1 << INSTR_TYPE_ ##type))
+
+/** Get instrumentation state of given CPU.
+ * This macro will also work when instrumentation is not compiled in.
+ */
+#define INSTR_CPU_STATE(cpu) ((cpu)->instr_state)
+
+/** Get instrumentation state of given TranslationBLock.
+ * This macro will also work when instrumentation is not compiled in.
+ */
+#define INSTR_TB_STATE(tb) ((tb)->instr_state)
+
+#else  /* defined(CONFIG_INSTRUMENT) */
+
+#define INSTR_CPU_STATE(cpu) 0
+#define INSTR_TB_STATE(tb) 0
+
+#endif  /* defined(CONFIG_INSTRUMENT) */
+
+#endif /* INSTRUMENT__STATE_H */
diff --git a/qemu-common.h b/qemu-common.h
index 81aafa0..e0063a7 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -278,7 +278,11 @@  struct qemu_work_item {
 };
 
 #ifdef CONFIG_USER_ONLY
+#if defined(CONFIG_INSTRUMENT)
+#define qemu_init_vcpu(env) do { instr_init_vcpu(env); } while (0)
+#else
 #define qemu_init_vcpu(env) do { } while (0)
+#endif
 #else
 void qemu_init_vcpu(void *env);
 #endif
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index 38149bb..9dcc78a 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -1607,6 +1607,12 @@  CPUState *cpu_mb_init (const char *cpu_model)
                           offsetof(CPUState, sregs[i]),
                           special_regnames[i]);
     }
+
+#if defined(CONFIG_INSTRUMENT)
+    /* XXX: Here only because qemu_init_vcpu is not called in this target */
+    instr_init_vcpu(env);
+#endif
+
 #define GEN_HELPER 2
 #include "helper.h"