Merge tag 'trace-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace
Pull tracing updates from Steven Rostedt: "The main changes in this release include: - Add user space specific memory reading for kprobes - Allow kprobes to be executed earlier in boot The rest are mostly just various clean ups and small fixes" * tag 'trace-v5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: (33 commits) tracing: Make trace_get_fields() global tracing: Let filter_assign_type() detect FILTER_PTR_STRING tracing: Pass type into tracing_generic_entry_update() ftrace/selftest: Test if set_event/ftrace_pid exists before writing ftrace/selftests: Return the skip code when tracing directory not configured in kernel tracing/kprobe: Check registered state using kprobe tracing/probe: Add trace_event_call accesses APIs tracing/probe: Add probe event name and group name accesses APIs tracing/probe: Add trace flag access APIs for trace_probe tracing/probe: Add trace_event_file access APIs for trace_probe tracing/probe: Add trace_event_call register API for trace_probe tracing/probe: Add trace_probe init and free functions tracing/uprobe: Set print format when parsing command tracing/kprobe: Set print format right after parsed command kprobes: Fix to init kprobes in subsys_initcall tracepoint: Use struct_size() in kmalloc() ring-buffer: Remove HAVE_64BIT_ALIGNED_ACCESS ftrace: Enable trampoline when rec count returns back to one tracing/kprobe: Do not run kprobe boot tests if kprobe_event is on cmdline tracing: Make a separate config for trace event self tests ...
This commit is contained in:
@@ -140,6 +140,13 @@ probe_mem_read(void *dest, void *src, size_t size)
|
||||
|
||||
return copy_from_user(dest, vaddr, size) ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
static nokprobe_inline int
|
||||
probe_mem_read_user(void *dest, void *src, size_t size)
|
||||
{
|
||||
return probe_mem_read(dest, src, size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
|
||||
* length and relative data location.
|
||||
@@ -176,6 +183,12 @@ fetch_store_string(unsigned long addr, void *dest, void *base)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static nokprobe_inline int
|
||||
fetch_store_string_user(unsigned long addr, void *dest, void *base)
|
||||
{
|
||||
return fetch_store_string(addr, dest, base);
|
||||
}
|
||||
|
||||
/* Return the length of string -- including null terminal byte */
|
||||
static nokprobe_inline int
|
||||
fetch_store_strlen(unsigned long addr)
|
||||
@@ -191,6 +204,12 @@ fetch_store_strlen(unsigned long addr)
|
||||
return (len > MAX_STRING_SIZE) ? 0 : len;
|
||||
}
|
||||
|
||||
static nokprobe_inline int
|
||||
fetch_store_strlen_user(unsigned long addr)
|
||||
{
|
||||
return fetch_store_strlen(addr);
|
||||
}
|
||||
|
||||
static unsigned long translate_user_vaddr(unsigned long file_offset)
|
||||
{
|
||||
unsigned long base_addr;
|
||||
@@ -270,8 +289,8 @@ static bool trace_uprobe_match(const char *system, const char *event,
|
||||
{
|
||||
struct trace_uprobe *tu = to_trace_uprobe(ev);
|
||||
|
||||
return strcmp(trace_event_name(&tu->tp.call), event) == 0 &&
|
||||
(!system || strcmp(tu->tp.call.class->system, system) == 0);
|
||||
return strcmp(trace_probe_name(&tu->tp), event) == 0 &&
|
||||
(!system || strcmp(trace_probe_group_name(&tu->tp), system) == 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -281,25 +300,17 @@ static struct trace_uprobe *
|
||||
alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
|
||||
{
|
||||
struct trace_uprobe *tu;
|
||||
|
||||
if (!event || !group)
|
||||
return ERR_PTR(-EINVAL);
|
||||
int ret;
|
||||
|
||||
tu = kzalloc(SIZEOF_TRACE_UPROBE(nargs), GFP_KERNEL);
|
||||
if (!tu)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
tu->tp.call.class = &tu->tp.class;
|
||||
tu->tp.call.name = kstrdup(event, GFP_KERNEL);
|
||||
if (!tu->tp.call.name)
|
||||
goto error;
|
||||
|
||||
tu->tp.class.system = kstrdup(group, GFP_KERNEL);
|
||||
if (!tu->tp.class.system)
|
||||
ret = trace_probe_init(&tu->tp, event, group);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
dyn_event_init(&tu->devent, &trace_uprobe_ops);
|
||||
INIT_LIST_HEAD(&tu->tp.files);
|
||||
tu->consumer.handler = uprobe_dispatcher;
|
||||
if (is_ret)
|
||||
tu->consumer.ret_handler = uretprobe_dispatcher;
|
||||
@@ -307,25 +318,18 @@ alloc_trace_uprobe(const char *group, const char *event, int nargs, bool is_ret)
|
||||
return tu;
|
||||
|
||||
error:
|
||||
kfree(tu->tp.call.name);
|
||||
kfree(tu);
|
||||
|
||||
return ERR_PTR(-ENOMEM);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static void free_trace_uprobe(struct trace_uprobe *tu)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!tu)
|
||||
return;
|
||||
|
||||
for (i = 0; i < tu->tp.nr_args; i++)
|
||||
traceprobe_free_probe_arg(&tu->tp.args[i]);
|
||||
|
||||
path_put(&tu->path);
|
||||
kfree(tu->tp.call.class->system);
|
||||
kfree(tu->tp.call.name);
|
||||
trace_probe_cleanup(&tu->tp);
|
||||
kfree(tu->filename);
|
||||
kfree(tu);
|
||||
}
|
||||
@@ -336,8 +340,8 @@ static struct trace_uprobe *find_probe_event(const char *event, const char *grou
|
||||
struct trace_uprobe *tu;
|
||||
|
||||
for_each_trace_uprobe(tu, pos)
|
||||
if (strcmp(trace_event_name(&tu->tp.call), event) == 0 &&
|
||||
strcmp(tu->tp.call.class->system, group) == 0)
|
||||
if (strcmp(trace_probe_name(&tu->tp), event) == 0 &&
|
||||
strcmp(trace_probe_group_name(&tu->tp), group) == 0)
|
||||
return tu;
|
||||
|
||||
return NULL;
|
||||
@@ -372,8 +376,8 @@ static struct trace_uprobe *find_old_trace_uprobe(struct trace_uprobe *new)
|
||||
struct trace_uprobe *tmp, *old = NULL;
|
||||
struct inode *new_inode = d_real_inode(new->path.dentry);
|
||||
|
||||
old = find_probe_event(trace_event_name(&new->tp.call),
|
||||
new->tp.call.class->system);
|
||||
old = find_probe_event(trace_probe_name(&new->tp),
|
||||
trace_probe_group_name(&new->tp));
|
||||
|
||||
for_each_trace_uprobe(tmp, pos) {
|
||||
if ((old ? old != tmp : true) &&
|
||||
@@ -578,6 +582,10 @@ static int trace_uprobe_create(int argc, const char **argv)
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret = traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu));
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = register_trace_uprobe(tu);
|
||||
if (!ret)
|
||||
goto out;
|
||||
@@ -621,8 +629,8 @@ static int trace_uprobe_show(struct seq_file *m, struct dyn_event *ev)
|
||||
char c = is_ret_probe(tu) ? 'r' : 'p';
|
||||
int i;
|
||||
|
||||
seq_printf(m, "%c:%s/%s %s:0x%0*lx", c, tu->tp.call.class->system,
|
||||
trace_event_name(&tu->tp.call), tu->filename,
|
||||
seq_printf(m, "%c:%s/%s %s:0x%0*lx", c, trace_probe_group_name(&tu->tp),
|
||||
trace_probe_name(&tu->tp), tu->filename,
|
||||
(int)(sizeof(void *) * 2), tu->offset);
|
||||
|
||||
if (tu->ref_ctr_offset)
|
||||
@@ -692,7 +700,7 @@ static int probes_profile_seq_show(struct seq_file *m, void *v)
|
||||
|
||||
tu = to_trace_uprobe(ev);
|
||||
seq_printf(m, " %s %-44s %15lu\n", tu->filename,
|
||||
trace_event_name(&tu->tp.call), tu->nhit);
|
||||
trace_probe_name(&tu->tp), tu->nhit);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -818,7 +826,7 @@ static void __uprobe_trace_func(struct trace_uprobe *tu,
|
||||
struct ring_buffer *buffer;
|
||||
void *data;
|
||||
int size, esize;
|
||||
struct trace_event_call *call = &tu->tp.call;
|
||||
struct trace_event_call *call = trace_probe_event_call(&tu->tp);
|
||||
|
||||
WARN_ON(call != trace_file->event_call);
|
||||
|
||||
@@ -860,7 +868,7 @@ static int uprobe_trace_func(struct trace_uprobe *tu, struct pt_regs *regs,
|
||||
return 0;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(link, &tu->tp.files, list)
|
||||
trace_probe_for_each_link_rcu(link, &tu->tp)
|
||||
__uprobe_trace_func(tu, 0, regs, ucb, dsize, link->file);
|
||||
rcu_read_unlock();
|
||||
|
||||
@@ -874,7 +882,7 @@ static void uretprobe_trace_func(struct trace_uprobe *tu, unsigned long func,
|
||||
struct event_file_link *link;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(link, &tu->tp.files, list)
|
||||
trace_probe_for_each_link_rcu(link, &tu->tp)
|
||||
__uprobe_trace_func(tu, func, regs, ucb, dsize, link->file);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
@@ -893,12 +901,12 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e
|
||||
|
||||
if (is_ret_probe(tu)) {
|
||||
trace_seq_printf(s, "%s: (0x%lx <- 0x%lx)",
|
||||
trace_event_name(&tu->tp.call),
|
||||
trace_probe_name(&tu->tp),
|
||||
entry->vaddr[1], entry->vaddr[0]);
|
||||
data = DATAOF_TRACE_ENTRY(entry, true);
|
||||
} else {
|
||||
trace_seq_printf(s, "%s: (0x%lx)",
|
||||
trace_event_name(&tu->tp.call),
|
||||
trace_probe_name(&tu->tp),
|
||||
entry->vaddr[0]);
|
||||
data = DATAOF_TRACE_ENTRY(entry, false);
|
||||
}
|
||||
@@ -921,26 +929,20 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
|
||||
filter_func_t filter)
|
||||
{
|
||||
bool enabled = trace_probe_is_enabled(&tu->tp);
|
||||
struct event_file_link *link = NULL;
|
||||
int ret;
|
||||
|
||||
if (file) {
|
||||
if (tu->tp.flags & TP_FLAG_PROFILE)
|
||||
if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
|
||||
return -EINTR;
|
||||
|
||||
link = kmalloc(sizeof(*link), GFP_KERNEL);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
|
||||
link->file = file;
|
||||
list_add_tail_rcu(&link->list, &tu->tp.files);
|
||||
|
||||
tu->tp.flags |= TP_FLAG_TRACE;
|
||||
ret = trace_probe_add_file(&tu->tp, file);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
} else {
|
||||
if (tu->tp.flags & TP_FLAG_TRACE)
|
||||
if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
|
||||
return -EINTR;
|
||||
|
||||
tu->tp.flags |= TP_FLAG_PROFILE;
|
||||
trace_probe_set_flag(&tu->tp, TP_FLAG_PROFILE);
|
||||
}
|
||||
|
||||
WARN_ON(!uprobe_filter_is_empty(&tu->filter));
|
||||
@@ -970,13 +972,11 @@ probe_event_enable(struct trace_uprobe *tu, struct trace_event_file *file,
|
||||
uprobe_buffer_disable();
|
||||
|
||||
err_flags:
|
||||
if (file) {
|
||||
list_del(&link->list);
|
||||
kfree(link);
|
||||
tu->tp.flags &= ~TP_FLAG_TRACE;
|
||||
} else {
|
||||
tu->tp.flags &= ~TP_FLAG_PROFILE;
|
||||
}
|
||||
if (file)
|
||||
trace_probe_remove_file(&tu->tp, file);
|
||||
else
|
||||
trace_probe_clear_flag(&tu->tp, TP_FLAG_PROFILE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -987,26 +987,18 @@ probe_event_disable(struct trace_uprobe *tu, struct trace_event_file *file)
|
||||
return;
|
||||
|
||||
if (file) {
|
||||
struct event_file_link *link;
|
||||
|
||||
link = find_event_file_link(&tu->tp, file);
|
||||
if (!link)
|
||||
if (trace_probe_remove_file(&tu->tp, file) < 0)
|
||||
return;
|
||||
|
||||
list_del_rcu(&link->list);
|
||||
/* synchronize with u{,ret}probe_trace_func */
|
||||
synchronize_rcu();
|
||||
kfree(link);
|
||||
|
||||
if (!list_empty(&tu->tp.files))
|
||||
if (trace_probe_is_enabled(&tu->tp))
|
||||
return;
|
||||
}
|
||||
} else
|
||||
trace_probe_clear_flag(&tu->tp, TP_FLAG_PROFILE);
|
||||
|
||||
WARN_ON(!uprobe_filter_is_empty(&tu->filter));
|
||||
|
||||
uprobe_unregister(tu->inode, tu->offset, &tu->consumer);
|
||||
tu->inode = NULL;
|
||||
tu->tp.flags &= file ? ~TP_FLAG_TRACE : ~TP_FLAG_PROFILE;
|
||||
|
||||
uprobe_buffer_disable();
|
||||
}
|
||||
@@ -1126,7 +1118,7 @@ static void __uprobe_perf_func(struct trace_uprobe *tu,
|
||||
unsigned long func, struct pt_regs *regs,
|
||||
struct uprobe_cpu_buffer *ucb, int dsize)
|
||||
{
|
||||
struct trace_event_call *call = &tu->tp.call;
|
||||
struct trace_event_call *call = trace_probe_event_call(&tu->tp);
|
||||
struct uprobe_trace_entry_head *entry;
|
||||
struct hlist_head *head;
|
||||
void *data;
|
||||
@@ -1279,11 +1271,11 @@ static int uprobe_dispatcher(struct uprobe_consumer *con, struct pt_regs *regs)
|
||||
ucb = uprobe_buffer_get();
|
||||
store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
|
||||
|
||||
if (tu->tp.flags & TP_FLAG_TRACE)
|
||||
if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
|
||||
ret |= uprobe_trace_func(tu, regs, ucb, dsize);
|
||||
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
if (tu->tp.flags & TP_FLAG_PROFILE)
|
||||
if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
|
||||
ret |= uprobe_perf_func(tu, regs, ucb, dsize);
|
||||
#endif
|
||||
uprobe_buffer_put(ucb);
|
||||
@@ -1314,11 +1306,11 @@ static int uretprobe_dispatcher(struct uprobe_consumer *con,
|
||||
ucb = uprobe_buffer_get();
|
||||
store_trace_args(ucb->buf, &tu->tp, regs, esize, dsize);
|
||||
|
||||
if (tu->tp.flags & TP_FLAG_TRACE)
|
||||
if (trace_probe_test_flag(&tu->tp, TP_FLAG_TRACE))
|
||||
uretprobe_trace_func(tu, func, regs, ucb, dsize);
|
||||
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
if (tu->tp.flags & TP_FLAG_PROFILE)
|
||||
if (trace_probe_test_flag(&tu->tp, TP_FLAG_PROFILE))
|
||||
uretprobe_perf_func(tu, func, regs, ucb, dsize);
|
||||
#endif
|
||||
uprobe_buffer_put(ucb);
|
||||
@@ -1329,10 +1321,10 @@ static struct trace_event_functions uprobe_funcs = {
|
||||
.trace = print_uprobe_event
|
||||
};
|
||||
|
||||
static inline void init_trace_event_call(struct trace_uprobe *tu,
|
||||
struct trace_event_call *call)
|
||||
static inline void init_trace_event_call(struct trace_uprobe *tu)
|
||||
{
|
||||
INIT_LIST_HEAD(&call->class->fields);
|
||||
struct trace_event_call *call = trace_probe_event_call(&tu->tp);
|
||||
|
||||
call->event.funcs = &uprobe_funcs;
|
||||
call->class->define_fields = uprobe_event_define_fields;
|
||||
|
||||
@@ -1343,43 +1335,14 @@ static inline void init_trace_event_call(struct trace_uprobe *tu,
|
||||
|
||||
static int register_uprobe_event(struct trace_uprobe *tu)
|
||||
{
|
||||
struct trace_event_call *call = &tu->tp.call;
|
||||
int ret = 0;
|
||||
init_trace_event_call(tu);
|
||||
|
||||
init_trace_event_call(tu, call);
|
||||
|
||||
if (traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = register_trace_event(&call->event);
|
||||
if (!ret) {
|
||||
kfree(call->print_fmt);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = trace_add_event_call(call);
|
||||
|
||||
if (ret) {
|
||||
pr_info("Failed to register uprobe event: %s\n",
|
||||
trace_event_name(call));
|
||||
kfree(call->print_fmt);
|
||||
unregister_trace_event(&call->event);
|
||||
}
|
||||
|
||||
return ret;
|
||||
return trace_probe_register_event_call(&tu->tp);
|
||||
}
|
||||
|
||||
static int unregister_uprobe_event(struct trace_uprobe *tu)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* tu->event is unregistered in trace_remove_event_call() */
|
||||
ret = trace_remove_event_call(&tu->tp.call);
|
||||
if (ret)
|
||||
return ret;
|
||||
kfree(tu->tp.call.print_fmt);
|
||||
tu->tp.call.print_fmt = NULL;
|
||||
return 0;
|
||||
return trace_probe_unregister_event_call(&tu->tp);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
@@ -1419,14 +1382,14 @@ create_local_trace_uprobe(char *name, unsigned long offs,
|
||||
tu->path = path;
|
||||
tu->ref_ctr_offset = ref_ctr_offset;
|
||||
tu->filename = kstrdup(name, GFP_KERNEL);
|
||||
init_trace_event_call(tu, &tu->tp.call);
|
||||
init_trace_event_call(tu);
|
||||
|
||||
if (traceprobe_set_print_fmt(&tu->tp, is_ret_probe(tu)) < 0) {
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return &tu->tp.call;
|
||||
return trace_probe_event_call(&tu->tp);
|
||||
error:
|
||||
free_trace_uprobe(tu);
|
||||
return ERR_PTR(ret);
|
||||
@@ -1438,9 +1401,6 @@ void destroy_local_trace_uprobe(struct trace_event_call *event_call)
|
||||
|
||||
tu = container_of(event_call, struct trace_uprobe, tp.call);
|
||||
|
||||
kfree(tu->tp.call.print_fmt);
|
||||
tu->tp.call.print_fmt = NULL;
|
||||
|
||||
free_trace_uprobe(tu);
|
||||
}
|
||||
#endif /* CONFIG_PERF_EVENTS */
|
||||
|
Reference in New Issue
Block a user