Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d0616c17 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge branch 'uprobes/core' of...

Merge branch 'uprobes/core' of git://git.kernel.org/pub/scm/linux/kernel/git/oleg/misc

 into perf/core

Pull uprobes fixes + cleanups from Oleg Nesterov.

Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents bea8f354 baedbf02
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -759,6 +759,8 @@ static inline void update_debugctlmsr(unsigned long debugctlmsr)
	wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr);
}

extern void set_task_blockstep(struct task_struct *task, bool on);

/*
 * from system description table in BIOS. Mostly for MCA use, but
 * others may find it useful:
+2 −1
Original line number Diff line number Diff line
@@ -42,10 +42,11 @@ struct arch_uprobe {
};

struct arch_uprobe_task {
	unsigned long			saved_trap_nr;
#ifdef CONFIG_X86_64
	unsigned long			saved_scratch_register;
#endif
	unsigned int			saved_trap_nr;
	unsigned int			saved_tf;
};

extern int  arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr);
+33 −20
Original line number Diff line number Diff line
@@ -157,6 +157,33 @@ static int enable_single_step(struct task_struct *child)
	return 1;
}

void set_task_blockstep(struct task_struct *task, bool on)
{
	unsigned long debugctl;

	/*
	 * Ensure irq/preemption can't change debugctl in between.
	 * Note also that both TIF_BLOCKSTEP and debugctl should
	 * be changed atomically wrt preemption.
	 * FIXME: this means that set/clear TIF_BLOCKSTEP is simply
	 * wrong if task != current, SIGKILL can wakeup the stopped
	 * tracee and set/clear can play with the running task, this
	 * can confuse the next __switch_to_xtra().
	 */
	local_irq_disable();
	debugctl = get_debugctlmsr();
	if (on) {
		debugctl |= DEBUGCTLMSR_BTF;
		set_tsk_thread_flag(task, TIF_BLOCKSTEP);
	} else {
		debugctl &= ~DEBUGCTLMSR_BTF;
		clear_tsk_thread_flag(task, TIF_BLOCKSTEP);
	}
	if (task == current)
		update_debugctlmsr(debugctl);
	local_irq_enable();
}

/*
 * Enable single or block step.
 */
@@ -169,19 +196,10 @@ static void enable_step(struct task_struct *child, bool block)
	 * So no one should try to use debugger block stepping in a program
	 * that uses user-mode single stepping itself.
	 */
	if (enable_single_step(child) && block) {
		unsigned long debugctl = get_debugctlmsr();

		debugctl |= DEBUGCTLMSR_BTF;
		update_debugctlmsr(debugctl);
		set_tsk_thread_flag(child, TIF_BLOCKSTEP);
	} else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) {
		unsigned long debugctl = get_debugctlmsr();

		debugctl &= ~DEBUGCTLMSR_BTF;
		update_debugctlmsr(debugctl);
		clear_tsk_thread_flag(child, TIF_BLOCKSTEP);
	}
	if (enable_single_step(child) && block)
		set_task_blockstep(child, true);
	else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP))
		set_task_blockstep(child, false);
}

void user_enable_single_step(struct task_struct *child)
@@ -199,13 +217,8 @@ void user_disable_single_step(struct task_struct *child)
	/*
	 * Make sure block stepping (BTF) is disabled.
	 */
	if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) {
		unsigned long debugctl = get_debugctlmsr();

		debugctl &= ~DEBUGCTLMSR_BTF;
		update_debugctlmsr(debugctl);
		clear_tsk_thread_flag(child, TIF_BLOCKSTEP);
	}
	if (test_tsk_thread_flag(child, TIF_BLOCKSTEP))
		set_task_blockstep(child, false);

	/* Always clear TIF_SINGLESTEP... */
	clear_tsk_thread_flag(child, TIF_SINGLESTEP);
+51 −1
Original line number Diff line number Diff line
@@ -41,6 +41,9 @@
/* Adjust the return address of a call insn */
#define UPROBE_FIX_CALL	0x2

/* Instruction will modify TF, don't change it */
#define UPROBE_FIX_SETF	0x4

#define UPROBE_FIX_RIP_AX	0x8000
#define UPROBE_FIX_RIP_CX	0x4000

@@ -239,6 +242,10 @@ static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn)
	insn_get_opcode(insn);	/* should be a nop */

	switch (OPCODE1(insn)) {
	case 0x9d:
		/* popf */
		auprobe->fixups |= UPROBE_FIX_SETF;
		break;
	case 0xc3:		/* ret/lret */
	case 0xcb:
	case 0xc2:
@@ -646,7 +653,7 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
 * Skip these instructions as per the currently known x86 ISA.
 * 0x66* { 0x90 | 0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0 }
 */
bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
{
	int i;

@@ -673,3 +680,46 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
	}
	return false;
}

bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
{
	bool ret = __skip_sstep(auprobe, regs);
	if (ret && (regs->flags & X86_EFLAGS_TF))
		send_sig(SIGTRAP, current, 0);
	return ret;
}

void arch_uprobe_enable_step(struct arch_uprobe *auprobe)
{
	struct task_struct *task = current;
	struct arch_uprobe_task	*autask	= &task->utask->autask;
	struct pt_regs *regs = task_pt_regs(task);

	autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF);

	regs->flags |= X86_EFLAGS_TF;
	if (test_tsk_thread_flag(task, TIF_BLOCKSTEP))
		set_task_blockstep(task, false);
}

void arch_uprobe_disable_step(struct arch_uprobe *auprobe)
{
	struct task_struct *task = current;
	struct arch_uprobe_task	*autask	= &task->utask->autask;
	bool trapped = (task->utask->state == UTASK_SSTEP_TRAPPED);
	struct pt_regs *regs = task_pt_regs(task);
	/*
	 * The state of TIF_BLOCKSTEP was not saved so we can get an extra
	 * SIGTRAP if we do not clear TF. We need to examine the opcode to
	 * make it right.
	 */
	if (unlikely(trapped)) {
		if (!autask->saved_tf)
			regs->flags &= ~X86_EFLAGS_TF;
	} else {
		if (autask->saved_tf)
			send_sig(SIGTRAP, task, 0);
		else if (!(auprobe->fixups & UPROBE_FIX_SETF))
			regs->flags &= ~X86_EFLAGS_TF;
	}
}
+2 −1
Original line number Diff line number Diff line
@@ -446,7 +446,8 @@ extern int get_dumpable(struct mm_struct *mm);
#define MMF_VM_HUGEPAGE		17	/* set when VM_HUGEPAGE is set on vma */
#define MMF_EXE_FILE_CHANGED	18	/* see prctl_set_mm_exe_file() */

#define MMF_HAS_UPROBES		19	/* might have uprobes */
#define MMF_HAS_UPROBES		19	/* has uprobes */
#define MMF_RECALC_UPROBES	20	/* MMF_HAS_UPROBES can be wrong */

#define MMF_INIT_MASK		(MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK)

Loading