Commit 13cb7349 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'x86-entry-2020-10-12' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull x86 entry code updates from Thomas Gleixner:
 "More consolidation and correctness fixes for the debug exception:

   - Ensure BTF synchronization under all circumstances

   - Distangle kernel and user mode #DB further

   - Get ordering vs. the debug notifier correct to make KGDB work more
     reliably.

   - Cleanup historical gunk and make the code simpler to understand"

* tag 'x86-entry-2020-10-12' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/debug: Change thread.debugreg6 to thread.virtual_dr6
  x86/debug: Support negative polarity DR6 bits
  x86/debug: Simplify hw_breakpoint_handler()
  x86/debug: Remove aout_dump_debugregs()
  x86/debug: Remove the historical junk
  x86/debug: Move cond_local_irq_enable() block into exc_debug_user()
  x86/debug: Move historical SYSENTER junk into exc_debug_kernel()
  x86/debug: Simplify #DB signal code
  x86/debug: Remove handle_debug(.user) argument
  x86/debug: Move kprobe_debug_handler() into exc_debug_kernel()
  x86/debug: Sync BTF earlier
parents cc734372 d53d9bc0
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -90,8 +90,6 @@ static __always_inline bool hw_breakpoint_active(void)
	return __this_cpu_read(cpu_dr7) & DR_GLOBAL_ENABLE_MASK;
}

extern void aout_dump_debugregs(struct user *dump);

extern void hw_breakpoint_restore(void);

static __always_inline unsigned long local_db_save(void)
+4 −0
Original line number Diff line number Diff line
@@ -106,5 +106,9 @@ extern int kprobe_exceptions_notify(struct notifier_block *self,
extern int kprobe_int3_handler(struct pt_regs *regs);
extern int kprobe_debug_handler(struct pt_regs *regs);

#else

static inline int kprobe_debug_handler(struct pt_regs *regs) { return 0; }

#endif /* CONFIG_KPROBES */
#endif /* _ASM_X86_KPROBES_H */
+1 −1
Original line number Diff line number Diff line
@@ -517,7 +517,7 @@ struct thread_struct {
	/* Save middle states of ptrace breakpoints */
	struct perf_event	*ptrace_bps[HBP_NUM];
	/* Debug status used for traps, single steps, etc... */
	unsigned long           debugreg6;
	unsigned long           virtual_dr6;
	/* Keep track of the exact dr7 value set by the user */
	unsigned long           ptrace_dr7;
	/* Fault info: */
+6 −52
Original line number Diff line number Diff line
@@ -441,42 +441,6 @@ int hw_breakpoint_arch_parse(struct perf_event *bp,
	return 0;
}

/*
 * Dump the debug register contents to the user.
 * We can't dump our per cpu values because it
 * may contain cpu wide breakpoint, something that
 * doesn't belong to the current task.
 *
 * TODO: include non-ptrace user breakpoints (perf)
 */
void aout_dump_debugregs(struct user *dump)
{
	int i;
	int dr7 = 0;
	struct perf_event *bp;
	struct arch_hw_breakpoint *info;
	struct thread_struct *thread = &current->thread;

	for (i = 0; i < HBP_NUM; i++) {
		bp = thread->ptrace_bps[i];

		if (bp && !bp->attr.disabled) {
			dump->u_debugreg[i] = bp->attr.bp_addr;
			info = counter_arch_bp(bp);
			dr7 |= encode_dr7(i, info->len, info->type);
		} else {
			dump->u_debugreg[i] = 0;
		}
	}

	dump->u_debugreg[4] = 0;
	dump->u_debugreg[5] = 0;
	dump->u_debugreg[6] = current->thread.debugreg6;

	dump->u_debugreg[7] = dr7;
}
EXPORT_SYMBOL_GPL(aout_dump_debugregs);

/*
 * Release the user breakpoints used by ptrace
 */
@@ -490,7 +454,7 @@ void flush_ptrace_hw_breakpoint(struct task_struct *tsk)
		t->ptrace_bps[i] = NULL;
	}

	t->debugreg6 = 0;
	t->virtual_dr6 = 0;
	t->ptrace_dr7 = 0;
}

@@ -500,7 +464,7 @@ void hw_breakpoint_restore(void)
	set_debugreg(__this_cpu_read(cpu_debugreg[1]), 1);
	set_debugreg(__this_cpu_read(cpu_debugreg[2]), 2);
	set_debugreg(__this_cpu_read(cpu_debugreg[3]), 3);
	set_debugreg(current->thread.debugreg6, 6);
	set_debugreg(DR6_RESERVED, 6);
	set_debugreg(__this_cpu_read(cpu_dr7), 7);
}
EXPORT_SYMBOL_GPL(hw_breakpoint_restore);
@@ -523,10 +487,10 @@ EXPORT_SYMBOL_GPL(hw_breakpoint_restore);
 */
static int hw_breakpoint_handler(struct die_args *args)
{
	int i, cpu, rc = NOTIFY_STOP;
	int i, rc = NOTIFY_STOP;
	struct perf_event *bp;
	unsigned long dr6;
	unsigned long *dr6_p;
	unsigned long dr6;

	/* The DR6 value is pointed by args->err */
	dr6_p = (unsigned long *)ERR_PTR(args->err);
@@ -540,14 +504,6 @@ static int hw_breakpoint_handler(struct die_args *args)
	if ((dr6 & DR_TRAP_BITS) == 0)
		return NOTIFY_DONE;

	/*
	 * Assert that local interrupts are disabled
	 * Reset the DRn bits in the virtualized register value.
	 * The ptrace trigger routine will add in whatever is needed.
	 */
	current->thread.debugreg6 &= ~DR_TRAP_BITS;
	cpu = get_cpu();

	/* Handle all the breakpoints that were triggered */
	for (i = 0; i < HBP_NUM; ++i) {
		if (likely(!(dr6 & (DR_TRAP0 << i))))
@@ -561,7 +517,7 @@ static int hw_breakpoint_handler(struct die_args *args)
		 */
		rcu_read_lock();

		bp = per_cpu(bp_per_reg[i], cpu);
		bp = this_cpu_read(bp_per_reg[i]);
		/*
		 * Reset the 'i'th TRAP bit in dr6 to denote completion of
		 * exception handling
@@ -592,12 +548,10 @@ static int hw_breakpoint_handler(struct die_args *args)
	 * breakpoints (to generate signals) and b) when the system has
	 * taken exception due to multiple causes
	 */
	if ((current->thread.debugreg6 & DR_TRAP_BITS) ||
	if ((current->thread.virtual_dr6 & DR_TRAP_BITS) ||
	    (dr6 & (~DR_TRAP_BITS)))
		rc = NOTIFY_DONE;

	put_cpu();

	return rc;
}

+3 −2
Original line number Diff line number Diff line
@@ -629,9 +629,10 @@ static void kgdb_hw_overflow_handler(struct perf_event *event,
	struct task_struct *tsk = current;
	int i;

	for (i = 0; i < 4; i++)
	for (i = 0; i < 4; i++) {
		if (breakinfo[i].enabled)
			tsk->thread.debugreg6 |= (DR_TRAP0 << i);
			tsk->thread.virtual_dr6 |= (DR_TRAP0 << i);
	}
}

void kgdb_arch_late(void)
Loading