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 "util/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        int nevents;
  58        struct perf_probe_event events[MAX_PROBES];
  59        struct strlist *dellist;
  60        struct line_range line_range;
  61        const char *target_module;
  62        int max_probe_points;
  63        struct strfilter *filter;
  64} params;
  65
  66/* Parse an event definition. Note that any error must die. */
  67static int parse_probe_event(const char *str)
  68{
  69        struct perf_probe_event *pev = &params.events[params.nevents];
  70        int ret;
  71
  72        pr_debug("probe-definition(%d): %s\n", params.nevents, str);
  73        if (++params.nevents == MAX_PROBES) {
  74                pr_err("Too many probes (> %d) were specified.", MAX_PROBES);
  75                return -1;
  76        }
  77
  78        /* Parse a perf-probe command into event */
  79        ret = parse_perf_probe_command(str, pev);
  80        pr_debug("%d arguments\n", pev->nargs);
  81
  82        return ret;
  83}
  84
  85static int parse_probe_event_argv(int argc, const char **argv)
  86{
  87        int i, len, ret;
  88        char *buf;
  89
  90        /* Bind up rest arguments */
  91        len = 0;
  92        for (i = 0; i < argc; i++)
  93                len += strlen(argv[i]) + 1;
  94        buf = zalloc(len + 1);
  95        if (buf == NULL)
  96                return -ENOMEM;
  97        len = 0;
  98        for (i = 0; i < argc; i++)
  99                len += sprintf(&buf[len], "%s ", argv[i]);
 100        params.mod_events = true;
 101        ret = parse_probe_event(buf);
 102        free(buf);
 103        return ret;
 104}
 105
 106static int opt_add_probe_event(const struct option *opt __used,
 107                              const char *str, int unset __used)
 108{
 109        if (str) {
 110                params.mod_events = true;
 111                return parse_probe_event(str);
 112        } else
 113                return 0;
 114}
 115
 116static int opt_del_probe_event(const struct option *opt __used,
 117                               const char *str, int unset __used)
 118{
 119        if (str) {
 120                params.mod_events = true;
 121                if (!params.dellist)
 122                        params.dellist = strlist__new(true, NULL);
 123                strlist__add(params.dellist, str);
 124        }
 125        return 0;
 126}
 127
 128#ifdef DWARF_SUPPORT
 129static int opt_show_lines(const struct option *opt __used,
 130                          const char *str, int unset __used)
 131{
 132        int ret = 0;
 133
 134        if (!str)
 135                return 0;
 136
 137        if (params.show_lines) {
 138                pr_warning("Warning: more than one --line options are"
 139                           " detected. Only the first one is valid.\n");
 140                return 0;
 141        }
 142
 143        params.show_lines = true;
 144        ret = parse_line_range_desc(str, &params.line_range);
 145        INIT_LIST_HEAD(&params.line_range.line_list);
 146
 147        return ret;
 148}
 149
 150static int opt_show_vars(const struct option *opt __used,
 151                         const char *str, int unset __used)
 152{
 153        struct perf_probe_event *pev = &params.events[params.nevents];
 154        int ret;
 155
 156        if (!str)
 157                return 0;
 158
 159        ret = parse_probe_event(str);
 160        if (!ret && pev->nargs != 0) {
 161                pr_err("  Error: '--vars' doesn't accept arguments.\n");
 162                return -EINVAL;
 163        }
 164        params.show_vars = true;
 165
 166        return ret;
 167}
 168#endif
 169
 170static int opt_set_filter(const struct option *opt __used,
 171                          const char *str, int unset __used)
 172{
 173        const char *err;
 174
 175        if (str) {
 176                pr_debug2("Set filter: %s\n", str);
 177                if (params.filter)
 178                        strfilter__delete(params.filter);
 179                params.filter = strfilter__new(str, &err);
 180                if (!params.filter) {
 181                        pr_err("Filter parse error at %td.\n", err - str + 1);
 182                        pr_err("Source: \"%s\"\n", str);
 183                        pr_err("         %*c\n", (int)(err - str + 1), '^');
 184                        return -EINVAL;
 185                }
 186        }
 187
 188        return 0;
 189}
 190
 191static const char * const probe_usage[] = {
 192        "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
 193        "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
 194        "perf probe [<options>] --del '[GROUP:]EVENT' ...",
 195        "perf probe --list",
 196#ifdef DWARF_SUPPORT
 197        "perf probe [<options>] --line 'LINEDESC'",
 198        "perf probe [<options>] --vars 'PROBEPOINT'",
 199#endif
 200        NULL
 201};
 202
 203static const struct option options[] = {
 204        OPT_INCR('v', "verbose", &verbose,
 205                    "be more verbose (show parsed arguments, etc)"),
 206        OPT_BOOLEAN('l', "list", &params.list_events,
 207                    "list up current probe events"),
 208        OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
 209                opt_del_probe_event),
 210        OPT_CALLBACK('a', "add", NULL,
 211#ifdef DWARF_SUPPORT
 212                "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
 213                " [[NAME=]ARG ...]",
 214#else
 215                "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]",
 216#endif
 217                "probe point definition, where\n"
 218                "\t\tGROUP:\tGroup name (optional)\n"
 219                "\t\tEVENT:\tEvent name\n"
 220                "\t\tFUNC:\tFunction name\n"
 221                "\t\tOFF:\tOffset from function entry (in byte)\n"
 222                "\t\t%return:\tPut the probe at function return\n"
 223#ifdef DWARF_SUPPORT
 224                "\t\tSRC:\tSource code path\n"
 225                "\t\tRL:\tRelative line number from function entry.\n"
 226                "\t\tAL:\tAbsolute line number in file.\n"
 227                "\t\tPT:\tLazy expression of line code.\n"
 228                "\t\tARG:\tProbe argument (local variable name or\n"
 229                "\t\t\tkprobe-tracer argument format.)\n",
 230#else
 231                "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n",
 232#endif
 233                opt_add_probe_event),
 234        OPT_BOOLEAN('f', "force", &params.force_add, "forcibly add events"
 235                    " with existing name"),
 236#ifdef DWARF_SUPPORT
 237        OPT_CALLBACK('L', "line", NULL,
 238                     "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
 239                     "Show source code lines.", opt_show_lines),
 240        OPT_CALLBACK('V', "vars", NULL,
 241                     "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",
 242                     "Show accessible variables on PROBEDEF", opt_show_vars),
 243        OPT_BOOLEAN('\0', "externs", &params.show_ext_vars,
 244                    "Show external variables too (with --vars only)"),
 245        OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
 246                   "file", "vmlinux pathname"),
 247        OPT_STRING('s', "source", &symbol_conf.source_prefix,
 248                   "directory", "path to kernel source"),
 249        OPT_STRING('m', "module", &params.target_module,
 250                   "modname|path",
 251                   "target module name (for online) or path (for offline)"),
 252#endif
 253        OPT__DRY_RUN(&probe_event_dry_run),
 254        OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
 255                 "Set how many probe points can be found for a probe."),
 256        OPT_BOOLEAN('F', "funcs", &params.show_funcs,
 257                    "Show potential probe-able functions."),
 258        OPT_CALLBACK('\0', "filter", NULL,
 259                     "[!]FILTER", "Set a filter (with --vars/funcs only)\n"
 260                     "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
 261                     "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
 262                     opt_set_filter),
 263        OPT_END()
 264};
 265
 266int cmd_probe(int argc, const char **argv, const char *prefix __used)
 267{
 268        int ret;
 269
 270        argc = parse_options(argc, argv, options, probe_usage,
 271                             PARSE_OPT_STOP_AT_NON_OPTION);
 272        if (argc > 0) {
 273                if (strcmp(argv[0], "-") == 0) {
 274                        pr_warning("  Error: '-' is not supported.\n");
 275                        usage_with_options(probe_usage, options);
 276                }
 277                ret = parse_probe_event_argv(argc, argv);
 278                if (ret < 0) {
 279                        pr_err("  Error: Parse Error.  (%d)\n", ret);
 280                        return ret;
 281                }
 282        }
 283
 284        if (params.max_probe_points == 0)
 285                params.max_probe_points = MAX_PROBES;
 286
 287        if ((!params.nevents && !params.dellist && !params.list_events &&
 288             !params.show_lines && !params.show_funcs))
 289                usage_with_options(probe_usage, options);
 290
 291        /*
 292         * Only consider the user's kernel image path if given.
 293         */
 294        symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
 295
 296        if (params.list_events) {
 297                if (params.mod_events) {
 298                        pr_err("  Error: Don't use --list with --add/--del.\n");
 299                        usage_with_options(probe_usage, options);
 300                }
 301                if (params.show_lines) {
 302                        pr_err("  Error: Don't use --list with --line.\n");
 303                        usage_with_options(probe_usage, options);
 304                }
 305                if (params.show_vars) {
 306                        pr_err(" Error: Don't use --list with --vars.\n");
 307                        usage_with_options(probe_usage, options);
 308                }
 309                if (params.show_funcs) {
 310                        pr_err("  Error: Don't use --list with --funcs.\n");
 311                        usage_with_options(probe_usage, options);
 312                }
 313                ret = show_perf_probe_events();
 314                if (ret < 0)
 315                        pr_err("  Error: Failed to show event list. (%d)\n",
 316                               ret);
 317                return ret;
 318        }
 319        if (params.show_funcs) {
 320                if (params.nevents != 0 || params.dellist) {
 321                        pr_err("  Error: Don't use --funcs with"
 322                               " --add/--del.\n");
 323                        usage_with_options(probe_usage, options);
 324                }
 325                if (params.show_lines) {
 326                        pr_err("  Error: Don't use --funcs with --line.\n");
 327                        usage_with_options(probe_usage, options);
 328                }
 329                if (params.show_vars) {
 330                        pr_err("  Error: Don't use --funcs with --vars.\n");
 331                        usage_with_options(probe_usage, options);
 332                }
 333                if (!params.filter)
 334                        params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
 335                                                       NULL);
 336                ret = show_available_funcs(params.target_module,
 337                                           params.filter);
 338                strfilter__delete(params.filter);
 339                if (ret < 0)
 340                        pr_err("  Error: Failed to show functions."
 341                               " (%d)\n", ret);
 342                return ret;
 343        }
 344
 345#ifdef DWARF_SUPPORT
 346        if (params.show_lines) {
 347                if (params.mod_events) {
 348                        pr_err("  Error: Don't use --line with"
 349                               " --add/--del.\n");
 350                        usage_with_options(probe_usage, options);
 351                }
 352                if (params.show_vars) {
 353                        pr_err(" Error: Don't use --line with --vars.\n");
 354                        usage_with_options(probe_usage, options);
 355                }
 356
 357                ret = show_line_range(&params.line_range, params.target_module);
 358                if (ret < 0)
 359                        pr_err("  Error: Failed to show lines. (%d)\n", ret);
 360                return ret;
 361        }
 362        if (params.show_vars) {
 363                if (params.mod_events) {
 364                        pr_err("  Error: Don't use --vars with"
 365                               " --add/--del.\n");
 366                        usage_with_options(probe_usage, options);
 367                }
 368                if (!params.filter)
 369                        params.filter = strfilter__new(DEFAULT_VAR_FILTER,
 370                                                       NULL);
 371
 372                ret = show_available_vars(params.events, params.nevents,
 373                                          params.max_probe_points,
 374                                          params.target_module,
 375                                          params.filter,
 376                                          params.show_ext_vars);
 377                strfilter__delete(params.filter);
 378                if (ret < 0)
 379                        pr_err("  Error: Failed to show vars. (%d)\n", ret);
 380                return ret;
 381        }
 382#endif
 383
 384        if (params.dellist) {
 385                ret = del_perf_probe_events(params.dellist);
 386                strlist__delete(params.dellist);
 387                if (ret < 0) {
 388                        pr_err("  Error: Failed to delete events. (%d)\n", ret);
 389                        return ret;
 390                }
 391        }
 392
 393        if (params.nevents) {
 394                ret = add_perf_probe_events(params.events, params.nevents,
 395                                            params.max_probe_points,
 396                                            params.target_module,
 397                                            params.force_add);
 398                if (ret < 0) {
 399                        pr_err("  Error: Failed to add events. (%d)\n", ret);
 400                        return ret;
 401                }
 402        }
 403        return 0;
 404}
 405
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.