@@ -35,6 +35,7 @@ void translator_loop_temp_check(DisasContextBase *db)
void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
CPUState *cpu, TranslationBlock *tb)
{
+ target_ulong pc_bbl;
int max_insns;
/* Initialize DisasContext */
@@ -63,6 +64,11 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
/* Reset the temp count so that we can identify leaks */
tcg_clear_temp_count();
+ /* Tracking gen_goto_tb / gen_exit_tb */
+ pc_bbl = db->pc_first;
+ tcg_ctx.disas.seen_goto_tb = false;
+ tcg_ctx.disas.in_guest_code = false;
+
/* Start translating. */
gen_tb_start(db->tb);
ops->tb_start(db, cpu);
@@ -74,6 +80,11 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
int insn_size_opcode_idx;
db->num_insns++;
+ if (db->num_insns == 1) {
+ tcg_ctx.disas.in_guest_code = true;
+ tcg_ctx.disas.inline_label = NULL;
+ }
+
ops->insn_start(db, cpu);
tcg_debug_assert(db->is_jmp == DISAS_NEXT); /* no early exit */
@@ -144,6 +155,22 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
}
}
+ /* Tracing after */
+ if (TRACE_GUEST_BBL_AFTER_ENABLED) {
+ tcg_ctx.disas.in_guest_code = false;
+ if (tcg_ctx.disas.inline_label == NULL) {
+ tcg_ctx.disas.inline_label = gen_new_inline_label();
+ }
+
+ gen_set_inline_region_begin(tcg_ctx.disas.inline_label);
+
+ if (TRACE_GUEST_BBL_AFTER_ENABLED) {
+ trace_guest_bbl_after_tcg(cpu, tcg_ctx.tcg_env, pc_bbl);
+ }
+
+ gen_set_inline_region_end(tcg_ctx.disas.inline_label);
+ }
+
/* Emit code to exit the TB, as indicated by db->is_jmp. */
ops->tb_stop(db, cpu);
gen_tb_end(db->tb, db->num_insns);
@@ -163,3 +190,30 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
}
#endif
}
+
+
+void translator__gen_goto_tb(TCGContext *ctx)
+{
+ if (ctx->disas.in_guest_code &&
+ (TRACE_GUEST_BBL_AFTER_ENABLED)) {
+ if (ctx->disas.inline_label == NULL) {
+ ctx->disas.inline_label = gen_new_inline_label();
+ }
+ gen_set_inline_point(ctx->disas.inline_label);
+ /* disable next exit_tb */
+ ctx->disas.seen_goto_tb = true;
+ }
+}
+
+void translator__gen_exit_tb(TCGContext *ctx)
+{
+ if (ctx->disas.in_guest_code && !ctx->disas.seen_goto_tb &&
+ (TRACE_GUEST_BBL_AFTER_ENABLED)) {
+ if (ctx->disas.inline_label == NULL) {
+ ctx->disas.inline_label = gen_new_inline_label();
+ }
+ gen_set_inline_point(ctx->disas.inline_label);
+ /* enable next exit_tb */
+ ctx->disas.seen_goto_tb = false;
+ }
+}
@@ -20,7 +20,6 @@
#include "exec/exec-all.h"
-#include "tcg/tcg.h"
/**
@@ -71,6 +70,21 @@ typedef struct DisasContextBase {
bool singlestep_enabled;
} DisasContextBase;
+/**
+ * TCGContextDisas:
+ * @seen_goto_tb: Whether we've seen a call to tcg_gen_goto_tb().
+ * @in_guest_code: Whether we're generating guest code (or supporting
+ * boilerplate otherwise).
+ * @inline_label: Inline label.
+ *
+ * Extensions to #TCGContext specific to the generic translation framework.
+ */
+typedef struct TCGContextDisas {
+ bool seen_goto_tb;
+ bool in_guest_code;
+ TCGInlineLabel *inline_label;
+} TCGContextDisas;
+
/**
* TranslatorOps:
* @init_disas_context:
@@ -117,6 +131,8 @@ typedef struct TranslatorOps {
void (*disas_log)(const DisasContextBase *db, CPUState *cpu);
} TranslatorOps;
+#include "tcg/tcg.h"
+
/**
* translator_loop:
* @ops: Target-specific operations.
@@ -141,4 +157,8 @@ void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
void translator_loop_temp_check(DisasContextBase *db);
+/* Internal functions to hook tracing into */
+void translator__gen_goto_tb(TCGContext *ctx);
+void translator__gen_exit_tb(TCGContext *ctx);
+
#endif /* EXEC__TRANSLATOR_H */
@@ -2578,6 +2578,8 @@ void tcg_gen_extr32_i64(TCGv_i64 lo, TCGv_i64 hi, TCGv_i64 arg)
void tcg_gen_goto_tb(unsigned idx)
{
+ translator__gen_goto_tb(&tcg_ctx);
+
/* We only support two chained exits. */
tcg_debug_assert(idx <= 1);
#ifdef CONFIG_DEBUG_TCG
@@ -817,6 +817,7 @@ static inline void tcg_gen_insn_start(target_ulong pc, target_ulong a1,
static inline void tcg_gen_exit_tb(uintptr_t val)
{
+ translator__gen_exit_tb(&tcg_ctx);
tcg_gen_op1i(INDEX_op_exit_tb, val);
}
@@ -655,6 +655,8 @@ QEMU_BUILD_BUG_ON(OPPARAM_BUF_SIZE > (1 << 14));
/* Make sure that we don't overflow 64 bits without noticing. */
QEMU_BUILD_BUG_ON(sizeof(TCGOp) > 8);
+#include "exec/translator.h"
+
struct TCGContext {
uint8_t *pool_cur, *pool_end;
TCGPool *pool_first, *pool_current, *pool_first_large;
@@ -730,6 +732,9 @@ struct TCGContext {
CPUState *cpu; /* *_trans */
TCGv_env tcg_env; /* *_exec */
+ /* Used by generic gen_intermediate_code */
+ TCGContextDisas disas;
+
/* These structures are private to tcg-target.inc.c. */
#ifdef TCG_TARGET_NEED_LDST_LABELS
struct TCGLabelQemuLdst *ldst_labels;
@@ -99,6 +99,17 @@ vcpu guest_cpu_reset(void)
# Targets: TCG(all)
vcpu tcg guest_bbl_before(uint64_t vaddr) "vaddr=0x%016"PRIx64, "vaddr=0x%016"PRIx64
+# @vaddr: BBL's starting virtual address
+#
+# Mark end of BBL execution (after the BBL-exiting instruction).
+#
+# NOTE: This event might not be raised if the BBL ends unexpectedly (e.g.,
+# triggers an exception).
+#
+# Mode: user, softmmu
+# Targets: TCG(all)
+vcpu tcg guest_bbl_after(uint64_t vaddr) "vaddr=0x%016"PRIx64, "vaddr=0x%016"PRIx64
+
# @vaddr: Instruction's virtual address
#
# Mark start of instruction execution (before anything gets really executed).
Need to use "TCG inlining" to avoid showing a trace entry for each exit point (up to two per BBL). Signed-off-by: Lluís Vilanova <vilanova@ac.upc.edu> --- accel/tcg/translator.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ include/exec/translator.h | 22 ++++++++++++++++++ tcg/tcg-op.c | 2 ++ tcg/tcg-op.h | 1 + tcg/tcg.h | 5 ++++ trace-events | 11 +++++++++ 6 files changed, 94 insertions(+), 1 deletion(-)