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 | |
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
-rw-r--r-- | sys/arm64/arm64/debug_monitor.c | 5 | ||||
-rw-r--r-- | sys/conf/files.arm | 3 | ||||
-rw-r--r-- | sys/conf/files.x86 | 2 | ||||
-rw-r--r-- | sys/gdb/gdb_main.c | 102 | ||||
-rw-r--r-- | sys/x86/x86/mp_x86.c | 3 |
5 files changed, 110 insertions, 5 deletions
diff --git a/sys/arm64/arm64/debug_monitor.c b/sys/arm64/arm64/debug_monitor.c index 845784129b4c..c3dce1883e68 100644 --- a/sys/arm64/arm64/debug_monitor.c +++ b/sys/arm64/arm64/debug_monitor.c @@ -28,6 +28,7 @@ */ #include "opt_ddb.h" +#include "opt_gdb.h" #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -181,7 +182,7 @@ dbg_wb_write_reg(int reg, int n, uint64_t val) isb(); } -#ifdef DDB +#if defined(DDB) || defined(GDB) void kdb_cpu_set_singlestep(void) { @@ -254,7 +255,9 @@ kdb_cpu_clr_watchpoint(vm_offset_t addr, vm_size_t size) return (dbg_remove_watchpoint(NULL, addr, size)); } +#endif /* DDB || GDB */ +#ifdef DDB static const char * dbg_watchtype_str(uint32_t type) { diff --git a/sys/conf/files.arm b/sys/conf/files.arm index 69986585bdf6..a3b0d166f020 100644 --- a/sys/conf/files.arm +++ b/sys/conf/files.arm @@ -19,8 +19,7 @@ arm/arm/cpu_asm-v6.S standard arm/arm/db_disasm.c optional ddb arm/arm/db_interface.c optional ddb arm/arm/db_trace.c optional ddb -arm/arm/debug_monitor.c optional ddb armv6 -arm/arm/debug_monitor.c optional ddb armv7 +arm/arm/debug_monitor.c optional ddb | gdb arm/arm/disassem.c optional ddb arm/arm/dump_machdep.c standard arm/arm/elf_machdep.c standard diff --git a/sys/conf/files.x86 b/sys/conf/files.x86 index fd31d95fa162..0f83126e99a6 100644 --- a/sys/conf/files.x86 +++ b/sys/conf/files.x86 @@ -320,7 +320,7 @@ x86/x86/bus_machdep.c standard x86/x86/busdma_bounce.c standard x86/x86/busdma_machdep.c standard x86/x86/cpu_machdep.c standard -x86/x86/dbreg.c optional ddb +x86/x86/dbreg.c optional ddb | gdb x86/x86/dump_machdep.c standard x86/x86/fdt_machdep.c optional fdt x86/x86/identcpu.c standard 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 */ diff --git a/sys/x86/x86/mp_x86.c b/sys/x86/x86/mp_x86.c index 0f528f6567ee..2dcdf923c467 100644 --- a/sys/x86/x86/mp_x86.c +++ b/sys/x86/x86/mp_x86.c @@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$"); #endif #include "opt_cpu.h" #include "opt_ddb.h" +#include "opt_gdb.h" #include "opt_kstack_pages.h" #include "opt_pmap.h" #include "opt_sched.h" @@ -1520,7 +1521,7 @@ cpustop_handler_post(u_int cpu) */ invltlb_glob(); -#if defined(__amd64__) && defined(DDB) +#if defined(__amd64__) && (defined(DDB) || defined(GDB)) amd64_db_resume_dbreg(); #endif |