18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * builtin-probe.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Builtin probe command: Set up probe events by C expression 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Written by Masami Hiramatsu <mhiramat@redhat.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <sys/utsname.h> 108c2ecf20Sopenharmony_ci#include <sys/types.h> 118c2ecf20Sopenharmony_ci#include <sys/stat.h> 128c2ecf20Sopenharmony_ci#include <fcntl.h> 138c2ecf20Sopenharmony_ci#include <errno.h> 148c2ecf20Sopenharmony_ci#include <stdio.h> 158c2ecf20Sopenharmony_ci#include <unistd.h> 168c2ecf20Sopenharmony_ci#include <stdlib.h> 178c2ecf20Sopenharmony_ci#include <string.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "builtin.h" 208c2ecf20Sopenharmony_ci#include "namespaces.h" 218c2ecf20Sopenharmony_ci#include "util/build-id.h" 228c2ecf20Sopenharmony_ci#include "util/strlist.h" 238c2ecf20Sopenharmony_ci#include "util/strfilter.h" 248c2ecf20Sopenharmony_ci#include "util/symbol_conf.h" 258c2ecf20Sopenharmony_ci#include "util/debug.h" 268c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h> 278c2ecf20Sopenharmony_ci#include "util/probe-finder.h" 288c2ecf20Sopenharmony_ci#include "util/probe-event.h" 298c2ecf20Sopenharmony_ci#include "util/probe-file.h" 308c2ecf20Sopenharmony_ci#include <linux/string.h> 318c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*" 348c2ecf20Sopenharmony_ci#define DEFAULT_FUNC_FILTER "!_*" 358c2ecf20Sopenharmony_ci#define DEFAULT_LIST_FILTER "*" 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* Session management structure */ 388c2ecf20Sopenharmony_cistatic struct { 398c2ecf20Sopenharmony_ci int command; /* Command short_name */ 408c2ecf20Sopenharmony_ci bool list_events; 418c2ecf20Sopenharmony_ci bool uprobes; 428c2ecf20Sopenharmony_ci bool quiet; 438c2ecf20Sopenharmony_ci bool target_used; 448c2ecf20Sopenharmony_ci int nevents; 458c2ecf20Sopenharmony_ci struct perf_probe_event events[MAX_PROBES]; 468c2ecf20Sopenharmony_ci struct line_range line_range; 478c2ecf20Sopenharmony_ci char *target; 488c2ecf20Sopenharmony_ci struct strfilter *filter; 498c2ecf20Sopenharmony_ci struct nsinfo *nsi; 508c2ecf20Sopenharmony_ci} params; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* Parse an event definition. Note that any error must die. */ 538c2ecf20Sopenharmony_cistatic int parse_probe_event(const char *str) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct perf_probe_event *pev = ¶ms.events[params.nevents]; 568c2ecf20Sopenharmony_ci int ret; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci pr_debug("probe-definition(%d): %s\n", params.nevents, str); 598c2ecf20Sopenharmony_ci if (++params.nevents == MAX_PROBES) { 608c2ecf20Sopenharmony_ci pr_err("Too many probes (> %d) were specified.", MAX_PROBES); 618c2ecf20Sopenharmony_ci return -1; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci pev->uprobes = params.uprobes; 658c2ecf20Sopenharmony_ci if (params.target) { 668c2ecf20Sopenharmony_ci pev->target = strdup(params.target); 678c2ecf20Sopenharmony_ci if (!pev->target) 688c2ecf20Sopenharmony_ci return -ENOMEM; 698c2ecf20Sopenharmony_ci params.target_used = true; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci pev->nsi = nsinfo__get(params.nsi); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* Parse a perf-probe command into event */ 758c2ecf20Sopenharmony_ci ret = parse_perf_probe_command(str, pev); 768c2ecf20Sopenharmony_ci pr_debug("%d arguments\n", pev->nargs); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return ret; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic int params_add_filter(const char *str) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci const char *err = NULL; 848c2ecf20Sopenharmony_ci int ret = 0; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci pr_debug2("Add filter: %s\n", str); 878c2ecf20Sopenharmony_ci if (!params.filter) { 888c2ecf20Sopenharmony_ci params.filter = strfilter__new(str, &err); 898c2ecf20Sopenharmony_ci if (!params.filter) 908c2ecf20Sopenharmony_ci ret = err ? -EINVAL : -ENOMEM; 918c2ecf20Sopenharmony_ci } else 928c2ecf20Sopenharmony_ci ret = strfilter__or(params.filter, str, &err); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (ret == -EINVAL) { 958c2ecf20Sopenharmony_ci pr_err("Filter parse error at %td.\n", err - str + 1); 968c2ecf20Sopenharmony_ci pr_err("Source: \"%s\"\n", str); 978c2ecf20Sopenharmony_ci pr_err(" %*c\n", (int)(err - str + 1), '^'); 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci return ret; 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int set_target(const char *ptr) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci int found = 0; 1068c2ecf20Sopenharmony_ci const char *buf; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci /* 1098c2ecf20Sopenharmony_ci * The first argument after options can be an absolute path 1108c2ecf20Sopenharmony_ci * to an executable / library or kernel module. 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * TODO: Support relative path, and $PATH, $LD_LIBRARY_PATH, 1138c2ecf20Sopenharmony_ci * short module name. 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ci if (!params.target && ptr && *ptr == '/') { 1168c2ecf20Sopenharmony_ci params.target = strdup(ptr); 1178c2ecf20Sopenharmony_ci if (!params.target) 1188c2ecf20Sopenharmony_ci return -ENOMEM; 1198c2ecf20Sopenharmony_ci params.target_used = false; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci found = 1; 1228c2ecf20Sopenharmony_ci buf = ptr + (strlen(ptr) - 3); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci if (strcmp(buf, ".ko")) 1258c2ecf20Sopenharmony_ci params.uprobes = true; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci return found; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int parse_probe_event_argv(int argc, const char **argv) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci int i, len, ret, found_target; 1358c2ecf20Sopenharmony_ci char *buf; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci found_target = set_target(argv[0]); 1388c2ecf20Sopenharmony_ci if (found_target < 0) 1398c2ecf20Sopenharmony_ci return found_target; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (found_target && argc == 1) 1428c2ecf20Sopenharmony_ci return 0; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci /* Bind up rest arguments */ 1458c2ecf20Sopenharmony_ci len = 0; 1468c2ecf20Sopenharmony_ci for (i = 0; i < argc; i++) { 1478c2ecf20Sopenharmony_ci if (i == 0 && found_target) 1488c2ecf20Sopenharmony_ci continue; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci len += strlen(argv[i]) + 1; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci buf = zalloc(len + 1); 1538c2ecf20Sopenharmony_ci if (buf == NULL) 1548c2ecf20Sopenharmony_ci return -ENOMEM; 1558c2ecf20Sopenharmony_ci len = 0; 1568c2ecf20Sopenharmony_ci for (i = 0; i < argc; i++) { 1578c2ecf20Sopenharmony_ci if (i == 0 && found_target) 1588c2ecf20Sopenharmony_ci continue; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci len += sprintf(&buf[len], "%s ", argv[i]); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci ret = parse_probe_event(buf); 1638c2ecf20Sopenharmony_ci free(buf); 1648c2ecf20Sopenharmony_ci return ret; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic int opt_set_target(const struct option *opt, const char *str, 1688c2ecf20Sopenharmony_ci int unset __maybe_unused) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci int ret = -ENOENT; 1718c2ecf20Sopenharmony_ci char *tmp; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (str) { 1748c2ecf20Sopenharmony_ci if (!strcmp(opt->long_name, "exec")) 1758c2ecf20Sopenharmony_ci params.uprobes = true; 1768c2ecf20Sopenharmony_ci else if (!strcmp(opt->long_name, "module")) 1778c2ecf20Sopenharmony_ci params.uprobes = false; 1788c2ecf20Sopenharmony_ci else 1798c2ecf20Sopenharmony_ci return ret; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* Expand given path to absolute path, except for modulename */ 1828c2ecf20Sopenharmony_ci if (params.uprobes || strchr(str, '/')) { 1838c2ecf20Sopenharmony_ci tmp = nsinfo__realpath(str, params.nsi); 1848c2ecf20Sopenharmony_ci if (!tmp) { 1858c2ecf20Sopenharmony_ci pr_warning("Failed to get the absolute path of %s: %m\n", str); 1868c2ecf20Sopenharmony_ci return ret; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci } else { 1898c2ecf20Sopenharmony_ci tmp = strdup(str); 1908c2ecf20Sopenharmony_ci if (!tmp) 1918c2ecf20Sopenharmony_ci return -ENOMEM; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci free(params.target); 1948c2ecf20Sopenharmony_ci params.target = tmp; 1958c2ecf20Sopenharmony_ci params.target_used = false; 1968c2ecf20Sopenharmony_ci ret = 0; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return ret; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int opt_set_target_ns(const struct option *opt __maybe_unused, 2038c2ecf20Sopenharmony_ci const char *str, int unset __maybe_unused) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci int ret = -ENOENT; 2068c2ecf20Sopenharmony_ci pid_t ns_pid; 2078c2ecf20Sopenharmony_ci struct nsinfo *nsip; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (str) { 2108c2ecf20Sopenharmony_ci errno = 0; 2118c2ecf20Sopenharmony_ci ns_pid = (pid_t)strtol(str, NULL, 10); 2128c2ecf20Sopenharmony_ci if (errno != 0) { 2138c2ecf20Sopenharmony_ci ret = -errno; 2148c2ecf20Sopenharmony_ci pr_warning("Failed to parse %s as a pid: %s\n", str, 2158c2ecf20Sopenharmony_ci strerror(errno)); 2168c2ecf20Sopenharmony_ci return ret; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci nsip = nsinfo__new(ns_pid); 2198c2ecf20Sopenharmony_ci if (nsip && nsip->need_setns) 2208c2ecf20Sopenharmony_ci params.nsi = nsinfo__get(nsip); 2218c2ecf20Sopenharmony_ci nsinfo__put(nsip); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci ret = 0; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return ret; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/* Command option callbacks */ 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci#ifdef HAVE_DWARF_SUPPORT 2338c2ecf20Sopenharmony_cistatic int opt_show_lines(const struct option *opt, 2348c2ecf20Sopenharmony_ci const char *str, int unset __maybe_unused) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci int ret = 0; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (!str) 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (params.command == 'L') { 2428c2ecf20Sopenharmony_ci pr_warning("Warning: more than one --line options are" 2438c2ecf20Sopenharmony_ci " detected. Only the first one is valid.\n"); 2448c2ecf20Sopenharmony_ci return 0; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci params.command = opt->short_name; 2488c2ecf20Sopenharmony_ci ret = parse_line_range_desc(str, ¶ms.line_range); 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci return ret; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistatic int opt_show_vars(const struct option *opt, 2548c2ecf20Sopenharmony_ci const char *str, int unset __maybe_unused) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct perf_probe_event *pev = ¶ms.events[params.nevents]; 2578c2ecf20Sopenharmony_ci int ret; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (!str) 2608c2ecf20Sopenharmony_ci return 0; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci ret = parse_probe_event(str); 2638c2ecf20Sopenharmony_ci if (!ret && pev->nargs != 0) { 2648c2ecf20Sopenharmony_ci pr_err(" Error: '--vars' doesn't accept arguments.\n"); 2658c2ecf20Sopenharmony_ci return -EINVAL; 2668c2ecf20Sopenharmony_ci } 2678c2ecf20Sopenharmony_ci params.command = opt->short_name; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return ret; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci#else 2728c2ecf20Sopenharmony_ci# define opt_show_lines NULL 2738c2ecf20Sopenharmony_ci# define opt_show_vars NULL 2748c2ecf20Sopenharmony_ci#endif 2758c2ecf20Sopenharmony_cistatic int opt_add_probe_event(const struct option *opt, 2768c2ecf20Sopenharmony_ci const char *str, int unset __maybe_unused) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci if (str) { 2798c2ecf20Sopenharmony_ci params.command = opt->short_name; 2808c2ecf20Sopenharmony_ci return parse_probe_event(str); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci return 0; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic int opt_set_filter_with_command(const struct option *opt, 2878c2ecf20Sopenharmony_ci const char *str, int unset) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci if (!unset) 2908c2ecf20Sopenharmony_ci params.command = opt->short_name; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (str) 2938c2ecf20Sopenharmony_ci return params_add_filter(str); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci return 0; 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_cistatic int opt_set_filter(const struct option *opt __maybe_unused, 2998c2ecf20Sopenharmony_ci const char *str, int unset __maybe_unused) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci if (str) 3028c2ecf20Sopenharmony_ci return params_add_filter(str); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return 0; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int init_params(void) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci return line_range__init(¶ms.line_range); 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic void cleanup_params(void) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci int i; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci for (i = 0; i < params.nevents; i++) 3178c2ecf20Sopenharmony_ci clear_perf_probe_event(params.events + i); 3188c2ecf20Sopenharmony_ci line_range__clear(¶ms.line_range); 3198c2ecf20Sopenharmony_ci free(params.target); 3208c2ecf20Sopenharmony_ci strfilter__delete(params.filter); 3218c2ecf20Sopenharmony_ci nsinfo__put(params.nsi); 3228c2ecf20Sopenharmony_ci memset(¶ms, 0, sizeof(params)); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic void pr_err_with_code(const char *msg, int err) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci char sbuf[STRERR_BUFSIZE]; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci pr_err("%s", msg); 3308c2ecf20Sopenharmony_ci pr_debug(" Reason: %s (Code: %d)", 3318c2ecf20Sopenharmony_ci str_error_r(-err, sbuf, sizeof(sbuf)), err); 3328c2ecf20Sopenharmony_ci pr_err("\n"); 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic int perf_add_probe_events(struct perf_probe_event *pevs, int npevs) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci int ret; 3388c2ecf20Sopenharmony_ci int i, k; 3398c2ecf20Sopenharmony_ci const char *event = NULL, *group = NULL; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci ret = init_probe_symbol_maps(pevs->uprobes); 3428c2ecf20Sopenharmony_ci if (ret < 0) 3438c2ecf20Sopenharmony_ci return ret; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci ret = convert_perf_probe_events(pevs, npevs); 3468c2ecf20Sopenharmony_ci if (ret < 0) 3478c2ecf20Sopenharmony_ci goto out_cleanup; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (params.command == 'D') { /* it shows definition */ 3508c2ecf20Sopenharmony_ci ret = show_probe_trace_events(pevs, npevs); 3518c2ecf20Sopenharmony_ci goto out_cleanup; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci ret = apply_perf_probe_events(pevs, npevs); 3558c2ecf20Sopenharmony_ci if (ret < 0) 3568c2ecf20Sopenharmony_ci goto out_cleanup; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci for (i = k = 0; i < npevs; i++) 3598c2ecf20Sopenharmony_ci k += pevs[i].ntevs; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci pr_info("Added new event%s\n", (k > 1) ? "s:" : ":"); 3628c2ecf20Sopenharmony_ci for (i = 0; i < npevs; i++) { 3638c2ecf20Sopenharmony_ci struct perf_probe_event *pev = &pevs[i]; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci for (k = 0; k < pev->ntevs; k++) { 3668c2ecf20Sopenharmony_ci struct probe_trace_event *tev = &pev->tevs[k]; 3678c2ecf20Sopenharmony_ci /* Skipped events have no event name */ 3688c2ecf20Sopenharmony_ci if (!tev->event) 3698c2ecf20Sopenharmony_ci continue; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* We use tev's name for showing new events */ 3728c2ecf20Sopenharmony_ci show_perf_probe_event(tev->group, tev->event, pev, 3738c2ecf20Sopenharmony_ci tev->point.module, false); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Save the last valid name */ 3768c2ecf20Sopenharmony_ci event = tev->event; 3778c2ecf20Sopenharmony_ci group = tev->group; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Note that it is possible to skip all events because of blacklist */ 3828c2ecf20Sopenharmony_ci if (event) { 3838c2ecf20Sopenharmony_ci /* Show how to use the event. */ 3848c2ecf20Sopenharmony_ci pr_info("\nYou can now use it in all perf tools, such as:\n\n"); 3858c2ecf20Sopenharmony_ci pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", group, event); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ciout_cleanup: 3898c2ecf20Sopenharmony_ci cleanup_perf_probe_events(pevs, npevs); 3908c2ecf20Sopenharmony_ci exit_probe_symbol_maps(); 3918c2ecf20Sopenharmony_ci return ret; 3928c2ecf20Sopenharmony_ci} 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic int del_perf_probe_caches(struct strfilter *filter) 3958c2ecf20Sopenharmony_ci{ 3968c2ecf20Sopenharmony_ci struct probe_cache *cache; 3978c2ecf20Sopenharmony_ci struct strlist *bidlist; 3988c2ecf20Sopenharmony_ci struct str_node *nd; 3998c2ecf20Sopenharmony_ci int ret; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci bidlist = build_id_cache__list_all(false); 4028c2ecf20Sopenharmony_ci if (!bidlist) { 4038c2ecf20Sopenharmony_ci ret = -errno; 4048c2ecf20Sopenharmony_ci pr_debug("Failed to get buildids: %d\n", ret); 4058c2ecf20Sopenharmony_ci return ret ?: -ENOMEM; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci strlist__for_each_entry(nd, bidlist) { 4098c2ecf20Sopenharmony_ci cache = probe_cache__new(nd->s, NULL); 4108c2ecf20Sopenharmony_ci if (!cache) 4118c2ecf20Sopenharmony_ci continue; 4128c2ecf20Sopenharmony_ci if (probe_cache__filter_purge(cache, filter) < 0 || 4138c2ecf20Sopenharmony_ci probe_cache__commit(cache) < 0) 4148c2ecf20Sopenharmony_ci pr_warning("Failed to remove entries for %s\n", nd->s); 4158c2ecf20Sopenharmony_ci probe_cache__delete(cache); 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci return 0; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic int perf_del_probe_events(struct strfilter *filter) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci int ret, ret2, ufd = -1, kfd = -1; 4238c2ecf20Sopenharmony_ci char *str = strfilter__string(filter); 4248c2ecf20Sopenharmony_ci struct strlist *klist = NULL, *ulist = NULL; 4258c2ecf20Sopenharmony_ci struct str_node *ent; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (!str) 4288c2ecf20Sopenharmony_ci return -EINVAL; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci pr_debug("Delete filter: \'%s\'\n", str); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (probe_conf.cache) 4338c2ecf20Sopenharmony_ci return del_perf_probe_caches(filter); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* Get current event names */ 4368c2ecf20Sopenharmony_ci ret = probe_file__open_both(&kfd, &ufd, PF_FL_RW); 4378c2ecf20Sopenharmony_ci if (ret < 0) 4388c2ecf20Sopenharmony_ci goto out; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci klist = strlist__new(NULL, NULL); 4418c2ecf20Sopenharmony_ci ulist = strlist__new(NULL, NULL); 4428c2ecf20Sopenharmony_ci if (!klist || !ulist) { 4438c2ecf20Sopenharmony_ci ret = -ENOMEM; 4448c2ecf20Sopenharmony_ci goto out; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci ret = probe_file__get_events(kfd, filter, klist); 4488c2ecf20Sopenharmony_ci if (ret == 0) { 4498c2ecf20Sopenharmony_ci strlist__for_each_entry(ent, klist) 4508c2ecf20Sopenharmony_ci pr_info("Removed event: %s\n", ent->s); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci ret = probe_file__del_strlist(kfd, klist); 4538c2ecf20Sopenharmony_ci if (ret < 0) 4548c2ecf20Sopenharmony_ci goto error; 4558c2ecf20Sopenharmony_ci } else if (ret == -ENOMEM) 4568c2ecf20Sopenharmony_ci goto error; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci ret2 = probe_file__get_events(ufd, filter, ulist); 4598c2ecf20Sopenharmony_ci if (ret2 == 0) { 4608c2ecf20Sopenharmony_ci strlist__for_each_entry(ent, ulist) 4618c2ecf20Sopenharmony_ci pr_info("Removed event: %s\n", ent->s); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci ret2 = probe_file__del_strlist(ufd, ulist); 4648c2ecf20Sopenharmony_ci if (ret2 < 0) 4658c2ecf20Sopenharmony_ci goto error; 4668c2ecf20Sopenharmony_ci } else if (ret2 == -ENOMEM) 4678c2ecf20Sopenharmony_ci goto error; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (ret == -ENOENT && ret2 == -ENOENT) 4708c2ecf20Sopenharmony_ci pr_warning("\"%s\" does not hit any event.\n", str); 4718c2ecf20Sopenharmony_ci else 4728c2ecf20Sopenharmony_ci ret = 0; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cierror: 4758c2ecf20Sopenharmony_ci if (kfd >= 0) 4768c2ecf20Sopenharmony_ci close(kfd); 4778c2ecf20Sopenharmony_ci if (ufd >= 0) 4788c2ecf20Sopenharmony_ci close(ufd); 4798c2ecf20Sopenharmony_ciout: 4808c2ecf20Sopenharmony_ci strlist__delete(klist); 4818c2ecf20Sopenharmony_ci strlist__delete(ulist); 4828c2ecf20Sopenharmony_ci free(str); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci return ret; 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci#ifdef HAVE_DWARF_SUPPORT 4888c2ecf20Sopenharmony_ci#define PROBEDEF_STR \ 4898c2ecf20Sopenharmony_ci "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT [[NAME=]ARG ...]" 4908c2ecf20Sopenharmony_ci#else 4918c2ecf20Sopenharmony_ci#define PROBEDEF_STR "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]" 4928c2ecf20Sopenharmony_ci#endif 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic int 4968c2ecf20Sopenharmony_ci__cmd_probe(int argc, const char **argv) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci const char * const probe_usage[] = { 4998c2ecf20Sopenharmony_ci "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", 5008c2ecf20Sopenharmony_ci "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 5018c2ecf20Sopenharmony_ci "perf probe [<options>] --del '[GROUP:]EVENT' ...", 5028c2ecf20Sopenharmony_ci "perf probe --list [GROUP:]EVENT ...", 5038c2ecf20Sopenharmony_ci#ifdef HAVE_DWARF_SUPPORT 5048c2ecf20Sopenharmony_ci "perf probe [<options>] --line 'LINEDESC'", 5058c2ecf20Sopenharmony_ci "perf probe [<options>] --vars 'PROBEPOINT'", 5068c2ecf20Sopenharmony_ci#endif 5078c2ecf20Sopenharmony_ci "perf probe [<options>] --funcs", 5088c2ecf20Sopenharmony_ci NULL 5098c2ecf20Sopenharmony_ci }; 5108c2ecf20Sopenharmony_ci struct option options[] = { 5118c2ecf20Sopenharmony_ci OPT_INCR('v', "verbose", &verbose, 5128c2ecf20Sopenharmony_ci "be more verbose (show parsed arguments, etc)"), 5138c2ecf20Sopenharmony_ci OPT_BOOLEAN('q', "quiet", ¶ms.quiet, 5148c2ecf20Sopenharmony_ci "be quiet (do not show any messages)"), 5158c2ecf20Sopenharmony_ci OPT_CALLBACK_DEFAULT('l', "list", NULL, "[GROUP:]EVENT", 5168c2ecf20Sopenharmony_ci "list up probe events", 5178c2ecf20Sopenharmony_ci opt_set_filter_with_command, DEFAULT_LIST_FILTER), 5188c2ecf20Sopenharmony_ci OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", 5198c2ecf20Sopenharmony_ci opt_set_filter_with_command), 5208c2ecf20Sopenharmony_ci OPT_CALLBACK('a', "add", NULL, PROBEDEF_STR, 5218c2ecf20Sopenharmony_ci "probe point definition, where\n" 5228c2ecf20Sopenharmony_ci "\t\tGROUP:\tGroup name (optional)\n" 5238c2ecf20Sopenharmony_ci "\t\tEVENT:\tEvent name\n" 5248c2ecf20Sopenharmony_ci "\t\tFUNC:\tFunction name\n" 5258c2ecf20Sopenharmony_ci "\t\tOFF:\tOffset from function entry (in byte)\n" 5268c2ecf20Sopenharmony_ci "\t\t%return:\tPut the probe at function return\n" 5278c2ecf20Sopenharmony_ci#ifdef HAVE_DWARF_SUPPORT 5288c2ecf20Sopenharmony_ci "\t\tSRC:\tSource code path\n" 5298c2ecf20Sopenharmony_ci "\t\tRL:\tRelative line number from function entry.\n" 5308c2ecf20Sopenharmony_ci "\t\tAL:\tAbsolute line number in file.\n" 5318c2ecf20Sopenharmony_ci "\t\tPT:\tLazy expression of line code.\n" 5328c2ecf20Sopenharmony_ci "\t\tARG:\tProbe argument (local variable name or\n" 5338c2ecf20Sopenharmony_ci "\t\t\tkprobe-tracer argument format.)\n", 5348c2ecf20Sopenharmony_ci#else 5358c2ecf20Sopenharmony_ci "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n", 5368c2ecf20Sopenharmony_ci#endif 5378c2ecf20Sopenharmony_ci opt_add_probe_event), 5388c2ecf20Sopenharmony_ci OPT_CALLBACK('D', "definition", NULL, PROBEDEF_STR, 5398c2ecf20Sopenharmony_ci "Show trace event definition of given traceevent for k/uprobe_events.", 5408c2ecf20Sopenharmony_ci opt_add_probe_event), 5418c2ecf20Sopenharmony_ci OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events" 5428c2ecf20Sopenharmony_ci " with existing name"), 5438c2ecf20Sopenharmony_ci OPT_CALLBACK('L', "line", NULL, 5448c2ecf20Sopenharmony_ci "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", 5458c2ecf20Sopenharmony_ci "Show source code lines.", opt_show_lines), 5468c2ecf20Sopenharmony_ci OPT_CALLBACK('V', "vars", NULL, 5478c2ecf20Sopenharmony_ci "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT", 5488c2ecf20Sopenharmony_ci "Show accessible variables on PROBEDEF", opt_show_vars), 5498c2ecf20Sopenharmony_ci OPT_BOOLEAN('\0', "externs", &probe_conf.show_ext_vars, 5508c2ecf20Sopenharmony_ci "Show external variables too (with --vars only)"), 5518c2ecf20Sopenharmony_ci OPT_BOOLEAN('\0', "range", &probe_conf.show_location_range, 5528c2ecf20Sopenharmony_ci "Show variables location range in scope (with --vars only)"), 5538c2ecf20Sopenharmony_ci OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 5548c2ecf20Sopenharmony_ci "file", "vmlinux pathname"), 5558c2ecf20Sopenharmony_ci OPT_STRING('s', "source", &symbol_conf.source_prefix, 5568c2ecf20Sopenharmony_ci "directory", "path to kernel source"), 5578c2ecf20Sopenharmony_ci OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines, 5588c2ecf20Sopenharmony_ci "Don't search inlined functions"), 5598c2ecf20Sopenharmony_ci OPT__DRY_RUN(&probe_event_dry_run), 5608c2ecf20Sopenharmony_ci OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes, 5618c2ecf20Sopenharmony_ci "Set how many probe points can be found for a probe."), 5628c2ecf20Sopenharmony_ci OPT_CALLBACK_DEFAULT('F', "funcs", NULL, "[FILTER]", 5638c2ecf20Sopenharmony_ci "Show potential probe-able functions.", 5648c2ecf20Sopenharmony_ci opt_set_filter_with_command, DEFAULT_FUNC_FILTER), 5658c2ecf20Sopenharmony_ci OPT_CALLBACK('\0', "filter", NULL, 5668c2ecf20Sopenharmony_ci "[!]FILTER", "Set a filter (with --vars/funcs only)\n" 5678c2ecf20Sopenharmony_ci "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n" 5688c2ecf20Sopenharmony_ci "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)", 5698c2ecf20Sopenharmony_ci opt_set_filter), 5708c2ecf20Sopenharmony_ci OPT_CALLBACK('x', "exec", NULL, "executable|path", 5718c2ecf20Sopenharmony_ci "target executable name or path", opt_set_target), 5728c2ecf20Sopenharmony_ci OPT_CALLBACK('m', "module", NULL, "modname|path", 5738c2ecf20Sopenharmony_ci "target module name (for online) or path (for offline)", 5748c2ecf20Sopenharmony_ci opt_set_target), 5758c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, 5768c2ecf20Sopenharmony_ci "Enable symbol demangling"), 5778c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, 5788c2ecf20Sopenharmony_ci "Enable kernel symbol demangling"), 5798c2ecf20Sopenharmony_ci OPT_BOOLEAN(0, "cache", &probe_conf.cache, "Manipulate probe cache"), 5808c2ecf20Sopenharmony_ci OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", 5818c2ecf20Sopenharmony_ci "Look for files with symbols relative to this directory"), 5828c2ecf20Sopenharmony_ci OPT_CALLBACK(0, "target-ns", NULL, "pid", 5838c2ecf20Sopenharmony_ci "target pid for namespace contexts", opt_set_target_ns), 5848c2ecf20Sopenharmony_ci OPT_END() 5858c2ecf20Sopenharmony_ci }; 5868c2ecf20Sopenharmony_ci int ret; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci set_option_flag(options, 'a', "add", PARSE_OPT_EXCLUSIVE); 5898c2ecf20Sopenharmony_ci set_option_flag(options, 'd', "del", PARSE_OPT_EXCLUSIVE); 5908c2ecf20Sopenharmony_ci set_option_flag(options, 'D', "definition", PARSE_OPT_EXCLUSIVE); 5918c2ecf20Sopenharmony_ci set_option_flag(options, 'l', "list", PARSE_OPT_EXCLUSIVE); 5928c2ecf20Sopenharmony_ci#ifdef HAVE_DWARF_SUPPORT 5938c2ecf20Sopenharmony_ci set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE); 5948c2ecf20Sopenharmony_ci set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE); 5958c2ecf20Sopenharmony_ci#else 5968c2ecf20Sopenharmony_ci# define set_nobuild(s, l, c) set_option_nobuild(options, s, l, "NO_DWARF=1", c) 5978c2ecf20Sopenharmony_ci set_nobuild('L', "line", false); 5988c2ecf20Sopenharmony_ci set_nobuild('V', "vars", false); 5998c2ecf20Sopenharmony_ci set_nobuild('\0', "externs", false); 6008c2ecf20Sopenharmony_ci set_nobuild('\0', "range", false); 6018c2ecf20Sopenharmony_ci set_nobuild('k', "vmlinux", true); 6028c2ecf20Sopenharmony_ci set_nobuild('s', "source", true); 6038c2ecf20Sopenharmony_ci set_nobuild('\0', "no-inlines", true); 6048c2ecf20Sopenharmony_ci# undef set_nobuild 6058c2ecf20Sopenharmony_ci#endif 6068c2ecf20Sopenharmony_ci set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci argc = parse_options(argc, argv, options, probe_usage, 6098c2ecf20Sopenharmony_ci PARSE_OPT_STOP_AT_NON_OPTION); 6108c2ecf20Sopenharmony_ci if (argc > 0) { 6118c2ecf20Sopenharmony_ci if (strcmp(argv[0], "-") == 0) { 6128c2ecf20Sopenharmony_ci usage_with_options_msg(probe_usage, options, 6138c2ecf20Sopenharmony_ci "'-' is not supported.\n"); 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci if (params.command && params.command != 'a') { 6168c2ecf20Sopenharmony_ci usage_with_options_msg(probe_usage, options, 6178c2ecf20Sopenharmony_ci "another command except --add is set.\n"); 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci ret = parse_probe_event_argv(argc, argv); 6208c2ecf20Sopenharmony_ci if (ret < 0) { 6218c2ecf20Sopenharmony_ci pr_err_with_code(" Error: Command Parse Error.", ret); 6228c2ecf20Sopenharmony_ci return ret; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci params.command = 'a'; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (params.quiet) { 6288c2ecf20Sopenharmony_ci if (verbose != 0) { 6298c2ecf20Sopenharmony_ci pr_err(" Error: -v and -q are exclusive.\n"); 6308c2ecf20Sopenharmony_ci return -EINVAL; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci verbose = -1; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci if (probe_conf.max_probes == 0) 6368c2ecf20Sopenharmony_ci probe_conf.max_probes = MAX_PROBES; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* 6398c2ecf20Sopenharmony_ci * Only consider the user's kernel image path if given. 6408c2ecf20Sopenharmony_ci */ 6418c2ecf20Sopenharmony_ci symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci /* 6448c2ecf20Sopenharmony_ci * Except for --list, --del and --add, other command doesn't depend 6458c2ecf20Sopenharmony_ci * nor change running kernel. So if user gives offline vmlinux, 6468c2ecf20Sopenharmony_ci * ignore its buildid. 6478c2ecf20Sopenharmony_ci */ 6488c2ecf20Sopenharmony_ci if (!strchr("lda", params.command) && symbol_conf.vmlinux_name) 6498c2ecf20Sopenharmony_ci symbol_conf.ignore_vmlinux_buildid = true; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci switch (params.command) { 6528c2ecf20Sopenharmony_ci case 'l': 6538c2ecf20Sopenharmony_ci if (params.uprobes) { 6548c2ecf20Sopenharmony_ci pr_err(" Error: Don't use --list with --exec.\n"); 6558c2ecf20Sopenharmony_ci parse_options_usage(probe_usage, options, "l", true); 6568c2ecf20Sopenharmony_ci parse_options_usage(NULL, options, "x", true); 6578c2ecf20Sopenharmony_ci return -EINVAL; 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci ret = show_perf_probe_events(params.filter); 6608c2ecf20Sopenharmony_ci if (ret < 0) 6618c2ecf20Sopenharmony_ci pr_err_with_code(" Error: Failed to show event list.", ret); 6628c2ecf20Sopenharmony_ci return ret; 6638c2ecf20Sopenharmony_ci case 'F': 6648c2ecf20Sopenharmony_ci ret = show_available_funcs(params.target, params.nsi, 6658c2ecf20Sopenharmony_ci params.filter, params.uprobes); 6668c2ecf20Sopenharmony_ci if (ret < 0) 6678c2ecf20Sopenharmony_ci pr_err_with_code(" Error: Failed to show functions.", ret); 6688c2ecf20Sopenharmony_ci return ret; 6698c2ecf20Sopenharmony_ci#ifdef HAVE_DWARF_SUPPORT 6708c2ecf20Sopenharmony_ci case 'L': 6718c2ecf20Sopenharmony_ci ret = show_line_range(¶ms.line_range, params.target, 6728c2ecf20Sopenharmony_ci params.nsi, params.uprobes); 6738c2ecf20Sopenharmony_ci if (ret < 0) 6748c2ecf20Sopenharmony_ci pr_err_with_code(" Error: Failed to show lines.", ret); 6758c2ecf20Sopenharmony_ci return ret; 6768c2ecf20Sopenharmony_ci case 'V': 6778c2ecf20Sopenharmony_ci if (!params.filter) 6788c2ecf20Sopenharmony_ci params.filter = strfilter__new(DEFAULT_VAR_FILTER, 6798c2ecf20Sopenharmony_ci NULL); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci ret = show_available_vars(params.events, params.nevents, 6828c2ecf20Sopenharmony_ci params.filter); 6838c2ecf20Sopenharmony_ci if (ret < 0) 6848c2ecf20Sopenharmony_ci pr_err_with_code(" Error: Failed to show vars.", ret); 6858c2ecf20Sopenharmony_ci return ret; 6868c2ecf20Sopenharmony_ci#endif 6878c2ecf20Sopenharmony_ci case 'd': 6888c2ecf20Sopenharmony_ci ret = perf_del_probe_events(params.filter); 6898c2ecf20Sopenharmony_ci if (ret < 0) { 6908c2ecf20Sopenharmony_ci pr_err_with_code(" Error: Failed to delete events.", ret); 6918c2ecf20Sopenharmony_ci return ret; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci break; 6948c2ecf20Sopenharmony_ci case 'D': 6958c2ecf20Sopenharmony_ci case 'a': 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* Ensure the last given target is used */ 6988c2ecf20Sopenharmony_ci if (params.target && !params.target_used) { 6998c2ecf20Sopenharmony_ci pr_err(" Error: -x/-m must follow the probe definitions.\n"); 7008c2ecf20Sopenharmony_ci parse_options_usage(probe_usage, options, "m", true); 7018c2ecf20Sopenharmony_ci parse_options_usage(NULL, options, "x", true); 7028c2ecf20Sopenharmony_ci return -EINVAL; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci ret = perf_add_probe_events(params.events, params.nevents); 7068c2ecf20Sopenharmony_ci if (ret < 0) { 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* 7098c2ecf20Sopenharmony_ci * When perf_add_probe_events() fails it calls 7108c2ecf20Sopenharmony_ci * cleanup_perf_probe_events(pevs, npevs), i.e. 7118c2ecf20Sopenharmony_ci * cleanup_perf_probe_events(params.events, params.nevents), which 7128c2ecf20Sopenharmony_ci * will call clear_perf_probe_event(), so set nevents to zero 7138c2ecf20Sopenharmony_ci * to avoid cleanup_params() to call clear_perf_probe_event() again 7148c2ecf20Sopenharmony_ci * on the same pevs. 7158c2ecf20Sopenharmony_ci */ 7168c2ecf20Sopenharmony_ci params.nevents = 0; 7178c2ecf20Sopenharmony_ci pr_err_with_code(" Error: Failed to add events.", ret); 7188c2ecf20Sopenharmony_ci return ret; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci break; 7218c2ecf20Sopenharmony_ci default: 7228c2ecf20Sopenharmony_ci usage_with_options(probe_usage, options); 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci return 0; 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ciint cmd_probe(int argc, const char **argv) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci int ret; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci ret = init_params(); 7328c2ecf20Sopenharmony_ci if (!ret) { 7338c2ecf20Sopenharmony_ci ret = __cmd_probe(argc, argv); 7348c2ecf20Sopenharmony_ci cleanup_params(); 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci return ret < 0 ? ret : 0; 7388c2ecf20Sopenharmony_ci} 739