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:
parent
85425bdc5a
commit
4beb385813
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user