xref: /openbmc/linux/tools/perf/util/session.c (revision 2c46dbb5)
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