Commit 116b4116 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'probes-v6.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

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
......@@ -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,20 +396,12 @@ 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:
continue;
if (process_common_fetch_insn(code, &val) < 0)
continue;
}
code++;
len = process_fetch_insn_bottom(code, val, NULL, NULL);
......@@ -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)
......
......@@ -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;
......
......@@ -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;
......
......@@ -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;
}
......@@ -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)
......
......@@ -12,7 +12,7 @@
*/
/* Return the length of string -- including null terminal byte */
static nokprobe_inline int
kern_fetch_store_strlen_user(unsigned long addr)
fetch_store_strlen_user(unsigned long addr)
{
const void __user *uaddr = (__force const void __user *)addr;
int ret;
......@@ -29,14 +29,14 @@ kern_fetch_store_strlen_user(unsigned long addr)
/* Return the length of string -- including null terminal byte */
static nokprobe_inline int
kern_fetch_store_strlen(unsigned long addr)
fetch_store_strlen(unsigned long addr)
{
int ret, len = 0;
u8 c;
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
if (addr < TASK_SIZE)
return kern_fetch_store_strlen_user(addr);
return fetch_store_strlen_user(addr);
#endif
do {
......@@ -63,7 +63,7 @@ static nokprobe_inline void set_data_loc(int ret, void *dest, void *__dest, void
* with max length and relative data location.
*/
static nokprobe_inline int
kern_fetch_store_string_user(unsigned long addr, void *dest, void *base)
fetch_store_string_user(unsigned long addr, void *dest, void *base)
{
const void __user *uaddr = (__force const void __user *)addr;
int maxlen = get_loc_len(*(u32 *)dest);
......@@ -86,7 +86,7 @@ kern_fetch_store_string_user(unsigned long addr, void *dest, void *base)
* length and relative data location.
*/
static nokprobe_inline int
kern_fetch_store_string(unsigned long addr, void *dest, void *base)
fetch_store_string(unsigned long addr, void *dest, void *base)
{
int maxlen = get_loc_len(*(u32 *)dest);
void *__dest;
......@@ -94,7 +94,7 @@ kern_fetch_store_string(unsigned long addr, void *dest, void *base)
#ifdef CONFIG_ARCH_HAS_NON_OVERLAPPING_ADDRESS_SPACE
if ((unsigned long)addr < TASK_SIZE)
return kern_fetch_store_string_user(addr, dest, base);
return fetch_store_string_user(addr, dest, base);
#endif
if (unlikely(!maxlen))
......@@ -112,4 +112,22 @@ kern_fetch_store_string(unsigned long addr, void *dest, void *base)
return ret;
}
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);
}
#endif /* __TRACE_PROBE_KERNEL_H_ */
......@@ -98,6 +98,26 @@ fetch_store_symstring(unsigned long addr, void *dest, void *base)
return sprint_symbol(__dest, addr);
}
/* common part of process_fetch_insn*/
static nokprobe_inline int
process_common_fetch_insn(struct fetch_insn *code, unsigned long *val)
{
switch (code->op) {
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;
default:
return -EILSEQ;
}
return 0;
}
/* From the 2nd stage, routine is same */
static nokprobe_inline int
process_fetch_insn_bottom(struct fetch_insn *code, unsigned long val,
......@@ -253,31 +273,3 @@ store_trace_args(void *data, struct trace_probe *tp, void *rec,
}
}
}
static inline int
print_probe_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;
}
......@@ -220,6 +220,7 @@ process_fetch_insn(struct fetch_insn *code, void *rec, void *dest,
{
struct pt_regs *regs = rec;
unsigned long val;
int ret;
/* 1st stage: get value from context */
switch (code->op) {
......@@ -235,20 +236,16 @@ 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 = FETCH_TOKEN_COMM;
break;
case FETCH_OP_DATA:
val = (unsigned long)code->data;
break;
case FETCH_OP_FOFFS:
val = translate_user_vaddr(code->immediate);
break;
default:
return -EILSEQ;
ret = process_common_fetch_insn(code, &val);
if (ret < 0)
return ret;
}
code++;
......@@ -1042,7 +1039,7 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e
data = DATAOF_TRACE_ENTRY(entry, false);
}
if (print_probe_args(s, tu->tp.args, tu->tp.nr_args, data, entry) < 0)
if (trace_probe_print_args(s, tu->tp.args, tu->tp.nr_args, data, entry) < 0)
goto out;
trace_seq_putc(s, '\n');
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment