summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--gdbstub.c32
-rw-r--r--include/qom/cpu.h3
-rw-r--r--target-arm/cpu.c1
-rw-r--r--target-cris/cpu.c1
-rw-r--r--target-lm32/cpu.c1
-rw-r--r--target-mips/cpu.c1
-rw-r--r--target-xtensa/cpu.c1
7 files changed, 31 insertions, 9 deletions
diff --git a/gdbstub.c b/gdbstub.c
index 71aaa23da3..d1b5afd8fe 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -625,11 +625,23 @@ void gdb_register_coprocessor(CPUState *cpu,
 }
 
 #ifndef CONFIG_USER_ONLY
-static const int xlat_gdb_type[] = {
-    [GDB_WATCHPOINT_WRITE]  = BP_GDB | BP_MEM_WRITE,
-    [GDB_WATCHPOINT_READ]   = BP_GDB | BP_MEM_READ,
-    [GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS,
-};
+/* Translate GDB watchpoint type to a flags value for cpu_watchpoint_* */
+static inline int xlat_gdb_type(CPUState *cpu, int gdbtype)
+{
+    static const int xlat[] = {
+        [GDB_WATCHPOINT_WRITE]  = BP_GDB | BP_MEM_WRITE,
+        [GDB_WATCHPOINT_READ]   = BP_GDB | BP_MEM_READ,
+        [GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS,
+    };
+
+    CPUClass *cc = CPU_GET_CLASS(cpu);
+    int cputype = xlat[gdbtype];
+
+    if (cc->gdb_stop_before_watchpoint) {
+        cputype |= BP_STOP_BEFORE_ACCESS;
+    }
+    return cputype;
+}
 #endif
 
 static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type)
@@ -656,10 +668,11 @@ static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type)
     case GDB_WATCHPOINT_READ:
     case GDB_WATCHPOINT_ACCESS:
         CPU_FOREACH(cpu) {
-            err = cpu_watchpoint_insert(cpu, addr, len, xlat_gdb_type[type],
-                                        NULL);
-            if (err)
+            err = cpu_watchpoint_insert(cpu, addr, len,
+                                        xlat_gdb_type(cpu, type), NULL);
+            if (err) {
                 break;
+            }
         }
         return err;
 #endif
@@ -692,7 +705,8 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type)
     case GDB_WATCHPOINT_READ:
     case GDB_WATCHPOINT_ACCESS:
         CPU_FOREACH(cpu) {
-            err = cpu_watchpoint_remove(cpu, addr, len, xlat_gdb_type[type]);
+            err = cpu_watchpoint_remove(cpu, addr, len,
+                                        xlat_gdb_type(cpu, type));
             if (err)
                 break;
         }
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index f576b472fd..2098f1cb50 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -99,6 +99,8 @@ struct TranslationBlock;
  * @vmsd: State description for migration.
  * @gdb_num_core_regs: Number of core registers accessible to GDB.
  * @gdb_core_xml_file: File name for core registers GDB XML description.
+ * @gdb_stop_before_watchpoint: Indicates whether GDB expects the CPU to stop
+ *           before the insn which triggers a watchpoint rather than after it.
  * @cpu_exec_enter: Callback for cpu_exec preparation.
  * @cpu_exec_exit: Callback for cpu_exec cleanup.
  * @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec.
@@ -152,6 +154,7 @@ typedef struct CPUClass {
     const struct VMStateDescription *vmsd;
     int gdb_num_core_regs;
     const char *gdb_core_xml_file;
+    bool gdb_stop_before_watchpoint;
 
     void (*cpu_exec_enter)(CPUState *cpu);
     void (*cpu_exec_exit)(CPUState *cpu);
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 8ab6d9532e..edfd5868b8 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -1117,6 +1117,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
 #endif
     cc->gdb_num_core_regs = 26;
     cc->gdb_core_xml_file = "arm-core.xml";
+    cc->gdb_stop_before_watchpoint = true;
     cc->debug_excp_handler = arm_debug_excp_handler;
 }
 
diff --git a/target-cris/cpu.c b/target-cris/cpu.c
index 528e458aaa..16cfba95ff 100644
--- a/target-cris/cpu.c
+++ b/target-cris/cpu.c
@@ -291,6 +291,7 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data)
 #endif
 
     cc->gdb_num_core_regs = 49;
+    cc->gdb_stop_before_watchpoint = true;
 }
 
 static const TypeInfo cris_cpu_type_info = {
diff --git a/target-lm32/cpu.c b/target-lm32/cpu.c
index 6c5de660dd..f8081f52c1 100644
--- a/target-lm32/cpu.c
+++ b/target-lm32/cpu.c
@@ -273,6 +273,7 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data)
     cc->vmsd = &vmstate_lm32_cpu;
 #endif
     cc->gdb_num_core_regs = 32 + 7;
+    cc->gdb_stop_before_watchpoint = true;
     cc->debug_excp_handler = lm32_debug_excp_handler;
 }
 
diff --git a/target-mips/cpu.c b/target-mips/cpu.c
index 5ed60f78a7..98dc94e74b 100644
--- a/target-mips/cpu.c
+++ b/target-mips/cpu.c
@@ -151,6 +151,7 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
 #endif
 
     cc->gdb_num_core_regs = 73;
+    cc->gdb_stop_before_watchpoint = true;
 }
 
 static const TypeInfo mips_cpu_type_info = {
diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c
index 51c41d526d..6a5414f815 100644
--- a/target-xtensa/cpu.c
+++ b/target-xtensa/cpu.c
@@ -147,6 +147,7 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
     cc->set_pc = xtensa_cpu_set_pc;
     cc->gdb_read_register = xtensa_cpu_gdb_read_register;
     cc->gdb_write_register = xtensa_cpu_gdb_write_register;
+    cc->gdb_stop_before_watchpoint = true;
 #ifndef CONFIG_USER_ONLY
     cc->do_unaligned_access = xtensa_cpu_do_unaligned_access;
     cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug;