Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 7 Nov 2016 12:10:18 +0000 (UTC)
From:      Konstantin Belousov <kib@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: r308418 - in stable/11: share/man/man4 sys/amd64/amd64 sys/amd64/include sys/ddb sys/i386/i386 sys/i386/include sys/x86/include
Message-ID:  <201611071210.uA7CAILf015426@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Mon Nov  7 12:10:17 2016
New Revision: 308418
URL: https://svnweb.freebsd.org/changeset/base/308418

Log:
  Merge bde improvements for ddb on x86, mostly for single-stepping and
  vm86 mode.
  
  MFC r304085 (by bde):
  Fix the variables $esp, $ds, $es, $fs, $gs and $ss in vm86 mode.  Fix
  PC_REGS() so that printing of instructions works in some useful cases.
  
  MFC r304962 (by bde):
  Expand error messages: print symbol names, parentheses and shift tokens,
  and negative shift counts.  Fix error messages.
  
  MFC r305612 (by bde):
  Fix single-stepping of instructions emulated by vm86.
  
  MFC r305661 (by bde):
  Give the full syntax of the 'count' arg for all commmands that support
  it. Give the full syntax of the 'addr' arg for these commands and some
  others.  Rename it from 'address' for the generic command. Fix
  description of how 'count' is supposed to work for the 'break'
  command.
  
  Don't (mis)describe the syntax of the comma for the 'step' command.
  
  Expand the description for the generic command.
  
  Give the full syntax for the 'examine' command.  It was also missing
  the possible values for the modifier.
  
  MFC r305663 (by bde):
  Fix stopping when the specified breakpoint count is reached.
  
  MFC r305665 (by bde):
  Pass the trap type and code down from db_trap() to db_stop_at_pc() so
  that the latter can easily determine what the trap type actually is
  after callers are fixed to encode the type unambigously.
  
  MFC r305807 (by bde):
  Use the MI macro TRAPF_USERMODE() instead of open-coded checks for
  SEL_UPL and sometimes PSL_VM.  Fix logic errors in treating vm86
  bioscall mode as kernel mode.  The main place checked all the
  necessary flags, but put the necessary parentheses for the PSL_VM and
  PCB_VM86CALL checks in the wrong place.
  
  MFC r305811 (by bz):
  Try to fix LINT builds after r305807.
  
  MFC r305840 (by bde):
  Abort single stepping in ddb if the trap is not for single-stepping.
  
  MFC r305862 (by bde):
  Ifdef the new dr6 variable for KDB.
  
  MFC r305864 (by bde):
  Statically initialize the run mode to the one that will become current
  on first entry. Don't reset to the run mode to STEP_NONE when
  stopping, and remove STEP_NONE.
  
  MFC r305865 (by bde):
  Fix decoding of tf_rsp on amd64, and move TF_HAS_STACKREGS() to the
  i386-only section, and fix a comment about the amd64 kernel trapframe
  not having stackregs.
  
  MFC r305897 (by bde):
  Silently ignore unexpected single-step traps.
  
  MFC r306311 (by bde):
  Determine the operand/address size of %cs in a new function
  db_segsize().  Use db_segsize() to set the default operand/address
  size for disassembling.
  
  Fix db_print_loc_and_inst() to ask for the normal format and not the
  alternate in normal operation. Use db_segsize() to avoid trying to
  print a garbage stack trace if %cs is 16 bits.

Modified:
  stable/11/share/man/man4/ddb.4
  stable/11/sys/amd64/amd64/trap.c
  stable/11/sys/amd64/include/db_machdep.h
  stable/11/sys/ddb/db_examine.c
  stable/11/sys/ddb/db_expr.c
  stable/11/sys/ddb/db_main.c
  stable/11/sys/ddb/db_run.c
  stable/11/sys/ddb/ddb.h
  stable/11/sys/i386/i386/db_disasm.c
  stable/11/sys/i386/i386/db_interface.c
  stable/11/sys/i386/i386/db_trace.c
  stable/11/sys/i386/i386/trap.c
  stable/11/sys/i386/i386/vm86.c
  stable/11/sys/i386/include/db_machdep.h
  stable/11/sys/x86/include/frame.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/share/man/man4/ddb.4
==============================================================================
--- stable/11/share/man/man4/ddb.4	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/share/man/man4/ddb.4	Mon Nov  7 12:10:17 2016	(r308418)
@@ -146,25 +146,32 @@ to be the same as
 .Pp
 The general command syntax is:
 .Ar command Ns Op Li / Ns Ar modifier
-.Ar address Ns Op Li , Ns Ar count
+.Oo Ar addr Oc Ns Op Li , Ns Ar count
 .Pp
 A blank line repeats the previous command from the address
 .Va next
 with
 count 1 and no modifiers.
 Specifying
-.Ar address
+.Ar addr
 sets
 .Va dot
 to the address.
 Omitting
-.Ar address
+.Ar addr
 uses
 .Va dot .
 A missing
 .Ar count
 is taken
 to be 1 for printing commands or infinity for stack traces.
+A
+.Ar count
+of -1 is equivalent to a missing
+.Ar count .
+Options that are supplied but not supported by the given
+.Ar command
+are usually ignored.
 .Pp
 The
 .Nm
@@ -204,8 +211,14 @@ browse through the history buffer, and m
 current line.
 .Sh COMMANDS
 .Bl -tag -width indent -compact
-.It Ic examine
-.It Ic x
+.It Xo
+.Ic examine Ns Op Li / Ns Cm AISabcdghilmorsuxz ...
+.Oo Ar addr Oc Ns Op Li , Ns Ar count
+.Xc
+.It Xo
+.Ic x       Ns Op Li / Ns Cm AISabcdghilmorsuxz ...
+.Oo Ar addr Oc Ns Op Li , Ns Ar count
+.Xc
 Display the addressed locations according to the formats in the modifier.
 Multiple modifier formats display multiple locations.
 If no format is specified, the last format specified for this command
@@ -251,7 +264,9 @@ The location is also displayed in hex at
 display as an instruction
 .It Cm I
 display as an instruction with possible alternate formats depending on the
-machine, but none of the supported architectures have an alternate format.
+machine.
+On i386, this selects the alternate format for the instruction decoding
+(16 bits in a 32-bit code segment and vice versa).
 .It Cm S
 display a symbol name for the pointer stored at the address
 .El
@@ -328,16 +343,17 @@ Set the named variable or register with 
 .Ar expr .
 Valid variable names are described below.
 .Pp
-.It Ic break Ns Op Li / Ns Cm u
-.It Ic b Ns Op Li / Ns Cm u
+.It Ic break Ns Oo Li / Ns Cm u Oc Oo Ar addr Oc Ns Op Li , Ns Ar count
+.It Ic b     Ns Oo Li / Ns Cm u Oc Oo Ar addr Oc Ns Op Li , Ns Ar count
 Set a break point at
 .Ar addr .
 If
 .Ar count
-is supplied, continues
+is supplied, the
+.Ic continue
+command will not stop at this break point on the first
 .Ar count
-\- 1 times before stopping at the
-break point.
+\- 1 times that it is hit.
 If the break point is set, a break point number is
 printed with
 .Ql # .
@@ -361,21 +377,24 @@ user space break points may not work cor
 Setting a break
 point at the low-level code paths may also cause strange behavior.
 .Pp
-.It Ic delete Ar addr
-.It Ic d Ar addr
+.It Ic delete Op Ar addr
+.It Ic d      Op Ar addr
 .It Ic delete Li # Ns Ar number
-.It Ic d Li # Ns Ar number
-Delete the break point.
-The target break point can be specified by a
+.It Ic d      Li # Ns Ar number
+Delete the specified break point.
+The break point can be specified by a
 break point number with
 .Ql # ,
 or by using the same
 .Ar addr
 specified in the original
 .Ic break
-command.
+command, or by omitting
+.Ar addr
+to get the default address of
+.Va dot .
 .Pp
-.It Ic watch Ar addr Ns Li , Ns Ar size
+.It Ic watch Oo Ar addr Oc Ns Op Li , Ns Ar size
 Set a watchpoint for a region.
 Execution stops when an attempt to modify the region occurs.
 The
@@ -389,7 +408,7 @@ Attempts to watch wired kernel memory
 may cause unrecoverable error in some systems such as i386.
 Watchpoints on user addresses work best.
 .Pp
-.It Ic hwatch Ar addr Ns Li , Ns Ar size
+.It Ic hwatch Oo Ar addr Oc Ns Op Li , Ns Ar size
 Set a hardware watchpoint for a region if supported by the
 architecture.
 Execution stops when an attempt to modify the region occurs.
@@ -405,14 +424,14 @@ Use
 for setting watchpoints on kernel address locations only, and avoid
 its use on user mode address spaces.
 .Pp
-.It Ic dhwatch Ar addr Ns Li , Ns Ar size
+.It Ic dhwatch Oo Ar addr Oc Ns Op Li , Ns Ar size
 Delete specified hardware watchpoint.
 .Pp
-.It Ic step Ns Op Li / Ns Cm p
-.It Ic s Ns Op Li / Ns Cm p
+.It Ic step Ns Oo Li / Ns Cm p Oc Ns Op Li , Ns Ar count
+.It Ic s    Ns Oo Li / Ns Cm p Oc Ns Op Li , Ns Ar count
 Single step
 .Ar count
-times (the comma is a mandatory part of the syntax).
+times.
 If the
 .Cm p
 modifier is specified, print each instruction at each step.
@@ -458,22 +477,22 @@ Otherwise, only print when the matching 
 .Pp
 .It Xo
 .Ic trace Ns Op Li / Ns Cm u
-.Op Ar pid | tid
+.Op Ar pid | tid Ns
 .Op Li , Ns Ar count
 .Xc
 .It Xo
 .Ic t Ns Op Li / Ns Cm u
-.Op Ar pid | tid
+.Op Ar pid | tid Ns
 .Op Li , Ns Ar count
 .Xc
 .It Xo
 .Ic where Ns Op Li / Ns Cm u
-.Op Ar pid | tid
+.Op Ar pid | tid Ns
 .Op Li , Ns Ar count
 .Xc
 .It Xo
 .Ic bt Ns Op Li / Ns Cm u
-.Op Ar pid | tid
+.Op Ar pid | tid Ns
 .Op Li , Ns Ar count
 .Xc
 Stack trace.
@@ -498,16 +517,11 @@ only if the machine dependent code suppo
 .Ic search Ns Op Li / Ns Cm bhl
 .Ar addr
 .Ar value
-.Op Ar mask
+.Op Ar mask Ns
 .Op Li , Ns Ar count
 .Xc
 Search memory for
 .Ar value .
-This command might fail in interesting
-ways if it does not find the searched-for value.
-This is because
-.Nm
-does not always recover from touching bad memory.
 The optional
 .Ar count
 argument limits the search.
@@ -537,7 +551,6 @@ addresses for the process and not show o
 .Pp
 .It Ic show Cm all trace
 .It Ic alltrace
-.Xc
 Show a stack trace for every thread in the system.
 .Pp
 .It Ic show Cm all ttys

Modified: stable/11/sys/amd64/amd64/trap.c
==============================================================================
--- stable/11/sys/amd64/amd64/trap.c	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/sys/amd64/amd64/trap.c	Mon Nov  7 12:10:17 2016	(r308418)
@@ -176,7 +176,10 @@ trap(struct trapframe *frame)
 #endif
 	struct thread *td = curthread;
 	struct proc *p = td->td_proc;
-	int i = 0, ucode = 0, code;
+#ifdef KDB
+	register_t dr6;
+#endif
+	int i = 0, ucode = 0;
 	u_int type;
 	register_t addr = 0;
 	ksiginfo_t ksi;
@@ -236,7 +239,7 @@ trap(struct trapframe *frame)
 		 * interrupts disabled until they are accidentally
 		 * enabled later.
 		 */
-		if (ISPL(frame->tf_cs) == SEL_UPL)
+		if (TRAPF_USERMODE(frame))
 			uprintf(
 			    "pid %ld (%s): trap %d with interrupts disabled\n",
 			    (long)curproc->p_pid, curthread->td_name, type);
@@ -258,9 +261,7 @@ trap(struct trapframe *frame)
 		}
 	}
 
-	code = frame->tf_err;
-
-        if (ISPL(frame->tf_cs) == SEL_UPL) {
+	if (TRAPF_USERMODE(frame)) {
 		/* user trap */
 
 		td->td_pticks = 0;
@@ -377,7 +378,7 @@ trap(struct trapframe *frame)
 #ifdef DEV_ISA
 		case T_NMI:
 			/* machine/parity/power fail/"kitchen sink" faults */
-			if (isa_nmi(code) == 0) {
+			if (isa_nmi(frame->tf_err) == 0) {
 #ifdef KDB
 				/*
 				 * NMI can be hooked up to a pushbutton
@@ -540,8 +541,7 @@ trap(struct trapframe *frame)
 				 * Reset breakpoint bits because the
 				 * processor doesn't
 				 */
-				/* XXX check upper bits here */
-				load_dr6(rdr6() & 0xfffffff0);
+				load_dr6(rdr6() & ~0xf);
 				goto out;
 			}
 			/*
@@ -553,7 +553,10 @@ trap(struct trapframe *frame)
 			 * Otherwise, debugger traps "can't happen".
 			 */
 #ifdef KDB
-			if (kdb_trap(type, 0, frame))
+			/* XXX %dr6 is not quite reentrant. */
+			dr6 = rdr6();
+			load_dr6(dr6 & ~0x4000);
+			if (kdb_trap(type, dr6, frame))
 				goto out;
 #endif
 			break;
@@ -561,7 +564,7 @@ trap(struct trapframe *frame)
 #ifdef DEV_ISA
 		case T_NMI:
 			/* machine/parity/power fail/"kitchen sink" faults */
-			if (isa_nmi(code) == 0) {
+			if (isa_nmi(frame->tf_err) == 0) {
 #ifdef KDB
 				/*
 				 * NMI can be hooked up to a pushbutton
@@ -773,7 +776,6 @@ trap_fatal(frame, eva)
 {
 	int code, ss;
 	u_int type;
-	long esp;
 	struct soft_segment_descriptor softseg;
 	char *msg;
 
@@ -787,7 +789,7 @@ trap_fatal(frame, eva)
 	else
 		msg = "UNKNOWN";
 	printf("\n\nFatal trap %d: %s while in %s mode\n", type, msg,
-	    ISPL(frame->tf_cs) == SEL_UPL ? "user" : "kernel");
+	    TRAPF_USERMODE(frame) ? "user" : "kernel");
 #ifdef SMP
 	/* two separate prints in case of a trap on an unmapped page */
 	printf("cpuid = %d; ", PCPU_GET(cpuid));
@@ -804,14 +806,8 @@ trap_fatal(frame, eva)
 	}
 	printf("instruction pointer	= 0x%lx:0x%lx\n",
 	       frame->tf_cs & 0xffff, frame->tf_rip);
-        if (ISPL(frame->tf_cs) == SEL_UPL) {
-		ss = frame->tf_ss & 0xffff;
-		esp = frame->tf_rsp;
-	} else {
-		ss = GSEL(GDATA_SEL, SEL_KPL);
-		esp = (long)&frame->tf_rsp;
-	}
-	printf("stack pointer	        = 0x%x:0x%lx\n", ss, esp);
+	ss = frame->tf_ss & 0xffff;
+	printf("stack pointer	        = 0x%x:0x%lx\n", ss, frame->tf_rsp);
 	printf("frame pointer	        = 0x%x:0x%lx\n", ss, frame->tf_rbp);
 	printf("code segment		= base 0x%lx, limit 0x%lx, type 0x%x\n",
 	       softseg.ssd_base, softseg.ssd_limit, softseg.ssd_type);
@@ -934,7 +930,7 @@ amd64_syscall(struct thread *td, int tra
 	ksiginfo_t ksi;
 
 #ifdef DIAGNOSTIC
-	if (ISPL(td->td_frame->tf_cs) != SEL_UPL) {
+	if (!TRAPF_USERMODE(td->td_frame)) {
 		panic("syscall");
 		/* NOT REACHED */
 	}

Modified: stable/11/sys/amd64/include/db_machdep.h
==============================================================================
--- stable/11/sys/amd64/include/db_machdep.h	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/sys/amd64/include/db_machdep.h	Mon Nov  7 12:10:17 2016	(r308418)
@@ -56,12 +56,16 @@ do {						\
 #define	db_clear_single_step	kdb_cpu_clear_singlestep
 #define	db_set_single_step	kdb_cpu_set_singlestep
 
-#define	IS_BREAKPOINT_TRAP(type, code)	((type) == T_BPTFLT)
 /*
- * Watchpoints are not supported.  The debug exception type is in %dr6
- * and not yet in the args to this macro.
+ * The debug exception type is copied from %dr6 to 'code' and used to
+ * disambiguate single step traps.  Watchpoints have no special support.
+ * Our hardware breakpoints are not well integrated with ddb and are too
+ * different from watchpoints.  ddb treats them as unknown traps with
+ * unknown addresses and doesn't turn them off while it is running.
  */
-#define IS_WATCHPOINT_TRAP(type, code)	0
+#define	IS_BREAKPOINT_TRAP(type, code)	((type) == T_BPTFLT)
+#define	IS_SSTEP_TRAP(type, code)	((type) == T_TRCTRAP && (code) & 0x4000)
+#define	IS_WATCHPOINT_TRAP(type, code)	0
 
 #define	I_CALL		0xe8
 #define	I_CALLI		0xff

Modified: stable/11/sys/ddb/db_examine.c
==============================================================================
--- stable/11/sys/ddb/db_examine.c	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/sys/ddb/db_examine.c	Mon Nov  7 12:10:17 2016	(r308418)
@@ -241,7 +241,7 @@ db_print_loc_and_inst(db_addr_t loc)
 	db_printsym(loc, DB_STGY_PROC);
 	if (db_search_symbol(loc, DB_STGY_PROC, &off) != C_DB_SYM_NULL) {
 		db_printf(":\t");
-		(void)db_disasm(loc, true);
+		(void)db_disasm(loc, false);
 	}
 }
 

Modified: stable/11/sys/ddb/db_expr.c
==============================================================================
--- stable/11/sys/ddb/db_expr.c	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/sys/ddb/db_expr.c	Mon Nov  7 12:10:17 2016	(r308418)
@@ -57,7 +57,8 @@ db_term(db_expr_t *valuep)
 	    if (!db_value_of_name(db_tok_string, valuep) &&
 		!db_value_of_name_pcpu(db_tok_string, valuep) &&
 		!db_value_of_name_vnet(db_tok_string, valuep)) {
-		db_error("Symbol not found\n");
+		db_printf("Symbol '%s' not found\n", db_tok_string);
+		db_error(NULL);
 		/*NOTREACHED*/
 	    }
 	    return (true);
@@ -89,12 +90,14 @@ db_term(db_expr_t *valuep)
 	}
 	if (t == tLPAREN) {
 	    if (!db_expression(valuep)) {
-		db_error("Syntax error\n");
+		db_printf("Expression syntax error after '%c'\n", '(');
+		db_error(NULL);
 		/*NOTREACHED*/
 	    }
 	    t = db_read_token();
 	    if (t != tRPAREN) {
-		db_error("Syntax error\n");
+		db_printf("Expression syntax error -- expected '%c'\n", ')');
+		db_error(NULL);
 		/*NOTREACHED*/
 	    }
 	    return (true);
@@ -164,7 +167,9 @@ db_mult_expr(db_expr_t *valuep)
 	while (t == tSTAR || t == tSLASH || t == tPCT || t == tHASH ||
 	    t == tBIT_AND ) {
 	    if (!db_term(&rhs)) {
-		db_printf("Expression syntax error after '%c'\n", '!');
+		db_printf("Expression syntax error after '%c'\n",
+		    t == tSTAR ? '*' : t == tSLASH ? '/' : t == tPCT ? '%' :
+		    t == tHASH ? '#' : '&');
 		db_error(NULL);
 		/*NOTREACHED*/
 	    }
@@ -177,7 +182,7 @@ db_mult_expr(db_expr_t *valuep)
 		    break;
 		default:
 		    if (rhs == 0) {
-			db_error("Divide by 0\n");
+			db_error("Division by 0\n");
 			/*NOTREACHED*/
 		    }
 		    if (t == tSLASH)
@@ -199,7 +204,6 @@ db_add_expr(db_expr_t *valuep)
 {
 	db_expr_t	lhs, rhs;
 	int		t;
-	char		c;
 
 	if (!db_mult_expr(&lhs))
 	    return (false);
@@ -207,8 +211,8 @@ db_add_expr(db_expr_t *valuep)
 	t = db_read_token();
 	while (t == tPLUS || t == tMINUS || t == tBIT_OR) {
 	    if (!db_mult_expr(&rhs)) {
-		c = db_tok_string[0];
-		db_printf("Expression syntax error after '%c'\n", c);
+		db_printf("Expression syntax error after '%c'\n",
+		    t == tPLUS ? '+' : t == tMINUS ? '-' : '|');
 		db_error(NULL);
 		/*NOTREACHED*/
 	    }
@@ -243,11 +247,14 @@ db_shift_expr(db_expr_t *valuep)
 	t = db_read_token();
 	while (t == tSHIFT_L || t == tSHIFT_R) {
 	    if (!db_add_expr(&rhs)) {
-		db_error("Syntax error\n");
+		db_printf("Expression syntax error after '%s'\n",
+		    t == tSHIFT_L ? "<<" : ">>");
+		db_error(NULL);
 		/*NOTREACHED*/
 	    }
 	    if (rhs < 0) {
-		db_error("Negative shift amount\n");
+		db_printf("Negative shift amount %jd\n", (intmax_t)rhs);
+		db_error(NULL);
 		/*NOTREACHED*/
 	    }
 	    if (t == tSHIFT_L)
@@ -269,7 +276,6 @@ db_logical_relation_expr(
 {
 	db_expr_t	lhs, rhs;
 	int		t;
-	char		op[3];
 
 	if (!db_shift_expr(&lhs))
 	    return (false);
@@ -277,11 +283,11 @@ db_logical_relation_expr(
 	t = db_read_token();
 	while (t == tLOG_EQ || t == tLOG_NOT_EQ || t == tGREATER ||
 	    t == tGREATER_EQ || t == tLESS || t == tLESS_EQ) {
-	    op[0] = db_tok_string[0];
-	    op[1] = db_tok_string[1];
-	    op[2] = 0;
 	    if (!db_shift_expr(&rhs)) {
-		db_printf("Expression syntax error after \"%s\"\n", op);
+		db_printf("Expression syntax error after '%s'\n",
+		    t == tLOG_EQ ? "==" : t == tLOG_NOT_EQ ? "!=" :
+		    t == tGREATER ? ">" : t == tGREATER_EQ ? ">=" :
+		    t == tLESS ? "<" : "<=");
 		db_error(NULL);
 		/*NOTREACHED*/
 	    }

Modified: stable/11/sys/ddb/db_main.c
==============================================================================
--- stable/11/sys/ddb/db_main.c	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/sys/ddb/db_main.c	Mon Nov  7 12:10:17 2016	(r308418)
@@ -226,10 +226,7 @@ db_trap(int type, int code)
 	if (cnunavailable())
 		return (0);
 
-	bkpt = IS_BREAKPOINT_TRAP(type, code);
-	watchpt = IS_WATCHPOINT_TRAP(type, code);
-
-	if (db_stop_at_pc(&bkpt)) {
+	if (db_stop_at_pc(type, code, &bkpt, &watchpt)) {
 		if (db_inst_count) {
 			db_printf("After %d instructions (%d loads, %d stores),\n",
 			    db_inst_count, db_load_count, db_store_count);

Modified: stable/11/sys/ddb/db_run.c
==============================================================================
--- stable/11/sys/ddb/db_run.c	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/sys/ddb/db_run.c	Mon Nov  7 12:10:17 2016	(r308418)
@@ -48,15 +48,15 @@ __FBSDID("$FreeBSD$");
 #include <ddb/db_break.h>
 #include <ddb/db_access.h>
 
-static int	db_run_mode;
-#define	STEP_NONE	0
 #define	STEP_ONCE	1
 #define	STEP_RETURN	2
 #define	STEP_CALLT	3
 #define	STEP_CONTINUE	4
 #define	STEP_INVISIBLE	5
 #define	STEP_COUNT	6
+static int	db_run_mode = STEP_CONTINUE;
 
+static bool		db_sstep_multiple;
 static bool		db_sstep_print;
 static int		db_loop_count;
 static int		db_call_depth;
@@ -90,13 +90,14 @@ db_pc_is_singlestep(db_addr_t pc)
 #endif
 
 bool
-db_stop_at_pc(bool *is_breakpoint)
+db_stop_at_pc(int type, int code, bool *is_breakpoint, bool *is_watchpoint)
 {
 	db_addr_t	pc;
 	db_breakpoint_t bkpt;
 
+	*is_breakpoint = IS_BREAKPOINT_TRAP(type, code);
+	*is_watchpoint = IS_WATCHPOINT_TRAP(type, code);
 	pc = PC_REGS();
-
 	if (db_pc_is_singlestep(pc))
 		*is_breakpoint = false;
 
@@ -125,13 +126,39 @@ db_stop_at_pc(bool *is_breakpoint)
 		*is_breakpoint = true;
 		return (true);	/* stop here */
 	    }
+	    return (false);	/* continue the countdown */
 	} else if (*is_breakpoint) {
 #ifdef BKPT_SKIP
 		BKPT_SKIP;
 #endif
 	}
 
-	*is_breakpoint = false;
+	*is_breakpoint = false;	/* might be a breakpoint, but not ours */
+
+	/*
+	 * If not stepping, then silently ignore single-step traps
+	 * (except for clearing the single-step-flag above).
+	 *
+	 * If stepping, then abort if the trap type is unexpected.
+	 * Breakpoints owned by us are expected and were handled above.
+	 * Single-steps are expected and are handled below.  All others
+	 * are unexpected.
+	 *
+	 * Only do either of these if the MD layer claims to classify
+	 * single-step traps unambiguously (by defining IS_SSTEP_TRAP).
+	 * Otherwise, fall through to the bad historical behaviour
+	 * given by turning unexpected traps into expected traps: if not
+	 * stepping, then expect only breakpoints and stop, and if
+	 * stepping, then expect only single-steps and step.
+	 */
+#ifdef IS_SSTEP_TRAP
+	if (db_run_mode == STEP_CONTINUE && IS_SSTEP_TRAP(type, code))
+	    return (false);
+	if (db_run_mode != STEP_CONTINUE && !IS_SSTEP_TRAP(type, code)) {
+	    printf("Stepping aborted\n");
+	    return (true);
+	}
+#endif
 
 	if (db_run_mode == STEP_INVISIBLE) {
 	    db_run_mode = STEP_CONTINUE;
@@ -184,7 +211,6 @@ db_stop_at_pc(bool *is_breakpoint)
 		return (false);	/* continue */
 	    }
 	}
-	db_run_mode = STEP_NONE;
 	return (true);
 }
 
@@ -194,6 +220,7 @@ db_restart_at_pc(bool watchpt)
 	db_addr_t	pc = PC_REGS();
 
 	if ((db_run_mode == STEP_COUNT) ||
+	    ((db_run_mode == STEP_ONCE) && db_sstep_multiple) ||
 	    (db_run_mode == STEP_RETURN) ||
 	    (db_run_mode == STEP_CALLT)) {
 	    /*
@@ -321,6 +348,7 @@ db_single_step_cmd(db_expr_t addr, bool 
 
 	db_run_mode = STEP_ONCE;
 	db_loop_count = count;
+	db_sstep_multiple = (count != 1);
 	db_sstep_print = print;
 	db_inst_count = 0;
 	db_load_count = 0;

Modified: stable/11/sys/ddb/ddb.h
==============================================================================
--- stable/11/sys/ddb/ddb.h	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/sys/ddb/ddb.h	Mon Nov  7 12:10:17 2016	(r308418)
@@ -215,7 +215,8 @@ void		db_restart_at_pc(bool watchpt);
 int		db_set_variable(db_expr_t value);
 void		db_set_watchpoints(void);
 void		db_skip_to_eol(void);
-bool		db_stop_at_pc(bool *is_breakpoint);
+bool		db_stop_at_pc(int type, int code, bool *is_breakpoint,
+		    bool *is_watchpoint);
 #define		db_strcpy	strcpy
 void		db_trace_self(void);
 int		db_trace_thread(struct thread *, int);

Modified: stable/11/sys/i386/i386/db_disasm.c
==============================================================================
--- stable/11/sys/i386/i386/db_disasm.c	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/sys/i386/i386/db_disasm.c	Mon Nov  7 12:10:17 2016	(r308418)
@@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
  * Instruction disassembler.
  */
 #include <sys/param.h>
+#include <sys/kdb.h>
 
 #include <ddb/ddb.h>
 #include <ddb/db_access.h>
@@ -1168,9 +1169,17 @@ db_disasm(db_addr_t loc, bool altfmt)
 	int	len;
 	struct i_addr	address;
 
+	if (db_segsize(kdb_frame) == 16)
+	   altfmt = !altfmt;
 	get_value_inc(inst, loc, 1, FALSE);
-	short_addr = FALSE;
-	size = LONG;
+	if (altfmt) {
+	    short_addr = TRUE;
+	    size = WORD;
+	}
+	else {
+	    short_addr = FALSE;
+	    size = LONG;
+	}
 	seg = NULL;
 
 	/*

Modified: stable/11/sys/i386/i386/db_interface.c
==============================================================================
--- stable/11/sys/i386/i386/db_interface.c	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/sys/i386/i386/db_interface.c	Mon Nov  7 12:10:17 2016	(r308418)
@@ -135,6 +135,30 @@ db_write_bytes(vm_offset_t addr, size_t 
 	return (ret);
 }
 
+int
+db_segsize(struct trapframe *tfp)
+{
+	struct proc_ldt *plp;
+	struct segment_descriptor *sdp;
+	int sel;
+
+	if (tfp == NULL)
+	    return (32);
+	if (tfp->tf_eflags & PSL_VM)
+	    return (16);
+	sel = tfp->tf_cs & 0xffff;
+	if (sel == GSEL(GCODE_SEL, SEL_KPL))
+	    return (32);
+	/* Rare cases follow.  User mode cases are currently unreachable. */
+	if (ISLDT(sel)) {
+	    plp = curthread->td_proc->p_md.md_ldt;
+	    sdp = (plp != NULL) ? &plp->ldt_sd : &ldt[0].sd;
+	} else {
+	    sdp = &gdt[PCPU_GET(cpuid) * NGDT].sd;
+	}
+	return (sdp[IDXSEL(sel)].sd_def32 == 0 ? 16 : 32);
+}
+
 void
 db_show_mdpcpu(struct pcpu *pc)
 {

Modified: stable/11/sys/i386/i386/db_trace.c
==============================================================================
--- stable/11/sys/i386/i386/db_trace.c	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/sys/i386/i386/db_trace.c	Mon Nov  7 12:10:17 2016	(r308418)
@@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/sysent.h>
 
 #include <machine/cpu.h>
+#include <machine/frame.h>
 #include <machine/md_var.h>
 #include <machine/pcb.h>
 #include <machine/reg.h>
@@ -81,8 +82,7 @@ struct db_variable *db_eregs = db_regs +
 static __inline int
 get_esp(struct trapframe *tf)
 {
-	return ((ISPL(tf->tf_cs)) ? tf->tf_esp :
-	    (db_expr_t)tf + (uintptr_t)DB_OFFSET(tf_esp));
+	return (TF_HAS_STACKREGS(tf) ? tf->tf_esp : (intptr_t)&tf->tf_esp);
 }
 
 static int
@@ -104,12 +104,32 @@ db_frame(struct db_variable *vp, db_expr
 static int
 db_frame_seg(struct db_variable *vp, db_expr_t *valuep, int op)
 {
+	struct trapframe_vm86 *tfp;
+	int off;
 	uint16_t *reg;
 
 	if (kdb_frame == NULL)
 		return (0);
 
-	reg = (uint16_t *)((uintptr_t)kdb_frame + (db_expr_t)vp->valuep);
+	off = (intptr_t)vp->valuep;
+	if (kdb_frame->tf_eflags & PSL_VM) {
+		tfp = (void *)kdb_frame;
+		switch ((intptr_t)vp->valuep) {
+		case (intptr_t)DB_OFFSET(tf_cs):
+			reg = (uint16_t *)&tfp->tf_cs;
+			break;
+		case (intptr_t)DB_OFFSET(tf_ds):
+			reg = (uint16_t *)&tfp->tf_vm86_ds;
+			break;
+		case (intptr_t)DB_OFFSET(tf_es):
+			reg = (uint16_t *)&tfp->tf_vm86_es;
+			break;
+		case (intptr_t)DB_OFFSET(tf_fs):
+			reg = (uint16_t *)&tfp->tf_vm86_fs;
+			break;
+		}
+	} else
+		reg = (uint16_t *)((uintptr_t)kdb_frame + off);
 	if (op == DB_VAR_GET)
 		*valuep = *reg;
 	else
@@ -126,7 +146,7 @@ db_esp(struct db_variable *vp, db_expr_t
 
 	if (op == DB_VAR_GET)
 		*valuep = get_esp(kdb_frame);
-	else if (ISPL(kdb_frame->tf_cs))
+	else if (TF_HAS_STACKREGS(kdb_frame))
 		kdb_frame->tf_esp = *valuep;
 	return (1);
 }
@@ -134,7 +154,16 @@ db_esp(struct db_variable *vp, db_expr_t
 static int
 db_gs(struct db_variable *vp, db_expr_t *valuep, int op)
 {
+	struct trapframe_vm86 *tfp;
 
+	if (kdb_frame != NULL && kdb_frame->tf_eflags & PSL_VM) {
+		tfp = (void *)kdb_frame;
+		if (op == DB_VAR_GET)
+			*valuep = tfp->tf_vm86_gs;
+		else
+			tfp->tf_vm86_gs = *valuep;
+		return (1);
+	}
 	if (op == DB_VAR_GET)
 		*valuep = rgs();
 	else
@@ -150,8 +179,9 @@ db_ss(struct db_variable *vp, db_expr_t 
 		return (0);
 
 	if (op == DB_VAR_GET)
-		*valuep = (ISPL(kdb_frame->tf_cs)) ? kdb_frame->tf_ss : rss();
-	else if (ISPL(kdb_frame->tf_cs))
+		*valuep = TF_HAS_STACKREGS(kdb_frame) ? kdb_frame->tf_ss :
+		    rss();
+	else if (TF_HAS_STACKREGS(kdb_frame))
 		kdb_frame->tf_ss = *valuep;
 	return (1);
 }
@@ -391,6 +421,17 @@ db_backtrace(struct thread *td, struct t
 	int instr, narg;
 	boolean_t first;
 
+	if (db_segsize(tf) == 16) {
+		db_printf(
+"--- 16-bit%s, cs:eip = %#x:%#x, ss:esp = %#x:%#x, ebp = %#x, tf = %p ---\n",
+		    (tf->tf_eflags & PSL_VM) ? " (vm86)" : "",
+		    tf->tf_cs, tf->tf_eip,
+		    TF_HAS_STACKREGS(tf) ? tf->tf_ss : rss(),
+		    TF_HAS_STACKREGS(tf) ? tf->tf_esp : (intptr_t)&tf->tf_esp,
+		    tf->tf_ebp, tf);
+		return (0);
+	}
+
 	/*
 	 * If an indirect call via an invalid pointer caused a trap,
 	 * %pc contains the invalid address while the return address
@@ -408,7 +449,7 @@ db_backtrace(struct thread *td, struct t
 		 * Find where the trap frame actually ends.
 		 * It won't contain tf_esp or tf_ss unless crossing rings.
 		 */
-		if (ISPL(kdb_frame->tf_cs))
+		if (TF_HAS_STACKREGS(kdb_frame))
 			instr = (int)(kdb_frame + 1);
 		else
 			instr = (int)&kdb_frame->tf_esp;

Modified: stable/11/sys/i386/i386/trap.c
==============================================================================
--- stable/11/sys/i386/i386/trap.c	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/sys/i386/i386/trap.c	Mon Nov  7 12:10:17 2016	(r308418)
@@ -189,7 +189,10 @@ trap(struct trapframe *frame)
 #endif
 	struct thread *td = curthread;
 	struct proc *p = td->td_proc;
-	int i = 0, ucode = 0, code;
+#ifdef KDB
+	register_t dr6;
+#endif
+	int i = 0, ucode = 0;
 	u_int type;
 	register_t addr = 0;
 	vm_offset_t eva;
@@ -267,7 +270,8 @@ trap(struct trapframe *frame)
 		 * interrupts disabled until they are accidentally
 		 * enabled later.
 		 */
-		if (ISPL(frame->tf_cs) == SEL_UPL || (frame->tf_eflags & PSL_VM))
+		if (TRAPF_USERMODE(frame) &&
+		    (curpcb->pcb_flags & PCB_VM86CALL) == 0)
 			uprintf(
 			    "pid %ld (%s): trap %d with interrupts disabled\n",
 			    (long)curproc->p_pid, curthread->td_name, type);
@@ -291,7 +295,6 @@ trap(struct trapframe *frame)
 		}
 	}
 	eva = 0;
-	code = frame->tf_err;
 	if (type == T_PAGEFLT) {
 		/*
 		 * For some Cyrix CPUs, %cr2 is clobbered by
@@ -307,9 +310,7 @@ trap(struct trapframe *frame)
 			enable_intr();
 	}
 
-        if ((ISPL(frame->tf_cs) == SEL_UPL) ||
-	    ((frame->tf_eflags & PSL_VM) && 
-		!(curpcb->pcb_flags & PCB_VM86CALL))) {
+        if (TRAPF_USERMODE(frame) && (curpcb->pcb_flags & PCB_VM86CALL) == 0) {
 		/* user trap */
 
 		td->td_pticks = 0;
@@ -335,6 +336,7 @@ trap(struct trapframe *frame)
 					goto out;
 			}
 #endif
+user_trctrap_out:
 			frame->tf_eflags &= ~PSL_T;
 			i = SIGTRAP;
 			ucode = (type == T_TRCTRAP ? TRAP_TRACE : TRAP_BRKPT);
@@ -360,6 +362,11 @@ trap(struct trapframe *frame)
 		case T_STKFLT:		/* stack fault */
 			if (frame->tf_eflags & PSL_VM) {
 				i = vm86_emulate((struct vm86frame *)frame);
+				if (i == SIGTRAP) {
+					type = T_TRCTRAP;
+					load_dr6(rdr6() | 0x4000);
+					goto user_trctrap_out;
+				}
 				if (i == 0)
 					goto user;
 				break;
@@ -461,7 +468,7 @@ trap(struct trapframe *frame)
 			goto userout;
 #else /* !POWERFAIL_NMI */
 			/* machine/parity/power fail/"kitchen sink" faults */
-			if (isa_nmi(code) == 0) {
+			if (isa_nmi(frame->tf_err) == 0) {
 #ifdef KDB
 				/*
 				 * NMI can be hooked up to a pushbutton
@@ -566,6 +573,11 @@ trap(struct trapframe *frame)
 		case T_STKFLT:		/* stack fault */
 			if (frame->tf_eflags & PSL_VM) {
 				i = vm86_emulate((struct vm86frame *)frame);
+				if (i == SIGTRAP) {
+					type = T_TRCTRAP;
+					load_dr6(rdr6() | 0x4000);
+					goto kernel_trctrap;
+				}
 				if (i != 0)
 					/*
 					 * returns to original process
@@ -654,6 +666,7 @@ trap(struct trapframe *frame)
 			break;
 
 		case T_TRCTRAP:	 /* trace trap */
+kernel_trctrap:
 			if (frame->tf_eip == (int)IDTVEC(lcall_syscall)) {
 				/*
 				 * We've just entered system mode via the
@@ -687,7 +700,7 @@ trap(struct trapframe *frame)
 				 * Reset breakpoint bits because the
 				 * processor doesn't
 				 */
-				load_dr6(rdr6() & 0xfffffff0);
+				load_dr6(rdr6() & ~0xf);
 				goto out;
 			}
 			/*
@@ -699,7 +712,10 @@ trap(struct trapframe *frame)
 			 * Otherwise, debugger traps "can't happen".
 			 */
 #ifdef KDB
-			if (kdb_trap(type, 0, frame))
+			/* XXX %dr6 is not quite reentrant. */
+			dr6 = rdr6();
+			load_dr6(dr6 & ~0x4000);
+			if (kdb_trap(type, dr6, frame))
 				goto out;
 #endif
 			break;
@@ -715,7 +731,7 @@ trap(struct trapframe *frame)
 			goto out;
 #else /* !POWERFAIL_NMI */
 			/* machine/parity/power fail/"kitchen sink" faults */
-			if (isa_nmi(code) == 0) {
+			if (isa_nmi(frame->tf_err) == 0) {
 #ifdef KDB
 				/*
 				 * NMI can be hooked up to a pushbutton
@@ -953,7 +969,7 @@ trap_fatal(frame, eva)
 	}
 	printf("instruction pointer	= 0x%x:0x%x\n",
 	       frame->tf_cs & 0xffff, frame->tf_eip);
-        if ((ISPL(frame->tf_cs) == SEL_UPL) || (frame->tf_eflags & PSL_VM)) {
+        if (TF_HAS_STACKREGS(frame)) {
 		ss = frame->tf_ss & 0xffff;
 		esp = frame->tf_esp;
 	} else {
@@ -1107,7 +1123,8 @@ syscall(struct trapframe *frame)
 	ksiginfo_t ksi;
 
 #ifdef DIAGNOSTIC
-	if (ISPL(frame->tf_cs) != SEL_UPL) {
+	if (!(TRAPF_USERMODE(frame) &&
+	    (curpcb->pcb_flags & PCB_VM86CALL) == 0)) {
 		panic("syscall");
 		/* NOT REACHED */
 	}

Modified: stable/11/sys/i386/i386/vm86.c
==============================================================================
--- stable/11/sys/i386/i386/vm86.c	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/sys/i386/i386/vm86.c	Mon Nov  7 12:10:17 2016	(r308418)
@@ -171,7 +171,7 @@ vm86_emulate(vmf)
 					PUSHL((vmf->vmf_eflags & PUSH_MASK)
 					    | PSL_IOPL, vmf);
 				vmf->vmf_ip += inc_ip;
-				return (0);
+				return (retcode);
 
 			case POPF:
 				temp_flags = POPL(vmf) & POP_MASK;
@@ -185,7 +185,7 @@ vm86_emulate(vmf)
 				} else {
 					vmf->vmf_eflags &= ~PSL_VIF;
 				}
-				return (0);
+				return (retcode);
 			}
 			break;
 
@@ -203,7 +203,7 @@ vm86_emulate(vmf)
 		case INTn:
 			break;
 
-		/* VME if trying to set PSL_TF, or PSL_I when VIP is set */
+		/* VME if trying to set PSL_T, or PSL_I when VIP is set */
 		case POPF:
 			temp_flags = POP(vmf) & POP_MASK;
 			vmf->vmf_flags = (vmf->vmf_flags & ~POP_MASK)
@@ -218,7 +218,7 @@ vm86_emulate(vmf)
 			}
 			return (retcode);
 
-		/* VME if trying to set PSL_TF, or PSL_I when VIP is set */
+		/* VME if trying to set PSL_T, or PSL_I when VIP is set */
 		case IRET:
 			vmf->vmf_ip = POP(vmf);
 			vmf->vmf_cs = POP(vmf);

Modified: stable/11/sys/i386/include/db_machdep.h
==============================================================================
--- stable/11/sys/i386/include/db_machdep.h	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/sys/i386/include/db_machdep.h	Mon Nov  7 12:10:17 2016	(r308418)
@@ -35,7 +35,10 @@
 typedef	vm_offset_t	db_addr_t;	/* address - unsigned */
 typedef	int		db_expr_t;	/* expression - signed */
 
-#define	PC_REGS()	((db_addr_t)kdb_thrctx->pcb_eip)
+#define	PC_REGS()	((db_addr_t)(kdb_frame->tf_eflags & PSL_VM ?	\
+			    (kdb_frame->tf_eip & 0xffff) +		\
+			    ((kdb_frame->tf_cs & 0xffff) << 4) :	\
+			    kdb_frame->tf_eip))
 
 #define	BKPT_INST	0xcc		/* breakpoint instruction */
 #define	BKPT_SIZE	(1)		/* size of breakpoint inst */
@@ -56,12 +59,16 @@ do {						\
 #define	db_clear_single_step	kdb_cpu_clear_singlestep
 #define	db_set_single_step	kdb_cpu_set_singlestep
 
-#define	IS_BREAKPOINT_TRAP(type, code)	((type) == T_BPTFLT)
 /*
- * Watchpoints are not supported.  The debug exception type is in %dr6
- * and not yet in the args to this macro.
+ * The debug exception type is copied from %dr6 to 'code' and used to
+ * disambiguate single step traps.  Watchpoints have no special support.
+ * Our hardware breakpoints are not well integrated with ddb and are too
+ * different from watchpoints.  ddb treats them as unknown traps with
+ * unknown addresses and doesn't turn them off while it is running.
  */
-#define IS_WATCHPOINT_TRAP(type, code)	0
+#define	IS_BREAKPOINT_TRAP(type, code)	((type) == T_BPTFLT)
+#define	IS_SSTEP_TRAP(type, code)	((type) == T_TRCTRAP && (code) & 0x4000)
+#define	IS_WATCHPOINT_TRAP(type, code)	0
 
 #define	I_CALL		0xe8
 #define	I_CALLI		0xff
@@ -91,4 +98,6 @@ do {						\
 #define	DB_SMALL_VALUE_MAX	0x7fffffff
 #define	DB_SMALL_VALUE_MIN	(-0x400001)
 
+int	db_segsize(struct trapframe *tfp);
+
 #endif /* !_MACHINE_DB_MACHDEP_H_ */

Modified: stable/11/sys/x86/include/frame.h
==============================================================================
--- stable/11/sys/x86/include/frame.h	Mon Nov  7 11:56:18 2016	(r308417)
+++ stable/11/sys/x86/include/frame.h	Mon Nov  7 12:10:17 2016	(r308418)
@@ -64,7 +64,7 @@ struct trapframe {
 	int	tf_eip;
 	int	tf_cs;
 	int	tf_eflags;
-	/* below only when crossing rings (e.g. user to kernel) */

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



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