cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

trace-event-read.c (8279B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com>
      4 */
      5#include <dirent.h>
      6#include <stdio.h>
      7#include <stdlib.h>
      8#include <string.h>
      9#include <stdarg.h>
     10#include <sys/types.h>
     11#include <sys/stat.h>
     12#include <sys/wait.h>
     13#include <sys/mman.h>
     14#include <fcntl.h>
     15#include <unistd.h>
     16#include <errno.h>
     17
     18#include "trace-event.h"
     19#include "debug.h"
     20
     21static int input_fd;
     22
     23static ssize_t trace_data_size;
     24static bool repipe;
     25
     26static int __do_read(int fd, void *buf, int size)
     27{
     28	int rsize = size;
     29
     30	while (size) {
     31		int ret = read(fd, buf, size);
     32
     33		if (ret <= 0)
     34			return -1;
     35
     36		if (repipe) {
     37			int retw = write(STDOUT_FILENO, buf, ret);
     38
     39			if (retw <= 0 || retw != ret) {
     40				pr_debug("repiping input file");
     41				return -1;
     42			}
     43		}
     44
     45		size -= ret;
     46		buf += ret;
     47	}
     48
     49	return rsize;
     50}
     51
     52static int do_read(void *data, int size)
     53{
     54	int r;
     55
     56	r = __do_read(input_fd, data, size);
     57	if (r <= 0) {
     58		pr_debug("reading input file (size expected=%d received=%d)",
     59			 size, r);
     60		return -1;
     61	}
     62
     63	trace_data_size += r;
     64
     65	return r;
     66}
     67
     68/* If it fails, the next read will report it */
     69static void skip(int size)
     70{
     71	char buf[BUFSIZ];
     72	int r;
     73
     74	while (size) {
     75		r = size > BUFSIZ ? BUFSIZ : size;
     76		do_read(buf, r);
     77		size -= r;
     78	}
     79}
     80
     81static unsigned int read4(struct tep_handle *pevent)
     82{
     83	unsigned int data;
     84
     85	if (do_read(&data, 4) < 0)
     86		return 0;
     87	return tep_read_number(pevent, &data, 4);
     88}
     89
     90static unsigned long long read8(struct tep_handle *pevent)
     91{
     92	unsigned long long data;
     93
     94	if (do_read(&data, 8) < 0)
     95		return 0;
     96	return tep_read_number(pevent, &data, 8);
     97}
     98
     99static char *read_string(void)
    100{
    101	char buf[BUFSIZ];
    102	char *str = NULL;
    103	int size = 0;
    104	off_t r;
    105	char c;
    106
    107	for (;;) {
    108		r = read(input_fd, &c, 1);
    109		if (r < 0) {
    110			pr_debug("reading input file");
    111			goto out;
    112		}
    113
    114		if (!r) {
    115			pr_debug("no data");
    116			goto out;
    117		}
    118
    119		if (repipe) {
    120			int retw = write(STDOUT_FILENO, &c, 1);
    121
    122			if (retw <= 0 || retw != r) {
    123				pr_debug("repiping input file string");
    124				goto out;
    125			}
    126		}
    127
    128		buf[size++] = c;
    129
    130		if (!c)
    131			break;
    132	}
    133
    134	trace_data_size += size;
    135
    136	str = malloc(size);
    137	if (str)
    138		memcpy(str, buf, size);
    139out:
    140	return str;
    141}
    142
    143static int read_proc_kallsyms(struct tep_handle *pevent)
    144{
    145	unsigned int size;
    146
    147	size = read4(pevent);
    148	if (!size)
    149		return 0;
    150	/*
    151	 * Just skip it, now that we configure libtraceevent to use the
    152	 * tools/perf/ symbol resolver.
    153	 *
    154	 * We need to skip it so that we can continue parsing old perf.data
    155	 * files, that contains this /proc/kallsyms payload.
    156	 *
    157	 * Newer perf.data files will have just the 4-bytes zeros "kallsyms
    158	 * payload", so that older tools can continue reading it and interpret
    159	 * it as "no kallsyms payload is present".
    160	 */
    161	lseek(input_fd, size, SEEK_CUR);
    162	trace_data_size += size;
    163	return 0;
    164}
    165
    166static int read_ftrace_printk(struct tep_handle *pevent)
    167{
    168	unsigned int size;
    169	char *buf;
    170
    171	/* it can have 0 size */
    172	size = read4(pevent);
    173	if (!size)
    174		return 0;
    175
    176	buf = malloc(size + 1);
    177	if (buf == NULL)
    178		return -1;
    179
    180	if (do_read(buf, size) < 0) {
    181		free(buf);
    182		return -1;
    183	}
    184
    185	buf[size] = '\0';
    186
    187	parse_ftrace_printk(pevent, buf, size);
    188
    189	free(buf);
    190	return 0;
    191}
    192
    193static int read_header_files(struct tep_handle *pevent)
    194{
    195	unsigned long long size;
    196	char *header_page;
    197	char buf[BUFSIZ];
    198	int ret = 0;
    199
    200	if (do_read(buf, 12) < 0)
    201		return -1;
    202
    203	if (memcmp(buf, "header_page", 12) != 0) {
    204		pr_debug("did not read header page");
    205		return -1;
    206	}
    207
    208	size = read8(pevent);
    209
    210	header_page = malloc(size);
    211	if (header_page == NULL)
    212		return -1;
    213
    214	if (do_read(header_page, size) < 0) {
    215		pr_debug("did not read header page");
    216		free(header_page);
    217		return -1;
    218	}
    219
    220	if (!tep_parse_header_page(pevent, header_page, size,
    221				   tep_get_long_size(pevent))) {
    222		/*
    223		 * The commit field in the page is of type long,
    224		 * use that instead, since it represents the kernel.
    225		 */
    226		tep_set_long_size(pevent, tep_get_header_page_size(pevent));
    227	}
    228	free(header_page);
    229
    230	if (do_read(buf, 13) < 0)
    231		return -1;
    232
    233	if (memcmp(buf, "header_event", 13) != 0) {
    234		pr_debug("did not read header event");
    235		return -1;
    236	}
    237
    238	size = read8(pevent);
    239	skip(size);
    240
    241	return ret;
    242}
    243
    244static int read_ftrace_file(struct tep_handle *pevent, unsigned long long size)
    245{
    246	int ret;
    247	char *buf;
    248
    249	buf = malloc(size);
    250	if (buf == NULL) {
    251		pr_debug("memory allocation failure\n");
    252		return -1;
    253	}
    254
    255	ret = do_read(buf, size);
    256	if (ret < 0) {
    257		pr_debug("error reading ftrace file.\n");
    258		goto out;
    259	}
    260
    261	ret = parse_ftrace_file(pevent, buf, size);
    262	if (ret < 0)
    263		pr_debug("error parsing ftrace file.\n");
    264out:
    265	free(buf);
    266	return ret;
    267}
    268
    269static int read_event_file(struct tep_handle *pevent, char *sys,
    270			   unsigned long long size)
    271{
    272	int ret;
    273	char *buf;
    274
    275	buf = malloc(size);
    276	if (buf == NULL) {
    277		pr_debug("memory allocation failure\n");
    278		return -1;
    279	}
    280
    281	ret = do_read(buf, size);
    282	if (ret < 0)
    283		goto out;
    284
    285	ret = parse_event_file(pevent, buf, size, sys);
    286	if (ret < 0)
    287		pr_debug("error parsing event file.\n");
    288out:
    289	free(buf);
    290	return ret;
    291}
    292
    293static int read_ftrace_files(struct tep_handle *pevent)
    294{
    295	unsigned long long size;
    296	int count;
    297	int i;
    298	int ret;
    299
    300	count = read4(pevent);
    301
    302	for (i = 0; i < count; i++) {
    303		size = read8(pevent);
    304		ret = read_ftrace_file(pevent, size);
    305		if (ret)
    306			return ret;
    307	}
    308	return 0;
    309}
    310
    311static int read_event_files(struct tep_handle *pevent)
    312{
    313	unsigned long long size;
    314	char *sys;
    315	int systems;
    316	int count;
    317	int i,x;
    318	int ret;
    319
    320	systems = read4(pevent);
    321
    322	for (i = 0; i < systems; i++) {
    323		sys = read_string();
    324		if (sys == NULL)
    325			return -1;
    326
    327		count = read4(pevent);
    328
    329		for (x=0; x < count; x++) {
    330			size = read8(pevent);
    331			ret = read_event_file(pevent, sys, size);
    332			if (ret) {
    333				free(sys);
    334				return ret;
    335			}
    336		}
    337		free(sys);
    338	}
    339	return 0;
    340}
    341
    342static int read_saved_cmdline(struct tep_handle *pevent)
    343{
    344	unsigned long long size;
    345	char *buf;
    346	int ret;
    347
    348	/* it can have 0 size */
    349	size = read8(pevent);
    350	if (!size)
    351		return 0;
    352
    353	buf = malloc(size + 1);
    354	if (buf == NULL) {
    355		pr_debug("memory allocation failure\n");
    356		return -1;
    357	}
    358
    359	ret = do_read(buf, size);
    360	if (ret < 0) {
    361		pr_debug("error reading saved cmdlines\n");
    362		goto out;
    363	}
    364	buf[ret] = '\0';
    365
    366	parse_saved_cmdline(pevent, buf, size);
    367	ret = 0;
    368out:
    369	free(buf);
    370	return ret;
    371}
    372
    373ssize_t trace_report(int fd, struct trace_event *tevent, bool __repipe)
    374{
    375	char buf[BUFSIZ];
    376	char test[] = { 23, 8, 68 };
    377	char *version;
    378	int show_version = 0;
    379	int show_funcs = 0;
    380	int show_printk = 0;
    381	ssize_t size = -1;
    382	int file_bigendian;
    383	int host_bigendian;
    384	int file_long_size;
    385	int file_page_size;
    386	struct tep_handle *pevent = NULL;
    387	int err;
    388
    389	repipe = __repipe;
    390	input_fd = fd;
    391
    392	if (do_read(buf, 3) < 0)
    393		return -1;
    394	if (memcmp(buf, test, 3) != 0) {
    395		pr_debug("no trace data in the file");
    396		return -1;
    397	}
    398
    399	if (do_read(buf, 7) < 0)
    400		return -1;
    401	if (memcmp(buf, "tracing", 7) != 0) {
    402		pr_debug("not a trace file (missing 'tracing' tag)");
    403		return -1;
    404	}
    405
    406	version = read_string();
    407	if (version == NULL)
    408		return -1;
    409	if (show_version)
    410		printf("version = %s\n", version);
    411
    412	if (do_read(buf, 1) < 0) {
    413		free(version);
    414		return -1;
    415	}
    416	file_bigendian = buf[0];
    417	host_bigendian = bigendian();
    418
    419	if (trace_event__init(tevent)) {
    420		pr_debug("trace_event__init failed");
    421		goto out;
    422	}
    423
    424	pevent = tevent->pevent;
    425
    426	tep_set_flag(pevent, TEP_NSEC_OUTPUT);
    427	tep_set_file_bigendian(pevent, file_bigendian);
    428	tep_set_local_bigendian(pevent, host_bigendian);
    429
    430	if (do_read(buf, 1) < 0)
    431		goto out;
    432	file_long_size = buf[0];
    433
    434	file_page_size = read4(pevent);
    435	if (!file_page_size)
    436		goto out;
    437
    438	tep_set_long_size(pevent, file_long_size);
    439	tep_set_page_size(pevent, file_page_size);
    440
    441	err = read_header_files(pevent);
    442	if (err)
    443		goto out;
    444	err = read_ftrace_files(pevent);
    445	if (err)
    446		goto out;
    447	err = read_event_files(pevent);
    448	if (err)
    449		goto out;
    450	err = read_proc_kallsyms(pevent);
    451	if (err)
    452		goto out;
    453	err = read_ftrace_printk(pevent);
    454	if (err)
    455		goto out;
    456	if (atof(version) >= 0.6) {
    457		err = read_saved_cmdline(pevent);
    458		if (err)
    459			goto out;
    460	}
    461
    462	size = trace_data_size;
    463	repipe = false;
    464
    465	if (show_funcs) {
    466		tep_print_funcs(pevent);
    467	} else if (show_printk) {
    468		tep_print_printk(pevent);
    469	}
    470
    471	pevent = NULL;
    472
    473out:
    474	if (pevent)
    475		trace_event__cleanup(tevent);
    476	free(version);
    477	return size;
    478}