aboutsummaryrefslogtreecommitdiff
path: root/sys/gdb/gdb_main.c
diff options
context:
space:
mode:
authorMitchell Horne <mhorne@FreeBSD.org>2021-03-08 19:03:45 +0000
committerMitchell Horne <mhorne@FreeBSD.org>2021-03-30 14:36:41 +0000
commit4beb385813c8b1014f8250a31b07fdc09a059713 (patch)
treeb8c798a9029beac30b464583742979c4623a32e9 /sys/gdb/gdb_main.c
parent85425bdc5a80c948f99aa046f9c48512466806dd (diff)
downloadsrc-4beb385813c8b1014f8250a31b07fdc09a059713.tar.gz
src-4beb385813c8b1014f8250a31b07fdc09a059713.zip
gdb: allow setting/removing hardware watchpoints
Handle the 'z' and 'Z' remote packets for manipulating hardware watchpoints. This could be expanded quite easily to support hardware or software breakpoints as well. https://sourceware.org/gdb/onlinedocs/gdb/Packets.html Reviewed by: cem, markj MFC after: 3 weeks Sponsored by: NetApp, Inc. Sponsored by: Klara, Inc. NetApp PR: 51 Differential Revision: https://reviews.freebsd.org/D29173
Diffstat (limited to 'sys/gdb/gdb_main.c')
-rw-r--r--sys/gdb/gdb_main.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/sys/gdb/gdb_main.c b/sys/gdb/gdb_main.c
index a9e935ebfbb5..a4469fdf4997 100644
--- a/sys/gdb/gdb_main.c
+++ b/sys/gdb/gdb_main.c
@@ -618,6 +618,100 @@ gdb_handle_detach(void)
#endif
}
+/*
+ * Handle a 'Z' packet: set a breakpoint or watchpoint.
+ *
+ * Currently, only watchpoints are supported.
+ */
+static void
+gdb_z_insert(void)
+{
+ intmax_t addr, length;
+ char ztype;
+ int error;
+
+ ztype = gdb_rx_char();
+ if (gdb_rx_char() != ',' || gdb_rx_varhex(&addr) ||
+ gdb_rx_char() != ',' || gdb_rx_varhex(&length)) {
+ error = EINVAL;
+ goto fail;
+ }
+
+ switch (ztype) {
+ case '2': /* write watchpoint */
+ error = kdb_cpu_set_watchpoint((vm_offset_t)addr,
+ (vm_size_t)length, KDB_DBG_ACCESS_W);
+ break;
+ case '3': /* read watchpoint */
+ error = kdb_cpu_set_watchpoint((vm_offset_t)addr,
+ (vm_size_t)length, KDB_DBG_ACCESS_R);
+ break;
+ case '4': /* access (RW) watchpoint */
+ error = kdb_cpu_set_watchpoint((vm_offset_t)addr,
+ (vm_size_t)length, KDB_DBG_ACCESS_RW);
+ break;
+ case '1': /* hardware breakpoint */
+ case '0': /* software breakpoint */
+ /* Not implemented. */
+ gdb_tx_empty();
+ return;
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (error != 0)
+ goto fail;
+ gdb_tx_ok();
+ return;
+fail:
+ gdb_tx_err(error);
+ return;
+}
+
+/*
+ * Handle a 'z' packet; clear a breakpoint or watchpoint.
+ *
+ * Currently, only watchpoints are supported.
+ */
+static void
+gdb_z_remove(void)
+{
+ intmax_t addr, length;
+ char ztype;
+ int error;
+
+ ztype = gdb_rx_char();
+ if (gdb_rx_char() != ',' || gdb_rx_varhex(&addr) ||
+ gdb_rx_char() != ',' || gdb_rx_varhex(&length)) {
+ error = EINVAL;
+ goto fail;
+ }
+
+ switch (ztype) {
+ case '2': /* write watchpoint */
+ case '3': /* read watchpoint */
+ case '4': /* access (RW) watchpoint */
+ error = kdb_cpu_clr_watchpoint((vm_offset_t)addr,
+ (vm_size_t)length);
+ break;
+ case '1': /* hardware breakpoint */
+ case '0': /* software breakpoint */
+ /* Not implemented. */
+ gdb_tx_empty();
+ return;
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (error != 0)
+ goto fail;
+ gdb_tx_ok();
+ return;
+fail:
+ gdb_tx_err(error);
+ return;
+}
+
static int
gdb_trap(int type, int code)
{
@@ -868,6 +962,14 @@ gdb_trap(int type, int code)
gdb_tx_err(ENOENT);
break;
}
+ case 'z': { /* Remove watchpoint. */
+ gdb_z_remove();
+ break;
+ }
+ case 'Z': { /* Set watchpoint. */
+ gdb_z_insert();
+ break;
+ }
case EOF:
/* Empty command. Treat as unknown command. */
/* FALLTHROUGH */