linux/tools/perf/builtin-script.c
<<
>>
Prefs
   1#include "builtin.h"
   2
   3#include "perf.h"
   4#include "util/cache.h"
   5#include "util/debug.h"
   6#include "util/exec_cmd.h"
   7#include "util/header.h"
   8#include "util/parse-options.h"
   9#include "util/session.h"
  10#include "util/symbol.h"
  11#include "util/thread.h"
  12#include "util/trace-event.h"
  13#include "util/parse-options.h"
  14#include "util/util.h"
  15#include "util/evlist.h"
  16#include "util/evsel.h"
  17
  18static char const               *script_name;
  19static char const               *generate_script_lang;
  20static bool                     debug_mode;
  21static u64                      last_timestamp;
  22static u64                      nr_unordered;
  23extern const struct option      record_options[];
  24static bool                     no_callchain;
  25
  26enum perf_output_field {
  27        PERF_OUTPUT_COMM            = 1U << 0,
  28        PERF_OUTPUT_TID             = 1U << 1,
  29        PERF_OUTPUT_PID             = 1U << 2,
  30        PERF_OUTPUT_TIME            = 1U << 3,
  31        PERF_OUTPUT_CPU             = 1U << 4,
  32        PERF_OUTPUT_EVNAME          = 1U << 5,
  33        PERF_OUTPUT_TRACE           = 1U << 6,
  34        PERF_OUTPUT_SYM             = 1U << 7,
  35};
  36
  37struct output_option {
  38        const char *str;
  39        enum perf_output_field field;
  40} all_output_options[] = {
  41        {.str = "comm",  .field = PERF_OUTPUT_COMM},
  42        {.str = "tid",   .field = PERF_OUTPUT_TID},
  43        {.str = "pid",   .field = PERF_OUTPUT_PID},
  44        {.str = "time",  .field = PERF_OUTPUT_TIME},
  45        {.str = "cpu",   .field = PERF_OUTPUT_CPU},
  46        {.str = "event", .field = PERF_OUTPUT_EVNAME},
  47        {.str = "trace", .field = PERF_OUTPUT_TRACE},
  48        {.str = "sym",   .field = PERF_OUTPUT_SYM},
  49};
  50
  51/* default set to maintain compatibility with current format */
  52static u64 output_fields[PERF_TYPE_MAX] = {
  53        [PERF_TYPE_HARDWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
  54                               PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
  55                               PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
  56
  57        [PERF_TYPE_SOFTWARE] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
  58                               PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
  59                               PERF_OUTPUT_EVNAME | PERF_OUTPUT_SYM,
  60
  61        [PERF_TYPE_TRACEPOINT] = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | \
  62                                 PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | \
  63                                 PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE,
  64};
  65
  66static bool output_set_by_user;
  67
  68#define PRINT_FIELD(x)  (output_fields[attr->type] & PERF_OUTPUT_##x)
  69
  70static int perf_session__check_attr(struct perf_session *session,
  71                                    struct perf_event_attr *attr)
  72{
  73        if (PRINT_FIELD(TRACE) &&
  74                !perf_session__has_traces(session, "record -R"))
  75                return -EINVAL;
  76
  77        if (PRINT_FIELD(SYM)) {
  78                if (!(session->sample_type & PERF_SAMPLE_IP)) {
  79                        pr_err("Samples do not contain IP data.\n");
  80                        return -EINVAL;
  81                }
  82                if (!no_callchain &&
  83                    !(session->sample_type & PERF_SAMPLE_CALLCHAIN))
  84                        symbol_conf.use_callchain = false;
  85        }
  86
  87        if ((PRINT_FIELD(PID) || PRINT_FIELD(TID)) &&
  88                !(session->sample_type & PERF_SAMPLE_TID)) {
  89                pr_err("Samples do not contain TID/PID data.\n");
  90                return -EINVAL;
  91        }
  92
  93        if (PRINT_FIELD(TIME) &&
  94                !(session->sample_type & PERF_SAMPLE_TIME)) {
  95                pr_err("Samples do not contain timestamps.\n");
  96                return -EINVAL;
  97        }
  98
  99        if (PRINT_FIELD(CPU) &&
 100                !(session->sample_type & PERF_SAMPLE_CPU)) {
 101                pr_err("Samples do not contain cpu.\n");
 102                return -EINVAL;
 103        }
 104
 105        return 0;
 106}
 107
 108static void print_sample_start(struct perf_sample *sample,
 109                               struct thread *thread,
 110                               struct perf_event_attr *attr)
 111{
 112        int type;
 113        struct event *event;
 114        const char *evname = NULL;
 115        unsigned long secs;
 116        unsigned long usecs;
 117        unsigned long long nsecs;
 118
 119        if (PRINT_FIELD(COMM)) {
 120                if (latency_format)
 121                        printf("%8.8s ", thread->comm);
 122                else if (PRINT_FIELD(SYM) && symbol_conf.use_callchain)
 123                        printf("%s ", thread->comm);
 124                else
 125                        printf("%16s ", thread->comm);
 126        }
 127
 128        if (PRINT_FIELD(PID) && PRINT_FIELD(TID))
 129                printf("%5d/%-5d ", sample->pid, sample->tid);
 130        else if (PRINT_FIELD(PID))
 131                printf("%5d ", sample->pid);
 132        else if (PRINT_FIELD(TID))
 133                printf("%5d ", sample->tid);
 134
 135        if (PRINT_FIELD(CPU)) {
 136                if (latency_format)
 137                        printf("%3d ", sample->cpu);
 138                else
 139                        printf("[%03d] ", sample->cpu);
 140        }
 141
 142        if (PRINT_FIELD(TIME)) {
 143                nsecs = sample->time;
 144                secs = nsecs / NSECS_PER_SEC;
 145                nsecs -= secs * NSECS_PER_SEC;
 146                usecs = nsecs / NSECS_PER_USEC;
 147                printf("%5lu.%06lu: ", secs, usecs);
 148        }
 149
 150        if (PRINT_FIELD(EVNAME)) {
 151                if (attr->type == PERF_TYPE_TRACEPOINT) {
 152                        type = trace_parse_common_type(sample->raw_data);
 153                        event = trace_find_event(type);
 154                        if (event)
 155                                evname = event->name;
 156                } else
 157                        evname = __event_name(attr->type, attr->config);
 158
 159                printf("%s: ", evname ? evname : "(unknown)");
 160        }
 161}
 162
 163static void process_event(union perf_event *event __unused,
 164                          struct perf_sample *sample,
 165                          struct perf_evsel *evsel,
 166                          struct perf_session *session,
 167                          struct thread *thread)
 168{
 169        struct perf_event_attr *attr = &evsel->attr;
 170
 171        if (output_fields[attr->type] == 0)
 172                return;
 173
 174        if (perf_session__check_attr(session, attr) < 0)
 175                return;
 176
 177        print_sample_start(sample, thread, attr);
 178
 179        if (PRINT_FIELD(TRACE))
 180                print_trace_event(sample->cpu, sample->raw_data,
 181                                  sample->raw_size);
 182
 183        if (PRINT_FIELD(SYM)) {
 184                if (!symbol_conf.use_callchain)
 185                        printf(" ");
 186                else
 187                        printf("\n");
 188                perf_session__print_symbols(event, sample, session);
 189        }
 190
 191        printf("\n");
 192}
 193
 194static int default_start_script(const char *script __unused,
 195                                int argc __unused,
 196                                const char **argv __unused)
 197{
 198        return 0;
 199}
 200
 201static int default_stop_script(void)
 202{
 203        return 0;
 204}
 205
 206static int default_generate_script(const char *outfile __unused)
 207{
 208        return 0;
 209}
 210
 211static struct scripting_ops default_scripting_ops = {
 212        .start_script           = default_start_script,
 213        .stop_script            = default_stop_script,
 214        .process_event          = process_event,
 215        .generate_script        = default_generate_script,
 216};
 217
 218static struct scripting_ops     *scripting_ops;
 219
 220static void setup_scripting(void)
 221{
 222        setup_perl_scripting();
 223        setup_python_scripting();
 224
 225        scripting_ops = &default_scripting_ops;
 226}
 227
 228static int cleanup_scripting(void)
 229{
 230        pr_debug("\nperf script stopped\n");
 231
 232        return scripting_ops->stop_script();
 233}
 234
 235static char const               *input_name = "perf.data";
 236
 237static int process_sample_event(union perf_event *event,
 238                                struct perf_sample *sample,
 239                                struct perf_evsel *evsel,
 240                                struct perf_session *session)
 241{
 242        struct thread *thread = perf_session__findnew(session, event->ip.pid);
 243
 244        if (thread == NULL) {
 245                pr_debug("problem processing %d event, skipping it.\n",
 246                         event->header.type);
 247                return -1;
 248        }
 249
 250        if (debug_mode) {
 251                if (sample->time < last_timestamp) {
 252                        pr_err("Samples misordered, previous: %" PRIu64
 253                                " this: %" PRIu64 "\n", last_timestamp,
 254                                sample->time);
 255                        nr_unordered++;
 256                }
 257                last_timestamp = sample->time;
 258                return 0;
 259        }
 260        scripting_ops->process_event(event, sample, evsel, session, thread);
 261
 262        session->hists.stats.total_period += sample->period;
 263        return 0;
 264}
 265
 266static struct perf_event_ops event_ops = {
 267        .sample          = process_sample_event,
 268        .mmap            = perf_event__process_mmap,
 269        .comm            = perf_event__process_comm,
 270        .exit            = perf_event__process_task,
 271        .fork            = perf_event__process_task,
 272        .attr            = perf_event__process_attr,
 273        .event_type      = perf_event__process_event_type,
 274        .tracing_data    = perf_event__process_tracing_data,
 275        .build_id        = perf_event__process_build_id,
 276        .ordered_samples = true,
 277        .ordering_requires_timestamps = true,
 278};
 279
 280extern volatile int session_done;
 281
 282static void sig_handler(int sig __unused)
 283{
 284        session_done = 1;
 285}
 286
 287static int __cmd_script(struct perf_session *session)
 288{
 289        int ret;
 290
 291        signal(SIGINT, sig_handler);
 292
 293        ret = perf_session__process_events(session, &event_ops);
 294
 295        if (debug_mode)
 296                pr_err("Misordered timestamps: %" PRIu64 "\n", nr_unordered);
 297
 298        return ret;
 299}
 300
 301struct script_spec {
 302        struct list_head        node;
 303        struct scripting_ops    *ops;
 304        char                    spec[0];
 305};
 306
 307static LIST_HEAD(script_specs);
 308
 309static struct script_spec *script_spec__new(const char *spec,
 310                                            struct scripting_ops *ops)
 311{
 312        struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
 313
 314        if (s != NULL) {
 315                strcpy(s->spec, spec);
 316                s->ops = ops;
 317        }
 318
 319        return s;
 320}
 321
 322static void script_spec__delete(struct script_spec *s)
 323{
 324        free(s->spec);
 325        free(s);
 326}
 327
 328static void script_spec__add(struct script_spec *s)
 329{
 330        list_add_tail(&s->node, &script_specs);
 331}
 332
 333static struct script_spec *script_spec__find(const char *spec)
 334{
 335        struct script_spec *s;
 336
 337        list_for_each_entry(s, &script_specs, node)
 338                if (strcasecmp(s->spec, spec) == 0)
 339                        return s;
 340        return NULL;
 341}
 342
 343static struct script_spec *script_spec__findnew(const char *spec,
 344                                                struct scripting_ops *ops)
 345{
 346        struct script_spec *s = script_spec__find(spec);
 347
 348        if (s)
 349                return s;
 350
 351        s = script_spec__new(spec, ops);
 352        if (!s)
 353                goto out_delete_spec;
 354
 355        script_spec__add(s);
 356
 357        return s;
 358
 359out_delete_spec:
 360        script_spec__delete(s);
 361
 362        return NULL;
 363}
 364
 365int script_spec_register(const char *spec, struct scripting_ops *ops)
 366{
 367        struct script_spec *s;
 368
 369        s = script_spec__find(spec);
 370        if (s)
 371                return -1;
 372
 373        s = script_spec__findnew(spec, ops);
 374        if (!s)
 375                return -1;
 376
 377        return 0;
 378}
 379
 380static struct scripting_ops *script_spec__lookup(const char *spec)
 381{
 382        struct script_spec *s = script_spec__find(spec);
 383        if (!s)
 384                return NULL;
 385
 386        return s->ops;
 387}
 388
 389static void list_available_languages(void)
 390{
 391        struct script_spec *s;
 392
 393        fprintf(stderr, "\n");
 394        fprintf(stderr, "Scripting language extensions (used in "
 395                "perf script -s [spec:]script.[spec]):\n\n");
 396
 397        list_for_each_entry(s, &script_specs, node)
 398                fprintf(stderr, "  %-42s [%s]\n", s->spec, s->ops->name);
 399
 400        fprintf(stderr, "\n");
 401}
 402
 403static int parse_scriptname(const struct option *opt __used,
 404                            const char *str, int unset __used)
 405{
 406        char spec[PATH_MAX];
 407        const char *script, *ext;
 408        int len;
 409
 410        if (strcmp(str, "lang") == 0) {
 411                list_available_languages();
 412                exit(0);
 413        }
 414
 415        script = strchr(str, ':');
 416        if (script) {
 417                len = script - str;
 418                if (len >= PATH_MAX) {
 419                        fprintf(stderr, "invalid language specifier");
 420                        return -1;
 421                }
 422                strncpy(spec, str, len);
 423                spec[len] = '\0';
 424                scripting_ops = script_spec__lookup(spec);
 425                if (!scripting_ops) {
 426                        fprintf(stderr, "invalid language specifier");
 427                        return -1;
 428                }
 429                script++;
 430        } else {
 431                script = str;
 432                ext = strrchr(script, '.');
 433                if (!ext) {
 434                        fprintf(stderr, "invalid script extension");
 435                        return -1;
 436                }
 437                scripting_ops = script_spec__lookup(++ext);
 438                if (!scripting_ops) {
 439                        fprintf(stderr, "invalid script extension");
 440                        return -1;
 441                }
 442        }
 443
 444        script_name = strdup(script);
 445
 446        return 0;
 447}
 448
 449static int parse_output_fields(const struct option *opt __used,
 450                            const char *arg, int unset __used)
 451{
 452        char *tok;
 453        int i, imax = sizeof(all_output_options) / sizeof(struct output_option);
 454        int rc = 0;
 455        char *str = strdup(arg);
 456        int type = -1;
 457
 458        if (!str)
 459                return -ENOMEM;
 460
 461        tok = strtok(str, ":");
 462        if (!tok) {
 463                fprintf(stderr,
 464                        "Invalid field string - not prepended with type.");
 465                return -EINVAL;
 466        }
 467
 468        /* first word should state which event type user
 469         * is specifying the fields
 470         */
 471        if (!strcmp(tok, "hw"))
 472                type = PERF_TYPE_HARDWARE;
 473        else if (!strcmp(tok, "sw"))
 474                type = PERF_TYPE_SOFTWARE;
 475        else if (!strcmp(tok, "trace"))
 476                type = PERF_TYPE_TRACEPOINT;
 477        else {
 478                fprintf(stderr, "Invalid event type in field string.");
 479                return -EINVAL;
 480        }
 481
 482        output_fields[type] = 0;
 483        while (1) {
 484                tok = strtok(NULL, ",");
 485                if (!tok)
 486                        break;
 487                for (i = 0; i < imax; ++i) {
 488                        if (strcmp(tok, all_output_options[i].str) == 0) {
 489                                output_fields[type] |= all_output_options[i].field;
 490                                break;
 491                        }
 492                }
 493                if (i == imax) {
 494                        fprintf(stderr, "Invalid field requested.");
 495                        rc = -EINVAL;
 496                        break;
 497                }
 498        }
 499
 500        if (output_fields[type] == 0) {
 501                pr_debug("No fields requested for %s type. "
 502                         "Events will not be displayed\n", event_type(type));
 503        }
 504
 505        output_set_by_user = true;
 506
 507        free(str);
 508        return rc;
 509}
 510
 511/* Helper function for filesystems that return a dent->d_type DT_UNKNOWN */
 512static int is_directory(const char *base_path, const struct dirent *dent)
 513{
 514        char path[PATH_MAX];
 515        struct stat st;
 516
 517        sprintf(path, "%s/%s", base_path, dent->d_name);
 518        if (stat(path, &st))
 519                return 0;
 520
 521        return S_ISDIR(st.st_mode);
 522}
 523
 524#define for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next)\
 525        while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) &&     \
 526               lang_next)                                               \
 527                if ((lang_dirent.d_type == DT_DIR ||                    \
 528                     (lang_dirent.d_type == DT_UNKNOWN &&               \
 529                      is_directory(scripts_path, &lang_dirent))) &&     \
 530                    (strcmp(lang_dirent.d_name, ".")) &&                \
 531                    (strcmp(lang_dirent.d_name, "..")))
 532
 533#define for_each_script(lang_path, lang_dir, script_dirent, script_next)\
 534        while (!readdir_r(lang_dir, &script_dirent, &script_next) &&    \
 535               script_next)                                             \
 536                if (script_dirent.d_type != DT_DIR &&                   \
 537                    (script_dirent.d_type != DT_UNKNOWN ||              \
 538                     !is_directory(lang_path, &script_dirent)))
 539
 540
 541#define RECORD_SUFFIX                   "-record"
 542#define REPORT_SUFFIX                   "-report"
 543
 544struct script_desc {
 545        struct list_head        node;
 546        char                    *name;
 547        char                    *half_liner;
 548        char                    *args;
 549};
 550
 551static LIST_HEAD(script_descs);
 552
 553static struct script_desc *script_desc__new(const char *name)
 554{
 555        struct script_desc *s = zalloc(sizeof(*s));
 556
 557        if (s != NULL && name)
 558                s->name = strdup(name);
 559
 560        return s;
 561}
 562
 563static void script_desc__delete(struct script_desc *s)
 564{
 565        free(s->name);
 566        free(s->half_liner);
 567        free(s->args);
 568        free(s);
 569}
 570
 571static void script_desc__add(struct script_desc *s)
 572{
 573        list_add_tail(&s->node, &script_descs);
 574}
 575
 576static struct script_desc *script_desc__find(const char *name)
 577{
 578        struct script_desc *s;
 579
 580        list_for_each_entry(s, &script_descs, node)
 581                if (strcasecmp(s->name, name) == 0)
 582                        return s;
 583        return NULL;
 584}
 585
 586static struct script_desc *script_desc__findnew(const char *name)
 587{
 588        struct script_desc *s = script_desc__find(name);
 589
 590        if (s)
 591                return s;
 592
 593        s = script_desc__new(name);
 594        if (!s)
 595                goto out_delete_desc;
 596
 597        script_desc__add(s);
 598
 599        return s;
 600
 601out_delete_desc:
 602        script_desc__delete(s);
 603
 604        return NULL;
 605}
 606
 607static const char *ends_with(const char *str, const char *suffix)
 608{
 609        size_t suffix_len = strlen(suffix);
 610        const char *p = str;
 611
 612        if (strlen(str) > suffix_len) {
 613                p = str + strlen(str) - suffix_len;
 614                if (!strncmp(p, suffix, suffix_len))
 615                        return p;
 616        }
 617
 618        return NULL;
 619}
 620
 621static char *ltrim(char *str)
 622{
 623        int len = strlen(str);
 624
 625        while (len && isspace(*str)) {
 626                len--;
 627                str++;
 628        }
 629
 630        return str;
 631}
 632
 633static int read_script_info(struct script_desc *desc, const char *filename)
 634{
 635        char line[BUFSIZ], *p;
 636        FILE *fp;
 637
 638        fp = fopen(filename, "r");
 639        if (!fp)
 640                return -1;
 641
 642        while (fgets(line, sizeof(line), fp)) {
 643                p = ltrim(line);
 644                if (strlen(p) == 0)
 645                        continue;
 646                if (*p != '#')
 647                        continue;
 648                p++;
 649                if (strlen(p) && *p == '!')
 650                        continue;
 651
 652                p = ltrim(p);
 653                if (strlen(p) && p[strlen(p) - 1] == '\n')
 654                        p[strlen(p) - 1] = '\0';
 655
 656                if (!strncmp(p, "description:", strlen("description:"))) {
 657                        p += strlen("description:");
 658                        desc->half_liner = strdup(ltrim(p));
 659                        continue;
 660                }
 661
 662                if (!strncmp(p, "args:", strlen("args:"))) {
 663                        p += strlen("args:");
 664                        desc->args = strdup(ltrim(p));
 665                        continue;
 666                }
 667        }
 668
 669        fclose(fp);
 670
 671        return 0;
 672}
 673
 674static int list_available_scripts(const struct option *opt __used,
 675                                  const char *s __used, int unset __used)
 676{
 677        struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
 678        char scripts_path[MAXPATHLEN];
 679        DIR *scripts_dir, *lang_dir;
 680        char script_path[MAXPATHLEN];
 681        char lang_path[MAXPATHLEN];
 682        struct script_desc *desc;
 683        char first_half[BUFSIZ];
 684        char *script_root;
 685        char *str;
 686
 687        snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
 688
 689        scripts_dir = opendir(scripts_path);
 690        if (!scripts_dir)
 691                return -1;
 692
 693        for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
 694                snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
 695                         lang_dirent.d_name);
 696                lang_dir = opendir(lang_path);
 697                if (!lang_dir)
 698                        continue;
 699
 700                for_each_script(lang_path, lang_dir, script_dirent, script_next) {
 701                        script_root = strdup(script_dirent.d_name);
 702                        str = (char *)ends_with(script_root, REPORT_SUFFIX);
 703                        if (str) {
 704                                *str = '\0';
 705                                desc = script_desc__findnew(script_root);
 706                                snprintf(script_path, MAXPATHLEN, "%s/%s",
 707                                         lang_path, script_dirent.d_name);
 708                                read_script_info(desc, script_path);
 709                        }
 710                        free(script_root);
 711                }
 712        }
 713
 714        fprintf(stdout, "List of available trace scripts:\n");
 715        list_for_each_entry(desc, &script_descs, node) {
 716                sprintf(first_half, "%s %s", desc->name,
 717                        desc->args ? desc->args : "");
 718                fprintf(stdout, "  %-36s %s\n", first_half,
 719                        desc->half_liner ? desc->half_liner : "");
 720        }
 721
 722        exit(0);
 723}
 724
 725static char *get_script_path(const char *script_root, const char *suffix)
 726{
 727        struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
 728        char scripts_path[MAXPATHLEN];
 729        char script_path[MAXPATHLEN];
 730        DIR *scripts_dir, *lang_dir;
 731        char lang_path[MAXPATHLEN];
 732        char *str, *__script_root;
 733        char *path = NULL;
 734
 735        snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
 736
 737        scripts_dir = opendir(scripts_path);
 738        if (!scripts_dir)
 739                return NULL;
 740
 741        for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) {
 742                snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
 743                         lang_dirent.d_name);
 744                lang_dir = opendir(lang_path);
 745                if (!lang_dir)
 746                        continue;
 747
 748                for_each_script(lang_path, lang_dir, script_dirent, script_next) {
 749                        __script_root = strdup(script_dirent.d_name);
 750                        str = (char *)ends_with(__script_root, suffix);
 751                        if (str) {
 752                                *str = '\0';
 753                                if (strcmp(__script_root, script_root))
 754                                        continue;
 755                                snprintf(script_path, MAXPATHLEN, "%s/%s",
 756                                         lang_path, script_dirent.d_name);
 757                                path = strdup(script_path);
 758                                free(__script_root);
 759                                break;
 760                        }
 761                        free(__script_root);
 762                }
 763        }
 764
 765        return path;
 766}
 767
 768static bool is_top_script(const char *script_path)
 769{
 770        return ends_with(script_path, "top") == NULL ? false : true;
 771}
 772
 773static int has_required_arg(char *script_path)
 774{
 775        struct script_desc *desc;
 776        int n_args = 0;
 777        char *p;
 778
 779        desc = script_desc__new(NULL);
 780
 781        if (read_script_info(desc, script_path))
 782                goto out;
 783
 784        if (!desc->args)
 785                goto out;
 786
 787        for (p = desc->args; *p; p++)
 788                if (*p == '<')
 789                        n_args++;
 790out:
 791        script_desc__delete(desc);
 792
 793        return n_args;
 794}
 795
 796static const char * const script_usage[] = {
 797        "perf script [<options>]",
 798        "perf script [<options>] record <script> [<record-options>] <command>",
 799        "perf script [<options>] report <script> [script-args]",
 800        "perf script [<options>] <script> [<record-options>] <command>",
 801        "perf script [<options>] <top-script> [script-args]",
 802        NULL
 803};
 804
 805static const struct option options[] = {
 806        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
 807                    "dump raw trace in ASCII"),
 808        OPT_INCR('v', "verbose", &verbose,
 809                    "be more verbose (show symbol address, etc)"),
 810        OPT_BOOLEAN('L', "Latency", &latency_format,
 811                    "show latency attributes (irqs/preemption disabled, etc)"),
 812        OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
 813                           list_available_scripts),
 814        OPT_CALLBACK('s', "script", NULL, "name",
 815                     "script file name (lang:script name, script name, or *)",
 816                     parse_scriptname),
 817        OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
 818                   "generate perf-script.xx script in specified language"),
 819        OPT_STRING('i', "input", &input_name, "file",
 820                    "input file name"),
 821        OPT_BOOLEAN('d', "debug-mode", &debug_mode,
 822                   "do various checks like samples ordering and lost events"),
 823        OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
 824                   "file", "vmlinux pathname"),
 825        OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
 826                   "file", "kallsyms pathname"),
 827        OPT_BOOLEAN('G', "hide-call-graph", &no_callchain,
 828                    "When printing symbols do not display call chain"),
 829        OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
 830                    "Look for files with symbols relative to this directory"),
 831        OPT_CALLBACK('f', "fields", NULL, "str",
 832                     "comma separated output fields prepend with 'type:'. Valid types: hw,sw,trace. Fields: comm,tid,pid,time,cpu,event,trace,sym",
 833                     parse_output_fields),
 834
 835        OPT_END()
 836};
 837
 838static bool have_cmd(int argc, const char **argv)
 839{
 840        char **__argv = malloc(sizeof(const char *) * argc);
 841
 842        if (!__argv)
 843                die("malloc");
 844        memcpy(__argv, argv, sizeof(const char *) * argc);
 845        argc = parse_options(argc, (const char **)__argv, record_options,
 846                             NULL, PARSE_OPT_STOP_AT_NON_OPTION);
 847        free(__argv);
 848
 849        return argc != 0;
 850}
 851
 852int cmd_script(int argc, const char **argv, const char *prefix __used)
 853{
 854        char *rec_script_path = NULL;
 855        char *rep_script_path = NULL;
 856        struct perf_session *session;
 857        char *script_path = NULL;
 858        const char **__argv;
 859        bool system_wide;
 860        int i, j, err;
 861
 862        setup_scripting();
 863
 864        argc = parse_options(argc, argv, options, script_usage,
 865                             PARSE_OPT_STOP_AT_NON_OPTION);
 866
 867        if (argc > 1 && !strncmp(argv[0], "rec", strlen("rec"))) {
 868                rec_script_path = get_script_path(argv[1], RECORD_SUFFIX);
 869                if (!rec_script_path)
 870                        return cmd_record(argc, argv, NULL);
 871        }
 872
 873        if (argc > 1 && !strncmp(argv[0], "rep", strlen("rep"))) {
 874                rep_script_path = get_script_path(argv[1], REPORT_SUFFIX);
 875                if (!rep_script_path) {
 876                        fprintf(stderr,
 877                                "Please specify a valid report script"
 878                                "(see 'perf script -l' for listing)\n");
 879                        return -1;
 880                }
 881        }
 882
 883        /* make sure PERF_EXEC_PATH is set for scripts */
 884        perf_set_argv_exec_path(perf_exec_path());
 885
 886        if (argc && !script_name && !rec_script_path && !rep_script_path) {
 887                int live_pipe[2];
 888                int rep_args;
 889                pid_t pid;
 890
 891                rec_script_path = get_script_path(argv[0], RECORD_SUFFIX);
 892                rep_script_path = get_script_path(argv[0], REPORT_SUFFIX);
 893
 894                if (!rec_script_path && !rep_script_path) {
 895                        fprintf(stderr, " Couldn't find script %s\n\n See perf"
 896                                " script -l for available scripts.\n", argv[0]);
 897                        usage_with_options(script_usage, options);
 898                }
 899
 900                if (is_top_script(argv[0])) {
 901                        rep_args = argc - 1;
 902                } else {
 903                        int rec_args;
 904
 905                        rep_args = has_required_arg(rep_script_path);
 906                        rec_args = (argc - 1) - rep_args;
 907                        if (rec_args < 0) {
 908                                fprintf(stderr, " %s script requires options."
 909                                        "\n\n See perf script -l for available "
 910                                        "scripts and options.\n", argv[0]);
 911                                usage_with_options(script_usage, options);
 912                        }
 913                }
 914
 915                if (pipe(live_pipe) < 0) {
 916                        perror("failed to create pipe");
 917                        exit(-1);
 918                }
 919
 920                pid = fork();
 921                if (pid < 0) {
 922                        perror("failed to fork");
 923                        exit(-1);
 924                }
 925
 926                if (!pid) {
 927                        system_wide = true;
 928                        j = 0;
 929
 930                        dup2(live_pipe[1], 1);
 931                        close(live_pipe[0]);
 932
 933                        if (!is_top_script(argv[0]))
 934                                system_wide = !have_cmd(argc - rep_args,
 935                                                        &argv[rep_args]);
 936
 937                        __argv = malloc((argc + 6) * sizeof(const char *));
 938                        if (!__argv)
 939                                die("malloc");
 940
 941                        __argv[j++] = "/bin/sh";
 942                        __argv[j++] = rec_script_path;
 943                        if (system_wide)
 944                                __argv[j++] = "-a";
 945                        __argv[j++] = "-q";
 946                        __argv[j++] = "-o";
 947                        __argv[j++] = "-";
 948                        for (i = rep_args + 1; i < argc; i++)
 949                                __argv[j++] = argv[i];
 950                        __argv[j++] = NULL;
 951
 952                        execvp("/bin/sh", (char **)__argv);
 953                        free(__argv);
 954                        exit(-1);
 955                }
 956
 957                dup2(live_pipe[0], 0);
 958                close(live_pipe[1]);
 959
 960                __argv = malloc((argc + 4) * sizeof(const char *));
 961                if (!__argv)
 962                        die("malloc");
 963                j = 0;
 964                __argv[j++] = "/bin/sh";
 965                __argv[j++] = rep_script_path;
 966                for (i = 1; i < rep_args + 1; i++)
 967                        __argv[j++] = argv[i];
 968                __argv[j++] = "-i";
 969                __argv[j++] = "-";
 970                __argv[j++] = NULL;
 971
 972                execvp("/bin/sh", (char **)__argv);
 973                free(__argv);
 974                exit(-1);
 975        }
 976
 977        if (rec_script_path)
 978                script_path = rec_script_path;
 979        if (rep_script_path)
 980                script_path = rep_script_path;
 981
 982        if (script_path) {
 983                system_wide = false;
 984                j = 0;
 985
 986                if (rec_script_path)
 987                        system_wide = !have_cmd(argc - 1, &argv[1]);
 988
 989                __argv = malloc((argc + 2) * sizeof(const char *));
 990                if (!__argv)
 991                        die("malloc");
 992                __argv[j++] = "/bin/sh";
 993                __argv[j++] = script_path;
 994                if (system_wide)
 995                        __argv[j++] = "-a";
 996                for (i = 2; i < argc; i++)
 997                        __argv[j++] = argv[i];
 998                __argv[j++] = NULL;
 999
1000                execvp("/bin/sh", (char **)__argv);
1001                free(__argv);
1002                exit(-1);
1003        }
1004
1005        if (symbol__init() < 0)
1006                return -1;
1007        if (!script_name)
1008                setup_pager();
1009
1010        session = perf_session__new(input_name, O_RDONLY, 0, false, &event_ops);
1011        if (session == NULL)
1012                return -ENOMEM;
1013
1014        if (!no_callchain)
1015                symbol_conf.use_callchain = true;
1016        else
1017                symbol_conf.use_callchain = false;
1018
1019        if (generate_script_lang) {
1020                struct stat perf_stat;
1021                int input;
1022
1023                if (output_set_by_user) {
1024                        fprintf(stderr,
1025                                "custom fields not supported for generated scripts");
1026                        return -1;
1027                }
1028
1029                input = open(input_name, O_RDONLY);
1030                if (input < 0) {
1031                        perror("failed to open file");
1032                        exit(-1);
1033                }
1034
1035                err = fstat(input, &perf_stat);
1036                if (err < 0) {
1037                        perror("failed to stat file");
1038                        exit(-1);
1039                }
1040
1041                if (!perf_stat.st_size) {
1042                        fprintf(stderr, "zero-sized file, nothing to do!\n");
1043                        exit(0);
1044                }
1045
1046                scripting_ops = script_spec__lookup(generate_script_lang);
1047                if (!scripting_ops) {
1048                        fprintf(stderr, "invalid language specifier");
1049                        return -1;
1050                }
1051
1052                err = scripting_ops->generate_script("perf-script");
1053                goto out;
1054        }
1055
1056        if (script_name) {
1057                err = scripting_ops->start_script(script_name, argc, argv);
1058                if (err)
1059                        goto out;
1060                pr_debug("perf script started with script %s\n\n", script_name);
1061        }
1062
1063        err = __cmd_script(session);
1064
1065        perf_session__delete(session);
1066        cleanup_scripting();
1067out:
1068        return err;
1069}
1070