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 = ¶ms.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, ¶ms.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 = ¶ms.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(¶ms.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(¶ms.line_range); 320 free(params.target); 321 strfilter__delete(params.filter); 322 nsinfo__put(params.nsi); 323 memset(¶ms, 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", ¶ms.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(¶ms.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}