linux/tools/perf/builtin-probe.c
<<
>>
Prefs
   1/*
   2 * builtin-probe.c
   3 *
   4 * Builtin probe command: Set up probe events by C expression
   5 *
   6 * Written by Masami Hiramatsu <mhiramat@redhat.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21 *
  22 */
  23#include <sys/utsname.h>
  24#include <sys/types.h>
  25#include <sys/stat.h>
  26#include <fcntl.h>
  27#include <errno.h>
  28#include <stdio.h>
  29#include <unistd.h>
  30#include <stdlib.h>
  31#include <string.h>
  32
  33#include "perf.h"
  34#include "builtin.h"
  35#include "util/util.h"
  36#include "util/strlist.h"
  37#include "util/strfilter.h"
  38#include "util/symbol.h"
  39#include "util/debug.h"
  40#include <lk/debugfs.h>
  41#include "util/parse-options.h"
  42#include "util/probe-finder.h"
  43#include "util/probe-event.h"
  44
  45#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
  46#define DEFAULT_FUNC_FILTER "!_*"
  47
  48/* Session management structure */
  49static struct {
  50        bool list_events;
  51        bool force_add;
  52        bool show_lines;
  53        bool show_vars;
  54        bool show_ext_vars;
  55        bool show_funcs;
  56        bool mod_events;
  57        bool uprobes;
  58        int nevents;
  59        struct perf_probe_event events[MAX_PROBES];
  60        struct strlist *dellist;
  61        struct line_range line_range;
  62        const char *target;
  63        int max_probe_points;
  64        struct strfilter *filter;
  65} params;
  66
  67/* Parse an event definition. Note that any error must die. */
  68static int parse_probe_event(const char *str)
  69{
  70        struct perf_probe_event *pev = &params.events[params.nevents];
  71        int ret;
  72
  73        pr_debug("probe-definition(%d): %s\n", params.nevents, str);
  74        if (++params.nevents == MAX_PROBES) {
  75                pr_err("Too many probes (> %d) were specified.", MAX_PROBES);
  76                return -1;
  77        }
  78
  79        pev->uprobes = params.uprobes;
  80
  81        /* Parse a perf-probe command into event */
  82        ret = parse_perf_probe_command(str, pev);
  83        pr_debug("%d arguments\n", pev->nargs);
  84
  85        return ret;
  86}
  87
  88static int set_target(const char *ptr)
  89{
  90        int found = 0;
  91        const char *buf;
  92
  93        /*
  94         * The first argument after options can be an absolute path
  95         * to an executable / library or kernel module.
  96         *
  97         * TODO: Support relative path, and $PATH, $LD_LIBRARY_PATH,
  98         * short module name.
  99         */
 100        if (!params.target && ptr && *ptr == '/') {
 101                params.target = ptr;
 102                found = 1;
 103                buf = ptr + (strlen(ptr) - 3);
 104
 105                if (strcmp(buf, ".ko"))
 106                        params.uprobes = true;
 107
 108        }
 109
 110        return found;
 111}
 112
 113static int parse_probe_event_argv(int argc, const char **argv)
 114{
 115        int i, len, ret, found_target;
 116        char *buf;
 117
 118        found_target = set_target(argv[0]);
 119        if (found_target && argc == 1)
 120                return 0;
 121
 122        /* Bind up rest arguments */
 123        len = 0;
 124        for (i = 0; i < argc; i++) {
 125                if (i == 0 && found_target)
 126                        continue;
 127
 128                len += strlen(argv[i]) + 1;
 129        }
 130        buf = zalloc(len + 1);
 131        if (buf == NULL)
 132                return -ENOMEM;
 133        len = 0;
 134        for (i = 0; i < argc; i++) {
 135                if (i == 0 && found_target)
 136                        continue;
 137
 138                len += sprintf(&buf[len], "%s ", argv[i]);
 139        }
 140        params.mod_events = true;
 141        ret = parse_probe_event(buf);
 142        free(buf);
 143        return ret;
 144}
 145
 146static int opt_add_probe_event(const struct option *opt __maybe_unused,
 147                              const char *str, int unset __maybe_unused)
 148{
 149        if (str) {
 150                params.mod_events = true;
 151                return parse_probe_event(str);
 152        } else
 153                return 0;
 154}
 155
 156static int opt_del_probe_event(const struct option *opt __maybe_unused,
 157                               const char *str, int unset __maybe_unused)
 158{
 159        if (str) {
 160                params.mod_events = true;
 161                if (!params.dellist)
 162                        params.dellist = strlist__new(true, NULL);
 163                strlist__add(params.dellist, str);
 164        }
 165        return 0;
 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
 173        if  (str && !params.target) {
 174                if (!strcmp(opt->long_name, "exec"))
 175                        params.uprobes = true;
 176#ifdef DWARF_SUPPORT
 177                else if (!strcmp(opt->long_name, "module"))
 178                        params.uprobes = false;
 179#endif
 180                else
 181                        return ret;
 182
 183                params.target = str;
 184                ret = 0;
 185        }
 186
 187        return ret;
 188}
 189
 190#ifdef DWARF_SUPPORT
 191static int opt_show_lines(const struct option *opt __maybe_unused,
 192                          const char *str, int unset __maybe_unused)
 193{
 194        int ret = 0;
 195
 196        if (!str)
 197                return 0;
 198
 199        if (params.show_lines) {
 200                pr_warning("Warning: more than one --line options are"
 201                           " detected. Only the first one is valid.\n");
 202                return 0;
 203        }
 204
 205        params.show_lines = true;
 206        ret = parse_line_range_desc(str, &params.line_range);
 207        INIT_LIST_HEAD(&params.line_range.line_list);
 208
 209        return ret;
 210}
 211
 212static int opt_show_vars(const struct option *opt __maybe_unused,
 213                         const char *str, int unset __maybe_unused)
 214{
 215        struct perf_probe_event *pev = &params.events[params.nevents];
 216        int ret;
 217
 218        if (!str)
 219                return 0;
 220
 221        ret = parse_probe_event(str);
 222        if (!ret && pev->nargs != 0) {
 223                pr_err("  Error: '--vars' doesn't accept arguments.\n");
 224                return -EINVAL;
 225        }
 226        params.show_vars = true;
 227
 228        return ret;
 229}
 230#endif
 231
 232static int opt_set_filter(const struct option *opt __maybe_unused,
 233                          const char *str, int unset __maybe_unused)
 234{
 235        const char *err;
 236
 237        if (str) {
 238                pr_debug2("Set filter: %s\n", str);
 239                if (params.filter)
 240                        strfilter__delete(params.filter);
 241                params.filter = strfilter__new(str, &err);
 242                if (!params.filter) {
 243                        pr_err("Filter parse error at %td.\n", err - str + 1);
 244                        pr_err("Source: \"%s\"\n", str);
 245                        pr_err("         %*c\n", (int)(err - str + 1), '^');
 246                        return -EINVAL;
 247                }
 248        }
 249
 250        return 0;
 251}
 252
 253int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 254{
 255        const char * const probe_usage[] = {
 256                "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
 257                "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
 258                "perf probe [<options>] --del '[GROUP:]EVENT' ...",
 259                "perf probe --list",
 260#ifdef DWARF_SUPPORT
 261                "perf probe [<options>] --line 'LINEDESC'",
 262                "perf probe [<options>] --vars 'PROBEPOINT'",
 263#endif
 264                NULL
 265};
 266        const struct option options[] = {
 267        OPT_INCR('v', "verbose", &verbose,
 268                    "be more verbose (show parsed arguments, etc)"),
 269        OPT_BOOLEAN('l', "list", &params.list_events,
 270                    "list up current probe events"),
 271        OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
 272                opt_del_probe_event),
 273        OPT_CALLBACK('a', "add", NULL,
 274#ifdef DWARF_SUPPORT
 275                "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
 276                " [[NAME=]ARG ...]",
 277#else
 278                "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]",
 279#endif
 280                "probe point definition, where\n"
 281                "\t\tGROUP:\tGroup name (optional)\n"
 282                "\t\tEVENT:\tEvent name\n"
 283                "\t\tFUNC:\tFunction name\n"
 284                "\t\tOFF:\tOffset from function entry (in byte)\n"
 285                "\t\t%return:\tPut the probe at function return\n"
 286#ifdef DWARF_SUPPORT
 287                "\t\tSRC:\tSource code path\n"
 288                "\t\tRL:\tRelative line number from function entry.\n"
 289                "\t\tAL:\tAbsolute line number in file.\n"
 290                "\t\tPT:\tLazy expression of line code.\n"
 291                "\t\tARG:\tProbe argument (local variable name or\n"
 292                "\t\t\tkprobe-tracer argument format.)\n",
 293#else
 294                "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n",
 295#endif
 296                opt_add_probe_event),
 297        OPT_BOOLEAN('f', "force", &params.force_add, "forcibly add events"
 298                    " with existing name"),
 299#ifdef DWARF_SUPPORT
 300        OPT_CALLBACK('L', "line", NULL,
 301                     "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
 302                     "Show source code lines.", opt_show_lines),
 303        OPT_CALLBACK('V', "vars", NULL,
 304                     "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",
 305                     "Show accessible variables on PROBEDEF", opt_show_vars),
 306        OPT_BOOLEAN('\0', "externs", &params.show_ext_vars,
 307                    "Show external variables too (with --vars only)"),
 308        OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
 309                   "file", "vmlinux pathname"),
 310        OPT_STRING('s', "source", &symbol_conf.source_prefix,
 311                   "directory", "path to kernel source"),
 312        OPT_CALLBACK('m', "module", NULL, "modname|path",
 313                "target module name (for online) or path (for offline)",
 314                opt_set_target),
 315#endif
 316        OPT__DRY_RUN(&probe_event_dry_run),
 317        OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
 318                 "Set how many probe points can be found for a probe."),
 319        OPT_BOOLEAN('F', "funcs", &params.show_funcs,
 320                    "Show potential probe-able functions."),
 321        OPT_CALLBACK('\0', "filter", NULL,
 322                     "[!]FILTER", "Set a filter (with --vars/funcs only)\n"
 323                     "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
 324                     "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
 325                     opt_set_filter),
 326        OPT_CALLBACK('x', "exec", NULL, "executable|path",
 327                        "target executable name or path", opt_set_target),
 328        OPT_END()
 329        };
 330        int ret;
 331
 332        argc = parse_options(argc, argv, options, probe_usage,
 333                             PARSE_OPT_STOP_AT_NON_OPTION);
 334        if (argc > 0) {
 335                if (strcmp(argv[0], "-") == 0) {
 336                        pr_warning("  Error: '-' is not supported.\n");
 337                        usage_with_options(probe_usage, options);
 338                }
 339                ret = parse_probe_event_argv(argc, argv);
 340                if (ret < 0) {
 341                        pr_err("  Error: Parse Error.  (%d)\n", ret);
 342                        return ret;
 343                }
 344        }
 345
 346        if (params.max_probe_points == 0)
 347                params.max_probe_points = MAX_PROBES;
 348
 349        if ((!params.nevents && !params.dellist && !params.list_events &&
 350             !params.show_lines && !params.show_funcs))
 351                usage_with_options(probe_usage, options);
 352
 353        /*
 354         * Only consider the user's kernel image path if given.
 355         */
 356        symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
 357
 358        if (params.list_events) {
 359                if (params.mod_events) {
 360                        pr_err("  Error: Don't use --list with --add/--del.\n");
 361                        usage_with_options(probe_usage, options);
 362                }
 363                if (params.show_lines) {
 364                        pr_err("  Error: Don't use --list with --line.\n");
 365                        usage_with_options(probe_usage, options);
 366                }
 367                if (params.show_vars) {
 368                        pr_err(" Error: Don't use --list with --vars.\n");
 369                        usage_with_options(probe_usage, options);
 370                }
 371                if (params.show_funcs) {
 372                        pr_err("  Error: Don't use --list with --funcs.\n");
 373                        usage_with_options(probe_usage, options);
 374                }
 375                if (params.uprobes) {
 376                        pr_warning("  Error: Don't use --list with --exec.\n");
 377                        usage_with_options(probe_usage, options);
 378                }
 379                ret = show_perf_probe_events();
 380                if (ret < 0)
 381                        pr_err("  Error: Failed to show event list. (%d)\n",
 382                               ret);
 383                return ret;
 384        }
 385        if (params.show_funcs) {
 386                if (params.nevents != 0 || params.dellist) {
 387                        pr_err("  Error: Don't use --funcs with"
 388                               " --add/--del.\n");
 389                        usage_with_options(probe_usage, options);
 390                }
 391                if (params.show_lines) {
 392                        pr_err("  Error: Don't use --funcs with --line.\n");
 393                        usage_with_options(probe_usage, options);
 394                }
 395                if (params.show_vars) {
 396                        pr_err("  Error: Don't use --funcs with --vars.\n");
 397                        usage_with_options(probe_usage, options);
 398                }
 399                if (!params.filter)
 400                        params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
 401                                                       NULL);
 402                ret = show_available_funcs(params.target, params.filter,
 403                                        params.uprobes);
 404                strfilter__delete(params.filter);
 405                if (ret < 0)
 406                        pr_err("  Error: Failed to show functions."
 407                               " (%d)\n", ret);
 408                return ret;
 409        }
 410
 411#ifdef DWARF_SUPPORT
 412        if (params.show_lines && !params.uprobes) {
 413                if (params.mod_events) {
 414                        pr_err("  Error: Don't use --line with"
 415                               " --add/--del.\n");
 416                        usage_with_options(probe_usage, options);
 417                }
 418                if (params.show_vars) {
 419                        pr_err(" Error: Don't use --line with --vars.\n");
 420                        usage_with_options(probe_usage, options);
 421                }
 422
 423                ret = show_line_range(&params.line_range, params.target);
 424                if (ret < 0)
 425                        pr_err("  Error: Failed to show lines. (%d)\n", ret);
 426                return ret;
 427        }
 428        if (params.show_vars) {
 429                if (params.mod_events) {
 430                        pr_err("  Error: Don't use --vars with"
 431                               " --add/--del.\n");
 432                        usage_with_options(probe_usage, options);
 433                }
 434                if (!params.filter)
 435                        params.filter = strfilter__new(DEFAULT_VAR_FILTER,
 436                                                       NULL);
 437
 438                ret = show_available_vars(params.events, params.nevents,
 439                                          params.max_probe_points,
 440                                          params.target,
 441                                          params.filter,
 442                                          params.show_ext_vars);
 443                strfilter__delete(params.filter);
 444                if (ret < 0)
 445                        pr_err("  Error: Failed to show vars. (%d)\n", ret);
 446                return ret;
 447        }
 448#endif
 449
 450        if (params.dellist) {
 451                ret = del_perf_probe_events(params.dellist);
 452                strlist__delete(params.dellist);
 453                if (ret < 0) {
 454                        pr_err("  Error: Failed to delete events. (%d)\n", ret);
 455                        return ret;
 456                }
 457        }
 458
 459        if (params.nevents) {
 460                ret = add_perf_probe_events(params.events, params.nevents,
 461                                            params.max_probe_points,
 462                                            params.target,
 463                                            params.force_add);
 464                if (ret < 0) {
 465                        pr_err("  Error: Failed to add events. (%d)\n", ret);
 466                        return ret;
 467                }
 468        }
 469        return 0;
 470}
 471
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.