diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 3ffb8702a84f..0926c8477152 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -176,6 +176,7 @@ trap(struct trapframe *frame) #endif struct thread *td = curthread; struct proc *p = td->td_proc; + register_t dr6; int i = 0, ucode = 0, code; u_int type; register_t addr = 0; @@ -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; diff --git a/sys/amd64/include/db_machdep.h b/sys/amd64/include/db_machdep.h index 29e385e3af0c..722a7b3b0fb6 100644 --- a/sys/amd64/include/db_machdep.h +++ b/sys/amd64/include/db_machdep.h @@ -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 diff --git a/sys/ddb/db_run.c b/sys/ddb/db_run.c index 08c724cf76fb..564cbfe1ec25 100644 --- a/sys/ddb/db_run.c +++ b/sys/ddb/db_run.c @@ -57,6 +57,7 @@ static int db_run_mode; #define STEP_INVISIBLE 5 #define STEP_COUNT 6 +static bool db_sstep_multiple; static bool db_sstep_print; static int db_loop_count; static int db_call_depth; @@ -133,7 +134,25 @@ db_stop_at_pc(int type, int code, bool *is_breakpoint, bool *is_watchpoint) #endif } - *is_breakpoint = false; + *is_breakpoint = false; /* might be a breakpoint, but not ours */ + + /* + * 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. + * + * If the MD layer doesn't tell us when it is stepping, use the + * bad historical default that all unexepected traps. + */ +#ifndef IS_SSTEP_TRAP +#define IS_SSTEP_TRAP(type, code) true +#endif + if (db_run_mode != STEP_CONTINUE && !IS_SSTEP_TRAP(type, code)) { + printf("Stepping aborted\n"); + db_run_mode = STEP_NONE; + return (true); + } if (db_run_mode == STEP_INVISIBLE) { db_run_mode = STEP_CONTINUE; @@ -194,6 +213,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 +341,7 @@ db_single_step_cmd(db_expr_t addr, bool have_addr, db_expr_t count, char *modif) 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; diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index 724dd57d947b..8317c5bbb904 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -189,6 +189,7 @@ trap(struct trapframe *frame) #endif struct thread *td = curthread; struct proc *p = td->td_proc; + register_t dr6; int i = 0, ucode = 0, code; u_int type; register_t addr = 0; @@ -362,6 +363,7 @@ user_trctrap_out: i = vm86_emulate((struct vm86frame *)frame); if (i == SIGTRAP) { type = T_TRCTRAP; + load_dr6(rdr6() | 0x4000); goto user_trctrap_out; } if (i == 0) @@ -572,6 +574,7 @@ user_trctrap_out: i = vm86_emulate((struct vm86frame *)frame); if (i == SIGTRAP) { type = T_TRCTRAP; + load_dr6(rdr6() | 0x4000); goto kernel_trctrap; } if (i != 0) @@ -696,7 +699,7 @@ kernel_trctrap: * Reset breakpoint bits because the * processor doesn't */ - load_dr6(rdr6() & 0xfffffff0); + load_dr6(rdr6() & ~0xf); goto out; } /* @@ -708,7 +711,10 @@ kernel_trctrap: * 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; diff --git a/sys/i386/include/db_machdep.h b/sys/i386/include/db_machdep.h index cfffee807587..3ab06486a3fb 100644 --- a/sys/i386/include/db_machdep.h +++ b/sys/i386/include/db_machdep.h @@ -59,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