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        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 __used,
 147                              const char *str, int unset __used)
 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 __used,
 157                               const char *str, int unset __used)
 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 __used)
 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 __used,
 192                          const char *str, int unset __used)
 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 __used,
 213                         const char *str, int unset __used)
 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 __used,
 233                          const char *str, int unset __used)
 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
 253static const char * const probe_usage[] = {
 254        "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
 255        "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
 256        "perf probe [<options>] --del '[GROUP:]EVENT' ...",
 257        "perf probe --list",
 258#ifdef DWARF_SUPPORT
 259        "perf probe [<options>] --line 'LINEDESC'",
 260        "perf probe [<options>] --vars 'PROBEPOINT'",
 261#endif
 262        NULL
 263};
 264
 265static const struct option options[] = {
 266        OPT_INCR('v', "verbose", &verbose,
 267                    "be more verbose (show parsed arguments, etc)"),
 268        OPT_BOOLEAN('l', "list", &params.list_events,
 269                    "list up current probe events"),
 270        OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
 271                opt_del_probe_event),
 272        OPT_CALLBACK('a', "add", NULL,
 273#ifdef DWARF_SUPPORT
 274                "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
 275                " [[NAME=]ARG ...]",
 276#else
 277                "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]",
 278#endif
 279                "probe point definition, where\n"
 280                "\t\tGROUP:\tGroup name (optional)\n"
 281                "\t\tEVENT:\tEvent name\n"
 282                "\t\tFUNC:\tFunction name\n"
 283                "\t\tOFF:\tOffset from function entry (in byte)\n"
 284                "\t\t%return:\tPut the probe at function return\n"
 285#ifdef DWARF_SUPPORT
 286                "\t\tSRC:\tSource code path\n"
 287                "\t\tRL:\tRelative line number from function entry.\n"
 288                "\t\tAL:\tAbsolute line number in file.\n"
 289                "\t\tPT:\tLazy expression of line code.\n"
 290                "\t\tARG:\tProbe argument (local variable name or\n"
 291                "\t\t\tkprobe-tracer argument format.)\n",
 292#else
 293                "\t\tARG:\tProbe argument (kprobe-tracer argument format.)\n",
 294#endif
 295                opt_add_probe_event),
 296        OPT_BOOLEAN('f', "force", &params.force_add, "forcibly add events"
 297                    " with existing name"),
 298#ifdef DWARF_SUPPORT
 299        OPT_CALLBACK('L', "line", NULL,
 300                     "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
 301                     "Show source code lines.", opt_show_lines),
 302        OPT_CALLBACK('V', "vars", NULL,
 303                     "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",
 304                     "Show accessible variables on PROBEDEF", opt_show_vars),
 305        OPT_BOOLEAN('\0', "externs", &params.show_ext_vars,
 306                    "Show external variables too (with --vars only)"),
 307        OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
 308                   "file", "vmlinux pathname"),
 309        OPT_STRING('s', "source", &symbol_conf.source_prefix,
 310                   "directory", "path to kernel source"),
 311        OPT_CALLBACK('m', "module", NULL, "modname|path",
 312                "target module name (for online) or path (for offline)",
 313                opt_set_target),
 314#endif
 315        OPT__DRY_RUN(&probe_event_dry_run),
 316        OPT_INTEGER('\0', "max-probes", &params.max_probe_points,
 317                 "Set how many probe points can be found for a probe."),
 318        OPT_BOOLEAN('F', "funcs", &params.show_funcs,
 319                    "Show potential probe-able functions."),
 320        OPT_CALLBACK('\0', "filter", NULL,
 321                     "[!]FILTER", "Set a filter (with --vars/funcs only)\n"
 322                     "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n"
 323                     "\t\t\t \"" DEFAULT_FUNC_FILTER "\" for --funcs)",
 324                     opt_set_filter),
 325        OPT_CALLBACK('x', "exec", NULL, "executable|path",
 326                        "target executable name or path", opt_set_target),
 327        OPT_END()
 328};
 329
 330int cmd_probe(int argc, const char **argv, const char *prefix __used)
 331{
 332        int ret;
 333
 334        argc = parse_options(argc, argv, options, probe_usage,
 335                             PARSE_OPT_STOP_AT_NON_OPTION);
 336        if (argc > 0) {
 337                if (strcmp(argv[0], "-") == 0) {
 338                        pr_warning("  Error: '-' is not supported.\n");
 339                        usage_with_options(probe_usage, options);
 340                }
 341                ret = parse_probe_event_argv(argc, argv);
 342                if (ret < 0) {
 343                        pr_err("  Error: Parse Error.  (%d)\n", ret);
 344                        return ret;
 345                }
 346        }
 347
 348        if (params.max_probe_points == 0)
 349                params.max_probe_points = MAX_PROBES;
 350
 351        if ((!params.nevents && !params.dellist && !params.list_events &&
 352             !params.show_lines && !params.show_funcs))
 353                usage_with_options(probe_usage, options);
 354
 355        /*
 356         * Only consider the user's kernel image path if given.
 357         */
 358        symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
 359
 360        if (params.list_events) {
 361                if (params.mod_events) {
 362                        pr_err("  Error: Don't use --list with --add/--del.\n");
 363                        usage_with_options(probe_usage, options);
 364                }
 365                if (params.show_lines) {
 366                        pr_err("  Error: Don't use --list with --line.\n");
 367                        usage_with_options(probe_usage, options);
 368                }
 369                if (params.show_vars) {
 370                        pr_err(" Error: Don't use --list with --vars.\n");
 371                        usage_with_options(probe_usage, options);
 372                }
 373                if (params.show_funcs) {
 374                        pr_err("  Error: Don't use --list with --funcs.\n");
 375                        usage_with_options(probe_usage, options);
 376                }
 377                if (params.uprobes) {
 378                        pr_warning("  Error: Don't use --list with --exec.\n");
 379                        usage_with_options(probe_usage, options);
 380                }
 381                ret = show_perf_probe_events();
 382                if (ret < 0)
 383                        pr_err("  Error: Failed to show event list. (%d)\n",
 384                               ret);
 385                return ret;
 386        }
 387        if (params.show_funcs) {
 388                if (params.nevents != 0 || params.dellist) {
 389                        pr_err("  Error: Don't use --funcs with"
 390                               " --add/--del.\n");
 391                        usage_with_options(probe_usage, options);
 392                }
 393                if (params.show_lines) {
 394                        pr_err("  Error: Don't use --funcs with --line.\n");
 395                        usage_with_options(probe_usage, options);
 396                }
 397                if (params.show_vars) {
 398                        pr_err("  Error: Don't use --funcs with --vars.\n");
 399                        usage_with_options(probe_usage, options);
 400                }
 401                if (!params.filter)
 402                        params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
 403                                                       NULL);
 404                ret = show_available_funcs(params.target, params.filter,
 405                                        params.uprobes);
 406                strfilter__delete(params.filter);
 407                if (ret < 0)
 408                        pr_err("  Error: Failed to show functions."
 409                               " (%d)\n", ret);
 410                return ret;
 411        }
 412
 413#ifdef DWARF_SUPPORT
 414        if (params.show_lines && !params.uprobes) {
 415                if (params.mod_events) {
 416                        pr_err("  Error: Don't use --line with"
 417                               " --add/--del.\n");
 418                        usage_with_options(probe_usage, options);
 419                }
 420                if (params.show_vars) {
 421                        pr_err(" Error: Don't use --line with --vars.\n");
 422                        usage_with_options(probe_usage, options);
 423                }
 424
 425                ret = show_line_range(&params.line_range, params.target);
 426                if (ret < 0)
 427                        pr_err("  Error: Failed to show lines. (%d)\n", ret);
 428                return ret;
 429        }
 430        if (params.show_vars) {
 431                if (params.mod_events) {
 432                        pr_err("  Error: Don't use --vars with"
 433                               " --add/--del.\n");
 434                        usage_with_options(probe_usage, options);
 435                }
 436                if (!params.filter)
 437                        params.filter = strfilter__new(DEFAULT_VAR_FILTER,
 438                                                       NULL);
 439
 440                ret = show_available_vars(params.events, params.nevents,
 441                                          params.max_probe_points,
 442                                          params.target,
 443                                          params.filter,
 444                                          params.show_ext_vars);
 445                strfilter__delete(params.filter);
 446                if (ret < 0)
 447                        pr_err("  Error: Failed to show vars. (%d)\n", ret);
 448                return ret;
 449        }
 450#endif
 451
 452        if (params.dellist) {
 453                ret = del_perf_probe_events(params.dellist);
 454                strlist__delete(params.dellist);
 455                if (ret < 0) {
 456                        pr_err("  Error: Failed to delete events. (%d)\n", ret);
 457                        return ret;
 458                }
 459        }
 460
 461        if (params.nevents) {
 462                ret = add_perf_probe_events(params.events, params.nevents,
 463                                            params.max_probe_points,
 464                                            params.target,
 465                                            params.force_add);
 466                if (ret < 0) {
 467                        pr_err("  Error: Failed to add events. (%d)\n", ret);
 468                        return ret;
 469                }
 470        }
 471        return 0;
 472}
 473
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.