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