Skip to content

Commit 2472b6c

Browse files
committed
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: Peter Maydell <[email protected]> Reviewed-by: Edgar E. Iglesias <[email protected]> Tested-by: Max Filippov <[email protected]> Tested-by: Edgar E. Iglesias <[email protected]> Tested-by: Michael Walle <[email protected]> (for lm32) Message-id: [email protected]
1 parent 507ef2f commit 2472b6c

File tree

7 files changed

+31
-9
lines changed

7 files changed

+31
-9
lines changed

gdbstub.c

+23-9
Original file line numberDiff line numberDiff line change
@@ -625,11 +625,23 @@ void gdb_register_coprocessor(CPUState *cpu,
625625
}
626626

627627
#ifndef CONFIG_USER_ONLY
628-
static const int xlat_gdb_type[] = {
629-
[GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE,
630-
[GDB_WATCHPOINT_READ] = BP_GDB | BP_MEM_READ,
631-
[GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS,
632-
};
628+
/* Translate GDB watchpoint type to a flags value for cpu_watchpoint_* */
629+
static inline int xlat_gdb_type(CPUState *cpu, int gdbtype)
630+
{
631+
static const int xlat[] = {
632+
[GDB_WATCHPOINT_WRITE] = BP_GDB | BP_MEM_WRITE,
633+
[GDB_WATCHPOINT_READ] = BP_GDB | BP_MEM_READ,
634+
[GDB_WATCHPOINT_ACCESS] = BP_GDB | BP_MEM_ACCESS,
635+
};
636+
637+
CPUClass *cc = CPU_GET_CLASS(cpu);
638+
int cputype = xlat[gdbtype];
639+
640+
if (cc->gdb_stop_before_watchpoint) {
641+
cputype |= BP_STOP_BEFORE_ACCESS;
642+
}
643+
return cputype;
644+
}
633645
#endif
634646

635647
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)
656668
case GDB_WATCHPOINT_READ:
657669
case GDB_WATCHPOINT_ACCESS:
658670
CPU_FOREACH(cpu) {
659-
err = cpu_watchpoint_insert(cpu, addr, len, xlat_gdb_type[type],
660-
NULL);
661-
if (err)
671+
err = cpu_watchpoint_insert(cpu, addr, len,
672+
xlat_gdb_type(cpu, type), NULL);
673+
if (err) {
662674
break;
675+
}
663676
}
664677
return err;
665678
#endif
@@ -692,7 +705,8 @@ static int gdb_breakpoint_remove(target_ulong addr, target_ulong len, int type)
692705
case GDB_WATCHPOINT_READ:
693706
case GDB_WATCHPOINT_ACCESS:
694707
CPU_FOREACH(cpu) {
695-
err = cpu_watchpoint_remove(cpu, addr, len, xlat_gdb_type[type]);
708+
err = cpu_watchpoint_remove(cpu, addr, len,
709+
xlat_gdb_type(cpu, type));
696710
if (err)
697711
break;
698712
}

include/qom/cpu.h

+3
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ struct TranslationBlock;
9999
* @vmsd: State description for migration.
100100
* @gdb_num_core_regs: Number of core registers accessible to GDB.
101101
* @gdb_core_xml_file: File name for core registers GDB XML description.
102+
* @gdb_stop_before_watchpoint: Indicates whether GDB expects the CPU to stop
103+
* before the insn which triggers a watchpoint rather than after it.
102104
* @cpu_exec_enter: Callback for cpu_exec preparation.
103105
* @cpu_exec_exit: Callback for cpu_exec cleanup.
104106
* @cpu_exec_interrupt: Callback for processing interrupts in cpu_exec.
@@ -152,6 +154,7 @@ typedef struct CPUClass {
152154
const struct VMStateDescription *vmsd;
153155
int gdb_num_core_regs;
154156
const char *gdb_core_xml_file;
157+
bool gdb_stop_before_watchpoint;
155158

156159
void (*cpu_exec_enter)(CPUState *cpu);
157160
void (*cpu_exec_exit)(CPUState *cpu);

target-arm/cpu.c

+1
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
11171117
#endif
11181118
cc->gdb_num_core_regs = 26;
11191119
cc->gdb_core_xml_file = "arm-core.xml";
1120+
cc->gdb_stop_before_watchpoint = true;
11201121
cc->debug_excp_handler = arm_debug_excp_handler;
11211122
}
11221123

target-cris/cpu.c

+1
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,7 @@ static void cris_cpu_class_init(ObjectClass *oc, void *data)
291291
#endif
292292

293293
cc->gdb_num_core_regs = 49;
294+
cc->gdb_stop_before_watchpoint = true;
294295
}
295296

296297
static const TypeInfo cris_cpu_type_info = {

target-lm32/cpu.c

+1
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ static void lm32_cpu_class_init(ObjectClass *oc, void *data)
273273
cc->vmsd = &vmstate_lm32_cpu;
274274
#endif
275275
cc->gdb_num_core_regs = 32 + 7;
276+
cc->gdb_stop_before_watchpoint = true;
276277
cc->debug_excp_handler = lm32_debug_excp_handler;
277278
}
278279

target-mips/cpu.c

+1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
151151
#endif
152152

153153
cc->gdb_num_core_regs = 73;
154+
cc->gdb_stop_before_watchpoint = true;
154155
}
155156

156157
static const TypeInfo mips_cpu_type_info = {

target-xtensa/cpu.c

+1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ static void xtensa_cpu_class_init(ObjectClass *oc, void *data)
147147
cc->set_pc = xtensa_cpu_set_pc;
148148
cc->gdb_read_register = xtensa_cpu_gdb_read_register;
149149
cc->gdb_write_register = xtensa_cpu_gdb_write_register;
150+
cc->gdb_stop_before_watchpoint = true;
150151
#ifndef CONFIG_USER_ONLY
151152
cc->do_unaligned_access = xtensa_cpu_do_unaligned_access;
152153
cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug;

0 commit comments

Comments
 (0)