/* Parse an event definition. Note that any error must die. */ staticint parse_probe_event(constchar *str)
{ struct perf_probe_event *pev = ¶ms->events[params->nevents]; int ret;
pr_debug("probe-definition(%d): %s\n", params->nevents, str); if (++params->nevents == MAX_PROBES) {
pr_err("Too many probes (> %d) were specified.", MAX_PROBES); return -1;
}
pev->uprobes = params->uprobes; if (params->target) {
pev->target = strdup(params->target); if (!pev->target) return -ENOMEM;
params->target_used = true;
}
pev->nsi = nsinfo__get(params->nsi);
/* Parse a perf-probe command into event */
ret = parse_perf_probe_command(str, pev);
pr_debug("%d arguments\n", pev->nargs);
return ret;
}
staticint params_add_filter(constchar *str)
{ constchar *err = NULL; int ret = 0;
pr_debug2("Add filter: %s\n", str); if (!params->filter) {
params->filter = strfilter__new(str, &err); if (!params->filter)
ret = err ? -EINVAL : -ENOMEM;
} else
ret = strfilter__or(params->filter, str, &err);
staticint set_target(constchar *ptr)
{ int found = 0; constchar *buf;
/* * The first argument after options can be an absolute path * to an executable / library or kernel module. * * TODO: Support relative path, and $PATH, $LD_LIBRARY_PATH, * short module name.
*/ if (!params->target && ptr && *ptr == '/') {
params->target = strdup(ptr); if (!params->target) return -ENOMEM;
params->target_used = false;
found = 1;
buf = ptr + (strlen(ptr) - 3);
if (strcmp(buf, ".ko"))
params->uprobes = true;
}
return found;
}
staticint parse_probe_event_argv(int argc, constchar **argv)
{ int i, len, ret, found_target; char *buf;
found_target = set_target(argv[0]); if (found_target < 0) return found_target;
if (found_target && argc == 1) return 0;
/* Bind up rest arguments */
len = 0; for (i = 0; i < argc; i++) { if (i == 0 && found_target) continue;
len += strlen(argv[i]) + 1;
}
buf = zalloc(len + 1); if (buf == NULL) return -ENOMEM;
len = 0; for (i = 0; i < argc; i++) { if (i == 0 && found_target) continue;
len += sprintf(&buf[len], "%s ", argv[i]);
}
ret = parse_probe_event(buf);
free(buf); return ret;
}
staticint opt_set_target(conststruct option *opt, constchar *str, int unset __maybe_unused)
{ int ret = -ENOENT; char *tmp;
if (str) { if (!strcmp(opt->long_name, "exec"))
params->uprobes = true; elseif (!strcmp(opt->long_name, "module"))
params->uprobes = false; else return ret;
/* Expand given path to absolute path, except for modulename */ if (params->uprobes || strchr(str, '/')) {
tmp = nsinfo__realpath(str, params->nsi); if (!tmp) {
pr_warning("Failed to get the absolute path of %s: %m\n", str); return ret;
}
} else {
tmp = strdup(str); if (!tmp) return -ENOMEM;
}
free(params->target);
params->target = tmp;
params->target_used = false;
ret = 0;
}
return ret;
}
staticint opt_set_target_ns(conststruct option *opt __maybe_unused, constchar *str, int unset __maybe_unused)
{ int ret = -ENOENT;
pid_t ns_pid; struct nsinfo *nsip;
if (str) {
errno = 0;
ns_pid = (pid_t)strtol(str, NULL, 10); if (errno != 0) {
ret = -errno;
pr_warning("Failed to parse %s as a pid: %s\n", str,
strerror(errno)); return ret;
}
nsip = nsinfo__new(ns_pid); if (nsip && nsinfo__need_setns(nsip))
params->nsi = nsinfo__get(nsip);
nsinfo__put(nsip);
ret = 0;
}
return ret;
}
/* Command option callbacks */
#ifdef HAVE_LIBDW_SUPPORT staticint opt_show_lines(conststruct option *opt, constchar *str, int unset __maybe_unused)
{ int ret = 0;
if (!str) return 0;
if (params->command == 'L') {
pr_warning("Warning: more than one --line options are" " detected. Only the first one is valid.\n"); return 0;
}
params->command = opt->short_name;
ret = parse_line_range_desc(str, ¶ms->line_range);
return ret;
}
staticint opt_show_vars(conststruct option *opt, constchar *str, int unset __maybe_unused)
{ struct perf_probe_event *pev = ¶ms->events[params->nevents]; int ret;
staticint perf_add_probe_events(struct perf_probe_event *pevs, int npevs)
{ int ret; int i, k; constchar *event = NULL, *group = NULL;
ret = init_probe_symbol_maps(pevs->uprobes); if (ret < 0) return ret;
ret = convert_perf_probe_events(pevs, npevs); if (ret < 0) goto out_cleanup;
if (params->command == 'D') { /* it shows definition */ if (probe_conf.bootconfig)
ret = show_bootconfig_events(pevs, npevs); else
ret = show_probe_trace_events(pevs, npevs); goto out_cleanup;
}
ret = apply_perf_probe_events(pevs, npevs); if (ret < 0) goto out_cleanup;
for (i = k = 0; i < npevs; i++)
k += pevs[i].ntevs;
pr_info("Added new event%s\n", (k > 1) ? "s:" : ":"); for (i = 0; i < npevs; i++) { struct perf_probe_event *pev = &pevs[i];
for (k = 0; k < pev->ntevs; k++) { struct probe_trace_event *tev = &pev->tevs[k]; /* Skipped events have no event name */ if (!tev->event) continue;
/* We use tev's name for showing new events */
show_perf_probe_event(tev->group, tev->event, pev,
tev->point.module, false);
/* Save the last valid name */
event = tev->event;
group = tev->group;
}
}
/* Note that it is possible to skip all events because of blacklist */ if (event) { #ifndef HAVE_LIBTRACEEVENT
pr_info("\nperf is not linked with libtraceevent, to use the new probe you can use tracefs:\n\n");
pr_info("\tcd /sys/kernel/tracing/\n");
pr_info("\techo 1 > events/%s/%s/enable\n", group, event);
pr_info("\techo 1 > tracing_on\n");
pr_info("\tcat trace_pipe\n");
pr_info("\tBefore removing the probe, echo 0 > events/%s/%s/enable\n", group, event); #else /* Show how to use the event. */
pr_info("\nYou can now use it in all perf tools, such as:\n\n");
pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", group, event); #endif
}
if (quiet) { if (verbose != 0) {
pr_err(" Error: -v and -q are exclusive.\n"); return -EINVAL;
}
verbose = -1;
}
if (argc > 0) { if (strcmp(argv[0], "-") == 0) {
usage_with_options_msg(probe_usage, options, "'-' is not supported.\n");
} if (params->command && params->command != 'a') {
usage_with_options_msg(probe_usage, options, "another command except --add is set.\n");
}
ret = parse_probe_event_argv(argc, argv); if (ret < 0) {
pr_err_with_code(" Error: Command Parse Error.", ret); return ret;
}
params->command = 'a';
}
ret = symbol__validate_sym_arguments(); if (ret) return ret;
if (probe_conf.max_probes == 0)
probe_conf.max_probes = MAX_PROBES;
/* * Only consider the user's kernel image path if given.
*/
symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
/* * Except for --list, --del and --add, other command doesn't depend * nor change running kernel. So if user gives offline vmlinux, * ignore its buildid.
*/ if (!strchr("lda", params->command) && symbol_conf.vmlinux_name)
symbol_conf.ignore_vmlinux_buildid = true;
switch (params->command) { case'l': if (params->uprobes) {
pr_err(" Error: Don't use --list with --exec.\n");
parse_options_usage(probe_usage, options, "l", true);
parse_options_usage(NULL, options, "x", true); return -EINVAL;
}
ret = show_perf_probe_events(params->filter); if (ret < 0)
pr_err_with_code(" Error: Failed to show event list.", ret); return ret; case'F':
ret = show_available_funcs(params->target, params->nsi,
params->filter, params->uprobes); if (ret < 0)
pr_err_with_code(" Error: Failed to show functions.", ret); return ret; #ifdef HAVE_LIBDW_SUPPORT case'L':
ret = show_line_range(¶ms->line_range, params->target,
params->nsi, params->uprobes); if (ret < 0)
pr_err_with_code(" Error: Failed to show lines.", ret); return ret; case'V': if (!params->filter)
params->filter = strfilter__new(DEFAULT_VAR_FILTER,
NULL);
ret = show_available_vars(params->events, params->nevents,
params->filter); if (ret < 0)
pr_err_with_code(" Error: Failed to show vars.", ret); return ret; #endif case'd':
ret = perf_del_probe_events(params->filter); if (ret < 0) {
pr_err_with_code(" Error: Failed to delete events.", ret); return ret;
} break; case'D': if (probe_conf.bootconfig && params->uprobes) {
pr_err(" Error: --bootconfig doesn't support uprobes.\n"); return -EINVAL;
}
fallthrough; case'a':
/* Ensure the last given target is used */ if (params->target && !params->target_used) {
pr_err(" Error: -x/-m must follow the probe definitions.\n");
parse_options_usage(probe_usage, options, "m", true);
parse_options_usage(NULL, options, "x", true); return -EINVAL;
}
ret = perf_add_probe_events(params->events, params->nevents); if (ret < 0) {
/* * When perf_add_probe_events() fails it calls * cleanup_perf_probe_events(pevs, npevs), i.e. * cleanup_perf_probe_events(params->events, params->nevents), which * will call clear_perf_probe_event(), so set nevents to zero * to avoid cleanup_params() to call clear_perf_probe_event() again * on the same pevs.
*/
params->nevents = 0;
pr_err_with_code(" Error: Failed to add events.", ret); return ret;
} break; default:
usage_with_options(probe_usage, options);
} return 0;
}
int cmd_probe(int argc, constchar **argv)
{ int ret;
ret = init_params(); if (!ret) {
ret = __cmd_probe(argc, argv);
cleanup_params();
}
return ret < 0 ? ret : 0;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
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.