aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAurelien Jarno <aurelien@aurel32.net>2015-06-13 00:45:59 +0200
committerAlexander Graf <agraf@suse.de>2015-06-17 12:40:52 +0200
commit8d302e76755b8157373073d7107e31b0b13f80c1 (patch)
treeb42f028aba55a7ed4068c5108934efa99c58bf4d
parentf0e0d817c22539cd2ce1bcb5487e076f117b04c0 (diff)
translate-all: fix watchpoints if retranslation not possible
The tb_check_watchpoint function currently assumes that all memory access is done either directly through the TCG code or through an helper which knows its return address. This is obviously wrong as the helpers use cpu_ldxx/stxx_data functions to access the memory. Instead of aborting in that case, don't try to retranslate the code, but assume that the CPU state (and especially the program counter) has been saved before calling the helper. Then invalidate the TB based on this address. Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> Signed-off-by: Alexander Graf <agraf@suse.de>
-rw-r--r--translate-all.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/translate-all.c b/translate-all.c
index e2e7422609..b6b0e1c098 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -1431,12 +1431,22 @@ void tb_check_watchpoint(CPUState *cpu)
TranslationBlock *tb;
tb = tb_find_pc(cpu->mem_io_pc);
- if (!tb) {
- cpu_abort(cpu, "check_watchpoint: could not find TB for pc=%p",
- (void *)cpu->mem_io_pc);
+ if (tb) {
+ /* We can use retranslation to find the PC. */
+ cpu_restore_state_from_tb(cpu, tb, cpu->mem_io_pc);
+ tb_phys_invalidate(tb, -1);
+ } else {
+ /* The exception probably happened in a helper. The CPU state should
+ have been saved before calling it. Fetch the PC from there. */
+ CPUArchState *env = cpu->env_ptr;
+ target_ulong pc, cs_base;
+ tb_page_addr_t addr;
+ int flags;
+
+ cpu_get_tb_cpu_state(env, &pc, &cs_base, &flags);
+ addr = get_page_addr_code(env, pc);
+ tb_invalidate_phys_range(addr, addr + 1);
}
- cpu_restore_state_from_tb(cpu, tb, cpu->mem_io_pc);
- tb_phys_invalidate(tb, -1);
}
#ifndef CONFIG_USER_ONLY