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