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