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

Commit a83cfeb9 authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Ingo Molnar
Browse files

uprobes: Change handle_trampoline() to find the next chain beforehand



No functional changes, preparation.

Add the new helper, find_next_ret_chain(), which finds the first
!chained entry and returns its ->next. Yes, it is suboptimal. We
probably want to turn ->chained into ->start_of_this_chain
pointer and avoid another loop. But this needs the boring
changes in dup_utask(), so lets do this later.

Change the main loop in handle_trampoline() to unwind the stack
until ri is equal to the pointer returned by this new helper.

Tested-by: default avatarPratyush Anand <panand@redhat.com>
Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
Acked-by: default avatarSrikar Dronamraju <srikar@linux.vnet.ibm.com>
Acked-by: default avatarAnton Arapov <arapov@gmail.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20150721134013.GA4755@redhat.com


Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 6c58d0e4
Loading
Loading
Loading
Loading
+16 −11
Original line number Diff line number Diff line
@@ -1766,11 +1766,22 @@ handle_uretprobe_chain(struct return_instance *ri, struct pt_regs *regs)
	up_read(&uprobe->register_rwsem);
}

static struct return_instance *find_next_ret_chain(struct return_instance *ri)
{
	bool chained;

	do {
		chained = ri->chained;
		ri = ri->next;	/* can't be NULL if chained */
	} while (chained);

	return ri;
}

static void handle_trampoline(struct pt_regs *regs)
{
	struct uprobe_task *utask;
	struct return_instance *ri;
	bool chained;
	struct return_instance *ri, *next;

	utask = current->utask;
	if (!utask)
@@ -1780,24 +1791,18 @@ static void handle_trampoline(struct pt_regs *regs)
	if (!ri)
		goto sigill;

	next = find_next_ret_chain(ri);
	/*
	 * TODO: we should throw out return_instance's invalidated by
	 * longjmp(), currently we assume that the probed function always
	 * returns.
	 */
	instruction_pointer_set(regs, ri->orig_ret_vaddr);

	for (;;) {
	do {
		handle_uretprobe_chain(ri, regs);

		chained = ri->chained;
		ri = free_ret_instance(ri);
		utask->depth--;

		if (!chained)
			break;
		BUG_ON(!ri);
	}
	} while (ri != next);

	utask->return_instances = ri;
	return;