Index: sys/amd64/amd64/gdb_machdep.c =================================================================== --- sys/amd64/amd64/gdb_machdep.c +++ sys/amd64/amd64/gdb_machdep.c @@ -152,6 +152,43 @@ return (SIGEMT); } +char * +gdb_cpu_stop_reason(int type, uintmax_t *val) +{ + uint64_t dr6; + char *reason; + + *val = 0; + reason = NULL; + if (type == T_TRCTRAP) { + dr6 = rdr6(); + load_dr6(dr6 & ~DBREG_DR6_BMASK); + + if ((dr6 & DBREG_DR6_B(0)) != 0) { + *val = rdr0(); + } + if ((dr6 & DBREG_DR6_B(1)) != 0) { + *val = rdr1(); + } + if ((dr6 & DBREG_DR6_B(2)) != 0) { + *val = rdr2(); + } + if ((dr6 & DBREG_DR6_B(3)) != 0) { + *val = rdr3(); + } + + /* + * TODO: validate the bits in DR7 to differentiate between a + * watchpoint trap and a hardware breakpoint trap (currently + * unsupported). + */ + if (*val != 0) + reason = "watch"; + } + + return (reason); +} + 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 *); +char *gdb_cpu_stop_reason(int type, uintmax_t *val); #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 char * +gdb_cpu_stop_reason(int type __unused, uintmax_t *val __unused) +{ + + /* Not implemented. */ + return (NULL); +} + void *gdb_cpu_getreg(int, size_t *); void gdb_cpu_setreg(int, void *); int gdb_cpu_signal(int, int); Index: sys/arm64/arm64/gdb_machdep.c =================================================================== --- sys/arm64/arm64/gdb_machdep.c +++ sys/arm64/arm64/gdb_machdep.c @@ -110,3 +110,15 @@ } return (SIGEMT); } + +char * +gdb_cpu_stop_reason(int type, uintmax_t *val) +{ + + if (type == EXCP_WATCHPT_EL1) { + *val = READ_SPECIALREG(far_el1); + return ("watch"); + } + + return (NULL); +} Index: sys/arm64/include/gdb_machdep.h =================================================================== --- sys/arm64/include/gdb_machdep.h +++ sys/arm64/include/gdb_machdep.h @@ -77,5 +77,6 @@ void *gdb_cpu_getreg(int, size_t *); void gdb_cpu_setreg(int, void *); int gdb_cpu_signal(int, int); +char *gdb_cpu_stop_reason(int type, uintmax_t *val); #endif /* !_MACHINE_GDB_MACHDEP_H_ */ Index: sys/gdb/gdb_main.c =================================================================== --- sys/gdb/gdb_main.c +++ sys/gdb/gdb_main.c @@ -712,6 +712,31 @@ 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_stop_reason(int type) +{ + char *reason; + uintmax_t val; + + reason = gdb_cpu_stop_reason(type, &val); + if (reason != NULL) { + gdb_tx_str(reason); + gdb_tx_char(':'); + if (val != 0) + gdb_tx_varhex(val); + gdb_tx_char(';'); + } +} + static int gdb_trap(int type, int code) { @@ -741,8 +766,9 @@ gdb_tx_char(':'); gdb_tx_reg(GDB_REG_PC); gdb_tx_char(';'); + gdb_stop_reason(type); gdb_tx_str("thread:"); - gdb_tx_varhex((long)kdb_thread->td_tid); + gdb_tx_varhex((uintmax_t)kdb_thread->td_tid); 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,40 @@ } return (SIGEMT); } + +char * +gdb_cpu_stop_reason(int type, uintmax_t *val) +{ + uint64_t dr6; + char *reason; + + *val = 0; + reason = NULL; + if (type == T_TRCTRAP) { + dr6 = rdr6(); + load_dr6(dr6 & ~DBREG_DR6_BMASK); + + if ((dr6 & DBREG_DR6_B(0)) != 0) { + *val = rdr0(); + } + if ((dr6 & DBREG_DR6_B(1)) != 0) { + *val = rdr1(); + } + if ((dr6 & DBREG_DR6_B(2)) != 0) { + *val = rdr2(); + } + if ((dr6 & DBREG_DR6_B(3)) != 0) { + *val = rdr3(); + } + + /* + * TODO: validate the bits in DR7 to differentiate between a + * watchpoint trap and a hardware breakpoint trap (currently + * unsupported). + */ + if (*val != 0) + reason = "watch"; + } + + return (reason); +} 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); +char *gdb_cpu_stop_reason(int type, uintmax_t *val); #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,14 @@ } +static __inline char * +gdb_cpu_stop_reason(int type __unused, uintmax_t *val __unused) +{ + + /* Not implemented. */ + return (NULL); +} + 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,14 @@ } +static __inline char * +gdb_cpu_stop_reason(int type __unused, uintmax_t *val __unused) +{ + + /* Not implemented. */ + return (NULL); +} + void *gdb_cpu_getreg(int, size_t *); void gdb_cpu_setreg(int, void *); int gdb_cpu_signal(int, int);