aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/event.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/event.c')
-rw-r--r--tools/perf/util/event.c302
1 files changed, 58 insertions, 244 deletions
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 6715b1938725..3cf2c3e0605f 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1,6 +1,7 @@
1#include <linux/types.h> 1#include <linux/types.h>
2#include "event.h" 2#include "event.h"
3#include "debug.h" 3#include "debug.h"
4#include "machine.h"
4#include "sort.h" 5#include "sort.h"
5#include "string.h" 6#include "string.h"
6#include "strlist.h" 7#include "strlist.h"
@@ -192,55 +193,43 @@ static int perf_event__synthesize_mmap_events(struct perf_tool *tool,
192 event->header.misc = PERF_RECORD_MISC_USER; 193 event->header.misc = PERF_RECORD_MISC_USER;
193 194
194 while (1) { 195 while (1) {
195 char bf[BUFSIZ], *pbf = bf; 196 char bf[BUFSIZ];
196 int n; 197 char prot[5];
198 char execname[PATH_MAX];
199 char anonstr[] = "//anon";
197 size_t size; 200 size_t size;
201
198 if (fgets(bf, sizeof(bf), fp) == NULL) 202 if (fgets(bf, sizeof(bf), fp) == NULL)
199 break; 203 break;
200 204
205 /* ensure null termination since stack will be reused. */
206 strcpy(execname, "");
207
201 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */ 208 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */
202 n = hex2u64(pbf, &event->mmap.start); 209 sscanf(bf, "%"PRIx64"-%"PRIx64" %s %"PRIx64" %*x:%*x %*u %s\n",
203 if (n < 0) 210 &event->mmap.start, &event->mmap.len, prot,
204 continue; 211 &event->mmap.pgoff, execname);
205 pbf += n + 1; 212
206 n = hex2u64(pbf, &event->mmap.len); 213 if (prot[2] != 'x')
207 if (n < 0)
208 continue; 214 continue;
209 pbf += n + 3; 215
210 if (*pbf == 'x') { /* vm_exec */ 216 if (!strcmp(execname, ""))
211 char anonstr[] = "//anon\n"; 217 strcpy(execname, anonstr);
212 char *execname = strchr(bf, '/'); 218
213 219 size = strlen(execname) + 1;
214 /* Catch VDSO */ 220 memcpy(event->mmap.filename, execname, size);
215 if (execname == NULL) 221 size = PERF_ALIGN(size, sizeof(u64));
216 execname = strstr(bf, "[vdso]"); 222 event->mmap.len -= event->mmap.start;
217 223 event->mmap.header.size = (sizeof(event->mmap) -
218 /* Catch anonymous mmaps */ 224 (sizeof(event->mmap.filename) - size));
219 if ((execname == NULL) && !strstr(bf, "[")) 225 memset(event->mmap.filename + size, 0, machine->id_hdr_size);
220 execname = anonstr; 226 event->mmap.header.size += machine->id_hdr_size;
221 227 event->mmap.pid = tgid;
222 if (execname == NULL) 228 event->mmap.tid = pid;
223 continue; 229
224 230 if (process(tool, event, &synth_sample, machine) != 0) {
225 pbf += 3; 231 rc = -1;
226 n = hex2u64(pbf, &event->mmap.pgoff); 232 break;
227
228 size = strlen(execname);
229 execname[size - 1] = '\0'; /* Remove \n */
230 memcpy(event->mmap.filename, execname, size);
231 size = PERF_ALIGN(size, sizeof(u64));
232 event->mmap.len -= event->mmap.start;
233 event->mmap.header.size = (sizeof(event->mmap) -
234 (sizeof(event->mmap.filename) - size));
235 memset(event->mmap.filename + size, 0, machine->id_hdr_size);
236 event->mmap.header.size += machine->id_hdr_size;
237 event->mmap.pid = tgid;
238 event->mmap.tid = pid;
239
240 if (process(tool, event, &synth_sample, machine) != 0) {
241 rc = -1;
242 break;
243 }
244 } 233 }
245 } 234 }
246 235
@@ -404,16 +393,15 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
404 393
405 if (*end) /* only interested in proper numerical dirents */ 394 if (*end) /* only interested in proper numerical dirents */
406 continue; 395 continue;
407 396 /*
408 if (__event__synthesize_thread(comm_event, mmap_event, pid, 1, 397 * We may race with exiting thread, so don't stop just because
409 process, tool, machine) != 0) { 398 * one thread couldn't be synthesized.
410 err = -1; 399 */
411 goto out_closedir; 400 __event__synthesize_thread(comm_event, mmap_event, pid, 1,
412 } 401 process, tool, machine);
413 } 402 }
414 403
415 err = 0; 404 err = 0;
416out_closedir:
417 closedir(proc); 405 closedir(proc);
418out_free_mmap: 406out_free_mmap:
419 free(mmap_event); 407 free(mmap_event);
@@ -519,134 +507,15 @@ int perf_event__process_comm(struct perf_tool *tool __maybe_unused,
519 struct perf_sample *sample __maybe_unused, 507 struct perf_sample *sample __maybe_unused,
520 struct machine *machine) 508 struct machine *machine)
521{ 509{
522 struct thread *thread = machine__findnew_thread(machine, event->comm.tid); 510 return machine__process_comm_event(machine, event);
523
524 if (dump_trace)
525 perf_event__fprintf_comm(event, stdout);
526
527 if (thread == NULL || thread__set_comm(thread, event->comm.comm)) {
528 dump_printf("problem processing PERF_RECORD_COMM, skipping event.\n");
529 return -1;
530 }
531
532 return 0;
533} 511}
534 512
535int perf_event__process_lost(struct perf_tool *tool __maybe_unused, 513int perf_event__process_lost(struct perf_tool *tool __maybe_unused,
536 union perf_event *event, 514 union perf_event *event,
537 struct perf_sample *sample __maybe_unused, 515 struct perf_sample *sample __maybe_unused,
538 struct machine *machine __maybe_unused) 516 struct machine *machine)
539{
540 dump_printf(": id:%" PRIu64 ": lost:%" PRIu64 "\n",
541 event->lost.id, event->lost.lost);
542 return 0;
543}
544
545static void perf_event__set_kernel_mmap_len(union perf_event *event,
546 struct map **maps)
547{
548 maps[MAP__FUNCTION]->start = event->mmap.start;
549 maps[MAP__FUNCTION]->end = event->mmap.start + event->mmap.len;
550 /*
551 * Be a bit paranoid here, some perf.data file came with
552 * a zero sized synthesized MMAP event for the kernel.
553 */
554 if (maps[MAP__FUNCTION]->end == 0)
555 maps[MAP__FUNCTION]->end = ~0ULL;
556}
557
558static int perf_event__process_kernel_mmap(struct perf_tool *tool
559 __maybe_unused,
560 union perf_event *event,
561 struct machine *machine)
562{ 517{
563 struct map *map; 518 return machine__process_lost_event(machine, event);
564 char kmmap_prefix[PATH_MAX];
565 enum dso_kernel_type kernel_type;
566 bool is_kernel_mmap;
567
568 machine__mmap_name(machine, kmmap_prefix, sizeof(kmmap_prefix));
569 if (machine__is_host(machine))
570 kernel_type = DSO_TYPE_KERNEL;
571 else
572 kernel_type = DSO_TYPE_GUEST_KERNEL;
573
574 is_kernel_mmap = memcmp(event->mmap.filename,
575 kmmap_prefix,
576 strlen(kmmap_prefix) - 1) == 0;
577 if (event->mmap.filename[0] == '/' ||
578 (!is_kernel_mmap && event->mmap.filename[0] == '[')) {
579
580 char short_module_name[1024];
581 char *name, *dot;
582
583 if (event->mmap.filename[0] == '/') {
584 name = strrchr(event->mmap.filename, '/');
585 if (name == NULL)
586 goto out_problem;
587
588 ++name; /* skip / */
589 dot = strrchr(name, '.');
590 if (dot == NULL)
591 goto out_problem;
592 snprintf(short_module_name, sizeof(short_module_name),
593 "[%.*s]", (int)(dot - name), name);
594 strxfrchar(short_module_name, '-', '_');
595 } else
596 strcpy(short_module_name, event->mmap.filename);
597
598 map = machine__new_module(machine, event->mmap.start,
599 event->mmap.filename);
600 if (map == NULL)
601 goto out_problem;
602
603 name = strdup(short_module_name);
604 if (name == NULL)
605 goto out_problem;
606
607 map->dso->short_name = name;
608 map->dso->sname_alloc = 1;
609 map->end = map->start + event->mmap.len;
610 } else if (is_kernel_mmap) {
611 const char *symbol_name = (event->mmap.filename +
612 strlen(kmmap_prefix));
613 /*
614 * Should be there already, from the build-id table in
615 * the header.
616 */
617 struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
618 kmmap_prefix);
619 if (kernel == NULL)
620 goto out_problem;
621
622 kernel->kernel = kernel_type;
623 if (__machine__create_kernel_maps(machine, kernel) < 0)
624 goto out_problem;
625
626 perf_event__set_kernel_mmap_len(event, machine->vmlinux_maps);
627
628 /*
629 * Avoid using a zero address (kptr_restrict) for the ref reloc
630 * symbol. Effectively having zero here means that at record
631 * time /proc/sys/kernel/kptr_restrict was non zero.
632 */
633 if (event->mmap.pgoff != 0) {
634 maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps,
635 symbol_name,
636 event->mmap.pgoff);
637 }
638
639 if (machine__is_default_guest(machine)) {
640 /*
641 * preload dso of guest kernel and modules
642 */
643 dso__load(kernel, machine->vmlinux_maps[MAP__FUNCTION],
644 NULL);
645 }
646 }
647 return 0;
648out_problem:
649 return -1;
650} 519}
651 520
652size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp) 521size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
@@ -656,43 +525,12 @@ size_t perf_event__fprintf_mmap(union perf_event *event, FILE *fp)
656 event->mmap.len, event->mmap.pgoff, event->mmap.filename); 525 event->mmap.len, event->mmap.pgoff, event->mmap.filename);
657} 526}
658 527
659int perf_event__process_mmap(struct perf_tool *tool, 528int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
660 union perf_event *event, 529 union perf_event *event,
661 struct perf_sample *sample __maybe_unused, 530 struct perf_sample *sample __maybe_unused,
662 struct machine *machine) 531 struct machine *machine)
663{ 532{
664 struct thread *thread; 533 return machine__process_mmap_event(machine, event);
665 struct map *map;
666 u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
667 int ret = 0;
668
669 if (dump_trace)
670 perf_event__fprintf_mmap(event, stdout);
671
672 if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL ||
673 cpumode == PERF_RECORD_MISC_KERNEL) {
674 ret = perf_event__process_kernel_mmap(tool, event, machine);
675 if (ret < 0)
676 goto out_problem;
677 return 0;
678 }
679
680 thread = machine__findnew_thread(machine, event->mmap.pid);
681 if (thread == NULL)
682 goto out_problem;
683 map = map__new(&machine->user_dsos, event->mmap.start,
684 event->mmap.len, event->mmap.pgoff,
685 event->mmap.pid, event->mmap.filename,
686 MAP__FUNCTION);
687 if (map == NULL)
688 goto out_problem;
689
690 thread__insert_map(thread, map);
691 return 0;
692
693out_problem:
694 dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n");
695 return 0;
696} 534}
697 535
698size_t perf_event__fprintf_task(union perf_event *event, FILE *fp) 536size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
@@ -702,29 +540,20 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp)
702 event->fork.ppid, event->fork.ptid); 540 event->fork.ppid, event->fork.ptid);
703} 541}
704 542
705int perf_event__process_task(struct perf_tool *tool __maybe_unused, 543int perf_event__process_fork(struct perf_tool *tool __maybe_unused,
706 union perf_event *event, 544 union perf_event *event,
707 struct perf_sample *sample __maybe_unused, 545 struct perf_sample *sample __maybe_unused,
708 struct machine *machine) 546 struct machine *machine)
709{ 547{
710 struct thread *thread = machine__findnew_thread(machine, event->fork.tid); 548 return machine__process_fork_event(machine, event);
711 struct thread *parent = machine__findnew_thread(machine, event->fork.ptid); 549}
712
713 if (dump_trace)
714 perf_event__fprintf_task(event, stdout);
715
716 if (event->header.type == PERF_RECORD_EXIT) {
717 machine__remove_thread(machine, thread);
718 return 0;
719 }
720
721 if (thread == NULL || parent == NULL ||
722 thread__fork(thread, parent) < 0) {
723 dump_printf("problem processing PERF_RECORD_FORK, skipping event.\n");
724 return -1;
725 }
726 550
727 return 0; 551int 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);
728} 557}
729 558
730size_t perf_event__fprintf(union perf_event *event, FILE *fp) 559size_t perf_event__fprintf(union perf_event *event, FILE *fp)
@@ -750,27 +579,12 @@ size_t perf_event__fprintf(union perf_event *event, FILE *fp)
750 return ret; 579 return ret;
751} 580}
752 581
753int perf_event__process(struct perf_tool *tool, union perf_event *event, 582int perf_event__process(struct perf_tool *tool __maybe_unused,
754 struct perf_sample *sample, struct machine *machine) 583 union perf_event *event,
584 struct perf_sample *sample __maybe_unused,
585 struct machine *machine)
755{ 586{
756 switch (event->header.type) { 587 return machine__process_event(machine, event);
757 case PERF_RECORD_COMM:
758 perf_event__process_comm(tool, event, sample, machine);
759 break;
760 case PERF_RECORD_MMAP:
761 perf_event__process_mmap(tool, event, sample, machine);
762 break;
763 case PERF_RECORD_FORK:
764 case PERF_RECORD_EXIT:
765 perf_event__process_task(tool, event, sample, machine);
766 break;
767 case PERF_RECORD_LOST:
768 perf_event__process_lost(tool, event, sample, machine);
769 default:
770 break;
771 }
772
773 return 0;
774} 588}
775 589
776void thread__find_addr_map(struct thread *self, 590void thread__find_addr_map(struct thread *self,