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