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 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 (__map__is_kernel(pos)) 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 = machine__kernel_map(machine); 653 struct kmap *kmap; 654 int err; 655 union perf_event *event; 656 657 if (map == 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 kmap = map__kmap(map); 684 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 685 "%s%s", mmap_name, kmap->ref_reloc_sym->name) + 1; 686 size = PERF_ALIGN(size, sizeof(u64)); 687 event->mmap.header.type = PERF_RECORD_MMAP; 688 event->mmap.header.size = (sizeof(event->mmap) - 689 (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); 690 event->mmap.pgoff = kmap->ref_reloc_sym->addr; 691 event->mmap.start = map->start; 692 event->mmap.len = map->end - event->mmap.start; 693 event->mmap.pid = machine->pid; 694 695 err = process(tool, event, &synth_sample, machine); 696 free(event); 697 698 return err; 699 } 700 701 size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) 702 { 703 const char *s; 704 705 if (event->header.misc & PERF_RECORD_MISC_COMM_EXEC) 706 s = " exec"; 707 else 708 s = ""; 709 710 return fprintf(fp, "%s: %s:%d/%d\n", s, event->comm.comm, event->comm.pid, event->comm.tid); 711 } 712 713 int perf_event__process_comm(struct perf_tool *tool __maybe_unused, 714 union perf_event *event, 715 struct perf_sample *sample, 716 struct machine *machine) 717 { 718 return machine__process_comm_event(machine, event, sample); 719 } 720 721 int perf_event__process_lost(struct perf_tool *tool __maybe_unused, 722 union perf_event *event, 723 struct perf_sample *sample, 724 struct machine *machine) 725 { 726 return machine__process_lost_event(machine, event, sample); 727 } 728 729 int perf_event__process_aux(struct perf_tool *tool __maybe_unused, 730 union perf_event *event, 731 struct perf_sample *sample __maybe_unused, 732 struct machine *machine) 733 { 734 return machine__process_aux_event(machine, event); 735 } 736 737 int perf_event__process_itrace_start(struct perf_tool *tool __maybe_unused, 738 union perf_event *event, 739 struct perf_sample *sample __maybe_unused, 740 struct machine *machine) 741 { 742 return machine__process_itrace_start_event(machine, event); 743 } 744 745 int perf_event__process_lost_samples(struct perf_tool *tool __maybe_unused, 746 union perf_event *event, 747 struct perf_sample *sample, 748 struct machine *machine) 749 { 750 return machine__process_lost_samples_event(machine, event, sample); 751 } 752 753 int perf_event__process_switch(struct perf_tool *tool __maybe_unused, 754 union perf_event *event, 755 struct perf_sample *sample __maybe_unused, 756 struct machine *machine) 757 { 758 return machine__process_switch_event(machine, event); 759 } 760 761 size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) 762 { 763 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %c %s\n", 764 event->mmap.pid, event->mmap.tid, event->mmap.start, 765 event->mmap.len, event->mmap.pgoff, 766 (event->header.misc & PERF_RECORD_MISC_MMAP_DATA) ? 'r' : 'x', 767 event->mmap.filename); 768 } 769 770 size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp) 771 { 772 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 773 " %02x:%02x %"PRIu64" %"PRIu64"]: %c%c%c%c %s\n", 774 event->mmap2.pid, event->mmap2.tid, event->mmap2.start, 775 event->mmap2.len, event->mmap2.pgoff, event->mmap2.maj, 776 event->mmap2.min, event->mmap2.ino, 777 event->mmap2.ino_generation, 778 (event->mmap2.prot & PROT_READ) ? 'r' : '-', 779 (event->mmap2.prot & PROT_WRITE) ? 'w' : '-', 780 (event->mmap2.prot & PROT_EXEC) ? 'x' : '-', 781 (event->mmap2.flags & MAP_SHARED) ? 's' : 'p', 782 event->mmap2.filename); 783 } 784 785 int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, 786 union perf_event *event, 787 struct perf_sample *sample, 788 struct machine *machine) 789 { 790 return machine__process_mmap_event(machine, event, sample); 791 } 792 793 int perf_event__process_mmap2(struct perf_tool *tool __maybe_unused, 794 union perf_event *event, 795 struct perf_sample *sample, 796 struct machine *machine) 797 { 798 return machine__process_mmap2_event(machine, event, sample); 799 } 800 801 size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) 802 { 803 return fprintf(fp, "(%d:%d):(%d:%d)\n", 804 event->fork.pid, event->fork.tid, 805 event->fork.ppid, event->fork.ptid); 806 } 807 808 int perf_event__process_fork(struct perf_tool *tool __maybe_unused, 809 union perf_event *event, 810 struct perf_sample *sample, 811 struct machine *machine) 812 { 813 return machine__process_fork_event(machine, event, sample); 814 } 815 816 int perf_event__process_exit(struct perf_tool *tool __maybe_unused, 817 union perf_event *event, 818 struct perf_sample *sample, 819 struct machine *machine) 820 { 821 return machine__process_exit_event(machine, event, sample); 822 } 823 824 size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp) 825 { 826 return fprintf(fp, " offset: %#"PRIx64" size: %#"PRIx64" flags: %#"PRIx64" [%s%s]\n", 827 event->aux.aux_offset, event->aux.aux_size, 828 event->aux.flags, 829 event->aux.flags & PERF_AUX_FLAG_TRUNCATED ? "T" : "", 830 event->aux.flags & PERF_AUX_FLAG_OVERWRITE ? "O" : ""); 831 } 832 833 size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp) 834 { 835 return fprintf(fp, " pid: %u tid: %u\n", 836 event->itrace_start.pid, event->itrace_start.tid); 837 } 838 839 size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp) 840 { 841 bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT; 842 const char *in_out = out ? "OUT" : "IN "; 843 844 if (event->header.type == PERF_RECORD_SWITCH) 845 return fprintf(fp, " %s\n", in_out); 846 847 return fprintf(fp, " %s %s pid/tid: %5u/%-5u\n", 848 in_out, out ? "next" : "prev", 849 event->context_switch.next_prev_pid, 850 event->context_switch.next_prev_tid); 851 } 852 853 size_t perf_event__fprintf(union perf_event *event, FILE *fp) 854 { 855 size_t ret = fprintf(fp, "PERF_RECORD_%s", 856 perf_event__name(event->header.type)); 857 858 switch (event->header.type) { 859 case PERF_RECORD_COMM: 860 ret += perf_event__fprintf_comm(event, fp); 861 break; 862 case PERF_RECORD_FORK: 863 case PERF_RECORD_EXIT: 864 ret += perf_event__fprintf_task(event, fp); 865 break; 866 case PERF_RECORD_MMAP: 867 ret += perf_event__fprintf_mmap(event, fp); 868 break; 869 case PERF_RECORD_MMAP2: 870 ret += perf_event__fprintf_mmap2(event, fp); 871 break; 872 case PERF_RECORD_AUX: 873 ret += perf_event__fprintf_aux(event, fp); 874 break; 875 case PERF_RECORD_ITRACE_START: 876 ret += perf_event__fprintf_itrace_start(event, fp); 877 break; 878 case PERF_RECORD_SWITCH: 879 case PERF_RECORD_SWITCH_CPU_WIDE: 880 ret += perf_event__fprintf_switch(event, fp); 881 break; 882 default: 883 ret += fprintf(fp, "\n"); 884 } 885 886 return ret; 887 } 888 889 int perf_event__process(struct perf_tool *tool __maybe_unused, 890 union perf_event *event, 891 struct perf_sample *sample, 892 struct machine *machine) 893 { 894 return machine__process_event(machine, event, sample); 895 } 896 897 void thread__find_addr_map(struct thread *thread, u8 cpumode, 898 enum map_type type, u64 addr, 899 struct addr_location *al) 900 { 901 struct map_groups *mg = thread->mg; 902 struct machine *machine = mg->machine; 903 bool load_map = false; 904 905 al->machine = machine; 906 al->thread = thread; 907 al->addr = addr; 908 al->cpumode = cpumode; 909 al->filtered = 0; 910 911 if (machine == NULL) { 912 al->map = NULL; 913 return; 914 } 915 916 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) { 917 al->level = 'k'; 918 mg = &machine->kmaps; 919 load_map = true; 920 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) { 921 al->level = '.'; 922 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { 923 al->level = 'g'; 924 mg = &machine->kmaps; 925 load_map = true; 926 } else if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) { 927 al->level = 'u'; 928 } else { 929 al->level = 'H'; 930 al->map = NULL; 931 932 if ((cpumode == PERF_RECORD_MISC_GUEST_USER || 933 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) && 934 !perf_guest) 935 al->filtered |= (1 << HIST_FILTER__GUEST); 936 if ((cpumode == PERF_RECORD_MISC_USER || 937 cpumode == PERF_RECORD_MISC_KERNEL) && 938 !perf_host) 939 al->filtered |= (1 << HIST_FILTER__HOST); 940 941 return; 942 } 943 try_again: 944 al->map = map_groups__find(mg, type, al->addr); 945 if (al->map == NULL) { 946 /* 947 * If this is outside of all known maps, and is a negative 948 * address, try to look it up in the kernel dso, as it might be 949 * a vsyscall or vdso (which executes in user-mode). 950 * 951 * XXX This is nasty, we should have a symbol list in the 952 * "[vdso]" dso, but for now lets use the old trick of looking 953 * in the whole kernel symbol list. 954 */ 955 if (cpumode == PERF_RECORD_MISC_USER && machine && 956 mg != &machine->kmaps && 957 machine__kernel_ip(machine, al->addr)) { 958 mg = &machine->kmaps; 959 load_map = true; 960 goto try_again; 961 } 962 } else { 963 /* 964 * Kernel maps might be changed when loading symbols so loading 965 * must be done prior to using kernel maps. 966 */ 967 if (load_map) 968 map__load(al->map, machine->symbol_filter); 969 al->addr = al->map->map_ip(al->map, al->addr); 970 } 971 } 972 973 void thread__find_addr_location(struct thread *thread, 974 u8 cpumode, enum map_type type, u64 addr, 975 struct addr_location *al) 976 { 977 thread__find_addr_map(thread, cpumode, type, addr, al); 978 if (al->map != NULL) 979 al->sym = map__find_symbol(al->map, al->addr, 980 thread->mg->machine->symbol_filter); 981 else 982 al->sym = NULL; 983 } 984 985 /* 986 * Callers need to drop the reference to al->thread, obtained in 987 * machine__findnew_thread() 988 */ 989 int perf_event__preprocess_sample(const union perf_event *event, 990 struct machine *machine, 991 struct addr_location *al, 992 struct perf_sample *sample) 993 { 994 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 995 struct thread *thread = machine__findnew_thread(machine, sample->pid, 996 sample->tid); 997 998 if (thread == NULL) 999 return -1; 1000 1001 dump_printf(" ... thread: %s:%d\n", thread__comm_str(thread), thread->tid); 1002 /* 1003 * Have we already created the kernel maps for this machine? 1004 * 1005 * This should have happened earlier, when we processed the kernel MMAP 1006 * events, but for older perf.data files there was no such thing, so do 1007 * it now. 1008 */ 1009 if (cpumode == PERF_RECORD_MISC_KERNEL && 1010 machine__kernel_map(machine) == NULL) 1011 machine__create_kernel_maps(machine); 1012 1013 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, al); 1014 dump_printf(" ...... dso: %s\n", 1015 al->map ? al->map->dso->long_name : 1016 al->level == 'H' ? "[hypervisor]" : "<not found>"); 1017 1018 if (thread__is_filtered(thread)) 1019 al->filtered |= (1 << HIST_FILTER__THREAD); 1020 1021 al->sym = NULL; 1022 al->cpu = sample->cpu; 1023 al->socket = -1; 1024 1025 if (al->cpu >= 0) { 1026 struct perf_env *env = machine->env; 1027 1028 if (env && env->cpu) 1029 al->socket = env->cpu[al->cpu].socket_id; 1030 } 1031 1032 if (al->map) { 1033 struct dso *dso = al->map->dso; 1034 1035 if (symbol_conf.dso_list && 1036 (!dso || !(strlist__has_entry(symbol_conf.dso_list, 1037 dso->short_name) || 1038 (dso->short_name != dso->long_name && 1039 strlist__has_entry(symbol_conf.dso_list, 1040 dso->long_name))))) { 1041 al->filtered |= (1 << HIST_FILTER__DSO); 1042 } 1043 1044 al->sym = map__find_symbol(al->map, al->addr, 1045 machine->symbol_filter); 1046 } 1047 1048 if (symbol_conf.sym_list && 1049 (!al->sym || !strlist__has_entry(symbol_conf.sym_list, 1050 al->sym->name))) { 1051 al->filtered |= (1 << HIST_FILTER__SYMBOL); 1052 } 1053 1054 return 0; 1055 } 1056 1057 /* 1058 * The preprocess_sample method will return with reference counts for the 1059 * in it, when done using (and perhaps getting ref counts if needing to 1060 * keep a pointer to one of those entries) it must be paired with 1061 * addr_location__put(), so that the refcounts can be decremented. 1062 */ 1063 void addr_location__put(struct addr_location *al) 1064 { 1065 thread__zput(al->thread); 1066 } 1067 1068 bool is_bts_event(struct perf_event_attr *attr) 1069 { 1070 return attr->type == PERF_TYPE_HARDWARE && 1071 (attr->config & PERF_COUNT_HW_BRANCH_INSTRUCTIONS) && 1072 attr->sample_period == 1; 1073 } 1074 1075 bool sample_addr_correlates_sym(struct perf_event_attr *attr) 1076 { 1077 if (attr->type == PERF_TYPE_SOFTWARE && 1078 (attr->config == PERF_COUNT_SW_PAGE_FAULTS || 1079 attr->config == PERF_COUNT_SW_PAGE_FAULTS_MIN || 1080 attr->config == PERF_COUNT_SW_PAGE_FAULTS_MAJ)) 1081 return true; 1082 1083 if (is_bts_event(attr)) 1084 return true; 1085 1086 return false; 1087 } 1088 1089 void perf_event__preprocess_sample_addr(union perf_event *event, 1090 struct perf_sample *sample, 1091 struct thread *thread, 1092 struct addr_location *al) 1093 { 1094 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 1095 1096 thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->addr, al); 1097 if (!al->map) 1098 thread__find_addr_map(thread, cpumode, MAP__VARIABLE, 1099 sample->addr, al); 1100 1101 al->cpu = sample->cpu; 1102 al->sym = NULL; 1103 1104 if (al->map) 1105 al->sym = map__find_symbol(al->map, al->addr, NULL); 1106 } 1107