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

Commit 9b960a38 authored by Masami Hiramatsu's avatar Masami Hiramatsu Committed by Steven Rostedt (VMware)
Browse files

tracing: probeevent: Unify fetch_insn processing common part

Unify the fetch_insn bottom process (from stage 2: dereference
indirect data) from kprobe and uprobe events, since those are
mostly same.

Link: http://lkml.kernel.org/r/152465879965.26224.8547240824606804815.stgit@devbox



Signed-off-by: default avatarMasami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: default avatarSteven Rostedt (VMware) <rostedt@goodmis.org>
parent 0a46c854
Loading
Loading
Loading
Loading
+7 −40
Original line number Diff line number Diff line
@@ -899,13 +899,18 @@ fetch_store_string(unsigned long addr, void *dest, void *base)
	return ret;
}

static nokprobe_inline int
probe_mem_read(void *dest, void *src, size_t size)
{
	return probe_kernel_read(dest, src, size);
}

/* Note that we don't verify it, since the code does not come from user space */
static int
process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
		   void *base)
{
	unsigned long val;
	int ret = 0;

	/* 1st stage: get value from context */
	switch (code->op) {
@@ -932,45 +937,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
	}
	code++;

	/* 2nd stage: dereference memory if needed */
	while (code->op == FETCH_OP_DEREF) {
		ret = probe_kernel_read(&val, (void *)val + code->offset,
					sizeof(val));
		if (ret)
			return ret;
		code++;
	}

	/* 3rd stage: store value to buffer */
	if (unlikely(!dest)) {
		if (code->op == FETCH_OP_ST_STRING)
			return fetch_store_strlen(val + code->offset);
		else
			return -EILSEQ;
	}

	switch (code->op) {
	case FETCH_OP_ST_RAW:
		fetch_store_raw(val, code, dest);
		break;
	case FETCH_OP_ST_MEM:
		probe_kernel_read(dest, (void *)val + code->offset, code->size);
		break;
	case FETCH_OP_ST_STRING:
		ret = fetch_store_string(val + code->offset, dest, base);
		break;
	default:
		return -EILSEQ;
	}
	code++;

	/* 4th stage: modify stored value if needed */
	if (code->op == FETCH_OP_MOD_BF) {
		fetch_apply_bitfield(code, dest);
		code++;
	}

	return code->op == FETCH_OP_END ? ret : -EILSEQ;
	return process_fetch_insn_bottom(code, val, dest, base);
}
NOKPROBE_SYMBOL(process_fetch_insn)

+54 −1
Original line number Diff line number Diff line
@@ -49,13 +49,66 @@ fetch_apply_bitfield(struct fetch_insn *code, void *buf)
}

/*
 * This must be defined for each callsite.
 * These functions must be defined for each callsite.
 * Return consumed dynamic data size (>= 0), or error (< 0).
 * If dest is NULL, don't store result and return required dynamic data size.
 */
static int
process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs,
		   void *dest, void *base);
static nokprobe_inline int fetch_store_strlen(unsigned long addr);
static nokprobe_inline int
fetch_store_string(unsigned long addr, void *dest, void *base);
static nokprobe_inline int
probe_mem_read(void *dest, void *src, size_t size);

/* From the 2nd stage, routine is same */
static nokprobe_inline int
process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
			   void *dest, void *base)
{
	int ret = 0;

	/* 2nd stage: dereference memory if needed */
	while (code->op == FETCH_OP_DEREF) {
		ret = probe_mem_read(&val, (void *)val + code->offset,
					sizeof(val));
		if (ret)
			return ret;
		code++;
	}

	/* 3rd stage: store value to buffer */
	if (unlikely(!dest)) {
		if (code->op == FETCH_OP_ST_STRING)
			return fetch_store_strlen(val + code->offset);
		else
			return -EILSEQ;
	}

	switch (code->op) {
	case FETCH_OP_ST_RAW:
		fetch_store_raw(val, code, dest);
		break;
	case FETCH_OP_ST_MEM:
		probe_mem_read(dest, (void *)val + code->offset, code->size);
		break;
	case FETCH_OP_ST_STRING:
		ret = fetch_store_string(val + code->offset, dest, base);
		break;
	default:
		return -EILSEQ;
	}
	code++;

	/* 4th stage: modify stored value if needed */
	if (code->op == FETCH_OP_MOD_BF) {
		fetch_apply_bitfield(code, dest);
		code++;
	}

	return code->op == FETCH_OP_END ? ret : -EILSEQ;
}

/* Sum up total data length for dynamic arraies (strings) */
static nokprobe_inline int
+2 −41
Original line number Diff line number Diff line
@@ -101,7 +101,7 @@ static unsigned long get_user_stack_nth(struct pt_regs *regs, unsigned int n)
 * Uprobes-specific fetch functions
 */
static nokprobe_inline int
probe_user_read(void *dest, void *src, size_t size)
probe_mem_read(void *dest, void *src, size_t size)
{
	void __user *vaddr = (void __force __user *)src;

@@ -162,7 +162,6 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
		   void *base)
{
	unsigned long val;
	int ret = 0;

	/* 1st stage: get value from context */
	switch (code->op) {
@@ -189,45 +188,7 @@ process_fetch_insn(struct fetch_insn *code, struct pt_regs *regs, void *dest,
	}
	code++;

	/* 2nd stage: dereference memory if needed */
	while (code->op == FETCH_OP_DEREF) {
		ret = probe_user_read(&val, (void *)val + code->offset,
				      sizeof(val));
		if (ret)
			return ret;
		code++;
	}

	/* 3rd stage: store value to buffer */
	if (unlikely(!dest)) {
		if (code->op == FETCH_OP_ST_STRING)
			return fetch_store_strlen(val + code->offset);
		else
			return -EILSEQ;
	}

	switch (code->op) {
	case FETCH_OP_ST_RAW:
		fetch_store_raw(val, code, dest);
		break;
	case FETCH_OP_ST_MEM:
		probe_kernel_read(dest, (void *)val + code->offset, code->size);
		break;
	case FETCH_OP_ST_STRING:
		ret = fetch_store_string(val + code->offset, dest, base);
		break;
	default:
		return -EILSEQ;
	}
	code++;

	/* 4th stage: modify stored value if needed */
	if (code->op == FETCH_OP_MOD_BF) {
		fetch_apply_bitfield(code, dest);
		code++;
	}

	return code->op == FETCH_OP_END ? ret : -EILSEQ;
	return process_fetch_insn_bottom(code, val, dest, base);
}
NOKPROBE_SYMBOL(process_fetch_insn)