Commit 116b4116 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull kprobes cleanup updates from Masami Hiramatsu:
 "These are probe events cleanups, no new features but improve
  readability:

   - Rename print_probe_args() to trace_probe_print_args() and
     un-inline it

   - Introduce a set of default data fetch functions for dynamic
     probe events

   - Extract common code of data fetch process of dynamic probe events"

* tag 'probes-v6.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
  kernel/trace: extract common part in process_fetch_insn
  kernel/trace: Provide default impelentations defined in trace_probe_tmpl.h
  kernel/trace: Introduce trace_probe_print_args and use it in *probes
parents 0447ed0d bd78acc8
Loading
Loading
Loading
Loading
+9 −74
Original line number Diff line number Diff line
@@ -311,7 +311,7 @@ print_eprobe_event(struct trace_iterator *iter, int flags,

	trace_seq_putc(s, ')');

	if (print_probe_args(s, tp->args, tp->nr_args,
	if (trace_probe_print_args(s, tp->args, tp->nr_args,
			     (u8 *)&field[1], field) < 0)
		goto out;

@@ -320,7 +320,8 @@ print_eprobe_event(struct trace_iterator *iter, int flags,
	return trace_handle_return(s);
}

static unsigned long get_event_field(struct fetch_insn *code, void *rec)
static nokprobe_inline unsigned long
get_event_field(struct fetch_insn *code, void *rec)
{
	struct ftrace_event_field *field = code->data;
	unsigned long val;
@@ -395,19 +396,11 @@ static int get_eprobe_size(struct trace_probe *tp, void *rec)
			case FETCH_OP_TP_ARG:
				val = get_event_field(code, rec);
				break;
			case FETCH_OP_IMM:
				val = code->immediate;
				break;
			case FETCH_OP_COMM:
				val = (unsigned long)current->comm;
				break;
			case FETCH_OP_DATA:
				val = (unsigned long)code->data;
				break;
			case FETCH_NOP_SYMBOL:	/* Ignore a place holder */
				code++;
				goto retry;
			default:
				if (process_common_fetch_insn(code, &val) < 0)
					continue;
			}
			code++;
@@ -428,84 +421,26 @@ process_fetch_insn(struct fetch_insn *code, void *rec, void *dest,
		   void *base)
{
	unsigned long val;
	int ret;

 retry:
	switch (code->op) {
	case FETCH_OP_TP_ARG:
		val = get_event_field(code, rec);
		break;
	case FETCH_OP_IMM:
		val = code->immediate;
		break;
	case FETCH_OP_COMM:
		val = (unsigned long)current->comm;
		break;
	case FETCH_OP_DATA:
		val = (unsigned long)code->data;
		break;
	case FETCH_NOP_SYMBOL:	/* Ignore a place holder */
		code++;
		goto retry;
	default:
		return -EILSEQ;
		ret = process_common_fetch_insn(code, &val);
		if (ret < 0)
			return ret;
	}
	code++;
	return process_fetch_insn_bottom(code, val, dest, base);
}
NOKPROBE_SYMBOL(process_fetch_insn)

/* Return the length of string -- including null terminal byte */
static nokprobe_inline int
fetch_store_strlen_user(unsigned long addr)
{
	return kern_fetch_store_strlen_user(addr);
}

/* Return the length of string -- including null terminal byte */
static nokprobe_inline int
fetch_store_strlen(unsigned long addr)
{
	return kern_fetch_store_strlen(addr);
}

/*
 * Fetch a null-terminated string from user. Caller MUST set *(u32 *)buf
 * with max length and relative data location.
 */
static nokprobe_inline int
fetch_store_string_user(unsigned long addr, void *dest, void *base)
{
	return kern_fetch_store_string_user(addr, dest, base);
}

/*
 * Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max
 * length and relative data location.
 */
static nokprobe_inline int
fetch_store_string(unsigned long addr, void *dest, void *base)
{
	return kern_fetch_store_string(addr, dest, base);
}

static nokprobe_inline int
probe_mem_read_user(void *dest, void *src, size_t size)
{
	const void __user *uaddr =  (__force const void __user *)src;

	return copy_from_user_nofault(dest, uaddr, size);
}

static nokprobe_inline int
probe_mem_read(void *dest, void *src, size_t size)
{
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
	if ((unsigned long)src < TASK_SIZE)
		return probe_mem_read_user(dest, src, size);
#endif
	return copy_from_kernel_nofault(dest, src, size);
}

/* eprobe handler */
static inline void
__eprobe_trace_func(struct eprobe_data *edata, void *rec)
+3 −3
Original line number Diff line number Diff line
@@ -448,12 +448,12 @@ static unsigned int trace_string(struct synth_trace_event *entry,
		data_offset = struct_size(entry, fields, event->n_u64);
		data_offset += data_size;

		len = kern_fetch_store_strlen((unsigned long)str_val);
		len = fetch_store_strlen((unsigned long)str_val);

		data_offset |= len << 16;
		*(u32 *)&entry->fields[*n_u64] = data_offset;

		ret = kern_fetch_store_string((unsigned long)str_val, &entry->fields[*n_u64], entry);
		ret = fetch_store_string((unsigned long)str_val, &entry->fields[*n_u64], entry);

		(*n_u64)++;
	} else {
@@ -542,7 +542,7 @@ static notrace void trace_event_raw_event_synth(void *__data,
			len = *((unsigned long *)str_val);
			len *= sizeof(unsigned long);
		} else {
			len = kern_fetch_store_strlen((unsigned long)str_val);
			len = fetch_store_strlen((unsigned long)str_val);
		}

		fields_size += len;
+6 −66
Original line number Diff line number Diff line
@@ -1218,60 +1218,6 @@ static const struct file_operations kprobe_profile_ops = {
	.release        = seq_release,
};

/* Kprobe specific fetch functions */

/* Return the length of string -- including null terminal byte */
static nokprobe_inline int
fetch_store_strlen_user(unsigned long addr)
{
	return kern_fetch_store_strlen_user(addr);
}

/* Return the length of string -- including null terminal byte */
static nokprobe_inline int
fetch_store_strlen(unsigned long addr)
{
	return kern_fetch_store_strlen(addr);
}

/*
 * Fetch a null-terminated string from user. Caller MUST set *(u32 *)buf
 * with max length and relative data location.
 */
static nokprobe_inline int
fetch_store_string_user(unsigned long addr, void *dest, void *base)
{
	return kern_fetch_store_string_user(addr, dest, base);
}

/*
 * Fetch a null-terminated string. Caller MUST set *(u32 *)buf with max
 * length and relative data location.
 */
static nokprobe_inline int
fetch_store_string(unsigned long addr, void *dest, void *base)
{
	return kern_fetch_store_string(addr, dest, base);
}

static nokprobe_inline int
probe_mem_read_user(void *dest, void *src, size_t size)
{
	const void __user *uaddr =  (__force const void __user *)src;

	return copy_from_user_nofault(dest, uaddr, size);
}

static nokprobe_inline int
probe_mem_read(void *dest, void *src, size_t size)
{
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
	if ((unsigned long)src < TASK_SIZE)
		return probe_mem_read_user(dest, src, size);
#endif
	return copy_from_kernel_nofault(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, void *rec, void *dest,
@@ -1279,6 +1225,7 @@ process_fetch_insn(struct fetch_insn *code, void *rec, void *dest,
{
	struct pt_regs *regs = rec;
	unsigned long val;
	int ret;

retry:
	/* 1st stage: get value from context */
@@ -1295,15 +1242,6 @@ process_fetch_insn(struct fetch_insn *code, void *rec, void *dest,
	case FETCH_OP_RETVAL:
		val = regs_return_value(regs);
		break;
	case FETCH_OP_IMM:
		val = code->immediate;
		break;
	case FETCH_OP_COMM:
		val = (unsigned long)current->comm;
		break;
	case FETCH_OP_DATA:
		val = (unsigned long)code->data;
		break;
#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
	case FETCH_OP_ARG:
		val = regs_get_kernel_argument(regs, code->param);
@@ -1313,7 +1251,9 @@ process_fetch_insn(struct fetch_insn *code, void *rec, void *dest,
		code++;
		goto retry;
	default:
		return -EILSEQ;
		ret = process_common_fetch_insn(code, &val);
		if (ret < 0)
			return ret;
	}
	code++;

@@ -1424,7 +1364,7 @@ print_kprobe_event(struct trace_iterator *iter, int flags,

	trace_seq_putc(s, ')');

	if (print_probe_args(s, tp->args, tp->nr_args,
	if (trace_probe_print_args(s, tp->args, tp->nr_args,
			     (u8 *)&field[1], field) < 0)
		goto out;

@@ -1459,7 +1399,7 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,

	trace_seq_putc(s, ')');

	if (print_probe_args(s, tp->args, tp->nr_args,
	if (trace_probe_print_args(s, tp->args, tp->nr_args,
			     (u8 *)&field[1], field) < 0)
		goto out;

+27 −0
Original line number Diff line number Diff line
@@ -1239,3 +1239,30 @@ int trace_probe_create(const char *raw_command, int (*createfn)(int, const char

	return ret;
}

int trace_probe_print_args(struct trace_seq *s, struct probe_arg *args, int nr_args,
		 u8 *data, void *field)
{
	void *p;
	int i, j;

	for (i = 0; i < nr_args; i++) {
		struct probe_arg *a = args + i;

		trace_seq_printf(s, " %s=", a->name);
		if (likely(!a->count)) {
			if (!a->type->print(s, data + a->offset, field))
				return -ENOMEM;
			continue;
		}
		trace_seq_putc(s, '{');
		p = data + a->offset;
		for (j = 0; j < a->count; j++) {
			if (!a->type->print(s, p, field))
				return -ENOMEM;
			trace_seq_putc(s, j == a->count - 1 ? '}' : ',');
			p += a->type->size;
		}
	}
	return 0;
}
+2 −0
Original line number Diff line number Diff line
@@ -349,6 +349,8 @@ int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b);
bool trace_probe_match_command_args(struct trace_probe *tp,
				    int argc, const char **argv);
int trace_probe_create(const char *raw_command, int (*createfn)(int, const char **));
int trace_probe_print_args(struct trace_seq *s, struct probe_arg *args, int nr_args,
		 u8 *data, void *field);

#define trace_probe_for_each_link(pos, tp)	\
	list_for_each_entry(pos, &(tp)->event->files, list)
Loading