diff options
author | Mitchell Horne <mhorne@FreeBSD.org> | 2021-03-08 19:03:45 +0000 |
---|---|---|
committer | Mitchell Horne <mhorne@FreeBSD.org> | 2021-03-30 14:36:41 +0000 |
commit | 4beb385813c8b1014f8250a31b07fdc09a059713 (patch) | |
tree | b8c798a9029beac30b464583742979c4623a32e9 /sys/gdb | |
parent | 85425bdc5a80c948f99aa046f9c48512466806dd (diff) | |
download | src-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')
-rw-r--r-- | sys/gdb/gdb_main.c | 102 |
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 */ |