Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Apr 2021 14:31:12 GMT
From:      Mitchell Horne <mhorne@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 47301dfb9abd - stable/13 - x86: consolidate hw watchpoint logic into new file
Message-ID:  <202104211431.13LEVCsj047640@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=47301dfb9abd30278eebd36d4f283e6bb256fffe

commit 47301dfb9abd30278eebd36d4f283e6bb256fffe
Author:     Mitchell Horne <mhorne@FreeBSD.org>
AuthorDate: 2021-03-19 19:39:12 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2021-04-21 13:20:32 +0000

    x86: consolidate hw watchpoint logic into new file
    
    This is a prerequisite to using these functions outside of ddb, but also
    provides some cleanup and minor refactoring. This code is almost
    entirely duplicated between the two implementations, the only
    significant difference being the lack of dbreg synchronization on i386.
    
    Cleanups are:
     - demote some internal functions to static
     - use the constant NDBREGS instead of a '4' literal
     - remove K&R definitions
     - some added comments
    
    Reviewed by:    kib, jhb
    Sponsored by:   NetApp, Inc.
    Sponsored by:   Klara, Inc.
    
    (cherry picked from commit c02c04f113fe65001bc21363ae3ad08cf6c763eb)
---
 sys/amd64/amd64/db_trace.c | 216 +-----------------------------------
 sys/conf/files.x86         |   1 +
 sys/i386/i386/db_trace.c   | 173 +----------------------------
 sys/x86/include/x86_var.h  |   3 +
 sys/x86/x86/dbreg.c        | 267 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 281 insertions(+), 379 deletions(-)

diff --git a/sys/amd64/amd64/db_trace.c b/sys/amd64/amd64/db_trace.c
index 7d1544a5d0bc..5c1cd41cda15 100644
--- a/sys/amd64/amd64/db_trace.c
+++ b/sys/amd64/amd64/db_trace.c
@@ -128,11 +128,6 @@ static void db_nextframe(struct amd64_frame **, db_addr_t *, struct thread *);
 static void db_print_stack_entry(const char *, db_addr_t, void *);
 static void decode_syscall(int, struct thread *);
 
-static const char * watchtype_str(int type);
-int  amd64_set_watch(int watchnum, unsigned long watchaddr, int size,
-		    int access, struct dbreg *d);
-int  amd64_clr_watch(int watchnum, struct dbreg *d);
-
 static void
 db_print_stack_entry(const char *name, db_addr_t callpc, void *frame)
 {
@@ -391,223 +386,22 @@ db_trace_thread(struct thread *thr, int count)
 }
 
 int
-amd64_set_watch(watchnum, watchaddr, size, access, d)
-	int watchnum;
-	unsigned long watchaddr;
-	int size;
-	int access;
-	struct dbreg *d;
-{
-	int i, len;
-
-	if (watchnum == -1) {
-		for (i = 0; i < 4; i++)
-			if (!DBREG_DR7_ENABLED(d->dr[7], i))
-				break;
-		if (i < 4)
-			watchnum = i;
-		else
-			return (-1);
-	}
-
-	switch (access) {
-	case DBREG_DR7_EXEC:
-		size = 1; /* size must be 1 for an execution breakpoint */
-		/* fall through */
-	case DBREG_DR7_WRONLY:
-	case DBREG_DR7_RDWR:
-		break;
-	default:
-		return (-1);
-	}
-
-	/*
-	 * we can watch a 1, 2, 4, or 8 byte sized location
-	 */
-	switch (size) {
-	case 1:
-		len = DBREG_DR7_LEN_1;
-		break;
-	case 2:
-		len = DBREG_DR7_LEN_2;
-		break;
-	case 4:
-		len = DBREG_DR7_LEN_4;
-		break;
-	case 8:
-		len = DBREG_DR7_LEN_8;
-		break;
-	default:
-		return (-1);
-	}
-
-	/* clear the bits we are about to affect */
-	d->dr[7] &= ~DBREG_DR7_MASK(watchnum);
-
-	/* set drN register to the address, N=watchnum */
-	DBREG_DRX(d, watchnum) = watchaddr;
-
-	/* enable the watchpoint */
-	d->dr[7] |= DBREG_DR7_SET(watchnum, len, access,
-	    DBREG_DR7_GLOBAL_ENABLE);
-
-	return (watchnum);
-}
-
-int
-amd64_clr_watch(watchnum, d)
-	int watchnum;
-	struct dbreg *d;
-{
-
-	if (watchnum < 0 || watchnum >= 4)
-		return (-1);
-
-	d->dr[7] &= ~DBREG_DR7_MASK(watchnum);
-	DBREG_DRX(d, watchnum) = 0;
-
-	return (0);
-}
-
-int
-db_md_set_watchpoint(addr, size)
-	db_expr_t addr;
-	db_expr_t size;
+db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
 {
-	struct dbreg *d;
-	struct pcpu *pc;
-	int avail, c, cpu, i, wsize;
-
-	d = (struct dbreg *)PCPU_PTR(dbreg);
-	cpu = PCPU_GET(cpuid);
-	fill_dbregs(NULL, d);
-
-	avail = 0;
-	for (i = 0; i < 4; i++) {
-		if (!DBREG_DR7_ENABLED(d->dr[7], i))
-			avail++;
-	}
-
-	if (avail * 8 < size)
-		return (-1);
-
-	for (i = 0; i < 4 && size > 0; i++) {
-		if (!DBREG_DR7_ENABLED(d->dr[7], i)) {
-			if (size >= 8 || (avail == 1 && size > 4))
-				wsize = 8;
-			else if (size > 2)
-				wsize = 4;
-			else
-				wsize = size;
-			amd64_set_watch(i, addr, wsize, DBREG_DR7_WRONLY, d);
-			addr += wsize;
-			size -= wsize;
-			avail--;
-		}
-	}
-
-	set_dbregs(NULL, d);
-	CPU_FOREACH(c) {
-		if (c == cpu)
-			continue;
-		pc = pcpu_find(c);
-		memcpy(pc->pc_dbreg, d, sizeof(*d));
-		pc->pc_dbreg_cmd = PC_DBREG_CMD_LOAD;
-	}
 
-	return (0);
+	return (dbreg_set_watchpoint((vm_offset_t)addr, (vm_size_t)size));
 }
 
 int
-db_md_clr_watchpoint(addr, size)
-	db_expr_t addr;
-	db_expr_t size;
+db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
 {
-	struct dbreg *d;
-	struct pcpu *pc;
-	int i, c, cpu;
-
-	d = (struct dbreg *)PCPU_PTR(dbreg);
-	cpu = PCPU_GET(cpuid);
-	fill_dbregs(NULL, d);
-
-	for (i = 0; i < 4; i++) {
-		if (DBREG_DR7_ENABLED(d->dr[7], i)) {
-			if (DBREG_DRX((d), i) >= addr &&
-			    DBREG_DRX((d), i) < addr + size)
-				amd64_clr_watch(i, d);
-		}
-	}
-
-	set_dbregs(NULL, d);
-	CPU_FOREACH(c) {
-		if (c == cpu)
-			continue;
-		pc = pcpu_find(c);
-		memcpy(pc->pc_dbreg, d, sizeof(*d));
-		pc->pc_dbreg_cmd = PC_DBREG_CMD_LOAD;
-	}
 
-	return (0);
-}
-
-static const char *
-watchtype_str(type)
-	int type;
-{
-	switch (type) {
-		case DBREG_DR7_EXEC   : return "execute";    break;
-		case DBREG_DR7_RDWR   : return "read/write"; break;
-		case DBREG_DR7_WRONLY : return "write";	     break;
-		default		      : return "invalid";    break;
-	}
+	return (dbreg_clr_watchpoint((vm_offset_t)addr, (vm_size_t)size));
 }
 
 void
 db_md_list_watchpoints(void)
 {
-	struct dbreg d;
-	int i, len, type;
-
-	fill_dbregs(NULL, &d);
-
-	db_printf("\nhardware watchpoints:\n");
-	db_printf("  watch    status        type  len             address\n");
-	db_printf("  -----  --------  ----------  ---  ------------------\n");
-	for (i = 0; i < 4; i++) {
-		if (DBREG_DR7_ENABLED(d.dr[7], i)) {
-			type = DBREG_DR7_ACCESS(d.dr[7], i);
-			len = DBREG_DR7_LEN(d.dr[7], i);
-			if (len == DBREG_DR7_LEN_8)
-				len = 8;
-			else
-				len++;
-			db_printf("  %-5d  %-8s  %10s  %3d  ",
-			    i, "enabled", watchtype_str(type), len);
-			db_printsym((db_addr_t)DBREG_DRX(&d, i), DB_STGY_ANY);
-			db_printf("\n");
-		} else {
-			db_printf("  %-5d  disabled\n", i);
-		}
-	}
 
-	db_printf("\ndebug register values:\n");
-	for (i = 0; i < 8; i++)
-		if (i != 4 && i != 5)
-			db_printf("  dr%d 0x%016lx\n", i, DBREG_DRX(&d, i));
-	db_printf("\n");
-}
-
-void
-amd64_db_resume_dbreg(void)
-{
-	struct dbreg *d;
-
-	switch (PCPU_GET(dbreg_cmd)) {
-	case PC_DBREG_CMD_LOAD:
-		d = (struct dbreg *)PCPU_PTR(dbreg);
-		set_dbregs(NULL, d);
-		PCPU_SET(dbreg_cmd, PC_DBREG_CMD_NONE);
-		break;
-	}
+	dbreg_list_watchpoints();
 }
diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
index f51392d0614c..292389ac312f 100644
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -331,6 +331,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/dump_machdep.c		standard
 x86/x86/fdt_machdep.c		optional	fdt
 x86/x86/identcpu.c		standard
diff --git a/sys/i386/i386/db_trace.c b/sys/i386/i386/db_trace.c
index 87229e74e70b..50fb1fa6355d 100644
--- a/sys/i386/i386/db_trace.c
+++ b/sys/i386/i386/db_trace.c
@@ -198,11 +198,6 @@ static void db_print_stack_entry(const char *, int, char **, int *, db_addr_t,
     void *);
 static void decode_syscall(int, struct thread *);
 
-static const char * watchtype_str(int type);
-int  i386_set_watch(int watchnum, unsigned int watchaddr, int size, int access,
-		    struct dbreg *d);
-int  i386_clr_watch(int watchnum, struct dbreg *d);
-
 /*
  * Figure out how many arguments were passed into the frame at "fp".
  */
@@ -618,180 +613,22 @@ db_trace_thread(struct thread *thr, int count)
 }
 
 int
-i386_set_watch(watchnum, watchaddr, size, access, d)
-	int watchnum;
-	unsigned int watchaddr;
-	int size;
-	int access;
-	struct dbreg *d;
+db_md_set_watchpoint(db_expr_t addr, db_expr_t size)
 {
-	int i, len;
-
-	if (watchnum == -1) {
-		for (i = 0; i < 4; i++)
-			if (!DBREG_DR7_ENABLED(d->dr[7], i))
-				break;
-		if (i < 4)
-			watchnum = i;
-		else
-			return (-1);
-	}
-
-	switch (access) {
-	case DBREG_DR7_EXEC:
-		size = 1; /* size must be 1 for an execution breakpoint */
-		/* fall through */
-	case DBREG_DR7_WRONLY:
-	case DBREG_DR7_RDWR:
-		break;
-	default:
-		return (-1);
-	}
 
-	/*
-	 * we can watch a 1, 2, or 4 byte sized location
-	 */
-	switch (size) {
-	case 1:
-		len = DBREG_DR7_LEN_1;
-		break;
-	case 2:
-		len = DBREG_DR7_LEN_2;
-		break;
-	case 4:
-		len = DBREG_DR7_LEN_4;
-		break;
-	default:
-		return (-1);
-	}
-
-	/* clear the bits we are about to affect */
-	d->dr[7] &= ~DBREG_DR7_MASK(watchnum);
-
-	/* set drN register to the address, N=watchnum */
-	DBREG_DRX(d, watchnum) = watchaddr;
-
-	/* enable the watchpoint */
-	d->dr[7] |= DBREG_DR7_SET(watchnum, len, access,
-	    DBREG_DR7_GLOBAL_ENABLE);
-
-	return (watchnum);
+	return (dbreg_set_watchpoint((vm_offset_t)addr, (vm_size_t)size));
 }
 
 int
-i386_clr_watch(watchnum, d)
-	int watchnum;
-	struct dbreg *d;
+db_md_clr_watchpoint(db_expr_t addr, db_expr_t size)
 {
 
-	if (watchnum < 0 || watchnum >= 4)
-		return (-1);
-
-	d->dr[7] &= ~DBREG_DR7_MASK(watchnum);
-	DBREG_DRX(d, watchnum) = 0;
-
-	return (0);
-}
-
-int
-db_md_set_watchpoint(addr, size)
-	db_expr_t addr;
-	db_expr_t size;
-{
-	struct dbreg d;
-	int avail, i, wsize;
-
-	fill_dbregs(NULL, &d);
-
-	avail = 0;
-	for(i = 0; i < 4; i++) {
-		if (!DBREG_DR7_ENABLED(d.dr[7], i))
-			avail++;
-	}
-
-	if (avail * 4 < size)
-		return (-1);
-
-	for (i = 0; i < 4 && (size > 0); i++) {
-		if (!DBREG_DR7_ENABLED(d.dr[7], i)) {
-			if (size > 2)
-				wsize = 4;
-			else
-				wsize = size;
-			i386_set_watch(i, addr, wsize,
-				       DBREG_DR7_WRONLY, &d);
-			addr += wsize;
-			size -= wsize;
-		}
-	}
-
-	set_dbregs(NULL, &d);
-
-	return(0);
-}
-
-int
-db_md_clr_watchpoint(addr, size)
-	db_expr_t addr;
-	db_expr_t size;
-{
-	struct dbreg d;
-	int i;
-
-	fill_dbregs(NULL, &d);
-
-	for(i = 0; i < 4; i++) {
-		if (DBREG_DR7_ENABLED(d.dr[7], i)) {
-			if ((DBREG_DRX((&d), i) >= addr) &&
-			    (DBREG_DRX((&d), i) < addr+size))
-				i386_clr_watch(i, &d);
-		}
-	}
-
-	set_dbregs(NULL, &d);
-
-	return(0);
-}
-
-static const char *
-watchtype_str(type)
-	int type;
-{
-	switch (type) {
-		case DBREG_DR7_EXEC   : return "execute";    break;
-		case DBREG_DR7_RDWR   : return "read/write"; break;
-		case DBREG_DR7_WRONLY : return "write";	     break;
-		default		      : return "invalid";    break;
-	}
+	return (dbreg_clr_watchpoint((vm_offset_t)addr, (vm_size_t)size));
 }
 
 void
 db_md_list_watchpoints(void)
 {
-	struct dbreg d;
-	int i, len, type;
-
-	fill_dbregs(NULL, &d);
-
-	db_printf("\nhardware watchpoints:\n");
-	db_printf("  watch    status        type  len     address\n");
-	db_printf("  -----  --------  ----------  ---  ----------\n");
-	for (i = 0; i < 4; i++) {
-		if (DBREG_DR7_ENABLED(d.dr[7], i)) {
-			type = DBREG_DR7_ACCESS(d.dr[7], i);
-			len = DBREG_DR7_LEN(d.dr[7], i);
-			db_printf("  %-5d  %-8s  %10s  %3d  ",
-			    i, "enabled", watchtype_str(type), len + 1);
-			db_printsym((db_addr_t)DBREG_DRX(&d, i), DB_STGY_ANY);
-			db_printf("\n");
-		} else {
-			db_printf("  %-5d  disabled\n", i);
-		}
-	}
 
-	db_printf("\ndebug register values:\n");
-	for (i = 0; i < 8; i++)
-		if (i != 4 && i != 5)
-			db_printf("  dr%d 0x%08x\n", i, DBREG_DRX(&d, i));
-	db_printf("\n");
+	dbreg_list_watchpoints();
 }
diff --git a/sys/x86/include/x86_var.h b/sys/x86/include/x86_var.h
index c1425755b5d1..642f18964a3d 100644
--- a/sys/x86/include/x86_var.h
+++ b/sys/x86/include/x86_var.h
@@ -119,6 +119,9 @@ vm_paddr_t cpu_getmaxphyaddr(void);
 bool	cpu_mwait_usable(void);
 void	cpu_probe_amdc1e(void);
 void	cpu_setregs(void);
+int	dbreg_set_watchpoint(vm_offset_t addr, vm_size_t size);
+int	dbreg_clr_watchpoint(vm_offset_t addr, vm_size_t size);
+void	dbreg_list_watchpoints(void);
 bool	disable_wp(void);
 void	restore_wp(bool old_wp);
 void	finishidentcpu(void);
diff --git a/sys/x86/x86/dbreg.c b/sys/x86/x86/dbreg.c
new file mode 100644
index 000000000000..0d28ef8dba38
--- /dev/null
+++ b/sys/x86/x86/dbreg.c
@@ -0,0 +1,267 @@
+/*-
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include "opt_ddb.h"
+
+#include <sys/types.h>
+#include <sys/pcpu.h>
+#include <sys/smp.h>
+#include <sys/systm.h>
+
+#include <machine/frame.h>
+#include <machine/md_var.h>
+
+#include <ddb/ddb.h>
+#include <ddb/db_sym.h>
+
+#define NDBREGS		4
+#ifdef __amd64__
+#define	MAXWATCHSIZE	8
+#else
+#define	MAXWATCHSIZE	4
+#endif
+
+/*
+ * Set a watchpoint in the debug register denoted by 'watchnum'.
+ */
+static void
+dbreg_set_watchreg(int watchnum, vm_offset_t watchaddr, vm_size_t size,
+    int access, struct dbreg *d)
+{
+	int len;
+
+	MPASS(watchnum >= 0 && watchnum < NDBREGS);
+
+	/* size must be 1 for an execution breakpoint */
+	if (access == DBREG_DR7_EXEC)
+		size = 1;
+
+	/*
+	 * we can watch a 1, 2, or 4 byte sized location
+	 */
+	switch (size) {
+	case 1:
+		len = DBREG_DR7_LEN_1;
+		break;
+	case 2:
+		len = DBREG_DR7_LEN_2;
+		break;
+	case 4:
+		len = DBREG_DR7_LEN_4;
+		break;
+#if MAXWATCHSIZE >= 8
+	case 8:
+		len = DBREG_DR7_LEN_8;
+		break;
+#endif
+	default:
+		return;
+	}
+
+	/* clear the bits we are about to affect */
+	d->dr[7] &= ~DBREG_DR7_MASK(watchnum);
+
+	/* set drN register to the address, N=watchnum */
+	DBREG_DRX(d, watchnum) = watchaddr;
+
+	/* enable the watchpoint */
+	d->dr[7] |= DBREG_DR7_SET(watchnum, len, access,
+	    DBREG_DR7_GLOBAL_ENABLE);
+}
+
+/*
+ * Remove a watchpoint from the debug register denoted by 'watchnum'.
+ */
+static void
+dbreg_clr_watchreg(int watchnum, struct dbreg *d)
+{
+	MPASS(watchnum >= 0 && watchnum < NDBREGS);
+
+	d->dr[7] &= ~DBREG_DR7_MASK(watchnum);
+	DBREG_DRX(d, watchnum) = 0;
+}
+
+/*
+ * Sync the debug registers. Other cores will read these values from the PCPU
+ * area when they resume. See amd64_db_resume_dbreg() below.
+ */
+static void
+dbreg_sync(struct dbreg *dp)
+{
+#ifdef __amd64__
+	struct pcpu *pc;
+	int cpu, c;
+
+	cpu = PCPU_GET(cpuid);
+	CPU_FOREACH(c) {
+		if (c == cpu)
+			continue;
+		pc = pcpu_find(c);
+		memcpy(pc->pc_dbreg, dp, sizeof(*dp));
+		pc->pc_dbreg_cmd = PC_DBREG_CMD_LOAD;
+	}
+#endif
+}
+
+int
+dbreg_set_watchpoint(vm_offset_t addr, vm_size_t size)
+{
+	struct dbreg *d;
+	int avail, i, wsize;
+
+#ifdef __amd64__
+	d = (struct dbreg *)PCPU_PTR(dbreg);
+#else
+	/* debug registers aren't stored in PCPU on i386. */
+	struct dbreg d_temp;
+	d = &d_temp;
+#endif
+
+	fill_dbregs(NULL, d);
+
+	/*
+	 * Check if there are enough available registers to cover the desired
+	 * area.
+	 */
+	avail = 0;
+	for (i = 0; i < NDBREGS; i++) {
+		if (!DBREG_DR7_ENABLED(d->dr[7], i))
+			avail++;
+	}
+
+	if (avail * MAXWATCHSIZE < size)
+		return (-1);
+
+	for (i = 0; i < NDBREGS && size > 0; i++) {
+		if (!DBREG_DR7_ENABLED(d->dr[7], i)) {
+			if ((size >= 8 || (avail == 1 && size > 4)) &&
+			    MAXWATCHSIZE == 8)
+				wsize = 8;
+			else if (size > 2)
+				wsize = 4;
+			else
+				wsize = size;
+			dbreg_set_watchreg(i, addr, wsize, DBREG_DR7_WRONLY, d);
+			addr += wsize;
+			size -= wsize;
+			avail--;
+		}
+	}
+
+	set_dbregs(NULL, d);
+	dbreg_sync(d);
+
+	return (0);
+}
+
+int
+dbreg_clr_watchpoint(vm_offset_t addr, vm_size_t size)
+{
+	struct dbreg *d;
+	int i;
+
+#ifdef __amd64__
+	d = (struct dbreg *)PCPU_PTR(dbreg);
+#else
+	/* debug registers aren't stored in PCPU on i386. */
+	struct dbreg d_temp;
+	d = &d_temp;
+#endif
+	fill_dbregs(NULL, d);
+
+	for (i = 0; i < NDBREGS; i++) {
+		if (DBREG_DR7_ENABLED(d->dr[7], i)) {
+			if (DBREG_DRX((d), i) >= addr &&
+			    DBREG_DRX((d), i) < addr + size)
+				dbreg_clr_watchreg(i, d);
+		}
+	}
+
+	set_dbregs(NULL, d);
+	dbreg_sync(d);
+
+	return (0);
+}
+
+#ifdef DDB
+static const char *
+watchtype_str(int type)
+{
+
+	switch (type) {
+	case DBREG_DR7_EXEC:
+		return ("execute");
+	case DBREG_DR7_RDWR:
+		return ("read/write");
+	case DBREG_DR7_WRONLY:
+		return ("write");
+	default:
+		return ("invalid");
+	}
+}
+
+void
+dbreg_list_watchpoints(void)
+{
+	struct dbreg d;
+	int i, len, type;
+
+	fill_dbregs(NULL, &d);
+
+	db_printf("\nhardware watchpoints:\n");
+	db_printf("  watch    status        type  len     address\n");
+	db_printf("  -----  --------  ----------  ---  ----------\n");
+	for (i = 0; i < NDBREGS; i++) {
+		if (DBREG_DR7_ENABLED(d.dr[7], i)) {
+			type = DBREG_DR7_ACCESS(d.dr[7], i);
+			len = DBREG_DR7_LEN(d.dr[7], i);
+			db_printf("  %-5d  %-8s  %10s  %3d  ",
+			    i, "enabled", watchtype_str(type), len + 1);
+			db_printsym((db_addr_t)DBREG_DRX(&d, i), DB_STGY_ANY);
+			db_printf("\n");
+		} else {
+			db_printf("  %-5d  disabled\n", i);
+		}
+	}
+}
+#endif
+
+#ifdef __amd64__
+/* Sync debug registers when resuming from debugger. */
+void
+amd64_db_resume_dbreg(void)
+{
+	struct dbreg *d;
+
+	switch (PCPU_GET(dbreg_cmd)) {
+	case PC_DBREG_CMD_LOAD:
+		d = (struct dbreg *)PCPU_PTR(dbreg);
+		set_dbregs(NULL, d);
+		PCPU_SET(dbreg_cmd, PC_DBREG_CMD_NONE);
+		break;
+	}
+}
+#endif



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202104211431.13LEVCsj047640>