Index: sys/amd64/amd64/gdb_machdep.c =================================================================== --- sys/amd64/amd64/gdb_machdep.c +++ sys/amd64/amd64/gdb_machdep.c @@ -152,6 +152,36 @@ return (SIGEMT); } +bool +gdb_is_watchpoint_trap(int type, uintptr_t *addr) +{ + uint64_t dr6; + + if (type != T_TRCTRAP) + return (false); + + dr6 = rdr6(); + load_dr6(dr6 & ~DBREG_DR6_BMASK); + + if ((dr6 & DBREG_DR6_B(0)) != 0) { + *addr = rdr0(); + return (true); + } + if ((dr6 & DBREG_DR6_B(1)) != 0) { + *addr = rdr1(); + return (true); + } + if ((dr6 & DBREG_DR6_B(2)) != 0) { + *addr = rdr2(); + return (true); + } + if ((dr6 & DBREG_DR6_B(3)) != 0) { + *addr = rdr3(); + return (true); + } + return (false); +} + void * gdb_begin_write(void) { Index: sys/amd64/include/gdb_machdep.h =================================================================== --- sys/amd64/include/gdb_machdep.h +++ sys/amd64/include/gdb_machdep.h @@ -72,5 +72,6 @@ void gdb_cpu_setreg(int, void *); int gdb_cpu_signal(int, int); void gdb_end_write(void *); +bool gdb_is_watchpoint_trap(int type, uintptr_t *addr); #endif /* !_MACHINE_GDB_MACHDEP_H_ */ Index: sys/arm/include/gdb_machdep.h =================================================================== --- sys/arm/include/gdb_machdep.h +++ sys/arm/include/gdb_machdep.h @@ -66,6 +66,14 @@ } +static __inline bool +gdb_is_watchpoint_trap(int type __unused, uintptr_t *addr __unused) +{ + + /* Return false since we can't trivially find addr. */ + return (false); +} + void *gdb_cpu_getreg(int, size_t *); void gdb_cpu_setreg(int, void *); int gdb_cpu_signal(int, int); Index: sys/arm64/include/gdb_machdep.h =================================================================== --- sys/arm64/include/gdb_machdep.h +++ sys/arm64/include/gdb_machdep.h @@ -78,4 +78,12 @@ void gdb_cpu_setreg(int, void *); int gdb_cpu_signal(int, int); +static __inline bool +gdb_is_watchpoint_trap(int type __unused, uintptr_t *addr __unused) +{ + + /* Return false since we can't trivially find addr. */ + return (false); +} + #endif /* !_MACHINE_GDB_MACHDEP_H_ */ Index: sys/gdb/gdb_main.c =================================================================== --- sys/gdb/gdb_main.c +++ sys/gdb/gdb_main.c @@ -716,6 +716,28 @@ return; } +/* + * Communicate the stop reason for the trap to the gdb client. + * + * Normally, this is simply "thread:$tid". We can prepend more specific trap + * reasons when they are detected, such as the address that triggered a + * watchpoint. Doing so is never required, however. + * + * https://sourceware.org/gdb/onlinedocs/gdb/Stop-Reply-Packets.html + */ +static void +gdb_trap_reason(int type) +{ + uintptr_t watch_addr; + + if (gdb_is_watchpoint_trap(type, &watch_addr)) { + gdb_tx_str("watch:"); + gdb_tx_varhex(watch_addr); + } + gdb_tx_str("thread:"); + gdb_tx_varhex((uintmax_t)kdb_thread->td_tid); +} + static int gdb_trap(int type, int code) { @@ -745,8 +767,7 @@ gdb_tx_char(':'); gdb_tx_reg(GDB_REG_PC); gdb_tx_char(';'); - gdb_tx_str("thread:"); - gdb_tx_varhex((long)kdb_thread->td_tid); + gdb_trap_reason(type); gdb_tx_char(';'); gdb_tx_end(); /* XXX check error condition. */ Index: sys/i386/i386/gdb_machdep.c =================================================================== --- sys/i386/i386/gdb_machdep.c +++ sys/i386/i386/gdb_machdep.c @@ -36,11 +36,12 @@ #include #include +#include +#include #include #include +#include #include -#include -#include #include @@ -114,3 +115,33 @@ } return (SIGEMT); } + +bool +gdb_is_watchpoint_trap(int type, uintptr_t *addr) +{ + uint64_t dr6; + + if (type != T_TRCTRAP) + return (false); + + dr6 = rdr6(); + load_dr6(dr6 & ~DBREG_DR6_BMASK); + + if ((dr6 & DBREG_DR6_B(0)) != 0) { + *addr = rdr0(); + return (true); + } + if ((dr6 & DBREG_DR6_B(1)) != 0) { + *addr = rdr1(); + return (true); + } + if ((dr6 & DBREG_DR6_B(2)) != 0) { + *addr = rdr2(); + return (true); + } + if ((dr6 & DBREG_DR6_B(3)) != 0) { + *addr = rdr3(); + return (true); + } + return (false); +} Index: sys/i386/include/gdb_machdep.h =================================================================== --- sys/i386/include/gdb_machdep.h +++ sys/i386/include/gdb_machdep.h @@ -63,5 +63,6 @@ void *gdb_cpu_getreg(int, size_t *); void gdb_cpu_setreg(int, void *); int gdb_cpu_signal(int, int); +bool gdb_is_watchpoint_trap(int type, uintptr_t *addr); #endif /* !_MACHINE_GDB_MACHDEP_H_ */ Index: sys/mips/include/gdb_machdep.h =================================================================== --- sys/mips/include/gdb_machdep.h +++ sys/mips/include/gdb_machdep.h @@ -64,6 +64,13 @@ } +static __inline bool +gdb_is_watchpoint_trap(int type __unused, uintptr_t *addr __unused) +{ + + return (false); +} + void *gdb_cpu_getreg(int, size_t *); void gdb_cpu_setreg(int, void *); int gdb_cpu_signal(int, int); Index: sys/powerpc/include/gdb_machdep.h =================================================================== --- sys/powerpc/include/gdb_machdep.h +++ sys/powerpc/include/gdb_machdep.h @@ -128,6 +128,13 @@ } +static __inline bool +gdb_is_watchpoint_trap(int type __unused, uintptr_t *addr __unused) +{ + + return (false); +} + void *gdb_cpu_getreg(int, size_t *); void gdb_cpu_setreg(int, void *); int gdb_cpu_signal(int, int);