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

Commit 7e0dd574 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 and preparation for the ARM port from Oleg Nesterov.

Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents f0b9abfb 32cdba1e
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -158,10 +158,8 @@ static int do_signal(struct pt_regs *regs)

void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
{
	if (thread_info_flags & _TIF_UPROBE) {
		clear_thread_flag(TIF_UPROBE);
	if (thread_info_flags & _TIF_UPROBE)
		uprobe_notify_resume(regs);
	}

	if (thread_info_flags & _TIF_SIGPENDING)
		do_signal(regs);
+6 −0
Original line number Diff line number Diff line
@@ -64,6 +64,8 @@ int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
	autask->saved_trap_nr = current->thread.trap_nr;
	current->thread.trap_nr = UPROBE_TRAP_NR;
	regs->nip = current->utask->xol_vaddr;

	user_enable_single_step(current);
	return 0;
}

@@ -119,6 +121,8 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
	 * to be executed.
	 */
	regs->nip = utask->vaddr + MAX_UINSN_BYTES;

	user_disable_single_step(current);
	return 0;
}

@@ -162,6 +166,8 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)

	current->thread.trap_nr = utask->autask.saved_trap_nr;
	instruction_pointer_set(regs, utask->vaddr);

	user_disable_single_step(current);
}

/*
+19 −35
Original line number Diff line number Diff line
@@ -478,6 +478,11 @@ int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
	regs->ip = current->utask->xol_vaddr;
	pre_xol_rip_insn(auprobe, regs, autask);

	autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF);
	regs->flags |= X86_EFLAGS_TF;
	if (test_tsk_thread_flag(current, TIF_BLOCKSTEP))
		set_task_blockstep(current, false);

	return 0;
}

@@ -603,6 +608,16 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
	if (auprobe->fixups & UPROBE_FIX_CALL)
		result = adjust_ret_addr(regs->sp, correction);

	/*
	 * arch_uprobe_pre_xol() doesn't save the state of TIF_BLOCKSTEP
	 * so we can get an extra SIGTRAP if we do not clear TF. We need
	 * to examine the opcode to make it right.
	 */
	if (utask->autask.saved_tf)
		send_sig(SIGTRAP, current, 0);
	else if (!(auprobe->fixups & UPROBE_FIX_SETF))
		regs->flags &= ~X86_EFLAGS_TF;

	return result;
}

@@ -647,6 +662,10 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
	current->thread.trap_nr = utask->autask.saved_trap_nr;
	handle_riprel_post_xol(auprobe, regs, NULL);
	instruction_pointer_set(regs, utask->vaddr);

	/* clear TF if it was set by us in arch_uprobe_pre_xol() */
	if (!utask->autask.saved_tf)
		regs->flags &= ~X86_EFLAGS_TF;
}

/*
@@ -676,38 +695,3 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
		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;
	}
}
+8 −2
Original line number Diff line number Diff line
@@ -97,12 +97,12 @@ extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_con
extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
extern int uprobe_mmap(struct vm_area_struct *vma);
extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end);
extern void uprobe_start_dup_mmap(void);
extern void uprobe_end_dup_mmap(void);
extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm);
extern void uprobe_free_utask(struct task_struct *t);
extern void uprobe_copy_process(struct task_struct *t);
extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs);
extern void __weak arch_uprobe_enable_step(struct arch_uprobe *arch);
extern void __weak arch_uprobe_disable_step(struct arch_uprobe *arch);
extern int uprobe_post_sstep_notifier(struct pt_regs *regs);
extern int uprobe_pre_sstep_notifier(struct pt_regs *regs);
extern void uprobe_notify_resume(struct pt_regs *regs);
@@ -129,6 +129,12 @@ static inline void
uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end)
{
}
static inline void uprobe_start_dup_mmap(void)
{
}
static inline void uprobe_end_dup_mmap(void)
{
}
static inline void
uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm)
{
+28 −15
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include <linux/ptrace.h>	/* user_enable_single_step */
#include <linux/kdebug.h>	/* notifier mechanism */
#include "../../mm/internal.h"	/* munlock_vma_page */
#include <linux/percpu-rwsem.h>

#include <linux/uprobes.h>

@@ -71,6 +72,8 @@ static struct mutex uprobes_mutex[UPROBES_HASH_SZ];
static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ];
#define uprobes_mmap_hash(v)	(&uprobes_mmap_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ])

static struct percpu_rw_semaphore dup_mmap_sem;

/*
 * uprobe_events allows us to skip the uprobe_mmap if there are no uprobe
 * events active at this time.  Probably a fine grained per inode count is
@@ -766,10 +769,13 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
	struct map_info *info;
	int err = 0;

	percpu_down_write(&dup_mmap_sem);
	info = build_map_info(uprobe->inode->i_mapping,
					uprobe->offset, is_register);
	if (IS_ERR(info))
		return PTR_ERR(info);
	if (IS_ERR(info)) {
		err = PTR_ERR(info);
		goto out;
	}

	while (info) {
		struct mm_struct *mm = info->mm;
@@ -799,7 +805,8 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
		mmput(mm);
		info = free_map_info(info);
	}

 out:
	percpu_up_write(&dup_mmap_sem);
	return err;
}

@@ -1131,6 +1138,16 @@ void uprobe_clear_state(struct mm_struct *mm)
	kfree(area);
}

void uprobe_start_dup_mmap(void)
{
	percpu_down_read(&dup_mmap_sem);
}

void uprobe_end_dup_mmap(void)
{
	percpu_up_read(&dup_mmap_sem);
}

void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm)
{
	newmm->uprobes_state.xol_area = NULL;
@@ -1199,6 +1216,11 @@ static unsigned long xol_get_insn_slot(struct uprobe *uprobe, unsigned long slot
	vaddr = kmap_atomic(area->page);
	memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES);
	kunmap_atomic(vaddr);
	/*
	 * We probably need flush_icache_user_range() but it needs vma.
	 * This should work on supported architectures too.
	 */
	flush_dcache_page(area->page);

	return current->utask->xol_vaddr;
}
@@ -1430,16 +1452,6 @@ static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
	return uprobe;
}

void __weak arch_uprobe_enable_step(struct arch_uprobe *arch)
{
	user_enable_single_step(current);
}

void __weak arch_uprobe_disable_step(struct arch_uprobe *arch)
{
	user_disable_single_step(current);
}

/*
 * Run handler and ask thread to singlestep.
 * Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
@@ -1493,7 +1505,6 @@ static void handle_swbp(struct pt_regs *regs)
		goto out;

	if (!pre_ssout(uprobe, regs, bp_vaddr)) {
		arch_uprobe_enable_step(&uprobe->arch);
		utask->active_uprobe = uprobe;
		utask->state = UTASK_SSTEP;
		return;
@@ -1525,7 +1536,6 @@ static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs)
	else
		WARN_ON_ONCE(1);

	arch_uprobe_disable_step(&uprobe->arch);
	put_uprobe(uprobe);
	utask->active_uprobe = NULL;
	utask->state = UTASK_RUNNING;
@@ -1604,6 +1614,9 @@ static int __init init_uprobes(void)
		mutex_init(&uprobes_mmap_mutex[i]);
	}

	if (percpu_init_rwsem(&dup_mmap_sem))
		return -ENOMEM;

	return register_die_notifier(&uprobe_exception_nb);
}
module_init(init_uprobes);
Loading