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-info.c (11019B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2008,2009, Steven Rostedt <srostedt@redhat.com>
      4 */
      5#include <dirent.h>
      6#include <mntent.h>
      7#include <stdio.h>
      8#include <stdlib.h>
      9#include <string.h>
     10#include <stdarg.h>
     11#include <sys/types.h>
     12#include <sys/stat.h>
     13#include <sys/wait.h>
     14#include <fcntl.h>
     15#include <unistd.h>
     16#include <errno.h>
     17#include <stdbool.h>
     18#include <linux/list.h>
     19#include <linux/kernel.h>
     20#include <linux/zalloc.h>
     21#include <internal/lib.h> // page_size
     22
     23#include "trace-event.h"
     24#include <api/fs/tracing_path.h>
     25#include "evsel.h"
     26#include "debug.h"
     27
     28#define VERSION "0.6"
     29
     30static int output_fd;
     31
     32
     33int bigendian(void)
     34{
     35	unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
     36	unsigned int *ptr;
     37
     38	ptr = (unsigned int *)(void *)str;
     39	return *ptr == 0x01020304;
     40}
     41
     42/* unfortunately, you can not stat debugfs or proc files for size */
     43static int record_file(const char *file, ssize_t hdr_sz)
     44{
     45	unsigned long long size = 0;
     46	char buf[BUFSIZ], *sizep;
     47	off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR);
     48	int r, fd;
     49	int err = -EIO;
     50
     51	fd = open(file, O_RDONLY);
     52	if (fd < 0) {
     53		pr_debug("Can't read '%s'", file);
     54		return -errno;
     55	}
     56
     57	/* put in zeros for file size, then fill true size later */
     58	if (hdr_sz) {
     59		if (write(output_fd, &size, hdr_sz) != hdr_sz)
     60			goto out;
     61	}
     62
     63	do {
     64		r = read(fd, buf, BUFSIZ);
     65		if (r > 0) {
     66			size += r;
     67			if (write(output_fd, buf, r) != r)
     68				goto out;
     69		}
     70	} while (r > 0);
     71
     72	/* ugh, handle big-endian hdr_size == 4 */
     73	sizep = (char*)&size;
     74	if (bigendian())
     75		sizep += sizeof(u64) - hdr_sz;
     76
     77	if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) {
     78		pr_debug("writing file size failed\n");
     79		goto out;
     80	}
     81
     82	err = 0;
     83out:
     84	close(fd);
     85	return err;
     86}
     87
     88static int record_header_files(void)
     89{
     90	char *path = get_events_file("header_page");
     91	struct stat st;
     92	int err = -EIO;
     93
     94	if (!path) {
     95		pr_debug("can't get tracing/events/header_page");
     96		return -ENOMEM;
     97	}
     98
     99	if (stat(path, &st) < 0) {
    100		pr_debug("can't read '%s'", path);
    101		goto out;
    102	}
    103
    104	if (write(output_fd, "header_page", 12) != 12) {
    105		pr_debug("can't write header_page\n");
    106		goto out;
    107	}
    108
    109	if (record_file(path, 8) < 0) {
    110		pr_debug("can't record header_page file\n");
    111		goto out;
    112	}
    113
    114	put_events_file(path);
    115
    116	path = get_events_file("header_event");
    117	if (!path) {
    118		pr_debug("can't get tracing/events/header_event");
    119		err = -ENOMEM;
    120		goto out;
    121	}
    122
    123	if (stat(path, &st) < 0) {
    124		pr_debug("can't read '%s'", path);
    125		goto out;
    126	}
    127
    128	if (write(output_fd, "header_event", 13) != 13) {
    129		pr_debug("can't write header_event\n");
    130		goto out;
    131	}
    132
    133	if (record_file(path, 8) < 0) {
    134		pr_debug("can't record header_event file\n");
    135		goto out;
    136	}
    137
    138	err = 0;
    139out:
    140	put_events_file(path);
    141	return err;
    142}
    143
    144static bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
    145{
    146	while (tps) {
    147		if (!strcmp(sys, tps->name))
    148			return true;
    149		tps = tps->next;
    150	}
    151
    152	return false;
    153}
    154
    155#define for_each_event_tps(dir, dent, tps)			\
    156	while ((dent = readdir(dir)))				\
    157		if (dent->d_type == DT_DIR &&			\
    158		    (strcmp(dent->d_name, ".")) &&		\
    159		    (strcmp(dent->d_name, "..")))		\
    160
    161static int copy_event_system(const char *sys, struct tracepoint_path *tps)
    162{
    163	struct dirent *dent;
    164	struct stat st;
    165	char *format;
    166	DIR *dir;
    167	int count = 0;
    168	int ret;
    169	int err;
    170
    171	dir = opendir(sys);
    172	if (!dir) {
    173		pr_debug("can't read directory '%s'", sys);
    174		return -errno;
    175	}
    176
    177	for_each_event_tps(dir, dent, tps) {
    178		if (!name_in_tp_list(dent->d_name, tps))
    179			continue;
    180
    181		if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
    182			err = -ENOMEM;
    183			goto out;
    184		}
    185		ret = stat(format, &st);
    186		free(format);
    187		if (ret < 0)
    188			continue;
    189		count++;
    190	}
    191
    192	if (write(output_fd, &count, 4) != 4) {
    193		err = -EIO;
    194		pr_debug("can't write count\n");
    195		goto out;
    196	}
    197
    198	rewinddir(dir);
    199	for_each_event_tps(dir, dent, tps) {
    200		if (!name_in_tp_list(dent->d_name, tps))
    201			continue;
    202
    203		if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
    204			err = -ENOMEM;
    205			goto out;
    206		}
    207		ret = stat(format, &st);
    208
    209		if (ret >= 0) {
    210			err = record_file(format, 8);
    211			if (err) {
    212				free(format);
    213				goto out;
    214			}
    215		}
    216		free(format);
    217	}
    218	err = 0;
    219out:
    220	closedir(dir);
    221	return err;
    222}
    223
    224static int record_ftrace_files(struct tracepoint_path *tps)
    225{
    226	char *path;
    227	int ret;
    228
    229	path = get_events_file("ftrace");
    230	if (!path) {
    231		pr_debug("can't get tracing/events/ftrace");
    232		return -ENOMEM;
    233	}
    234
    235	ret = copy_event_system(path, tps);
    236
    237	put_tracing_file(path);
    238
    239	return ret;
    240}
    241
    242static bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
    243{
    244	while (tps) {
    245		if (!strcmp(sys, tps->system))
    246			return true;
    247		tps = tps->next;
    248	}
    249
    250	return false;
    251}
    252
    253static int record_event_files(struct tracepoint_path *tps)
    254{
    255	struct dirent *dent;
    256	struct stat st;
    257	char *path;
    258	char *sys;
    259	DIR *dir;
    260	int count = 0;
    261	int ret;
    262	int err;
    263
    264	path = get_tracing_file("events");
    265	if (!path) {
    266		pr_debug("can't get tracing/events");
    267		return -ENOMEM;
    268	}
    269
    270	dir = opendir(path);
    271	if (!dir) {
    272		err = -errno;
    273		pr_debug("can't read directory '%s'", path);
    274		goto out;
    275	}
    276
    277	for_each_event_tps(dir, dent, tps) {
    278		if (strcmp(dent->d_name, "ftrace") == 0 ||
    279		    !system_in_tp_list(dent->d_name, tps))
    280			continue;
    281
    282		count++;
    283	}
    284
    285	if (write(output_fd, &count, 4) != 4) {
    286		err = -EIO;
    287		pr_debug("can't write count\n");
    288		goto out;
    289	}
    290
    291	rewinddir(dir);
    292	for_each_event_tps(dir, dent, tps) {
    293		if (strcmp(dent->d_name, "ftrace") == 0 ||
    294		    !system_in_tp_list(dent->d_name, tps))
    295			continue;
    296
    297		if (asprintf(&sys, "%s/%s", path, dent->d_name) < 0) {
    298			err = -ENOMEM;
    299			goto out;
    300		}
    301		ret = stat(sys, &st);
    302		if (ret >= 0) {
    303			ssize_t size = strlen(dent->d_name) + 1;
    304
    305			if (write(output_fd, dent->d_name, size) != size ||
    306			    copy_event_system(sys, tps) < 0) {
    307				err = -EIO;
    308				free(sys);
    309				goto out;
    310			}
    311		}
    312		free(sys);
    313	}
    314	err = 0;
    315out:
    316	closedir(dir);
    317	put_tracing_file(path);
    318
    319	return err;
    320}
    321
    322static int record_proc_kallsyms(void)
    323{
    324	unsigned long long size = 0;
    325	/*
    326	 * Just to keep older perf.data file parsers happy, record a zero
    327	 * sized kallsyms file, i.e. do the same thing that was done when
    328	 * /proc/kallsyms (or something specified via --kallsyms, in a
    329	 * different path) couldn't be read.
    330	 */
    331	return write(output_fd, &size, 4) != 4 ? -EIO : 0;
    332}
    333
    334static int record_ftrace_printk(void)
    335{
    336	unsigned int size;
    337	char *path;
    338	struct stat st;
    339	int ret, err = 0;
    340
    341	path = get_tracing_file("printk_formats");
    342	if (!path) {
    343		pr_debug("can't get tracing/printk_formats");
    344		return -ENOMEM;
    345	}
    346
    347	ret = stat(path, &st);
    348	if (ret < 0) {
    349		/* not found */
    350		size = 0;
    351		if (write(output_fd, &size, 4) != 4)
    352			err = -EIO;
    353		goto out;
    354	}
    355	err = record_file(path, 4);
    356
    357out:
    358	put_tracing_file(path);
    359	return err;
    360}
    361
    362static int record_saved_cmdline(void)
    363{
    364	unsigned long long size;
    365	char *path;
    366	struct stat st;
    367	int ret, err = 0;
    368
    369	path = get_tracing_file("saved_cmdlines");
    370	if (!path) {
    371		pr_debug("can't get tracing/saved_cmdline");
    372		return -ENOMEM;
    373	}
    374
    375	ret = stat(path, &st);
    376	if (ret < 0) {
    377		/* not found */
    378		size = 0;
    379		if (write(output_fd, &size, 8) != 8)
    380			err = -EIO;
    381		goto out;
    382	}
    383	err = record_file(path, 8);
    384
    385out:
    386	put_tracing_file(path);
    387	return err;
    388}
    389
    390static void
    391put_tracepoints_path(struct tracepoint_path *tps)
    392{
    393	while (tps) {
    394		struct tracepoint_path *t = tps;
    395
    396		tps = tps->next;
    397		zfree(&t->name);
    398		zfree(&t->system);
    399		free(t);
    400	}
    401}
    402
    403static struct tracepoint_path *
    404get_tracepoints_path(struct list_head *pattrs)
    405{
    406	struct tracepoint_path path, *ppath = &path;
    407	struct evsel *pos;
    408	int nr_tracepoints = 0;
    409
    410	list_for_each_entry(pos, pattrs, core.node) {
    411		if (pos->core.attr.type != PERF_TYPE_TRACEPOINT)
    412			continue;
    413		++nr_tracepoints;
    414
    415		if (pos->name) {
    416			ppath->next = tracepoint_name_to_path(pos->name);
    417			if (ppath->next)
    418				goto next;
    419
    420			if (strchr(pos->name, ':') == NULL)
    421				goto try_id;
    422
    423			goto error;
    424		}
    425
    426try_id:
    427		ppath->next = tracepoint_id_to_path(pos->core.attr.config);
    428		if (!ppath->next) {
    429error:
    430			pr_debug("No memory to alloc tracepoints list\n");
    431			put_tracepoints_path(path.next);
    432			return NULL;
    433		}
    434next:
    435		ppath = ppath->next;
    436	}
    437
    438	return nr_tracepoints > 0 ? path.next : NULL;
    439}
    440
    441bool have_tracepoints(struct list_head *pattrs)
    442{
    443	struct evsel *pos;
    444
    445	list_for_each_entry(pos, pattrs, core.node)
    446		if (pos->core.attr.type == PERF_TYPE_TRACEPOINT)
    447			return true;
    448
    449	return false;
    450}
    451
    452static int tracing_data_header(void)
    453{
    454	char buf[20];
    455	ssize_t size;
    456
    457	/* just guessing this is someone's birthday.. ;) */
    458	buf[0] = 23;
    459	buf[1] = 8;
    460	buf[2] = 68;
    461	memcpy(buf + 3, "tracing", 7);
    462
    463	if (write(output_fd, buf, 10) != 10)
    464		return -1;
    465
    466	size = strlen(VERSION) + 1;
    467	if (write(output_fd, VERSION, size) != size)
    468		return -1;
    469
    470	/* save endian */
    471	if (bigendian())
    472		buf[0] = 1;
    473	else
    474		buf[0] = 0;
    475
    476	if (write(output_fd, buf, 1) != 1)
    477		return -1;
    478
    479	/* save size of long */
    480	buf[0] = sizeof(long);
    481	if (write(output_fd, buf, 1) != 1)
    482		return -1;
    483
    484	/* save page_size */
    485	if (write(output_fd, &page_size, 4) != 4)
    486		return -1;
    487
    488	return 0;
    489}
    490
    491struct tracing_data *tracing_data_get(struct list_head *pattrs,
    492				      int fd, bool temp)
    493{
    494	struct tracepoint_path *tps;
    495	struct tracing_data *tdata;
    496	int err;
    497
    498	output_fd = fd;
    499
    500	tps = get_tracepoints_path(pattrs);
    501	if (!tps)
    502		return NULL;
    503
    504	tdata = malloc(sizeof(*tdata));
    505	if (!tdata)
    506		return NULL;
    507
    508	tdata->temp = temp;
    509	tdata->size = 0;
    510
    511	if (temp) {
    512		int temp_fd;
    513
    514		snprintf(tdata->temp_file, sizeof(tdata->temp_file),
    515			 "/tmp/perf-XXXXXX");
    516		if (!mkstemp(tdata->temp_file)) {
    517			pr_debug("Can't make temp file");
    518			free(tdata);
    519			return NULL;
    520		}
    521
    522		temp_fd = open(tdata->temp_file, O_RDWR);
    523		if (temp_fd < 0) {
    524			pr_debug("Can't read '%s'", tdata->temp_file);
    525			free(tdata);
    526			return NULL;
    527		}
    528
    529		/*
    530		 * Set the temp file the default output, so all the
    531		 * tracing data are stored into it.
    532		 */
    533		output_fd = temp_fd;
    534	}
    535
    536	err = tracing_data_header();
    537	if (err)
    538		goto out;
    539	err = record_header_files();
    540	if (err)
    541		goto out;
    542	err = record_ftrace_files(tps);
    543	if (err)
    544		goto out;
    545	err = record_event_files(tps);
    546	if (err)
    547		goto out;
    548	err = record_proc_kallsyms();
    549	if (err)
    550		goto out;
    551	err = record_ftrace_printk();
    552	if (err)
    553		goto out;
    554	err = record_saved_cmdline();
    555
    556out:
    557	/*
    558	 * All tracing data are stored by now, we can restore
    559	 * the default output file in case we used temp file.
    560	 */
    561	if (temp) {
    562		tdata->size = lseek(output_fd, 0, SEEK_CUR);
    563		close(output_fd);
    564		output_fd = fd;
    565	}
    566
    567	if (err)
    568		zfree(&tdata);
    569
    570	put_tracepoints_path(tps);
    571	return tdata;
    572}
    573
    574int tracing_data_put(struct tracing_data *tdata)
    575{
    576	int err = 0;
    577
    578	if (tdata->temp) {
    579		err = record_file(tdata->temp_file, 0);
    580		unlink(tdata->temp_file);
    581	}
    582
    583	free(tdata);
    584	return err;
    585}
    586
    587int read_tracing_data(int fd, struct list_head *pattrs)
    588{
    589	int err;
    590	struct tracing_data *tdata;
    591
    592	/*
    593	 * We work over the real file, so we can write data
    594	 * directly, no temp file is needed.
    595	 */
    596	tdata = tracing_data_get(pattrs, fd, false);
    597	if (!tdata)
    598		return -ENOMEM;
    599
    600	err = tracing_data_put(tdata);
    601	return err;
    602}