linux/tools/perf/util/event.c
<<
>>
Prefs
   1#include <linux/types.h>
   2#include "event.h"
   3#include "debug.h"
   4#include "sort.h"
   5#include "string.h"
   6#include "strlist.h"
   7#include "thread.h"
   8#include "thread_map.h"
   9
  10static const char *perf_event__names[] = {
  11        [0]                                     = "TOTAL",
  12        [PERF_RECORD_MMAP]                      = "MMAP",
  13        [PERF_RECORD_LOST]                      = "LOST",
  14        [PERF_RECORD_COMM]                      = "COMM",
  15        [PERF_RECORD_EXIT]                      = "EXIT",
  16        [PERF_RECORD_THROTTLE]                  = "THROTTLE",
  17        [PERF_RECORD_UNTHROTTLE]                = "UNTHROTTLE",
  18        [PERF_RECORD_FORK]                      = "FORK",
  19        [PERF_RECORD_READ]                      = "READ",
  20        [PERF_RECORD_SAMPLE]                    = "SAMPLE",
  21        [PERF_RECORD_HEADER_ATTR]               = "ATTR",
  22        [PERF_RECORD_HEADER_EVENT_TYPE]         = "EVENT_TYPE",
  23        [PERF_RECORD_HEADER_TRACING_DATA]       = "TRACING_DATA",
  24        [PERF_RECORD_HEADER_BUILD_ID]           = "BUILD_ID",
  25        [PERF_RECORD_FINISHED_ROUND]            = "FINISHED_ROUND",
  26};
  27
  28const char *perf_event__name(unsigned int id)
  29{
  30        if (id >= ARRAY_SIZE(perf_event__names))
  31                return "INVALID";
  32        if (!perf_event__names[id])
  33                return "UNKNOWN";
  34        return perf_event__names[id];
  35}
  36
  37static struct perf_sample synth_sample = {
  38        .pid       = -1,
  39        .tid       = -1,
  40        .time      = -1,
  41        .stream_id = -1,
  42        .cpu       = -1,
  43        .period    = 1,
  44};
  45
  46static pid_t perf_event__get_comm_tgid(pid_t pid, char *comm, size_t len)
  47{
  48        char filename[PATH_MAX];
  49        char bf[BUFSIZ];
  50        FILE *fp;
  51        size_t size = 0;
  52        pid_t tgid = -1;
  53
  54        snprintf(filename, sizeof(filename), "/proc/%d/status", pid);
  55
  56        fp = fopen(filename, "r");
  57        if (fp == NULL) {
  58                pr_debug("couldn't open %s\n", filename);
  59                return 0;
  60        }
  61
  62        while (!comm[0] || (tgid < 0)) {
  63                if (fgets(bf, sizeof(bf), fp) == NULL) {
  64                        pr_warning("couldn't get COMM and pgid, malformed %s\n",
  65                                   filename);
  66                        break;
  67                }
  68
  69                if (memcmp(bf, "Name:", 5) == 0) {
  70                        char *name = bf + 5;
  71                        while (*name && isspace(*name))
  72                                ++name;
  73                        size = strlen(name) - 1;
  74                        if (size >= len)
  75                                size = len - 1;
  76                        memcpy(comm, name, size);
  77                        comm[size] = '\0';
  78
  79                } else if (memcmp(bf, "Tgid:", 5) == 0) {
  80                        char *tgids = bf + 5;
  81                        while (*tgids && isspace(*tgids))
  82                                ++tgids;
  83                        tgid = atoi(tgids);
  84                }
  85        }
  86
  87        fclose(fp);
  88
  89        return tgid;
  90}
  91
  92static pid_t perf_event__synthesize_comm(struct perf_tool *tool,
  93                                         union perf_event *event, pid_t pid,
  94                                         int full,
  95                                         perf_event__handler_t process,
  96                                         struct machine *machine)
  97{
  98        char filename[PATH_MAX];
  99        size_t size;
 100        DIR *tasks;
 101        struct dirent dirent, *next;
 102        pid_t tgid;
 103
 104        memset(&event->comm, 0, sizeof(event->comm));
 105
 106        tgid = perf_event__get_comm_tgid(pid, event->comm.comm,
 107                                         sizeof(event->comm.comm));
 108        if (tgid < 0)
 109                goto out;
 110
 111        event->comm.pid = tgid;
 112        event->comm.header.type = PERF_RECORD_COMM;
 113
 114        size = strlen(event->comm.comm) + 1;
 115        size = ALIGN(size, sizeof(u64));
 116        memset(event->comm.comm + size, 0, machine->id_hdr_size);
 117        event->comm.header.size = (sizeof(event->comm) -
 118                                (sizeof(event->comm.comm) - size) +
 119                                machine->id_hdr_size);
 120        if (!full) {
 121                event->comm.tid = pid;
 122
 123                process(tool, event, &synth_sample, machine);
 124                goto out;
 125        }
 126
 127        snprintf(filename, sizeof(filename), "/proc/%d/task", pid);
 128
 129        tasks = opendir(filename);
 130        if (tasks == NULL) {
 131                pr_debug("couldn't open %s\n", filename);
 132                return 0;
 133        }
 134
 135        while (!readdir_r(tasks, &dirent, &next) && next) {
 136                char *end;
 137                pid = strtol(dirent.d_name, &end, 10);
 138                if (*end)
 139                        continue;
 140
 141                /* already have tgid; jut want to update the comm */
 142                (void) perf_event__get_comm_tgid(pid, event->comm.comm,
 143                                         sizeof(event->comm.comm));
 144
 145                size = strlen(event->comm.comm) + 1;
 146                size = ALIGN(size, sizeof(u64));
 147                memset(event->comm.comm + size, 0, machine->id_hdr_size);
 148                event->comm.header.size = (sizeof(event->comm) -
 149                                          (sizeof(event->comm.comm) - size) +
 150                                          machine->id_hdr_size);
 151
 152                event->comm.tid = pid;
 153
 154                process(tool, event, &synth_sample, machine);
 155        }
 156
 157        closedir(tasks);
 158out:
 159        return tgid;
 160}
 161
 162static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
 163                                              union perf_event *event,
 164                                              pid_t pid, pid_t tgid,
 165                                              perf_event__handler_t process,
 166                                              struct machine *machine)
 167{
 168        char filename[PATH_MAX];
 169        FILE *fp;
 170
 171        snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
 172
 173        fp = fopen(filename, "r");
 174        if (fp == NULL) {
 175                /*
 176                 * We raced with a task exiting - just return:
 177                 */
 178                pr_debug("couldn't open %s\n", filename);
 179                return -1;
 180        }
 181
 182        event->header.type = PERF_RECORD_MMAP;
 183        /*
 184         * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
 185         */
 186        event->header.misc = PERF_RECORD_MISC_USER;
 187
 188        while (1) {
 189                char bf[BUFSIZ], *pbf = bf;
 190                int n;
 191                size_t size;
 192                if (fgets(bf, sizeof(bf), fp) == NULL)
 193                        break;
 194
 195                /* 00400000-0040c000 r-xp 00000000 fd:01 41038  /bin/cat */
 196                n = hex2u64(pbf, &event->mmap.start);
 197                if (n < 0)
 198                        continue;
 199                pbf += n + 1;
 200                n = hex2u64(pbf, &event->mmap.len);
 201                if (n < 0)
 202                        continue;
 203                pbf += n + 3;
 204                if (*pbf == 'x') { /* vm_exec */
 205                        char anonstr[] = "//anon\n";
 206                        char *execname = strchr(bf, '/');
 207
 208                        /* Catch VDSO */
 209                        if (execname == NULL)
 210                                execname = strstr(bf, "[vdso]");
 211
 212                        /* Catch anonymous mmaps */
 213                        if ((execname == NULL) && !strstr(bf, "["))
 214                                execname = anonstr;
 215
 216                        if (execname == NULL)
 217                                continue;
 218
 219                        pbf += 3;
 220                        n = hex2u64(pbf, &event->mmap.pgoff);
 221
 222                        size = strlen(execname);
 223                        execname[size - 1] = '\0'; /* Remove \n */
 224                        memcpy(event->mmap.filename, execname, size);
 225                        size = ALIGN(size, sizeof(u64));
 226                        event->mmap.len -= event->mmap.start;
 227                        event->mmap.header.size = (sizeof(event->mmap) -
 228                                                (sizeof(event->mmap.filename) - size));
 229                        memset(event->mmap.filename + size, 0, machine->id_hdr_size);
 230                        event->mmap.header.size += machine->id_hdr_size;
 231                        event->mmap.pid = tgid;
 232                        event->mmap.tid = pid;
 233
 234                        process(tool, event, &synth_sample, machine);
 235                }
 236        }
 237
 238        fclose(fp);
 239        return 0;
 240}
 241
 242int perf_event__synthesize_modules(struct perf_tool *tool,
 243                                   perf_event__handler_t process,
 244                                   struct machine *machine)
 245{
 246        struct rb_node *nd;
 247        struct map_groups *kmaps = &machine->kmaps;
 248        union perf_event *event = zalloc((sizeof(event->mmap) +
 249                                          machine->id_hdr_size));
 250        if (event == NULL) {
 251                pr_debug("Not enough memory synthesizing mmap event "
 252                         "for kernel modules\n");
 253                return -1;
 254        }
 255
 256        event->header.type = PERF_RECORD_MMAP;
 257
 258        /*
 259         * kernel uses 0 for user space maps, see kernel/perf_event.c
 260         * __perf_event_mmap
 261         */
 262        if (machine__is_host(machine))
 263                event->header.misc = PERF_RECORD_MISC_KERNEL;
 264        else
 265                event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
 266
 267        for (nd = rb_first(&kmaps->maps[MAP__FUNCTION]);
 268             nd; nd = rb_next(nd)) {
 269                size_t size;
 270                struct map *pos = rb_entry(nd, struct map, rb_node);
 271
 272                if (pos->dso->kernel)
 273                        continue;
 274
 275                size = ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
 276                event->mmap.header.type = PERF_RECORD_MMAP;
 277                event->mmap.header.size = (sizeof(event->mmap) -
 278                                        (sizeof(event->mmap.filename) - size));
 279                memset(event->mmap.filename + size, 0, machine->id_hdr_size);
 280                event->mmap.header.size += machine->id_hdr_size;
 281                event->mmap.start = pos->start;
 282                event->mmap.len   = pos->end - pos->start;
 283                event->mmap.pid   = machine->pid;
 284
 285                memcpy(event->mmap.filename, pos->dso->long_name,
 286                       pos->dso->long_name_len + 1);
 287                process(tool, event, &synth_sample, machine);
 288        }
 289
 290        free(event);
 291        return 0;
 292}
 293
 294static int __event__synthesize_thread(union perf_event *comm_event,
 295                                      union perf_event *mmap_event,
 296                                      pid_t pid, int full,
 297                                          perf_event__handler_t process,
 298                                      struct perf_tool *tool,
 299                                      struct machine *machine)
 300{
 301        pid_t tgid = perf_event__synthesize_comm(tool, comm_event, pid, full,
 302                                                 process, machine);
 303        if (tgid == -1)
 304                return -1;
 305        return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
 306                                                  process, machine);
 307}
 308
 309int perf_event__synthesize_thread_map(struct perf_tool *tool,
 310                                      struct thread_map *threads,
 311                                      perf_event__handler_t process,
 312                                      struct machine *machine)
 313{
 314        union perf_event *comm_event, *mmap_event;
 315        int err = -1, thread, j;
 316
 317        comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
 318        if (comm_event == NULL)
 319                goto out;
 320
 321        mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size);
 322        if (mmap_event == NULL)
 323                goto out_free_comm;
 324
 325        err = 0;
 326        for (thread = 0; thread < threads->nr; ++thread) {
 327                if (__event__synthesize_thread(comm_event, mmap_event,
 328                                               threads->map[thread], 0,
 329                                               process, tool, machine)) {
 330                        err = -1;
 331                        break;
 332                }
 333
 334                /*
 335                 * comm.pid is set to thread group id by
 336                 * perf_event__synthesize_comm
 337                 */
 338                if ((int) comm_event->comm.pid != threads->map[thread]) {
 339                        bool need_leader = true;
 340
 341                        /* is thread group leader in thread_map? */
 342                        for (j = 0; j < threads->nr; ++j) {
 343                                if ((int) comm_event->comm.pid == threads->map[j]) {
 344                                        need_leader = false;
 345                                        break;
 346                                }
 347                        }
 348
 349                        /* if not, generate events for it */
 350                        if (need_leader &&
 351                            __event__synthesize_thread(comm_event,
 352                                                      mmap_event,
 353                                                      comm_event->comm.pid, 0,
 354                                                      process, tool, machine)) {
 355                                err = -1;
 356                                break;
 357                        }
 358                }
 359        }
 360        free(mmap_event);
 361out_free_comm:
 362        free(comm_event);
 363out:
 364        return err;
 365}
 366
 367int perf_event__synthesize_threads(struct perf_tool *tool,
 368                                   perf_event__handler_t process,
 369                                   struct machine *machine)
 370{
 371        DIR *proc;
 372        struct dirent dirent, *next;
 373        union perf_event *comm_event, *mmap_event;
 374        int err = -1;
 375
 376        comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
 377        if (comm_event == NULL)
 378                goto out;
 379
 380        mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size);
 381        if (mmap_event == NULL)
 382                goto out_free_comm;
 383
 384        proc = opendir("/proc");
 385        if (proc == NULL)
 386                goto out_free_mmap;
 387
 388        while (!readdir_r(proc, &dirent, &next) && next) {
 389                char *end;
 390                pid_t pid = strtol(dirent.d_name, &end, 10);
 391
 392                if (*end) /* only interested in proper numerical dirents */
 393                        continue;
 394
 395                __event__synthesize_thread(comm_event, mmap_event, pid, 1,
 396                                           process, tool, machine);
 397        }
 398
 399        closedir(proc);
 400        err = 0;
 401out_free_mmap:
 402        free(mmap_event);
 403out_free_comm:
 404        free(comm_event);
 405out:
 406        return err;
 407}
 408
 409struct process_symbol_args {
 410        const char *name;
 411        u64        start;
 412};
 413
 414static int find_symbol_cb(void *arg, const char *name, char type,
 415                          u64 start, u64 end __used)
 416{
 417        struct process_symbol_args *args = arg;
 418
 419        /*
 420         * Must be a function or at least an alias, as in PARISC64, where "_text" is
 421         * an 'A' to the same address as "_stext".
 422         */
 423        if (!(symbol_type__is_a(type, MAP__FUNCTION) ||
 424              type == 'A') || strcmp(name, args->name))
 425                return 0;
 426
 427        args->start = start;
 428        return 1;
 429}
 430
 431int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
 432                                       perf_event__handler_t process,
 433                                       struct machine *machine,
 434                                       const char *symbol_name)
 435{
 436        size_t size;
 437        const char *filename, *mmap_name;
 438        char path[PATH_MAX];
 439        char name_buff[PATH_MAX];
 440        struct map *map;
 441        int err;
 442        /*
 443         * We should get this from /sys/kernel/sections/.text, but till that is
 444         * available use this, and after it is use this as a fallback for older
 445         * kernels.
 446         */
 447        struct process_symbol_args args = { .name = symbol_name, };
 448        union perf_event *event = zalloc((sizeof(event->mmap) +
 449                                          machine->id_hdr_size));
 450        if (event == NULL) {
 451                pr_debug("Not enough memory synthesizing mmap event "
 452                         "for kernel modules\n");
 453                return -1;
 454        }
 455
 456        mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff));
 457        if (machine__is_host(machine)) {
 458                /*
 459                 * kernel uses PERF_RECORD_MISC_USER for user space maps,
 460                 * see kernel/perf_event.c __perf_event_mmap
 461                 */
 462                event->header.misc = PERF_RECORD_MISC_KERNEL;
 463                filename = "/proc/kallsyms";
 464        } else {
 465                event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
 466                if (machine__is_default_guest(machine))
 467                        filename = (char *) symbol_conf.default_guest_kallsyms;
 468                else {
 469                        sprintf(path, "%s/proc/kallsyms", machine->root_dir);
 470                        filename = path;
 471                }
 472        }
 473
 474        if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0)
 475                return -ENOENT;
 476
 477        map = machine->vmlinux_maps[MAP__FUNCTION];
 478        size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
 479                        "%s%s", mmap_name, symbol_name) + 1;
 480        size = ALIGN(size, sizeof(u64));
 481        event->mmap.header.type = PERF_RECORD_MMAP;
 482        event->mmap.header.size = (sizeof(event->mmap) -
 483                        (sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
 484        event->mmap.pgoff = args.start;
 485        event->mmap.start = map->start;
 486        event->mmap.len   = map->end - event->mmap.start;
 487        event->mmap.pid   = machine->pid;
 488
 489        err = process(tool, event, &synth_sample, machine);
 490        free(event);
 491
 492        return err;
 493}
 494
 495size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
 496{
 497        return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid);
 498}
 499
 500int perf_event__process_comm(struct perf_tool *tool __used,
 501                             union perf_event *event,
 502                             struct perf_sample *sample __used,
 503                             struct machine *machine)
 504{
 505        struct thread *thread = machine__findnew_thread(machine, event->comm.tid);
 506
 507        if (dump_trace)
 508                perf_event__fprintf_comm(event, stdout);
 509
 510        if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
 511                dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
 512                return -1;
 513        }
 514
 515        return 0;
 516}
 517
 518int perf_event__process_lost(struct perf_tool *tool __used,
 519                             union perf_event *event,
 520                             struct perf_sample *sample __used,
 521                             struct machine *machine __used)
 522{
 523        dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
 524                    event->lost.id, event->lost.lost);
 525        return 0;
 526}
 527
 528static void perf_event__set_kernel_mmap_len(union perf_event *event,
 529                                            struct map **maps)
 530{
 531        maps[MAP__FUNCTION]->start = event->mmap.start;
 532        maps[MAP__FUNCTION]->end   = event->mmap.start + event->mmap.len;
 533        /*
 534         * Be a bit paranoid here, some perf.data file came with
 535         * a zero sized synthesized MMAP event for the kernel.
 536         */
 537        if (maps[MAP__FUNCTION]->end == 0)
 538                maps[MAP__FUNCTION]->end = ~0ULL;
 539}
 540
 541static int perf_event__process_kernel_mmap(struct perf_tool *tool __used,
 542                                           union perf_event *event,
 543                                           struct machine *machine)
 544{
 545        struct map *map;
 546        char kmmap_prefix[PATH_MAX];
 547        enum dso_kernel_type kernel_type;
 548        bool is_kernel_mmap;
 549
 550        machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
 551        if (machine__is_host(machine))
 552                kernel_type = DSO_TYPE_KERNEL;
 553        else
 554                kernel_type = DSO_TYPE_GUEST_KERNEL;
 555
 556        is_kernel_mmap = memcmp(event->mmap.filename,
 557                                kmmap_prefix,
 558                                strlen(kmmap_prefix) - 1) == 0;
 559        if (event->mmap.filename[0] == '/' ||
 560            (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
 561
 562                char short_module_name[1024];
 563                char *name, *dot;
 564
 565                if (event->mmap.filename[0] == '/') {
 566                        name = strrchr(event->mmap.filename, '/');
 567                        if (name == NULL)
 568                                goto out_problem;
 569
 570                        ++name; /* skip / */
 571                        dot = strrchr(name, '.');
 572                        if (dot == NULL)
 573                                goto out_problem;
 574                        snprintf(short_module_name, sizeof(short_module_name),
 575                                        "[%.*s]", (int)(dot - name), name);
 576                        strxfrchar(short_module_name, '-', '_');
 577                } else
 578                        strcpy(short_module_name, event->mmap.filename);
 579
 580                map = machine__new_module(machine, event->mmap.start,
 581                                          event->mmap.filename);
 582                if (map == NULL)
 583                        goto out_problem;
 584
 585                name = strdup(short_module_name);
 586                if (name == NULL)
 587                        goto out_problem;
 588
 589                map->dso->short_name = name;
 590                map->dso->sname_alloc = 1;
 591                map->end = map->start + event->mmap.len;
 592        } else if (is_kernel_mmap) {
 593                const char *symbol_name = (event->mmap.filename +
 594                                strlen(kmmap_prefix));
 595                /*
 596                 * Should be there already, from the build-id table in
 597                 * the header.
 598                 */
 599                struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
 600                                                     kmmap_prefix);
 601                if (kernel == NULL)
 602                        goto out_problem;
 603
 604                kernel->kernel = kernel_type;
 605                if (__machine__create_kernel_maps(machine, kernel) < 0)
 606                        goto out_problem;
 607
 608                perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps);
 609
 610                /*
 611                 * Avoid using a zero address (kptr_restrict) for the ref reloc
 612                 * symbol. Effectively having zero here means that at record
 613                 * time /proc/sys/kernel/kptr_restrict was non zero.
 614                 */
 615                if (event->mmap.pgoff != 0) {
 616                        maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
 617                                                         symbol_name,
 618                                                         event->mmap.pgoff);
 619                }
 620
 621                if (machine__is_default_guest(machine)) {
 622                        /*
 623                         * preload dso of guest kernel and modules
 624                         */
 625                        dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
 626                                  NULL);
 627                }
 628        }
 629        return 0;
 630out_problem:
 631        return -1;
 632}
 633
 634size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
 635{
 636        return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n",
 637                       event->mmap.pid, event->mmap.tid, event->mmap.start,
 638                       event->mmap.len, event->mmap.pgoff, event->mmap.filename);
 639}
 640
 641int perf_event__process_mmap(struct perf_tool *tool,
 642                             union perf_event *event,
 643                             struct perf_sample *sample __used,
 644                             struct machine *machine)
 645{
 646        struct thread *thread;
 647        struct map *map;
 648        u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 649        int ret = 0;
 650
 651        if (dump_trace)
 652                perf_event__fprintf_mmap(event, stdout);
 653
 654        if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
 655            cpumode == PERF_RECORD_MISC_KERNEL) {
 656                ret = perf_event__process_kernel_mmap(tool, event, machine);
 657                if (ret < 0)
 658                        goto out_problem;
 659                return 0;
 660        }
 661
 662        thread = machine__findnew_thread(machine, event->mmap.pid);
 663        if (thread == NULL)
 664                goto out_problem;
 665        map = map__new(&machine->user_dsos, event->mmap.start,
 666                        event->mmap.len, event->mmap.pgoff,
 667                        event->mmap.pid, event->mmap.filename,
 668                        MAP__FUNCTION);
 669        if (map == NULL)
 670                goto out_problem;
 671
 672        thread__insert_map(thread, map);
 673        return 0;
 674
 675out_problem:
 676        dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
 677        return 0;
 678}
 679
 680size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
 681{
 682        return fprintf(fp, "(%d:%d):(%d:%d)\n",
 683                       event->fork.pid, event->fork.tid,
 684                       event->fork.ppid, event->fork.ptid);
 685}
 686
 687int perf_event__process_task(struct perf_tool *tool __used,
 688                             union perf_event *event,
 689                             struct perf_sample *sample __used,
 690                              struct machine *machine)
 691{
 692        struct thread *thread = machine__findnew_thread(machine, event->fork.tid);
 693        struct thread *parent = machine__findnew_thread(machine, event->fork.ptid);
 694
 695        if (dump_trace)
 696                perf_event__fprintf_task(event, stdout);
 697
 698        if (event->header.type == PERF_RECORD_EXIT) {
 699                machine__remove_thread(machine, thread);
 700                return 0;
 701        }
 702
 703        if (thread == NULL || parent == NULL ||
 704            thread__fork(thread, parent) < 0) {
 705                dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
 706                return -1;
 707        }
 708
 709        return 0;
 710}
 711
 712size_t perf_event__fprintf(union perf_event *event, FILE *fp)
 713{
 714        size_t ret = fprintf(fp, "PERF_RECORD_%s",
 715                             perf_event__name(event->header.type));
 716
 717        switch (event->header.type) {
 718        case PERF_RECORD_COMM:
 719                ret += perf_event__fprintf_comm(event, fp);
 720                break;
 721        case PERF_RECORD_FORK:
 722        case PERF_RECORD_EXIT:
 723                ret += perf_event__fprintf_task(event, fp);
 724                break;
 725        case PERF_RECORD_MMAP:
 726                ret += perf_event__fprintf_mmap(event, fp);
 727                break;
 728        default:
 729                ret += fprintf(fp, "\n");
 730        }
 731
 732        return ret;
 733}
 734
 735int perf_event__process(struct perf_tool *tool, union perf_event *event,
 736                        struct perf_sample *sample, struct machine *machine)
 737{
 738        switch (event->header.type) {
 739        case PERF_RECORD_COMM:
 740                perf_event__process_comm(tool, event, sample, machine);
 741                break;
 742        case PERF_RECORD_MMAP:
 743                perf_event__process_mmap(tool, event, sample, machine);
 744                break;
 745        case PERF_RECORD_FORK:
 746        case PERF_RECORD_EXIT:
 747                perf_event__process_task(tool, event, sample, machine);
 748                break;
 749        case PERF_RECORD_LOST:
 750                perf_event__process_lost(tool, event, sample, machine);
 751        default:
 752                break;
 753        }
 754
 755        return 0;
 756}
 757
 758void thread__find_addr_map(struct thread *self,
 759                           struct machine *machine, u8 cpumode,
 760                           enum map_type type, u64 addr,
 761                           struct addr_location *al)
 762{
 763        struct map_groups *mg = &self->mg;
 764
 765        al->thread = self;
 766        al->addr = addr;
 767        al->cpumode = cpumode;
 768        al->filtered = false;
 769
 770        if (machine == NULL) {
 771                al->map = NULL;
 772                return;
 773        }
 774
 775        if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) {
 776                al->level = 'k';
 777                mg = &machine->kmaps;
 778        } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) {
 779                al->level = '.';
 780        } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) {
 781                al->level = 'g';
 782                mg = &machine->kmaps;
 783        } else {
 784                /*
 785                 * 'u' means guest os user space.
 786                 * TODO: We don't support guest user space. Might support late.
 787                 */
 788                if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest)
 789                        al->level = 'u';
 790                else
 791                        al->level = 'H';
 792                al->map = NULL;
 793
 794                if ((cpumode == PERF_RECORD_MISC_GUEST_USER ||
 795                        cpumode == PERF_RECORD_MISC_GUEST_KERNEL) &&
 796                        !perf_guest)
 797                        al->filtered = true;
 798                if ((cpumode == PERF_RECORD_MISC_USER ||
 799                        cpumode == PERF_RECORD_MISC_KERNEL) &&
 800                        !perf_host)
 801                        al->filtered = true;
 802
 803                return;
 804        }
 805try_again:
 806        al->map = map_groups__find(mg, type, al->addr);
 807        if (al->map == NULL) {
 808                /*
 809                 * If this is outside of all known maps, and is a negative
 810                 * address, try to look it up in the kernel dso, as it might be
 811                 * a vsyscall or vdso (which executes in user-mode).
 812                 *
 813                 * XXX This is nasty, we should have a symbol list in the
 814                 * "[vdso]" dso, but for now lets use the old trick of looking
 815                 * in the whole kernel symbol list.
 816                 */
 817                if ((long long)al->addr < 0 &&
 818                    cpumode == PERF_RECORD_MISC_USER &&
 819                    machine && mg != &machine->kmaps) {
 820                        mg = &machine->kmaps;
 821                        goto try_again;
 822                }
 823        } else
 824                al->addr = al->map->map_ip(al->map, al->addr);
 825}
 826
 827void thread__find_addr_location(struct thread *thread, struct machine *machine,
 828                                u8 cpumode, enum map_type type, u64 addr,
 829                                struct addr_location *al,
 830                                symbol_filter_t filter)
 831{
 832        thread__find_addr_map(thread, machine, cpumode, type, addr, al);
 833        if (al->map != NULL)
 834                al->sym = map__find_symbol(al->map, al->addr, filter);
 835        else
 836                al->sym = NULL;
 837}
 838
 839int perf_event__preprocess_sample(const union perf_event *event,
 840                                  struct machine *machine,
 841                                  struct addr_location *al,
 842                                  struct perf_sample *sample,
 843                                  symbol_filter_t filter)
 844{
 845        u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
 846        struct thread *thread = machine__findnew_thread(machine, event->ip.pid);
 847
 848        if (thread == NULL)
 849                return -1;
 850
 851        if (symbol_conf.comm_list &&
 852            !strlist__has_entry(symbol_conf.comm_list, thread->comm))
 853                goto out_filtered;
 854
 855        dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid);
 856        /*
 857         * Have we already created the kernel maps for this machine?
 858         *
 859         * This should have happened earlier, when we processed the kernel MMAP
 860         * events, but for older perf.data files there was no such thing, so do
 861         * it now.
 862         */
 863        if (cpumode == PERF_RECORD_MISC_KERNEL &&
 864            machine->vmlinux_maps[MAP__FUNCTION] == NULL)
 865                machine__create_kernel_maps(machine);
 866
 867        thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
 868                              event->ip.ip, al);
 869        dump_printf(" ...... dso: %s\n",
 870                    al->map ? al->map->dso->long_name :
 871                        al->level == 'H' ? "[hypervisor]" : "<not found>");
 872        al->sym = NULL;
 873        al->cpu = sample->cpu;
 874
 875        if (al->map) {
 876                struct dso *dso = al->map->dso;
 877
 878                if (symbol_conf.dso_list &&
 879                    (!dso || !(strlist__has_entry(symbol_conf.dso_list,
 880                                                  dso->short_name) ||
 881                               (dso->short_name != dso->long_name &&
 882                                strlist__has_entry(symbol_conf.dso_list,
 883                                                   dso->long_name)))))
 884                        goto out_filtered;
 885
 886                al->sym = map__find_symbol(al->map, al->addr, filter);
 887        }
 888
 889        if (symbol_conf.sym_list && al->sym &&
 890            !strlist__has_entry(symbol_conf.sym_list, al->sym->name))
 891                goto out_filtered;
 892
 893        return 0;
 894
 895out_filtered:
 896        al->filtered = true;
 897        return 0;
 898}
 899