]> git.ipfire.org Git - thirdparty/qemu.git/commitdiff
gdbstub: Allow target CPUs to specify watchpoint STOP_BEFORE_ACCESS flag
authorPeter Maydell <peter.maydell@linaro.org>
Fri, 12 Sep 2014 18:04:17 +0000 (19:04 +0100)
committerPeter Maydell <peter.maydell@linaro.org>
Mon, 6 Oct 2014 13:25:43 +0000 (14:25 +0100)
GDB assumes that watchpoint set via the gdbstub remote protocol will
behave in the same way as hardware watchpoints for the target. In
particular, whether the CPU stops with the PC before or after the insn
which triggers the watchpoint is target dependent. Allow guest CPU
code to specify which behaviour to use. This fixes a bug where with
guest CPUs which stop before the accessing insn GDB would manually
step forward over what it thought was the insn and end up one insn
further forward than it should be.

We set this flag for the CPU architectures which set
gdbarch_have_nonsteppable_watchpoint in gdb 7.7:
ARM, CRIS, LM32, MIPS and Xtensa.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Tested-by: Max Filippov <jcmvbkbc@gmail.com>
Tested-by: Edgar E. Iglesias <edgar.iglesias@xilinx.com>
Tested-by: Michael Walle <michael@walle.cc> (for lm32)
Message-id: 1410545057-14014-1-git-send-email-peter.maydell@linaro.org

gdbstub.c
include/qom/cpu.h
target-arm/cpu.c
target-cris/cpu.c
target-lm32/cpu.c
target-mips/cpu.c
target-xtensa/cpu.c

index 71aaa23da33865e9e1bc4ee9f83d1cc3a74a4a43..d1b5afd8fed47ce5b6680889fbffbf8d85066c1f 100644 (file)
--- 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;
         }
index f576b472fd372edb6d3842caf46ea51e616d51b2..2098f1cb50573eded54f8a6cf3a8a98cd09c1619 100644 (file)
@@ -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);
index 8ab6d9532edd3c29d02793cb76366f08fa1c70d8..edfd5868b82f71cee4964a53a8bb7cd992ac39d7 100644 (file)
@@ -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;
 }
 
index 528e458aaa1eb130a2999ebab35ad7bc9833f558..16cfba95fffd2d9a88e4e8ed6a4709cf813c4735 100644 (file)
@@ -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 = {
index 6c5de660dd61e38cf58ebe94b00c992ac7ace7ba..f8081f52c1fb8b356306c479f3f6d8cc459ba52e 100644 (file)
@@ -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;
 }
 
index 5ed60f78a741d6a1fd4fdf7b3d3889b29bfc11bb..98dc94e74b6a7c0c14b3384b3dbbdc80e5ee1741 100644 (file)
@@ -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 = {
index 51c41d526db391c310de39293e876dd0eada55a5..6a5414f8159cd9fd842cdc4f2949fdf9f6f51240 100644 (file)
@@ -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;