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
This commit is contained in:
Mitchell Horne 2021-03-08 15:03:45 -04:00
parent 85425bdc5a
commit 4beb385813
5 changed files with 110 additions and 5 deletions

View File

@ -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)
{

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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