• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3  * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
4  *
5  */
6 #include <stdbool.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <sys/mman.h>
10 #include <regex.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <errno.h>
14 
15 #include <linux/time64.h>
16 
17 #include "trace-write-local.h"
18 #include "trace-cmd-local.h"
19 #include "trace-rbtree.h"
20 #include "trace-local.h"
21 #include "kbuffer.h"
22 #include "list.h"
23 
24 #define _STRINGIFY(x) #x
25 #define STRINGIFY(x) _STRINGIFY(x)
26 
27 #define MISSING_EVENTS (1 << 31)
28 #define MISSING_STORED (1 << 30)
29 
30 #define COMMIT_MASK ((1 << 27) - 1)
31 
32 /* force uncompressing in memory */
33 #define INMEMORY_DECOMPRESS
34 
35 /* for debugging read instead of mmap */
36 static int force_read = 0;
37 
38 struct page_map {
39 	struct list_head	list;
40 	off_t			offset;
41 	off_t			size;
42 	void			*map;
43 	int			ref_count;
44 };
45 
46 struct follow_event {
47 	struct tep_event	*event;
48 	void			*callback_data;
49 	int (*callback)(struct tracecmd_input *handle,
50 			struct tep_event *,
51 			struct tep_record *,
52 			int, void *);
53 };
54 
55 struct page {
56 	struct list_head	list;
57 	off_t			offset;
58 	struct tracecmd_input	*handle;
59 	struct page_map		*page_map;
60 	void			*map;
61 	int			ref_count;
62 	int			cpu;
63 	long long		lost_events;
64 #if DEBUG_RECORD
65 	struct tep_record	*records;
66 #endif
67 };
68 
69 struct zchunk_cache {
70 	struct trace_rbtree_node	node;
71 	struct tracecmd_compress_chunk *chunk;
72 	void				*map;
73 	int				ref;
74 };
75 
76 struct cpu_zdata {
77 	/* uncompressed cpu data */
78 	int			fd;
79 #ifdef __ANDROID__
80 	char			file[37]; /* strlen(COMPR_TEMP_FILE) */
81 #else	/* !__ANDROID__ */
82 	char			file[26]; /* strlen(COMPR_TEMP_FILE) */
83 #endif	/* __ANDROID__ */
84 
85 	unsigned int		count;
86 	unsigned int		last_chunk;
87 	struct trace_rbtree	cache;
88 	struct tracecmd_compress_chunk	*chunks;
89 };
90 
91 #ifdef __ANDROID__
92 #define COMPR_TEMP_FILE "/data/local/tmp/trace_cpu_dataXXXXXX"
93 #else	/* !__ANDROID__ */
94 #define COMPR_TEMP_FILE "/tmp/trace_cpu_dataXXXXXX"
95 #endif	/* __ANDROID__ */
96 
97 struct cpu_data {
98 	/* the first two never change */
99 	unsigned long long	file_offset;
100 	unsigned long long	file_size;
101 	unsigned long long	offset;
102 	unsigned long long	size;
103 	unsigned long long	timestamp;
104 	unsigned long long	first_ts;
105 	struct list_head	page_maps;
106 	struct page_map		*page_map;
107 	struct page		**pages;
108 	struct tep_record	*next;
109 	struct page		*page;
110 	struct kbuffer		*kbuf;
111 	int			nr_pages;
112 	int			page_cnt;
113 	int			cpu;
114 	int			pipe_fd;
115 	struct cpu_zdata	compress;
116 };
117 
118 struct cpu_file_data {
119 	int			cpu;
120 	unsigned long long	offset;
121 	unsigned long long	size;
122 };
123 
124 struct input_buffer_instance {
125 	char			*name;
126 	size_t			offset;
127 	char			*clock;
128 	bool			latency;
129 	int			page_size;
130 	int			cpus;
131 	struct cpu_file_data	*cpu_data;
132 };
133 
134 struct ts_offset_sample {
135 	long long	time;
136 	long long	offset;
137 	long long	scaling;
138 	long long	fraction;
139 };
140 
141 struct guest_trace_info {
142 	struct guest_trace_info	*next;
143 	char			*name;
144 	unsigned long long	trace_id;
145 	int			vcpu_count;
146 	int			*cpu_pid;
147 };
148 
149 struct timesync_offsets {
150 	int	ts_samples_count;
151 	struct ts_offset_sample	*ts_samples;
152 };
153 
154 struct host_trace_info {
155 	unsigned long long	peer_trace_id;
156 	unsigned int		flags;
157 	bool			sync_enable;
158 	int			ts_samples_count;
159 	struct ts_offset_sample	*ts_samples;
160 	int			cpu_count;
161 	struct timesync_offsets	*ts_offsets;
162 };
163 
164 struct tsc2nsec {
165 	int	mult;
166 	int	shift;
167 	unsigned long long offset;
168 };
169 
170 struct file_section {
171 	unsigned long long		section_offset;
172 	unsigned long long		data_offset;
173 	int				id;
174 	int				flags;
175 	struct file_section		*next;
176 };
177 
178 struct tracecmd_input {
179 	struct tep_handle	*pevent;
180 	struct tep_plugin_list	*plugin_list;
181 	struct tracecmd_input	*parent;
182 	struct tracecmd_filter	*filter;
183 	struct follow_event	*followers;
184 	struct follow_event	*missed_followers;
185 	struct tracecmd_cpu_map *map;
186 	unsigned long		file_state;
187 	unsigned long long	trace_id;
188 	unsigned long long	next_offset;
189 	unsigned long		flags;
190 	int			fd;
191 	int			long_size;
192 	int			page_size;
193 	int			page_map_size;
194 	int			max_cpu;
195 	int			cpus;
196 	int			start_cpu;
197 	int			ref;
198 	int			nr_followers;
199 	int			nr_missed_followers;
200 	int			nr_buffers;	/* buffer instances */
201 	bool			use_trace_clock;
202 	bool			read_page;
203 	bool			use_pipe;
204 	bool			read_zpage; /* uncompress pages in memory, do not use tmp files */
205 	bool			cpu_compressed;
206 	int			file_version;
207 	int			map_cnt;
208 	unsigned int		cpustats_size;
209 	struct cpu_zdata	latz;
210 	struct cpu_data 	*cpu_data;
211 	long long		ts_offset;
212 	struct tsc2nsec		tsc_calc;
213 
214 	unsigned int		strings_size;	/* size of the metadata strings */
215 	char			*strings;	/* metadata strings */
216 
217 	bool			read_compress;
218 	struct tracecmd_compression *compress;
219 
220 	struct host_trace_info	host;
221 	double			ts2secs;
222 	char *			cpustats;
223 	char *			uname;
224 	char *			version;
225 	char *			trace_clock;
226 	struct input_buffer_instance	top_buffer;
227 	struct input_buffer_instance	*buffers;
228 	int			parsing_failures;
229 	struct guest_trace_info	*guest;
230 
231 	struct tracecmd_ftrace	finfo;
232 
233 	struct hook_list	*hooks;
234 	struct pid_addr_maps	*pid_maps;
235 	/* file information */
236 	struct file_section	*sections;
237 	bool			options_init;
238 	unsigned long long	options_start;
239 	unsigned long long	options_last_offset;
240 	size_t			total_file_size;
241 
242 	/* For custom profilers. */
243 	tracecmd_show_data_func	show_data_func;
244 
245 	void			*private;
246 };
247 
248 __thread struct tracecmd_input *tracecmd_curr_thread_handle;
249 
250 #define CHECK_READ_STATE(H, S) ((H)->file_version < FILE_VERSION_SECTIONS && (H)->file_state >= (S))
251 #define HAS_SECTIONS(H) ((H)->flags & TRACECMD_FL_SECTIONED)
252 #define HAS_COMPRESSION(H) ((H)->flags & TRACECMD_FL_COMPRESSION)
253 
254 static int read_options_type(struct tracecmd_input *handle);
255 
tracecmd_set_flag(struct tracecmd_input * handle,int flag)256 void tracecmd_set_flag(struct tracecmd_input *handle, int flag)
257 {
258 	handle->flags |= flag;
259 }
260 
tracecmd_clear_flag(struct tracecmd_input * handle,int flag)261 void tracecmd_clear_flag(struct tracecmd_input *handle, int flag)
262 {
263 	handle->flags &= ~flag;
264 }
265 
tracecmd_get_flags(struct tracecmd_input * handle)266 unsigned long tracecmd_get_flags(struct tracecmd_input *handle)
267 {
268 	return handle->flags;
269 }
270 
tracecmd_get_file_state(struct tracecmd_input * handle)271 enum tracecmd_file_states tracecmd_get_file_state(struct tracecmd_input *handle)
272 {
273 	return handle->file_state;
274 }
275 
tracecmd_set_private(struct tracecmd_input * handle,void * data)276 void tracecmd_set_private(struct tracecmd_input *handle, void *data)
277 {
278 	handle->private = data;
279 }
280 
tracecmd_get_private(struct tracecmd_input * handle)281 void *tracecmd_get_private(struct tracecmd_input *handle)
282 {
283 	return handle->private;
284 }
285 
286 #if DEBUG_RECORD
remove_record(struct page * page,struct tep_record * record)287 static void remove_record(struct page *page, struct tep_record *record)
288 {
289 	if (record->prev)
290 		record->prev->next = record->next;
291 	else
292 		page->records = record->next;
293 	if (record->next)
294 		record->next->prev = record->prev;
295 }
add_record(struct page * page,struct tep_record * record)296 static void add_record(struct page *page, struct tep_record *record)
297 {
298 	if (page->records)
299 		page->records->prev = record;
300 	record->next = page->records;
301 	record->prev = NULL;
302 	page->records = record;
303 }
show_records(struct page ** pages,int nr_pages)304 static const char *show_records(struct page **pages, int nr_pages)
305 {
306 	static char buf[BUFSIZ + 1];
307 	struct tep_record *record;
308 	struct page *page;
309 	int len;
310 	int i;
311 
312 	memset(buf, 0, sizeof(buf));
313 	len = 0;
314 	for (i = 0; i < nr_pages; i++) {
315 		page = pages[i];
316 		if (!page)
317 			continue;
318 		for (record = page->records; record; record = record->next) {
319 			int n;
320 			n = snprintf(buf+len, BUFSIZ - len, " 0x%lx", record->alloc_addr);
321 			len += n;
322 			if (len >= BUFSIZ)
323 				break;
324 		}
325 	}
326 	return buf;
327 }
328 #else
remove_record(struct page * page,struct tep_record * record)329 static inline void remove_record(struct page *page, struct tep_record *record) {}
add_record(struct page * page,struct tep_record * record)330 static inline void add_record(struct page *page, struct tep_record *record) {}
show_records(struct page ** pages,int nr_pages)331 static const char *show_records(struct page **pages, int nr_pages)
332 {
333 	return "";
334 }
335 #endif
336 
337 /**
338  * trace_set_guest_map - set map to input handle
339  * @handle: The handle to set the cpu map to
340  * @map: The cpu map for this handle (to the host)
341  *
342  * Assign the mapping of host to guest for a guest handle.
343  */
trace_set_guest_map(struct tracecmd_input * handle,struct tracecmd_cpu_map * map)344 __hidden void trace_set_guest_map(struct tracecmd_input *handle,
345 				  struct tracecmd_cpu_map *map)
346 {
347 	handle->map = map;
348 }
349 
trace_get_guest_map(struct tracecmd_input * handle)350 __hidden struct tracecmd_cpu_map *trace_get_guest_map(struct tracecmd_input *handle)
351 {
352 	return handle->map;
353 }
354 
trace_set_guest_map_cnt(struct tracecmd_input * handle,int count)355 __hidden void trace_set_guest_map_cnt(struct tracecmd_input *handle, int count)
356 {
357 	handle->map_cnt = count;
358 }
359 
trace_get_guest_map_cnt(struct tracecmd_input * handle)360 __hidden int trace_get_guest_map_cnt(struct tracecmd_input *handle)
361 {
362 	return handle->map_cnt;
363 }
364 
365 static int init_cpu(struct tracecmd_input *handle, int cpu);
366 
do_read_fd(int fd,void * data,size_t size)367 static ssize_t do_read_fd(int fd, void *data, size_t size)
368 {
369 	ssize_t tot = 0;
370 	ssize_t r;
371 
372 	do {
373 		r = read(fd, data + tot, size - tot);
374 		tot += r;
375 
376 		if (!r)
377 			break;
378 		if (r < 0)
379 			return r;
380 	} while (tot != size);
381 
382 	return tot;
383 }
384 
do_lseek(struct tracecmd_input * handle,int offset,int whence)385 static inline int do_lseek(struct tracecmd_input *handle, int offset, int whence)
386 {
387 	if (handle->read_compress)
388 		return tracecmd_compress_lseek(handle->compress, offset, whence);
389 	else
390 		return lseek(handle->fd, offset, whence);
391 }
392 
do_read(struct tracecmd_input * handle,void * data,size_t size)393 static inline ssize_t do_read(struct tracecmd_input *handle, void *data, size_t size)
394 {
395 	if (handle->read_compress)
396 		return tracecmd_compress_buffer_read(handle->compress, data, size);
397 	else
398 		return do_read_fd(handle->fd, data, size);
399 }
400 
401 static ssize_t
do_read_check(struct tracecmd_input * handle,void * data,size_t size)402 do_read_check(struct tracecmd_input *handle, void *data, size_t size)
403 {
404 	ssize_t ret;
405 
406 	ret = do_read(handle, data, size);
407 	if (ret < 0)
408 		return ret;
409 	if (ret != size)
410 		return -1;
411 
412 	return 0;
413 }
414 
read_string(struct tracecmd_input * handle)415 static char *read_string(struct tracecmd_input *handle)
416 {
417 	char buf[BUFSIZ];
418 	char *str = NULL;
419 	size_t size = 0;
420 	ssize_t i;
421 	ssize_t r;
422 
423 	for (;;) {
424 		r = do_read(handle, buf, BUFSIZ);
425 		if (r <= 0)
426 			goto fail;
427 
428 		for (i = 0; i < r; i++) {
429 			if (!buf[i])
430 				break;
431 		}
432 		if (i < r)
433 			break;
434 
435 		if (str) {
436 			size += BUFSIZ;
437 			str = realloc(str, size);
438 			if (!str)
439 				return NULL;
440 			memcpy(str + (size - BUFSIZ), buf, BUFSIZ);
441 		} else {
442 			size = BUFSIZ;
443 			str = malloc(size);
444 			if (!str)
445 				return NULL;
446 			memcpy(str, buf, size);
447 		}
448 	}
449 
450 	/* move the file descriptor to the end of the string */
451 	r = do_lseek(handle, -(r - (i+1)), SEEK_CUR);
452 	if (r < 0)
453 		goto fail;
454 
455 	if (str) {
456 		size += i + 1;
457 		str = realloc(str, size);
458 		if (!str)
459 			return NULL;
460 		memcpy(str + (size - i), buf, i + 1);
461 	} else {
462 		size = i + 1;
463 		str = malloc(size);
464 		if (!str)
465 			return NULL;
466 		memcpy(str, buf, i + 1);
467 	}
468 
469 	return str;
470 
471  fail:
472 	if (str)
473 		free(str);
474 	return NULL;
475 }
476 
read2(struct tracecmd_input * handle,unsigned short * size)477 static int read2(struct tracecmd_input *handle, unsigned short *size)
478 {
479 	struct tep_handle *pevent = handle->pevent;
480 	unsigned short data;
481 
482 	if (do_read_check(handle, &data, 2))
483 		return -1;
484 
485 	*size = tep_read_number(pevent, &data, 2);
486 	return 0;
487 }
488 
read4(struct tracecmd_input * handle,unsigned int * size)489 static int read4(struct tracecmd_input *handle, unsigned int *size)
490 {
491 	struct tep_handle *pevent = handle->pevent;
492 	unsigned int data;
493 
494 	if (do_read_check(handle, &data, 4))
495 		return -1;
496 
497 	*size = tep_read_number(pevent, &data, 4);
498 	return 0;
499 }
500 
read8(struct tracecmd_input * handle,unsigned long long * size)501 static int read8(struct tracecmd_input *handle, unsigned long long *size)
502 {
503 	struct tep_handle *pevent = handle->pevent;
504 	unsigned long long data;
505 
506 	if (do_read_check(handle, &data, 8))
507 		return -1;
508 
509 	*size = tep_read_number(pevent, &data, 8);
510 	return 0;
511 }
512 
in_uncompress_reset(struct tracecmd_input * handle)513 __hidden void in_uncompress_reset(struct tracecmd_input *handle)
514 {
515 	if (handle->compress) {
516 		handle->read_compress = false;
517 		tracecmd_compress_reset(handle->compress);
518 	}
519 }
520 
in_uncompress_block(struct tracecmd_input * handle)521 __hidden int in_uncompress_block(struct tracecmd_input *handle)
522 {
523 	int ret = 0;
524 
525 	if (handle->compress) {
526 		ret = tracecmd_uncompress_block(handle->compress);
527 		if (!ret)
528 			handle->read_compress = true;
529 	}
530 	return ret;
531 }
532 
section_get(struct tracecmd_input * handle,int id)533 static struct file_section *section_get(struct tracecmd_input *handle, int id)
534 {
535 	struct file_section *sec;
536 
537 	for (sec = handle->sections; sec; sec = sec->next) {
538 		if (sec->id == id)
539 			return sec;
540 	}
541 
542 	return NULL;
543 }
544 
section_open(struct tracecmd_input * handle,int id)545 static struct file_section *section_open(struct tracecmd_input *handle, int id)
546 {
547 	struct file_section *sec = section_get(handle, id);
548 
549 	if (!sec)
550 		return NULL;
551 
552 	if (lseek(handle->fd, sec->data_offset, SEEK_SET) == (off_t)-1)
553 		return NULL;
554 
555 	if ((sec->flags & TRACECMD_SEC_FL_COMPRESS) && in_uncompress_block(handle))
556 		return NULL;
557 
558 	return sec;
559 }
560 
section_close(struct tracecmd_input * handle,struct file_section * sec)561 static void section_close(struct tracecmd_input *handle, struct file_section *sec)
562 {
563 	if (sec->flags & TRACECMD_SEC_FL_COMPRESS)
564 		in_uncompress_reset(handle);
565 }
566 
section_add_or_update(struct tracecmd_input * handle,int id,int flags,unsigned long long section_offset,unsigned long long data_offset)567 static int section_add_or_update(struct tracecmd_input *handle, int id, int flags,
568 				 unsigned long long section_offset,
569 				 unsigned long long data_offset)
570 {
571 	struct file_section *sec = section_get(handle, id);
572 
573 	if (!sec) {
574 		sec = calloc(1, sizeof(struct file_section));
575 		if (!sec)
576 			return -1;
577 		sec->next = handle->sections;
578 		handle->sections = sec;
579 		sec->id = id;
580 	}
581 
582 	if (section_offset)
583 		sec->section_offset = section_offset;
584 	if (data_offset)
585 		sec->data_offset = data_offset;
586 	if (flags >= 0)
587 		sec->flags = flags;
588 
589 	return 0;
590 }
591 
read_header_files(struct tracecmd_input * handle)592 static int read_header_files(struct tracecmd_input *handle)
593 {
594 	struct tep_handle *pevent = handle->pevent;
595 	unsigned long long size;
596 	char *header;
597 	char buf[BUFSIZ];
598 
599 	if (CHECK_READ_STATE(handle, TRACECMD_FILE_HEADERS))
600 		return 0;
601 
602 	if (!HAS_SECTIONS(handle))
603 		section_add_or_update(handle, TRACECMD_OPTION_HEADER_INFO, 0, 0,
604 				      lseek(handle->fd, 0, SEEK_CUR));
605 
606 	if (do_read_check(handle, buf, 12))
607 		return -1;
608 
609 	if (memcmp(buf, "header_page", 12) != 0)
610 		return -1;
611 
612 	if (read8(handle, &size) < 0)
613 		return -1;
614 
615 	header = malloc(size);
616 	if (!header)
617 		return -1;
618 
619 	if (do_read_check(handle, header, size))
620 		goto failed_read;
621 
622 	tep_parse_header_page(pevent, header, size, handle->long_size);
623 	free(header);
624 
625 	/*
626 	 * The size field in the page is of type long,
627 	 * use that instead, since it represents the kernel.
628 	 */
629 	handle->long_size = tep_get_header_page_size(pevent);
630 
631 	if (do_read_check(handle, buf, 13))
632 		return -1;
633 
634 	if (memcmp(buf, "header_event", 13) != 0)
635 		return -1;
636 
637 	if (read8(handle, &size) < 0)
638 		return -1;
639 
640 	header = malloc(size);
641 	if (!header)
642 		return -1;
643 
644 	if (do_read_check(handle, header, size))
645 		goto failed_read;
646 
647 	free(header);
648 
649 	handle->file_state = TRACECMD_FILE_HEADERS;
650 
651 	return 0;
652 
653  failed_read:
654 	free(header);
655 	return -1;
656 }
657 
regex_event_buf(const char * file,int size,regex_t * epreg)658 static int regex_event_buf(const char *file, int size, regex_t *epreg)
659 {
660 	char *buf;
661 	char *line;
662 	int ret;
663 
664 	buf = malloc(size + 1);
665 	if (!buf) {
666 		tracecmd_warning("Insufficient memory");
667 		return 0;
668 	}
669 
670 	strncpy(buf, file, size);
671 	buf[size] = 0;
672 
673 	/* get the name from the first line */
674 	line = strtok(buf, "\n");
675 	if (!line) {
676 		tracecmd_warning("No newline found in '%s'", buf);
677 		free(buf);
678 		return 0;
679 	}
680 	/* skip name if it is there */
681 	if (strncmp(line, "name: ", 6) == 0)
682 		line += 6;
683 
684 	ret = regexec(epreg, line, 0, NULL, 0) == 0;
685 
686 	free(buf);
687 
688 	return ret;
689 }
690 
read_ftrace_file(struct tracecmd_input * handle,unsigned long long size,int print,regex_t * epreg)691 static int read_ftrace_file(struct tracecmd_input *handle,
692 			    unsigned long long size,
693 			    int print, regex_t *epreg)
694 {
695 	struct tep_handle *pevent = handle->pevent;
696 	char *buf;
697 
698 	buf = malloc(size);
699 	if (!buf)
700 		return -1;
701 	if (do_read_check(handle, buf, size)) {
702 		free(buf);
703 		return -1;
704 	}
705 
706 	if (epreg) {
707 		if (print || regex_event_buf(buf, size, epreg))
708 			printf("%.*s\n", (int)size, buf);
709 	} else {
710 		if (tep_parse_event(pevent, buf, size, "ftrace"))
711 			handle->parsing_failures++;
712 	}
713 	free(buf);
714 
715 	return 0;
716 }
717 
read_event_file(struct tracecmd_input * handle,char * system,unsigned long long size,int print,int * sys_printed,regex_t * epreg)718 static int read_event_file(struct tracecmd_input *handle,
719 			   char *system, unsigned long long size,
720 			   int print, int *sys_printed,
721 			   regex_t *epreg)
722 {
723 	struct tep_handle *pevent = handle->pevent;
724 	char *buf;
725 
726 	buf = malloc(size);
727 	if (!buf)
728 		return -1;
729 
730 	if (do_read_check(handle, buf, size)) {
731 		free(buf);
732 		return -1;
733 	}
734 
735 	if (epreg) {
736 		if (print || regex_event_buf(buf, size, epreg)) {
737 			if (!*sys_printed) {
738 				printf("\nsystem: %s\n", system);
739 				*sys_printed = 1;
740 			}
741 			printf("%.*s\n", (int)size, buf);
742 		}
743 	} else {
744 		if (tep_parse_event(pevent, buf, size, system))
745 			handle->parsing_failures++;
746 	}
747 	free(buf);
748 
749 	return 0;
750 }
751 
make_preg_files(const char * regex,regex_t * system,regex_t * event,int * unique)752 static int make_preg_files(const char *regex, regex_t *system,
753 			   regex_t *event, int *unique)
754 {
755 	char *buf;
756 	char *sstr;
757 	char *estr;
758 	int ret;
759 
760 	/* unique is set if a colon is found */
761 	*unique = 0;
762 
763 	/* split "system:event" into "system" and "event" */
764 
765 	buf = strdup(regex);
766 	if (!buf)
767 		return -ENOMEM;
768 
769 	sstr = strtok(buf, ":");
770 	estr = strtok(NULL, ":");
771 
772 	/* If no colon is found, set event == system */
773 	if (!estr)
774 		estr = sstr;
775 	else
776 		*unique = 1;
777 
778 	ret = regcomp(system, sstr, REG_ICASE|REG_NOSUB);
779 	if (ret) {
780 		tracecmd_warning("Bad regular expression '%s'", sstr);
781 		goto out;
782 	}
783 
784 	ret = regcomp(event, estr, REG_ICASE|REG_NOSUB);
785 	if (ret) {
786 		tracecmd_warning("Bad regular expression '%s'", estr);
787 		goto out;
788 	}
789 
790  out:
791 	free(buf);
792 	return ret;
793 }
794 
read_ftrace_files(struct tracecmd_input * handle,const char * regex)795 static int read_ftrace_files(struct tracecmd_input *handle, const char *regex)
796 {
797 	unsigned long long size;
798 	regex_t spreg;
799 	regex_t epreg;
800 	regex_t *sreg = NULL;
801 	regex_t *ereg = NULL;
802 	unsigned int count, i;
803 	int print_all = 0;
804 	int unique;
805 	int ret;
806 
807 	if (CHECK_READ_STATE(handle, TRACECMD_FILE_FTRACE_EVENTS))
808 		return 0;
809 
810 	if (!HAS_SECTIONS(handle))
811 		section_add_or_update(handle, TRACECMD_OPTION_FTRACE_EVENTS, 0, 0,
812 				      lseek(handle->fd, 0, SEEK_CUR));
813 
814 	if (regex) {
815 		sreg = &spreg;
816 		ereg = &epreg;
817 		ret = make_preg_files(regex, sreg, ereg, &unique);
818 		if (ret)
819 			return -1;
820 
821 		if (regexec(sreg, "ftrace", 0, NULL, 0) == 0) {
822 			/*
823 			 * If the system matches a regex that did
824 			 * not contain a colon, then print all events.
825 			 */
826 			if (!unique)
827 				print_all = 1;
828 		} else if (unique) {
829 			/*
830 			 * The user specified a unique event that did
831 			 * not match the ftrace system. Don't print any
832 			 * events here.
833 			 */
834 			regfree(sreg);
835 			regfree(ereg);
836 			sreg = NULL;
837 			ereg = NULL;
838 		}
839 	}
840 
841 	ret = read4(handle, &count);
842 	if (ret < 0)
843 		goto out;
844 
845 	for (i = 0; i < count; i++) {
846 		ret = read8(handle, &size);
847 		if (ret < 0)
848 			goto out;
849 		ret = read_ftrace_file(handle, size, print_all, ereg);
850 		if (ret < 0)
851 			goto out;
852 	}
853 
854 	handle->file_state = TRACECMD_FILE_FTRACE_EVENTS;
855 	ret = 0;
856 out:
857 	if (sreg) {
858 		regfree(sreg);
859 		regfree(ereg);
860 	}
861 
862 	return ret;
863 }
864 
read_event_files(struct tracecmd_input * handle,const char * regex)865 static int read_event_files(struct tracecmd_input *handle, const char *regex)
866 {
867 	unsigned long long size;
868 	char *system = NULL;
869 	regex_t spreg;
870 	regex_t epreg;
871 	regex_t *sreg = NULL;
872 	regex_t *ereg = NULL;
873 	regex_t *reg;
874 	unsigned int systems;
875 	unsigned int count;
876 	unsigned int i, x;
877 	int print_all;
878 	int sys_printed;
879 	int unique;
880 	int ret;
881 
882 	if (CHECK_READ_STATE(handle, TRACECMD_FILE_ALL_EVENTS))
883 		return 0;
884 
885 	if (!HAS_SECTIONS(handle))
886 		section_add_or_update(handle, TRACECMD_OPTION_EVENT_FORMATS, 0, 0,
887 				      lseek(handle->fd, 0, SEEK_CUR));
888 
889 	if (regex) {
890 		sreg = &spreg;
891 		ereg = &epreg;
892 		ret = make_preg_files(regex, sreg, ereg, &unique);
893 		if (ret)
894 			return -1;
895 	}
896 
897 	ret = read4(handle, &systems);
898 	if (ret < 0)
899 		goto out;
900 
901 	for (i = 0; i < systems; i++) {
902 		system = read_string(handle);
903 		if (!system) {
904 			ret = -1;
905 			goto out;
906 		}
907 
908 		sys_printed = 0;
909 		print_all = 0;
910 		reg = ereg;
911 
912 		if (sreg) {
913 			if (regexec(sreg, system, 0, NULL, 0) == 0) {
914 				/*
915 				 * If the user passed in a regex that
916 				 * did not contain a colon, then we can
917 				 * print all the events of this system.
918 				 */
919 				if (!unique)
920 					print_all = 1;
921 			} else if (unique) {
922 				/*
923 				 * The user passed in a unique event that
924 				 * specified a specific system and event.
925 				 * Since this system doesn't match this
926 				 * event, then we don't print any events
927 				 * for this system.
928 				 */
929 				reg = NULL;
930 			}
931 		}
932 
933 		ret = read4(handle, &count);
934 		if (ret < 0)
935 			goto out;
936 
937 		for (x=0; x < count; x++) {
938 			ret = read8(handle, &size);
939 			if (ret < 0)
940 				goto out;
941 
942 			ret = read_event_file(handle, system, size,
943 					      print_all, &sys_printed,
944 					      reg);
945 			if (ret < 0)
946 				goto out;
947 		}
948 		free(system);
949 	}
950 	system = NULL;
951 
952 	handle->file_state = TRACECMD_FILE_ALL_EVENTS;
953 	ret = 0;
954  out:
955 	if (sreg) {
956 		regfree(sreg);
957 		regfree(ereg);
958 	}
959 
960 	free(system);
961 	return ret;
962 }
963 
read_proc_kallsyms(struct tracecmd_input * handle)964 static int read_proc_kallsyms(struct tracecmd_input *handle)
965 {
966 	struct tep_handle *tep = handle->pevent;
967 	unsigned int size;
968 	char *buf;
969 
970 	if (CHECK_READ_STATE(handle, TRACECMD_FILE_KALLSYMS))
971 		return 0;
972 	if (!HAS_SECTIONS(handle))
973 		section_add_or_update(handle, TRACECMD_OPTION_KALLSYMS, 0, 0,
974 				      lseek(handle->fd, 0, SEEK_CUR));
975 
976 	if (read4(handle, &size) < 0)
977 		return -1;
978 	if (!size) {
979 		handle->file_state = TRACECMD_FILE_KALLSYMS;
980 		return 0; /* OK? */
981 	}
982 
983 	buf = malloc(size+1);
984 	if (!buf)
985 		return -1;
986 	if (do_read_check(handle, buf, size)){
987 		free(buf);
988 		return -1;
989 	}
990 	buf[size] = 0;
991 
992 	tep_parse_kallsyms(tep, buf);
993 
994 	free(buf);
995 
996 	handle->file_state = TRACECMD_FILE_KALLSYMS;
997 
998 	return 0;
999 }
1000 
read_ftrace_printk(struct tracecmd_input * handle)1001 static int read_ftrace_printk(struct tracecmd_input *handle)
1002 {
1003 	unsigned int size;
1004 	char *buf;
1005 
1006 	if (CHECK_READ_STATE(handle, TRACECMD_FILE_PRINTK))
1007 		return 0;
1008 
1009 	if (!HAS_SECTIONS(handle))
1010 		section_add_or_update(handle, TRACECMD_OPTION_PRINTK, 0, 0,
1011 				      lseek(handle->fd, 0, SEEK_CUR));
1012 
1013 	if (read4(handle, &size) < 0)
1014 		return -1;
1015 	if (!size) {
1016 		handle->file_state = TRACECMD_FILE_PRINTK;
1017 		return 0; /* OK? */
1018 	}
1019 
1020 	buf = malloc(size + 1);
1021 	if (!buf)
1022 		return -1;
1023 	if (do_read_check(handle, buf, size)) {
1024 		free(buf);
1025 		return -1;
1026 	}
1027 
1028 	buf[size] = 0;
1029 
1030 	tep_parse_printk_formats(handle->pevent, buf);
1031 
1032 	free(buf);
1033 
1034 	handle->file_state = TRACECMD_FILE_PRINTK;
1035 
1036 	return 0;
1037 }
1038 
1039 static int read_and_parse_cmdlines(struct tracecmd_input *handle);
1040 
1041 /**
1042  * tracecmd_get_parsing_failures - get the count of parsing failures
1043  * @handle: input handle for the trace.dat file
1044  *
1045  * This returns the count of failures while parsing the event files
1046  */
tracecmd_get_parsing_failures(struct tracecmd_input * handle)1047 int tracecmd_get_parsing_failures(struct tracecmd_input *handle)
1048 {
1049 	if (handle)
1050 		return handle->parsing_failures;
1051 	return 0;
1052 }
1053 
read_cpus(struct tracecmd_input * handle)1054 static int read_cpus(struct tracecmd_input *handle)
1055 {
1056 	unsigned int cpus;
1057 
1058 	if (CHECK_READ_STATE(handle, TRACECMD_FILE_CPU_COUNT))
1059 		return 0;
1060 
1061 	if (read4(handle, &cpus) < 0)
1062 		return -1;
1063 
1064 	handle->cpus = cpus;
1065 	handle->max_cpu = cpus;
1066 	tep_set_cpus(handle->pevent, handle->cpus);
1067 	handle->file_state = TRACECMD_FILE_CPU_COUNT;
1068 
1069 	return 0;
1070 }
1071 
read_headers_v6(struct tracecmd_input * handle,enum tracecmd_file_states state,const char * regex)1072 static int read_headers_v6(struct tracecmd_input *handle, enum tracecmd_file_states state,
1073 			   const char *regex)
1074 {
1075 	int ret;
1076 
1077 	/* Set to read all if state is zero */
1078 	if (!state)
1079 		state = TRACECMD_FILE_OPTIONS;
1080 
1081 	if (state <= handle->file_state)
1082 		return 0;
1083 
1084 	handle->parsing_failures = 0;
1085 
1086 	ret = read_header_files(handle);
1087 	if (ret < 0)
1088 		return -1;
1089 
1090 	if (state <= handle->file_state)
1091 		return 0;
1092 
1093 	ret = read_ftrace_files(handle, NULL);
1094 	if (ret < 0)
1095 		return -1;
1096 
1097 	if (state <= handle->file_state)
1098 		return 0;
1099 
1100 	ret = read_event_files(handle, regex);
1101 	if (ret < 0)
1102 		return -1;
1103 
1104 	if (state <= handle->file_state)
1105 		return 0;
1106 
1107 	ret = read_proc_kallsyms(handle);
1108 	if (ret < 0)
1109 		return -1;
1110 
1111 	if (state <= handle->file_state)
1112 		return 0;
1113 
1114 	ret = read_ftrace_printk(handle);
1115 	if (ret < 0)
1116 		return -1;
1117 
1118 	if (state <= handle->file_state)
1119 		return 0;
1120 
1121 	if (read_and_parse_cmdlines(handle) < 0)
1122 		return -1;
1123 
1124 	if (state <= handle->file_state)
1125 		return 0;
1126 
1127 	if (read_cpus(handle) < 0)
1128 		return -1;
1129 
1130 	if (state <= handle->file_state)
1131 		return 0;
1132 
1133 	if (read_options_type(handle) < 0)
1134 		return -1;
1135 
1136 	return 0;
1137 }
1138 
1139 static int handle_options(struct tracecmd_input *handle);
1140 
get_metadata_string(struct tracecmd_input * handle,int offset)1141 static const char *get_metadata_string(struct tracecmd_input *handle, int offset)
1142 {
1143 	if (!handle || !handle->strings || offset < 0 || handle->strings_size >= offset)
1144 		return NULL;
1145 
1146 	return handle->strings + offset;
1147 }
1148 
read_section_header(struct tracecmd_input * handle,unsigned short * id,unsigned short * flags,unsigned long long * size,const char ** description)1149 static int read_section_header(struct tracecmd_input *handle, unsigned short *id,
1150 			       unsigned short *flags, unsigned long long *size, const char **description)
1151 {
1152 	unsigned short fl;
1153 	unsigned short sec_id;
1154 	unsigned long long sz;
1155 	int desc;
1156 
1157 	if (read2(handle, &sec_id))
1158 		return -1;
1159 	if (read2(handle, &fl))
1160 		return -1;
1161 	if (read4(handle, (unsigned int *)&desc))
1162 		return -1;
1163 	if (read8(handle, &sz))
1164 		return -1;
1165 
1166 	if (id)
1167 		*id = sec_id;
1168 	if (flags)
1169 		*flags = fl;
1170 	if (size)
1171 		*size = sz;
1172 	if (description)
1173 		*description = get_metadata_string(handle, desc);
1174 
1175 	return 0;
1176 }
1177 
handle_section(struct tracecmd_input * handle,struct file_section * section,const char * regex)1178 static int handle_section(struct tracecmd_input *handle, struct file_section *section,
1179 			  const char *regex)
1180 {
1181 	unsigned short id, flags;
1182 	unsigned long long size;
1183 	int ret;
1184 
1185 	if (lseek(handle->fd, section->section_offset, SEEK_SET) == (off_t)-1)
1186 		return -1;
1187 	if (read_section_header(handle, &id, &flags, &size, NULL))
1188 		return -1;
1189 	section->flags = flags;
1190 	if (id != section->id)
1191 		return -1;
1192 
1193 	section->data_offset = lseek(handle->fd, 0, SEEK_CUR);
1194 	if ((section->flags & TRACECMD_SEC_FL_COMPRESS) && in_uncompress_block(handle))
1195 		return -1;
1196 
1197 	switch (section->id) {
1198 	case TRACECMD_OPTION_HEADER_INFO:
1199 		ret = read_header_files(handle);
1200 		break;
1201 	case TRACECMD_OPTION_FTRACE_EVENTS:
1202 		ret = read_ftrace_files(handle, NULL);
1203 		break;
1204 	case TRACECMD_OPTION_EVENT_FORMATS:
1205 		ret = read_event_files(handle, regex);
1206 		break;
1207 	case TRACECMD_OPTION_KALLSYMS:
1208 		ret = read_proc_kallsyms(handle);
1209 		break;
1210 	case TRACECMD_OPTION_PRINTK:
1211 		ret = read_ftrace_printk(handle);
1212 		break;
1213 	case TRACECMD_OPTION_CMDLINES:
1214 		ret = read_and_parse_cmdlines(handle);
1215 		break;
1216 	default:
1217 		ret = 0;
1218 		break;
1219 	}
1220 
1221 	if (section->flags & TRACECMD_SEC_FL_COMPRESS)
1222 		in_uncompress_reset(handle);
1223 
1224 	return ret;
1225 }
1226 
read_headers(struct tracecmd_input * handle,const char * regex)1227 static int read_headers(struct tracecmd_input *handle, const char *regex)
1228 {
1229 	struct file_section *section;
1230 
1231 	if (handle->options_init)
1232 		return 0;
1233 
1234 	if (!handle->options_start)
1235 		return -1;
1236 
1237 	if (lseek(handle->fd, handle->options_start, SEEK_SET) == (off_t)-1) {
1238 		tracecmd_warning("Filed to goto options offset %lld", handle->options_start);
1239 		return -1;
1240 	}
1241 
1242 	if (handle_options(handle))
1243 		return -1;
1244 
1245 	section = handle->sections;
1246 	while (section) {
1247 		if (handle_section(handle, section, NULL))
1248 			return -1;
1249 		section = section->next;
1250 	}
1251 
1252 	handle->options_init = true;
1253 	return 0;
1254 }
1255 
1256 /**
1257  * tracecmd_read_headers - read the header information from trace.dat
1258  * @handle: input handle for the trace.dat file
1259  * @state: The state to read up to or zero to read up to options.
1260  *
1261  * This reads the trace.dat file for various information. Like the
1262  * format of the ring buffer, event formats, ftrace formats, kallsyms
1263  * and printk. This may be called multiple times with different @state
1264  * values, to read partial data at a time. It will always continue
1265  * where it left off.
1266  */
tracecmd_read_headers(struct tracecmd_input * handle,enum tracecmd_file_states state)1267 int tracecmd_read_headers(struct tracecmd_input *handle,
1268 			  enum tracecmd_file_states state)
1269 {
1270 	if (!HAS_SECTIONS(handle))
1271 		return read_headers_v6(handle, state, NULL);
1272 	return read_headers(handle, NULL);
1273 }
1274 
calc_page_offset(struct tracecmd_input * handle,unsigned long long offset)1275 static unsigned long long calc_page_offset(struct tracecmd_input *handle,
1276 					   unsigned long long offset)
1277 {
1278 	return offset & ~(handle->page_size - 1);
1279 }
1280 
read_page(struct tracecmd_input * handle,off_t offset,int cpu,void * map)1281 static int read_page(struct tracecmd_input *handle, off_t offset,
1282 		     int cpu, void *map)
1283 {
1284 	off_t save_seek;
1285 	off_t ret;
1286 
1287 	if (handle->use_pipe) {
1288 		ret = read(handle->cpu_data[cpu].pipe_fd, map, handle->page_size);
1289 		/* Set EAGAIN if the pipe is empty */
1290 		if (ret < 0) {
1291 			errno = EAGAIN;
1292 			return -1;
1293 
1294 		} else if (ret == 0) {
1295 			/* Set EINVAL when the pipe has closed */
1296 			errno = EINVAL;
1297 			return -1;
1298 		}
1299 		return 0;
1300 	}
1301 
1302 	/* other parts of the code may expect the pointer to not move */
1303 	save_seek = lseek(handle->fd, 0, SEEK_CUR);
1304 
1305 	ret = lseek(handle->fd, offset, SEEK_SET);
1306 	if (ret < 0)
1307 		return -1;
1308 	ret = read(handle->fd, map, handle->page_size);
1309 	if (ret < 0)
1310 		return -1;
1311 
1312 	/* reset the file pointer back */
1313 	lseek(handle->fd, save_seek, SEEK_SET);
1314 
1315 	return 0;
1316 }
1317 
1318 /* page_map_size must be a power of two */
normalize_size(unsigned long long size)1319 static unsigned long long normalize_size(unsigned long long size)
1320 {
1321 	/* From Hacker's Delight: or bits after first set bit to all 1s */
1322 	size |= (size >> 1);
1323 	size |= (size >> 2);
1324 	size |= (size >> 4);
1325 	size |= (size >> 8);
1326 	size |= (size >> 16);
1327 	size |= (size >> 32);
1328 
1329 	/* Clear all bits except first one for previous power of two */
1330 	return size - (size >> 1);
1331 }
1332 
free_page_map(struct page_map * page_map)1333 static void free_page_map(struct page_map *page_map)
1334 {
1335 	page_map->ref_count--;
1336 	if (page_map->ref_count)
1337 		return;
1338 
1339 	munmap(page_map->map, page_map->size);
1340 	list_del(&page_map->list);
1341 	free(page_map);
1342 }
1343 
1344 #define CHUNK_CHECK_OFFSET(C, O)	((O) >= (C)->offset && (O) < ((C)->offset + (C)->size))
1345 
chunk_cmp(const void * A,const void * B)1346 static int chunk_cmp(const void *A, const void *B)
1347 {
1348 	const struct tracecmd_compress_chunk *a = A;
1349 	const struct tracecmd_compress_chunk *b = B;
1350 
1351 	if (CHUNK_CHECK_OFFSET(b, a->offset))
1352 		return 0;
1353 
1354 	if (a->offset < b->offset)
1355 		return -1;
1356 
1357 	return 1;
1358 }
1359 
get_zchunk(struct cpu_data * cpu,off_t offset)1360 static struct tracecmd_compress_chunk *get_zchunk(struct cpu_data *cpu, off_t offset)
1361 {
1362 	struct cpu_zdata *cpuz = &cpu->compress;
1363 	struct tracecmd_compress_chunk *chunk;
1364 	struct tracecmd_compress_chunk key;
1365 
1366 	if (!cpuz->chunks)
1367 		return NULL;
1368 
1369 	if (offset > (cpuz->chunks[cpuz->count - 1].offset + cpuz->chunks[cpuz->count - 1].size))
1370 		return NULL;
1371 
1372 	/* check if the requested offset is in the last requested chunk or in the next chunk */
1373 	if (CHUNK_CHECK_OFFSET(cpuz->chunks + cpuz->last_chunk, offset))
1374 		return cpuz->chunks + cpuz->last_chunk;
1375 
1376 	cpuz->last_chunk++;
1377 	if (cpuz->last_chunk < cpuz->count &&
1378 	    CHUNK_CHECK_OFFSET(cpuz->chunks + cpuz->last_chunk, offset))
1379 		return cpuz->chunks + cpuz->last_chunk;
1380 
1381 	key.offset = offset;
1382 	chunk = bsearch(&key, cpuz->chunks, cpuz->count, sizeof(*chunk), chunk_cmp);
1383 
1384 	if (!chunk) /* should never happen */
1385 		return NULL;
1386 
1387 	cpuz->last_chunk = chunk - cpuz->chunks;
1388 	return chunk;
1389 }
1390 
free_zpage(struct cpu_data * cpu_data,off_t offset)1391 static void free_zpage(struct cpu_data *cpu_data, off_t offset)
1392 {
1393 	struct trace_rbtree_node *node;
1394 	struct zchunk_cache *cache;
1395 
1396 	offset -= cpu_data->file_offset;
1397 
1398 	node = trace_rbtree_find(&cpu_data->compress.cache, (void *)&offset);
1399 
1400 	if (!node)
1401 		return;
1402 
1403 	cache = container_of(node, struct zchunk_cache, node);
1404 
1405 	cache->ref--;
1406 	if (cache->ref)
1407 		return;
1408 
1409 	trace_rbtree_delete(&cpu_data->compress.cache, node);
1410 
1411 	free(cache->map);
1412 	free(cache);
1413 }
1414 
read_zpage(struct tracecmd_input * handle,int cpu,off_t offset)1415 static void *read_zpage(struct tracecmd_input *handle, int cpu, off_t offset)
1416 {
1417 	struct cpu_data *cpu_data = &handle->cpu_data[cpu];
1418 	struct tracecmd_compress_chunk *chunk;
1419 	struct trace_rbtree_node *node;
1420 	struct zchunk_cache *cache;
1421 	void *map = NULL;
1422 	int pindex;
1423 	int size;
1424 
1425 	offset -= cpu_data->file_offset;
1426 
1427 	/* Look in the cache of already loaded chunks */
1428 	node = trace_rbtree_find(&cpu_data->compress.cache, (void *)&offset);
1429 	if (node) {
1430 		cache = container_of(node, struct zchunk_cache, node);
1431 		cache->ref++;
1432 		goto out;
1433 	}
1434 
1435 	chunk =  get_zchunk(cpu_data, offset);
1436 	if (!chunk)
1437 		return NULL;
1438 
1439 	size = handle->page_size > chunk->size ? handle->page_size : chunk->size;
1440 	map = malloc(size);
1441 	if (!map)
1442 		return NULL;
1443 
1444 	if (tracecmd_uncompress_chunk(handle->compress, chunk, map) < 0)
1445 		goto error;
1446 
1447 	cache = calloc(1, sizeof(struct zchunk_cache));
1448 	if (!cache)
1449 		goto error;
1450 
1451 	cache->ref = 1;
1452 	cache->chunk = chunk;
1453 	cache->map = map;
1454 	trace_rbtree_insert(&cpu_data->compress.cache, &cache->node);
1455 
1456 	/* a chunk can hold multiple pages, get the requested one */
1457 out:
1458 	pindex = (offset - cache->chunk->offset) / handle->page_size;
1459 	return cache->map + (pindex * handle->page_size);
1460 error:
1461 	free(map);
1462 	return NULL;
1463 }
1464 
allocate_page_map(struct tracecmd_input * handle,struct page * page,int cpu,off_t offset)1465 static void *allocate_page_map(struct tracecmd_input *handle,
1466 			       struct page *page, int cpu, off_t offset)
1467 {
1468 	struct cpu_data *cpu_data = &handle->cpu_data[cpu];
1469 	struct page_map *page_map;
1470 	off_t map_size;
1471 	off_t map_offset;
1472 	void *map;
1473 	int ret;
1474 	int fd;
1475 
1476 	if (handle->cpu_compressed) {
1477 		if (handle->read_zpage)
1478 			return read_zpage(handle, cpu, offset);
1479 		offset -= cpu_data->file_offset;
1480 	}
1481 
1482 	if (handle->read_page) {
1483 		map = malloc(handle->page_size);
1484 		if (!map)
1485 			return NULL;
1486 		ret = read_page(handle, offset, cpu, map);
1487 		if (ret < 0) {
1488 			free(map);
1489 			return NULL;
1490 		}
1491 		return map;
1492 	}
1493 
1494 	map_size = handle->page_map_size;
1495 	map_offset = offset & ~(map_size - 1);
1496 
1497 	if (!handle->cpu_compressed && map_offset < cpu_data->file_offset) {
1498 		map_size -= cpu_data->file_offset - map_offset;
1499 		map_offset = cpu_data->file_offset;
1500 	}
1501 
1502 	page_map = cpu_data->page_map;
1503 
1504 	if (page_map && page_map->offset == map_offset)
1505 		goto out;
1506 
1507 	list_for_each_entry(page_map, &cpu_data->page_maps, list) {
1508 		if (page_map->offset == map_offset)
1509 			goto out;
1510 	}
1511 
1512 	page_map = calloc(1, sizeof(*page_map));
1513 	if (!page_map)
1514 		return NULL;
1515 
1516 	if (map_offset + map_size > cpu_data->file_offset + cpu_data->file_size)
1517 		map_size -= map_offset + map_size -
1518 			(cpu_data->file_offset + cpu_data->file_size);
1519 
1520 	if (cpu_data->compress.fd >= 0)
1521 		fd = cpu_data->compress.fd;
1522 	else
1523 		fd = handle->fd;
1524  again:
1525 	page_map->size = map_size;
1526 	page_map->offset = map_offset;
1527 
1528 	page_map->map = mmap(NULL, map_size, PROT_READ, MAP_PRIVATE, fd, map_offset);
1529 
1530 	if (page_map->map == MAP_FAILED) {
1531 		/* Try a smaller map */
1532 		map_size >>= 1;
1533 		if (map_size < handle->page_size) {
1534 			free(page_map);
1535 			return NULL;
1536 		}
1537 		handle->page_map_size = map_size;
1538 		map_offset = offset & ~(map_size - 1);
1539 		/*
1540 		 * Note, it is now possible to get duplicate memory
1541 		 * maps. But that's fine, the previous maps with
1542 		 * larger sizes will eventually be unmapped.
1543 		 */
1544 		goto again;
1545 	}
1546 
1547 	list_add(&page_map->list, &cpu_data->page_maps);
1548  out:
1549 	if (cpu_data->page_map != page_map) {
1550 		struct page_map *old_map = cpu_data->page_map;
1551 		cpu_data->page_map = page_map;
1552 		page_map->ref_count++;
1553 		if (old_map)
1554 			free_page_map(old_map);
1555 	}
1556 	page->page_map = page_map;
1557 	page_map->ref_count++;
1558 	return page_map->map + offset - page_map->offset;
1559 }
1560 
allocate_page(struct tracecmd_input * handle,int cpu,off_t offset)1561 static struct page *allocate_page(struct tracecmd_input *handle,
1562 				  int cpu, off_t offset)
1563 {
1564 	struct cpu_data *cpu_data = &handle->cpu_data[cpu];
1565 	struct page **pages;
1566 	struct page *page;
1567 	int index;
1568 
1569 	index = (offset - cpu_data->file_offset) / handle->page_size;
1570 	if (index >= cpu_data->nr_pages) {
1571 		pages = realloc(cpu_data->pages, (index + 1) * sizeof(*cpu_data->pages));
1572 		if (!pages)
1573 			return NULL;
1574 		memset(pages + cpu_data->nr_pages, 0,
1575 		       (index + 1 - cpu_data->nr_pages) * sizeof(*cpu_data->pages));
1576 		cpu_data->pages = pages;
1577 		cpu_data->nr_pages = index + 1;
1578 	}
1579 	if (cpu_data->pages[index]) {
1580 		cpu_data->pages[index]->ref_count++;
1581 		return cpu_data->pages[index];
1582 	}
1583 
1584 	page = malloc(sizeof(*page));
1585 	if (!page)
1586 		return NULL;
1587 
1588 	memset(page, 0, sizeof(*page));
1589 	page->offset = offset;
1590 	page->handle = handle;
1591 	page->cpu = cpu;
1592 
1593 	page->map = allocate_page_map(handle, page, cpu, offset);
1594 
1595 	if (!page->map) {
1596 		free(page);
1597 		return NULL;
1598 	}
1599 
1600 	cpu_data->pages[index] = page;
1601 	cpu_data->page_cnt++;
1602 	page->ref_count = 1;
1603 
1604 	return page;
1605 }
1606 
__free_page(struct tracecmd_input * handle,struct page * page)1607 static void __free_page(struct tracecmd_input *handle, struct page *page)
1608 {
1609 	struct cpu_data *cpu_data = &handle->cpu_data[page->cpu];
1610 	struct page **pages;
1611 	int index;
1612 
1613 	if (!page->ref_count) {
1614 		tracecmd_critical("Page ref count is zero!");
1615 		return;
1616 	}
1617 
1618 	page->ref_count--;
1619 	if (page->ref_count)
1620 		return;
1621 
1622 	if (handle->read_page)
1623 		free(page->map);
1624 	else if (handle->read_zpage)
1625 		free_zpage(cpu_data, page->offset);
1626 	else
1627 		free_page_map(page->page_map);
1628 
1629 	index = (page->offset - cpu_data->file_offset) / handle->page_size;
1630 	cpu_data->pages[index] = NULL;
1631 	cpu_data->page_cnt--;
1632 
1633 	free(page);
1634 
1635 	if (handle->use_pipe) {
1636 		for (index = cpu_data->nr_pages - 1; index > 0; index--)
1637 			if (cpu_data->pages[index])
1638 				break;
1639 		if (index < (cpu_data->nr_pages - 1)) {
1640 			pages = realloc(cpu_data->pages, (index + 1) * sizeof(*cpu_data->pages));
1641 			if (!pages)
1642 				return;
1643 			cpu_data->pages = pages;
1644 			cpu_data->nr_pages = index + 1;
1645 		}
1646 	}
1647 }
1648 
free_page(struct tracecmd_input * handle,int cpu)1649 static void free_page(struct tracecmd_input *handle, int cpu)
1650 {
1651 	if (!handle->cpu_data || cpu >= handle->cpus ||
1652 	    !handle->cpu_data[cpu].page)
1653 		return;
1654 
1655 	__free_page(handle, handle->cpu_data[cpu].page);
1656 
1657 	handle->cpu_data[cpu].page = NULL;
1658 }
1659 
__free_record(struct tep_record * record)1660 static void __free_record(struct tep_record *record)
1661 {
1662 	if (record->priv) {
1663 		struct page *page = record->priv;
1664 		remove_record(page, record);
1665 		__free_page(page->handle, page);
1666 	}
1667 
1668 	free(record);
1669 }
1670 
tracecmd_free_record(struct tep_record * record)1671 void tracecmd_free_record(struct tep_record *record)
1672 {
1673 	if (!record)
1674 		return;
1675 
1676 	if (!record->ref_count) {
1677 		tracecmd_critical("record ref count is zero!");
1678 		return;
1679 	}
1680 
1681 	record->ref_count--;
1682 
1683 	if (record->ref_count)
1684 		return;
1685 
1686 	if (record->locked) {
1687 		tracecmd_critical("freeing record when it is locked!");
1688 		return;
1689 	}
1690 
1691 	record->data = NULL;
1692 
1693 	__free_record(record);
1694 }
1695 
tracecmd_record_ref(struct tep_record * record)1696 void tracecmd_record_ref(struct tep_record *record)
1697 {
1698 	record->ref_count++;
1699 #if DEBUG_RECORD
1700 	/* Update locating of last reference */
1701 	record->alloc_addr = (unsigned long)__builtin_return_address(0);
1702 #endif
1703 }
1704 
free_next(struct tracecmd_input * handle,int cpu)1705 static void free_next(struct tracecmd_input *handle, int cpu)
1706 {
1707 	struct tep_record *record;
1708 
1709 	if (!handle->cpu_data || cpu >= handle->cpus)
1710 		return;
1711 
1712 	record = handle->cpu_data[cpu].next;
1713 	if (!record)
1714 		return;
1715 
1716 	handle->cpu_data[cpu].next = NULL;
1717 
1718 	record->locked = 0;
1719 	tracecmd_free_record(record);
1720 }
1721 
1722 /* This functions was taken from the Linux kernel */
mul_u64_u32_shr(unsigned long long a,unsigned long long mul,unsigned int shift)1723 static unsigned long long mul_u64_u32_shr(unsigned long long a,
1724 					  unsigned long long mul, unsigned int shift)
1725 {
1726 	unsigned int ah, al;
1727 	unsigned long long ret;
1728 
1729 	al = a;
1730 	ah = a >> 32;
1731 
1732 	ret = (al * mul) >> shift;
1733 	if (ah)
1734 		ret += (ah * mul) << (32 - shift);
1735 
1736 	return ret;
1737 }
1738 
1739 static inline unsigned long long
timestamp_correction_calc(unsigned long long ts,unsigned int flags,struct ts_offset_sample * min,struct ts_offset_sample * max)1740 timestamp_correction_calc(unsigned long long ts, unsigned int flags,
1741 			  struct ts_offset_sample *min,
1742 			  struct ts_offset_sample *max)
1743 {
1744 	long long tscor;
1745 
1746 	if (flags & TRACECMD_TSYNC_FLAG_INTERPOLATE) {
1747 		long long delta = max->time - min->time;
1748 		long long offset = ((long long)ts - min->time) *
1749 				   (max->offset - min->offset);
1750 
1751 		tscor = min->offset + (offset + delta / 2) / delta;
1752 	} else {
1753 		tscor = min->offset;
1754 	}
1755 
1756 	ts = (ts * min->scaling) >> min->fraction;
1757 	if (tscor < 0)
1758 		return ts - llabs(tscor);
1759 
1760 	return ts + tscor;
1761 }
1762 
timestamp_host_sync(unsigned long long ts,int cpu,struct tracecmd_input * handle)1763 static unsigned long long timestamp_host_sync(unsigned long long ts, int cpu,
1764 					      struct tracecmd_input *handle)
1765 {
1766 	struct timesync_offsets *tsync;
1767 	int min, mid, max;
1768 
1769 	if (cpu >= handle->host.cpu_count)
1770 		return ts;
1771 	tsync = &handle->host.ts_offsets[cpu];
1772 
1773 	/* We have one sample, nothing to calc here */
1774 	if (tsync->ts_samples_count == 1)
1775 		return ts + tsync->ts_samples[0].offset;
1776 
1777 	/* We have two samples, nothing to search here */
1778 	if (tsync->ts_samples_count == 2)
1779 		return timestamp_correction_calc(ts, handle->host.flags,
1780 						 &tsync->ts_samples[0],
1781 						 &tsync->ts_samples[1]);
1782 
1783 	/* We have more than two samples */
1784 	if (ts <= tsync->ts_samples[0].time)
1785 		return timestamp_correction_calc(ts, handle->host.flags,
1786 						 &tsync->ts_samples[0],
1787 						 &tsync->ts_samples[1]);
1788 	else if (ts >= tsync->ts_samples[tsync->ts_samples_count-1].time)
1789 		return timestamp_correction_calc(ts, handle->host.flags,
1790 						 &tsync->ts_samples[tsync->ts_samples_count-2],
1791 						 &tsync->ts_samples[tsync->ts_samples_count-1]);
1792 	min = 0;
1793 	max = tsync->ts_samples_count-1;
1794 	mid = (min + max)/2;
1795 	while (min <= max) {
1796 		if (ts < tsync->ts_samples[mid].time)
1797 			max = mid - 1;
1798 		else if (ts > tsync->ts_samples[mid].time)
1799 			min = mid + 1;
1800 		else
1801 			break;
1802 		mid = (min + max)/2;
1803 	}
1804 
1805 	return timestamp_correction_calc(ts, handle->host.flags,
1806 					 &tsync->ts_samples[mid],
1807 					 &tsync->ts_samples[mid+1]);
1808 }
1809 
timestamp_calc(unsigned long long ts,int cpu,struct tracecmd_input * handle)1810 static unsigned long long timestamp_calc(unsigned long long ts, int cpu,
1811 					 struct tracecmd_input *handle)
1812 {
1813 	/* do not modify raw timestamps */
1814 	if (handle->flags & TRACECMD_FL_RAW_TS)
1815 		return ts;
1816 
1817 	/* Guest trace file, sync with host timestamps */
1818 	if (handle->host.sync_enable)
1819 		ts = timestamp_host_sync(ts, cpu, handle);
1820 
1821 	if (handle->ts2secs) {
1822 		/* user specified clock frequency */
1823 		ts *= handle->ts2secs;
1824 	} else if (handle->tsc_calc.mult) {
1825 		/* auto calculated TSC clock frequency */
1826 		ts = mul_u64_u32_shr(ts, handle->tsc_calc.mult, handle->tsc_calc.shift);
1827 	}
1828 
1829 	/* User specified time offset with --ts-offset or --date options */
1830 	ts += handle->ts_offset;
1831 
1832 	return ts;
1833 }
1834 
1835 /*
1836  * Page is mapped, now read in the page header info.
1837  */
update_page_info(struct tracecmd_input * handle,int cpu)1838 static int update_page_info(struct tracecmd_input *handle, int cpu)
1839 {
1840 	struct tep_handle *pevent = handle->pevent;
1841 	void *ptr = handle->cpu_data[cpu].page->map;
1842 	struct kbuffer *kbuf = handle->cpu_data[cpu].kbuf;
1843 
1844 	/* FIXME: handle header page */
1845 	if (tep_get_header_timestamp_size(pevent) != 8) {
1846 		tracecmd_warning("expected a long long type for timestamp");
1847 		return -1;
1848 	}
1849 
1850 	kbuffer_load_subbuffer(kbuf, ptr);
1851 	if (kbuffer_subbuffer_size(kbuf) > handle->page_size) {
1852 		tracecmd_warning("bad page read, with size of %d", kbuffer_subbuffer_size(kbuf));
1853 		return -1;
1854 	}
1855 	handle->cpu_data[cpu].timestamp = timestamp_calc(kbuffer_timestamp(kbuf),
1856 							 cpu, handle);
1857 
1858 	return 0;
1859 }
1860 
1861 /*
1862  * get_page maps a page for a given cpu.
1863  *
1864  * Returns 1 if the page was already mapped,
1865  *         0 if it mapped successfully
1866  *        -1 on error
1867  */
get_page(struct tracecmd_input * handle,int cpu,off_t offset)1868 static int get_page(struct tracecmd_input *handle, int cpu,
1869 		    off_t offset)
1870 {
1871 	/* Don't map if the page is already where we want */
1872 	if (handle->cpu_data[cpu].offset == offset &&
1873 	    handle->cpu_data[cpu].page)
1874 		return 1;
1875 
1876 	/* Do not map no data for CPU */
1877 	if (!handle->cpu_data[cpu].size)
1878 		return -1;
1879 
1880 	if (offset & (handle->page_size - 1)) {
1881 		errno = -EINVAL;
1882 		tracecmd_critical("bad page offset %llx", offset);
1883 		return -1;
1884 	}
1885 
1886 	if (offset < handle->cpu_data[cpu].file_offset ||
1887 	    offset > handle->cpu_data[cpu].file_offset +
1888 	    handle->cpu_data[cpu].file_size) {
1889 		errno = -EINVAL;
1890 		tracecmd_critical("bad page offset %llx", offset);
1891 		return -1;
1892 	}
1893 
1894 	handle->cpu_data[cpu].offset = offset;
1895 	handle->cpu_data[cpu].size = (handle->cpu_data[cpu].file_offset +
1896 				      handle->cpu_data[cpu].file_size) -
1897 					offset;
1898 
1899 	free_page(handle, cpu);
1900 
1901 	handle->cpu_data[cpu].page = allocate_page(handle, cpu, offset);
1902 	if (!handle->cpu_data[cpu].page)
1903 		return -1;
1904 
1905 	if (update_page_info(handle, cpu))
1906 		return -1;
1907 
1908 	return 0;
1909 }
1910 
get_next_page(struct tracecmd_input * handle,int cpu)1911 static int get_next_page(struct tracecmd_input *handle, int cpu)
1912 {
1913 	off_t offset;
1914 
1915 	if (!handle->cpu_data[cpu].page && !handle->use_pipe)
1916 		return 0;
1917 
1918 	free_page(handle, cpu);
1919 
1920 	if (handle->cpu_data[cpu].size <= handle->page_size) {
1921 		handle->cpu_data[cpu].offset = 0;
1922 		return 0;
1923 	}
1924 
1925 	offset = handle->cpu_data[cpu].offset + handle->page_size;
1926 
1927 	return get_page(handle, cpu, offset);
1928 }
1929 
1930 static struct tep_record *
peek_event(struct tracecmd_input * handle,unsigned long long offset,int cpu)1931 peek_event(struct tracecmd_input *handle, unsigned long long offset,
1932 	   int cpu)
1933 {
1934 	struct tep_record *record = NULL;
1935 
1936 	/*
1937 	 * Since the timestamp is calculated from the beginning
1938 	 * of the page and through each event, we reset the
1939 	 * page to the beginning. This is just used by
1940 	 * tracecmd_read_at.
1941 	 */
1942 	update_page_info(handle, cpu);
1943 
1944 	do {
1945 		free_next(handle, cpu);
1946 		record = tracecmd_peek_data(handle, cpu);
1947 		if (record && (record->offset + record->record_size) > offset)
1948 			break;
1949         } while (record);
1950 
1951 	return record;
1952 }
1953 
1954 static struct tep_record *
read_event(struct tracecmd_input * handle,unsigned long long offset,int cpu)1955 read_event(struct tracecmd_input *handle, unsigned long long offset,
1956 	   int cpu)
1957 {
1958 	struct tep_record *record;
1959 
1960 	record = peek_event(handle, offset, cpu);
1961 	if (record)
1962 		record = tracecmd_read_data(handle, cpu);
1963 	return record;
1964 }
1965 
1966 static struct tep_record *
find_and_peek_event(struct tracecmd_input * handle,unsigned long long offset,int * pcpu)1967 find_and_peek_event(struct tracecmd_input *handle, unsigned long long offset,
1968 		    int *pcpu)
1969 {
1970 	unsigned long long page_offset;
1971 	int cpu;
1972 
1973 	/* find the cpu that this offset exists in */
1974 	for (cpu = 0; cpu < handle->cpus; cpu++) {
1975 		if (offset >= handle->cpu_data[cpu].file_offset &&
1976 		    offset < handle->cpu_data[cpu].file_offset +
1977 		    handle->cpu_data[cpu].file_size)
1978 			break;
1979 	}
1980 
1981 	/* Not found? */
1982 	if (cpu == handle->cpus)
1983 		return NULL;
1984 
1985 	/* Move this cpu index to point to this offest */
1986 	page_offset = calc_page_offset(handle, offset);
1987 
1988 	if (get_page(handle, cpu, page_offset) < 0)
1989 		return NULL;
1990 
1991 	if (pcpu)
1992 		*pcpu = cpu;
1993 
1994 	return peek_event(handle, offset, cpu);
1995 }
1996 
1997 
1998 static struct tep_record *
find_and_read_event(struct tracecmd_input * handle,unsigned long long offset,int * pcpu)1999 find_and_read_event(struct tracecmd_input *handle, unsigned long long offset,
2000 		    int *pcpu)
2001 {
2002 	struct tep_record *record;
2003 	int cpu;
2004 
2005 	record = find_and_peek_event(handle, offset, &cpu);
2006 	if (record) {
2007 		record = tracecmd_read_data(handle, cpu);
2008 		if (pcpu)
2009 			*pcpu = cpu;
2010 	}
2011 	return record;
2012 }
2013 
2014 /**
2015  * tracecmd_read_at - read a record from a specific offset
2016  * @handle: input handle for the trace.dat file
2017  * @offset: the offset into the file to find the record
2018  * @pcpu: pointer to a variable to store the CPU id the record was found in
2019  *
2020  * This function is useful when looking for a previous record.
2021  * You can store the offset of the record "record->offset" and use that
2022  * offset to retreive the record again without needing to store any
2023  * other information about the record.
2024  *
2025  * The record returned must be freed.
2026  */
2027 struct tep_record *
tracecmd_read_at(struct tracecmd_input * handle,unsigned long long offset,int * pcpu)2028 tracecmd_read_at(struct tracecmd_input *handle, unsigned long long offset,
2029 		 int *pcpu)
2030 {
2031 	unsigned long long page_offset;
2032 	int cpu;
2033 
2034 	page_offset = calc_page_offset(handle, offset);
2035 
2036 	/* check to see if we have this page already */
2037 	for (cpu = 0; cpu < handle->cpus; cpu++) {
2038 		if (handle->cpu_data[cpu].offset == page_offset &&
2039 		    handle->cpu_data[cpu].file_size)
2040 			break;
2041 	}
2042 
2043 	if (cpu < handle->cpus && handle->cpu_data[cpu].page) {
2044 		if (pcpu)
2045 			*pcpu = cpu;
2046 		return read_event(handle, offset, cpu);
2047 	} else
2048 		return find_and_read_event(handle, offset, pcpu);
2049 }
2050 
2051 /**
2052  * tracecmd_refresh_record - remaps the records data
2053  * @handle: input handle for the trace.dat file
2054  * @record: the record to be refreshed
2055  *
2056  * A record data points to a mmap section of memory.
2057  * by reading new records the mmap section may be unmapped.
2058  * This will refresh the record's data mapping.
2059  *
2060  * ===== OBSOLETED BY PAGE REFERENCES =====
2061  *
2062  * Returns 1 if page is still mapped (does not modify CPU iterator)
2063  *         0 on successful mapping (was not mapped before,
2064  *                      This will update CPU iterator to point to
2065  *                      the next record)
2066  *        -1 on error.
2067  */
tracecmd_refresh_record(struct tracecmd_input * handle,struct tep_record * record)2068 int tracecmd_refresh_record(struct tracecmd_input *handle,
2069 			    struct tep_record *record)
2070 {
2071 	unsigned long long page_offset;
2072 	int cpu = record->cpu;
2073 	struct cpu_data *cpu_data = &handle->cpu_data[cpu];
2074 	int index;
2075 	int ret;
2076 
2077 	page_offset = calc_page_offset(handle, record->offset);
2078 	index = record->offset & (handle->page_size - 1);
2079 
2080 	ret = get_page(handle, record->cpu, page_offset);
2081 	if (ret < 0)
2082 		return -1;
2083 
2084 	/* If the page is still mapped, there's nothing to do */
2085 	if (ret)
2086 		return 1;
2087 
2088 	record->data = kbuffer_read_at_offset(cpu_data->kbuf, index, &record->ts);
2089 	cpu_data->timestamp = record->ts;
2090 
2091 	return 0;
2092 }
2093 
2094 /**
2095  * tracecmd_read_cpu_first - get the first record in a CPU
2096  * @handle: input handle for the trace.dat file
2097  * @cpu: the CPU to search
2098  *
2099  * This returns the first (by time) record entry in a given CPU.
2100  *
2101  * The record returned must be freed.
2102  */
2103 struct tep_record *
tracecmd_read_cpu_first(struct tracecmd_input * handle,int cpu)2104 tracecmd_read_cpu_first(struct tracecmd_input *handle, int cpu)
2105 {
2106 	unsigned long long page_offset;
2107 	int ret;
2108 
2109 	if (cpu >= handle->cpus)
2110 		return NULL;
2111 
2112 	page_offset = calc_page_offset(handle, handle->cpu_data[cpu].file_offset);
2113 
2114 	ret = get_page(handle, cpu, page_offset);
2115 	if (ret < 0)
2116 		return NULL;
2117 
2118 	/* If the page was already mapped, we need to reset it */
2119 	if (ret)
2120 		update_page_info(handle, cpu);
2121 
2122 	free_next(handle, cpu);
2123 
2124 	return tracecmd_read_data(handle, cpu);
2125 }
2126 
2127 /**
2128  * tracecmd_iterate_reset - Set the handle to iterate from the beginning
2129  * @handle: input handle for the trace.dat file
2130  *
2131  * This causes tracecmd_iterate_events*() to start from the beginning
2132  * of the trace.dat file.
2133  */
tracecmd_iterate_reset(struct tracecmd_input * handle)2134 int tracecmd_iterate_reset(struct tracecmd_input *handle)
2135 {
2136 	unsigned long long page_offset;
2137 	int cpu;
2138 	int ret = 0;
2139 	int r;
2140 
2141 	for (cpu = 0; cpu < handle->cpus; cpu++) {
2142 		page_offset = calc_page_offset(handle, handle->cpu_data[cpu].file_offset);
2143 
2144 		r = get_page(handle, cpu, page_offset);
2145 		if (r < 0) {
2146 			ret = -1;
2147 			continue; /* ?? */
2148 		}
2149 
2150 		/* If the page was already mapped, we need to reset it */
2151 		if (r)
2152 			update_page_info(handle, cpu);
2153 
2154 		free_next(handle, cpu);
2155 	}
2156 	return ret;
2157 }
2158 
2159 /**
2160  * tracecmd_read_cpu_last - get the last record in a CPU
2161  * @handle: input handle for the trace.dat file
2162  * @cpu: the CPU to search
2163  *
2164  * This returns the last (by time) record entry in a given CPU.
2165  *
2166  * The record returned must be freed.
2167  */
2168 struct tep_record *
tracecmd_read_cpu_last(struct tracecmd_input * handle,int cpu)2169 tracecmd_read_cpu_last(struct tracecmd_input *handle, int cpu)
2170 {
2171 	struct tep_record *record = NULL;
2172 	off_t offset, page_offset;
2173 
2174 	offset = handle->cpu_data[cpu].file_offset +
2175 		handle->cpu_data[cpu].file_size;
2176 
2177 	if (offset & (handle->page_size - 1))
2178 		offset &= ~(handle->page_size - 1);
2179 	else
2180 		offset -= handle->page_size;
2181 
2182 	page_offset = offset;
2183 
2184  again:
2185 	if (get_page(handle, cpu, page_offset) < 0)
2186 		return NULL;
2187 
2188 	offset = page_offset;
2189 
2190 	do {
2191 		tracecmd_free_record(record);
2192 		record = tracecmd_read_data(handle, cpu);
2193 		if (record)
2194 			offset = record->offset;
2195 	} while (record);
2196 
2197 	record = tracecmd_read_at(handle, offset, NULL);
2198 
2199 	/*
2200 	 * It is possible that a page has just a timestamp
2201 	 * or just padding on it.
2202 	 */
2203 	if (!record) {
2204 		if (page_offset == handle->cpu_data[cpu].file_offset)
2205 			return NULL;
2206 		page_offset -= handle->page_size;
2207 		goto again;
2208 	}
2209 
2210 	return record;
2211 }
2212 
2213 /**
2214  * tracecmd_set_cpu_to_timestamp - set the CPU iterator to a given time
2215  * @handle: input handle for the trace.dat file
2216  * @cpu: the CPU pointer to set
2217  * @ts: the timestamp to set the CPU at.
2218  *
2219  * This sets the CPU iterator used by tracecmd_read_data and
2220  * tracecmd_peek_data to a location in the CPU storage near
2221  * a given timestamp. It will try to set the iterator to a time before
2222  * the time stamp and not actually at a given time.
2223  *
2224  * To use this to find a record in a time field, call this function
2225  * first, than iterate with tracecmd_read_data to find the records
2226  * you need.
2227  */
2228 int
tracecmd_set_cpu_to_timestamp(struct tracecmd_input * handle,int cpu,unsigned long long ts)2229 tracecmd_set_cpu_to_timestamp(struct tracecmd_input *handle, int cpu,
2230 			      unsigned long long ts)
2231 {
2232 	struct cpu_data *cpu_data = &handle->cpu_data[cpu];
2233 	off_t start, end, next;
2234 
2235 	if (cpu < 0 || cpu >= handle->cpus) {
2236 		errno = -EINVAL;
2237 		return -1;
2238 	}
2239 
2240 	if (!cpu_data->size)
2241 		return -1;
2242 
2243 	if (!cpu_data->page) {
2244 		if (init_cpu(handle, cpu))
2245 		    return -1;
2246 	}
2247 
2248 	if (cpu_data->timestamp == ts) {
2249 		/*
2250 		 * If a record is cached, then that record is most
2251 		 * likely the matching timestamp. Otherwise we need
2252 		 * to start from the beginning of the index;
2253 		 */
2254 		if (!cpu_data->next ||
2255 		    cpu_data->next->ts != ts)
2256 			update_page_info(handle, cpu);
2257 		return 0;
2258 	}
2259 
2260 	/* Set to the first record on current page */
2261 	update_page_info(handle, cpu);
2262 
2263 	if (cpu_data->timestamp < ts) {
2264 		start = cpu_data->offset;
2265 		end = cpu_data->file_offset + cpu_data->file_size;
2266 		if (end & (handle->page_size - 1))
2267 			end &= ~(handle->page_size - 1);
2268 		else
2269 			end -= handle->page_size;
2270 		next = end;
2271 	} else {
2272 		end = cpu_data->offset;
2273 		start = cpu_data->file_offset;
2274 		next = start;
2275 	}
2276 
2277 	while (start < end) {
2278 		if (get_page(handle, cpu, next) < 0)
2279 			return -1;
2280 
2281 		if (cpu_data->timestamp == ts)
2282 			break;
2283 
2284 		if (cpu_data->timestamp < ts)
2285 			start = next;
2286 		else
2287 			end = next;
2288 
2289 		next = start + (end - start) / 2;
2290 		next = calc_page_offset(handle, next);
2291 
2292 		/* Prevent an infinite loop if start and end are a page off */
2293 		if (next == start)
2294 			start = next += handle->page_size;
2295 	}
2296 
2297 	/*
2298 	 * We need to end up on a page before the time stamp.
2299 	 * We go back even if the timestamp is the same. This is because
2300 	 * we want the event with the timestamp, not the page. The page
2301 	 * can start with the timestamp we are looking for, but the event
2302 	 * may be on the previous page.
2303 	 */
2304 	if (cpu_data->timestamp >= ts &&
2305 	    cpu_data->offset > cpu_data->file_offset)
2306 		get_page(handle, cpu, cpu_data->offset - handle->page_size);
2307 
2308 	return 0;
2309 }
2310 
2311 /**
2312  * tracecmd_set_all_cpus_to_timestamp - set all CPUs iterator to a given time
2313  * @handle: input handle for the trace.dat file
2314  * @cpu: the CPU pointer to set
2315  * @ts: the timestamp to set the CPU at.
2316  *
2317  * This sets the CPU iterator used by tracecmd_read_data and
2318  * tracecmd_peek_data to a location in the CPU storage near
2319  * a given timestamp. It will try to set the iterator to a time before
2320  * the time stamp and not actually at a given time.
2321  *
2322  * To use this to find a record in a time field, call this function
2323  * first, than iterate with tracecmd_read_next_data to find the records
2324  * you need.
2325  */
2326 void
tracecmd_set_all_cpus_to_timestamp(struct tracecmd_input * handle,unsigned long long time)2327 tracecmd_set_all_cpus_to_timestamp(struct tracecmd_input *handle,
2328 				   unsigned long long time)
2329 {
2330 	int cpu;
2331 
2332 	for (cpu = 0; cpu < handle->cpus; cpu++)
2333 		tracecmd_set_cpu_to_timestamp(handle, cpu, time);
2334 }
2335 
2336 /**
2337  * tracecmd_set_cursor - set the offset for the next tracecmd_read_data
2338  * @handle: input handle for the trace.dat file
2339  * @cpu: the CPU pointer to set
2340  * @offset: the offset to place the cursor
2341  *
2342  * Set the pointer to the next read or peek. This is useful when
2343  * needing to read sequentially and then look at another record
2344  * out of sequence without breaking the iteration. This is done with:
2345  *
2346  *  record = tracecmd_peek_data()
2347  *  offset = record->offset;
2348  *  record = tracecmd_read_at();
2349  *   - do what ever with record -
2350  *  tracecmd_set_cursor(handle, cpu, offset);
2351  *
2352  *  Now the next tracecmd_peek_data or tracecmd_read_data will return
2353  *  the original record.
2354  */
tracecmd_set_cursor(struct tracecmd_input * handle,int cpu,size_t offset)2355 int tracecmd_set_cursor(struct tracecmd_input *handle, int cpu, size_t offset)
2356 {
2357 	struct cpu_data *cpu_data = &handle->cpu_data[cpu];
2358 	unsigned long long page_offset;
2359 
2360 	if (cpu < 0 || cpu >= handle->cpus)
2361 		return -1;
2362 
2363 	if (offset < cpu_data->file_offset ||
2364 	    offset > cpu_data->file_offset + cpu_data->file_size)
2365 		return -1; 	/* cpu does not have this offset. */
2366 
2367 	/* Move this cpu index to point to this offest */
2368 	page_offset = calc_page_offset(handle, offset);
2369 
2370 	if (get_page(handle, cpu, page_offset) < 0)
2371 		return -1;
2372 
2373 	peek_event(handle, offset, cpu);
2374 
2375 	return 0;
2376 }
2377 
2378 /**
2379  * tracecmd_get_cursor - get the offset for the next tracecmd_read_data
2380  * @handle: input handle for the trace.dat file
2381  * @cpu: the CPU pointer to get the cursor from
2382  *
2383  * Returns the offset of the next record that would be read.
2384  */
2385 unsigned long long
tracecmd_get_cursor(struct tracecmd_input * handle,int cpu)2386 tracecmd_get_cursor(struct tracecmd_input *handle, int cpu)
2387 {
2388 	struct cpu_data *cpu_data = &handle->cpu_data[cpu];
2389 	struct kbuffer *kbuf = cpu_data->kbuf;
2390 
2391 	if (cpu < 0 || cpu >= handle->cpus)
2392 		return 0;
2393 
2394 	/*
2395 	 * Use the next pointer if it exists and matches the
2396 	 * current timestamp.
2397 	 */
2398 	if (cpu_data->next &&
2399 	    cpu_data->next->ts == cpu_data->timestamp)
2400 		return cpu_data->next->offset;
2401 
2402 	/*
2403 	 * Either the next point does not exist, or it does
2404 	 * not match the timestamp. The next read will use the
2405 	 * current page.
2406 	 *
2407 	 * If the offset is at the end, then return that.
2408 	 */
2409 	if (cpu_data->offset >= cpu_data->file_offset +
2410 	    cpu_data->file_size)
2411 		return cpu_data->offset;
2412 
2413 	return cpu_data->offset + kbuffer_curr_offset(kbuf);
2414 }
2415 
2416 /**
2417  * tracecmd_translate_data - create a record from raw data
2418  * @handle: input handle for the trace.dat file
2419  * @ptr: raw data to read
2420  * @size: the size of the data
2421  *
2422  * This function tries to create a record from some given
2423  * raw data. The data does not need to be from the trace.dat file.
2424  * It can be stored from another location.
2425  *
2426  * Note, since the timestamp is calculated from within the trace
2427  * buffer, the timestamp for the record will be zero, since it
2428  * can't calculate it.
2429  *
2430  * The record returned must be freed.
2431  */
2432 struct tep_record *
tracecmd_translate_data(struct tracecmd_input * handle,void * ptr,int size)2433 tracecmd_translate_data(struct tracecmd_input *handle,
2434 			void *ptr, int size)
2435 {
2436 	struct tep_handle *pevent = handle->pevent;
2437 	struct tep_record *record;
2438 	unsigned int length;
2439 	int swap = 1;
2440 
2441 	/* minimum record read is 8, (warn?) (TODO: make 8 into macro) */
2442 	if (size < 8)
2443 		return NULL;
2444 
2445 	record = malloc(sizeof(*record));
2446 	if (!record)
2447 		return NULL;
2448 	memset(record, 0, sizeof(*record));
2449 
2450 	record->ref_count = 1;
2451 	if (tep_is_local_bigendian(pevent) == tep_is_file_bigendian(pevent))
2452 		swap = 0;
2453 	record->data = kbuffer_translate_data(swap, ptr, &length);
2454 	record->size = length;
2455 	if (record->data)
2456 		record->record_size = record->size + (record->data - ptr);
2457 
2458 	return record;
2459 }
2460 
2461 
2462 /**
2463  * tracecmd_peek_data - return the record at the current location.
2464  * @handle: input handle for the trace.dat file
2465  * @cpu: the CPU to pull from
2466  *
2467  * This returns the record at the current location of the CPU
2468  * iterator. It does not increment the CPU iterator.
2469  */
2470 struct tep_record *
tracecmd_peek_data(struct tracecmd_input * handle,int cpu)2471 tracecmd_peek_data(struct tracecmd_input *handle, int cpu)
2472 {
2473 	struct tep_record *record;
2474 	unsigned long long ts;
2475 	struct kbuffer *kbuf;
2476 	struct page *page;
2477 	int index;
2478 	void *data;
2479 
2480 	if (cpu >= handle->cpus)
2481 		return NULL;
2482 
2483 	page = handle->cpu_data[cpu].page;
2484 	kbuf = handle->cpu_data[cpu].kbuf;
2485 
2486 	/* Hack to work around function graph read ahead */
2487 	tracecmd_curr_thread_handle = handle;
2488 
2489 	if (handle->cpu_data[cpu].next) {
2490 
2491 		record = handle->cpu_data[cpu].next;
2492 		if (!record->data) {
2493 			tracecmd_critical("Something freed the record");
2494 			return NULL;
2495 		}
2496 
2497 		if (handle->cpu_data[cpu].timestamp == record->ts)
2498 			return record;
2499 
2500 		/*
2501 		 * The timestamp changed, which means the cached
2502 		 * record is no longer valid. Reread a new record.
2503 		 */
2504 		free_next(handle, cpu);
2505 	}
2506 
2507 read_again:
2508 	if (!page) {
2509 		if (handle->use_pipe) {
2510 			get_next_page(handle, cpu);
2511 			page = handle->cpu_data[cpu].page;
2512 		}
2513 		if (!page)
2514 			return NULL;
2515 	}
2516 
2517 	data = kbuffer_read_event(kbuf, &ts);
2518 	if (!data) {
2519 		if (get_next_page(handle, cpu))
2520 			return NULL;
2521 		page = handle->cpu_data[cpu].page;
2522 		goto read_again;
2523 	}
2524 
2525 	handle->cpu_data[cpu].timestamp = timestamp_calc(ts, cpu, handle);
2526 
2527 	index = kbuffer_curr_offset(kbuf);
2528 
2529 	record = malloc(sizeof(*record));
2530 	if (!record)
2531 		return NULL;
2532 	memset(record, 0, sizeof(*record));
2533 
2534 	record->ts = handle->cpu_data[cpu].timestamp;
2535 	record->size = kbuffer_event_size(kbuf);
2536 	record->cpu = handle->cpu_data[cpu].cpu;
2537 	record->data = data;
2538 	record->offset = handle->cpu_data[cpu].offset + index;
2539 	record->missed_events = kbuffer_missed_events(kbuf);
2540 	record->ref_count = 1;
2541 	record->locked = 1;
2542 
2543 	handle->cpu_data[cpu].next = record;
2544 
2545 	record->record_size = kbuffer_curr_size(kbuf);
2546 	record->priv = page;
2547 	add_record(page, record);
2548 	page->ref_count++;
2549 
2550 	kbuffer_next_event(kbuf, NULL);
2551 
2552 	return record;
2553 }
2554 
2555 /**
2556  * tracecmd_read_data - read the next record and increment
2557  * @handle: input handle for the trace.dat file
2558  * @cpu: the CPU to pull from
2559  *
2560  * This returns the record at the current location of the CPU
2561  * iterator and increments the CPU iterator.
2562  *
2563  * The record returned must be freed.
2564  */
2565 struct tep_record *
tracecmd_read_data(struct tracecmd_input * handle,int cpu)2566 tracecmd_read_data(struct tracecmd_input *handle, int cpu)
2567 {
2568 	struct tep_record *record;
2569 
2570 	if (cpu >= handle->cpus)
2571 		return NULL;
2572 
2573 	record = tracecmd_peek_data(handle, cpu);
2574 	handle->cpu_data[cpu].next = NULL;
2575 	if (record) {
2576 		record->locked = 0;
2577 #if DEBUG_RECORD
2578 		record->alloc_addr = (unsigned long)__builtin_return_address(0);
2579 #endif
2580 	}
2581 	return record;
2582 }
2583 
2584 /**
2585  * tracecmd_read_next_data - read the next record
2586  * @handle: input handle to the trace.dat file
2587  * @rec_cpu: return pointer to the CPU that the record belongs to
2588  *
2589  * This returns the next record by time. This is different than
2590  * tracecmd_read_data in that it looks at all CPUs. It does a peek
2591  * at each CPU and the record with the earliest time stame is
2592  * returned. If @rec_cpu is not NULL it gets the CPU id the record was
2593  * on. The CPU cursor of the returned record is moved to the
2594  * next record.
2595  *
2596  * Multiple reads of this function will return a serialized list
2597  * of all records for all CPUs in order of time stamp.
2598  *
2599  * The record returned must be freed.
2600  */
2601 struct tep_record *
tracecmd_read_next_data(struct tracecmd_input * handle,int * rec_cpu)2602 tracecmd_read_next_data(struct tracecmd_input *handle, int *rec_cpu)
2603 {
2604 	struct tep_record *record;
2605 	int next_cpu;
2606 
2607 	record = tracecmd_peek_next_data(handle, &next_cpu);
2608 	if (!record)
2609 		return NULL;
2610 
2611 	if (rec_cpu)
2612 		*rec_cpu = next_cpu;
2613 
2614 	return tracecmd_read_data(handle, next_cpu);
2615 }
2616 
2617 /**
2618  * tracecmd_follow_event - Add callback for specific events for iterators
2619  * @handle: The handle to get a callback from
2620  * @system: The system of the event to track
2621  * @event_name: The name of the event to track
2622  * @callback: The function to call when the event is hit in an iterator
2623  * @callback_data: The data to pass to @callback
2624  *
2625  * This attaches a callback to @handle where if tracecmd_iterate_events()
2626  * or tracecmd_iterate_events_multi() is called, that if the specified
2627  * event is hit, it will call @callback, with the following parameters:
2628  *  @handle: Same handle as passed to this function.
2629  *  @event: The event pointer that was found by @system and @event_name.
2630  *  @record; The event instance of @event.
2631  *  @cpu: The cpu that the event happened on.
2632  *  @callback_data: The same as @callback_data passed to the function.
2633  *
2634  * Note that when used with tracecmd_iterate_events_multi() that @cpu
2635  * may be the nth CPU of all handles it is processing, so if the CPU
2636  * that the @record is on is desired, then use @record->cpu.
2637  *
2638  * Returns 0 on success and -1 on error.
2639  */
tracecmd_follow_event(struct tracecmd_input * handle,const char * system,const char * event_name,int (* callback)(struct tracecmd_input * handle,struct tep_event *,struct tep_record *,int,void *),void * callback_data)2640 int tracecmd_follow_event(struct tracecmd_input *handle,
2641 			  const char *system, const char *event_name,
2642 			  int (*callback)(struct tracecmd_input *handle,
2643 					  struct tep_event *,
2644 					  struct tep_record *,
2645 					  int, void *),
2646 			  void *callback_data)
2647 {
2648 	struct tep_handle *tep = tracecmd_get_tep(handle);
2649 	struct follow_event *followers;
2650 	struct follow_event follow;
2651 
2652 	if (!tep) {
2653 		errno = EINVAL;
2654 		return -1;
2655 	}
2656 
2657 	follow.event = tep_find_event_by_name(tep, system, event_name);
2658 	if (!follow.event) {
2659 		errno = ENOENT;
2660 		return -1;
2661 	}
2662 
2663 	follow.callback = callback;
2664 	follow.callback_data = callback_data;
2665 
2666 	followers = realloc(handle->followers, sizeof(*followers) *
2667 			    (handle->nr_followers + 1));
2668 	if (!followers)
2669 		return -1;
2670 
2671 	handle->followers = followers;
2672 	followers[handle->nr_followers++] = follow;
2673 
2674 	return 0;
2675 }
2676 
2677 /**
2678  * tracecmd_follow_missed_events - Add callback for missed events for iterators
2679  * @handle: The handle to get a callback from
2680  * @callback: The function to call when missed events is detected
2681  * @callback_data: The data to pass to @callback
2682  *
2683  * This attaches a callback to @handle where if tracecmd_iterate_events()
2684  * or tracecmd_iterate_events_multi() is called, that if missed events
2685  * is detected, it will call @callback, with the following parameters:
2686  *  @handle: Same handle as passed to this function.
2687  *  @event: The event pointer of the record with the missing events
2688  *  @record; The event instance of @event.
2689  *  @cpu: The cpu that the event happened on.
2690  *  @callback_data: The same as @callback_data passed to the function.
2691  *
2692  * Note that when used with tracecmd_iterate_events_multi() that @cpu
2693  * may be the nth CPU of all handles it is processing, so if the CPU
2694  * that the @record is on is desired, then use @record->cpu.
2695  *
2696  * If the count of missing events is available, @record->missed_events
2697  * will have a positive number holding the number of missed events since
2698  * the last event on the same CPU, or just -1 if that number is unknown
2699  * but missed events did happen.
2700  *
2701  * Returns 0 on success and -1 on error.
2702  */
tracecmd_follow_missed_events(struct tracecmd_input * handle,int (* callback)(struct tracecmd_input * handle,struct tep_event *,struct tep_record *,int,void *),void * callback_data)2703 int tracecmd_follow_missed_events(struct tracecmd_input *handle,
2704 				  int (*callback)(struct tracecmd_input *handle,
2705 						  struct tep_event *,
2706 						  struct tep_record *,
2707 						  int, void *),
2708 				  void *callback_data)
2709 {
2710 	struct follow_event *followers;
2711 	struct follow_event follow;
2712 
2713 	follow.event = NULL;
2714 	follow.callback = callback;
2715 	follow.callback_data = callback_data;
2716 
2717 	followers = realloc(handle->missed_followers, sizeof(*followers) *
2718 			    (handle->nr_missed_followers + 1));
2719 	if (!followers)
2720 		return -1;
2721 
2722 	handle->missed_followers = followers;
2723 	followers[handle->nr_missed_followers++] = follow;
2724 
2725 	return 0;
2726 }
2727 
call_followers(struct tracecmd_input * handle,struct tep_record * record,int cpu)2728 static int call_followers(struct tracecmd_input *handle,
2729 			  struct tep_record *record, int cpu)
2730 {
2731 	struct tep_handle *tep = tracecmd_get_tep(handle);
2732 	struct follow_event *followers = handle->followers;
2733 	struct tep_event *event;
2734 	int ret = 0;
2735 	int i;
2736 
2737 	event = tep_find_event_by_record(tep, record);
2738 	if (!event)
2739 		return -1;
2740 
2741 	for (i = 0; i < handle->nr_followers; i++) {
2742 		if (handle->followers[i].event == event)
2743 			ret |= followers[i].callback(handle, event, record,
2744 						     cpu, followers[i].callback_data);
2745 	}
2746 
2747 	return ret;
2748 }
2749 
call_missed_events(struct tracecmd_input * handle,struct tep_record * record,int cpu)2750 static int call_missed_events(struct tracecmd_input *handle,
2751 			      struct tep_record *record, int cpu)
2752 {
2753 	struct tep_handle *tep = tracecmd_get_tep(handle);
2754 	struct follow_event *followers = handle->missed_followers;
2755 	struct tep_event *event;
2756 	int ret = 0;
2757 	int i;
2758 
2759 	event = tep_find_event_by_record(tep, record);
2760 	if (!event)
2761 		return -1;
2762 
2763 	for (i = 0; i < handle->nr_missed_followers; i++) {
2764 		ret |= followers[i].callback(handle, event, record,
2765 					     cpu, followers[i].callback_data);
2766 	}
2767 
2768 	return ret;
2769 }
2770 
call_callbacks(struct tracecmd_input * handle,struct tep_record * record,int next_cpu,int (* callback)(struct tracecmd_input * handle,struct tep_record *,int,void *),void * callback_data)2771 static int call_callbacks(struct tracecmd_input *handle, struct tep_record *record,
2772 			  int next_cpu,
2773 			  int (*callback)(struct tracecmd_input *handle,
2774 					  struct tep_record *,
2775 					  int, void *),
2776 			  void *callback_data)
2777 {
2778 	int ret = 0;
2779 
2780 	if (!record)
2781 		return 0;
2782 
2783 	if (record->missed_events)
2784 		ret = call_missed_events(handle, record, next_cpu);
2785 
2786 	if (ret)
2787 		return ret;
2788 
2789 	if (!handle->filter ||
2790 	    tracecmd_filter_match(handle->filter, record) == TRACECMD_FILTER_MATCH) {
2791 		if (handle->nr_followers)
2792 			ret = call_followers(handle, record, next_cpu);
2793 		if (!ret && callback)
2794 			ret = callback(handle, record, next_cpu, callback_data);
2795 	}
2796 
2797 	return ret;
2798 }
2799 
2800 /**
2801  * tracecmd_iterate_events - iterate events over a given handle
2802  * @handle: The handle to iterate over
2803  * @cpus: The CPU set to filter on (NULL for all CPUs)
2804  * @cpu_size: The size of @cpus (ignored if @cpus is NULL)
2805  * @callback: The callback function for each event
2806  * @callback_data: The data to pass to the @callback.
2807  *
2808  * Will loop over all events in @handle (filtered by the given @cpus),
2809  * and will call @callback for each event in order of the event's records
2810  * timestamp.
2811  *
2812  * Returns the -1 on error, or the value of the callbacks.
2813  */
tracecmd_iterate_events(struct tracecmd_input * handle,cpu_set_t * cpus,int cpu_size,int (* callback)(struct tracecmd_input * handle,struct tep_record *,int,void *),void * callback_data)2814 int tracecmd_iterate_events(struct tracecmd_input *handle,
2815 			    cpu_set_t *cpus, int cpu_size,
2816 			    int (*callback)(struct tracecmd_input *handle,
2817 					    struct tep_record *,
2818 					    int, void *),
2819 			    void *callback_data)
2820 {
2821 	struct tep_record *record;
2822 	unsigned long long *timestamps;
2823 	unsigned long long ts, last_timestamp = 0;
2824 	int *cpu_list;
2825 	int cpu_count = 0;
2826 	int next_cpu;
2827 	int cpu;
2828 	int ret = 0;
2829 	int i;
2830 
2831 	if (!callback && !handle->nr_followers) {
2832 		errno = EINVAL;
2833 		return -1;
2834 	}
2835 
2836 	timestamps = calloc(handle->cpus, sizeof(*timestamps));
2837 	if (!timestamps)
2838 		return -1;
2839 
2840 	cpu_list = calloc(handle->cpus, sizeof(*cpu_list));
2841 	if (!cpu_list) {
2842 		free(timestamps);
2843 		return -1;
2844 	}
2845 
2846 	for (cpu = 0; cpu < handle->cpus; cpu++) {
2847 		if (cpus && !CPU_ISSET_S(cpu, cpu_size, cpus))
2848 			continue;
2849 		cpu_list[cpu_count++] = cpu;
2850 	}
2851 
2852 	for (i = 0; i < cpu_count; i++) {
2853 		cpu = cpu_list[i];
2854 		record = tracecmd_peek_data(handle, cpu);
2855 		timestamps[cpu] = record ? record->ts : -1ULL;
2856 	}
2857 
2858 	do {
2859 		next_cpu = -1;
2860 		for (i = 0; i < cpu_count; i++) {
2861 			cpu = cpu_list[i];
2862 			ts = timestamps[cpu];
2863 			if (ts == -1ULL)
2864 				continue;
2865 
2866 			if (next_cpu < 0 || ts < last_timestamp) {
2867 				next_cpu = cpu;
2868 				last_timestamp = ts;
2869 			}
2870 		}
2871 		if (next_cpu >= 0) {
2872 			record = tracecmd_peek_data(handle, next_cpu);
2873 
2874 			/* Make sure the record is still what we expect it to be */
2875 			if (!record || record->ts != last_timestamp) {
2876 				timestamps[next_cpu] = record ? record->ts : -1ULL;
2877 				continue;
2878 			}
2879 
2880 			/* Need to call read_data to increment to the next record */
2881 			record = tracecmd_read_data(handle, next_cpu);
2882 
2883 			ret = call_callbacks(handle, record, next_cpu,
2884 					     callback, callback_data);
2885 
2886 			tracecmd_free_record(record);
2887 
2888 			record = tracecmd_peek_data(handle, next_cpu);
2889 			timestamps[next_cpu] = record ? record->ts : -1ULL;
2890 		}
2891 	} while (next_cpu >= 0 && ret == 0);
2892 
2893 	free(timestamps);
2894 	free(cpu_list);
2895 
2896 	return ret;
2897 }
2898 
2899 static struct tep_record *
load_records(struct tracecmd_input * handle,int cpu,unsigned long long page_offset,unsigned long long start_offset)2900 load_records(struct tracecmd_input *handle, int cpu,
2901 	     unsigned long long page_offset, unsigned long long start_offset)
2902 {
2903 	struct tep_record *last_record = NULL;
2904 	struct tep_record *record;
2905 	unsigned long long page_end = page_offset + handle->page_size;
2906 
2907 	if (get_page(handle, cpu, page_offset) < 0)
2908 		return NULL;
2909 
2910 	update_page_info(handle, cpu);
2911 
2912 	if (start_offset)
2913 		page_end = start_offset + 1;
2914 
2915 	for (;;) {
2916 		record = tracecmd_read_data(handle, cpu);
2917 		if (!record || record->offset >= page_end) {
2918 			/* Make sure the cpu_data page is still valid */
2919 			get_page(handle, cpu, page_offset);
2920 			tracecmd_free_record(record);
2921 			break;
2922 		}
2923 		/*
2924 		 * Hijack the record->priv, as we know that it points
2925 		 * to handle->cpu_data[cpu].page, and use that as
2926 		 * a link list of all the records on this page going
2927 		 * backwards.
2928 		 */
2929 		record->priv = last_record;
2930 		last_record = record;
2931 	}
2932 
2933 	return last_record;
2934 }
2935 
initialize_last_events(struct tracecmd_input * handle,struct tep_record ** last_records,cpu_set_t * cpu_set,int cpu_size,int cpus,bool cont)2936 static void initialize_last_events(struct tracecmd_input *handle,
2937 				   struct tep_record **last_records,
2938 				   cpu_set_t *cpu_set, int cpu_size,
2939 				   int cpus, bool cont)
2940 {
2941 	unsigned long long page_offset;
2942 	unsigned long long start_offset = 0;
2943 	struct tep_record *record;
2944 	int cpu;
2945 
2946 	for (cpu = 0; cpu < cpus; cpu++) {
2947 		if (cpu_set && !CPU_ISSET_S(cpu, cpu_size, cpu_set))
2948 			continue;
2949 
2950 		if (!handle->cpu_data[cpu].file_size)
2951 			continue;
2952 
2953 		if (cont) {
2954 			record = tracecmd_read_data(handle, cpu);
2955 			if (record)
2956 				page_offset = start_offset = record->offset;
2957 			tracecmd_free_record(record);
2958 		}
2959 
2960 		if (!start_offset) {
2961 			/* Find the start of the last page for this CPU */
2962 			page_offset = handle->cpu_data[cpu].file_offset +
2963 				handle->cpu_data[cpu].file_size;
2964 		}
2965 		page_offset = calc_page_offset(handle, page_offset - 1);
2966 
2967 		last_records[cpu] = load_records(handle, cpu, page_offset, start_offset);
2968 	}
2969 }
2970 
peek_last_event(struct tracecmd_input * handle,struct tep_record ** last_records,int cpu)2971 static struct tep_record *peek_last_event(struct tracecmd_input *handle,
2972 					  struct tep_record **last_records, int cpu)
2973 {
2974 	struct tep_record *record = last_records[cpu];
2975 	struct page *page = handle->cpu_data[cpu].page;
2976 	unsigned long long page_offset;
2977 
2978 	if (record)
2979 		return record;
2980 
2981 	/* page can be NULL if the size is zero */
2982 	if (!page)
2983 		return NULL;
2984 
2985 	page_offset = page->offset - handle->page_size;
2986 	if (page_offset < handle->cpu_data[cpu].file_offset)
2987 		return NULL;
2988 
2989 	last_records[cpu] = load_records(handle, cpu, page_offset, 0);
2990 	return peek_last_event(handle, last_records, cpu);
2991 }
2992 
next_last_event(struct tracecmd_input * handle,struct tep_record ** last_records,int cpu)2993 static struct tep_record *next_last_event(struct tracecmd_input *handle,
2994 					  struct tep_record **last_records, int cpu)
2995 {
2996 	struct tep_record *record = last_records[cpu];
2997 	struct page *page = handle->cpu_data[cpu].page;
2998 
2999 	if (!record)
3000 		return NULL;
3001 
3002 	last_records[cpu] = record->priv;
3003 	record->priv = page;
3004 
3005 	return record;
3006 }
3007 
3008 /**
3009  * tracecmd_iterate_events_reverse - iterate events over a given handle backwards
3010  * @handle: The handle to iterate over
3011  * @cpus: The CPU set to filter on (NULL for all CPUs)
3012  * @cpu_size: The size of @cpus (ignored if @cpus is NULL)
3013  * @callback: The callback function for each event
3014  * @callback_data: The data to pass to the @callback.
3015  * @cont: If true, start where it left off, otherwise start at the end.
3016  *
3017  * Will loop over all events in @handle (filtered by the given @cpus),
3018  * and will call @callback for each event in reverse order.
3019  *
3020  * Returns the -1 on error, or the value of the callbacks.
3021  */
tracecmd_iterate_events_reverse(struct tracecmd_input * handle,cpu_set_t * cpus,int cpu_size,int (* callback)(struct tracecmd_input * handle,struct tep_record *,int,void *),void * callback_data,bool cont)3022 int tracecmd_iterate_events_reverse(struct tracecmd_input *handle,
3023 				    cpu_set_t *cpus, int cpu_size,
3024 				    int (*callback)(struct tracecmd_input *handle,
3025 						    struct tep_record *,
3026 						    int, void *),
3027 				    void *callback_data, bool cont)
3028 {
3029 	unsigned long long last_timestamp = 0;
3030 	struct tep_record **records;
3031 	struct tep_record *record;
3032 	int next_cpu;
3033 	int max_cpus = handle->cpus;
3034 	int cpu;
3035 	int ret = 0;
3036 
3037 	if (!callback && !handle->nr_followers) {
3038 		errno = EINVAL;
3039 		return -1;
3040 	}
3041 
3042 	records = calloc(max_cpus, sizeof(*records));
3043 	if (!records)
3044 		return -1;
3045 
3046 	initialize_last_events(handle, records, cpus, cpu_size, max_cpus, cont);
3047 
3048 	do {
3049 		next_cpu = -1;
3050 		for (cpu = 0; cpu < max_cpus; cpu++) {
3051 			if (cpus && !CPU_ISSET_S(cpu, cpu_size, cpus))
3052 				continue;
3053 			record = peek_last_event(handle, records, cpu);
3054 			if (!record)
3055 				continue;
3056 
3057 			if (next_cpu < 0 || record->ts > last_timestamp) {
3058 				next_cpu = cpu;
3059 				last_timestamp = record->ts;
3060 			}
3061 		}
3062 		if (next_cpu >= 0) {
3063 			record = next_last_event(handle, records, next_cpu);;
3064 			ret = call_callbacks(handle, record, next_cpu,
3065 					     callback, callback_data);
3066 			tracecmd_free_record(record);
3067 		}
3068 	} while (next_cpu >= 0 && ret == 0);
3069 
3070 	free(records);
3071 
3072 	return ret;
3073 }
3074 
3075 struct record_handle {
3076 	unsigned long long		ts;
3077 	struct tracecmd_input		*handle;
3078 };
3079 
3080 /**
3081  * tracecmd_iterate_events_multi - iterate events over multiple handles
3082  * @handles: An array of handles to iterate over
3083  * @nr_handles: The number of handles in the @handles array.
3084  * @callback: The callback function for each event
3085  * @callback_data: The data to pass to the @callback.
3086  *
3087  * Will loop over all CPUs for each handle in @handles and call the
3088  * @callback in the order of the timestamp for each event's record
3089  * for each handle.
3090  *
3091  * Returns the -1 on error, or the value of the callbacks.
3092  */
tracecmd_iterate_events_multi(struct tracecmd_input ** handles,int nr_handles,int (* callback)(struct tracecmd_input * handle,struct tep_record *,int,void *),void * callback_data)3093 int tracecmd_iterate_events_multi(struct tracecmd_input **handles,
3094 				  int nr_handles,
3095 				  int (*callback)(struct tracecmd_input *handle,
3096 						  struct tep_record *,
3097 						  int, void *),
3098 				  void *callback_data)
3099 {
3100 	struct tracecmd_input *handle;
3101 	struct record_handle *records;
3102 	struct tep_record *record;
3103 	unsigned long long ts, last_timestamp = 0;
3104 	int next_cpu;
3105 	int cpus = 0;
3106 	int all_cpus = 0;
3107 	int cpu;
3108 	int i;
3109 	int ret = 0;
3110 
3111 	for (i = 0; i < nr_handles; i++) {
3112 		handle = handles[i];
3113 		cpus += handle->cpus;
3114 	}
3115 
3116 	records = calloc(cpus, sizeof(*records));
3117 	if (!records)
3118 		return -1;
3119 
3120 	for (i = 0; i < nr_handles; i++) {
3121 		handle = handles[i];
3122 		handle->start_cpu = all_cpus;
3123 		for (cpu = 0; cpu < handle->cpus; cpu++) {
3124 			record = tracecmd_peek_data(handle, cpu);
3125 			records[all_cpus + cpu].ts = record ? record->ts : -1ULL;
3126 			records[all_cpus + cpu].handle = handle;
3127 		}
3128 		all_cpus += cpu;
3129 	}
3130 
3131 	do {
3132 		next_cpu = -1;
3133 		for (cpu = 0; cpu < all_cpus; cpu++) {
3134 			ts = records[cpu].ts;
3135 			if (ts == -1ULL)
3136 				continue;
3137 
3138 			if (next_cpu < 0 || ts < last_timestamp) {
3139 				next_cpu = cpu;
3140 				last_timestamp = ts;
3141 			}
3142 		}
3143 		if (next_cpu >= 0) {
3144 			handle = records[next_cpu].handle;
3145 			cpu = next_cpu - handle->start_cpu;
3146 
3147 			/* Refresh record as callback could have changed */
3148 			record = tracecmd_peek_data(handle, cpu);
3149 
3150 			/* If the record updated, try again */
3151 			if (!record || record->ts != last_timestamp) {
3152 				records[next_cpu].ts = record ? record->ts : -1ULL;
3153 				continue;
3154 			}
3155 
3156 			/* Need to call read_data to increment to the next record */
3157 			record = tracecmd_read_data(handle, cpu);
3158 
3159 			ret = call_callbacks(handle, record, next_cpu,
3160 					     callback, callback_data);
3161 
3162 			tracecmd_free_record(record);
3163 		}
3164 
3165 	} while (next_cpu >= 0 && ret == 0);
3166 
3167 	free(records);
3168 
3169 	return ret;
3170 }
3171 
3172 /**
3173  * tracecmd_peek_next_data - return the next record
3174  * @handle: input handle to the trace.dat file
3175  * @rec_cpu: return pointer to the CPU that the record belongs to
3176  *
3177  * This returns the next record by time. This is different than
3178  * tracecmd_peek_data in that it looks at all CPUs. It does a peek
3179  * at each CPU and the record with the earliest time stame is
3180  * returned. If @rec_cpu is not NULL it gets the CPU id the record was
3181  * on. It does not increment the CPU iterator.
3182  */
3183 struct tep_record *
tracecmd_peek_next_data(struct tracecmd_input * handle,int * rec_cpu)3184 tracecmd_peek_next_data(struct tracecmd_input *handle, int *rec_cpu)
3185 {
3186 	unsigned long long ts;
3187 	struct tep_record *record, *next_record = NULL;
3188 	int next_cpu;
3189 	int cpu;
3190 
3191 	if (rec_cpu)
3192 		*rec_cpu = -1;
3193 
3194 	next_cpu = -1;
3195 	ts = 0;
3196 
3197 	for (cpu = 0; cpu < handle->cpus; cpu++) {
3198 		record = tracecmd_peek_data(handle, cpu);
3199 		if (record && (!next_record || record->ts < ts)) {
3200 			ts = record->ts;
3201 			next_cpu = cpu;
3202 			next_record = record;
3203 		}
3204 	}
3205 
3206 	if (next_record) {
3207 		if (rec_cpu)
3208 			*rec_cpu = next_cpu;
3209 		return next_record;
3210 	}
3211 
3212 	return NULL;
3213 }
3214 
3215 /**
3216  * tracecmd_read_prev - read the record before the given record
3217  * @handle: input handle to the trace.dat file
3218  * @record: the record to use to find the previous record.
3219  *
3220  * This returns the record before the @record on its CPU. If
3221  * @record is the first record, NULL is returned. The cursor is set
3222  * as if the previous record was read by tracecmd_read_data().
3223  *
3224  * @record can not be NULL, otherwise NULL is returned; the
3225  * record ownership goes to this function.
3226  *
3227  * Note, this is not that fast of an algorithm, since it needs
3228  * to build the timestamp for the record.
3229  *
3230  * The record returned must be freed with tracecmd_free_record().
3231  */
3232 struct tep_record *
tracecmd_read_prev(struct tracecmd_input * handle,struct tep_record * record)3233 tracecmd_read_prev(struct tracecmd_input *handle, struct tep_record *record)
3234 {
3235 	unsigned long long offset, page_offset;;
3236 	struct cpu_data *cpu_data;
3237 	int index;
3238 	int cpu;
3239 
3240 	if (!record)
3241 		return NULL;
3242 
3243 	cpu = record->cpu;
3244 	offset = record->offset;
3245 	cpu_data = &handle->cpu_data[cpu];
3246 
3247 	page_offset = calc_page_offset(handle, offset);
3248 	index = offset - page_offset;
3249 
3250 	/* Note, the record passed in could have been a peek */
3251 	free_next(handle, cpu);
3252 
3253 	/* Reset the cursor */
3254 	/* Should not happen */
3255 	if (get_page(handle, cpu, page_offset) < 0)
3256 		return NULL;
3257 
3258 	update_page_info(handle, cpu);
3259 
3260 	/* Find the record before this record */
3261 	index = 0;
3262 	for (;;) {
3263 		record = tracecmd_read_data(handle, cpu);
3264 		/* Should not happen! */
3265 		if (!record)
3266 			return NULL;
3267 		if (record->offset == offset)
3268 			break;
3269 		index = record->offset - page_offset;
3270 		tracecmd_free_record(record);
3271 	}
3272 	tracecmd_free_record(record);
3273 
3274 	if (index)
3275 		/* we found our record */
3276 		return tracecmd_read_at(handle, page_offset + index, NULL);
3277 
3278 	/* reset the index to start at the beginning of the page */
3279 	update_page_info(handle, cpu);
3280 
3281 	/* The previous record is on the previous page */
3282 	for (;;) {
3283 		/* check if this is the first page */
3284 		if (page_offset == cpu_data->file_offset)
3285 			return NULL;
3286 		page_offset -= handle->page_size;
3287 
3288 		/* Updating page to a new page will reset index to 0 */
3289 		get_page(handle, cpu, page_offset);
3290 
3291 		record = NULL;
3292 		index = 0;
3293 		do {
3294 			if (record) {
3295 				index = record->offset - page_offset;
3296 				tracecmd_free_record(record);
3297 			}
3298 			record = tracecmd_read_data(handle, cpu);
3299 			/* Should not happen */
3300 			if (!record)
3301 				return NULL;
3302 		} while (record->offset != offset);
3303 		tracecmd_free_record(record);
3304 
3305 		if (index)
3306 			/* we found our record */
3307 			return tracecmd_read_at(handle, page_offset + index, NULL);
3308 	}
3309 
3310 	/* Not reached */
3311 }
3312 
init_cpu_zfile(struct tracecmd_input * handle,int cpu)3313 static int init_cpu_zfile(struct tracecmd_input *handle, int cpu)
3314 {
3315 	struct cpu_data *cpu_data;
3316 	off_t offset;
3317 	size_t size;
3318 
3319 	cpu_data = &handle->cpu_data[cpu];
3320 	offset = lseek(handle->fd, 0, SEEK_CUR);
3321 	if (lseek(handle->fd, cpu_data->file_offset, SEEK_SET) == (off_t)-1)
3322 		return -1;
3323 
3324 	strcpy(cpu_data->compress.file, COMPR_TEMP_FILE);
3325 	cpu_data->compress.fd = mkstemp(cpu_data->compress.file);
3326 	if (cpu_data->compress.fd < 0)
3327 		return -1;
3328 
3329 	if (tracecmd_uncompress_copy_to(handle->compress, cpu_data->compress.fd, NULL, &size))
3330 		return -1;
3331 
3332 	if (lseek(handle->fd, offset, SEEK_SET) == (off_t)-1)
3333 		return -1;
3334 
3335 	cpu_data->file_offset = handle->next_offset;
3336 	handle->next_offset = (handle->next_offset + size + handle->page_size - 1) &
3337 		~(handle->page_size - 1);
3338 	cpu_data->offset = cpu_data->file_offset;
3339 
3340 	cpu_data->file_size = size;
3341 	cpu_data->size = size;
3342 	return 0;
3343 }
3344 
init_cpu_zpage(struct tracecmd_input * handle,int cpu)3345 static int init_cpu_zpage(struct tracecmd_input *handle, int cpu)
3346 {
3347 	struct cpu_data *cpu_data = &handle->cpu_data[cpu];
3348 	int count;
3349 	int i;
3350 
3351 	if (lseek(handle->fd, cpu_data->file_offset, SEEK_SET) == (off_t)-1)
3352 		return -1;
3353 
3354 	count = tracecmd_load_chunks_info(handle->compress, &cpu_data->compress.chunks);
3355 	if (count < 0)
3356 		return -1;
3357 
3358 	cpu_data->compress.count = count;
3359 	cpu_data->compress.last_chunk = 0;
3360 
3361 	cpu_data->file_offset = handle->next_offset;
3362 	cpu_data->file_size = 0;
3363 
3364 	for (i = 0; i < count; i++)
3365 		cpu_data->file_size += cpu_data->compress.chunks[i].size;
3366 
3367 	cpu_data->offset = cpu_data->file_offset;
3368 	cpu_data->size = cpu_data->file_size;
3369 	handle->next_offset = (handle->next_offset + cpu_data->file_size + handle->page_size - 1) &
3370 		~(handle->page_size - 1);
3371 	return 0;
3372 }
3373 
compress_cmp(const struct trace_rbtree_node * A,const struct trace_rbtree_node * B)3374 static int compress_cmp(const struct trace_rbtree_node *A,
3375 			const struct trace_rbtree_node *B)
3376 {
3377 	const struct zchunk_cache *cacheA;
3378 	const struct zchunk_cache *cacheB;
3379 
3380 	cacheA = container_of(A, struct zchunk_cache, node);
3381 	cacheB = container_of(B, struct zchunk_cache, node);
3382 
3383 	return chunk_cmp(cacheA->chunk, cacheB->chunk);
3384 }
3385 
compress_search(const struct trace_rbtree_node * A,const void * data)3386 static int compress_search(const struct trace_rbtree_node *A,
3387 			   const void *data)
3388 {
3389 	const struct zchunk_cache *cache;
3390 	off_t offset = *(off_t *)data;
3391 
3392 	cache = container_of(A, struct zchunk_cache, node);
3393 
3394 	if (CHUNK_CHECK_OFFSET(cache->chunk, offset))
3395 		return 0;
3396 
3397 	if (cache->chunk->offset < offset)
3398 		return -1;
3399 
3400 	return 1;
3401 }
3402 
init_cpu(struct tracecmd_input * handle,int cpu)3403 static int init_cpu(struct tracecmd_input *handle, int cpu)
3404 {
3405 	struct cpu_data *cpu_data = &handle->cpu_data[cpu];
3406 	int ret;
3407 	int i;
3408 
3409 	if (handle->cpu_compressed && cpu_data->file_size > 0) {
3410 		if (handle->read_zpage)
3411 			ret = init_cpu_zpage(handle, cpu);
3412 		else
3413 			ret = init_cpu_zfile(handle, cpu);
3414 		if (ret)
3415 			return ret;
3416 	} else {
3417 		cpu_data->offset = cpu_data->file_offset;
3418 		cpu_data->size = cpu_data->file_size;
3419 	}
3420 	cpu_data->timestamp = 0;
3421 
3422 	list_head_init(&cpu_data->page_maps);
3423 
3424 	trace_rbtree_init(&cpu_data->compress.cache, compress_cmp, compress_search);
3425 
3426 	if (!cpu_data->size) {
3427 		tracecmd_info("CPU %d is empty", cpu);
3428 		return 0;
3429 	}
3430 
3431 	cpu_data->nr_pages = (cpu_data->size + handle->page_size - 1) / handle->page_size;
3432 	if (!cpu_data->nr_pages)
3433 		cpu_data->nr_pages = 1;
3434 	cpu_data->pages = calloc(cpu_data->nr_pages, sizeof(*cpu_data->pages));
3435 	if (!cpu_data->pages)
3436 		return -1;
3437 
3438 	if (handle->use_pipe) {
3439 		/* Just make a page, it will be nuked later */
3440 		cpu_data->page = malloc(sizeof(*cpu_data->page));
3441 		if (!cpu_data->page)
3442 			goto fail;
3443 
3444 		memset(cpu_data->page, 0, sizeof(*cpu_data->page));
3445 		cpu_data->pages[0] = cpu_data->page;
3446 		cpu_data->page_cnt = 1;
3447 		cpu_data->page->ref_count = 1;
3448 		return 0;
3449 	}
3450 
3451 	cpu_data->page = allocate_page(handle, cpu, cpu_data->offset);
3452 	if (!cpu_data->page && !handle->read_page) {
3453 		perror("mmap");
3454 		fprintf(stderr, "Can not mmap file, will read instead\n");
3455 
3456 		if (cpu) {
3457 			/*
3458 			 * If the other CPUs had size and was able to mmap
3459 			 * then bail.
3460 			 */
3461 			for (i = 0; i < cpu; i++) {
3462 				if (handle->cpu_data[i].size)
3463 					goto fail;
3464 			}
3465 		}
3466 
3467 		/* try again without mmapping, just read it directly */
3468 		handle->read_page = true;
3469 		cpu_data->page = allocate_page(handle, cpu, cpu_data->offset);
3470 		if (!cpu_data->page)
3471 			/* Still no luck, bail! */
3472 			goto fail;
3473 	}
3474 
3475 	if (update_page_info(handle, cpu))
3476 		goto fail;
3477 	cpu_data->first_ts = cpu_data->timestamp;
3478 
3479 	return 0;
3480  fail:
3481 	free(cpu_data->pages);
3482 	cpu_data->pages = NULL;
3483 	free(cpu_data->page);
3484 	cpu_data->page = NULL;
3485 	return -1;
3486 }
3487 
tracecmd_set_ts_offset(struct tracecmd_input * handle,long long offset)3488 void tracecmd_set_ts_offset(struct tracecmd_input *handle,
3489 			    long long offset)
3490 {
3491 	handle->ts_offset = offset;
3492 }
3493 
3494 /**
3495  * tracecmd_add_ts_offset - Add value to the offset which will be applied to the timestamps of all
3496  *			    events from given trace file
3497  * @handle: input handle to the trace.dat file
3498  * @offset: value, that will be added to the offset
3499  */
tracecmd_add_ts_offset(struct tracecmd_input * handle,long long offset)3500 void tracecmd_add_ts_offset(struct tracecmd_input *handle,
3501 			    long long offset)
3502 {
3503 	handle->ts_offset += offset;
3504 }
3505 
tracecmd_set_ts2secs(struct tracecmd_input * handle,unsigned long long hz)3506 void tracecmd_set_ts2secs(struct tracecmd_input *handle,
3507 			 unsigned long long hz)
3508 {
3509 	double ts2secs;
3510 
3511 	ts2secs = (double)NSEC_PER_SEC / (double)hz;
3512 	handle->ts2secs = ts2secs;
3513 	handle->use_trace_clock = false;
3514 }
3515 
tsync_offset_cmp(const void * a,const void * b)3516 static int tsync_offset_cmp(const void *a, const void *b)
3517 {
3518 	struct ts_offset_sample *ts_a = (struct ts_offset_sample *)a;
3519 	struct ts_offset_sample *ts_b = (struct ts_offset_sample *)b;
3520 
3521 	if (ts_a->time > ts_b->time)
3522 		return 1;
3523 	if (ts_a->time < ts_b->time)
3524 		return -1;
3525 	return 0;
3526 }
3527 
3528 #define safe_read(R, C)					\
3529 	do {						\
3530 		if ((C) > size)				\
3531 			return -EFAULT;			\
3532 		(R) = tep_read_number(tep, buf, (C));	\
3533 		buf += (C);				\
3534 		size -= (C);				\
3535 	} while (0)
3536 
3537 #define safe_read_loop(type)						\
3538 	do {								\
3539 		int ii;							\
3540 		for (ii = 0; ii < ts_offsets->ts_samples_count; ii++)	\
3541 			safe_read(ts_offsets->ts_samples[ii].type, 8);	\
3542 	} while (0)
3543 
tsync_cpu_offsets_load(struct tracecmd_input * handle,char * buf,int size)3544 static int tsync_cpu_offsets_load(struct tracecmd_input *handle, char *buf, int size)
3545 {
3546 	struct tep_handle *tep = handle->pevent;
3547 	struct timesync_offsets *ts_offsets;
3548 	int i, j, k;
3549 
3550 	safe_read(handle->host.cpu_count, 4);
3551 	handle->host.ts_offsets = calloc(handle->host.cpu_count,
3552 					 sizeof(struct timesync_offsets));
3553 	if (!handle->host.ts_offsets)
3554 		return -ENOMEM;
3555 	for (i = 0; i < handle->host.cpu_count; i++) {
3556 		ts_offsets = &handle->host.ts_offsets[i];
3557 		safe_read(ts_offsets->ts_samples_count, 4);
3558 		ts_offsets->ts_samples = calloc(ts_offsets->ts_samples_count,
3559 						sizeof(struct ts_offset_sample));
3560 		if (!ts_offsets->ts_samples)
3561 			return -ENOMEM;
3562 		safe_read_loop(time);
3563 		safe_read_loop(offset);
3564 		safe_read_loop(scaling);
3565 	}
3566 
3567 	if (size > 0) {
3568 		for (i = 0; i < handle->host.cpu_count; i++) {
3569 			ts_offsets = &handle->host.ts_offsets[i];
3570 			safe_read_loop(fraction);
3571 		}
3572 	}
3573 
3574 	for (i = 0; i < handle->host.cpu_count; i++) {
3575 		ts_offsets = &handle->host.ts_offsets[i];
3576 		qsort(ts_offsets->ts_samples, ts_offsets->ts_samples_count,
3577 		      sizeof(struct ts_offset_sample), tsync_offset_cmp);
3578 		/* Filter possible samples with equal time */
3579 		for (k = 0, j = 0; k < ts_offsets->ts_samples_count; k++) {
3580 			if (k == 0 || ts_offsets->ts_samples[k].time != ts_offsets->ts_samples[k-1].time)
3581 				ts_offsets->ts_samples[j++] = ts_offsets->ts_samples[k];
3582 		}
3583 		ts_offsets->ts_samples_count = j;
3584 	}
3585 
3586 	return 0;
3587 }
3588 
trace_tsync_offset_free(struct host_trace_info * host)3589 static void trace_tsync_offset_free(struct host_trace_info *host)
3590 {
3591 	int i;
3592 
3593 	if (host->ts_offsets) {
3594 		for (i = 0; i < host->cpu_count; i++)
3595 			free(host->ts_offsets[i].ts_samples);
3596 		free(host->ts_offsets);
3597 		host->ts_offsets = NULL;
3598 	}
3599 }
3600 
trace_pid_map_cmp(const void * a,const void * b)3601 static int trace_pid_map_cmp(const void *a, const void *b)
3602 {
3603 	struct tracecmd_proc_addr_map *m_a = (struct tracecmd_proc_addr_map *)a;
3604 	struct tracecmd_proc_addr_map *m_b = (struct tracecmd_proc_addr_map *)b;
3605 
3606 	if (m_a->start > m_b->start)
3607 	if (m_a->start < m_b->start)
3608 		return -1;
3609 	return 0;
3610 }
3611 
procmap_free(struct pid_addr_maps * maps)3612 static void procmap_free(struct pid_addr_maps *maps)
3613 {
3614 	int i;
3615 
3616 	if (!maps)
3617 		return;
3618 	if (maps->lib_maps) {
3619 		for (i = 0; i < maps->nr_lib_maps; i++)
3620 			free(maps->lib_maps[i].lib_name);
3621 		free(maps->lib_maps);
3622 	}
3623 	free(maps->proc_name);
3624 	free(maps);
3625 }
3626 
trace_guests_free(struct tracecmd_input * handle)3627 static void trace_guests_free(struct tracecmd_input *handle)
3628 {
3629 	struct guest_trace_info *guest;
3630 
3631 	while (handle->guest) {
3632 		guest = handle->guest;
3633 		handle->guest = handle->guest->next;
3634 		free(guest->name);
3635 		free(guest->cpu_pid);
3636 		free(guest);
3637 	}
3638 }
3639 
trace_guest_load(struct tracecmd_input * handle,char * buf,int size)3640 static int trace_guest_load(struct tracecmd_input *handle, char *buf, int size)
3641 {
3642 	struct guest_trace_info *guest = NULL;
3643 	int cpu;
3644 	int i;
3645 
3646 	guest = calloc(1, sizeof(struct guest_trace_info));
3647 	if (!guest)
3648 		goto error;
3649 
3650 	/*
3651 	 * Guest name, null terminated string
3652 	 * long long (8 bytes) trace-id
3653 	 * int (4 bytes) number of guest CPUs
3654 	 * array of size number of guest CPUs:
3655 	 *	int (4 bytes) Guest CPU id
3656 	 *	int (4 bytes) Host PID, running the guest CPU
3657 	 */
3658 
3659 	guest->name = strndup(buf, size);
3660 	if (!guest->name)
3661 		goto error;
3662 	buf += strlen(guest->name) + 1;
3663 	size -= strlen(guest->name) + 1;
3664 
3665 	if (size < sizeof(long long))
3666 		goto error;
3667 	guest->trace_id = tep_read_number(handle->pevent, buf, sizeof(long long));
3668 	buf += sizeof(long long);
3669 	size -= sizeof(long long);
3670 
3671 	if (size < sizeof(int))
3672 		goto error;
3673 	guest->vcpu_count = tep_read_number(handle->pevent, buf, sizeof(int));
3674 	buf += sizeof(int);
3675 	size -= sizeof(int);
3676 
3677 	guest->cpu_pid = calloc(guest->vcpu_count, sizeof(int));
3678 	if (!guest->cpu_pid)
3679 		goto error;
3680 
3681 	for (i = 0; i < guest->vcpu_count; i++) {
3682 		if (size < 2 * sizeof(int))
3683 			goto error;
3684 		cpu = tep_read_number(handle->pevent, buf, sizeof(int));
3685 		buf += sizeof(int);
3686 		if (cpu >= guest->vcpu_count)
3687 			goto error;
3688 		guest->cpu_pid[cpu] = tep_read_number(handle->pevent,
3689 						      buf, sizeof(int));
3690 		buf += sizeof(int);
3691 		size -= 2 * sizeof(int);
3692 	}
3693 
3694 	guest->next = handle->guest;
3695 	handle->guest = guest;
3696 	return 0;
3697 
3698 error:
3699 	if (guest) {
3700 		free(guest->cpu_pid);
3701 		free(guest->name);
3702 		free(guest);
3703 	}
3704 	return -1;
3705 }
3706 
3707 /* Needs to be a constant, and 4K should be good enough */
3708 #define STR_PROCMAP_LINE_MAX	4096
trace_pid_map_load(struct tracecmd_input * handle,char * buf)3709 static int trace_pid_map_load(struct tracecmd_input *handle, char *buf)
3710 {
3711 	struct pid_addr_maps *maps = NULL;
3712 	char mapname[STR_PROCMAP_LINE_MAX+1];
3713 	char *line;
3714 	int res;
3715 	int ret;
3716 	int i;
3717 
3718 	maps = calloc(1, sizeof(*maps));
3719 	if (!maps)
3720 		return -ENOMEM;
3721 
3722 	ret  = -EINVAL;
3723 	line = strchr(buf, '\n');
3724 	if (!line)
3725 		goto out_fail;
3726 
3727 	*line = '\0';
3728 	if (strlen(buf) > STR_PROCMAP_LINE_MAX)
3729 		goto out_fail;
3730 
3731 	res = sscanf(buf, "%x %x %"STRINGIFY(STR_PROCMAP_LINE_MAX)"s", &maps->pid, &maps->nr_lib_maps, mapname);
3732 	if (res != 3)
3733 		goto out_fail;
3734 
3735 	ret  = -ENOMEM;
3736 	maps->proc_name = strdup(mapname);
3737 	if (!maps->proc_name)
3738 		goto out_fail;
3739 
3740 	maps->lib_maps = calloc(maps->nr_lib_maps, sizeof(struct tracecmd_proc_addr_map));
3741 	if (!maps->lib_maps)
3742 		goto out_fail;
3743 
3744 	buf = line + 1;
3745 	line = strchr(buf, '\n');
3746 	for (i = 0; i < maps->nr_lib_maps; i++) {
3747 		if (!line)
3748 			break;
3749 		*line = '\0';
3750 		if (strlen(buf) > STR_PROCMAP_LINE_MAX)
3751 			break;
3752 		res = sscanf(buf, "%zx %zx %s", &maps->lib_maps[i].start,
3753 			     &maps->lib_maps[i].end, mapname);
3754 		if (res != 3)
3755 			break;
3756 		maps->lib_maps[i].lib_name = strdup(mapname);
3757 		if (!maps->lib_maps[i].lib_name)
3758 			goto out_fail;
3759 		buf = line + 1;
3760 		line = strchr(buf, '\n');
3761 	}
3762 
3763 	ret  = -EINVAL;
3764 	if (i != maps->nr_lib_maps)
3765 		goto out_fail;
3766 
3767 	qsort(maps->lib_maps, maps->nr_lib_maps,
3768 	      sizeof(*maps->lib_maps), trace_pid_map_cmp);
3769 
3770 	maps->next = handle->pid_maps;
3771 	handle->pid_maps = maps;
3772 
3773 	return 0;
3774 
3775 out_fail:
3776 	procmap_free(maps);
3777 	return ret;
3778 }
3779 
trace_pid_map_free(struct pid_addr_maps * maps)3780 static void trace_pid_map_free(struct pid_addr_maps *maps)
3781 {
3782 	struct pid_addr_maps *del;
3783 
3784 	while (maps) {
3785 		del = maps;
3786 		maps = maps->next;
3787 		procmap_free(del);
3788 	}
3789 }
3790 
trace_pid_map_search(const void * a,const void * b)3791 static int trace_pid_map_search(const void *a, const void *b)
3792 {
3793 	struct tracecmd_proc_addr_map *key = (struct tracecmd_proc_addr_map *)a;
3794 	struct tracecmd_proc_addr_map *map = (struct tracecmd_proc_addr_map *)b;
3795 
3796 	if (key->start >= map->end)
3797 		return 1;
3798 	if (key->start < map->start)
3799 		return -1;
3800 	return 0;
3801 }
3802 
3803 /**
3804  * tracecmd_search_task_map - Search task memory address map
3805  * @handle: input handle to the trace.dat file
3806  * @pid: pid of the task
3807  * @addr: address from the task memory space.
3808  *
3809  * Map of the task memory can be saved in the trace.dat file, using the option
3810  * "--proc-map". If there is such information, this API can be used to look up
3811  * into this memory map to find what library is loaded at the given @addr.
3812  *
3813  * A pointer to struct tracecmd_proc_addr_map is returned, containing the name
3814  * of the library at given task @addr and the library start and end addresses.
3815  */
3816 struct tracecmd_proc_addr_map *
tracecmd_search_task_map(struct tracecmd_input * handle,int pid,unsigned long long addr)3817 tracecmd_search_task_map(struct tracecmd_input *handle,
3818 			 int pid, unsigned long long addr)
3819 {
3820 	struct tracecmd_proc_addr_map *lib;
3821 	struct tracecmd_proc_addr_map key;
3822 	struct pid_addr_maps *maps;
3823 
3824 	if (!handle || !handle->pid_maps)
3825 		return NULL;
3826 
3827 	maps = handle->pid_maps;
3828 	while (maps) {
3829 		if (maps->pid == pid)
3830 			break;
3831 		maps = maps->next;
3832 	}
3833 	if (!maps || !maps->nr_lib_maps || !maps->lib_maps)
3834 		return NULL;
3835 	key.start = addr;
3836 	lib = bsearch(&key, maps->lib_maps, maps->nr_lib_maps,
3837 		      sizeof(*maps->lib_maps), trace_pid_map_search);
3838 
3839 	return lib;
3840 }
3841 
get_meta_strings_size(struct tracecmd_input * handle)3842 __hidden unsigned int get_meta_strings_size(struct tracecmd_input *handle)
3843 {
3844 	return handle->strings_size;
3845 }
3846 
get_last_option_offset(struct tracecmd_input * handle)3847 __hidden unsigned long long get_last_option_offset(struct tracecmd_input *handle)
3848 {
3849 	return handle->options_last_offset;
3850 }
3851 
handle_option_done(struct tracecmd_input * handle,char * buf,int size)3852 static int handle_option_done(struct tracecmd_input *handle, char *buf, int size)
3853 {
3854 	unsigned long long offset;
3855 
3856 	if (size < 8)
3857 		return -1;
3858 
3859 	offset = lseek(handle->fd, 0, SEEK_CUR);
3860 	if (offset >= size)
3861 		handle->options_last_offset = offset - size;
3862 
3863 	offset = tep_read_number(handle->pevent, buf, 8);
3864 	if (!offset)
3865 		return 0;
3866 
3867 	if (lseek(handle->fd, offset, SEEK_SET) == (off_t)-1)
3868 		return -1;
3869 
3870 	return handle_options(handle);
3871 }
3872 
save_read_number(struct tep_handle * tep,char * data,int * data_size,int * read_pos,int bytes,unsigned long long * num)3873 static inline int save_read_number(struct tep_handle *tep, char *data, int *data_size,
3874 				   int *read_pos, int bytes, unsigned long long *num)
3875 {
3876 	if (bytes > *data_size)
3877 		return -1;
3878 
3879 	*num = tep_read_number(tep, (data + *read_pos), bytes);
3880 	*read_pos += bytes;
3881 	*data_size -= bytes;
3882 	return 0;
3883 }
3884 
save_read_string(char * data,int * data_size,int * read_pos)3885 static inline char *save_read_string(char *data, int *data_size, int *read_pos)
3886 {
3887 	char *str;
3888 
3889 	if (*data_size < 1)
3890 		return NULL;
3891 
3892 	str = strdup(data + *read_pos);
3893 	if (!str)
3894 		return NULL;
3895 	*data_size -= (strlen(str) + 1);
3896 	if (*data_size < 0) {
3897 		free(str);
3898 		return NULL;
3899 	}
3900 	*read_pos += (strlen(str) + 1);
3901 
3902 	return str;
3903 }
3904 
handle_buffer_option(struct tracecmd_input * handle,unsigned short id,char * data,int size)3905 static int handle_buffer_option(struct tracecmd_input *handle,
3906 				unsigned short id, char *data, int size)
3907 {
3908 	struct input_buffer_instance *buff;
3909 	struct cpu_file_data *cpu_data;
3910 	unsigned long long tmp;
3911 	long long max_cpu = -1;
3912 	int rsize = 0;
3913 	char *name;
3914 	int i;
3915 
3916 	if (save_read_number(handle->pevent, data, &size, &rsize, 8, &tmp))
3917 		return -1;
3918 
3919 	name = save_read_string(data, &size, &rsize);
3920 	if (!name)
3921 		return -1;
3922 
3923 	if (*name == '\0') {
3924 		/* top buffer */
3925 		buff = &handle->top_buffer;
3926 	} else {
3927 		buff = realloc(handle->buffers, sizeof(*handle->buffers) * (handle->nr_buffers + 1));
3928 		if (!buff) {
3929 			free(name);
3930 			return -1;
3931 		}
3932 		handle->buffers = buff;
3933 		handle->nr_buffers++;
3934 
3935 		buff = &handle->buffers[handle->nr_buffers - 1];
3936 	}
3937 	memset(buff, 0, sizeof(struct input_buffer_instance));
3938 	buff->name = name;
3939 	buff->offset = tmp;
3940 
3941 	if (!HAS_SECTIONS(handle))
3942 		return 0;
3943 
3944 	/* file sections specific data */
3945 	buff->clock = save_read_string(data, &size, &rsize);
3946 	if (!buff->clock)
3947 		return -1;
3948 
3949 	if (*name == '\0' && !handle->trace_clock)
3950 		handle->trace_clock = strdup(buff->clock);
3951 
3952 	if (id == TRACECMD_OPTION_BUFFER) {
3953 		if (save_read_number(handle->pevent, data, &size, &rsize, 4, &tmp))
3954 			return -1;
3955 		buff->page_size = tmp;
3956 
3957 		if (save_read_number(handle->pevent, data, &size, &rsize, 4, &tmp))
3958 			return -1;
3959 		buff->cpus = tmp;
3960 		if (!buff->cpus)
3961 			return 0;
3962 		cpu_data = calloc(buff->cpus, sizeof(*cpu_data));
3963 		if (!cpu_data)
3964 			return -1;
3965 		for (i = 0; i < buff->cpus; i++) {
3966 			if (save_read_number(handle->pevent, data, &size, &rsize, 4, &tmp))
3967 				goto fail;
3968 			if ((long long)tmp > max_cpu)
3969 				max_cpu = tmp;
3970 			cpu_data[i].cpu = tmp;
3971 			if (save_read_number(handle->pevent, data,
3972 					     &size, &rsize, 8, &cpu_data[i].offset))
3973 				goto fail;
3974 			if (save_read_number(handle->pevent, data,
3975 					     &size, &rsize, 8, &cpu_data[i].size))
3976 				goto fail;
3977 		}
3978 		if (buff->cpus == max_cpu + 1) {
3979 			/* Check to make sure cpus match the index */
3980 			for (i = 0; i < buff->cpus; i++) {
3981 				if (cpu_data[i].cpu != i)
3982 					goto copy_buffer;
3983 			}
3984 			buff->cpu_data = cpu_data;
3985 		} else {
3986  copy_buffer:
3987 			buff->cpu_data = calloc(max_cpu + 1, sizeof(*cpu_data));
3988 			if (!buff->cpu_data)
3989 				goto fail;
3990 			for (i = 0; i < buff->cpus; i++) {
3991 				if (buff->cpu_data[cpu_data[i].cpu].size) {
3992 					tracecmd_warning("More than one buffer defined for CPU %d (buffer %d)\n",
3993 							 cpu_data[i].cpu, i);
3994 					goto fail;
3995 				}
3996 				buff->cpu_data[cpu_data[i].cpu] = cpu_data[i];
3997 			}
3998 			buff->cpus = max_cpu + 1;
3999 			free(cpu_data);
4000 		}
4001 	} else {
4002 		buff->latency = true;
4003 	}
4004 	return 0;
4005 fail:
4006 	free(cpu_data);
4007 	return -1;
4008 }
4009 
handle_options(struct tracecmd_input * handle)4010 static int handle_options(struct tracecmd_input *handle)
4011 {
4012 	long long offset;
4013 	unsigned short option;
4014 	unsigned int size;
4015 	unsigned short id, flags;
4016 	char *cpustats = NULL;
4017 	struct hook_list *hook;
4018 	bool compress = false;
4019 	char *buf;
4020 	int cpus;
4021 	int ret;
4022 
4023 	if (!HAS_SECTIONS(handle)) {
4024 		handle->options_start = lseek(handle->fd, 0, SEEK_CUR);
4025 	} else {
4026 		if (read_section_header(handle, &id, &flags, NULL, NULL))
4027 			return -1;
4028 		if (id != TRACECMD_OPTION_DONE)
4029 			return -1;
4030 		if (flags & TRACECMD_SEC_FL_COMPRESS)
4031 			compress = true;
4032 	}
4033 
4034 	if (compress && in_uncompress_block(handle))
4035 		return -1;
4036 
4037 	for (;;) {
4038 		ret = read2(handle, &option);
4039 		if (ret)
4040 			goto out;
4041 
4042 		if (!HAS_SECTIONS(handle) && option == TRACECMD_OPTION_DONE)
4043 			break;
4044 
4045 		/* next 4 bytes is the size of the option */
4046 		ret = read4(handle, &size);
4047 		if (ret)
4048 			goto out;
4049 		buf = malloc(size);
4050 		if (!buf) {
4051 			ret = -ENOMEM;
4052 			goto out;
4053 		}
4054 		ret = do_read_check(handle, buf, size);
4055 		if (ret)
4056 			goto out;
4057 
4058 		switch (option) {
4059 		case TRACECMD_OPTION_DATE:
4060 			/*
4061 			 * A time has been mapped that is the
4062 			 * difference between the timestamps and
4063 			 * gtod. It is stored as ASCII with '0x'
4064 			 * appended.
4065 			 */
4066 			if (handle->flags &
4067 			    (TRACECMD_FL_IGNORE_DATE | TRACECMD_FL_RAW_TS))
4068 				break;
4069 			offset = strtoll(buf, NULL, 0);
4070 			/* Convert from micro to nano */
4071 			offset *= 1000;
4072 			handle->ts_offset += offset;
4073 			break;
4074 		case TRACECMD_OPTION_OFFSET:
4075 			/*
4076 			 * Similar to date option, but just adds an
4077 			 * offset to the timestamp.
4078 			 */
4079 			if (handle->flags & TRACECMD_FL_RAW_TS)
4080 				break;
4081 			offset = strtoll(buf, NULL, 0);
4082 			handle->ts_offset += offset;
4083 			break;
4084 		case TRACECMD_OPTION_TIME_SHIFT:
4085 			/*
4086 			 * long long int (8 bytes) trace session ID
4087 			 * int (4 bytes) protocol flags.
4088 			 * int (4 bytes) CPU count.
4089 			 * array of size [CPU count]:
4090 			 * [
4091 			 *  int (4 bytes) count of timestamp offsets.
4092 			 *  long long array of size [count] of times,
4093 			 *      when the offsets were calculated.
4094 			 *  long long array of size [count] of timestamp offsets.
4095 			 *  long long array of size [count] of timestamp scaling ratios.*
4096 			 * ]
4097 			 * array of size [CPU count]:
4098 			 * [
4099 			 *  long long array of size [count] of timestamp scaling fraction bits.*
4100 			 * ]*
4101 			 */
4102 			if (size < 16 || (handle->flags & TRACECMD_FL_RAW_TS))
4103 				break;
4104 			handle->host.peer_trace_id = tep_read_number(handle->pevent,
4105 								     buf, 8);
4106 			handle->host.flags = tep_read_number(handle->pevent,
4107 							     buf + 8, 4);
4108 			ret = tsync_cpu_offsets_load(handle, buf + 12, size - 12);
4109 			if (ret < 0)
4110 				goto out;
4111 			tracecmd_enable_tsync(handle, true);
4112 			break;
4113 		case TRACECMD_OPTION_CPUSTAT:
4114 			buf[size-1] = '\n';
4115 			cpustats = realloc(handle->cpustats,
4116 					   handle->cpustats_size + size + 1);
4117 			if (!cpustats) {
4118 				ret = -ENOMEM;
4119 				goto out;
4120 			}
4121 			memcpy(cpustats + handle->cpustats_size, buf, size);
4122 			handle->cpustats_size += size;
4123 			cpustats[handle->cpustats_size] = 0;
4124 			handle->cpustats = cpustats;
4125 			break;
4126 		case TRACECMD_OPTION_BUFFER:
4127 		case TRACECMD_OPTION_BUFFER_TEXT:
4128 			ret = handle_buffer_option(handle, option, buf, size);
4129 			if (ret < 0)
4130 				goto out;
4131 			break;
4132 		case TRACECMD_OPTION_TRACECLOCK:
4133 			tracecmd_parse_trace_clock(handle, buf, size);
4134 			if (!handle->ts2secs)
4135 				handle->use_trace_clock = true;
4136 			break;
4137 		case TRACECMD_OPTION_UNAME:
4138 			handle->uname = strdup(buf);
4139 			break;
4140 		case TRACECMD_OPTION_VERSION:
4141 			handle->version = strdup(buf);
4142 			break;
4143 		case TRACECMD_OPTION_HOOK:
4144 			hook = tracecmd_create_event_hook(buf);
4145 			hook->next = handle->hooks;
4146 			handle->hooks = hook;
4147 			break;
4148 		case TRACECMD_OPTION_CPUCOUNT:
4149 			cpus = *(int *)buf;
4150 			handle->cpus = tep_read_number(handle->pevent, &cpus, 4);
4151 			if (handle->cpus > handle->max_cpu)
4152 				handle->max_cpu = handle->cpus;
4153 			tep_set_cpus(handle->pevent, handle->cpus);
4154 			break;
4155 		case TRACECMD_OPTION_PROCMAPS:
4156 			if (buf[size-1] == '\0')
4157 				trace_pid_map_load(handle, buf);
4158 			break;
4159 		case TRACECMD_OPTION_TRACEID:
4160 			if (size < 8)
4161 				break;
4162 			handle->trace_id = tep_read_number(handle->pevent,
4163 							   buf, 8);
4164 			break;
4165 		case TRACECMD_OPTION_GUEST:
4166 			trace_guest_load(handle, buf, size);
4167 			break;
4168 		case TRACECMD_OPTION_TSC2NSEC:
4169 			if (size < 16 || (handle->flags & TRACECMD_FL_RAW_TS))
4170 				break;
4171 			handle->tsc_calc.mult = tep_read_number(handle->pevent,
4172 								buf, 4);
4173 			handle->tsc_calc.shift = tep_read_number(handle->pevent,
4174 								 buf + 4, 4);
4175 			handle->tsc_calc.offset = tep_read_number(handle->pevent,
4176 								  buf + 8, 8);
4177 			if (!(handle->flags & TRACECMD_FL_RAW_TS))
4178 				handle->flags |= TRACECMD_FL_IN_USECS;
4179 			break;
4180 		case TRACECMD_OPTION_HEADER_INFO:
4181 		case TRACECMD_OPTION_FTRACE_EVENTS:
4182 		case TRACECMD_OPTION_EVENT_FORMATS:
4183 		case TRACECMD_OPTION_KALLSYMS:
4184 		case TRACECMD_OPTION_PRINTK:
4185 		case TRACECMD_OPTION_CMDLINES:
4186 			if (size < 8)
4187 				break;
4188 			section_add_or_update(handle, option, -1,
4189 					      tep_read_number(handle->pevent, buf, 8), 0);
4190 			break;
4191 		case TRACECMD_OPTION_DONE:
4192 			if (compress)
4193 				in_uncompress_reset(handle);
4194 			ret = handle_option_done(handle, buf, size);
4195 			free(buf);
4196 			return ret;
4197 
4198 		default:
4199 			tracecmd_warning("unknown option %d", option);
4200 			break;
4201 		}
4202 
4203 		free(buf);
4204 
4205 	}
4206 
4207 	ret = 0;
4208 
4209 out:
4210 	if (compress)
4211 		in_uncompress_reset(handle);
4212 	return ret;
4213 }
4214 
read_options_type(struct tracecmd_input * handle)4215 static int read_options_type(struct tracecmd_input *handle)
4216 {
4217 	char buf[10];
4218 
4219 	if (CHECK_READ_STATE(handle, TRACECMD_FILE_CPU_LATENCY))
4220 		return 0;
4221 
4222 	if (do_read_check(handle, buf, 10))
4223 		return -1;
4224 
4225 	/* check if this handles options */
4226 	if (strncmp(buf, "options", 7) == 0) {
4227 		if (handle_options(handle) < 0)
4228 			return -1;
4229 		handle->file_state = TRACECMD_FILE_OPTIONS;
4230 		if (do_read_check(handle, buf, 10))
4231 			return -1;
4232 	}
4233 
4234 	/*
4235 	 * Check if this is a latency report or flyrecord.
4236 	 */
4237 	if (strncmp(buf, "latency", 7) == 0)
4238 		handle->file_state = TRACECMD_FILE_CPU_LATENCY;
4239 	else if (strncmp(buf, "flyrecord", 9) == 0)
4240 		handle->file_state = TRACECMD_FILE_CPU_FLYRECORD;
4241 	else
4242 		return -1;
4243 
4244 	return 0;
4245 }
4246 
tracecmd_latency_data_read(struct tracecmd_input * handle,char ** buf,size_t * size)4247 int tracecmd_latency_data_read(struct tracecmd_input *handle, char **buf, size_t *size)
4248 {
4249 	struct cpu_zdata *zdata = &handle->latz;
4250 	void *data;
4251 	int rsize;
4252 	int fd = -1;
4253 	int id;
4254 
4255 	if (!handle || !buf || !size)
4256 		return -1;
4257 	if (handle->file_state != TRACECMD_FILE_CPU_LATENCY)
4258 		return -1;
4259 
4260 	if (!handle->cpu_compressed) {
4261 		fd = handle->fd;
4262 	} else if (!handle->read_zpage) {
4263 		if (zdata->fd < 0)
4264 			return -1;
4265 		fd = zdata->fd;
4266 	}
4267 
4268 	/* Read data from a file */
4269 	if (fd >= 0) {
4270 		if (!(*buf)) {
4271 			*size = BUFSIZ;
4272 			*buf = malloc(*size);
4273 			if (!(*buf))
4274 				return -1;
4275 		}
4276 		return do_read_fd(fd, *buf, *size);
4277 	}
4278 
4279 	/* Uncompress data in memory */
4280 	if (zdata->last_chunk >= zdata->count)
4281 		return 0;
4282 
4283 	id = zdata->last_chunk;
4284 	if (!*buf || *size < zdata->chunks[id].size) {
4285 		data = realloc(*buf, zdata->chunks[id].size);
4286 		if (!data)
4287 			return -1;
4288 		*buf = data;
4289 		*size = zdata->chunks[id].size;
4290 	}
4291 
4292 	if (tracecmd_uncompress_chunk(handle->compress, &zdata->chunks[id], *buf))
4293 		return -1;
4294 
4295 	rsize = zdata->chunks[id].size;
4296 	zdata->last_chunk++;
4297 	return rsize;
4298 }
4299 
init_cpu_data(struct tracecmd_input * handle)4300 static int init_cpu_data(struct tracecmd_input *handle)
4301 {
4302 	enum kbuffer_long_size long_size;
4303 	enum kbuffer_endian endian;
4304 	unsigned long long max_size = 0;
4305 	unsigned long long pages;
4306 	int cpu;
4307 
4308 	/* We expect this to be flyrecord */
4309 	if (handle->file_state != TRACECMD_FILE_CPU_FLYRECORD)
4310 		return -1;
4311 
4312 	if (force_read)
4313 		handle->read_page = true;
4314 
4315 	if (handle->long_size == 8)
4316 		long_size = KBUFFER_LSIZE_8;
4317 	else
4318 		long_size = KBUFFER_LSIZE_4;
4319 
4320 	if (tep_is_file_bigendian(handle->pevent))
4321 		endian = KBUFFER_ENDIAN_BIG;
4322 	else
4323 		endian = KBUFFER_ENDIAN_LITTLE;
4324 
4325 	for (cpu = 0; cpu < handle->cpus; cpu++) {
4326 		handle->cpu_data[cpu].compress.fd = -1;
4327 		handle->cpu_data[cpu].kbuf = kbuffer_alloc(long_size, endian);
4328 		if (!handle->cpu_data[cpu].kbuf)
4329 			goto out_free;
4330 		if (tep_is_old_format(handle->pevent))
4331 			kbuffer_set_old_format(handle->cpu_data[cpu].kbuf);
4332 
4333 		if (handle->cpu_data[cpu].file_size > max_size)
4334 			max_size = handle->cpu_data[cpu].file_size;
4335 	}
4336 
4337 	/* Calculate about a meg of pages for buffering */
4338 	pages = handle->page_size ? max_size / handle->page_size : 0;
4339 	if (!pages)
4340 		pages = 1;
4341 	pages = normalize_size(pages);
4342 	handle->page_map_size = handle->page_size * pages;
4343 	if (handle->page_map_size < handle->page_size)
4344 		handle->page_map_size = handle->page_size;
4345 
4346 
4347 	for (cpu = 0; cpu < handle->cpus; cpu++) {
4348 		if (init_cpu(handle, cpu))
4349 			goto out_free;
4350 	}
4351 
4352 	return 0;
4353 
4354  out_free:
4355 	for ( ; cpu >= 0; cpu--) {
4356 		free_page(handle, cpu);
4357 		kbuffer_free(handle->cpu_data[cpu].kbuf);
4358 		handle->cpu_data[cpu].kbuf = NULL;
4359 	}
4360 	return -1;
4361 }
4362 
init_latency_data(struct tracecmd_input * handle)4363 int init_latency_data(struct tracecmd_input *handle)
4364 {
4365 	size_t wsize;
4366 	int ret;
4367 
4368 	if (!handle->cpu_compressed)
4369 		return 0;
4370 
4371 	if (handle->read_zpage) {
4372 		handle->latz.count = tracecmd_load_chunks_info(handle->compress, &handle->latz.chunks);
4373 		if (handle->latz.count < 0)
4374 			return -1;
4375 	} else {
4376 		strcpy(handle->latz.file, COMPR_TEMP_FILE);
4377 		handle->latz.fd = mkstemp(handle->latz.file);
4378 		if (handle->latz.fd < 0)
4379 			return -1;
4380 
4381 		ret = tracecmd_uncompress_copy_to(handle->compress, handle->latz.fd, NULL, &wsize);
4382 		if (ret)
4383 			return -1;
4384 
4385 		lseek(handle->latz.fd, 0, SEEK_SET);
4386 	}
4387 
4388 	return 0;
4389 }
4390 
init_buffer_cpu_data(struct tracecmd_input * handle,struct input_buffer_instance * buffer)4391 static int init_buffer_cpu_data(struct tracecmd_input *handle, struct input_buffer_instance *buffer)
4392 {
4393 	unsigned long long offset;
4394 	unsigned long long size;
4395 	unsigned short id, flags;
4396 	int cpu;
4397 
4398 	if (handle->cpu_data)
4399 		return -1;
4400 
4401 	if (lseek(handle->fd, buffer->offset, SEEK_SET) == (off_t)-1)
4402 		return -1;
4403 	if (read_section_header(handle, &id, &flags, NULL, NULL))
4404 		return -1;
4405 	if (flags & TRACECMD_SEC_FL_COMPRESS)
4406 		handle->cpu_compressed = true;
4407 	if (buffer->latency) {
4408 		handle->file_state = TRACECMD_FILE_CPU_LATENCY;
4409 		return init_latency_data(handle) == 0 ? 1 : -1;
4410 	}
4411 	handle->file_state = TRACECMD_FILE_CPU_FLYRECORD;
4412 	handle->cpus = buffer->cpus;
4413 	if (handle->max_cpu < handle->cpus)
4414 		handle->max_cpu = handle->cpus;
4415 
4416 	handle->cpu_data = calloc(handle->cpus, sizeof(*handle->cpu_data));
4417 	if (!handle->cpu_data)
4418 		return -1;
4419 
4420 	for (cpu = 0; cpu < handle->cpus; cpu++) {
4421 		handle->cpu_data[cpu].cpu = buffer->cpu_data[cpu].cpu;
4422 		offset = buffer->cpu_data[cpu].offset;
4423 		size = buffer->cpu_data[cpu].size;
4424 		handle->cpu_data[cpu].file_offset = offset;
4425 		handle->cpu_data[cpu].file_size = size;
4426 		if (size && (offset + size > handle->total_file_size)) {
4427 			/* this happens if the file got truncated */
4428 			printf("File possibly truncated. "
4429 				"Need at least %llu, but file size is %zu.\n",
4430 				offset + size, handle->total_file_size);
4431 			errno = EINVAL;
4432 			return -1;
4433 		}
4434 	}
4435 
4436 	return init_cpu_data(handle);
4437 }
4438 
read_cpu_data(struct tracecmd_input * handle)4439 static int read_cpu_data(struct tracecmd_input *handle)
4440 {
4441 	unsigned long long size;
4442 	int cpus;
4443 	int cpu;
4444 
4445 	/*
4446 	 * Check if this is a latency report or not.
4447 	 */
4448 	if (handle->file_state == TRACECMD_FILE_CPU_LATENCY)
4449 		return 1;
4450 
4451 	/* We expect this to be flyrecord */
4452 	if (handle->file_state != TRACECMD_FILE_CPU_FLYRECORD)
4453 		return -1;
4454 
4455 	cpus = handle->cpus;
4456 
4457 	handle->cpu_data = malloc(sizeof(*handle->cpu_data) * handle->cpus);
4458 	if (!handle->cpu_data)
4459 		return -1;
4460 	memset(handle->cpu_data, 0, sizeof(*handle->cpu_data) * handle->cpus);
4461 
4462 	for (cpu = 0; cpu < handle->cpus; cpu++) {
4463 		unsigned long long offset;
4464 
4465 		handle->cpu_data[cpu].cpu = cpu;
4466 		read8(handle, &offset);
4467 		read8(handle, &size);
4468 		handle->cpu_data[cpu].file_offset = offset;
4469 		handle->cpu_data[cpu].file_size = size;
4470 		if (size && (offset + size > handle->total_file_size)) {
4471 			/* this happens if the file got truncated */
4472 			printf("File possibly truncated. "
4473 				"Need at least %llu, but file size is %zu.\n",
4474 				offset + size, handle->total_file_size);
4475 			errno = EINVAL;
4476 			return -1;
4477 		}
4478 	}
4479 
4480 	/*
4481 	 * It is possible that an option changed the number of CPUs.
4482 	 * If that happened, then there's "empty" cpu data saved for
4483 	 * backward compatibility.
4484 	 */
4485 	if (cpus < handle->cpus) {
4486 		unsigned long long ignore;
4487 		int once = 0;
4488 
4489 		read8(handle, &ignore); /* offset */
4490 		read8(handle, &ignore); /* size */
4491 		if (ignore != 0) {
4492 			if (!once) {
4493 				tracecmd_warning("ignored CPU data not zero size");
4494 				once++;
4495 			}
4496 		}
4497 	}
4498 
4499 	return init_cpu_data(handle);
4500 }
4501 
read_data_and_size(struct tracecmd_input * handle,char ** data,unsigned long long * size)4502 static int read_data_and_size(struct tracecmd_input *handle,
4503 				     char **data, unsigned long long *size)
4504 {
4505 	if (read8(handle, size) < 0)
4506 		return -1;
4507 	*data = malloc(*size + 1);
4508 	if (!*data)
4509 		return -1;
4510 	if (do_read_check(handle, *data, *size)) {
4511 		free(*data);
4512 		return -1;
4513 	}
4514 
4515 	return 0;
4516 }
4517 
read_and_parse_cmdlines(struct tracecmd_input * handle)4518 static int read_and_parse_cmdlines(struct tracecmd_input *handle)
4519 {
4520 	struct tep_handle *pevent = handle->pevent;
4521 	unsigned long long size;
4522 	char *cmdlines;
4523 
4524 	if (CHECK_READ_STATE(handle, TRACECMD_FILE_CMD_LINES))
4525 		return 0;
4526 
4527 	if (!HAS_SECTIONS(handle))
4528 		section_add_or_update(handle, TRACECMD_OPTION_CMDLINES, 0, 0,
4529 				      lseek(handle->fd, 0, SEEK_CUR));
4530 
4531 
4532 	if (read_data_and_size(handle, &cmdlines, &size) < 0)
4533 		return -1;
4534 	cmdlines[size] = 0;
4535 	tep_parse_saved_cmdlines(pevent, cmdlines);
4536 	free(cmdlines);
4537 
4538 	handle->file_state = TRACECMD_FILE_CMD_LINES;
4539 
4540 	return 0;
4541 }
4542 
extract_trace_clock(struct tracecmd_input * handle,char * line)4543 static void extract_trace_clock(struct tracecmd_input *handle, char *line)
4544 {
4545 	char *clock = NULL;
4546 	char *next = NULL;
4547 	char *data;
4548 
4549 	data = strtok_r(line, "[]", &next);
4550 	sscanf(data, "%ms", &clock);
4551 	/* TODO: report if it fails to allocate */
4552 	handle->trace_clock = clock;
4553 
4554 	if (!clock)
4555 		return;
4556 
4557 	/* Clear usecs if raw timestamps are requested */
4558 	if (handle->flags & TRACECMD_FL_RAW_TS)
4559 		handle->flags &= ~TRACECMD_FL_IN_USECS;
4560 
4561 	/* tsc_calc is a conversion to nanoseconds */
4562 	if (handle->tsc_calc.mult)
4563 		return;
4564 
4565 	/* Clear usecs if not one of the specified clocks */
4566 	if (strcmp(clock, "local") && strcmp(clock, "global") &&
4567 	    strcmp(clock, "uptime") && strcmp(clock, "perf") &&
4568 	    strncmp(clock, "mono", 4) && strcmp(clock, TSCNSEC_CLOCK) &&
4569 	    strcmp(clock, "tai"))
4570 		handle->flags &= ~TRACECMD_FL_IN_USECS;
4571 }
4572 
tracecmd_parse_trace_clock(struct tracecmd_input * handle,char * file,int size __maybe_unused)4573 void tracecmd_parse_trace_clock(struct tracecmd_input *handle,
4574 				char *file, int size __maybe_unused)
4575 {
4576 	char *line;
4577 	char *next = NULL;
4578 
4579 	line = strtok_r(file, " ", &next);
4580 	while (line) {
4581 		/* current trace_clock is shown as "[local]". */
4582 		if (*line == '[')
4583 			return extract_trace_clock(handle, line);
4584 		line = strtok_r(NULL, " ", &next);
4585 	}
4586 }
4587 
read_and_parse_trace_clock(struct tracecmd_input * handle,struct tep_handle * pevent)4588 static int read_and_parse_trace_clock(struct tracecmd_input *handle,
4589 							struct tep_handle *pevent)
4590 {
4591 	unsigned long long size;
4592 	char *trace_clock;
4593 
4594 	if (read_data_and_size(handle, &trace_clock, &size) < 0)
4595 		return -1;
4596 	trace_clock[size] = 0;
4597 	tracecmd_parse_trace_clock(handle, trace_clock, size);
4598 	free(trace_clock);
4599 	return 0;
4600 }
4601 
init_data_v6(struct tracecmd_input * handle)4602 static int init_data_v6(struct tracecmd_input *handle)
4603 {
4604 	struct tep_handle *pevent = handle->pevent;
4605 	int ret;
4606 
4607 	ret = read_cpu_data(handle);
4608 	if (ret < 0)
4609 		return ret;
4610 
4611 	if (handle->use_trace_clock) {
4612 		/*
4613 		 * There was a bug in the original setting of
4614 		 * the trace_clock file which let it get
4615 		 * corrupted. If it fails to read, force local
4616 		 * clock.
4617 		 */
4618 		if (read_and_parse_trace_clock(handle, pevent) < 0) {
4619 			char clock[] = "[local]";
4620 			tracecmd_warning("File has trace_clock bug, using local clock");
4621 			tracecmd_parse_trace_clock(handle, clock, 8);
4622 		}
4623 	}
4624 	return ret;
4625 }
4626 
init_data(struct tracecmd_input * handle)4627 static int init_data(struct tracecmd_input *handle)
4628 {
4629 	return init_buffer_cpu_data(handle, &handle->top_buffer);
4630 }
4631 
4632 /**
4633  * tracecmd_init_data - prepare reading the data from trace.dat
4634  * @handle: input handle for the trace.dat file
4635  *
4636  * This prepares reading the data from trace.dat. This is called
4637  * after tracecmd_read_headers() and before tracecmd_read_data().
4638  */
tracecmd_init_data(struct tracecmd_input * handle)4639 int tracecmd_init_data(struct tracecmd_input *handle)
4640 {
4641 	int ret;
4642 
4643 	if (!HAS_SECTIONS(handle))
4644 		ret = init_data_v6(handle);
4645 	else
4646 		ret = init_data(handle);
4647 	tracecmd_blk_hack(handle);
4648 
4649 	return ret;
4650 }
4651 
4652 /**
4653  * tracecmd_make_pipe - Have the handle read a pipe instead of a file
4654  * @handle: input handle to read from a pipe
4655  * @cpu: the cpu that the pipe represents
4656  * @fd: the read end of the pipe
4657  * @cpus: the total number of cpus for this handle
4658  *
4659  * In order to stream data from the binary trace files and produce
4660  * output or analyze the data, a tracecmd_input descriptor needs to
4661  * be created, and then converted into a form that can act on a
4662  * pipe.
4663  *
4664  * Note, there are limitations to what this descriptor can do.
4665  * Most notibly, it can not read backwards. Once a page is read
4666  * it can not be read at a later time (except if a record is attached
4667  * to it and is holding the page ref).
4668  *
4669  * It is expected that the handle has already been created and
4670  * tracecmd_read_headers() has run on it.
4671  */
tracecmd_make_pipe(struct tracecmd_input * handle,int cpu,int fd,int cpus)4672 int tracecmd_make_pipe(struct tracecmd_input *handle, int cpu, int fd, int cpus)
4673 {
4674 	enum kbuffer_long_size long_size;
4675 	enum kbuffer_endian endian;
4676 
4677 	handle->read_page = true;
4678 	handle->use_pipe = true;
4679 
4680 	if (!handle->cpus) {
4681 		handle->cpus = cpus;
4682 		handle->cpu_data = malloc(sizeof(*handle->cpu_data) * handle->cpus);
4683 		if (!handle->cpu_data)
4684 			return -1;
4685 	}
4686 
4687 	if (cpu >= handle->cpus)
4688 		return -1;
4689 
4690 
4691 	if (handle->long_size == 8)
4692 		long_size = KBUFFER_LSIZE_8;
4693 	else
4694 		long_size = KBUFFER_LSIZE_4;
4695 
4696 	if (tep_is_file_bigendian(handle->pevent))
4697 		endian = KBUFFER_ENDIAN_BIG;
4698 	else
4699 		endian = KBUFFER_ENDIAN_LITTLE;
4700 
4701 	memset(&handle->cpu_data[cpu], 0, sizeof(handle->cpu_data[cpu]));
4702 	handle->cpu_data[cpu].pipe_fd = fd;
4703 	handle->cpu_data[cpu].cpu = cpu;
4704 
4705 	handle->cpu_data[cpu].kbuf = kbuffer_alloc(long_size, endian);
4706 	if (!handle->cpu_data[cpu].kbuf)
4707 		return -1;
4708 	if (tep_is_old_format(handle->pevent))
4709 		kbuffer_set_old_format(handle->cpu_data[cpu].kbuf);
4710 
4711 	handle->cpu_data[cpu].file_offset = 0;
4712 	handle->cpu_data[cpu].file_size = -1;
4713 
4714 	init_cpu(handle, cpu);
4715 
4716 	return 0;
4717 }
4718 
4719 /**
4720  * tracecmd_print_events - print the events that are stored in trace.dat
4721  * @handle: input handle for the trace.dat file
4722  * @regex: regex of events to print (NULL is all events)
4723  *
4724  * This is a debugging routine to print out the events that
4725  * are stored in a given trace.dat file.
4726  */
tracecmd_print_events(struct tracecmd_input * handle,const char * regex)4727 void tracecmd_print_events(struct tracecmd_input *handle, const char *regex)
4728 {
4729 	if (!regex)
4730 		regex = ".*";
4731 
4732 	if (!HAS_SECTIONS(handle))
4733 		read_headers_v6(handle, TRACECMD_FILE_ALL_EVENTS, regex);
4734 
4735 	read_headers(handle, regex);
4736 }
4737 
4738 /* Show the cpu data stats */
show_cpu_stats(struct tracecmd_input * handle)4739 static void show_cpu_stats(struct tracecmd_input *handle)
4740 {
4741 	struct cpu_data *cpu_data;
4742 	int i;
4743 
4744 	for (i = 0; i < handle->cpus; i++) {
4745 		cpu_data = &handle->cpu_data[i];
4746 		printf("CPU%d data recorded at offset=0x%llx\n",
4747 		       i, cpu_data->file_offset);
4748 		printf("    %lld bytes in size\n", cpu_data->file_size);
4749 	}
4750 }
4751 
4752 /**
4753  * tracecmd_print_stats - prints the stats recorded in the options.
4754  * @handle: input handle for the trace.dat file
4755  *
4756  * Looks for the option TRACECMD_OPTION_CPUSTAT and prints out what's
4757  * stored there, if it is found. Otherwise it prints that none were found.
4758  */
tracecmd_print_stats(struct tracecmd_input * handle)4759 void tracecmd_print_stats(struct tracecmd_input *handle)
4760 {
4761 	if (handle->cpustats)
4762 		printf("%s\n", handle->cpustats);
4763 	else
4764 		printf(" No stats in this file\n");
4765 
4766 	show_cpu_stats(handle);
4767 }
4768 
4769 /**
4770  * tracecmd_print_uname - prints the recorded uname if it was recorded
4771  * @handle: input handle for the trace.dat file
4772  *
4773  * Looks for the option TRACECMD_OPTION_UNAME and prints out what's
4774  * stored there, if it is found. Otherwise it prints that none were found.
4775  */
tracecmd_print_uname(struct tracecmd_input * handle)4776 void tracecmd_print_uname(struct tracecmd_input *handle)
4777 {
4778 	if (handle->uname)
4779 		printf("%s\n", handle->uname);
4780 	else
4781 		printf(" uname was not recorded in this file\n");
4782 }
4783 
4784 /**
4785  * tracecmd_print_uname - prints the recorded uname if it was recorded
4786  * @handle: input handle for the trace.dat file
4787  *
4788  * Looks for the option TRACECMD_OPTION_VERSION and prints out what's
4789  * stored there, if it is found. Otherwise it prints that none were found.
4790  */
tracecmd_print_version(struct tracecmd_input * handle)4791 void tracecmd_print_version(struct tracecmd_input *handle)
4792 {
4793 	if (handle->version)
4794 		printf("%s\n", handle->version);
4795 	else
4796 		printf(" version was not recorded in this file\n");
4797 }
4798 
4799 /**
4800  * tracecmd_hooks - return the event hooks that were used in record
4801  * @handle: input handle for the trace.dat file
4802  *
4803  * If trace-cmd record used -H to save hooks, they are parsed and
4804  * presented as hooks here.
4805  *
4806  * Returns the hook list (do not free it, they are freed on close)
4807  */
tracecmd_hooks(struct tracecmd_input * handle)4808 struct hook_list *tracecmd_hooks(struct tracecmd_input *handle)
4809 {
4810 	return handle->hooks;
4811 }
4812 
init_metadata_strings(struct tracecmd_input * handle,int size)4813 static int init_metadata_strings(struct tracecmd_input *handle, int size)
4814 {
4815 	char *tmp;
4816 
4817 	tmp = realloc(handle->strings, handle->strings_size + size);
4818 	if (!tmp)
4819 		return -1;
4820 
4821 	handle->strings = tmp;
4822 	if (do_read_check(handle, handle->strings + handle->strings_size, size))
4823 		return -1;
4824 
4825 	handle->strings_size += size;
4826 
4827 	return 0;
4828 }
4829 
read_metadata_strings(struct tracecmd_input * handle)4830 static int read_metadata_strings(struct tracecmd_input *handle)
4831 {
4832 	unsigned short flags;
4833 	int found = 0;
4834 	unsigned short id;
4835 	unsigned int csize, rsize;
4836 	unsigned long long size;
4837 	off_t offset;
4838 
4839 	offset = lseek(handle->fd, 0, SEEK_CUR);
4840 	do {
4841 		if (read_section_header(handle, &id, &flags, &size, NULL))
4842 			break;
4843 		if (id == TRACECMD_OPTION_STRINGS) {
4844 			found++;
4845 			if ((flags & TRACECMD_SEC_FL_COMPRESS)) {
4846 				read4(handle, &csize);
4847 				read4(handle, &rsize);
4848 				do_lseek(handle, -8, SEEK_CUR);
4849 				if (in_uncompress_block(handle))
4850 					break;
4851 			} else {
4852 				rsize = size;
4853 			}
4854 			init_metadata_strings(handle, rsize);
4855 			if (flags & TRACECMD_SEC_FL_COMPRESS)
4856 				in_uncompress_reset(handle);
4857 		} else {
4858 			if (lseek(handle->fd, size, SEEK_CUR) == (off_t)-1)
4859 				break;
4860 		}
4861 	} while (1);
4862 
4863 	if (lseek(handle->fd, offset, SEEK_SET) == (off_t)-1)
4864 		return -1;
4865 
4866 	return found ? 0 : -1;
4867 }
4868 
4869 /**
4870  * tracecmd_alloc_fd - create a tracecmd_input handle from a file descriptor
4871  * @fd: the file descriptor for the trace.dat file
4872  * @flags: bitmask of enum tracecmd_open_flags
4873  *
4874  * Allocate a tracecmd_input handle from a file descriptor and open the
4875  * file. This tests if the file is of trace-cmd format and allocates
4876  * a parse event descriptor.
4877  *
4878  * The returned pointer is not ready to be read yet. A tracecmd_read_headers()
4879  * and tracecmd_init_data() still need to be called on the descriptor.
4880  *
4881  * Unless you know what you are doing with this, you want to use
4882  * tracecmd_open_fd() instead.
4883  */
tracecmd_alloc_fd(int fd,int flags)4884 struct tracecmd_input *tracecmd_alloc_fd(int fd, int flags)
4885 {
4886 	struct tracecmd_input *handle;
4887 	char test[] = TRACECMD_MAGIC;
4888 	unsigned int page_size;
4889 	size_t offset;
4890 	char *version = NULL;
4891 	char *zver = NULL;
4892 	char *zname = NULL;
4893 	char buf[BUFSIZ];
4894 	unsigned long ver;
4895 
4896 	handle = malloc(sizeof(*handle));
4897 	if (!handle)
4898 		return NULL;
4899 	memset(handle, 0, sizeof(*handle));
4900 
4901 	handle->fd = fd;
4902 	handle->ref = 1;
4903 	handle->latz.fd = -1;
4904 	/* By default, use usecs, unless told otherwise */
4905 	handle->flags |= TRACECMD_FL_IN_USECS;
4906 
4907 #ifdef INMEMORY_DECOMPRESS
4908 	handle->read_zpage = 1;
4909 #endif
4910 	if (do_read_check(handle, buf, 3))
4911 		goto failed_read;
4912 
4913 	if (memcmp(buf, test, 3) != 0)
4914 		goto failed_read;
4915 
4916 	if (do_read_check(handle, buf, 7))
4917 		goto failed_read;
4918 	if (memcmp(buf, "tracing", 7) != 0)
4919 		goto failed_read;
4920 
4921 	version = read_string(handle);
4922 	if (!version)
4923 		goto failed_read;
4924 	tracecmd_info("version = %s", version);
4925 	ver = strtol(version, NULL, 10);
4926 	if (!ver && errno)
4927 		goto failed_read;
4928 	if (!tracecmd_is_version_supported(ver)) {
4929 		tracecmd_warning("Unsupported file version %lu", ver);
4930 		goto failed_read;
4931 	}
4932 	handle->file_version = ver;
4933 	free(version);
4934 	version = NULL;
4935 
4936 	if (handle->file_version >= FILE_VERSION_SECTIONS)
4937 		handle->flags |= TRACECMD_FL_SECTIONED;
4938 	if (handle->file_version >= FILE_VERSION_COMPRESSION)
4939 		handle->flags |= TRACECMD_FL_COMPRESSION;
4940 
4941 	if (do_read_check(handle, buf, 1))
4942 		goto failed_read;
4943 
4944 	handle->pevent = tep_alloc();
4945 	if (!handle->pevent)
4946 		goto failed_read;
4947 
4948 	/* register default ftrace functions first */
4949 	if (!(flags & TRACECMD_FL_LOAD_NO_PLUGINS) &&
4950 	    !(flags & TRACECMD_FL_LOAD_NO_SYSTEM_PLUGINS))
4951 		tracecmd_ftrace_overrides(handle, &handle->finfo);
4952 
4953 	handle->plugin_list = trace_load_plugins(handle->pevent, flags);
4954 
4955 	tep_set_file_bigendian(handle->pevent, buf[0]);
4956 	tep_set_local_bigendian(handle->pevent, tracecmd_host_bigendian());
4957 
4958 	do_read_check(handle, buf, 1);
4959 	handle->long_size = buf[0];
4960 	tep_set_long_size(handle->pevent, handle->long_size);
4961 
4962 	read4(handle, &page_size);
4963 	handle->page_size = page_size;
4964 	handle->next_offset = page_size;
4965 
4966 	offset = lseek(handle->fd, 0, SEEK_CUR);
4967 	handle->total_file_size = lseek(handle->fd, 0, SEEK_END);
4968 	lseek(handle->fd, offset, SEEK_SET);
4969 
4970 	if (HAS_COMPRESSION(handle)) {
4971 		zname = read_string(handle);
4972 		if (!zname)
4973 			goto failed_read;
4974 
4975 		zver = read_string(handle);
4976 		if (!zver)
4977 			goto failed_read;
4978 
4979 		if (strcmp(zname, "none") == 0) {
4980 			handle->read_zpage = false;
4981 			handle->flags &= ~TRACECMD_FL_COMPRESSION;
4982 		} else {
4983 			handle->compress = tracecmd_compress_alloc(zname, zver,
4984 								   handle->fd,
4985 								   handle->pevent, NULL);
4986 			if (!handle->compress) {
4987 				tracecmd_warning("Unsupported file compression %s %s", zname, zver);
4988 				goto failed_read;
4989 			}
4990 		}
4991 
4992 		free(zname);
4993 		free(zver);
4994 	}
4995 
4996 	if (HAS_SECTIONS(handle)) {
4997 		if (read8(handle, &(handle->options_start))) {
4998 			tracecmd_warning("Filed to read the offset of the first option section");
4999 			goto failed_read;
5000 		}
5001 		read_metadata_strings(handle);
5002 	}
5003 
5004 	handle->file_state = TRACECMD_FILE_INIT;
5005 
5006 	return handle;
5007 
5008  failed_read:
5009 	free(version);
5010 	free(zname);
5011 	free(zver);
5012 	free(handle);
5013 
5014 	return NULL;
5015 }
5016 
5017 /**
5018  * tracecmd_alloc_fd - create a tracecmd_input handle from a file name
5019  * @file: the file name of the file that is of tracecmd data type.
5020  * @flags: bitmask of enum tracecmd_open_flags
5021  *
5022  * Allocate a tracecmd_input handle from a given file name and open the
5023  * file. This tests if the file is of trace-cmd format and allocates
5024  * a parse event descriptor.
5025  *
5026  * The returned pointer is not ready to be read yet. A tracecmd_read_headers()
5027  * and tracecmd_init_data() still need to be called on the descriptor.
5028  *
5029  * Unless you know what you are doing with this, you want to use
5030  * tracecmd_open() instead.
5031  */
tracecmd_alloc(const char * file,int flags)5032 struct tracecmd_input *tracecmd_alloc(const char *file, int flags)
5033 {
5034 	int fd;
5035 
5036 	fd = open(file, O_RDONLY);
5037 	if (fd < 0)
5038 		return NULL;
5039 
5040 	return tracecmd_alloc_fd(fd, flags);
5041 }
5042 
5043 /**
5044  * tracecmd_open_fd - create a tracecmd_handle from the trace.dat file descriptor
5045  * @fd: the file descriptor for the trace.dat file
5046  * @flags: bitmask of enum tracecmd_open_flags
5047  */
tracecmd_open_fd(int fd,int flags)5048 struct tracecmd_input *tracecmd_open_fd(int fd, int flags)
5049 {
5050 	struct tracecmd_input *handle;
5051 	int ret;
5052 
5053 	handle = tracecmd_alloc_fd(fd, flags);
5054 	if (!handle)
5055 		return NULL;
5056 
5057 	if (tracecmd_read_headers(handle, 0) < 0)
5058 		goto fail;
5059 
5060 	if ((ret = tracecmd_init_data(handle)) < 0)
5061 		goto fail;
5062 
5063 	return handle;
5064 
5065 fail:
5066 	tracecmd_close(handle);
5067 	return NULL;
5068 }
5069 
5070 /**
5071  * tracecmd_open - create a tracecmd_handle from a given file
5072  * @file: the file name of the file that is of tracecmd data type.
5073  * @flags: bitmask of enum tracecmd_open_flags
5074  */
tracecmd_open(const char * file,int flags)5075 struct tracecmd_input *tracecmd_open(const char *file, int flags)
5076 {
5077 	int fd;
5078 
5079 	fd = open(file, O_RDONLY);
5080 	if (fd < 0)
5081 		return NULL;
5082 
5083 	return tracecmd_open_fd(fd, flags);
5084 }
5085 
5086 /**
5087  * tracecmd_open_head - create a tracecmd_handle from a given file, read
5088  *			and parse only the trace headers from the file
5089  * @file: the file name of the file that is of tracecmd data type.
5090  * @flags: bitmask of enum tracecmd_open_flags
5091  */
tracecmd_open_head(const char * file,int flags)5092 struct tracecmd_input *tracecmd_open_head(const char *file, int flags)
5093 {
5094 	struct tracecmd_input *handle;
5095 	int fd;
5096 
5097 	fd = open(file, O_RDONLY);
5098 	if (fd < 0)
5099 		return NULL;
5100 
5101 	handle = tracecmd_alloc_fd(fd, flags);
5102 	if (!handle)
5103 		return NULL;
5104 
5105 	if (tracecmd_read_headers(handle, 0) < 0)
5106 		goto fail;
5107 
5108 	return handle;
5109 
5110 fail:
5111 	tracecmd_close(handle);
5112 	return NULL;
5113 }
5114 
5115 /**
5116  * tracecmd_ref - add a reference to the handle
5117  * @handle: input handle for the trace.dat file
5118  *
5119  * Some applications may share a handle between parts of
5120  * the application. Let those parts add reference counters
5121  * to the handle, and the last one to close it will free it.
5122  */
tracecmd_ref(struct tracecmd_input * handle)5123 void tracecmd_ref(struct tracecmd_input *handle)
5124 {
5125 	if (!handle)
5126 		return;
5127 
5128 	handle->ref++;
5129 }
5130 
free_buffer(struct input_buffer_instance * buf)5131 static inline void free_buffer(struct input_buffer_instance *buf)
5132 {
5133 	free(buf->name);
5134 	free(buf->clock);
5135 	free(buf->cpu_data);
5136 }
5137 
5138 /**
5139  * tracecmd_close - close and free the trace.dat handle
5140  * @handle: input handle for the trace.dat file
5141  *
5142  * Close the file descriptor of the handle and frees
5143  * the resources allocated by the handle.
5144  */
tracecmd_close(struct tracecmd_input * handle)5145 void tracecmd_close(struct tracecmd_input *handle)
5146 {
5147 	struct zchunk_cache *cache;
5148 	struct file_section *del_sec;
5149 	struct cpu_data *cpu_data;
5150 	struct page_map *page_map, *n;
5151 	int cpu;
5152 	int i;
5153 
5154 	if (!handle)
5155 		return;
5156 
5157 	if (handle->ref <= 0) {
5158 		tracecmd_warning("tracecmd: bad ref count on handle");
5159 		return;
5160 	}
5161 
5162 	if (--handle->ref)
5163 		return;
5164 
5165 	for (cpu = 0; cpu < handle->cpus; cpu++) {
5166 		/* The tracecmd_peek_data may have cached a record */
5167 		free_next(handle, cpu);
5168 		free_page(handle, cpu);
5169 		if (handle->cpu_data) {
5170 			cpu_data = &handle->cpu_data[cpu];
5171 			if (cpu_data->kbuf) {
5172 				kbuffer_free(cpu_data->kbuf);
5173 				if (cpu_data->page_map)
5174 					free_page_map(cpu_data->page_map);
5175 
5176 				if (cpu_data->page_cnt)
5177 					tracecmd_warning("%d pages still allocated on cpu %d%s",
5178 							 cpu_data->page_cnt, cpu,
5179 							 show_records(cpu_data->pages,
5180 								      cpu_data->nr_pages));
5181 				free(cpu_data->pages);
5182 			}
5183 			if (cpu_data->compress.fd >= 0) {
5184 				close(cpu_data->compress.fd);
5185 				unlink(cpu_data->compress.file);
5186 			}
5187 			while (cpu_data->compress.cache.node) {
5188 				struct trace_rbtree_node *node;
5189 				node = trace_rbtree_pop_nobalance(&cpu_data->compress.cache);
5190 				cache = container_of(node, struct zchunk_cache, node);
5191 				free(cache->map);
5192 				free(cache);
5193 			}
5194 			free(cpu_data->compress.chunks);
5195 			list_for_each_entry_safe(page_map, n, &cpu_data->page_maps, list) {
5196 				list_del(&page_map->list);
5197 				free(page_map);
5198 			}
5199 		}
5200 	}
5201 
5202 	free(handle->cpustats);
5203 	free(handle->cpu_data);
5204 	free(handle->uname);
5205 	free(handle->trace_clock);
5206 	free(handle->strings);
5207 	free(handle->version);
5208 	free(handle->followers);
5209 	free(handle->missed_followers);
5210 	trace_guest_map_free(handle->map);
5211 	close(handle->fd);
5212 	free(handle->latz.chunks);
5213 	if (handle->latz.fd >= 0) {
5214 		close(handle->latz.fd);
5215 		unlink(handle->latz.file);
5216 	}
5217 	while (handle->sections) {
5218 		del_sec = handle->sections;
5219 		handle->sections = handle->sections->next;
5220 		free(del_sec);
5221 	}
5222 
5223 	free_buffer(&handle->top_buffer);
5224 	for (i = 0; i < handle->nr_buffers; i++)
5225 		free_buffer(&handle->buffers[i]);
5226 	free(handle->buffers);
5227 
5228 	tracecmd_free_hooks(handle->hooks);
5229 	handle->hooks = NULL;
5230 
5231 	trace_pid_map_free(handle->pid_maps);
5232 	handle->pid_maps = NULL;
5233 
5234 	trace_tsync_offset_free(&handle->host);
5235 	trace_guests_free(handle);
5236 
5237 	tracecmd_filter_free(handle->filter);
5238 
5239 	if (handle->flags & TRACECMD_FL_BUFFER_INSTANCE)
5240 		tracecmd_close(handle->parent);
5241 	else {
5242 		/* Only main handle frees plugins, pevent and compression context */
5243 		tracecmd_compress_destroy(handle->compress);
5244 		tep_unload_plugins(handle->plugin_list, handle->pevent);
5245 		tep_free(handle->pevent);
5246 	}
5247 	free(handle);
5248 }
5249 
read_copy_size8(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle,unsigned long long * size)5250 static int read_copy_size8(struct tracecmd_input *in_handle,
5251 			   struct tracecmd_output *out_handle, unsigned long long *size)
5252 {
5253 	/* read size */
5254 	if (do_read_check(in_handle, size, 8))
5255 		return -1;
5256 
5257 	if (do_write_check(out_handle, size, 8))
5258 		return -1;
5259 
5260 	*size = tep_read_number(in_handle->pevent, size, 8);
5261 	return 0;
5262 }
5263 
read_copy_size4(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle,unsigned int * size)5264 static int read_copy_size4(struct tracecmd_input *in_handle, struct tracecmd_output *out_handle,
5265 			   unsigned int *size)
5266 {
5267 	/* read size */
5268 	if (do_read_check(in_handle, size, 4))
5269 		return -1;
5270 
5271 	if (do_write_check(out_handle, size, 4))
5272 		return -1;
5273 
5274 	*size = tep_read_number(in_handle->pevent, size, 4);
5275 	return 0;
5276 }
5277 
read_copy_data(struct tracecmd_input * in_handle,unsigned long long size,struct tracecmd_output * out_handle)5278 static int read_copy_data(struct tracecmd_input *in_handle,
5279 			  unsigned long long size,
5280 			  struct tracecmd_output *out_handle)
5281 {
5282 	char *buf;
5283 
5284 	buf = malloc(size);
5285 	if (!buf)
5286 		return -1;
5287 	if (do_read_check(in_handle, buf, size))
5288 		goto failed_read;
5289 
5290 	if (do_write_check(out_handle, buf, size))
5291 		goto failed_read;
5292 
5293 	free(buf);
5294 
5295 	return 0;
5296 
5297  failed_read:
5298 	free(buf);
5299 	return -1;
5300 }
5301 
5302 
check_in_state(struct tracecmd_input * handle,int new_state)5303 static bool check_in_state(struct tracecmd_input *handle, int new_state)
5304 {
5305 	return check_file_state(handle->file_version, handle->file_state, new_state);
5306 }
5307 
copy_header_files(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle)5308 static int copy_header_files(struct tracecmd_input *in_handle,
5309 			     struct tracecmd_output *out_handle)
5310 {
5311 	bool compress = out_check_compression(out_handle);
5312 	struct file_section *sec;
5313 	unsigned long long offset;
5314 	unsigned long long size;
5315 
5316 	if (!check_in_state(in_handle, TRACECMD_FILE_HEADERS) ||
5317 	    !check_out_state(out_handle, TRACECMD_FILE_HEADERS))
5318 		return -1;
5319 
5320 	sec = section_open(in_handle, TRACECMD_OPTION_HEADER_INFO);
5321 	if (!sec)
5322 		return -1;
5323 
5324 	offset = out_write_section_header(out_handle, TRACECMD_OPTION_HEADER_INFO,
5325 					  "headers", TRACECMD_SEC_FL_COMPRESS, true);
5326 	out_compression_start(out_handle, compress);
5327 
5328 	/* "header_page"  */
5329 	if (read_copy_data(in_handle, 12, out_handle) < 0)
5330 		goto error;
5331 
5332 	if (read_copy_size8(in_handle, out_handle, &size) < 0)
5333 		goto error;
5334 
5335 	if (read_copy_data(in_handle, size, out_handle) < 0)
5336 		goto error;
5337 
5338 	/* "header_event"  */
5339 	if (read_copy_data(in_handle, 13, out_handle) < 0)
5340 		goto error;
5341 
5342 	if (read_copy_size8(in_handle, out_handle, &size) < 0)
5343 		goto error;
5344 
5345 	if (read_copy_data(in_handle, size, out_handle) < 0)
5346 		goto error;
5347 
5348 	in_handle->file_state = TRACECMD_FILE_HEADERS;
5349 	if (out_compression_end(out_handle, compress))
5350 		goto error;
5351 
5352 	out_set_file_state(out_handle, in_handle->file_state);
5353 	section_close(in_handle, sec);
5354 
5355 	if (out_update_section_header(out_handle, offset))
5356 		goto error;
5357 
5358 	return 0;
5359 error:
5360 	out_compression_reset(out_handle, compress);
5361 	section_close(in_handle, sec);
5362 	return -1;
5363 }
5364 
copy_ftrace_files(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle)5365 static int copy_ftrace_files(struct tracecmd_input *in_handle, struct tracecmd_output *out_handle)
5366 {
5367 	bool compress = out_check_compression(out_handle);
5368 	struct file_section *sec;
5369 	unsigned long long offset;
5370 	unsigned long long size;
5371 	unsigned int count;
5372 	unsigned int i;
5373 
5374 	if (!check_in_state(in_handle, TRACECMD_FILE_FTRACE_EVENTS) ||
5375 	    !check_out_state(out_handle, TRACECMD_FILE_FTRACE_EVENTS))
5376 		return -1;
5377 
5378 	sec = section_open(in_handle, TRACECMD_OPTION_FTRACE_EVENTS);
5379 	if (!sec)
5380 		return -1;
5381 	offset = out_write_section_header(out_handle, TRACECMD_OPTION_FTRACE_EVENTS,
5382 					  "ftrace events", TRACECMD_SEC_FL_COMPRESS, true);
5383 
5384 	out_compression_start(out_handle, compress);
5385 
5386 	if (read_copy_size4(in_handle, out_handle, &count) < 0)
5387 		goto error;
5388 
5389 	for (i = 0; i < count; i++) {
5390 
5391 		if (read_copy_size8(in_handle, out_handle, &size) < 0)
5392 			goto error;
5393 
5394 		if (read_copy_data(in_handle, size, out_handle) < 0)
5395 			goto error;
5396 	}
5397 
5398 	in_handle->file_state = TRACECMD_FILE_FTRACE_EVENTS;
5399 	if (out_compression_end(out_handle, compress))
5400 		goto error;
5401 
5402 	out_set_file_state(out_handle, in_handle->file_state);
5403 
5404 	section_close(in_handle, sec);
5405 
5406 	if (out_update_section_header(out_handle, offset))
5407 		goto error;
5408 
5409 	return 0;
5410 error:
5411 	out_compression_reset(out_handle, compress);
5412 	section_close(in_handle, sec);
5413 	return -1;
5414 }
5415 
copy_event_files(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle)5416 static int copy_event_files(struct tracecmd_input *in_handle, struct tracecmd_output *out_handle)
5417 {
5418 	bool compress = out_check_compression(out_handle);
5419 	struct file_section *sec;
5420 	unsigned long long offset;
5421 	unsigned long long size;
5422 	char *system;
5423 	unsigned int systems;
5424 	unsigned int count;
5425 	unsigned int i,x;
5426 
5427 	if (!check_in_state(in_handle, TRACECMD_FILE_ALL_EVENTS) ||
5428 	    !check_out_state(out_handle, TRACECMD_FILE_ALL_EVENTS))
5429 		return -1;
5430 
5431 	sec = section_open(in_handle, TRACECMD_OPTION_EVENT_FORMATS);
5432 	if (!sec)
5433 		return -1;
5434 	offset = out_write_section_header(out_handle, TRACECMD_OPTION_EVENT_FORMATS,
5435 					  "events format", TRACECMD_SEC_FL_COMPRESS, true);
5436 
5437 	out_compression_start(out_handle, compress);
5438 
5439 	if (read_copy_size4(in_handle, out_handle, &systems) < 0)
5440 		goto error;
5441 
5442 	for (i = 0; i < systems; i++) {
5443 		system = read_string(in_handle);
5444 		if (!system)
5445 			goto error;
5446 		if (do_write_check(out_handle, system, strlen(system) + 1)) {
5447 			free(system);
5448 			goto error;
5449 		}
5450 		free(system);
5451 
5452 		if (read_copy_size4(in_handle, out_handle, &count) < 0)
5453 			goto error;
5454 
5455 		for (x=0; x < count; x++) {
5456 			if (read_copy_size8(in_handle, out_handle, &size) < 0)
5457 				goto error;
5458 
5459 			if (read_copy_data(in_handle, size, out_handle) < 0)
5460 				goto error;
5461 		}
5462 	}
5463 
5464 	in_handle->file_state = TRACECMD_FILE_ALL_EVENTS;
5465 	if (out_compression_end(out_handle, compress))
5466 		goto error;
5467 
5468 	out_set_file_state(out_handle, in_handle->file_state);
5469 
5470 	section_close(in_handle, sec);
5471 
5472 	if (out_update_section_header(out_handle, offset))
5473 		goto error;
5474 
5475 	return 0;
5476 error:
5477 	out_compression_reset(out_handle, compress);
5478 	section_close(in_handle, sec);
5479 	return -1;
5480 }
5481 
copy_proc_kallsyms(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle)5482 static int copy_proc_kallsyms(struct tracecmd_input *in_handle, struct tracecmd_output *out_handle)
5483 {
5484 	bool compress = out_check_compression(out_handle);
5485 	struct file_section *sec;
5486 	unsigned long long offset;
5487 	unsigned int size;
5488 
5489 	if (!check_in_state(in_handle, TRACECMD_FILE_KALLSYMS) ||
5490 	    !check_out_state(out_handle, TRACECMD_FILE_KALLSYMS))
5491 		return -1;
5492 
5493 	sec = section_open(in_handle, TRACECMD_OPTION_KALLSYMS);
5494 	if (!sec)
5495 		return -1;
5496 	offset = out_write_section_header(out_handle, TRACECMD_OPTION_KALLSYMS,
5497 					  "kallsyms", TRACECMD_SEC_FL_COMPRESS, true);
5498 
5499 	out_compression_start(out_handle, compress);
5500 	if (read_copy_size4(in_handle, out_handle, &size) < 0)
5501 		goto error;
5502 
5503 	if (!size)
5504 		goto out; /* OK? */
5505 
5506 	if (read_copy_data(in_handle, size, out_handle) < 0)
5507 		goto error;
5508 out:
5509 	in_handle->file_state = TRACECMD_FILE_KALLSYMS;
5510 	if (out_compression_end(out_handle, compress))
5511 		goto error;
5512 
5513 	out_set_file_state(out_handle, in_handle->file_state);
5514 
5515 	section_close(in_handle, sec);
5516 
5517 	if (out_update_section_header(out_handle, offset))
5518 		goto error;
5519 
5520 	return 0;
5521 error:
5522 	out_compression_reset(out_handle, compress);
5523 	section_close(in_handle, sec);
5524 	return -1;
5525 }
5526 
copy_ftrace_printk(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle)5527 static int copy_ftrace_printk(struct tracecmd_input *in_handle, struct tracecmd_output *out_handle)
5528 {
5529 	bool compress = out_check_compression(out_handle);
5530 	struct file_section *sec;
5531 	unsigned long long offset;
5532 	unsigned int size;
5533 
5534 	if (!check_in_state(in_handle, TRACECMD_FILE_PRINTK) ||
5535 	    !check_out_state(out_handle, TRACECMD_FILE_PRINTK))
5536 		return -1;
5537 
5538 	sec = section_open(in_handle, TRACECMD_OPTION_PRINTK);
5539 	if (!sec)
5540 		return -1;
5541 
5542 	offset = out_write_section_header(out_handle, TRACECMD_OPTION_PRINTK,
5543 					  "printk", TRACECMD_SEC_FL_COMPRESS, true);
5544 
5545 	out_compression_start(out_handle, compress);
5546 
5547 	if (read_copy_size4(in_handle, out_handle, &size) < 0)
5548 		goto error;
5549 
5550 	if (!size)
5551 		goto out; /* OK? */
5552 
5553 	if (read_copy_data(in_handle, size, out_handle) < 0)
5554 		goto error;
5555 
5556 out:
5557 	in_handle->file_state = TRACECMD_FILE_PRINTK;
5558 	if (out_compression_end(out_handle, compress))
5559 		goto error;
5560 
5561 	out_set_file_state(out_handle, in_handle->file_state);
5562 
5563 	section_close(in_handle, sec);
5564 
5565 	if (out_update_section_header(out_handle, offset))
5566 		goto error;
5567 
5568 	return 0;
5569 error:
5570 	out_compression_reset(out_handle, compress);
5571 	section_close(in_handle, sec);
5572 	return -1;
5573 }
5574 
copy_command_lines(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle)5575 static int copy_command_lines(struct tracecmd_input *in_handle, struct tracecmd_output *out_handle)
5576 {
5577 	bool compress = out_check_compression(out_handle);
5578 	struct file_section *sec;
5579 	unsigned long long offset;
5580 	unsigned long long size;
5581 
5582 	if (!check_in_state(in_handle, TRACECMD_FILE_CMD_LINES) ||
5583 	    !check_out_state(out_handle, TRACECMD_FILE_CMD_LINES))
5584 		return -1;
5585 
5586 	sec = section_open(in_handle, TRACECMD_OPTION_CMDLINES);
5587 	if (!sec)
5588 		return -1;
5589 	offset = out_write_section_header(out_handle, TRACECMD_OPTION_CMDLINES,
5590 					  "command lines", TRACECMD_SEC_FL_COMPRESS, true);
5591 
5592 	out_compression_start(out_handle, compress);
5593 
5594 	if (read_copy_size8(in_handle, out_handle, &size) < 0)
5595 		goto error;
5596 
5597 	if (!size)
5598 		goto out; /* OK? */
5599 
5600 	if (read_copy_data(in_handle, size, out_handle) < 0)
5601 		goto error;
5602 
5603 out:
5604 	in_handle->file_state = TRACECMD_FILE_CMD_LINES;
5605 	if (out_compression_end(out_handle, compress))
5606 		goto error;
5607 
5608 	out_set_file_state(out_handle, in_handle->file_state);
5609 
5610 	section_close(in_handle, sec);
5611 
5612 	if (out_update_section_header(out_handle, offset))
5613 		goto error;
5614 
5615 	return 0;
5616 error:
5617 	out_compression_reset(out_handle, compress);
5618 	section_close(in_handle, sec);
5619 	return -1;
5620 }
5621 
copy_cpu_count(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle)5622 static int copy_cpu_count(struct tracecmd_input *in_handle, struct tracecmd_output *out_handle)
5623 {
5624 	unsigned int cpus;
5625 
5626 	if (!check_in_state(in_handle, TRACECMD_FILE_CPU_COUNT) ||
5627 	    !check_out_state(out_handle, TRACECMD_FILE_CPU_COUNT))
5628 		return -1;
5629 
5630 	if (!HAS_SECTIONS(in_handle)) {
5631 		if (read4(in_handle, &cpus))
5632 			return -1;
5633 	} else {
5634 		cpus = in_handle->max_cpu;
5635 	}
5636 
5637 	if (tracecmd_get_out_file_version(out_handle) < FILE_VERSION_SECTIONS) {
5638 		cpus = tep_read_number(in_handle->pevent, &cpus, 4);
5639 		if (do_write_check(out_handle, &cpus, 4))
5640 			return -1;
5641 	} else {
5642 		tracecmd_add_option(out_handle, TRACECMD_OPTION_CPUCOUNT, sizeof(int), &cpus);
5643 	}
5644 
5645 	in_handle->file_state = TRACECMD_FILE_CPU_COUNT;
5646 	out_set_file_state(out_handle, in_handle->file_state);
5647 
5648 	return 0;
5649 }
5650 
5651 /**
5652  * tracecmd_copy_headers - Copy headers from a tracecmd_input handle to a file descriptor
5653  * @in_handle: input handle for the trace.dat file to copy from.
5654  * @out_handle: output handle to the trace.dat file to copy to.
5655  * @start_state: The file state to start copying from (zero for the beginnig)
5656  * @end_state: The file state to stop at (zero for up to cmdlines)
5657  *
5658  * This is used to copy trace header data of a trace.dat file to a
5659  * file descriptor. Using @start_state and @end_state it may be used
5660  * multiple times against the input handle.
5661  *
5662  * NOTE: The input handle is also modified, and ends at the end
5663  *       state as well.
5664  */
tracecmd_copy_headers(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle,enum tracecmd_file_states start_state,enum tracecmd_file_states end_state)5665 int tracecmd_copy_headers(struct tracecmd_input *in_handle,
5666 			  struct tracecmd_output *out_handle,
5667 			  enum tracecmd_file_states start_state,
5668 			  enum tracecmd_file_states end_state)
5669 {
5670 	struct file_section *sec = NULL;
5671 	int ret;
5672 
5673 	if (!start_state)
5674 		start_state = TRACECMD_FILE_HEADERS;
5675 	if (!end_state)
5676 		end_state = TRACECMD_FILE_CMD_LINES;
5677 
5678 	if (start_state > end_state)
5679 		return -1;
5680 
5681 	if (end_state < TRACECMD_FILE_HEADERS)
5682 		return 0;
5683 
5684 	if (in_handle->file_state >= start_state) {
5685 		/* Set the handle to just before the start state */
5686 		sec = section_open(in_handle, TRACECMD_OPTION_HEADER_INFO);
5687 		if (!sec)
5688 			return -1;
5689 		/* Now that the file handle has moved, change its state */
5690 		in_handle->file_state = TRACECMD_FILE_INIT;
5691 	}
5692 
5693 	/* Try to bring the input up to the start state - 1 */
5694 	ret = tracecmd_read_headers(in_handle, start_state - 1);
5695 	if (sec)
5696 		section_close(in_handle, sec);
5697 	if (ret < 0)
5698 		goto out;
5699 
5700 	switch (start_state) {
5701 	case TRACECMD_FILE_HEADERS:
5702 		ret = copy_header_files(in_handle, out_handle);
5703 		if (ret < 0)
5704 			goto out;
5705 
5706 		/* fallthrough */
5707 	case TRACECMD_FILE_FTRACE_EVENTS:
5708 		/* handle's state is now updating with the copies */
5709 		if (end_state <= in_handle->file_state)
5710 			return 0;
5711 
5712 		ret = copy_ftrace_files(in_handle, out_handle);
5713 		if (ret < 0)
5714 			goto out;
5715 
5716 		/* fallthrough */
5717 	case TRACECMD_FILE_ALL_EVENTS:
5718 		if (end_state <= in_handle->file_state)
5719 			return 0;
5720 
5721 		ret = copy_event_files(in_handle, out_handle);
5722 		if (ret < 0)
5723 			goto out;
5724 
5725 		/* fallthrough */
5726 	case TRACECMD_FILE_KALLSYMS:
5727 		if (end_state <= in_handle->file_state)
5728 			return 0;
5729 
5730 		ret = copy_proc_kallsyms(in_handle, out_handle);
5731 		if (ret < 0)
5732 			goto out;
5733 
5734 		/* fallthrough */
5735 	case TRACECMD_FILE_PRINTK:
5736 		if (end_state <= in_handle->file_state)
5737 			return 0;
5738 
5739 		ret = copy_ftrace_printk(in_handle, out_handle);
5740 		if (ret < 0)
5741 			goto out;
5742 
5743 		/* fallthrough */
5744 	case TRACECMD_FILE_CMD_LINES:
5745 		if (end_state <= in_handle->file_state)
5746 			return 0;
5747 
5748 		/* Optional */
5749 		copy_command_lines(in_handle, out_handle);
5750 
5751 		/* fallthrough */
5752 	case TRACECMD_FILE_CPU_COUNT:
5753 		if (end_state <= in_handle->file_state)
5754 			return 0;
5755 
5756 		ret = copy_cpu_count(in_handle, out_handle);
5757 		if (ret < 0)
5758 			goto out;
5759 
5760 		/* fallthrough */
5761 	default:
5762 		break;
5763 	}
5764 
5765  out:
5766 	return ret < 0 ? -1 : 0;
5767 }
5768 
tracecmd_copy_buffer_descr(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle)5769 int tracecmd_copy_buffer_descr(struct tracecmd_input *in_handle,
5770 			       struct tracecmd_output *out_handle)
5771 {
5772 	int i;
5773 
5774 	if (tracecmd_get_out_file_version(out_handle) >= FILE_VERSION_SECTIONS)
5775 		return 0;
5776 
5777 	for (i = 0; i < in_handle->nr_buffers; i++)
5778 		tracecmd_add_buffer_info(out_handle, in_handle->buffers[i].name, 0);
5779 
5780 	return tracecmd_write_buffer_info(out_handle);
5781 }
5782 
copy_options_recursive(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle)5783 static int copy_options_recursive(struct tracecmd_input *in_handle,
5784 				  struct tracecmd_output *out_handle)
5785 {
5786 	unsigned short id, flags = 0;
5787 	unsigned short option, en2;
5788 	unsigned long long next;
5789 	unsigned int size, en4;
5790 	bool skip;
5791 
5792 	for (;;) {
5793 		if (do_read_check(in_handle, &option, 2))
5794 			return -1;
5795 
5796 		en2 = tep_read_number(in_handle->pevent, &option, 2);
5797 
5798 		if (en2 == TRACECMD_OPTION_DONE && !HAS_SECTIONS(in_handle))
5799 			return 0;
5800 
5801 		/* next 4 bytes is the size of the option */
5802 		if (do_read_check(in_handle, &size, 4))
5803 			return -1;
5804 
5805 		en4 = tep_read_number(in_handle->pevent, &size, 4);
5806 		if (en2 == TRACECMD_OPTION_DONE) {
5807 			/* option done v7 */
5808 			if (en4 < 8)
5809 				return -1;
5810 
5811 			if (read8(in_handle, &next))
5812 				return -1;
5813 
5814 			if (!next)
5815 				break;
5816 
5817 			if (do_lseek(in_handle, next, SEEK_SET) == (off_t)-1)
5818 				return -1;
5819 
5820 			if (read_section_header(in_handle, &id, &flags, NULL, NULL))
5821 				return -1;
5822 
5823 			if (id != TRACECMD_OPTION_DONE)
5824 				return -1;
5825 
5826 			if (flags & TRACECMD_SEC_FL_COMPRESS && in_uncompress_block(in_handle))
5827 				return -1;
5828 
5829 			return copy_options_recursive(in_handle, out_handle);
5830 		}
5831 		/* Do not copy these, as they have file specific offsets */
5832 		switch (en2) {
5833 		case TRACECMD_OPTION_BUFFER:
5834 		case TRACECMD_OPTION_BUFFER_TEXT:
5835 		case TRACECMD_OPTION_HEADER_INFO:
5836 		case TRACECMD_OPTION_FTRACE_EVENTS:
5837 		case TRACECMD_OPTION_EVENT_FORMATS:
5838 		case TRACECMD_OPTION_KALLSYMS:
5839 		case TRACECMD_OPTION_PRINTK:
5840 		case TRACECMD_OPTION_CMDLINES:
5841 			skip = true;
5842 			break;
5843 		default:
5844 			skip = false;
5845 			break;
5846 		}
5847 		if (skip) {
5848 			do_lseek(in_handle, en4, SEEK_CUR);
5849 			continue;
5850 		}
5851 		if (do_write_check(out_handle, &option, 2))
5852 			return -1;
5853 
5854 		if (do_write_check(out_handle, &size, 4))
5855 			return -1;
5856 
5857 		if (read_copy_data(in_handle, en4, out_handle))
5858 			return -1;
5859 	}
5860 
5861 	return 0;
5862 }
5863 
copy_options(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle)5864 static int copy_options(struct tracecmd_input *in_handle, struct tracecmd_output *out_handle)
5865 {
5866 	unsigned long long offset, start;
5867 	unsigned short id, en2, flags = 0;
5868 	int tmp;
5869 
5870 	if (HAS_SECTIONS(in_handle)) {
5871 		if (read_section_header(in_handle, &id, &flags, NULL, NULL))
5872 			return -1;
5873 
5874 		if (id != TRACECMD_OPTION_DONE)
5875 			return -1;
5876 
5877 		if (flags & TRACECMD_SEC_FL_COMPRESS && in_uncompress_block(in_handle))
5878 			return -1;
5879 	}
5880 	start = tracecmd_get_out_file_offset(out_handle);
5881 	if (tracecmd_get_out_file_version(out_handle) < FILE_VERSION_SECTIONS) {
5882 		if (do_write_check(out_handle, "options  ", 10))
5883 			return -1;
5884 	}
5885 
5886 	offset = out_write_section_header(out_handle, TRACECMD_OPTION_DONE, "options", 0, false);
5887 
5888 	if (copy_options_recursive(in_handle, out_handle))
5889 		goto error;
5890 
5891 	id = TRACECMD_OPTION_DONE;
5892 	en2 = tep_read_number(in_handle->pevent, &id, 2);
5893 	if (do_write_check(out_handle, &en2, 2))
5894 		goto error;
5895 
5896 	if (tracecmd_get_out_file_version(out_handle) < FILE_VERSION_SECTIONS) {
5897 		out_save_options_offset(out_handle, start);
5898 	} else {
5899 		tmp = 8;
5900 		if (do_write_check(out_handle, &tmp, 4))
5901 			goto error;
5902 
5903 		out_save_options_offset(out_handle, start);
5904 		start = 0;
5905 		if (do_write_check(out_handle, &start, 8))
5906 			goto error;
5907 	}
5908 	out_update_section_header(out_handle, offset);
5909 	if (flags & TRACECMD_SEC_FL_COMPRESS)
5910 		in_uncompress_reset(in_handle);
5911 	in_handle->file_state = TRACECMD_FILE_OPTIONS;
5912 	out_set_file_state(out_handle, in_handle->file_state);
5913 	/* Append local options */
5914 	return tracecmd_append_options(out_handle);
5915 
5916 error:
5917 	if (flags & TRACECMD_SEC_FL_COMPRESS)
5918 		in_uncompress_reset(in_handle);
5919 	return 0;
5920 }
5921 
tracecmd_copy_options(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle)5922 int tracecmd_copy_options(struct tracecmd_input *in_handle,
5923 			  struct tracecmd_output *out_handle)
5924 {
5925 	if (!check_in_state(in_handle, TRACECMD_FILE_OPTIONS) ||
5926 	    !check_out_state(out_handle, TRACECMD_FILE_OPTIONS))
5927 		return -1;
5928 
5929 	if (!in_handle->options_start)
5930 		return 0;
5931 
5932 	if (lseek(in_handle->fd, in_handle->options_start, SEEK_SET) == (off_t)-1)
5933 		return -1;
5934 
5935 	if (copy_options(in_handle, out_handle) < 0)
5936 		return -1;
5937 
5938 	return 0;
5939 }
5940 
copy_trace_latency(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle,const char * buf_name)5941 static int copy_trace_latency(struct tracecmd_input *in_handle,
5942 			      struct tracecmd_output *out_handle, const char *buf_name)
5943 {
5944 	int page_size = getpagesize();
5945 	unsigned long long wsize;
5946 	unsigned long long offset;
5947 	int fd;
5948 
5949 	if (tracecmd_get_out_file_version(out_handle) < FILE_VERSION_SECTIONS &&
5950 	    do_write_check(out_handle, "latency  ", 10))
5951 		return -1;
5952 
5953 	offset = tracecmd_get_out_file_offset(out_handle);
5954 
5955 	if (tracecmd_get_out_file_version(out_handle) >= FILE_VERSION_SECTIONS &&
5956 	    !out_add_buffer_option(out_handle, buf_name, TRACECMD_OPTION_BUFFER_TEXT,
5957 				   offset, 0, NULL, page_size))
5958 		return -1;
5959 
5960 	offset = out_write_section_header(out_handle, TRACECMD_OPTION_BUFFER_TEXT,
5961 					  "buffer latency", TRACECMD_SEC_FL_COMPRESS, false);
5962 
5963 	if (in_handle->latz.fd >= 0)
5964 		fd = in_handle->latz.fd;
5965 	else
5966 		fd = in_handle->fd;
5967 
5968 	if (!out_copy_fd_compress(out_handle, fd, 0, &wsize, page_size))
5969 		return -1;
5970 
5971 	if (out_update_section_header(out_handle, offset))
5972 		return -1;
5973 
5974 	out_set_file_state(out_handle, TRACECMD_FILE_CPU_LATENCY);
5975 	return 0;
5976 }
5977 
copy_trace_flyrecord_data(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle,const char * buff_name)5978 static int copy_trace_flyrecord_data(struct tracecmd_input *in_handle,
5979 				     struct tracecmd_output *out_handle, const char *buff_name)
5980 {
5981 	struct cpu_data_source *data;
5982 	int total_size = 0;
5983 	int cpus;
5984 	int ret;
5985 	int i, j;
5986 
5987 	if (tracecmd_get_out_file_version(out_handle) < FILE_VERSION_SECTIONS)
5988 		cpus = in_handle->max_cpu;
5989 	else
5990 		cpus = in_handle->cpus;
5991 
5992 	data = calloc(cpus, sizeof(struct cpu_data_source));
5993 	if (!data)
5994 		return -1;
5995 
5996 	for (i = 0; i < in_handle->cpus; i++) {
5997 		j = in_handle->cpu_data[i].cpu;
5998 		data[j].size = in_handle->cpu_data[i].file_size;
5999 		total_size += data[j].size;
6000 		if (in_handle->cpu_data[i].compress.fd >= 0) {
6001 			data[j].fd = in_handle->cpu_data[i].compress.fd;
6002 			data[j].offset = 0;
6003 		} else {
6004 			data[j].fd = in_handle->fd;
6005 			data[j].offset = in_handle->cpu_data[i].file_offset;
6006 		}
6007 	}
6008 	if (total_size || tracecmd_get_out_file_version(out_handle) < FILE_VERSION_SECTIONS)
6009 		ret = out_write_cpu_data(out_handle, cpus, data, buff_name);
6010 	else
6011 		ret = 0;
6012 	free(data);
6013 
6014 	return ret;
6015 }
6016 
copy_flyrecord_buffer(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle,int index)6017 static int copy_flyrecord_buffer(struct tracecmd_input *in_handle,
6018 				 struct tracecmd_output *out_handle, int index)
6019 {
6020 	struct tracecmd_input *instance;
6021 	const char *name;
6022 	int ret;
6023 
6024 	name = tracecmd_buffer_instance_name(in_handle, index);
6025 	if (!name)
6026 		return -1;
6027 
6028 	instance = tracecmd_buffer_instance_handle(in_handle, index);
6029 	if (!instance)
6030 		return -1;
6031 
6032 	if (!tracecmd_get_quiet(out_handle) && *name)
6033 		fprintf(stderr, "\nBuffer: %s\n\n", name);
6034 
6035 	if (in_handle->buffers[index].latency)
6036 		ret = copy_trace_latency(in_handle, out_handle, name);
6037 	else
6038 		ret = copy_trace_flyrecord_data(instance, out_handle, name);
6039 	tracecmd_close(instance);
6040 
6041 	return ret;
6042 }
6043 
copy_trace_data_from_v6(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle)6044 static int copy_trace_data_from_v6(struct tracecmd_input *in_handle,
6045 				   struct tracecmd_output *out_handle)
6046 {
6047 	char buf[10];
6048 	int ret;
6049 	int i;
6050 
6051 	if (do_read_check(in_handle, buf, 10))
6052 		return -1;
6053 
6054 	if (strncmp(buf, "latency", 7) == 0)
6055 		in_handle->file_state = TRACECMD_FILE_CPU_LATENCY;
6056 	else if (strncmp(buf, "flyrecord", 9) == 0)
6057 		in_handle->file_state = TRACECMD_FILE_CPU_FLYRECORD;
6058 
6059 	tracecmd_init_data(in_handle);
6060 	tracecmd_set_out_clock(out_handle, in_handle->trace_clock);
6061 
6062 	if (in_handle->file_state == TRACECMD_FILE_CPU_LATENCY)
6063 		return copy_trace_latency(in_handle, out_handle, "");
6064 
6065 	/* top instance */
6066 	ret = copy_trace_flyrecord_data(in_handle, out_handle, "");
6067 	if (ret)
6068 		return ret;
6069 
6070 	for (i = 0; i < in_handle->nr_buffers; i++)
6071 		copy_flyrecord_buffer(in_handle, out_handle, i);
6072 
6073 	return 0;
6074 }
6075 
copy_trace_data_from_v7(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle)6076 static int copy_trace_data_from_v7(struct tracecmd_input *in_handle,
6077 				   struct tracecmd_output *out_handle)
6078 {
6079 	int ret;
6080 	int i;
6081 
6082 	/* Force using temporary files for trace data decompression */
6083 	in_handle->read_zpage = false;
6084 	ret = tracecmd_init_data(in_handle);
6085 	if (ret < 0)
6086 		return ret;
6087 	tracecmd_set_out_clock(out_handle, in_handle->trace_clock);
6088 
6089 	/* copy top buffer */
6090 	if (in_handle->top_buffer.latency)
6091 		ret = copy_trace_latency(in_handle, out_handle, in_handle->top_buffer.name);
6092 	else if (in_handle->top_buffer.cpus)
6093 		ret = copy_trace_flyrecord_data(in_handle, out_handle,
6094 						in_handle->top_buffer.name);
6095 	else if (tracecmd_get_out_file_version(out_handle) < FILE_VERSION_SECTIONS)
6096 		ret = out_write_emty_cpu_data(out_handle, in_handle->max_cpu);
6097 	if (ret)
6098 		return ret;
6099 
6100 	for (i = 0; i < in_handle->nr_buffers; i++)
6101 		copy_flyrecord_buffer(in_handle, out_handle, i);
6102 
6103 	return 0;
6104 }
6105 
tracecmd_copy_trace_data(struct tracecmd_input * in_handle,struct tracecmd_output * out_handle)6106 __hidden int tracecmd_copy_trace_data(struct tracecmd_input *in_handle,
6107 				      struct tracecmd_output *out_handle)
6108 {
6109 	int ret;
6110 
6111 	if (!check_in_state(in_handle, TRACECMD_FILE_CPU_FLYRECORD) ||
6112 	    !check_out_state(out_handle, TRACECMD_FILE_CPU_FLYRECORD))
6113 		return -1;
6114 
6115 	if (in_handle->file_version < FILE_VERSION_SECTIONS)
6116 		ret = copy_trace_data_from_v6(in_handle, out_handle);
6117 	else
6118 		ret = copy_trace_data_from_v7(in_handle, out_handle);
6119 
6120 	return ret;
6121 }
6122 
6123 /**
6124  * tracecmd_record_at_buffer_start - return true if record is first on subbuffer
6125  * @handle: input handle for the trace.dat file
6126  * @record: The record to test if it is the first record on page
6127  *
6128  * Returns true if the record is the first record on the page.
6129  */
tracecmd_record_at_buffer_start(struct tracecmd_input * handle,struct tep_record * record)6130 int tracecmd_record_at_buffer_start(struct tracecmd_input *handle,
6131 				    struct tep_record *record)
6132 {
6133 	struct page *page = record->priv;
6134 	struct kbuffer *kbuf = handle->cpu_data[record->cpu].kbuf;
6135 	int offset;
6136 
6137 	if (!page || !kbuf)
6138 		return 0;
6139 
6140 	offset = record->offset - page->offset;
6141 	return offset == kbuffer_start_of_data(kbuf);
6142 }
6143 
tracecmd_page_ts(struct tracecmd_input * handle,struct tep_record * record)6144 unsigned long long tracecmd_page_ts(struct tracecmd_input *handle,
6145 				    struct tep_record *record)
6146 {
6147 	struct page *page = record->priv;
6148 	struct kbuffer *kbuf = handle->cpu_data[record->cpu].kbuf;
6149 
6150 	if (!page || !kbuf)
6151 		return 0;
6152 
6153 	return kbuffer_subbuf_timestamp(kbuf, page->map);
6154 }
6155 
tracecmd_record_ts_delta(struct tracecmd_input * handle,struct tep_record * record)6156 unsigned int tracecmd_record_ts_delta(struct tracecmd_input *handle,
6157 				      struct tep_record *record)
6158 {
6159 	struct kbuffer *kbuf = handle->cpu_data[record->cpu].kbuf;
6160 	struct page *page = record->priv;
6161 	int offset;
6162 
6163 	if (!page || !kbuf)
6164 		return 0;
6165 
6166 	offset = record->offset - page->offset;
6167 
6168 	return kbuffer_ptr_delta(kbuf, page->map + offset);
6169 }
6170 
tracecmd_record_kbuf(struct tracecmd_input * handle,struct tep_record * record)6171 struct kbuffer *tracecmd_record_kbuf(struct tracecmd_input *handle,
6172 				     struct tep_record *record)
6173 {
6174 	return handle->cpu_data[record->cpu].kbuf;
6175 }
6176 
tracecmd_record_page(struct tracecmd_input * handle,struct tep_record * record)6177 void *tracecmd_record_page(struct tracecmd_input *handle,
6178 			   struct tep_record *record)
6179 {
6180 	struct page *page = record->priv;
6181 
6182 	return page ? page->map : NULL;
6183 }
6184 
tracecmd_record_offset(struct tracecmd_input * handle,struct tep_record * record)6185 void *tracecmd_record_offset(struct tracecmd_input *handle,
6186 			     struct tep_record *record)
6187 {
6188 	struct page *page = record->priv;
6189 	int offset;
6190 
6191 	if (!page)
6192 		return NULL;
6193 
6194 	offset = record->offset - page->offset;
6195 
6196 	return page->map + offset;
6197 }
6198 
tracecmd_buffer_instances(struct tracecmd_input * handle)6199 int tracecmd_buffer_instances(struct tracecmd_input *handle)
6200 {
6201 	return handle->nr_buffers;
6202 }
6203 
tracecmd_buffer_instance_name(struct tracecmd_input * handle,int indx)6204 const char *tracecmd_buffer_instance_name(struct tracecmd_input *handle, int indx)
6205 {
6206 	if (indx >= handle->nr_buffers)
6207 		return NULL;
6208 
6209 	return handle->buffers[indx].name;
6210 }
6211 
6212 struct tracecmd_input *
tracecmd_buffer_instance_handle(struct tracecmd_input * handle,int indx)6213 tracecmd_buffer_instance_handle(struct tracecmd_input *handle, int indx)
6214 {
6215 	struct tracecmd_input *new_handle;
6216 	struct input_buffer_instance *buffer = &handle->buffers[indx];
6217 	size_t offset;
6218 	ssize_t ret;
6219 
6220 	if (indx >= handle->nr_buffers)
6221 		return NULL;
6222 
6223 	/*
6224 	 * We make a copy of the current handle, but we substitute
6225 	 * the cpu data with the cpu data for this buffer.
6226 	 */
6227 	new_handle = malloc(sizeof(*handle));
6228 	if (!new_handle)
6229 		return NULL;
6230 
6231 	*new_handle = *handle;
6232 	memset(&new_handle->top_buffer, 0, sizeof(new_handle->top_buffer));
6233 	new_handle->cpu_data = NULL;
6234 	new_handle->nr_buffers = 0;
6235 	new_handle->buffers = NULL;
6236 	new_handle->version = NULL;
6237 	new_handle->sections = NULL;
6238 	new_handle->strings = NULL;
6239 	new_handle->guest = NULL;
6240 	new_handle->ref = 1;
6241 	if (handle->trace_clock) {
6242 		new_handle->trace_clock = strdup(handle->trace_clock);
6243 		if (!new_handle->trace_clock) {
6244 			free(new_handle);
6245 			return NULL;
6246 		}
6247 	}
6248 	memset(&new_handle->host, 0, sizeof(new_handle->host));
6249 	new_handle->parent = handle;
6250 	new_handle->cpustats = NULL;
6251 	new_handle->hooks = NULL;
6252 	if (handle->uname)
6253 		/* Ignore if fails to malloc, no biggy */
6254 		new_handle->uname = strdup(handle->uname);
6255 	tracecmd_ref(handle);
6256 
6257 	new_handle->fd = dup(handle->fd);
6258 
6259 	new_handle->flags |= TRACECMD_FL_BUFFER_INSTANCE;
6260 
6261 	new_handle->pid_maps = NULL;
6262 	if (!HAS_SECTIONS(handle)) {
6263 		/* Save where we currently are */
6264 		offset = lseek(handle->fd, 0, SEEK_CUR);
6265 
6266 		ret = lseek(handle->fd, buffer->offset, SEEK_SET);
6267 		if (ret == (off_t)-1) {
6268 			tracecmd_warning("could not seek to buffer %s offset %ld",
6269 					  buffer->name, buffer->offset);
6270 			goto error;
6271 		}
6272 		/*
6273 		 * read_options_type() is called right after the CPU count so update
6274 		 * file state accordingly.
6275 		 */
6276 		new_handle->file_state = TRACECMD_FILE_CPU_COUNT;
6277 		ret = read_options_type(new_handle);
6278 		if (!ret)
6279 			ret = read_cpu_data(new_handle);
6280 
6281 		if (ret < 0) {
6282 			tracecmd_warning("failed to read sub buffer %s", buffer->name);
6283 			goto error;
6284 		}
6285 		ret = lseek(handle->fd, offset, SEEK_SET);
6286 		if (ret < 0) {
6287 			tracecmd_warning("could not seek to back to offset %ld", offset);
6288 			goto error;
6289 		}
6290 	} else {
6291 		new_handle->page_size = handle->buffers[indx].page_size;
6292 		if (init_buffer_cpu_data(new_handle, buffer) < 0)
6293 			goto error;
6294 	}
6295 
6296 	return new_handle;
6297 
6298 error:
6299 	tracecmd_close(new_handle);
6300 	return NULL;
6301 }
6302 
tracecmd_is_buffer_instance(struct tracecmd_input * handle)6303 int tracecmd_is_buffer_instance(struct tracecmd_input *handle)
6304 {
6305 	return handle->flags & TRACECMD_FL_BUFFER_INSTANCE;
6306 }
6307 
6308 /**
6309  * tracecmd_long_size - return the size of "long" for the arch
6310  * @handle: input handle for the trace.dat file
6311  */
tracecmd_long_size(struct tracecmd_input * handle)6312 int tracecmd_long_size(struct tracecmd_input *handle)
6313 {
6314 	return handle->long_size;
6315 }
6316 
6317 /**
6318  * tracecmd_page_size - return the PAGE_SIZE for the arch
6319  * @handle: input handle for the trace.dat file
6320  */
tracecmd_page_size(struct tracecmd_input * handle)6321 int tracecmd_page_size(struct tracecmd_input *handle)
6322 {
6323 	return handle->page_size;
6324 }
6325 
6326 /**
6327  * tracecmd_cpus - return the number of CPUs recorded
6328  * @handle: input handle for the trace.dat file
6329  */
tracecmd_cpus(struct tracecmd_input * handle)6330 int tracecmd_cpus(struct tracecmd_input *handle)
6331 {
6332 	return handle->max_cpu;
6333 }
6334 
6335 /**
6336  * tracecmd_get_tep - return the tep handle
6337  * @handle: input handle for the trace.dat file
6338  */
tracecmd_get_tep(struct tracecmd_input * handle)6339 struct tep_handle *tracecmd_get_tep(struct tracecmd_input *handle)
6340 {
6341 	return handle->pevent;
6342 }
6343 
6344 /**
6345  * tracecmd_get_in_file_version - return the trace.dat file version
6346  * @handle: input handle for the trace.dat file
6347  */
tracecmd_get_in_file_version(struct tracecmd_input * handle)6348 unsigned long tracecmd_get_in_file_version(struct tracecmd_input *handle)
6349 {
6350 	return handle->file_version;
6351 }
6352 
6353 /**
6354  * tracecmd_get_file_compress_proto - get name and version of compression algorithm
6355  * @handle: input handle for the trace.dat file
6356  * @name: return, name of the compression algorithm.
6357  * @version: return, version of the compression algorithm.
6358  *
6359  * Get the name and the version of the compression algorithm, used to
6360  * compress the file associated with @handle.
6361  * Returns 0 on success, or -1 in case of an error. If 0 is returned,
6362  * the name and version of the algorithm are stored in @name and @version.
6363  * The returned strings must *not* be freed.
6364  */
tracecmd_get_file_compress_proto(struct tracecmd_input * handle,const char ** name,const char ** version)6365 int tracecmd_get_file_compress_proto(struct tracecmd_input *handle,
6366 				     const char **name, const char **version)
6367 {
6368 	return tracecmd_compress_proto_get_name(handle->compress, name, version);
6369 }
6370 
6371 /**
6372  * tracecmd_get_use_trace_clock - return use_trace_clock
6373  * @handle: input handle for the trace.dat file
6374  */
tracecmd_get_use_trace_clock(struct tracecmd_input * handle)6375 bool tracecmd_get_use_trace_clock(struct tracecmd_input *handle)
6376 {
6377 	return handle->use_trace_clock;
6378 }
6379 
6380 /**
6381  * tracecmd_get_options_offset - get offset of the options sections in the file
6382  * @handle: input handle for the trace.dat file
6383  */
tracecmd_get_options_offset(struct tracecmd_input * handle)6384 size_t tracecmd_get_options_offset(struct tracecmd_input *handle)
6385 {
6386 	return handle->options_start;
6387 }
6388 
6389 /**
6390  * tracecmd_get_trace_clock - return the saved trace clock
6391  * @handle: input handle for the trace.dat file
6392  *
6393  * Returns a string of the clock that was saved in the trace.dat file.
6394  * The string should not be freed, as it points to the internal
6395  * structure data.
6396  */
tracecmd_get_trace_clock(struct tracecmd_input * handle)6397 const char *tracecmd_get_trace_clock(struct tracecmd_input *handle)
6398 {
6399 	return handle->trace_clock;
6400 }
6401 
6402 /**
6403  * tracecmd_get_tsc2nsec - get the calculation numbers to convert to nsecs
6404  * @mult: If not NULL, points to where to save the multiplier
6405  * @shift: If not NULL, points to where to save the shift.
6406  * @offset: If not NULL, points to where to save the offset.
6407  *
6408  * This only returns a value if the clock is of a raw type.
6409  * (currently just x86-tsc is supported).
6410  *
6411  * Returns 0 on success, or -1 on not supported clock (but may still fill
6412  * in the values).
6413  */
tracecmd_get_tsc2nsec(struct tracecmd_input * handle,int * mult,int * shift,unsigned long long * offset)6414 int tracecmd_get_tsc2nsec(struct tracecmd_input *handle,
6415 			  int *mult, int *shift, unsigned long long *offset)
6416 {
6417 	if (mult)
6418 		*mult = handle->tsc_calc.mult;
6419 	if (shift)
6420 		*shift = handle->tsc_calc.shift;
6421 	if (offset)
6422 		*offset = handle->tsc_calc.offset;
6423 
6424 	return handle->top_buffer.clock &&
6425 		(strcmp(handle->top_buffer.clock, "x86-tsc") == 0 ||
6426 		 strcmp(handle->top_buffer.clock, "tsc2nsec") == 0) ? 0 : -1;
6427 }
6428 
6429 /**
6430  * tracecmd_get_cpustats - return the saved cpu stats
6431  * @handle: input handle for the trace.dat file
6432  *
6433  * Provides a method to extract the cpu stats saved in @handle.
6434  *
6435  * Returns a string of the cpu stats that was saved in the trace.dat file.
6436  * The string should not be freed, as it points to the internal
6437  * structure data.
6438  */
tracecmd_get_cpustats(struct tracecmd_input * handle)6439 const char *tracecmd_get_cpustats(struct tracecmd_input *handle)
6440 {
6441 	return handle->cpustats;
6442 }
6443 
6444 /**
6445  * tracecmd_get_uname - return the saved name and kernel information
6446  * @handle: input handle for the trace.dat file
6447  *
6448  * Provides a method to extract the system information saved in @handle.
6449  *
6450  * Returns a string of the system information that was saved in the
6451  * trace.dat file.
6452  * The string should not be freed, as it points to the internal
6453  * structure data.
6454  */
tracecmd_get_uname(struct tracecmd_input * handle)6455 const char *tracecmd_get_uname(struct tracecmd_input *handle)
6456 {
6457 	return handle->uname;
6458 }
6459 
6460 /**
6461  * tracecmd_get_version - return the saved version information
6462  * @handle: input handle for the trace.dat file
6463  *
6464  * Provides a method to extract the version string saved in @handle.
6465  *
6466  * Returns a string of the version that was saved in the trace.dat file.
6467  * The string should not be freed, as it points to the internal
6468  * structure data.
6469  */
tracecmd_get_version(struct tracecmd_input * handle)6470 const char *tracecmd_get_version(struct tracecmd_input *handle)
6471 {
6472 	return handle->version;
6473 }
6474 
6475 /**
6476  * tracecmd_get_cpu_file_size - return the saved cpu file size
6477  * @handle: input handle for the trace.dat file
6478  * @cpu: cpu index
6479  *
6480  * Provides a method to extract the cpu file size saved in @handle.
6481  *
6482  * Returns the cpu file size saved in trace.dat file or (off_t)-1 for
6483  * invalid cpu index.
6484  */
tracecmd_get_cpu_file_size(struct tracecmd_input * handle,int cpu)6485 off_t tracecmd_get_cpu_file_size(struct tracecmd_input *handle, int cpu)
6486 {
6487 	if (cpu < 0 || cpu >= handle->cpus)
6488 		return (off_t)-1;
6489 	return handle->cpu_data[cpu].file_size;
6490 }
6491 
6492 /**
6493  * tracecmd_get_show_data_func - return the show data func
6494  * @handle: input handle for the trace.dat file
6495  */
6496 tracecmd_show_data_func
tracecmd_get_show_data_func(struct tracecmd_input * handle)6497 tracecmd_get_show_data_func(struct tracecmd_input *handle)
6498 {
6499 	return handle->show_data_func;
6500 }
6501 
6502 /**
6503  * tracecmd_set_show_data_func - set the show data func
6504  * @handle: input handle for the trace.dat file
6505  */
tracecmd_set_show_data_func(struct tracecmd_input * handle,tracecmd_show_data_func func)6506 void tracecmd_set_show_data_func(struct tracecmd_input *handle,
6507 				 tracecmd_show_data_func func)
6508 {
6509 	handle->show_data_func = func;
6510 }
6511 
6512 /**
6513  * tracecmd_get_traceid - get the trace id of the session
6514  * @handle: input handle for the trace.dat file
6515  *
6516  * Returns the trace id, written in the trace file
6517  */
tracecmd_get_traceid(struct tracecmd_input * handle)6518 unsigned long long tracecmd_get_traceid(struct tracecmd_input *handle)
6519 {
6520 	return handle->trace_id;
6521 }
6522 
6523 /**
6524  * tracecmd_get_first_ts - get the timestamp of the first recorded event
6525  * @handle: input handle for the trace.dat file
6526  *
6527  * Returns the timestamp of the first recorded event
6528  */
tracecmd_get_first_ts(struct tracecmd_input * handle)6529 unsigned long long tracecmd_get_first_ts(struct tracecmd_input *handle)
6530 {
6531 	unsigned long long ts = 0;
6532 	bool first = true;
6533 	int i;
6534 
6535 	for (i = 0; i < handle->cpus; i++) {
6536 		/* Ignore empty buffers */
6537 		if (!handle->cpu_data[i].size)
6538 			continue;
6539 		if (first || ts > handle->cpu_data[i].first_ts)
6540 			ts = handle->cpu_data[i].first_ts;
6541 		first = false;
6542 	}
6543 
6544 	return ts;
6545 }
6546 
6547 /**
6548  * tracecmd_get_guest_cpumap - get the mapping of guest VCPU to host process
6549  * @handle: input handle for the trace.dat file
6550  * @trace_id: ID of the guest tracing session
6551  * @name: return, name of the guest
6552  * @vcpu_count: return, number of VPUs
6553  * @cpu_pid: return, array with guest VCPU to host process mapping
6554  *
6555  * Returns @name of the guest, number of VPUs (@vcpu_count)
6556  * and array @cpu_pid with size @vcpu_count. Array index is VCPU id, array
6557  * content is PID of the host process, running this VCPU.
6558  *
6559  * This information is stored in host trace.dat file
6560  */
tracecmd_get_guest_cpumap(struct tracecmd_input * handle,unsigned long long trace_id,const char ** name,int * vcpu_count,const int ** cpu_pid)6561 int tracecmd_get_guest_cpumap(struct tracecmd_input *handle,
6562 			      unsigned long long trace_id,
6563 			      const char **name,
6564 			      int *vcpu_count, const int **cpu_pid)
6565 {
6566 	struct guest_trace_info	*guest = handle->guest;
6567 
6568 	while (guest) {
6569 		if (guest->trace_id == trace_id)
6570 			break;
6571 		guest = guest->next;
6572 	}
6573 	if (!guest)
6574 		return -1;
6575 
6576 	if (name)
6577 		*name = guest->name;
6578 	if (vcpu_count)
6579 		*vcpu_count = guest->vcpu_count;
6580 	if (cpu_pid)
6581 		*cpu_pid = guest->cpu_pid;
6582 	return 0;
6583 }
6584 
6585 /**
6586  * tracecmd_enable_tsync - enable / disable the timestamps correction
6587  * @handle: input handle for the trace.dat file
6588  * @enable: enable / disable the timestamps correction
6589  *
6590  * Enables or disables timestamps correction on file load, using the array of
6591  * recorded time offsets. If "enable" is true, but there are no time offsets,
6592  * function fails and -1 is returned.
6593  *
6594  * Returns -1 in case of an error, or 0 otherwise
6595  */
tracecmd_enable_tsync(struct tracecmd_input * handle,bool enable)6596 int tracecmd_enable_tsync(struct tracecmd_input *handle, bool enable)
6597 {
6598 	if (enable &&
6599 	    (!handle->host.ts_offsets || !handle->host.cpu_count))
6600 		return -1;
6601 
6602 	handle->host.sync_enable = enable;
6603 
6604 	return 0;
6605 }
6606 
tracecmd_filter_get(struct tracecmd_input * handle)6607 __hidden struct tracecmd_filter *tracecmd_filter_get(struct tracecmd_input *handle)
6608 {
6609 	return handle->filter;
6610 }
6611 
tracecmd_filter_set(struct tracecmd_input * handle,struct tracecmd_filter * filter)6612 __hidden void tracecmd_filter_set(struct tracecmd_input *handle,
6613 				  struct tracecmd_filter *filter)
6614 {
6615 	/* This can be used to set filter to NULL though. */
6616 	if (handle->filter && filter) {
6617 		tracecmd_warning("Filter exists and setting a new one");
6618 		return;
6619 	}
6620 
6621 	handle->filter = filter;
6622 }
6623