for (i = 0; i < ep->tp.nr_args; i++)
seq_printf(m, " %s=%s", ep->tp.args[i].name, ep->tp.args[i].comm);
seq_putc(m, '\n');
return 0;
}
staticint unregister_trace_eprobe(struct trace_eprobe *ep)
{ /* If other probes are on the event, just unregister eprobe */ if (trace_probe_has_sibling(&ep->tp)) goto unreg;
/* Enabled event can not be unregistered */ if (trace_probe_is_enabled(&ep->tp)) return -EBUSY;
/* Will fail if probe is being used by ftrace or perf */ if (trace_probe_unregister_event_call(&ep->tp)) return -EBUSY;
/* * We match the following: * event only - match all eprobes with event name * system and event only - match all system/event probes * system only - match all system probes * * The below has the above satisfied with more arguments: * * attached system/event - If the arg has the system and event * the probe is attached to, match * probes with the attachment. * * If any more args are given, then it requires a full match.
*/
/* * If system exists, but this probe is not part of that system * do not match.
*/ if (system && strcmp(trace_probe_group_name(&ep->tp), system) != 0) returnfalse;
/* Must match the event name */ if (event[0] != '\0' && strcmp(trace_probe_name(&ep->tp), event) != 0) returnfalse;
/* No arguments match all */ if (argc < 1) returntrue;
/* First argument is the system/event the probe is attached to */
slash = strchr(argv[0], '/'); if (!slash)
slash = strchr(argv[0], '.'); if (!slash) returnfalse;
if (strncmp(ep->event_system, argv[0], slash - argv[0])) returnfalse; if (strcmp(ep->event_name, slash + 1)) returnfalse;
argc--;
argv++;
/* If there are no other args, then match */ if (argc < 1) returntrue;
if (is_string_field(field)) { switch (field->filter_type) { case FILTER_DYN_STRING:
val = (unsignedlong)(rec + (*(unsignedint *)addr & 0xffff)); break; case FILTER_RDYN_STRING:
val = (unsignedlong)(addr + (*(unsignedint *)addr & 0xffff)); break; case FILTER_STATIC_STRING:
val = (unsignedlong)addr; break; case FILTER_PTR_STRING:
val = (unsignedlong)(*(char *)addr); break; default:
WARN_ON_ONCE(1); return 0;
} return val;
}
switch (field->size) { case 1: if (field->is_signed)
val = *(char *)addr; else
val = *(unsignedchar *)addr; break; case 2: if (field->is_signed)
val = *(short *)addr; else
val = *(unsignedshort *)addr; break; case 4: if (field->is_signed)
val = *(int *)addr; else
val = *(unsignedint *)addr; break; default: if (field->size == sizeof(long)) { if (field->is_signed)
val = *(long *)addr; else
val = *(unsignedlong *)addr; break;
} /* This is an array, point to the addr itself */
val = (unsignedlong)addr; break;
} return val;
}
staticint get_eprobe_size(struct trace_probe *tp, void *rec)
{ struct fetch_insn *code; struct probe_arg *arg; int i, len, ret = 0;
for (i = 0; i < tp->nr_args; i++) {
arg = tp->args + i; if (arg->dynamic) { unsignedlong val;
code = arg->code;
retry: switch (code->op) { case FETCH_OP_TP_ARG:
val = get_event_field(code, rec); break; case FETCH_NOP_SYMBOL: /* Ignore a place holder */
code++; goto retry; default: if (process_common_fetch_insn(code, &val) < 0) continue;
}
code++;
len = process_fetch_insn_bottom(code, val, NULL, NULL); if (len > 0)
ret += len;
}
}
return ret;
}
/* Kprobe specific fetch functions */
/* Note that we don't verify it, since the code does not come from user space */ staticint
process_fetch_insn(struct fetch_insn *code, void *rec, void *edata, void *dest, void *base)
{ unsignedlong val; int ret;
retry: switch (code->op) { case FETCH_OP_TP_ARG:
val = get_event_field(code, rec); break; case FETCH_NOP_SYMBOL: /* Ignore a place holder */
code++; goto retry; default:
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)
/* * The event probe implementation uses event triggers to get access to * the event it is attached to, but is not an actual trigger. The below * functions are just stubs to fulfill what is needed to use the trigger * infrastructure.
*/ staticint eprobe_trigger_init(struct event_trigger_data *data)
{ return 0;
}
/* * EVENT PROBE triggers are not registered as commands with * register_event_command(), as they are not controlled by the user * from the trigger file
*/
trigger->cmd_ops = &event_trigger_cmd;
INIT_LIST_HEAD(&trigger->list);
if (ep->filter_str) {
ret = create_event_filter(file->tr, ep->event,
ep->filter_str, false, &filter); if (ret) goto error;
}
RCU_INIT_POINTER(trigger->filter, filter);
/* Make sure nothing is using the edata or trigger */
tracepoint_synchronize_unregister();
filter = rcu_access_pointer(trigger->filter);
if (filter)
free_event_filter(filter);
kfree(edata);
kfree(trigger);
return 0;
}
staticint enable_trace_eprobe(struct trace_event_call *call, struct trace_event_file *file)
{ struct trace_probe *tp; struct trace_eprobe *ep; bool enabled; int ret = 0; int cnt = 0;
tp = trace_probe_primary_from_call(call); if (WARN_ON_ONCE(!tp)) return -ENODEV;
enabled = trace_probe_is_enabled(tp);
/* This also changes "enabled" state */ if (file) {
ret = trace_probe_add_file(tp, file); if (ret) return ret;
} else
trace_probe_set_flag(tp, TP_FLAG_PROFILE);
if (enabled) return 0;
for_each_trace_eprobe_tp(ep, tp) {
ret = enable_eprobe(ep, file); if (ret) break;
enabled = true;
cnt++;
}
if (ret) { /* Failed to enable one of them. Roll back all */ if (enabled) { /* * It's a bug if one failed for something other than memory * not being available but another eprobe succeeded.
*/
WARN_ON_ONCE(ret != -ENOMEM);
for_each_trace_eprobe_tp(ep, tp) {
disable_eprobe(ep, file->tr); if (!--cnt) break;
}
} if (file)
trace_probe_remove_file(tp, file); else
trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
}
tp = trace_probe_primary_from_call(call); if (WARN_ON_ONCE(!tp)) return -ENODEV;
if (file) { if (!trace_probe_get_file_link(tp, file)) return -ENOENT; if (!trace_probe_has_single_file(tp)) goto out;
trace_probe_clear_flag(tp, TP_FLAG_TRACE);
} else
trace_probe_clear_flag(tp, TP_FLAG_PROFILE);
if (!trace_probe_is_enabled(tp)) {
for_each_trace_eprobe_tp(ep, tp)
disable_eprobe(ep, file->tr);
}
out: if (file) /* * Synchronization is done in below function. For perf event, * file == NULL and perf_trace_event_unreg() calls * tracepoint_synchronize_unregister() to ensure synchronize * event. We don't need to care about it.
*/
trace_probe_remove_file(tp, file);
switch (type) { case TRACE_REG_REGISTER: return enable_trace_eprobe(event, file); case TRACE_REG_UNREGISTER: return disable_trace_eprobe(event, file); #ifdef CONFIG_PERF_EVENTS case TRACE_REG_PERF_REGISTER: case TRACE_REG_PERF_UNREGISTER: case TRACE_REG_PERF_OPEN: case TRACE_REG_PERF_CLOSE: case TRACE_REG_PERF_ADD: case TRACE_REG_PERF_DEL: return 0; #endif
} return 0;
}
ret = traceprobe_parse_probe_arg(&ep->tp, i, argv[i], ctx); /* Handle symbols "@" */ if (!ret)
ret = traceprobe_update_arg(&ep->tp.args[i]);
return ret;
}
staticint trace_eprobe_parse_filter(struct trace_eprobe *ep, int argc, constchar *argv[])
{ struct event_filter *dummy = NULL; int i, ret, len = 0; char *p;
if (argc == 0) {
trace_probe_log_err(0, NO_EP_FILTER); return -EINVAL;
}
/* Recover the filter string */ for (i = 0; i < argc; i++)
len += strlen(argv[i]) + 1;
ep->filter_str = kzalloc(len, GFP_KERNEL); if (!ep->filter_str) return -ENOMEM;
p = ep->filter_str; for (i = 0; i < argc; i++) { if (i)
ret = snprintf(p, len, " %s", argv[i]); else
ret = snprintf(p, len, "%s", argv[i]);
p += ret;
len -= ret;
}
/* * Ensure the filter string can be parsed correctly. Note, this * filter string is for the original event, not for the eprobe.
*/
ret = create_event_filter(top_trace_array(), ep->event, ep->filter_str, true, &dummy);
free_event_filter(dummy); if (ret) goto error;
if (IS_ERR(ep)) {
ret = PTR_ERR(ep); if (ret == -ENODEV)
trace_probe_log_err(0, BAD_ATTACH_EVENT); /* This must return -ENOMEM or missing event, else there is a bug */
WARN_ON_ONCE(ret != -ENOMEM && ret != -ENODEV);
ep = NULL; goto error;
}
if (filter_idx) {
trace_probe_log_set_index(filter_idx);
ret = trace_eprobe_parse_filter(ep, filter_cnt, argv + filter_idx); if (ret) goto parse_error;
} else
ep->filter_str = NULL;
argc -= 2; argv += 2; /* parse arguments */ for (i = 0; i < argc; i++) {
trace_probe_log_set_index(i + 2);
ret = trace_eprobe_tp_update_arg(ep, argv, i); if (ret) goto error;
}
ret = traceprobe_set_print_fmt(&ep->tp, PROBE_PRINT_EVENT); if (ret < 0) goto error;
init_trace_eprobe_call(ep);
scoped_guard(mutex, &event_mutex) {
ret = trace_probe_register_event_call(&ep->tp); if (ret) { if (ret == -EEXIST) {
trace_probe_log_set_index(0);
trace_probe_log_err(0, EVENT_EXIST);
} goto error;
}
ret = dyn_event_add(&ep->devent, &ep->tp.event->call); if (ret < 0) {
trace_probe_unregister_event_call(&ep->tp); goto error;
}
}
trace_probe_log_clear(); return ret;
mem_error:
ret = -ENOMEM; goto error;
parse_error:
ret = -EINVAL;
error:
trace_probe_log_clear();
trace_event_probe_cleanup(ep); return ret;
}
/* * Register dynevent at core_initcall. This allows kernel to setup eprobe * events in postcore_initcall without tracefs.
*/ static __init int trace_events_eprobe_init_early(void)
{ int err = 0;
err = dyn_event_register(&eprobe_dyn_event_ops); if (err)
pr_warn("Could not register eprobe_dyn_event_ops\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.