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