Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107011134
D29153.id85408.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
D29153.id85408.diff
View Options
Index: sys/amd64/amd64/db_trace.c
===================================================================
--- sys/amd64/amd64/db_trace.c
+++ sys/amd64/amd64/db_trace.c
@@ -128,11 +128,6 @@
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,211 +386,24 @@
}
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");
+ dbreg_list_watchpoints();
}
void
Index: sys/conf/files.x86
===================================================================
--- sys/conf/files.x86
+++ sys/conf/files.x86
@@ -320,6 +320,7 @@
x86/x86/busdma_bounce.c standard
x86/x86/busdma_machdep.c standard
x86/x86/cpu_machdep.c standard
+x86/x86/dbreg.c standard
x86/x86/dump_machdep.c standard
x86/x86/fdt_machdep.c optional fdt
x86/x86/identcpu.c standard
Index: sys/i386/i386/db_trace.c
===================================================================
--- sys/i386/i386/db_trace.c
+++ sys/i386/i386/db_trace.c
@@ -198,11 +198,6 @@
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 @@
}
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();
}
Index: sys/x86/include/reg.h
===================================================================
--- sys/x86/include/reg.h
+++ sys/x86/include/reg.h
@@ -264,6 +264,10 @@
int fill_dbregs32(struct thread *, struct dbreg32 *);
int set_dbregs32(struct thread *, struct dbreg32 *);
#endif
+
+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);
#endif
#endif /* !_MACHINE_REG_H_ */
Index: sys/x86/x86/dbreg.c
===================================================================
--- /dev/null
+++ sys/x86/x86/dbreg.c
@@ -0,0 +1,281 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2021 Klara Inc.
+ *
+ * Portions of this software were developed by Mitchell Horne
+ * under sponsorship from Klara Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*-
+ * 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/reg.h>
+
+#ifdef DDB
+#include <ddb/ddb.h>
+#include <ddb/db_sym.h>
+#endif
+
+#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.
+ */
+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))
+ 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
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jan 9, 10:47 PM (9 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15736791
Default Alt Text
D29153.id85408.diff (16 KB)
Attached To
Mode
D29153: x86: consolidate hw watchpoint logic into new file
Attached
Detach File
Event Timeline
Log In to Comment