Silently ignore unexpected single-step traps (except for turning

off single-stepping).  Only do this on arches (only x86 so far)
which classify single-step traps unambiguously.

This allows other parts of the kernel to be intentionally and
unintentionally sloppy about generating single-step traps.  On
x86, at least the following places were unintentionally sloppy:
- all operations that context-switched [er]flags.  Especially
  spinlock_enter()/exit() and cpu_switch().  When single-stepped,
  saving the flags leaves PSL_T set in the saved flags, so
  restoring gives a trap that is spurious if it occurs after
  single-step mode has been left.  Switching contexts away from
  a low priority thread gives especially long-lived saved copies.
- the vm86 emulation allows user mode to set PSL_T.  This was
  correct until vm86 bios call mode was unintentionally given
  access to kdb handling its single-step traps.
Now these places are intentionally sloppy, but unexpected
debugger traps still cause panics if no debugger that handles
the trap is attached when the trap is delivered.
This commit is contained in:
Bruce Evans 2016-09-17 11:43:51 +00:00
parent ede2869c4c
commit e1e554a382

View File

@ -136,21 +136,29 @@ db_stop_at_pc(int type, int code, bool *is_breakpoint, bool *is_watchpoint)
*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.
*
* If the MD layer doesn't tell us when it is stepping, use the
* bad historical default that all unexepected traps.
* 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.
*/
#ifndef IS_SSTEP_TRAP
#define IS_SSTEP_TRAP(type, code) true
#endif
#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;