cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

builtin-probe.c (19433B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * builtin-probe.c
      4 *
      5 * Builtin probe command: Set up probe events by C expression
      6 *
      7 * Written by Masami Hiramatsu <mhiramat@redhat.com>
      8 */
      9#include <sys/utsname.h>
     10#include <sys/types.h>
     11#include <sys/stat.h>
     12#include <fcntl.h>
     13#include <errno.h>
     14#include <stdio.h>
     15#include <unistd.h>
     16#include <stdlib.h>
     17#include <string.h>
     18
     19#include "builtin.h"
     20#include "namespaces.h"
     21#include "util/build-id.h"
     22#include "util/strlist.h"
     23#include "util/strfilter.h"
     24#include "util/symbol.h"
     25#include "util/symbol_conf.h"
     26#include "util/debug.h"
     27#include <subcmd/parse-options.h>
     28#include "util/probe-finder.h"
     29#include "util/probe-event.h"
     30#include "util/probe-file.h"
     31#include <linux/string.h>
     32#include <linux/zalloc.h>
     33
     34#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
     35#define DEFAULT_FUNC_FILTER "!_* & !*@plt"
     36#define DEFAULT_LIST_FILTER "*"
     37
     38/* Session management structure */
     39static struct {
     40	int command;	/* Command short_name */
     41	bool list_events;
     42	bool uprobes;
     43	bool quiet;
     44	bool target_used;
     45	int nevents;
     46	struct perf_probe_event events[MAX_PROBES];
     47	struct line_range line_range;
     48	char *target;
     49	struct strfilter *filter;
     50	struct nsinfo *nsi;
     51} params;
     52
     53/* Parse an event definition. Note that any error must die. */
     54static int parse_probe_event(const char *str)
     55{
     56	struct perf_probe_event *pev = &params.events[params.nevents];
     57	int ret;
     58
     59	pr_debug("probe-definition(%d): %s\n", params.nevents, str);
     60	if (++params.nevents == MAX_PROBES) {
     61		pr_err("Too many probes (> %d) were specified.", MAX_PROBES);
     62		return -1;
     63	}
     64
     65	pev->uprobes = params.uprobes;
     66	if (params.target) {
     67		pev->target = strdup(params.target);
     68		if (!pev->target)
     69			return -ENOMEM;
     70		params.target_used = true;
     71	}
     72
     73	pev->nsi = nsinfo__get(params.nsi);
     74
     75	/* Parse a perf-probe command into event */
     76	ret = parse_perf_probe_command(str, pev);
     77	pr_debug("%d arguments\n", pev->nargs);
     78
     79	return ret;
     80}
     81
     82static int params_add_filter(const char *str)
     83{
     84	const char *err = NULL;
     85	int ret = 0;
     86
     87	pr_debug2("Add filter: %s\n", str);
     88	if (!params.filter) {
     89		params.filter = strfilter__new(str, &err);
     90		if (!params.filter)
     91			ret = err ? -EINVAL : -ENOMEM;
     92	} else
     93		ret = strfilter__or(params.filter, str, &err);
     94
     95	if (ret == -EINVAL) {
     96		pr_err("Filter parse error at %td.\n", err - str + 1);
     97		pr_err("Source: \"%s\"\n", str);
     98		pr_err("         %*c\n", (int)(err - str + 1), '^');
     99	}
    100
    101	return ret;
    102}
    103
    104static int set_target(const char *ptr)
    105{
    106	int found = 0;
    107	const char *buf;
    108
    109	/*
    110	 * The first argument after options can be an absolute path
    111	 * to an executable / library or kernel module.
    112	 *
    113	 * TODO: Support relative path, and $PATH, $LD_LIBRARY_PATH,
    114	 * short module name.
    115	 */
    116	if (!params.target && ptr && *ptr == '/') {
    117		params.target = strdup(ptr);
    118		if (!params.target)
    119			return -ENOMEM;
    120		params.target_used = false;
    121
    122		found = 1;
    123		buf = ptr + (strlen(ptr) - 3);
    124
    125		if (strcmp(buf, ".ko"))
    126			params.uprobes = true;
    127
    128	}
    129
    130	return found;
    131}
    132
    133static int parse_probe_event_argv(int argc, const char **argv)
    134{
    135	int i, len, ret, found_target;
    136	char *buf;
    137
    138	found_target = set_target(argv[0]);
    139	if (found_target < 0)
    140		return found_target;
    141
    142	if (found_target && argc == 1)
    143		return 0;
    144
    145	/* Bind up rest arguments */
    146	len = 0;
    147	for (i = 0; i < argc; i++) {
    148		if (i == 0 && found_target)
    149			continue;
    150
    151		len += strlen(argv[i]) + 1;
    152	}
    153	buf = zalloc(len + 1);
    154	if (buf == NULL)
    155		return -ENOMEM;
    156	len = 0;
    157	for (i = 0; i < argc; i++) {
    158		if (i == 0 && found_target)
    159			continue;
    160
    161		len += sprintf(&buf[len], "%s ", argv[i]);
    162	}
    163	ret = parse_probe_event(buf);
    164	free(buf);
    165	return ret;
    166}
    167
    168static int opt_set_target(const struct option *opt, const char *str,
    169			int unset __maybe_unused)
    170{
    171	int ret = -ENOENT;
    172	char *tmp;
    173
    174	if  (str) {
    175		if (!strcmp(opt->long_name, "exec"))
    176			params.uprobes = true;
    177		else if (!strcmp(opt->long_name, "module"))
    178			params.uprobes = false;
    179		else
    180			return ret;
    181
    182		/* Expand given path to absolute path, except for modulename */
    183		if (params.uprobes || strchr(str, '/')) {
    184			tmp = nsinfo__realpath(str, params.nsi);
    185			if (!tmp) {
    186				pr_warning("Failed to get the absolute path of %s: %m\n", str);
    187				return ret;
    188			}
    189		} else {
    190			tmp = strdup(str);
    191			if (!tmp)
    192				return -ENOMEM;
    193		}
    194		free(params.target);
    195		params.target = tmp;
    196		params.target_used = false;
    197		ret = 0;
    198	}
    199
    200	return ret;
    201}
    202
    203static int opt_set_target_ns(const struct option *opt __maybe_unused,
    204			     const char *str, int unset __maybe_unused)
    205{
    206	int ret = -ENOENT;
    207	pid_t ns_pid;
    208	struct nsinfo *nsip;
    209
    210	if (str) {
    211		errno = 0;
    212		ns_pid = (pid_t)strtol(str, NULL, 10);
    213		if (errno != 0) {
    214			ret = -errno;
    215			pr_warning("Failed to parse %s as a pid: %s\n", str,
    216				   strerror(errno));
    217			return ret;
    218		}
    219		nsip = nsinfo__new(ns_pid);
    220		if (nsip && nsinfo__need_setns(nsip))
    221			params.nsi = nsinfo__get(nsip);
    222		nsinfo__put(nsip);
    223
    224		ret = 0;
    225	}
    226
    227	return ret;
    228}
    229
    230
    231/* Command option callbacks */
    232
    233#ifdef HAVE_DWARF_SUPPORT
    234static int opt_show_lines(const struct option *opt,
    235			  const char *str, int unset __maybe_unused)
    236{
    237	int ret = 0;
    238
    239	if (!str)
    240		return 0;
    241
    242	if (params.command == 'L') {
    243		pr_warning("Warning: more than one --line options are"
    244			   " detected. Only the first one is valid.\n");
    245		return 0;
    246	}
    247
    248	params.command = opt->short_name;
    249	ret = parse_line_range_desc(str, &params.line_range);
    250
    251	return ret;
    252}
    253
    254static int opt_show_vars(const struct option *opt,
    255			 const char *str, int unset __maybe_unused)
    256{
    257	struct perf_probe_event *pev = &params.events[params.nevents];
    258	int ret;
    259
    260	if (!str)
    261		return 0;
    262
    263	ret = parse_probe_event(str);
    264	if (!ret && pev->nargs != 0) {
    265		pr_err("  Error: '--vars' doesn't accept arguments.\n");
    266		return -EINVAL;
    267	}
    268	params.command = opt->short_name;
    269
    270	return ret;
    271}
    272#else
    273# define opt_show_lines NULL
    274# define opt_show_vars NULL
    275#endif
    276static int opt_add_probe_event(const struct option *opt,
    277			      const char *str, int unset __maybe_unused)
    278{
    279	if (str) {
    280		params.command = opt->short_name;
    281		return parse_probe_event(str);
    282	}
    283
    284	return 0;
    285}
    286
    287static int opt_set_filter_with_command(const struct option *opt,
    288				       const char *str, int unset)
    289{
    290	if (!unset)
    291		params.command = opt->short_name;
    292
    293	if (str)
    294		return params_add_filter(str);
    295
    296	return 0;
    297}
    298
    299static int opt_set_filter(const struct option *opt __maybe_unused,
    300			  const char *str, int unset __maybe_unused)
    301{
    302	if (str)
    303		return params_add_filter(str);
    304
    305	return 0;
    306}
    307
    308static int init_params(void)
    309{
    310	return line_range__init(&params.line_range);
    311}
    312
    313static void cleanup_params(void)
    314{
    315	int i;
    316
    317	for (i = 0; i < params.nevents; i++)
    318		clear_perf_probe_event(params.events + i);
    319	line_range__clear(&params.line_range);
    320	free(params.target);
    321	strfilter__delete(params.filter);
    322	nsinfo__put(params.nsi);
    323	memset(&params, 0, sizeof(params));
    324}
    325
    326static void pr_err_with_code(const char *msg, int err)
    327{
    328	char sbuf[STRERR_BUFSIZE];
    329
    330	pr_err("%s", msg);
    331	pr_debug(" Reason: %s (Code: %d)",
    332		 str_error_r(-err, sbuf, sizeof(sbuf)), err);
    333	pr_err("\n");
    334}
    335
    336static int perf_add_probe_events(struct perf_probe_event *pevs, int npevs)
    337{
    338	int ret;
    339	int i, k;
    340	const char *event = NULL, *group = NULL;
    341
    342	ret = init_probe_symbol_maps(pevs->uprobes);
    343	if (ret < 0)
    344		return ret;
    345
    346	ret = convert_perf_probe_events(pevs, npevs);
    347	if (ret < 0)
    348		goto out_cleanup;
    349
    350	if (params.command == 'D') {	/* it shows definition */
    351		if (probe_conf.bootconfig)
    352			ret = show_bootconfig_events(pevs, npevs);
    353		else
    354			ret = show_probe_trace_events(pevs, npevs);
    355		goto out_cleanup;
    356	}
    357
    358	ret = apply_perf_probe_events(pevs, npevs);
    359	if (ret < 0)
    360		goto out_cleanup;
    361
    362	for (i = k = 0; i < npevs; i++)
    363		k += pevs[i].ntevs;
    364
    365	pr_info("Added new event%s\n", (k > 1) ? "s:" : ":");
    366	for (i = 0; i < npevs; i++) {
    367		struct perf_probe_event *pev = &pevs[i];
    368
    369		for (k = 0; k < pev->ntevs; k++) {
    370			struct probe_trace_event *tev = &pev->tevs[k];
    371			/* Skipped events have no event name */
    372			if (!tev->event)
    373				continue;
    374
    375			/* We use tev's name for showing new events */
    376			show_perf_probe_event(tev->group, tev->event, pev,
    377					      tev->point.module, false);
    378
    379			/* Save the last valid name */
    380			event = tev->event;
    381			group = tev->group;
    382		}
    383	}
    384
    385	/* Note that it is possible to skip all events because of blacklist */
    386	if (event) {
    387		/* Show how to use the event. */
    388		pr_info("\nYou can now use it in all perf tools, such as:\n\n");
    389		pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", group, event);
    390	}
    391
    392out_cleanup:
    393	cleanup_perf_probe_events(pevs, npevs);
    394	exit_probe_symbol_maps();
    395	return ret;
    396}
    397
    398static int del_perf_probe_caches(struct strfilter *filter)
    399{
    400	struct probe_cache *cache;
    401	struct strlist *bidlist;
    402	struct str_node *nd;
    403	int ret;
    404
    405	bidlist = build_id_cache__list_all(false);
    406	if (!bidlist) {
    407		ret = -errno;
    408		pr_debug("Failed to get buildids: %d\n", ret);
    409		return ret ?: -ENOMEM;
    410	}
    411
    412	strlist__for_each_entry(nd, bidlist) {
    413		cache = probe_cache__new(nd->s, NULL);
    414		if (!cache)
    415			continue;
    416		if (probe_cache__filter_purge(cache, filter) < 0 ||
    417		    probe_cache__commit(cache) < 0)
    418			pr_warning("Failed to remove entries for %s\n", nd->s);
    419		probe_cache__delete(cache);
    420	}
    421	return 0;
    422}
    423
    424static int perf_del_probe_events(struct strfilter *filter)
    425{
    426	int ret, ret2, ufd = -1, kfd = -1;
    427	char *str = strfilter__string(filter);
    428	struct strlist *klist = NULL, *ulist = NULL;
    429	struct str_node *ent;
    430
    431	if (!str)
    432		return -EINVAL;
    433
    434	pr_debug("Delete filter: \'%s\'\n", str);
    435
    436	if (probe_conf.cache)
    437		return del_perf_probe_caches(filter);
    438
    439	/* Get current event names */
    440	ret = probe_file__open_both(&kfd, &ufd, PF_FL_RW);
    441	if (ret < 0)
    442		goto out;
    443
    444	klist = strlist__new(NULL, NULL);
    445	ulist = strlist__new(NULL, NULL);
    446	if (!klist || !ulist) {
    447		ret = -ENOMEM;
    448		goto out;
    449	}
    450
    451	ret = probe_file__get_events(kfd, filter, klist);
    452	if (ret == 0) {
    453		strlist__for_each_entry(ent, klist)
    454			pr_info("Removed event: %s\n", ent->s);
    455
    456		ret = probe_file__del_strlist(kfd, klist);
    457		if (ret < 0)
    458			goto error;
    459	} else if (ret == -ENOMEM)
    460		goto error;
    461
    462	ret2 = probe_file__get_events(ufd, filter, ulist);
    463	if (ret2 == 0) {
    464		strlist__for_each_entry(ent, ulist)
    465			pr_info("Removed event: %s\n", ent->s);
    466
    467		ret2 = probe_file__del_strlist(ufd, ulist);
    468		if (ret2 < 0)
    469			goto error;
    470	} else if (ret2 == -ENOMEM)
    471		goto error;
    472
    473	if (ret == -ENOENT && ret2 == -ENOENT)
    474		pr_warning("\"%s\" does not hit any event.\n", str);
    475	else
    476		ret = 0;
    477
    478error:
    479	if (kfd >= 0)
    480		close(kfd);
    481	if (ufd >= 0)
    482		close(ufd);
    483out:
    484	strlist__delete(klist);
    485	strlist__delete(ulist);
    486	free(str);
    487
    488	return ret;
    489}
    490
    491#ifdef HAVE_DWARF_SUPPORT
    492#define PROBEDEF_STR	\
    493	"[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT [[NAME=]ARG ...]"
    494#else
    495#define PROBEDEF_STR	"[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]"
    496#endif
    497
    498
    499static int
    500__cmd_probe(int argc, const char **argv)
    501{
    502	const char * const probe_usage[] = {
    503		"perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
    504		"perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
    505		"perf probe [<options>] --del '[GROUP:]EVENT' ...",
    506		"perf probe --list [GROUP:]EVENT ...",
    507#ifdef HAVE_DWARF_SUPPORT
    508		"perf probe [<options>] --line 'LINEDESC'",
    509		"perf probe [<options>] --vars 'PROBEPOINT'",
    510#endif
    511		"perf probe [<options>] --funcs",
    512		NULL
    513	};
    514	struct option options[] = {
    515	OPT_INCR('v', "verbose", &verbose,
    516		    "be more verbose (show parsed arguments, etc)"),
    517	OPT_BOOLEAN('q', "quiet", &params.quiet,
    518		    "be quiet (do not show any messages)"),
    519	OPT_CALLBACK_DEFAULT('l', "list", NULL, "[GROUP:]EVENT",
    520			     "list up probe events",
    521			     opt_set_filter_with_command, DEFAULT_LIST_FILTER),
    522	OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
    523		     opt_set_filter_with_command),
    524	OPT_CALLBACK('a', "add", NULL, PROBEDEF_STR,
    525		"probe point definition, where\n"
    526		"\t\tGROUP:\tGroup name (optional)\n"
    527		"\t\tEVENT:\tEvent name\n"
    528		"\t\tFUNC:\tFunction name\n"
    529		"\t\tOFF:\tOffset from function entry (in byte)\n"
    530		"\t\t%return:\tPut the probe at function return\n"
    531#ifdef HAVE_DWARF_SUPPORT
    532		"\t\tSRC:\tSource code path\n"
    533		"\t\tRL:\tRelative line number from function entry.\n"
    534		"\t\tAL:\tAbsolute line number in file.\n"
    535		"\t\tPT:\tLazy expression of line code.\n"
    536		"\t\tARG:\tProbe argument (local variable name or\n"
    537		"\t\t\tkprobe-tracer argument format.)\n",
    538#else
    539		"\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n",
    540#endif
    541		opt_add_probe_event),
    542	OPT_CALLBACK('D', "definition", NULL, PROBEDEF_STR,
    543		"Show trace event definition of given traceevent for k/uprobe_events.",
    544		opt_add_probe_event),
    545	OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events"
    546		    " with existing name"),
    547	OPT_CALLBACK('L', "line", NULL,
    548		     "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
    549		     "Show source code lines.", opt_show_lines),
    550	OPT_CALLBACK('V', "vars", NULL,
    551		     "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",
    552		     "Show accessible variables on PROBEDEF", opt_show_vars),
    553	OPT_BOOLEAN('\0', "externs", &probe_conf.show_ext_vars,
    554		    "Show external variables too (with --vars only)"),
    555	OPT_BOOLEAN('\0', "range", &probe_conf.show_location_range,
    556		"Show variables location range in scope (with --vars only)"),
    557	OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
    558		   "file", "vmlinux pathname"),
    559	OPT_STRING('s', "source", &symbol_conf.source_prefix,
    560		   "directory", "path to kernel source"),
    561	OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines,
    562		"Don't search inlined functions"),
    563	OPT__DRY_RUN(&probe_event_dry_run),
    564	OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes,
    565		 "Set how many probe points can be found for a probe."),
    566	OPT_CALLBACK_DEFAULT('F', "funcs", NULL, "[FILTER]",
    567			     "Show potential probe-able functions.",
    568			     opt_set_filter_with_command, DEFAULT_FUNC_FILTER),
    569	OPT_CALLBACK('\0', "filter", NULL,
    570		     "[!]FILTER", "Set a filter (with --vars/funcs only)\n"
    571		     "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
    572		     "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
    573		     opt_set_filter),
    574	OPT_CALLBACK('x', "exec", NULL, "executable|path",
    575			"target executable name or path", opt_set_target),
    576	OPT_CALLBACK('m', "module", NULL, "modname|path",
    577		"target module name (for online) or path (for offline)",
    578		opt_set_target),
    579	OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
    580		    "Enable symbol demangling"),
    581	OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
    582		    "Enable kernel symbol demangling"),
    583	OPT_BOOLEAN(0, "cache", &probe_conf.cache, "Manipulate probe cache"),
    584	OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
    585		   "Look for files with symbols relative to this directory"),
    586	OPT_CALLBACK(0, "target-ns", NULL, "pid",
    587		     "target pid for namespace contexts", opt_set_target_ns),
    588	OPT_BOOLEAN(0, "bootconfig", &probe_conf.bootconfig,
    589		    "Output probe definition with bootconfig format"),
    590	OPT_END()
    591	};
    592	int ret;
    593
    594	set_option_flag(options, 'a', "add", PARSE_OPT_EXCLUSIVE);
    595	set_option_flag(options, 'd', "del", PARSE_OPT_EXCLUSIVE);
    596	set_option_flag(options, 'D', "definition", PARSE_OPT_EXCLUSIVE);
    597	set_option_flag(options, 'l', "list", PARSE_OPT_EXCLUSIVE);
    598#ifdef HAVE_DWARF_SUPPORT
    599	set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
    600	set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE);
    601#else
    602# define set_nobuild(s, l, c) set_option_nobuild(options, s, l, "NO_DWARF=1", c)
    603	set_nobuild('L', "line", false);
    604	set_nobuild('V', "vars", false);
    605	set_nobuild('\0', "externs", false);
    606	set_nobuild('\0', "range", false);
    607	set_nobuild('k', "vmlinux", true);
    608	set_nobuild('s', "source", true);
    609	set_nobuild('\0', "no-inlines", true);
    610# undef set_nobuild
    611#endif
    612	set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE);
    613
    614	argc = parse_options(argc, argv, options, probe_usage,
    615			     PARSE_OPT_STOP_AT_NON_OPTION);
    616	if (argc > 0) {
    617		if (strcmp(argv[0], "-") == 0) {
    618			usage_with_options_msg(probe_usage, options,
    619				"'-' is not supported.\n");
    620		}
    621		if (params.command && params.command != 'a') {
    622			usage_with_options_msg(probe_usage, options,
    623				"another command except --add is set.\n");
    624		}
    625		ret = parse_probe_event_argv(argc, argv);
    626		if (ret < 0) {
    627			pr_err_with_code("  Error: Command Parse Error.", ret);
    628			return ret;
    629		}
    630		params.command = 'a';
    631	}
    632
    633	ret = symbol__validate_sym_arguments();
    634	if (ret)
    635		return ret;
    636
    637	if (params.quiet) {
    638		if (verbose != 0) {
    639			pr_err("  Error: -v and -q are exclusive.\n");
    640			return -EINVAL;
    641		}
    642		verbose = -1;
    643	}
    644
    645	if (probe_conf.max_probes == 0)
    646		probe_conf.max_probes = MAX_PROBES;
    647
    648	/*
    649	 * Only consider the user's kernel image path if given.
    650	 */
    651	symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
    652
    653	/*
    654	 * Except for --list, --del and --add, other command doesn't depend
    655	 * nor change running kernel. So if user gives offline vmlinux,
    656	 * ignore its buildid.
    657	 */
    658	if (!strchr("lda", params.command) && symbol_conf.vmlinux_name)
    659		symbol_conf.ignore_vmlinux_buildid = true;
    660
    661	switch (params.command) {
    662	case 'l':
    663		if (params.uprobes) {
    664			pr_err("  Error: Don't use --list with --exec.\n");
    665			parse_options_usage(probe_usage, options, "l", true);
    666			parse_options_usage(NULL, options, "x", true);
    667			return -EINVAL;
    668		}
    669		ret = show_perf_probe_events(params.filter);
    670		if (ret < 0)
    671			pr_err_with_code("  Error: Failed to show event list.", ret);
    672		return ret;
    673	case 'F':
    674		ret = show_available_funcs(params.target, params.nsi,
    675					   params.filter, params.uprobes);
    676		if (ret < 0)
    677			pr_err_with_code("  Error: Failed to show functions.", ret);
    678		return ret;
    679#ifdef HAVE_DWARF_SUPPORT
    680	case 'L':
    681		ret = show_line_range(&params.line_range, params.target,
    682				      params.nsi, params.uprobes);
    683		if (ret < 0)
    684			pr_err_with_code("  Error: Failed to show lines.", ret);
    685		return ret;
    686	case 'V':
    687		if (!params.filter)
    688			params.filter = strfilter__new(DEFAULT_VAR_FILTER,
    689						       NULL);
    690
    691		ret = show_available_vars(params.events, params.nevents,
    692					  params.filter);
    693		if (ret < 0)
    694			pr_err_with_code("  Error: Failed to show vars.", ret);
    695		return ret;
    696#endif
    697	case 'd':
    698		ret = perf_del_probe_events(params.filter);
    699		if (ret < 0) {
    700			pr_err_with_code("  Error: Failed to delete events.", ret);
    701			return ret;
    702		}
    703		break;
    704	case 'D':
    705		if (probe_conf.bootconfig && params.uprobes) {
    706			pr_err("  Error: --bootconfig doesn't support uprobes.\n");
    707			return -EINVAL;
    708		}
    709		__fallthrough;
    710	case 'a':
    711
    712		/* Ensure the last given target is used */
    713		if (params.target && !params.target_used) {
    714			pr_err("  Error: -x/-m must follow the probe definitions.\n");
    715			parse_options_usage(probe_usage, options, "m", true);
    716			parse_options_usage(NULL, options, "x", true);
    717			return -EINVAL;
    718		}
    719
    720		ret = perf_add_probe_events(params.events, params.nevents);
    721		if (ret < 0) {
    722
    723			/*
    724			 * When perf_add_probe_events() fails it calls
    725			 * cleanup_perf_probe_events(pevs, npevs), i.e.
    726			 * cleanup_perf_probe_events(params.events, params.nevents), which
    727			 * will call clear_perf_probe_event(), so set nevents to zero
    728			 * to avoid cleanup_params() to call clear_perf_probe_event() again
    729			 * on the same pevs.
    730			 */
    731			params.nevents = 0;
    732			pr_err_with_code("  Error: Failed to add events.", ret);
    733			return ret;
    734		}
    735		break;
    736	default:
    737		usage_with_options(probe_usage, options);
    738	}
    739	return 0;
    740}
    741
    742int cmd_probe(int argc, const char **argv)
    743{
    744	int ret;
    745
    746	ret = init_params();
    747	if (!ret) {
    748		ret = __cmd_probe(argc, argv);
    749		cleanup_params();
    750	}
    751
    752	return ret < 0 ? ret : 0;
    753}