1 #define _FILE_OFFSET_BITS 64 2 3 #include <linux/kernel.h> 4 5 #include <byteswap.h> 6 #include <unistd.h> 7 #include <sys/types.h> 8 9 #include "session.h" 10 #include "sort.h" 11 #include "util.h" 12 13 static int perf_session__open(struct perf_session *self, bool force) 14 { 15 struct stat input_stat; 16 17 if (!strcmp(self->filename, "-")) { 18 self->fd_pipe = true; 19 self->fd = STDIN_FILENO; 20 21 if (perf_header__read(self, self->fd) < 0) 22 pr_err("incompatible file format"); 23 24 return 0; 25 } 26 27 self->fd = open(self->filename, O_RDONLY); 28 if (self->fd < 0) { 29 pr_err("failed to open file: %s", self->filename); 30 if (!strcmp(self->filename, "perf.data")) 31 pr_err(" (try 'perf record' first)"); 32 pr_err("\n"); 33 return -errno; 34 } 35 36 if (fstat(self->fd, &input_stat) < 0) 37 goto out_close; 38 39 if (!force && input_stat.st_uid && (input_stat.st_uid != geteuid())) { 40 pr_err("file %s not owned by current user or root\n", 41 self->filename); 42 goto out_close; 43 } 44 45 if (!input_stat.st_size) { 46 pr_info("zero-sized file (%s), nothing to do!\n", 47 self->filename); 48 goto out_close; 49 } 50 51 if (perf_header__read(self, self->fd) < 0) { 52 pr_err("incompatible file format"); 53 goto out_close; 54 } 55 56 self->size = input_stat.st_size; 57 return 0; 58 59 out_close: 60 close(self->fd); 61 self->fd = -1; 62 return -1; 63 } 64 65 void perf_session__update_sample_type(struct perf_session *self) 66 { 67 self->sample_type = perf_header__sample_type(&self->header); 68 } 69 70 struct perf_session *perf_session__new(const char *filename, int mode, bool force) 71 { 72 size_t len = filename ? strlen(filename) + 1 : 0; 73 struct perf_session *self = zalloc(sizeof(*self) + len); 74 75 if (self == NULL) 76 goto out; 77 78 if (perf_header__init(&self->header) < 0) 79 goto out_free; 80 81 memcpy(self->filename, filename, len); 82 self->threads = RB_ROOT; 83 self->stats_by_id = RB_ROOT; 84 self->last_match = NULL; 85 self->mmap_window = 32; 86 self->cwd = NULL; 87 self->cwdlen = 0; 88 self->unknown_events = 0; 89 map_groups__init(&self->kmaps); 90 91 if (mode == O_RDONLY) { 92 if (perf_session__open(self, force) < 0) 93 goto out_delete; 94 } else if (mode == O_WRONLY) { 95 /* 96 * In O_RDONLY mode this will be performed when reading the 97 * kernel MMAP event, in event__process_mmap(). 98 */ 99 if (perf_session__create_kernel_maps(self) < 0) 100 goto out_delete; 101 } 102 103 perf_session__update_sample_type(self); 104 out: 105 return self; 106 out_free: 107 free(self); 108 return NULL; 109 out_delete: 110 perf_session__delete(self); 111 return NULL; 112 } 113 114 void perf_session__delete(struct perf_session *self) 115 { 116 perf_header__exit(&self->header); 117 close(self->fd); 118 free(self->cwd); 119 free(self); 120 } 121 122 static bool symbol__match_parent_regex(struct symbol *sym) 123 { 124 if (sym->name && !regexec(&parent_regex, sym->name, 0, NULL, 0)) 125 return 1; 126 127 return 0; 128 } 129 130 struct map_symbol *perf_session__resolve_callchain(struct perf_session *self, 131 struct thread *thread, 132 struct ip_callchain *chain, 133 struct symbol **parent) 134 { 135 u8 cpumode = PERF_RECORD_MISC_USER; 136 unsigned int i; 137 struct map_symbol *syms = calloc(chain->nr, sizeof(*syms)); 138 139 if (!syms) 140 return NULL; 141 142 for (i = 0; i < chain->nr; i++) { 143 u64 ip = chain->ips[i]; 144 struct addr_location al; 145 146 if (ip >= PERF_CONTEXT_MAX) { 147 switch (ip) { 148 case PERF_CONTEXT_HV: 149 cpumode = PERF_RECORD_MISC_HYPERVISOR; break; 150 case PERF_CONTEXT_KERNEL: 151 cpumode = PERF_RECORD_MISC_KERNEL; break; 152 case PERF_CONTEXT_USER: 153 cpumode = PERF_RECORD_MISC_USER; break; 154 default: 155 break; 156 } 157 continue; 158 } 159 160 thread__find_addr_location(thread, self, cpumode, 161 MAP__FUNCTION, ip, &al, NULL); 162 if (al.sym != NULL) { 163 if (sort__has_parent && !*parent && 164 symbol__match_parent_regex(al.sym)) 165 *parent = al.sym; 166 if (!symbol_conf.use_callchain) 167 break; 168 syms[i].map = al.map; 169 syms[i].sym = al.sym; 170 } 171 } 172 173 return syms; 174 } 175 176 static int process_event_stub(event_t *event __used, 177 struct perf_session *session __used) 178 { 179 dump_printf(": unhandled!\n"); 180 return 0; 181 } 182 183 static void perf_event_ops__fill_defaults(struct perf_event_ops *handler) 184 { 185 if (handler->sample == NULL) 186 handler->sample = process_event_stub; 187 if (handler->mmap == NULL) 188 handler->mmap = process_event_stub; 189 if (handler->comm == NULL) 190 handler->comm = process_event_stub; 191 if (handler->fork == NULL) 192 handler->fork = process_event_stub; 193 if (handler->exit == NULL) 194 handler->exit = process_event_stub; 195 if (handler->lost == NULL) 196 handler->lost = process_event_stub; 197 if (handler->read == NULL) 198 handler->read = process_event_stub; 199 if (handler->throttle == NULL) 200 handler->throttle = process_event_stub; 201 if (handler->unthrottle == NULL) 202 handler->unthrottle = process_event_stub; 203 if (handler->attr == NULL) 204 handler->attr = process_event_stub; 205 } 206 207 static const char *event__name[] = { 208 [0] = "TOTAL", 209 [PERF_RECORD_MMAP] = "MMAP", 210 [PERF_RECORD_LOST] = "LOST", 211 [PERF_RECORD_COMM] = "COMM", 212 [PERF_RECORD_EXIT] = "EXIT", 213 [PERF_RECORD_THROTTLE] = "THROTTLE", 214 [PERF_RECORD_UNTHROTTLE] = "UNTHROTTLE", 215 [PERF_RECORD_FORK] = "FORK", 216 [PERF_RECORD_READ] = "READ", 217 [PERF_RECORD_SAMPLE] = "SAMPLE", 218 [PERF_RECORD_HEADER_ATTR] = "ATTR", 219 }; 220 221 unsigned long event__total[PERF_RECORD_HEADER_MAX]; 222 223 void event__print_totals(void) 224 { 225 int i; 226 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 227 if (!event__name[i]) 228 continue; 229 pr_info("%10s events: %10ld\n", 230 event__name[i], event__total[i]); 231 } 232 } 233 234 void mem_bswap_64(void *src, int byte_size) 235 { 236 u64 *m = src; 237 238 while (byte_size > 0) { 239 *m = bswap_64(*m); 240 byte_size -= sizeof(u64); 241 ++m; 242 } 243 } 244 245 static void event__all64_swap(event_t *self) 246 { 247 struct perf_event_header *hdr = &self->header; 248 mem_bswap_64(hdr + 1, self->header.size - sizeof(*hdr)); 249 } 250 251 static void event__comm_swap(event_t *self) 252 { 253 self->comm.pid = bswap_32(self->comm.pid); 254 self->comm.tid = bswap_32(self->comm.tid); 255 } 256 257 static void event__mmap_swap(event_t *self) 258 { 259 self->mmap.pid = bswap_32(self->mmap.pid); 260 self->mmap.tid = bswap_32(self->mmap.tid); 261 self->mmap.start = bswap_64(self->mmap.start); 262 self->mmap.len = bswap_64(self->mmap.len); 263 self->mmap.pgoff = bswap_64(self->mmap.pgoff); 264 } 265 266 static void event__task_swap(event_t *self) 267 { 268 self->fork.pid = bswap_32(self->fork.pid); 269 self->fork.tid = bswap_32(self->fork.tid); 270 self->fork.ppid = bswap_32(self->fork.ppid); 271 self->fork.ptid = bswap_32(self->fork.ptid); 272 self->fork.time = bswap_64(self->fork.time); 273 } 274 275 static void event__read_swap(event_t *self) 276 { 277 self->read.pid = bswap_32(self->read.pid); 278 self->read.tid = bswap_32(self->read.tid); 279 self->read.value = bswap_64(self->read.value); 280 self->read.time_enabled = bswap_64(self->read.time_enabled); 281 self->read.time_running = bswap_64(self->read.time_running); 282 self->read.id = bswap_64(self->read.id); 283 } 284 285 static void event__attr_swap(event_t *self) 286 { 287 size_t size; 288 289 self->attr.attr.type = bswap_32(self->attr.attr.type); 290 self->attr.attr.size = bswap_32(self->attr.attr.size); 291 self->attr.attr.config = bswap_64(self->attr.attr.config); 292 self->attr.attr.sample_period = bswap_64(self->attr.attr.sample_period); 293 self->attr.attr.sample_type = bswap_64(self->attr.attr.sample_type); 294 self->attr.attr.read_format = bswap_64(self->attr.attr.read_format); 295 self->attr.attr.wakeup_events = bswap_32(self->attr.attr.wakeup_events); 296 self->attr.attr.bp_type = bswap_32(self->attr.attr.bp_type); 297 self->attr.attr.bp_addr = bswap_64(self->attr.attr.bp_addr); 298 self->attr.attr.bp_len = bswap_64(self->attr.attr.bp_len); 299 300 size = self->header.size; 301 size -= (void *)&self->attr.id - (void *)self; 302 mem_bswap_64(self->attr.id, size); 303 } 304 305 typedef void (*event__swap_op)(event_t *self); 306 307 static event__swap_op event__swap_ops[] = { 308 [PERF_RECORD_MMAP] = event__mmap_swap, 309 [PERF_RECORD_COMM] = event__comm_swap, 310 [PERF_RECORD_FORK] = event__task_swap, 311 [PERF_RECORD_EXIT] = event__task_swap, 312 [PERF_RECORD_LOST] = event__all64_swap, 313 [PERF_RECORD_READ] = event__read_swap, 314 [PERF_RECORD_SAMPLE] = event__all64_swap, 315 [PERF_RECORD_HEADER_ATTR] = event__attr_swap, 316 [PERF_RECORD_HEADER_MAX] = NULL, 317 }; 318 319 static int perf_session__process_event(struct perf_session *self, 320 event_t *event, 321 struct perf_event_ops *ops, 322 u64 offset, u64 head) 323 { 324 trace_event(event); 325 326 if (event->header.type < PERF_RECORD_HEADER_MAX) { 327 dump_printf("%#Lx [%#x]: PERF_RECORD_%s", 328 offset + head, event->header.size, 329 event__name[event->header.type]); 330 ++event__total[0]; 331 ++event__total[event->header.type]; 332 } 333 334 if (self->header.needs_swap && event__swap_ops[event->header.type]) 335 event__swap_ops[event->header.type](event); 336 337 switch (event->header.type) { 338 case PERF_RECORD_SAMPLE: 339 return ops->sample(event, self); 340 case PERF_RECORD_MMAP: 341 return ops->mmap(event, self); 342 case PERF_RECORD_COMM: 343 return ops->comm(event, self); 344 case PERF_RECORD_FORK: 345 return ops->fork(event, self); 346 case PERF_RECORD_EXIT: 347 return ops->exit(event, self); 348 case PERF_RECORD_LOST: 349 return ops->lost(event, self); 350 case PERF_RECORD_READ: 351 return ops->read(event, self); 352 case PERF_RECORD_THROTTLE: 353 return ops->throttle(event, self); 354 case PERF_RECORD_UNTHROTTLE: 355 return ops->unthrottle(event, self); 356 case PERF_RECORD_HEADER_ATTR: 357 return ops->attr(event, self); 358 default: 359 self->unknown_events++; 360 return -1; 361 } 362 } 363 364 void perf_event_header__bswap(struct perf_event_header *self) 365 { 366 self->type = bswap_32(self->type); 367 self->misc = bswap_16(self->misc); 368 self->size = bswap_16(self->size); 369 } 370 371 int perf_header__read_build_ids(struct perf_header *self, 372 int input, u64 offset, u64 size) 373 { 374 struct build_id_event bev; 375 char filename[PATH_MAX]; 376 u64 limit = offset + size; 377 int err = -1; 378 379 while (offset < limit) { 380 struct dso *dso; 381 ssize_t len; 382 struct list_head *head = &dsos__user; 383 384 if (read(input, &bev, sizeof(bev)) != sizeof(bev)) 385 goto out; 386 387 if (self->needs_swap) 388 perf_event_header__bswap(&bev.header); 389 390 len = bev.header.size - sizeof(bev); 391 if (read(input, filename, len) != len) 392 goto out; 393 394 if (bev.header.misc & PERF_RECORD_MISC_KERNEL) 395 head = &dsos__kernel; 396 397 dso = __dsos__findnew(head, filename); 398 if (dso != NULL) { 399 dso__set_build_id(dso, &bev.build_id); 400 if (head == &dsos__kernel && filename[0] == '[') 401 dso->kernel = 1; 402 } 403 404 offset += bev.header.size; 405 } 406 err = 0; 407 out: 408 return err; 409 } 410 411 static struct thread *perf_session__register_idle_thread(struct perf_session *self) 412 { 413 struct thread *thread = perf_session__findnew(self, 0); 414 415 if (thread == NULL || thread__set_comm(thread, "swapper")) { 416 pr_err("problem inserting idle task.\n"); 417 thread = NULL; 418 } 419 420 return thread; 421 } 422 423 int do_read(int fd, void *buf, size_t size) 424 { 425 void *buf_start = buf; 426 427 while (size) { 428 int ret = read(fd, buf, size); 429 430 if (ret <= 0) 431 return ret; 432 433 size -= ret; 434 buf += ret; 435 } 436 437 return buf - buf_start; 438 } 439 440 #define session_done() (*(volatile int *)(&session_done)) 441 volatile int session_done; 442 443 static int __perf_session__process_pipe_events(struct perf_session *self, 444 struct perf_event_ops *ops) 445 { 446 event_t event; 447 uint32_t size; 448 int skip = 0; 449 u64 head; 450 int err; 451 void *p; 452 453 perf_event_ops__fill_defaults(ops); 454 455 head = 0; 456 more: 457 err = do_read(self->fd, &event, sizeof(struct perf_event_header)); 458 if (err <= 0) { 459 if (err == 0) 460 goto done; 461 462 pr_err("failed to read event header\n"); 463 goto out_err; 464 } 465 466 if (self->header.needs_swap) 467 perf_event_header__bswap(&event.header); 468 469 size = event.header.size; 470 if (size == 0) 471 size = 8; 472 473 p = &event; 474 p += sizeof(struct perf_event_header); 475 476 err = do_read(self->fd, p, size - sizeof(struct perf_event_header)); 477 if (err <= 0) { 478 if (err == 0) { 479 pr_err("unexpected end of event stream\n"); 480 goto done; 481 } 482 483 pr_err("failed to read event data\n"); 484 goto out_err; 485 } 486 487 if (size == 0 || 488 (skip = perf_session__process_event(self, &event, ops, 489 0, head)) < 0) { 490 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", 491 head, event.header.size, event.header.type); 492 /* 493 * assume we lost track of the stream, check alignment, and 494 * increment a single u64 in the hope to catch on again 'soon'. 495 */ 496 if (unlikely(head & 7)) 497 head &= ~7ULL; 498 499 size = 8; 500 } 501 502 head += size; 503 504 dump_printf("\n%#Lx [%#x]: event: %d\n", 505 head, event.header.size, event.header.type); 506 507 if (skip > 0) 508 head += skip; 509 510 if (!session_done()) 511 goto more; 512 done: 513 err = 0; 514 out_err: 515 return err; 516 } 517 518 int __perf_session__process_events(struct perf_session *self, 519 u64 data_offset, u64 data_size, 520 u64 file_size, struct perf_event_ops *ops) 521 { 522 int err, mmap_prot, mmap_flags; 523 u64 head, shift; 524 u64 offset = 0; 525 size_t page_size; 526 event_t *event; 527 uint32_t size; 528 char *buf; 529 struct ui_progress *progress = ui_progress__new("Processing events...", 530 self->size); 531 if (progress == NULL) 532 return -1; 533 534 perf_event_ops__fill_defaults(ops); 535 536 page_size = sysconf(_SC_PAGESIZE); 537 538 head = data_offset; 539 shift = page_size * (head / page_size); 540 offset += shift; 541 head -= shift; 542 543 mmap_prot = PROT_READ; 544 mmap_flags = MAP_SHARED; 545 546 if (self->header.needs_swap) { 547 mmap_prot |= PROT_WRITE; 548 mmap_flags = MAP_PRIVATE; 549 } 550 remap: 551 buf = mmap(NULL, page_size * self->mmap_window, mmap_prot, 552 mmap_flags, self->fd, offset); 553 if (buf == MAP_FAILED) { 554 pr_err("failed to mmap file\n"); 555 err = -errno; 556 goto out_err; 557 } 558 559 more: 560 event = (event_t *)(buf + head); 561 ui_progress__update(progress, offset); 562 563 if (self->header.needs_swap) 564 perf_event_header__bswap(&event->header); 565 size = event->header.size; 566 if (size == 0) 567 size = 8; 568 569 if (head + event->header.size >= page_size * self->mmap_window) { 570 int munmap_ret; 571 572 shift = page_size * (head / page_size); 573 574 munmap_ret = munmap(buf, page_size * self->mmap_window); 575 assert(munmap_ret == 0); 576 577 offset += shift; 578 head -= shift; 579 goto remap; 580 } 581 582 size = event->header.size; 583 584 dump_printf("\n%#Lx [%#x]: event: %d\n", 585 offset + head, event->header.size, event->header.type); 586 587 if (size == 0 || 588 perf_session__process_event(self, event, ops, offset, head) < 0) { 589 dump_printf("%#Lx [%#x]: skipping unknown header type: %d\n", 590 offset + head, event->header.size, 591 event->header.type); 592 /* 593 * assume we lost track of the stream, check alignment, and 594 * increment a single u64 in the hope to catch on again 'soon'. 595 */ 596 if (unlikely(head & 7)) 597 head &= ~7ULL; 598 599 size = 8; 600 } 601 602 head += size; 603 604 if (offset + head >= data_offset + data_size) 605 goto done; 606 607 if (offset + head < file_size) 608 goto more; 609 done: 610 err = 0; 611 out_err: 612 ui_progress__delete(progress); 613 return err; 614 } 615 616 int perf_session__process_events(struct perf_session *self, 617 struct perf_event_ops *ops) 618 { 619 int err; 620 621 if (perf_session__register_idle_thread(self) == NULL) 622 return -ENOMEM; 623 624 if (!symbol_conf.full_paths) { 625 char bf[PATH_MAX]; 626 627 if (getcwd(bf, sizeof(bf)) == NULL) { 628 err = -errno; 629 out_getcwd_err: 630 pr_err("failed to get the current directory\n"); 631 goto out_err; 632 } 633 self->cwd = strdup(bf); 634 if (self->cwd == NULL) { 635 err = -ENOMEM; 636 goto out_getcwd_err; 637 } 638 self->cwdlen = strlen(self->cwd); 639 } 640 641 if (!self->fd_pipe) 642 err = __perf_session__process_events(self, 643 self->header.data_offset, 644 self->header.data_size, 645 self->size, ops); 646 else 647 err = __perf_session__process_pipe_events(self, ops); 648 out_err: 649 return err; 650 } 651 652 bool perf_session__has_traces(struct perf_session *self, const char *msg) 653 { 654 if (!(self->sample_type & PERF_SAMPLE_RAW)) { 655 pr_err("No trace sample to read. Did you call 'perf %s'?\n", msg); 656 return false; 657 } 658 659 return true; 660 } 661 662 int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, 663 const char *symbol_name, 664 u64 addr) 665 { 666 char *bracket; 667 enum map_type i; 668 669 self->ref_reloc_sym.name = strdup(symbol_name); 670 if (self->ref_reloc_sym.name == NULL) 671 return -ENOMEM; 672 673 bracket = strchr(self->ref_reloc_sym.name, ']'); 674 if (bracket) 675 *bracket = '\0'; 676 677 self->ref_reloc_sym.addr = addr; 678 679 for (i = 0; i < MAP__NR_TYPES; ++i) { 680 struct kmap *kmap = map__kmap(self->vmlinux_maps[i]); 681 kmap->ref_reloc_sym = &self->ref_reloc_sym; 682 } 683 684 return 0; 685 } 686