1 #include <linux/types.h> 2 #include <sys/mman.h> 3 #include "event.h" 4 #include "debug.h" 5 #include "hist.h" 6 #include "machine.h" 7 #include "sort.h" 8 #include "string.h" 9 #include "strlist.h" 10 #include "thread.h" 11 #include "thread_map.h" 12 #include "symbol/kallsyms.h" 13 14 static const char *perf_event__names[] = { 15 [0] = "TOTAL", 16 [PERF_RECORD_MMAP] = "MMAP", 17 [PERF_RECORD_MMAP2] = "MMAP2", 18 [PERF_RECORD_LOST] = "LOST", 19 [PERF_RECORD_COMM] = "COMM", 20 [PERF_RECORD_EXIT] = "EXIT", 21 [PERF_RECORD_THROTTLE] = "THROTTLE", 22 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE", 23 [PERF_RECORD_FORK] = "FORK", 24 [PERF_RECORD_READ] = "READ", 25 [PERF_RECORD_SAMPLE] = "SAMPLE", 26 [PERF_RECORD_AUX] = "AUX", 27 [PERF_RECORD_ITRACE_START] = "ITRACE_START", 28 [PERF_RECORD_LOST_SAMPLES] = "LOST_SAMPLES", 29 [PERF_RECORD_SWITCH] = "SWITCH", 30 [PERF_RECORD_SWITCH_CPU_WIDE] = "SWITCH_CPU_WIDE", 31 [PERF_RECORD_HEADER_ATTR] = "ATTR", 32 [PERF_RECORD_HEADER_EVENT_TYPE] = "EVENT_TYPE", 33 [PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA", 34 [PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID", 35 [PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND", 36 [PERF_RECORD_ID_INDEX] = "ID_INDEX", 37 [PERF_RECORD_AUXTRACE_INFO] = "AUXTRACE_INFO", 38 [PERF_RECORD_AUXTRACE] = "AUXTRACE", 39 [PERF_RECORD_AUXTRACE_ERROR] = "AUXTRACE_ERROR", 40 }; 41 42 const char *perf_event__name(unsigned int id) 43 { 44 if (id >= ARRAY_SIZE(perf_event__names)) 45 return "INVALID"; 46 if (!perf_event__names[id]) 47 return "UNKNOWN"; 48 return perf_event__names[id]; 49 } 50 51 static struct perf_sample synth_sample = { 52 .pid = -1, 53 .tid = -1, 54 .time = -1, 55 .stream_id = -1, 56 .cpu = -1, 57 .period = 1, 58 }; 59 60 /* 61 * Assumes that the first 4095 bytes of /proc/pid/stat contains 62 * the comm, tgid and ppid. 63 */ 64 static int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len, 65 pid_t *tgid, pid_t *ppid) 66 { 67 char filename[PATH_MAX]; 68 char bf[4096]; 69 int fd; 70 size_t size = 0, n; 71 char *nl, *name, *tgids, *ppids; 72 73 *tgid = -1; 74 *ppid = -1; 75 76 snprintf(filename, sizeof(filename), "/proc/%d/status", pid); 77 78 fd = open(filename, O_RDONLY); 79 if (fd < 0) { 80 pr_debug("couldn't open %s\n", filename); 81 return -1; 82 } 83 84 n = read(fd, bf, sizeof(bf) - 1); 85 close(fd); 86 if (n <= 0) { 87 pr_warning("Couldn't get COMM, tigd and ppid for pid %d\n", 88 pid); 89 return -1; 90 } 91 bf[n] = '\0'; 92 93 name = strstr(bf, "Name:"); 94 tgids = strstr(bf, "Tgid:"); 95 ppids = strstr(bf, "PPid:"); 96 97 if (name) { 98 name += 5; /* strlen("Name:") */ 99 100 while (*name && isspace(*name)) 101 ++name; 102 103 nl = strchr(name, '\n'); 104 if (nl) 105 *nl = '\0'; 106 107 size = strlen(name); 108 if (size >= len) 109 size = len - 1; 110 memcpy(comm, name, size); 111 comm[size] = '\0'; 112 } else { 113 pr_debug("Name: string not found for pid %d\n", pid); 114 } 115 116 if (tgids) { 117 tgids += 5; /* strlen("Tgid:") */ 118 *tgid = atoi(tgids); 119 } else { 120 pr_debug("Tgid: string not found for pid %d\n", pid); 121 } 122 123 if (ppids) { 124 ppids += 5; /* strlen("PPid:") */ 125 *ppid = atoi(ppids); 126 } else { 127 pr_debug("PPid: string not found for pid %d\n", pid); 128 } 129 130 return 0; 131 } 132 133 static int perf_event__prepare_comm(union perf_event *event, pid_t pid, 134 struct machine *machine, 135 pid_t *tgid, pid_t *ppid) 136 { 137 size_t size; 138 139 *ppid = -1; 140 141 memset(&event->comm, 0, sizeof(event->comm)); 142 143 if (machine__is_host(machine)) { 144 if (perf_event__get_comm_ids(pid, event->comm.comm, 145 sizeof(event->comm.comm), 146 tgid, ppid) != 0) { 147 return -1; 148 } 149 } else { 150 *tgid = machine->pid; 151 } 152 153 if (*tgid < 0) 154 return -1; 155 156 event->comm.pid = *tgid; 157 event->comm.header.type = PERF_RECORD_COMM; 158 159 size = strlen(event->comm.comm) + 1; 160 size = PERF_ALIGN(size, sizeof(u64)); 161 memset(event->comm.comm + size, 0, machine->id_hdr_size); 162 event->comm.header.size = (sizeof(event->comm) - 163 (sizeof(event->comm.comm) - size) + 164 machine->id_hdr_size); 165 event->comm.tid = pid; 166 167 return 0; 168 } 169 170 static pid_t perf_event__synthesize_comm(struct perf_tool *tool, 171 union perf_event *event, pid_t pid, 172 perf_event__handler_t process, 173 struct machine *machine) 174 { 175 pid_t tgid, ppid; 176 177 if (perf_event__prepare_comm(event, pid, machine, &tgid, &ppid) != 0) 178 return -1; 179 180 if (process(tool, event, &synth_sample, machine) != 0) 181 return -1; 182 183 return tgid; 184 } 185 186 static int perf_event__synthesize_fork(struct perf_tool *tool, 187 union perf_event *event, 188 pid_t pid, pid_t tgid, pid_t ppid, 189 perf_event__handler_t process, 190 struct machine *machine) 191 { 192 memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size); 193 194 /* 195 * for main thread set parent to ppid from status file. For other 196 * threads set parent pid to main thread. ie., assume main thread 197 * spawns all threads in a process 198 */ 199 if (tgid == pid) { 200 event->fork.ppid = ppid; 201 event->fork.ptid = ppid; 202 } else { 203 event->fork.ppid = tgid; 204 event->fork.ptid = tgid; 205 } 206 event->fork.pid = tgid; 207 event->fork.tid = pid; 208 event->fork.header.type = PERF_RECORD_FORK; 209 210 event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size); 211 212 if (process(tool, event, &synth_sample, machine) != 0) 213 return -1; 214 215 return 0; 216 } 217 218 int perf_event__synthesize_mmap_events(struct perf_tool *tool, 219 union perf_event *event, 220 pid_t pid, pid_t tgid, 221 perf_event__handler_t process, 222 struct machine *machine, 223 bool mmap_data, 224 unsigned int proc_map_timeout) 225 { 226 char filename[PATH_MAX]; 227 FILE *fp; 228 unsigned long long t; 229 bool truncation = false; 230 unsigned long long timeout = proc_map_timeout * 1000000ULL; 231 int rc = 0; 232 233 if (machine__is_default_guest(machine)) 234 return 0; 235 236 snprintf(filename, sizeof(filename), "%s/proc/%d/maps", 237 machine->root_dir, pid); 238 239 fp = fopen(filename, "r"); 240 if (fp == NULL) { 241 /* 242 * We raced with a task exiting - just return: 243 */ 244 pr_debug("couldn't open %s\n", filename); 245 return -1; 246 } 247 248 event->header.type = PERF_RECORD_MMAP2; 249 t = rdclock(); 250 251 while (1) { 252 char bf[BUFSIZ]; 253 char prot[5]; 254 char execname[PATH_MAX]; 255 char anonstr[] = "//anon"; 256 unsigned int ino; 257 size_t size; 258 ssize_t n; 259 260 if (fgets(bf, sizeof(bf), fp) == NULL) 261 break; 262 263 if ((rdclock() - t) > timeout) { 264 pr_warning("Reading %s time out. " 265 "You may want to increase " 266 "the time limit by --proc-map-timeout\n", 267 filename); 268 truncation = true; 269 goto out; 270 } 271 272 /* ensure null termination since stack will be reused. */ 273 strcpy(execname, ""); 274 275 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 276 n = sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %x:%x %u %s\n", 277 &event->mmap2.start, &event->mmap2.len, prot, 278 &event->mmap2.pgoff, &event->mmap2.maj, 279 &event->mmap2.min, 280 &ino, execname); 281 282 /* 283 * Anon maps don't have the execname. 284 */ 285 if (n < 7) 286 continue; 287 288 event->mmap2.ino = (u64)ino; 289 290 /* 291 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c 292 */ 293 if (machine__is_host(machine)) 294 event->header.misc = PERF_RECORD_MISC_USER; 295 else 296 event->header.misc = PERF_RECORD_MISC_GUEST_USER; 297 298 /* map protection and flags bits */ 299 event->mmap2.prot = 0; 300 event->mmap2.flags = 0; 301 if (prot[0] == 'r') 302 event->mmap2.prot |= PROT_READ; 303 if (prot[1] == 'w') 304 event->mmap2.prot |= PROT_WRITE; 305 if (prot[2] == 'x') 306 event->mmap2.prot |= PROT_EXEC; 307 308 if (prot[3] == 's') 309 event->mmap2.flags |= MAP_SHARED; 310 else 311 event->mmap2.flags |= MAP_PRIVATE; 312 313 if (prot[2] != 'x') { 314 if (!mmap_data || prot[0] != 'r') 315 continue; 316 317 event->header.misc |= PERF_RECORD_MISC_MMAP_DATA; 318 } 319 320 out: 321 if (truncation) 322 event->header.misc |= PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT; 323 324 if (!strcmp(execname, "")) 325 strcpy(execname, anonstr); 326 327 size = strlen(execname) + 1; 328 memcpy(event->mmap2.filename, execname, size); 329 size = PERF_ALIGN(size, sizeof(u64)); 330 event->mmap2.len -= event->mmap.start; 331 event->mmap2.header.size = (sizeof(event->mmap2) - 332 (sizeof(event->mmap2.filename) - size)); 333 memset(event->mmap2.filename + size, 0, machine->id_hdr_size); 334 event->mmap2.header.size += machine->id_hdr_size; 335 event->mmap2.pid = tgid; 336 event->mmap2.tid = pid; 337 338 if (process(tool, event, &synth_sample, machine) != 0) { 339 rc = -1; 340 break; 341 } 342 343 if (truncation) 344 break; 345 } 346 347 fclose(fp); 348 return rc; 349 } 350 351 int perf_event__synthesize_modules(struct perf_tool *tool, 352 perf_event__handler_t process, 353 struct machine *machine) 354 { 355 int rc = 0; 356 struct map *pos; 357 struct map_groups *kmaps = &machine->kmaps; 358 struct maps *maps = &kmaps->maps[MAP__FUNCTION]; 359 union perf_event *event = zalloc((sizeof(event->mmap) + 360 machine->id_hdr_size)); 361 if (event == NULL) { 362 pr_debug("Not enough memory synthesizing mmap event " 363 "for kernel modules\n"); 364 return -1; 365 } 366 367 event->header.type = PERF_RECORD_MMAP; 368 369 /* 370 * kernel uses 0 for user space maps, see kernel/perf_event.c 371 * __perf_event_mmap 372 */ 373 if (machine__is_host(machine)) 374 event->header.misc = PERF_RECORD_MISC_KERNEL; 375 else 376 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 377 378 for (pos = maps__first(maps); pos; pos = map__next(pos)) { 379 size_t size; 380 381 if (pos->dso->kernel) 382 continue; 383 384 size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64)); 385 event->mmap.header.type = PERF_RECORD_MMAP; 386 event->mmap.header.size = (sizeof(event->mmap) - 387 (sizeof(event->mmap.filename) - size)); 388 memset(event->mmap.filename + size, 0, machine->id_hdr_size); 389 event->mmap.header.size += machine->id_hdr_size; 390 event->mmap.start = pos->start; 391 event->mmap.len = pos->end - pos->start; 392 event->mmap.pid = machine->pid; 393 394 memcpy(event->mmap.filename, pos->dso->long_name, 395 pos->dso->long_name_len + 1); 396 if (process(tool, event, &synth_sample, machine) != 0) { 397 rc = -1; 398 break; 399 } 400 } 401 402 free(event); 403 return rc; 404 } 405 406 static int __event__synthesize_thread(union perf_event *comm_event, 407 union perf_event *mmap_event, 408 union perf_event *fork_event, 409 pid_t pid, int full, 410 perf_event__handler_t process, 411 struct perf_tool *tool, 412 struct machine *machine, 413 bool mmap_data, 414 unsigned int proc_map_timeout) 415 { 416 char filename[PATH_MAX]; 417 DIR *tasks; 418 struct dirent dirent, *next; 419 pid_t tgid, ppid; 420 int rc = 0; 421 422 /* special case: only send one comm event using passed in pid */ 423 if (!full) { 424 tgid = perf_event__synthesize_comm(tool, comm_event, pid, 425 process, machine); 426 427 if (tgid == -1) 428 return -1; 429 430 return perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 431 process, machine, mmap_data, 432 proc_map_timeout); 433 } 434 435 if (machine__is_default_guest(machine)) 436 return 0; 437 438 snprintf(filename, sizeof(filename), "%s/proc/%d/task", 439 machine->root_dir, pid); 440 441 tasks = opendir(filename); 442 if (tasks == NULL) { 443 pr_debug("couldn't open %s\n", filename); 444 return 0; 445 } 446 447 while (!readdir_r(tasks, &dirent, &next) && next) { 448 char *end; 449 pid_t _pid; 450 451 _pid = strtol(dirent.d_name, &end, 10); 452 if (*end) 453 continue; 454 455 rc = -1; 456 if (perf_event__prepare_comm(comm_event, _pid, machine, 457 &tgid, &ppid) != 0) 458 break; 459 460 if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid, 461 ppid, process, machine) < 0) 462 break; 463 /* 464 * Send the prepared comm event 465 */ 466 if (process(tool, comm_event, &synth_sample, machine) != 0) 467 break; 468 469 rc = 0; 470 if (_pid == pid) { 471 /* process the parent's maps too */ 472 rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid, 473 process, machine, mmap_data, proc_map_timeout); 474 if (rc) 475 break; 476 } 477 } 478 479 closedir(tasks); 480 return rc; 481 } 482 483 int perf_event__synthesize_thread_map(struct perf_tool *tool, 484 struct thread_map *threads, 485 perf_event__handler_t process, 486 struct machine *machine, 487 bool mmap_data, 488 unsigned int proc_map_timeout) 489 { 490 union perf_event *comm_event, *mmap_event, *fork_event; 491 int err = -1, thread, j; 492 493 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 494 if (comm_event == NULL) 495 goto out; 496 497 mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); 498 if (mmap_event == NULL) 499 goto out_free_comm; 500 501 fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); 502 if (fork_event == NULL) 503 goto out_free_mmap; 504 505 err = 0; 506 for (thread = 0; thread < threads->nr; ++thread) { 507 if (__event__synthesize_thread(comm_event, mmap_event, 508 fork_event, 509 thread_map__pid(threads, thread), 0, 510 process, tool, machine, 511 mmap_data, proc_map_timeout)) { 512 err = -1; 513 break; 514 } 515 516 /* 517 * comm.pid is set to thread group id by 518 * perf_event__synthesize_comm 519 */ 520 if ((int) comm_event->comm.pid != thread_map__pid(threads, thread)) { 521 bool need_leader = true; 522 523 /* is thread group leader in thread_map? */ 524 for (j = 0; j < threads->nr; ++j) { 525 if ((int) comm_event->comm.pid == thread_map__pid(threads, j)) { 526 need_leader = false; 527 break; 528 } 529 } 530 531 /* if not, generate events for it */ 532 if (need_leader && 533 __event__synthesize_thread(comm_event, mmap_event, 534 fork_event, 535 comm_event->comm.pid, 0, 536 process, tool, machine, 537 mmap_data, proc_map_timeout)) { 538 err = -1; 539 break; 540 } 541 } 542 } 543 free(fork_event); 544 out_free_mmap: 545 free(mmap_event); 546 out_free_comm: 547 free(comm_event); 548 out: 549 return err; 550 } 551 552 int perf_event__synthesize_threads(struct perf_tool *tool, 553 perf_event__handler_t process, 554 struct machine *machine, 555 bool mmap_data, 556 unsigned int proc_map_timeout) 557 { 558 DIR *proc; 559 char proc_path[PATH_MAX]; 560 struct dirent dirent, *next; 561 union perf_event *comm_event, *mmap_event, *fork_event; 562 int err = -1; 563 564 if (machine__is_default_guest(machine)) 565 return 0; 566 567 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size); 568 if (comm_event == NULL) 569 goto out; 570 571 mmap_event = malloc(sizeof(mmap_event->mmap) + machine->id_hdr_size); 572 if (mmap_event == NULL) 573 goto out_free_comm; 574 575 fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size); 576 if (fork_event == NULL) 577 goto out_free_mmap; 578 579 snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir); 580 proc = opendir(proc_path); 581 582 if (proc == NULL) 583 goto out_free_fork; 584 585 while (!readdir_r(proc, &dirent, &next) && next) { 586 char *end; 587 pid_t pid = strtol(dirent.d_name, &end, 10); 588 589 if (*end) /* only interested in proper numerical dirents */ 590 continue; 591 /* 592 * We may race with exiting thread, so don't stop just because 593 * one thread couldn't be synthesized. 594 */ 595 __event__synthesize_thread(comm_event, mmap_event, fork_event, pid, 596 1, process, tool, machine, mmap_data, 597 proc_map_timeout); 598 } 599 600 err = 0; 601 closedir(proc); 602 out_free_fork: 603 free(fork_event); 604 out_free_mmap: 605 free(mmap_event); 606 out_free_comm: 607 free(comm_event); 608 out: 609 return err; 610 } 611 612 struct process_symbol_args { 613 const char *name; 614 u64 start; 615 }; 616 617 static int find_symbol_cb(void *arg, const char *name, char type, 618 u64 start) 619 { 620 struct process_symbol_args *args = arg; 621 622 /* 623 * Must be a function or at least an alias, as in PARISC64, where "_text" is 624 * an 'A' to the same address as "_stext". 625 */ 626 if (!(symbol_type__is_a(type, MAP__FUNCTION) || 627 type == 'A') || strcmp(name, args->name)) 628 return 0; 629 630 args->start = start; 631 return 1; 632 } 633 634 u64 kallsyms__get_function_start(const char *kallsyms_filename, 635 const char *symbol_name) 636 { 637 struct process_symbol_args args = { .name = symbol_name, }; 638 639 if (kallsyms__parse(kallsyms_filename, &args, find_symbol_cb) <= 0) 640 return 0; 641 642 return args.start; 643 } 644 645 int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 646 perf_event__handler_t process, 647 struct machine *machine) 648 { 649 size_t size; 650 const char *mmap_name; 651 char name_buff[PATH_MAX]; 652 struct map *map; 653 struct kmap *kmap; 654 int err; 655 union perf_event *event; 656 657 if (machine->vmlinux_maps[0] == NULL) 658 return -1; 659 660 /* 661 * We should get this from /sys/kernel/sections/.text, but till that is 662 * available use this, and after it is use this as a fallback for older 663 * kernels. 664 */ 665 event = zalloc((sizeof(event->mmap) + machine->id_hdr_size)); 666 if (event == NULL) { 667 pr_debug("Not enough memory synthesizing mmap event " 668 "for kernel modules\n"); 669 return -1; 670 } 671 672 mmap_name = machine__mmap_name(machine, name_buff, sizeof(name_buff)); 673 if (machine__is_host(machine)) { 674 /* 675 * kernel uses PERF_RECORD_MISC_USER for user space maps, 676 * see kernel/perf_event.c __perf_event_mmap 677 */ 678 event->header.misc = PERF_RECORD_MISC_KERNEL; 679 } else { 680 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 681 } 682 683 map = machine->vmlinux_maps[MAP__FUNCTION]; 684 kmap = map__kmap(map); 685 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 686 "%s%s", mmap_name, kmap->ref_reloc_sym->name) + 1; 687 size = PERF_ALIGN(size, sizeof(u64)); 688 event->mmap.header.type = PERF_RECORD_MMAP; 689 event->mmap.header.size = (sizeof(event->mmap) - 690 (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); 691 event->mmap.pgoff = kmap->ref_reloc_sym->addr; 692 event->mmap.start = map->start; 693 event->mmap.len = map->end - event->mmap.start; 694 event->mmap.pid = machine->pid; 695 696 err = process(tool, event, &synth_sample, machine); 697 free(event); 698 699 return err; 700 } 701 702 size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) 703 { 704 const char *s; 705 706 if (event->header.misc & PERF_RECORD_MISC_COMM_EXEC) 707 s = " exec"; 708 else 709 s = ""; 710 711 return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid); 712 } 713 714 int perf_event__process_comm(struct perf_tool *tool __maybe_unused, 715 union perf_event *event, 716 struct perf_sample *sample, 717 struct machine *machine) 718 { 719 return machine__process_comm_event(machine, event, sample); 720 } 721 722 int perf_event__process_lost(struct perf_tool *tool __maybe_unused, 723 union perf_event *event, 724 struct perf_sample *sample, 725 struct machine *machine) 726 { 727 return machine__process_lost_event(machine, event, sample); 728 } 729 730 int perf_event__process_aux(struct perf_tool *tool __maybe_unused, 731 union perf_event *event, 732 struct perf_sample *sample __maybe_unused, 733 struct machine *machine) 734 { 735 return machine__process_aux_event(machine, event); 736 } 737 738 int perf_event__process_itrace_start(struct perf_tool *tool __maybe_unused, 739 union perf_event *event, 740 struct perf_sample *sample __maybe_unused, 741 struct machine *machine) 742 { 743 return machine__process_itrace_start_event(machine, event); 744 } 745 746 int perf_event__process_lost_samples(struct perf_tool *tool __maybe_unused, 747 union perf_event *event, 748 struct perf_sample *sample, 749 struct machine *machine) 750 { 751 return machine__process_lost_samples_event(machine, event, sample); 752 } 753 754 int perf_event__process_switch(struct perf_tool *tool __maybe_unused, 755 union perf_event *event, 756 struct perf_sample *sample __maybe_unused, 757 struct machine *machine) 758 { 759 return machine__process_switch_event(machine, event); 760 } 761 762 size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) 763 { 764 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %c %s\n", 765 event->mmap.pid, event->mmap.tid, event->mmap.start, 766 event->mmap.len, event->mmap.pgoff, 767 (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x', 768 event->mmap.filename); 769 } 770 771 size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) 772 { 773 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 774 " %02x:%02x %"PRIu64" %"PRIu64"]: %c%c%c%c %s\n", 775 event->mmap2.pid, event->mmap2.tid, event->mmap2.start, 776 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj, 777 event->mmap2.min, event->mmap2.ino, 778 event->mmap2.ino_generation, 779 (event->mmap2.prot & PROT_READ) ? 'r' : '-', 780 (event->mmap2.prot & PROT_WRITE) ? 'w' : '-', 781 (event->mmap2.prot & PROT_EXEC) ? 'x' : '-', 782 (event->mmap2.flags & MAP_SHARED) ? 's' : 'p', 783 event->mmap2.filename); 784 } 785 786 int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, 787 union perf_event *event, 788 struct perf_sample *sample, 789 struct machine *machine) 790 { 791 return machine__process_mmap_event(machine, event, sample); 792 } 793 794 int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused, 795 union perf_event *event, 796 struct perf_sample *sample, 797 struct machine *machine) 798 { 799 return machine__process_mmap2_event(machine, event, sample); 800 } 801 802 size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) 803 { 804 return fprintf(fp, "(%d:%d):(%d:%d)\n", 805 event->fork.pid, event->fork.tid, 806 event->fork.ppid, event->fork.ptid); 807 } 808 809 int perf_event__process_fork(struct perf_tool *tool __maybe_unused, 810 union perf_event *event, 811 struct perf_sample *sample, 812 struct machine *machine) 813 { 814 return machine__process_fork_event(machine, event, sample); 815 } 816 817 int perf_event__process_exit(struct perf_tool *tool __maybe_unused, 818 union perf_event *event, 819 struct perf_sample *sample, 820 struct machine *machine) 821 { 822 return machine__process_exit_event(machine, event, sample); 823 } 824 825 size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp) 826 { 827 return fprintf(fp, " offset: %#"PRIx64" size: %#"PRIx64" flags: %#"PRIx64" [%s%s]\n", 828 event->aux.aux_offset, event->aux.aux_size, 829 event->aux.flags, 830 event->aux.flags & PERF_AUX_FLAG_TRUNCATED ? "T" : "", 831 event->aux.flags & PERF_AUX_FLAG_OVERWRITE ? "O" : ""); 832 } 833 834 size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp) 835 { 836 return fprintf(fp, " pid: %u tid: %u\n", 837 event->itrace_start.pid, event->itrace_start.tid); 838 } 839 840 size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp) 841 { 842 bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT; 843 const char *in_out = out ? "OUT" : "IN "; 844 845 if (event->header.type == PERF_RECORD_SWITCH) 846 return fprintf(fp, " %s\n", in_out); 847 848 return fprintf(fp, " %s %s pid/tid: %5u/%-5u\n", 849 in_out, out ? "next" : "prev", 850 event->context_switch.next_prev_pid, 851 event->context_switch.next_prev_tid); 852 } 853 854 size_t perf_event__fprintf(union perf_event *event, FILE *fp) 855 { 856 size_t ret = fprintf(fp, "PERF_RECORD_%s", 857 perf_event__name(event->header.type)); 858 859 switch (event->header.type) { 860 case PERF_RECORD_COMM: 861 ret += perf_event__fprintf_comm(event, fp); 862 break; 863 case PERF_RECORD_FORK: 864 case PERF_RECORD_EXIT: 865 ret += perf_event__fprintf_task(event, fp); 866 break; 867 case PERF_RECORD_MMAP: 868 ret += perf_event__fprintf_mmap(event, fp); 869 break; 870 case PERF_RECORD_MMAP2: 871 ret += perf_event__fprintf_mmap2(event, fp); 872 break; 873 case PERF_RECORD_AUX: 874 ret += perf_event__fprintf_aux(event, fp); 875 break; 876 case PERF_RECORD_ITRACE_START: 877 ret += perf_event__fprintf_itrace_start(event, fp); 878 break; 879 case PERF_RECORD_SWITCH: 880 case PERF_RECORD_SWITCH_CPU_WIDE: 881 ret += perf_event__fprintf_switch(event, fp); 882 break; 883 default: 884 ret += fprintf(fp, "\n"); 885 } 886 887 return ret; 888 } 889 890 int perf_event__process(struct perf_tool *tool __maybe_unused, 891 union perf_event *event, 892 struct perf_sample *sample, 893 struct machine *machine) 894 { 895 return machine__process_event(machine, event, sample); 896 } 897 898 void thread__find_addr_map(struct thread *thread, u8 cpumode, 899 enum map_type type, u64 addr, 900 struct addr_location *al) 901 { 902 struct map_groups *mg = thread->mg; 903 struct machine *machine = mg->machine; 904 bool load_map = false; 905 906 al->machine = machine; 907 al->thread = thread; 908 al->addr = addr; 909 al->cpumode = cpumode; 910 al->filtered = 0; 911 912 if (machine == NULL) { 913 al->map = NULL; 914 return; 915 } 916 917 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) { 918 al->level = 'k'; 919 mg = &machine->kmaps; 920 load_map = true; 921 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) { 922 al->level = '.'; 923 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { 924 al->level = 'g'; 925 mg = &machine->kmaps; 926 load_map = true; 927 } else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) { 928 al->level = 'u'; 929 } else { 930 al->level = 'H'; 931 al->map = NULL; 932 933 if ((cpumode == PERF_RECORD_MISC_GUEST_USER || 934 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) && 935 !perf_guest) 936 al->filtered |= (1 << HIST_FILTER__GUEST); 937 if ((cpumode == PERF_RECORD_MISC_USER || 938 cpumode == PERF_RECORD_MISC_KERNEL) && 939 !perf_host) 940 al->filtered |= (1 << HIST_FILTER__HOST); 941 942 return; 943 } 944 try_again: 945 al->map = map_groups__find(mg, type, al->addr); 946 if (al->map == NULL) { 947 /* 948 * If this is outside of all known maps, and is a negative 949 * address, try to look it up in the kernel dso, as it might be 950 * a vsyscall or vdso (which executes in user-mode). 951 * 952 * XXX This is nasty, we should have a symbol list in the 953 * "[vdso]" dso, but for now lets use the old trick of looking 954 * in the whole kernel symbol list. 955 */ 956 if (cpumode == PERF_RECORD_MISC_USER && machine && 957 mg != &machine->kmaps && 958 machine__kernel_ip(machine, al->addr)) { 959 mg = &machine->kmaps; 960 load_map = true; 961 goto try_again; 962 } 963 } else { 964 /* 965 * Kernel maps might be changed when loading symbols so loading 966 * must be done prior to using kernel maps. 967 */ 968 if (load_map) 969 map__load(al->map, machine->symbol_filter); 970 al->addr = al->map->map_ip(al->map, al->addr); 971 } 972 } 973 974 void thread__find_addr_location(struct thread *thread, 975 u8 cpumode, enum map_type type, u64 addr, 976 struct addr_location *al) 977 { 978 thread__find_addr_map(thread, cpumode, type, addr, al); 979 if (al->map != NULL) 980 al->sym = map__find_symbol(al->map, al->addr, 981 thread->mg->machine->symbol_filter); 982 else 983 al->sym = NULL; 984 } 985 986 /* 987 * Callers need to drop the reference to al->thread, obtained in 988 * machine__findnew_thread() 989 */ 990 int perf_event__preprocess_sample(const union perf_event *event, 991 struct machine *machine, 992 struct addr_location *al, 993 struct perf_sample *sample) 994 { 995 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 996 struct thread *thread = machine__findnew_thread(machine, sample->pid, 997 sample->tid); 998 999 if (thread == NULL) 1000 return -1; 1001 1002 dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); 1003 /* 1004 * Have we already created the kernel maps for this machine? 1005 * 1006 * This should have happened earlier, when we processed the kernel MMAP 1007 * events, but for older perf.data files there was no such thing, so do 1008 * it now. 1009 */ 1010 if (cpumode == PERF_RECORD_MISC_KERNEL && 1011 machine->vmlinux_maps[MAP__FUNCTION] == NULL) 1012 machine__create_kernel_maps(machine); 1013 1014 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, al); 1015 dump_printf(" ...... dso: %s\n", 1016 al->map ? al->map->dso->long_name : 1017 al->level == 'H' ? "[hypervisor]" : "<not found>"); 1018 1019 if (thread__is_filtered(thread)) 1020 al->filtered |= (1 << HIST_FILTER__THREAD); 1021 1022 al->sym = NULL; 1023 al->cpu = sample->cpu; 1024 1025 if (al->map) { 1026 struct dso *dso = al->map->dso; 1027 1028 if (symbol_conf.dso_list && 1029 (!dso || !(strlist__has_entry(symbol_conf.dso_list, 1030 dso->short_name) || 1031 (dso->short_name != dso->long_name && 1032 strlist__has_entry(symbol_conf.dso_list, 1033 dso->long_name))))) { 1034 al->filtered |= (1 << HIST_FILTER__DSO); 1035 } 1036 1037 al->sym = map__find_symbol(al->map, al->addr, 1038 machine->symbol_filter); 1039 } 1040 1041 if (symbol_conf.sym_list && 1042 (!al->sym || !strlist__has_entry(symbol_conf.sym_list, 1043 al->sym->name))) { 1044 al->filtered |= (1 << HIST_FILTER__SYMBOL); 1045 } 1046 1047 return 0; 1048 } 1049 1050 /* 1051 * The preprocess_sample method will return with reference counts for the 1052 * in it, when done using (and perhaps getting ref counts if needing to 1053 * keep a pointer to one of those entries) it must be paired with 1054 * addr_location__put(), so that the refcounts can be decremented. 1055 */ 1056 void addr_location__put(struct addr_location *al) 1057 { 1058 thread__zput(al->thread); 1059 } 1060 1061 bool is_bts_event(struct perf_event_attr *attr) 1062 { 1063 return attr->type == PERF_TYPE_HARDWARE && 1064 (attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) && 1065 attr->sample_period == 1; 1066 } 1067 1068 bool sample_addr_correlates_sym(struct perf_event_attr *attr) 1069 { 1070 if (attr->type == PERF_TYPE_SOFTWARE && 1071 (attr->config == PERF_COUNT_SW_PAGE_FAULTS || 1072 attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN || 1073 attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)) 1074 return true; 1075 1076 if (is_bts_event(attr)) 1077 return true; 1078 1079 return false; 1080 } 1081 1082 void perf_event__preprocess_sample_addr(union perf_event *event, 1083 struct perf_sample *sample, 1084 struct thread *thread, 1085 struct addr_location *al) 1086 { 1087 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 1088 1089 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->addr, al); 1090 if (!al->map) 1091 thread__find_addr_map(thread, cpumode, MAP__VARIABLE, 1092 sample->addr, al); 1093 1094 al->cpu = sample->cpu; 1095 al->sym = NULL; 1096 1097 if (al->map) 1098 al->sym = map__find_symbol(al->map, al->addr, NULL); 1099 } 1100