aboutsummaryrefslogtreecommitdiff
path: root/accel
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2022-10-24 22:15:04 +1000
committerRichard Henderson <richard.henderson@linaro.org>2022-11-01 07:28:53 +1100
commit6392bd6b90a488b3254b1cb85d79bf262ed5f9e0 (patch)
treea9b822d7b52a69c8aa41177cb569180b0505f0ef /accel
parent9dd1d56e570e5119fef2b28fda811d6891e597a8 (diff)
accel/tcg: Introduce cpu_unwind_state_data
Add a way to examine the unwind data without actually restoring the data back into env. Reviewed-by: Claudio Fontana <cfontana@suse.de> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'accel')
-rw-r--r--accel/tcg/internal.h4
-rw-r--r--accel/tcg/translate-all.c74
2 files changed, 51 insertions, 27 deletions
diff --git a/accel/tcg/internal.h b/accel/tcg/internal.h
index 1227bb69bd..9c06b320b7 100644
--- a/accel/tcg/internal.h
+++ b/accel/tcg/internal.h
@@ -106,8 +106,8 @@ void tb_reset_jump(TranslationBlock *tb, int n);
TranslationBlock *tb_link_page(TranslationBlock *tb, tb_page_addr_t phys_pc,
tb_page_addr_t phys_page2);
bool tb_invalidate_phys_page_unwind(tb_page_addr_t addr, uintptr_t pc);
-int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
- uintptr_t searched_pc, bool reset_icount);
+void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
+ uintptr_t host_pc, bool reset_icount);
/* Return the current PC from CPU, which may be cached in TB. */
static inline target_ulong log_pc(CPUState *cpu, const TranslationBlock *tb)
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index f185356a36..319becb698 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -247,52 +247,66 @@ static int encode_search(TranslationBlock *tb, uint8_t *block)
return p - block;
}
-/* The cpu state corresponding to 'searched_pc' is restored.
- * When reset_icount is true, current TB will be interrupted and
- * icount should be recalculated.
- */
-int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
- uintptr_t searched_pc, bool reset_icount)
+static int cpu_unwind_data_from_tb(TranslationBlock *tb, uintptr_t host_pc,
+ uint64_t *data)
{
- uint64_t data[TARGET_INSN_START_WORDS];
- uintptr_t host_pc = (uintptr_t)tb->tc.ptr;
+ uintptr_t iter_pc = (uintptr_t)tb->tc.ptr;
const uint8_t *p = tb->tc.ptr + tb->tc.size;
int i, j, num_insns = tb->icount;
-#ifdef CONFIG_PROFILER
- TCGProfile *prof = &tcg_ctx->prof;
- int64_t ti = profile_getclock();
-#endif
- searched_pc -= GETPC_ADJ;
+ host_pc -= GETPC_ADJ;
- if (searched_pc < host_pc) {
+ if (host_pc < iter_pc) {
return -1;
}
- memset(data, 0, sizeof(data));
+ memset(data, 0, sizeof(uint64_t) * TARGET_INSN_START_WORDS);
if (!TARGET_TB_PCREL) {
data[0] = tb_pc(tb);
}
- /* Reconstruct the stored insn data while looking for the point at
- which the end of the insn exceeds the searched_pc. */
+ /*
+ * Reconstruct the stored insn data while looking for the point
+ * at which the end of the insn exceeds host_pc.
+ */
for (i = 0; i < num_insns; ++i) {
for (j = 0; j < TARGET_INSN_START_WORDS; ++j) {
data[j] += decode_sleb128(&p);
}
- host_pc += decode_sleb128(&p);
- if (host_pc > searched_pc) {
- goto found;
+ iter_pc += decode_sleb128(&p);
+ if (iter_pc > host_pc) {
+ return num_insns - i;
}
}
return -1;
+}
+
+/*
+ * The cpu state corresponding to 'host_pc' is restored.
+ * When reset_icount is true, current TB will be interrupted and
+ * icount should be recalculated.
+ */
+void cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
+ uintptr_t host_pc, bool reset_icount)
+{
+ uint64_t data[TARGET_INSN_START_WORDS];
+#ifdef CONFIG_PROFILER
+ TCGProfile *prof = &tcg_ctx->prof;
+ int64_t ti = profile_getclock();
+#endif
+ int insns_left = cpu_unwind_data_from_tb(tb, host_pc, data);
+
+ if (insns_left < 0) {
+ return;
+ }
- found:
if (reset_icount && (tb_cflags(tb) & CF_USE_ICOUNT)) {
assert(icount_enabled());
- /* Reset the cycle counter to the start of the block
- and shift if to the number of actually executed instructions */
- cpu_neg(cpu)->icount_decr.u16.low += num_insns - i;
+ /*
+ * Reset the cycle counter to the start of the block and
+ * shift if to the number of actually executed instructions.
+ */
+ cpu_neg(cpu)->icount_decr.u16.low += insns_left;
}
cpu->cc->tcg_ops->restore_state_to_opc(cpu, tb, data);
@@ -302,7 +316,6 @@ int cpu_restore_state_from_tb(CPUState *cpu, TranslationBlock *tb,
prof->restore_time + profile_getclock() - ti);
qatomic_set(&prof->restore_count, prof->restore_count + 1);
#endif
- return 0;
}
bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit)
@@ -335,6 +348,17 @@ bool cpu_restore_state(CPUState *cpu, uintptr_t host_pc, bool will_exit)
return false;
}
+bool cpu_unwind_state_data(CPUState *cpu, uintptr_t host_pc, uint64_t *data)
+{
+ if (in_code_gen_buffer((const void *)(host_pc - tcg_splitwx_diff))) {
+ TranslationBlock *tb = tcg_tb_lookup(host_pc);
+ if (tb) {
+ return cpu_unwind_data_from_tb(tb, host_pc, data) >= 0;
+ }
+ }
+ return false;
+}
+
void page_init(void)
{
page_size_init();