Commit 2472b6c0 authored by Peter Maydell's avatar Peter Maydell

gdbstub: Allow target CPUs to specify watchpoint STOP_BEFORE_ACCESS flag

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: default avatarPeter Maydell <peter.maydell@linaro.org>
Reviewed-by: default avatarEdgar E. Iglesias <edgar.iglesias@xilinx.com>
Tested-by: default avatarMax Filippov <jcmvbkbc@gmail.com>
Tested-by: default avatarEdgar 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
parent 507ef2f9
...@@ -625,11 +625,23 @@ void gdb_register_coprocessor(CPUState *cpu, ...@@ -625,11 +625,23 @@ void gdb_register_coprocessor(CPUState *cpu,
} }
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
static const int xlat_gdb_type[] = { /* Translate GDB watchpoint type to a flags value for cpu_watchpoint_* */
[GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE, static inline int xlat_gdb_type(CPUState *cpu, int gdbtype)
[GDB_WATCHPOINT_READ] = BP_GDB | BP_MEM_READ, {
[GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS, 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 #endif
static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type) 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) ...@@ -656,10 +668,11 @@ static int gdb_breakpoint_insert(target_ulong addr, target_ulong len, int type)
case GDB_WATCHPOINT_READ: case GDB_WATCHPOINT_READ:
case GDB_WATCHPOINT_ACCESS: case GDB_WATCHPOINT_ACCESS:
CPU_FOREACH(cpu) { CPU_FOREACH(cpu) {
err = cpu_watchpoint_insert(cpu, addr, len, xlat_gdb_type[type], err = cpu_watchpoint_insert(cpu, addr, len,
NULL); xlat_gdb_type(cpu, type), NULL);
if (err) if (err) {
break; break;
}
} }
return err; return err;
#endif #endif
...@@ -692,7 +705,8 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type) ...@@ -692,7 +705,8 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type)
case GDB_WATCHPOINT_READ: case GDB_WATCHPOINT_READ:
case GDB_WATCHPOINT_ACCESS: case GDB_WATCHPOINT_ACCESS:
CPU_FOREACH(cpu) { 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) if (err)
break; break;
} }
......
...@@ -99,6 +99,8 @@ struct TranslationBlock; ...@@ -99,6 +99,8 @@ struct TranslationBlock;
* @vmsd: State description for migration. * @vmsd: State description for migration.
* @gdb_num_core_regs: Number of core registers accessible to GDB. * @gdb_num_core_regs: Number of core registers accessible to GDB.
* @gdb_core_xml_file: File name for core registers GDB XML description. * @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_enter: Callback for cpu_exec preparation.
* @cpu_exec_exit: Callback for cpu_exec cleanup. * @cpu_exec_exit: Callback for cpu_exec cleanup.
* @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec. * @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec.
...@@ -152,6 +154,7 @@ typedef struct CPUClass { ...@@ -152,6 +154,7 @@ typedef struct CPUClass {
const struct VMStateDescription *vmsd; const struct VMStateDescription *vmsd;
int gdb_num_core_regs; int gdb_num_core_regs;
const char *gdb_core_xml_file; const char *gdb_core_xml_file;
bool gdb_stop_before_watchpoint;
void (*cpu_exec_enter)(CPUState *cpu); void (*cpu_exec_enter)(CPUState *cpu);
void (*cpu_exec_exit)(CPUState *cpu); void (*cpu_exec_exit)(CPUState *cpu);
......
...@@ -1117,6 +1117,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) ...@@ -1117,6 +1117,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
#endif #endif
cc->gdb_num_core_regs = 26; cc->gdb_num_core_regs = 26;
cc->gdb_core_xml_file = "arm-core.xml"; cc->gdb_core_xml_file = "arm-core.xml";
cc->gdb_stop_before_watchpoint = true;
cc->debug_excp_handler = arm_debug_excp_handler; cc->debug_excp_handler = arm_debug_excp_handler;
} }
......
...@@ -291,6 +291,7 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data) ...@@ -291,6 +291,7 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data)
#endif #endif
cc->gdb_num_core_regs = 49; cc->gdb_num_core_regs = 49;
cc->gdb_stop_before_watchpoint = true;
} }
static const TypeInfo cris_cpu_type_info = { static const TypeInfo cris_cpu_type_info = {
......
...@@ -273,6 +273,7 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data) ...@@ -273,6 +273,7 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data)
cc->vmsd = &vmstate_lm32_cpu; cc->vmsd = &vmstate_lm32_cpu;
#endif #endif
cc->gdb_num_core_regs = 32 + 7; cc->gdb_num_core_regs = 32 + 7;
cc->gdb_stop_before_watchpoint = true;
cc->debug_excp_handler = lm32_debug_excp_handler; cc->debug_excp_handler = lm32_debug_excp_handler;
} }
......
...@@ -151,6 +151,7 @@ static void mips_cpu_class_init(ObjectClass *c, void *data) ...@@ -151,6 +151,7 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
#endif #endif
cc->gdb_num_core_regs = 73; cc->gdb_num_core_regs = 73;
cc->gdb_stop_before_watchpoint = true;
} }
static const TypeInfo mips_cpu_type_info = { static const TypeInfo mips_cpu_type_info = {
......
...@@ -147,6 +147,7 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data) ...@@ -147,6 +147,7 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
cc->set_pc = xtensa_cpu_set_pc; cc->set_pc = xtensa_cpu_set_pc;
cc->gdb_read_register = xtensa_cpu_gdb_read_register; cc->gdb_read_register = xtensa_cpu_gdb_read_register;
cc->gdb_write_register = xtensa_cpu_gdb_write_register; cc->gdb_write_register = xtensa_cpu_gdb_write_register;
cc->gdb_stop_before_watchpoint = true;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cc->do_unaligned_access = xtensa_cpu_do_unaligned_access; cc->do_unaligned_access = xtensa_cpu_do_unaligned_access;
cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug; cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment