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 free(event); 481 return -ENOENT; 482 } 483 484 map = machine->vmlinux_maps[MAP__FUNCTION]; 485 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 486 "%s%s", mmap_name, symbol_name) + 1; 487 size = PERF_ALIGN(size, sizeof(u64)); 488 event->mmap.header.type = PERF_RECORD_MMAP; 489 event->mmap.header.size = (sizeof(event->mmap) - 490 (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); 491 event->mmap.pgoff = args.start; 492 event->mmap.start = map->start; 493 event->mmap.len = map->end - event->mmap.start; 494 event->mmap.pid = machine->pid; 495 496 err = process(tool, event, &synth_sample, machine); 497 free(event); 498 499 return err; 500 } 501 502 size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp) 503 { 504 return fprintf(fp, ": %s:%d\n", event->comm.comm, event->comm.tid); 505 } 506 507 int perf_event__process_comm(struct perf_tool *tool __maybe_unused, 508 union perf_event *event, 509 struct perf_sample *sample __maybe_unused, 510 struct machine *machine) 511 { 512 return machine__process_comm_event(machine, event); 513 } 514 515 int perf_event__process_lost(struct perf_tool *tool __maybe_unused, 516 union perf_event *event, 517 struct perf_sample *sample __maybe_unused, 518 struct machine *machine) 519 { 520 return machine__process_lost_event(machine, event); 521 } 522 523 size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) 524 { 525 return fprintf(fp, " %d/%d: [%#" PRIx64 "(%#" PRIx64 ") @ %#" PRIx64 "]: %s\n", 526 event->mmap.pid, event->mmap.tid, event->mmap.start, 527 event->mmap.len, event->mmap.pgoff, event->mmap.filename); 528 } 529 530 int perf_event__process_mmap(struct perf_tool *tool __maybe_unused, 531 union perf_event *event, 532 struct perf_sample *sample __maybe_unused, 533 struct machine *machine) 534 { 535 return machine__process_mmap_event(machine, event); 536 } 537 538 size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) 539 { 540 return fprintf(fp, "(%d:%d):(%d:%d)\n", 541 event->fork.pid, event->fork.tid, 542 event->fork.ppid, event->fork.ptid); 543 } 544 545 int perf_event__process_fork(struct perf_tool *tool __maybe_unused, 546 union perf_event *event, 547 struct perf_sample *sample __maybe_unused, 548 struct machine *machine) 549 { 550 return machine__process_fork_event(machine, event); 551 } 552 553 int perf_event__process_exit(struct perf_tool *tool __maybe_unused, 554 union perf_event *event, 555 struct perf_sample *sample __maybe_unused, 556 struct machine *machine) 557 { 558 return machine__process_exit_event(machine, event); 559 } 560 561 size_t perf_event__fprintf(union perf_event *event, FILE *fp) 562 { 563 size_t ret = fprintf(fp, "PERF_RECORD_%s", 564 perf_event__name(event->header.type)); 565 566 switch (event->header.type) { 567 case PERF_RECORD_COMM: 568 ret += perf_event__fprintf_comm(event, fp); 569 break; 570 case PERF_RECORD_FORK: 571 case PERF_RECORD_EXIT: 572 ret += perf_event__fprintf_task(event, fp); 573 break; 574 case PERF_RECORD_MMAP: 575 ret += perf_event__fprintf_mmap(event, fp); 576 break; 577 default: 578 ret += fprintf(fp, "\n"); 579 } 580 581 return ret; 582 } 583 584 int perf_event__process(struct perf_tool *tool __maybe_unused, 585 union perf_event *event, 586 struct perf_sample *sample __maybe_unused, 587 struct machine *machine) 588 { 589 return machine__process_event(machine, event); 590 } 591 592 void thread__find_addr_map(struct thread *self, 593 struct machine *machine, u8 cpumode, 594 enum map_type type, u64 addr, 595 struct addr_location *al) 596 { 597 struct map_groups *mg = &self->mg; 598 599 al->thread = self; 600 al->addr = addr; 601 al->cpumode = cpumode; 602 al->filtered = false; 603 604 if (machine == NULL) { 605 al->map = NULL; 606 return; 607 } 608 609 if (cpumode == PERF_RECORD_MISC_KERNEL && perf_host) { 610 al->level = 'k'; 611 mg = &machine->kmaps; 612 } else if (cpumode == PERF_RECORD_MISC_USER && perf_host) { 613 al->level = '.'; 614 } else if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { 615 al->level = 'g'; 616 mg = &machine->kmaps; 617 } else { 618 /* 619 * 'u' means guest os user space. 620 * TODO: We don't support guest user space. Might support late. 621 */ 622 if (cpumode == PERF_RECORD_MISC_GUEST_USER && perf_guest) 623 al->level = 'u'; 624 else 625 al->level = 'H'; 626 al->map = NULL; 627 628 if ((cpumode == PERF_RECORD_MISC_GUEST_USER || 629 cpumode == PERF_RECORD_MISC_GUEST_KERNEL) && 630 !perf_guest) 631 al->filtered = true; 632 if ((cpumode == PERF_RECORD_MISC_USER || 633 cpumode == PERF_RECORD_MISC_KERNEL) && 634 !perf_host) 635 al->filtered = true; 636 637 return; 638 } 639 try_again: 640 al->map = map_groups__find(mg, type, al->addr); 641 if (al->map == NULL) { 642 /* 643 * If this is outside of all known maps, and is a negative 644 * address, try to look it up in the kernel dso, as it might be 645 * a vsyscall or vdso (which executes in user-mode). 646 * 647 * XXX This is nasty, we should have a symbol list in the 648 * "[vdso]" dso, but for now lets use the old trick of looking 649 * in the whole kernel symbol list. 650 */ 651 if ((long long)al->addr < 0 && 652 cpumode == PERF_RECORD_MISC_USER && 653 machine && mg != &machine->kmaps) { 654 mg = &machine->kmaps; 655 goto try_again; 656 } 657 } else 658 al->addr = al->map->map_ip(al->map, al->addr); 659 } 660 661 void thread__find_addr_location(struct thread *thread, struct machine *machine, 662 u8 cpumode, enum map_type type, u64 addr, 663 struct addr_location *al, 664 symbol_filter_t filter) 665 { 666 thread__find_addr_map(thread, machine, cpumode, type, addr, al); 667 if (al->map != NULL) 668 al->sym = map__find_symbol(al->map, al->addr, filter); 669 else 670 al->sym = NULL; 671 } 672 673 int perf_event__preprocess_sample(const union perf_event *event, 674 struct machine *machine, 675 struct addr_location *al, 676 struct perf_sample *sample, 677 symbol_filter_t filter) 678 { 679 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 680 struct thread *thread = machine__findnew_thread(machine, event->ip.pid); 681 682 if (thread == NULL) 683 return -1; 684 685 if (symbol_conf.comm_list && 686 !strlist__has_entry(symbol_conf.comm_list, thread->comm)) 687 goto out_filtered; 688 689 dump_printf(" ... thread: %s:%d\n", thread->comm, thread->pid); 690 /* 691 * Have we already created the kernel maps for this machine? 692 * 693 * This should have happened earlier, when we processed the kernel MMAP 694 * events, but for older perf.data files there was no such thing, so do 695 * it now. 696 */ 697 if (cpumode == PERF_RECORD_MISC_KERNEL && 698 machine->vmlinux_maps[MAP__FUNCTION] == NULL) 699 machine__create_kernel_maps(machine); 700 701 thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, 702 event->ip.ip, al); 703 dump_printf(" ...... dso: %s\n", 704 al->map ? al->map->dso->long_name : 705 al->level == 'H' ? "[hypervisor]" : "<not found>"); 706 al->sym = NULL; 707 al->cpu = sample->cpu; 708 709 if (al->map) { 710 struct dso *dso = al->map->dso; 711 712 if (symbol_conf.dso_list && 713 (!dso || !(strlist__has_entry(symbol_conf.dso_list, 714 dso->short_name) || 715 (dso->short_name != dso->long_name && 716 strlist__has_entry(symbol_conf.dso_list, 717 dso->long_name))))) 718 goto out_filtered; 719 720 al->sym = map__find_symbol(al->map, al->addr, filter); 721 } 722 723 if (symbol_conf.sym_list && 724 (!al->sym || !strlist__has_entry(symbol_conf.sym_list, 725 al->sym->name))) 726 goto out_filtered; 727 728 return 0; 729 730 out_filtered: 731 al->filtered = true; 732 return 0; 733 } 734