Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 Sep 2018 23:21:53 +0000 (UTC)
From:      John Baldwin <jhb@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r338691 - in stable/11/sys: amd64/amd64 amd64/ia32 amd64/include amd64/linux amd64/linux32 amd64/vmm/amd amd64/vmm/intel i386/i386 i386/include sys x86/include
Message-ID:  <201809142321.w8ENLrs7070080@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhb
Date: Fri Sep 14 23:21:52 2018
New Revision: 338691
URL: https://svnweb.freebsd.org/changeset/base/338691

Log:
  MFC 332454,334009,334122: Various fixes for x86 debug exceptions.
  
  332454:
  Fix PSL_T inheritance on exec for x86.
  
  The miscellaneous x86 sysent->sv_setregs() implementations tried to
  migrate PSL_T from the previous program to the new executed one, but
  they evaluated regs->tf_eflags after the whole regs structure was
  bzeroed.  Make this functional by saving PSL_T value before zeroing.
  
  Note that if the debugger is not attached, executing the first
  instruction in the new program with PSL_T set results in SIGTRAP, and
  since all intercepted signals are reset to default dispostion on
  exec(2), this means that non-debugged process gets killed immediately
  if PSL_T is inherited.  In particular, since suid images drop
  P_TRACED, attempt to set PSL_T for execution of such program would
  kill the process.
  
  Another issue with userspace PSL_T handling is that it is reset by
  trap().  It is reasonable to clear PSL_T when entering SIGTRAP
  handler, to allow the signal to be handled without recursion or
  delivery of blocked fault.  But it is not reasonable to return back to
  the normal flow with PSL_T cleared.  This is too late to change, I
  think.
  
  334009:
  Cleanups related to debug exceptions on x86.
  
  - Add constants for fields in DR6 and the reserved fields in DR7.  Use
    these constants instead of magic numbers in most places that use DR6
    and DR7.
  - Refer to T_TRCTRAP as "debug exception" rather than a "trace trap"
    as it is not just for trace exceptions.
  - Always read DR6 for debug exceptions and only clear TF in the flags
    register for user exceptions where DR6.BS is set.
  - Clear DR6 before returning from a debug exception handler as
    recommended by the SDM dating all the way back to the 386.  This
    allows debuggers to determine the cause of each exception.  For
    kernel traps, clear DR6 in the T_TRCTRAP case and pass DR6 by value
    to other parts of the handler (namely, user_dbreg_trap()).  For user
    traps, wait until after trapsignal to clear DR6 so that userland
    debuggers can read DR6 via PT_GETDBREGS while the thread is stopped
    in trapsignal().
  
  334122:
  x86: stop unconditionally clearing PSL_T on the trace trap.
  
  We certainly should clear PSL_T when calling the SIGTRAP signal
  handler, which is already done by all x86 sendsig(9) ABI code.  On the
  other hand, there is no obvious reason why PSL_T needs to be cleared
  when returning from the signal handler.  For instance, Linux allows
  userspace to set PSL_T and keep tracing enabled for the desired
  period.  There are userspace programs which would use PSL_T if we make
  it possible, for instance sbcl.
  
  Remember if PSL_T was set by PT_STEP or PT_SETSTEP by mean of TDB_STEP
  flag, and only clear it when the flag is set.

Modified:
  stable/11/sys/amd64/amd64/machdep.c
  stable/11/sys/amd64/amd64/trap.c
  stable/11/sys/amd64/ia32/ia32_signal.c
  stable/11/sys/amd64/include/db_machdep.h
  stable/11/sys/amd64/linux/linux_sysvec.c
  stable/11/sys/amd64/linux32/linux32_sysvec.c
  stable/11/sys/amd64/vmm/amd/svm.c
  stable/11/sys/amd64/vmm/intel/vmx.c
  stable/11/sys/i386/i386/machdep.c
  stable/11/sys/i386/i386/trap.c
  stable/11/sys/i386/include/db_machdep.h
  stable/11/sys/sys/proc.h
  stable/11/sys/x86/include/reg.h
  stable/11/sys/x86/include/x86_var.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/amd64/amd64/machdep.c
==============================================================================
--- stable/11/sys/amd64/amd64/machdep.c	Fri Sep 14 19:50:36 2018	(r338690)
+++ stable/11/sys/amd64/amd64/machdep.c	Fri Sep 14 23:21:52 2018	(r338691)
@@ -589,9 +589,13 @@ freebsd4_sigreturn(struct thread *td, struct freebsd4_
 void
 exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
 {
-	struct trapframe *regs = td->td_frame;
-	struct pcb *pcb = td->td_pcb;
+	struct trapframe *regs;
+	struct pcb *pcb;
+	register_t saved_rflags;
 
+	regs = td->td_frame;
+	pcb = td->td_pcb;
+
 	mtx_lock(&dt_lock);
 	if (td->td_proc->p_md.md_ldt != NULL)
 		user_ldt_free(td);
@@ -604,11 +608,12 @@ exec_setregs(struct thread *td, struct image_params *i
 	clear_pcb_flags(pcb, PCB_32BIT);
 	pcb->pcb_initial_fpucw = __INITIAL_FPUCW__;
 
+	saved_rflags = regs->tf_rflags & PSL_T;
 	bzero((char *)regs, sizeof(struct trapframe));
 	regs->tf_rip = imgp->entry_addr;
 	regs->tf_rsp = ((stack - 8) & ~0xFul) + 8;
 	regs->tf_rdi = stack;		/* argv */
-	regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+	regs->tf_rflags = PSL_USER | saved_rflags;
 	regs->tf_ss = _udatasel;
 	regs->tf_cs = _ucodesel;
 	regs->tf_ds = _udatasel;
@@ -1990,14 +1995,21 @@ ptrace_set_pc(struct thread *td, unsigned long addr)
 int
 ptrace_single_step(struct thread *td)
 {
-	td->td_frame->tf_rflags |= PSL_T;
+
+	PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
+	if ((td->td_frame->tf_rflags & PSL_T) == 0) {
+		td->td_frame->tf_rflags |= PSL_T;
+		td->td_dbgflags |= TDB_STEP;
+	}
 	return (0);
 }
 
 int
 ptrace_clear_single_step(struct thread *td)
 {
+	PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
 	td->td_frame->tf_rflags &= ~PSL_T;
+	td->td_dbgflags &= ~TDB_STEP;
 	return (0);
 }
 
@@ -2500,14 +2512,23 @@ reset_dbregs(void)
  * breakpoint was in user space.  Return 0, otherwise.
  */
 int
-user_dbreg_trap(void)
+user_dbreg_trap(register_t dr6)
 {
-        u_int64_t dr7, dr6; /* debug registers dr6 and dr7 */
+        u_int64_t dr7;
         u_int64_t bp;       /* breakpoint bits extracted from dr6 */
         int nbp;            /* number of breakpoints that triggered */
         caddr_t addr[4];    /* breakpoint addresses */
         int i;
-        
+
+        bp = dr6 & DBREG_DR6_BMASK;
+        if (bp == 0) {
+                /*
+                 * None of the breakpoint bits are set meaning this
+                 * trap was not caused by any of the debug registers
+                 */
+                return 0;
+        }
+
         dr7 = rdr7();
         if ((dr7 & 0x000000ff) == 0) {
                 /*
@@ -2519,16 +2540,6 @@ user_dbreg_trap(void)
         }
 
         nbp = 0;
-        dr6 = rdr6();
-        bp = dr6 & 0x0000000f;
-
-        if (!bp) {
-                /*
-                 * None of the breakpoint bits are set meaning this
-                 * trap was not caused by any of the debug registers
-                 */
-                return 0;
-        }
 
         /*
          * at least one of the breakpoints were hit, check to see

Modified: stable/11/sys/amd64/amd64/trap.c
==============================================================================
--- stable/11/sys/amd64/amd64/trap.c	Fri Sep 14 19:50:36 2018	(r338690)
+++ stable/11/sys/amd64/amd64/trap.c	Fri Sep 14 23:21:52 2018	(r338691)
@@ -123,7 +123,7 @@ static char *trap_msg[] = {
 	"",					/*  7 unused */
 	"",					/*  8 unused */
 	"general protection fault",		/*  9 T_PROTFLT */
-	"trace trap",				/* 10 T_TRCTRAP */
+	"debug exception",			/* 10 T_TRCTRAP */
 	"",					/* 11 unused */
 	"page fault",				/* 12 T_PAGEFLT */
 	"",					/* 13 unused */
@@ -184,10 +184,7 @@ trap(struct trapframe *frame)
 	ksiginfo_t ksi;
 	struct thread *td;
 	struct proc *p;
-	register_t addr;
-#ifdef KDB
-	register_t dr6;
-#endif
+	register_t addr, dr6;
 	int signo, ucode;
 	u_int type;
 
@@ -196,6 +193,7 @@ trap(struct trapframe *frame)
 	signo = 0;
 	ucode = 0;
 	addr = 0;
+	dr6 = 0;
 
 	PCPU_INC(cnt.v_trap);
 	type = frame->tf_trapno;
@@ -283,20 +281,31 @@ trap(struct trapframe *frame)
 			break;
 
 		case T_BPTFLT:		/* bpt instruction fault */
-		case T_TRCTRAP:		/* trace trap */
 			enable_intr();
 #ifdef KDTRACE_HOOKS
-			if (type == T_BPTFLT) {
-				if (dtrace_pid_probe_ptr != NULL &&
-				    dtrace_pid_probe_ptr(frame) == 0)
-					return;
-			}
+			if (dtrace_pid_probe_ptr != NULL &&
+			    dtrace_pid_probe_ptr(frame) == 0)
+				return;
 #endif
-			frame->tf_rflags &= ~PSL_T;
 			signo = SIGTRAP;
-			ucode = (type == T_TRCTRAP ? TRAP_TRACE : TRAP_BRKPT);
+			ucode = TRAP_BRKPT;
 			break;
 
+		case T_TRCTRAP:		/* debug exception */
+			enable_intr();
+			signo = SIGTRAP;
+			ucode = TRAP_TRACE;
+			dr6 = rdr6();
+			if ((dr6 & DBREG_DR6_BS) != 0) {
+				PROC_LOCK(td->td_proc);
+				if ((td->td_dbgflags & TDB_STEP) != 0) {
+					td->td_frame->tf_rflags &= ~PSL_T;
+					td->td_dbgflags &= ~TDB_STEP;
+				}
+				PROC_UNLOCK(td->td_proc);
+			}
+			break;
+
 		case T_ARITHTRAP:	/* arithmetic trap */
 			ucode = fputrap_x87();
 			if (ucode == -1)
@@ -532,9 +541,13 @@ trap(struct trapframe *frame)
 			}
 			break;
 
-		case T_TRCTRAP:	 /* trace trap */
+		case T_TRCTRAP:	 /* debug exception */
+			/* Clear any pending debug events. */
+			dr6 = rdr6();
+			load_dr6(0);
+
 			/*
-			 * Ignore debug register trace traps due to
+			 * Ignore debug register exceptions due to
 			 * accesses in the user's address space, which
 			 * can happen under several conditions such as
 			 * if a user sets a watchpoint on a buffer and
@@ -543,14 +556,8 @@ trap(struct trapframe *frame)
 			 * in kernel space because that is useful when
 			 * debugging the kernel.
 			 */
-			if (user_dbreg_trap()) {
-				/*
-				 * Reset breakpoint bits because the
-				 * processor doesn't
-				 */
-				load_dr6(rdr6() & ~0xf);
+			if (user_dbreg_trap(dr6))
 				return;
-			}
 
 			/*
 			 * Malicious user code can configure a debug
@@ -606,9 +613,6 @@ trap(struct trapframe *frame)
 			 * Otherwise, debugger traps "can't happen".
 			 */
 #ifdef KDB
-			/* XXX %dr6 is not quite reentrant. */
-			dr6 = rdr6();
-			load_dr6(dr6 & ~0x4000);
 			if (kdb_trap(type, dr6, frame))
 				return;
 #endif
@@ -651,6 +655,13 @@ trap(struct trapframe *frame)
 	}
 	KASSERT((read_rflags() & PSL_I) != 0, ("interrupts disabled"));
 	trapsignal(td, &ksi);
+
+	/*
+	 * Clear any pending debug exceptions after allowing a
+	 * debugger to read DR6 while stopped in trapsignal().
+	 */
+	if (type == T_TRCTRAP)
+		load_dr6(0);
 userret:
 	userret(td, frame);
 	KASSERT(PCB_USER_FPU(td->td_pcb),

Modified: stable/11/sys/amd64/ia32/ia32_signal.c
==============================================================================
--- stable/11/sys/amd64/ia32/ia32_signal.c	Fri Sep 14 19:50:36 2018	(r338690)
+++ stable/11/sys/amd64/ia32/ia32_signal.c	Fri Sep 14 23:21:52 2018	(r338691)
@@ -935,10 +935,14 @@ freebsd32_sigreturn(td, uap)
 void
 ia32_setregs(struct thread *td, struct image_params *imgp, u_long stack)
 {
-	struct trapframe *regs = td->td_frame;
-	struct pcb *pcb = td->td_pcb;
+	struct trapframe *regs;
+	struct pcb *pcb;
+	register_t saved_rflags;
 	
 	mtx_lock(&dt_lock);
+	regs = td->td_frame;
+	pcb = td->td_pcb;
+
 	if (td->td_proc->p_md.md_ldt != NULL)
 		user_ldt_free(td);
 	else
@@ -951,10 +955,11 @@ ia32_setregs(struct thread *td, struct image_params *i
 	pcb->pcb_gsbase = 0;
 	pcb->pcb_initial_fpucw = __INITIAL_FPUCW_I386__;
 
+	saved_rflags = regs->tf_rflags & PSL_T;
 	bzero((char *)regs, sizeof(struct trapframe));
 	regs->tf_rip = imgp->entry_addr;
 	regs->tf_rsp = stack;
-	regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+	regs->tf_rflags = PSL_USER | saved_rflags;
 	regs->tf_ss = _udatasel;
 	regs->tf_cs = _ucode32sel;
 	regs->tf_rbx = imgp->ps_strings;

Modified: stable/11/sys/amd64/include/db_machdep.h
==============================================================================
--- stable/11/sys/amd64/include/db_machdep.h	Fri Sep 14 19:50:36 2018	(r338690)
+++ stable/11/sys/amd64/include/db_machdep.h	Fri Sep 14 23:21:52 2018	(r338691)
@@ -30,6 +30,7 @@
 #define	_MACHINE_DB_MACHDEP_H_
 
 #include <machine/frame.h>
+#include <machine/reg.h>
 #include <machine/trap.h>
 
 typedef	vm_offset_t	db_addr_t;	/* address - unsigned */
@@ -64,7 +65,8 @@ do {						\
  * unknown addresses and doesn't turn them off while it is running.
  */
 #define	IS_BREAKPOINT_TRAP(type, code)	((type) == T_BPTFLT)
-#define	IS_SSTEP_TRAP(type, code)	((type) == T_TRCTRAP && (code) & 0x4000)
+#define	IS_SSTEP_TRAP(type, code)					\
+	((type) == T_TRCTRAP && (code) & DBREG_DR6_BS)
 #define	IS_WATCHPOINT_TRAP(type, code)	0
 
 #define	I_CALL		0xe8

Modified: stable/11/sys/amd64/linux/linux_sysvec.c
==============================================================================
--- stable/11/sys/amd64/linux/linux_sysvec.c	Fri Sep 14 19:50:36 2018	(r338690)
+++ stable/11/sys/amd64/linux/linux_sysvec.c	Fri Sep 14 23:21:52 2018	(r338691)
@@ -422,9 +422,13 @@ linux_copyout_strings(struct image_params *imgp)
 static void
 linux_exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
 {
-	struct trapframe *regs = td->td_frame;
-	struct pcb *pcb = td->td_pcb;
+	struct trapframe *regs;
+	struct pcb *pcb;
+	register_t saved_rflags;
 
+	regs = td->td_frame;
+	pcb = td->td_pcb;
+
 	mtx_lock(&dt_lock);
 	if (td->td_proc->p_md.md_ldt != NULL)
 		user_ldt_free(td);
@@ -437,10 +441,11 @@ linux_exec_setregs(struct thread *td, struct image_par
 	pcb->pcb_initial_fpucw = __LINUX_NPXCW__;
 	set_pcb_flags(pcb, PCB_FULL_IRET);
 
+	saved_rflags = regs->tf_rflags & PSL_T;
 	bzero((char *)regs, sizeof(struct trapframe));
 	regs->tf_rip = imgp->entry_addr;
 	regs->tf_rsp = stack;
-	regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+	regs->tf_rflags = PSL_USER | saved_rflags;
 	regs->tf_ss = _udatasel;
 	regs->tf_cs = _ucodesel;
 	regs->tf_ds = _udatasel;

Modified: stable/11/sys/amd64/linux32/linux32_sysvec.c
==============================================================================
--- stable/11/sys/amd64/linux32/linux32_sysvec.c	Fri Sep 14 19:50:36 2018	(r338690)
+++ stable/11/sys/amd64/linux32/linux32_sysvec.c	Fri Sep 14 23:21:52 2018	(r338691)
@@ -781,7 +781,11 @@ exec_linux_setregs(struct thread *td, struct image_par
 {
 	struct trapframe *regs = td->td_frame;
 	struct pcb *pcb = td->td_pcb;
+	register_t saved_rflags;
 
+	regs = td->td_frame;
+	pcb = td->td_pcb;
+
 	mtx_lock(&dt_lock);
 	if (td->td_proc->p_md.md_ldt != NULL)
 		user_ldt_free(td);
@@ -796,10 +800,11 @@ exec_linux_setregs(struct thread *td, struct image_par
 	critical_exit();
 	pcb->pcb_initial_fpucw = __LINUX_NPXCW__;
 
+	saved_rflags = regs->tf_rflags & PSL_T;
 	bzero((char *)regs, sizeof(struct trapframe));
 	regs->tf_rip = imgp->entry_addr;
 	regs->tf_rsp = stack;
-	regs->tf_rflags = PSL_USER | (regs->tf_rflags & PSL_T);
+	regs->tf_rflags = PSL_USER | saved_rflags;
 	regs->tf_gs = _ugssel;
 	regs->tf_fs = _ufssel;
 	regs->tf_es = _udatasel;

Modified: stable/11/sys/amd64/vmm/amd/svm.c
==============================================================================
--- stable/11/sys/amd64/vmm/amd/svm.c	Fri Sep 14 19:50:36 2018	(r338690)
+++ stable/11/sys/amd64/vmm/amd/svm.c	Fri Sep 14 23:21:52 2018	(r338691)
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/cpufunc.h>
 #include <machine/psl.h>
 #include <machine/md_var.h>
+#include <machine/reg.h>
 #include <machine/specialreg.h>
 #include <machine/smp.h>
 #include <machine/vmm.h>
@@ -509,8 +510,8 @@ vmcb_init(struct svm_softc *sc, int vcpu, uint64_t iop
 	    PAT_VALUE(7, PAT_UNCACHEABLE);
 
 	/* Set up DR6/7 to power-on state */
-	state->dr6 = 0xffff0ff0;
-	state->dr7 = 0x400;
+	state->dr6 = DBREG_DR6_RESERVED1;
+	state->dr7 = DBREG_DR7_RESERVED1;
 }
 
 /*

Modified: stable/11/sys/amd64/vmm/intel/vmx.c
==============================================================================
--- stable/11/sys/amd64/vmm/intel/vmx.c	Fri Sep 14 19:50:36 2018	(r338690)
+++ stable/11/sys/amd64/vmm/intel/vmx.c	Fri Sep 14 23:21:52 2018	(r338691)
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/psl.h>
 #include <machine/cpufunc.h>
 #include <machine/md_var.h>
+#include <machine/reg.h>
 #include <machine/segments.h>
 #include <machine/smp.h>
 #include <machine/specialreg.h>
@@ -962,8 +963,8 @@ vmx_vminit(struct vm *vm, pmap_t pmap)
 			exc_bitmap = 1 << IDT_MC;
 		error += vmwrite(VMCS_EXCEPTION_BITMAP, exc_bitmap);
 
-		vmx->ctx[i].guest_dr6 = 0xffff0ff0;
-		error += vmwrite(VMCS_GUEST_DR7, 0x400);
+		vmx->ctx[i].guest_dr6 = DBREG_DR6_RESERVED1;
+		error += vmwrite(VMCS_GUEST_DR7, DBREG_DR7_RESERVED1);
 
 		if (virtual_interrupt_delivery) {
 			error += vmwrite(VMCS_APIC_ACCESS, APIC_ACCESS_ADDRESS);

Modified: stable/11/sys/i386/i386/machdep.c
==============================================================================
--- stable/11/sys/i386/i386/machdep.c	Fri Sep 14 19:50:36 2018	(r338690)
+++ stable/11/sys/i386/i386/machdep.c	Fri Sep 14 23:21:52 2018	(r338691)
@@ -1125,9 +1125,13 @@ sys_sigreturn(td, uap)
 void
 exec_setregs(struct thread *td, struct image_params *imgp, u_long stack)
 {
-	struct trapframe *regs = td->td_frame;
-	struct pcb *pcb = td->td_pcb;
+	struct trapframe *regs;
+	struct pcb *pcb;
+	register_t saved_eflags;
 
+	regs = td->td_frame;
+	pcb = td->td_pcb;
+
 	/* Reset pc->pcb_gs and %gs before possibly invalidating it. */
 	pcb->pcb_gs = _udatasel;
 	load_gs(_udatasel);
@@ -1147,10 +1151,11 @@ exec_setregs(struct thread *td, struct image_params *i
 	set_fsbase(td, 0);
 	set_gsbase(td, 0);
 
+	saved_eflags = regs->tf_eflags & PSL_T;
 	bzero((char *)regs, sizeof(struct trapframe));
 	regs->tf_eip = imgp->entry_addr;
 	regs->tf_esp = stack;
-	regs->tf_eflags = PSL_USER | (regs->tf_eflags & PSL_T);
+	regs->tf_eflags = PSL_USER | saved_eflags;
 	regs->tf_ss = _udatasel;
 	regs->tf_ds = _udatasel;
 	regs->tf_es = _udatasel;
@@ -2916,14 +2921,21 @@ ptrace_set_pc(struct thread *td, u_long addr)
 int
 ptrace_single_step(struct thread *td)
 {
-	td->td_frame->tf_eflags |= PSL_T;
+
+	PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
+	if ((td->td_frame->tf_eflags & PSL_T) == 0) {
+		td->td_frame->tf_eflags |= PSL_T;
+		td->td_dbgflags |= TDB_STEP;
+	}
 	return (0);
 }
 
 int
 ptrace_clear_single_step(struct thread *td)
 {
+	PROC_LOCK_ASSERT(td->td_proc, MA_OWNED);
 	td->td_frame->tf_eflags &= ~PSL_T;
+	td->td_dbgflags &= ~TDB_STEP;
 	return (0);
 }
 
@@ -3309,14 +3321,23 @@ set_dbregs(struct thread *td, struct dbreg *dbregs)
  * breakpoint was in user space.  Return 0, otherwise.
  */
 int
-user_dbreg_trap(void)
+user_dbreg_trap(register_t dr6)
 {
-        u_int32_t dr7, dr6; /* debug registers dr6 and dr7 */
+        u_int32_t dr7;
         u_int32_t bp;       /* breakpoint bits extracted from dr6 */
         int nbp;            /* number of breakpoints that triggered */
         caddr_t addr[4];    /* breakpoint addresses */
         int i;
-        
+
+        bp = dr6 & DBREG_DR6_BMASK;
+        if (bp == 0) {
+                /*
+                 * None of the breakpoint bits are set meaning this
+                 * trap was not caused by any of the debug registers
+                 */
+                return 0;
+        }
+
         dr7 = rdr7();
         if ((dr7 & 0x000000ff) == 0) {
                 /*
@@ -3328,16 +3349,6 @@ user_dbreg_trap(void)
         }
 
         nbp = 0;
-        dr6 = rdr6();
-        bp = dr6 & 0x0000000f;
-
-        if (!bp) {
-                /*
-                 * None of the breakpoint bits are set meaning this
-                 * trap was not caused by any of the debug registers
-                 */
-                return 0;
-        }
 
         /*
          * at least one of the breakpoints were hit, check to see

Modified: stable/11/sys/i386/i386/trap.c
==============================================================================
--- stable/11/sys/i386/i386/trap.c	Fri Sep 14 19:50:36 2018	(r338690)
+++ stable/11/sys/i386/i386/trap.c	Fri Sep 14 23:21:52 2018	(r338691)
@@ -130,7 +130,7 @@ static char *trap_msg[] = {
 	"",					/*  7 unused */
 	"",					/*  8 unused */
 	"general protection fault",		/*  9 T_PROTFLT */
-	"trace trap",				/* 10 T_TRCTRAP */
+	"debug exception",			/* 10 T_TRCTRAP */
 	"",					/* 11 unused */
 	"page fault",				/* 12 T_PAGEFLT */
 	"",					/* 13 unused */
@@ -180,12 +180,9 @@ trap(struct trapframe *frame)
 	ksiginfo_t ksi;
 	struct thread *td;
 	struct proc *p;
-#ifdef KDB
-	register_t dr6;
-#endif
 	int signo, ucode;
 	u_int type;
-	register_t addr;
+	register_t addr, dr6;
 	vm_offset_t eva;
 #ifdef POWERFAIL_NMI
 	static int lastalert = 0;
@@ -196,6 +193,7 @@ trap(struct trapframe *frame)
 	signo = 0;
 	ucode = 0;
 	addr = 0;
+	dr6 = 0;
 
 	PCPU_INC(cnt.v_trap);
 	type = frame->tf_trapno;
@@ -320,19 +318,30 @@ trap(struct trapframe *frame)
 			break;
 
 		case T_BPTFLT:		/* bpt instruction fault */
-		case T_TRCTRAP:		/* trace trap */
 			enable_intr();
 #ifdef KDTRACE_HOOKS
-			if (type == T_BPTFLT) {
-				if (dtrace_pid_probe_ptr != NULL &&
-				    dtrace_pid_probe_ptr(frame) == 0)
-					return;
-			}
+			if (dtrace_pid_probe_ptr != NULL &&
+			    dtrace_pid_probe_ptr(frame) == 0)
+				return;
 #endif
+			signo = SIGTRAP;
+			ucode = TRAP_BRKPT;
+			break;
+
+		case T_TRCTRAP:		/* debug exception */
+			enable_intr();
 user_trctrap_out:
-			frame->tf_eflags &= ~PSL_T;
 			signo = SIGTRAP;
-			ucode = (type == T_TRCTRAP ? TRAP_TRACE : TRAP_BRKPT);
+			ucode = TRAP_TRACE;
+			dr6 = rdr6();
+			if ((dr6 & DBREG_DR6_BS) != 0) {
+				PROC_LOCK(td->td_proc);
+				if ((td->td_dbgflags & TDB_STEP) != 0) {
+					td->td_frame->tf_eflags &= ~PSL_T;
+					td->td_dbgflags &= ~TDB_STEP;
+				}
+				PROC_UNLOCK(td->td_proc);
+			}
 			break;
 
 		case T_ARITHTRAP:	/* arithmetic trap */
@@ -624,8 +633,12 @@ user_trctrap_out:
 			}
 			break;
 
-		case T_TRCTRAP:	 /* trace trap */
+		case T_TRCTRAP:	 /* debug exception */
 kernel_trctrap:
+			/* Clear any pending debug events. */
+			dr6 = rdr6();
+			load_dr6(0);
+
 			if (frame->tf_eip == (int)IDTVEC(lcall_syscall)) {
 				/*
 				 * We've just entered system mode via the
@@ -644,7 +657,7 @@ kernel_trctrap:
 				return;
 			}
 			/*
-			 * Ignore debug register trace traps due to
+			 * Ignore debug register exceptions due to
 			 * accesses in the user's address space, which
 			 * can happen under several conditions such as
 			 * if a user sets a watchpoint on a buffer and
@@ -653,15 +666,9 @@ kernel_trctrap:
 			 * in kernel space because that is useful when
 			 * debugging the kernel.
 			 */
-			if (user_dbreg_trap() && 
-			   !(curpcb->pcb_flags & PCB_VM86CALL)) {
-				/*
-				 * Reset breakpoint bits because the
-				 * processor doesn't
-				 */
-				load_dr6(rdr6() & ~0xf);
+			if (user_dbreg_trap(dr6) &&
+			   !(curpcb->pcb_flags & PCB_VM86CALL))
 				return;
-			}
 
 			/*
 			 * Malicious user code can configure a debug
@@ -699,9 +706,6 @@ kernel_trctrap:
 			 * Otherwise, debugger traps "can't happen".
 			 */
 #ifdef KDB
-			/* XXX %dr6 is not quite reentrant. */
-			dr6 = rdr6();
-			load_dr6(dr6 & ~0x4000);
 			if (kdb_trap(type, dr6, frame))
 				return;
 #endif
@@ -754,6 +758,12 @@ kernel_trctrap:
 	KASSERT((read_eflags() & PSL_I) != 0, ("interrupts disabled"));
 	trapsignal(td, &ksi);
 
+	/*
+	 * Clear any pending debug exceptions after allowing a
+	 * debugger to read DR6 while stopped in trapsignal().
+	 */
+	if (type == T_TRCTRAP)
+		load_dr6(0);
 user:
 	userret(td, frame);
 	KASSERT(PCB_USER_FPU(td->td_pcb),

Modified: stable/11/sys/i386/include/db_machdep.h
==============================================================================
--- stable/11/sys/i386/include/db_machdep.h	Fri Sep 14 19:50:36 2018	(r338690)
+++ stable/11/sys/i386/include/db_machdep.h	Fri Sep 14 23:21:52 2018	(r338691)
@@ -30,6 +30,7 @@
 #define	_MACHINE_DB_MACHDEP_H_
 
 #include <machine/frame.h>
+#include <machine/reg.h>
 #include <machine/trap.h>
 
 typedef	vm_offset_t	db_addr_t;	/* address - unsigned */
@@ -67,7 +68,8 @@ do {						\
  * unknown addresses and doesn't turn them off while it is running.
  */
 #define	IS_BREAKPOINT_TRAP(type, code)	((type) == T_BPTFLT)
-#define	IS_SSTEP_TRAP(type, code)	((type) == T_TRCTRAP && (code) & 0x4000)
+#define	IS_SSTEP_TRAP(type, code)					\
+	((type) == T_TRCTRAP && (code) & DBREG_DR6_BS)
 #define	IS_WATCHPOINT_TRAP(type, code)	0
 
 #define	I_CALL		0xe8

Modified: stable/11/sys/sys/proc.h
==============================================================================
--- stable/11/sys/sys/proc.h	Fri Sep 14 19:50:36 2018	(r338690)
+++ stable/11/sys/sys/proc.h	Fri Sep 14 23:21:52 2018	(r338691)
@@ -441,6 +441,7 @@ do {									\
 #define	TDB_EXIT	0x00000400 /* Exiting LWP indicator for ptrace() */
 #define	TDB_VFORK	0x00000800 /* vfork indicator for ptrace() */
 #define	TDB_FSTP	0x00001000 /* The thread is PT_ATTACH leader */
+#define	TDB_STEP	0x00002000 /* (x86) PSL_T set for PT_STEP */
 
 /*
  * "Private" flags kept in td_pflags:

Modified: stable/11/sys/x86/include/reg.h
==============================================================================
--- stable/11/sys/x86/include/reg.h	Fri Sep 14 19:50:36 2018	(r338690)
+++ stable/11/sys/x86/include/reg.h	Fri Sep 14 23:21:52 2018	(r338691)
@@ -204,6 +204,14 @@ struct __dbreg64 {
 				/* Index 8-15: reserved */
 };
 
+#define	DBREG_DR6_RESERVED1	0xffff0ff0
+#define	DBREG_DR6_BMASK		0x000f
+#define	DBREG_DR6_B(i)		(1 << (i))
+#define	DBREG_DR6_BD		0x2000
+#define	DBREG_DR6_BS		0x4000
+#define	DBREG_DR6_BT		0x8000
+
+#define	DBREG_DR7_RESERVED1	0x0400
 #define	DBREG_DR7_LOCAL_ENABLE	0x01
 #define	DBREG_DR7_GLOBAL_ENABLE	0x02
 #define	DBREG_DR7_LEN_1		0x00	/* 1 byte length          */
@@ -234,6 +242,8 @@ struct __dbreg64 {
 #undef __dbreg64
 
 #ifdef _KERNEL
+struct thread;
+
 /*
  * XXX these interfaces are MI, so they should be declared in a MI place.
  */

Modified: stable/11/sys/x86/include/x86_var.h
==============================================================================
--- stable/11/sys/x86/include/x86_var.h	Fri Sep 14 19:50:36 2018	(r338690)
+++ stable/11/sys/x86/include/x86_var.h	Fri Sep 14 23:21:52 2018	(r338691)
@@ -141,7 +141,7 @@ void	nmi_handle_intr(u_int type, struct trapframe *fra
 void	pagecopy(void *from, void *to);
 void	printcpuinfo(void);
 int	pti_get_default(void);
-int	user_dbreg_trap(void);
+int	user_dbreg_trap(register_t dr6);
 int	minidumpsys(struct dumperinfo *);
 struct pcb *get_pcb_td(struct thread *td);
 



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