18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2008,2009, Steven Rostedt <srostedt@redhat.com>
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#include <dirent.h>
68c2ecf20Sopenharmony_ci#include <mntent.h>
78c2ecf20Sopenharmony_ci#include <stdio.h>
88c2ecf20Sopenharmony_ci#include <stdlib.h>
98c2ecf20Sopenharmony_ci#include <string.h>
108c2ecf20Sopenharmony_ci#include <stdarg.h>
118c2ecf20Sopenharmony_ci#include <sys/types.h>
128c2ecf20Sopenharmony_ci#include <sys/stat.h>
138c2ecf20Sopenharmony_ci#include <sys/wait.h>
148c2ecf20Sopenharmony_ci#include <fcntl.h>
158c2ecf20Sopenharmony_ci#include <unistd.h>
168c2ecf20Sopenharmony_ci#include <errno.h>
178c2ecf20Sopenharmony_ci#include <stdbool.h>
188c2ecf20Sopenharmony_ci#include <linux/list.h>
198c2ecf20Sopenharmony_ci#include <linux/kernel.h>
208c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
218c2ecf20Sopenharmony_ci#include <internal/lib.h> // page_size
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include "trace-event.h"
248c2ecf20Sopenharmony_ci#include <api/fs/tracing_path.h>
258c2ecf20Sopenharmony_ci#include "evsel.h"
268c2ecf20Sopenharmony_ci#include "debug.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define VERSION "0.6"
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic int output_fd;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ciint bigendian(void)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	unsigned char str[] = { 0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0, 0x0};
368c2ecf20Sopenharmony_ci	unsigned int *ptr;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	ptr = (unsigned int *)(void *)str;
398c2ecf20Sopenharmony_ci	return *ptr == 0x01020304;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/* unfortunately, you can not stat debugfs or proc files for size */
438c2ecf20Sopenharmony_cistatic int record_file(const char *file, ssize_t hdr_sz)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	unsigned long long size = 0;
468c2ecf20Sopenharmony_ci	char buf[BUFSIZ], *sizep;
478c2ecf20Sopenharmony_ci	off_t hdr_pos = lseek(output_fd, 0, SEEK_CUR);
488c2ecf20Sopenharmony_ci	int r, fd;
498c2ecf20Sopenharmony_ci	int err = -EIO;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	fd = open(file, O_RDONLY);
528c2ecf20Sopenharmony_ci	if (fd < 0) {
538c2ecf20Sopenharmony_ci		pr_debug("Can't read '%s'", file);
548c2ecf20Sopenharmony_ci		return -errno;
558c2ecf20Sopenharmony_ci	}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	/* put in zeros for file size, then fill true size later */
588c2ecf20Sopenharmony_ci	if (hdr_sz) {
598c2ecf20Sopenharmony_ci		if (write(output_fd, &size, hdr_sz) != hdr_sz)
608c2ecf20Sopenharmony_ci			goto out;
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	do {
648c2ecf20Sopenharmony_ci		r = read(fd, buf, BUFSIZ);
658c2ecf20Sopenharmony_ci		if (r > 0) {
668c2ecf20Sopenharmony_ci			size += r;
678c2ecf20Sopenharmony_ci			if (write(output_fd, buf, r) != r)
688c2ecf20Sopenharmony_ci				goto out;
698c2ecf20Sopenharmony_ci		}
708c2ecf20Sopenharmony_ci	} while (r > 0);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	/* ugh, handle big-endian hdr_size == 4 */
738c2ecf20Sopenharmony_ci	sizep = (char*)&size;
748c2ecf20Sopenharmony_ci	if (bigendian())
758c2ecf20Sopenharmony_ci		sizep += sizeof(u64) - hdr_sz;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (hdr_sz && pwrite(output_fd, sizep, hdr_sz, hdr_pos) < 0) {
788c2ecf20Sopenharmony_ci		pr_debug("writing file size failed\n");
798c2ecf20Sopenharmony_ci		goto out;
808c2ecf20Sopenharmony_ci	}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	err = 0;
838c2ecf20Sopenharmony_ciout:
848c2ecf20Sopenharmony_ci	close(fd);
858c2ecf20Sopenharmony_ci	return err;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic int record_header_files(void)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	char *path = get_events_file("header_page");
918c2ecf20Sopenharmony_ci	struct stat st;
928c2ecf20Sopenharmony_ci	int err = -EIO;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (!path) {
958c2ecf20Sopenharmony_ci		pr_debug("can't get tracing/events/header_page");
968c2ecf20Sopenharmony_ci		return -ENOMEM;
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	if (stat(path, &st) < 0) {
1008c2ecf20Sopenharmony_ci		pr_debug("can't read '%s'", path);
1018c2ecf20Sopenharmony_ci		goto out;
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if (write(output_fd, "header_page", 12) != 12) {
1058c2ecf20Sopenharmony_ci		pr_debug("can't write header_page\n");
1068c2ecf20Sopenharmony_ci		goto out;
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (record_file(path, 8) < 0) {
1108c2ecf20Sopenharmony_ci		pr_debug("can't record header_page file\n");
1118c2ecf20Sopenharmony_ci		goto out;
1128c2ecf20Sopenharmony_ci	}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	put_events_file(path);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	path = get_events_file("header_event");
1178c2ecf20Sopenharmony_ci	if (!path) {
1188c2ecf20Sopenharmony_ci		pr_debug("can't get tracing/events/header_event");
1198c2ecf20Sopenharmony_ci		err = -ENOMEM;
1208c2ecf20Sopenharmony_ci		goto out;
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (stat(path, &st) < 0) {
1248c2ecf20Sopenharmony_ci		pr_debug("can't read '%s'", path);
1258c2ecf20Sopenharmony_ci		goto out;
1268c2ecf20Sopenharmony_ci	}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	if (write(output_fd, "header_event", 13) != 13) {
1298c2ecf20Sopenharmony_ci		pr_debug("can't write header_event\n");
1308c2ecf20Sopenharmony_ci		goto out;
1318c2ecf20Sopenharmony_ci	}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	if (record_file(path, 8) < 0) {
1348c2ecf20Sopenharmony_ci		pr_debug("can't record header_event file\n");
1358c2ecf20Sopenharmony_ci		goto out;
1368c2ecf20Sopenharmony_ci	}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	err = 0;
1398c2ecf20Sopenharmony_ciout:
1408c2ecf20Sopenharmony_ci	put_events_file(path);
1418c2ecf20Sopenharmony_ci	return err;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic bool name_in_tp_list(char *sys, struct tracepoint_path *tps)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	while (tps) {
1478c2ecf20Sopenharmony_ci		if (!strcmp(sys, tps->name))
1488c2ecf20Sopenharmony_ci			return true;
1498c2ecf20Sopenharmony_ci		tps = tps->next;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	return false;
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci#define for_each_event(dir, dent, tps)				\
1568c2ecf20Sopenharmony_ci	while ((dent = readdir(dir)))				\
1578c2ecf20Sopenharmony_ci		if (dent->d_type == DT_DIR &&			\
1588c2ecf20Sopenharmony_ci		    (strcmp(dent->d_name, ".")) &&		\
1598c2ecf20Sopenharmony_ci		    (strcmp(dent->d_name, "..")))		\
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cistatic int copy_event_system(const char *sys, struct tracepoint_path *tps)
1628c2ecf20Sopenharmony_ci{
1638c2ecf20Sopenharmony_ci	struct dirent *dent;
1648c2ecf20Sopenharmony_ci	struct stat st;
1658c2ecf20Sopenharmony_ci	char *format;
1668c2ecf20Sopenharmony_ci	DIR *dir;
1678c2ecf20Sopenharmony_ci	int count = 0;
1688c2ecf20Sopenharmony_ci	int ret;
1698c2ecf20Sopenharmony_ci	int err;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	dir = opendir(sys);
1728c2ecf20Sopenharmony_ci	if (!dir) {
1738c2ecf20Sopenharmony_ci		pr_debug("can't read directory '%s'", sys);
1748c2ecf20Sopenharmony_ci		return -errno;
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	for_each_event(dir, dent, tps) {
1788c2ecf20Sopenharmony_ci		if (!name_in_tp_list(dent->d_name, tps))
1798c2ecf20Sopenharmony_ci			continue;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci		if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
1828c2ecf20Sopenharmony_ci			err = -ENOMEM;
1838c2ecf20Sopenharmony_ci			goto out;
1848c2ecf20Sopenharmony_ci		}
1858c2ecf20Sopenharmony_ci		ret = stat(format, &st);
1868c2ecf20Sopenharmony_ci		free(format);
1878c2ecf20Sopenharmony_ci		if (ret < 0)
1888c2ecf20Sopenharmony_ci			continue;
1898c2ecf20Sopenharmony_ci		count++;
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if (write(output_fd, &count, 4) != 4) {
1938c2ecf20Sopenharmony_ci		err = -EIO;
1948c2ecf20Sopenharmony_ci		pr_debug("can't write count\n");
1958c2ecf20Sopenharmony_ci		goto out;
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	rewinddir(dir);
1998c2ecf20Sopenharmony_ci	for_each_event(dir, dent, tps) {
2008c2ecf20Sopenharmony_ci		if (!name_in_tp_list(dent->d_name, tps))
2018c2ecf20Sopenharmony_ci			continue;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci		if (asprintf(&format, "%s/%s/format", sys, dent->d_name) < 0) {
2048c2ecf20Sopenharmony_ci			err = -ENOMEM;
2058c2ecf20Sopenharmony_ci			goto out;
2068c2ecf20Sopenharmony_ci		}
2078c2ecf20Sopenharmony_ci		ret = stat(format, &st);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci		if (ret >= 0) {
2108c2ecf20Sopenharmony_ci			err = record_file(format, 8);
2118c2ecf20Sopenharmony_ci			if (err) {
2128c2ecf20Sopenharmony_ci				free(format);
2138c2ecf20Sopenharmony_ci				goto out;
2148c2ecf20Sopenharmony_ci			}
2158c2ecf20Sopenharmony_ci		}
2168c2ecf20Sopenharmony_ci		free(format);
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci	err = 0;
2198c2ecf20Sopenharmony_ciout:
2208c2ecf20Sopenharmony_ci	closedir(dir);
2218c2ecf20Sopenharmony_ci	return err;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_cistatic int record_ftrace_files(struct tracepoint_path *tps)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	char *path;
2278c2ecf20Sopenharmony_ci	int ret;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	path = get_events_file("ftrace");
2308c2ecf20Sopenharmony_ci	if (!path) {
2318c2ecf20Sopenharmony_ci		pr_debug("can't get tracing/events/ftrace");
2328c2ecf20Sopenharmony_ci		return -ENOMEM;
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	ret = copy_event_system(path, tps);
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	put_tracing_file(path);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	return ret;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic bool system_in_tp_list(char *sys, struct tracepoint_path *tps)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	while (tps) {
2458c2ecf20Sopenharmony_ci		if (!strcmp(sys, tps->system))
2468c2ecf20Sopenharmony_ci			return true;
2478c2ecf20Sopenharmony_ci		tps = tps->next;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	return false;
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic int record_event_files(struct tracepoint_path *tps)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	struct dirent *dent;
2568c2ecf20Sopenharmony_ci	struct stat st;
2578c2ecf20Sopenharmony_ci	char *path;
2588c2ecf20Sopenharmony_ci	char *sys;
2598c2ecf20Sopenharmony_ci	DIR *dir;
2608c2ecf20Sopenharmony_ci	int count = 0;
2618c2ecf20Sopenharmony_ci	int ret;
2628c2ecf20Sopenharmony_ci	int err;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	path = get_tracing_file("events");
2658c2ecf20Sopenharmony_ci	if (!path) {
2668c2ecf20Sopenharmony_ci		pr_debug("can't get tracing/events");
2678c2ecf20Sopenharmony_ci		return -ENOMEM;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	dir = opendir(path);
2718c2ecf20Sopenharmony_ci	if (!dir) {
2728c2ecf20Sopenharmony_ci		err = -errno;
2738c2ecf20Sopenharmony_ci		pr_debug("can't read directory '%s'", path);
2748c2ecf20Sopenharmony_ci		goto out;
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	for_each_event(dir, dent, tps) {
2788c2ecf20Sopenharmony_ci		if (strcmp(dent->d_name, "ftrace") == 0 ||
2798c2ecf20Sopenharmony_ci		    !system_in_tp_list(dent->d_name, tps))
2808c2ecf20Sopenharmony_ci			continue;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci		count++;
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	if (write(output_fd, &count, 4) != 4) {
2868c2ecf20Sopenharmony_ci		err = -EIO;
2878c2ecf20Sopenharmony_ci		pr_debug("can't write count\n");
2888c2ecf20Sopenharmony_ci		goto out;
2898c2ecf20Sopenharmony_ci	}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	rewinddir(dir);
2928c2ecf20Sopenharmony_ci	for_each_event(dir, dent, tps) {
2938c2ecf20Sopenharmony_ci		if (strcmp(dent->d_name, "ftrace") == 0 ||
2948c2ecf20Sopenharmony_ci		    !system_in_tp_list(dent->d_name, tps))
2958c2ecf20Sopenharmony_ci			continue;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		if (asprintf(&sys, "%s/%s", path, dent->d_name) < 0) {
2988c2ecf20Sopenharmony_ci			err = -ENOMEM;
2998c2ecf20Sopenharmony_ci			goto out;
3008c2ecf20Sopenharmony_ci		}
3018c2ecf20Sopenharmony_ci		ret = stat(sys, &st);
3028c2ecf20Sopenharmony_ci		if (ret >= 0) {
3038c2ecf20Sopenharmony_ci			ssize_t size = strlen(dent->d_name) + 1;
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci			if (write(output_fd, dent->d_name, size) != size ||
3068c2ecf20Sopenharmony_ci			    copy_event_system(sys, tps) < 0) {
3078c2ecf20Sopenharmony_ci				err = -EIO;
3088c2ecf20Sopenharmony_ci				free(sys);
3098c2ecf20Sopenharmony_ci				goto out;
3108c2ecf20Sopenharmony_ci			}
3118c2ecf20Sopenharmony_ci		}
3128c2ecf20Sopenharmony_ci		free(sys);
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci	err = 0;
3158c2ecf20Sopenharmony_ciout:
3168c2ecf20Sopenharmony_ci	closedir(dir);
3178c2ecf20Sopenharmony_ci	put_tracing_file(path);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	return err;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic int record_proc_kallsyms(void)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	unsigned long long size = 0;
3258c2ecf20Sopenharmony_ci	/*
3268c2ecf20Sopenharmony_ci	 * Just to keep older perf.data file parsers happy, record a zero
3278c2ecf20Sopenharmony_ci	 * sized kallsyms file, i.e. do the same thing that was done when
3288c2ecf20Sopenharmony_ci	 * /proc/kallsyms (or something specified via --kallsyms, in a
3298c2ecf20Sopenharmony_ci	 * different path) couldn't be read.
3308c2ecf20Sopenharmony_ci	 */
3318c2ecf20Sopenharmony_ci	return write(output_fd, &size, 4) != 4 ? -EIO : 0;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic int record_ftrace_printk(void)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	unsigned int size;
3378c2ecf20Sopenharmony_ci	char *path;
3388c2ecf20Sopenharmony_ci	struct stat st;
3398c2ecf20Sopenharmony_ci	int ret, err = 0;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	path = get_tracing_file("printk_formats");
3428c2ecf20Sopenharmony_ci	if (!path) {
3438c2ecf20Sopenharmony_ci		pr_debug("can't get tracing/printk_formats");
3448c2ecf20Sopenharmony_ci		return -ENOMEM;
3458c2ecf20Sopenharmony_ci	}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	ret = stat(path, &st);
3488c2ecf20Sopenharmony_ci	if (ret < 0) {
3498c2ecf20Sopenharmony_ci		/* not found */
3508c2ecf20Sopenharmony_ci		size = 0;
3518c2ecf20Sopenharmony_ci		if (write(output_fd, &size, 4) != 4)
3528c2ecf20Sopenharmony_ci			err = -EIO;
3538c2ecf20Sopenharmony_ci		goto out;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci	err = record_file(path, 4);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ciout:
3588c2ecf20Sopenharmony_ci	put_tracing_file(path);
3598c2ecf20Sopenharmony_ci	return err;
3608c2ecf20Sopenharmony_ci}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_cistatic int record_saved_cmdline(void)
3638c2ecf20Sopenharmony_ci{
3648c2ecf20Sopenharmony_ci	unsigned long long size;
3658c2ecf20Sopenharmony_ci	char *path;
3668c2ecf20Sopenharmony_ci	struct stat st;
3678c2ecf20Sopenharmony_ci	int ret, err = 0;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	path = get_tracing_file("saved_cmdlines");
3708c2ecf20Sopenharmony_ci	if (!path) {
3718c2ecf20Sopenharmony_ci		pr_debug("can't get tracing/saved_cmdline");
3728c2ecf20Sopenharmony_ci		return -ENOMEM;
3738c2ecf20Sopenharmony_ci	}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	ret = stat(path, &st);
3768c2ecf20Sopenharmony_ci	if (ret < 0) {
3778c2ecf20Sopenharmony_ci		/* not found */
3788c2ecf20Sopenharmony_ci		size = 0;
3798c2ecf20Sopenharmony_ci		if (write(output_fd, &size, 8) != 8)
3808c2ecf20Sopenharmony_ci			err = -EIO;
3818c2ecf20Sopenharmony_ci		goto out;
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci	err = record_file(path, 8);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ciout:
3868c2ecf20Sopenharmony_ci	put_tracing_file(path);
3878c2ecf20Sopenharmony_ci	return err;
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic void
3918c2ecf20Sopenharmony_ciput_tracepoints_path(struct tracepoint_path *tps)
3928c2ecf20Sopenharmony_ci{
3938c2ecf20Sopenharmony_ci	while (tps) {
3948c2ecf20Sopenharmony_ci		struct tracepoint_path *t = tps;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci		tps = tps->next;
3978c2ecf20Sopenharmony_ci		zfree(&t->name);
3988c2ecf20Sopenharmony_ci		zfree(&t->system);
3998c2ecf20Sopenharmony_ci		free(t);
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic struct tracepoint_path *
4048c2ecf20Sopenharmony_ciget_tracepoints_path(struct list_head *pattrs)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct tracepoint_path path, *ppath = &path;
4078c2ecf20Sopenharmony_ci	struct evsel *pos;
4088c2ecf20Sopenharmony_ci	int nr_tracepoints = 0;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	list_for_each_entry(pos, pattrs, core.node) {
4118c2ecf20Sopenharmony_ci		if (pos->core.attr.type != PERF_TYPE_TRACEPOINT)
4128c2ecf20Sopenharmony_ci			continue;
4138c2ecf20Sopenharmony_ci		++nr_tracepoints;
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci		if (pos->name) {
4168c2ecf20Sopenharmony_ci			ppath->next = tracepoint_name_to_path(pos->name);
4178c2ecf20Sopenharmony_ci			if (ppath->next)
4188c2ecf20Sopenharmony_ci				goto next;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci			if (strchr(pos->name, ':') == NULL)
4218c2ecf20Sopenharmony_ci				goto try_id;
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci			goto error;
4248c2ecf20Sopenharmony_ci		}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_citry_id:
4278c2ecf20Sopenharmony_ci		ppath->next = tracepoint_id_to_path(pos->core.attr.config);
4288c2ecf20Sopenharmony_ci		if (!ppath->next) {
4298c2ecf20Sopenharmony_cierror:
4308c2ecf20Sopenharmony_ci			pr_debug("No memory to alloc tracepoints list\n");
4318c2ecf20Sopenharmony_ci			put_tracepoints_path(path.next);
4328c2ecf20Sopenharmony_ci			return NULL;
4338c2ecf20Sopenharmony_ci		}
4348c2ecf20Sopenharmony_cinext:
4358c2ecf20Sopenharmony_ci		ppath = ppath->next;
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	return nr_tracepoints > 0 ? path.next : NULL;
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_cibool have_tracepoints(struct list_head *pattrs)
4428c2ecf20Sopenharmony_ci{
4438c2ecf20Sopenharmony_ci	struct evsel *pos;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	list_for_each_entry(pos, pattrs, core.node)
4468c2ecf20Sopenharmony_ci		if (pos->core.attr.type == PERF_TYPE_TRACEPOINT)
4478c2ecf20Sopenharmony_ci			return true;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	return false;
4508c2ecf20Sopenharmony_ci}
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_cistatic int tracing_data_header(void)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	char buf[20];
4558c2ecf20Sopenharmony_ci	ssize_t size;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	/* just guessing this is someone's birthday.. ;) */
4588c2ecf20Sopenharmony_ci	buf[0] = 23;
4598c2ecf20Sopenharmony_ci	buf[1] = 8;
4608c2ecf20Sopenharmony_ci	buf[2] = 68;
4618c2ecf20Sopenharmony_ci	memcpy(buf + 3, "tracing", 7);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	if (write(output_fd, buf, 10) != 10)
4648c2ecf20Sopenharmony_ci		return -1;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	size = strlen(VERSION) + 1;
4678c2ecf20Sopenharmony_ci	if (write(output_fd, VERSION, size) != size)
4688c2ecf20Sopenharmony_ci		return -1;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	/* save endian */
4718c2ecf20Sopenharmony_ci	if (bigendian())
4728c2ecf20Sopenharmony_ci		buf[0] = 1;
4738c2ecf20Sopenharmony_ci	else
4748c2ecf20Sopenharmony_ci		buf[0] = 0;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	if (write(output_fd, buf, 1) != 1)
4778c2ecf20Sopenharmony_ci		return -1;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	/* save size of long */
4808c2ecf20Sopenharmony_ci	buf[0] = sizeof(long);
4818c2ecf20Sopenharmony_ci	if (write(output_fd, buf, 1) != 1)
4828c2ecf20Sopenharmony_ci		return -1;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	/* save page_size */
4858c2ecf20Sopenharmony_ci	if (write(output_fd, &page_size, 4) != 4)
4868c2ecf20Sopenharmony_ci		return -1;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	return 0;
4898c2ecf20Sopenharmony_ci}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_cistruct tracing_data *tracing_data_get(struct list_head *pattrs,
4928c2ecf20Sopenharmony_ci				      int fd, bool temp)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	struct tracepoint_path *tps;
4958c2ecf20Sopenharmony_ci	struct tracing_data *tdata;
4968c2ecf20Sopenharmony_ci	int err;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	output_fd = fd;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	tps = get_tracepoints_path(pattrs);
5018c2ecf20Sopenharmony_ci	if (!tps)
5028c2ecf20Sopenharmony_ci		return NULL;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	tdata = malloc(sizeof(*tdata));
5058c2ecf20Sopenharmony_ci	if (!tdata)
5068c2ecf20Sopenharmony_ci		return NULL;
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	tdata->temp = temp;
5098c2ecf20Sopenharmony_ci	tdata->size = 0;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	if (temp) {
5128c2ecf20Sopenharmony_ci		int temp_fd;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci		snprintf(tdata->temp_file, sizeof(tdata->temp_file),
5158c2ecf20Sopenharmony_ci			 "/tmp/perf-XXXXXX");
5168c2ecf20Sopenharmony_ci		if (!mkstemp(tdata->temp_file)) {
5178c2ecf20Sopenharmony_ci			pr_debug("Can't make temp file");
5188c2ecf20Sopenharmony_ci			free(tdata);
5198c2ecf20Sopenharmony_ci			return NULL;
5208c2ecf20Sopenharmony_ci		}
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci		temp_fd = open(tdata->temp_file, O_RDWR);
5238c2ecf20Sopenharmony_ci		if (temp_fd < 0) {
5248c2ecf20Sopenharmony_ci			pr_debug("Can't read '%s'", tdata->temp_file);
5258c2ecf20Sopenharmony_ci			free(tdata);
5268c2ecf20Sopenharmony_ci			return NULL;
5278c2ecf20Sopenharmony_ci		}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci		/*
5308c2ecf20Sopenharmony_ci		 * Set the temp file the default output, so all the
5318c2ecf20Sopenharmony_ci		 * tracing data are stored into it.
5328c2ecf20Sopenharmony_ci		 */
5338c2ecf20Sopenharmony_ci		output_fd = temp_fd;
5348c2ecf20Sopenharmony_ci	}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	err = tracing_data_header();
5378c2ecf20Sopenharmony_ci	if (err)
5388c2ecf20Sopenharmony_ci		goto out;
5398c2ecf20Sopenharmony_ci	err = record_header_files();
5408c2ecf20Sopenharmony_ci	if (err)
5418c2ecf20Sopenharmony_ci		goto out;
5428c2ecf20Sopenharmony_ci	err = record_ftrace_files(tps);
5438c2ecf20Sopenharmony_ci	if (err)
5448c2ecf20Sopenharmony_ci		goto out;
5458c2ecf20Sopenharmony_ci	err = record_event_files(tps);
5468c2ecf20Sopenharmony_ci	if (err)
5478c2ecf20Sopenharmony_ci		goto out;
5488c2ecf20Sopenharmony_ci	err = record_proc_kallsyms();
5498c2ecf20Sopenharmony_ci	if (err)
5508c2ecf20Sopenharmony_ci		goto out;
5518c2ecf20Sopenharmony_ci	err = record_ftrace_printk();
5528c2ecf20Sopenharmony_ci	if (err)
5538c2ecf20Sopenharmony_ci		goto out;
5548c2ecf20Sopenharmony_ci	err = record_saved_cmdline();
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ciout:
5578c2ecf20Sopenharmony_ci	/*
5588c2ecf20Sopenharmony_ci	 * All tracing data are stored by now, we can restore
5598c2ecf20Sopenharmony_ci	 * the default output file in case we used temp file.
5608c2ecf20Sopenharmony_ci	 */
5618c2ecf20Sopenharmony_ci	if (temp) {
5628c2ecf20Sopenharmony_ci		tdata->size = lseek(output_fd, 0, SEEK_CUR);
5638c2ecf20Sopenharmony_ci		close(output_fd);
5648c2ecf20Sopenharmony_ci		output_fd = fd;
5658c2ecf20Sopenharmony_ci	}
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	if (err)
5688c2ecf20Sopenharmony_ci		zfree(&tdata);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	put_tracepoints_path(tps);
5718c2ecf20Sopenharmony_ci	return tdata;
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ciint tracing_data_put(struct tracing_data *tdata)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	int err = 0;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	if (tdata->temp) {
5798c2ecf20Sopenharmony_ci		err = record_file(tdata->temp_file, 0);
5808c2ecf20Sopenharmony_ci		unlink(tdata->temp_file);
5818c2ecf20Sopenharmony_ci	}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	free(tdata);
5848c2ecf20Sopenharmony_ci	return err;
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ciint read_tracing_data(int fd, struct list_head *pattrs)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	int err;
5908c2ecf20Sopenharmony_ci	struct tracing_data *tdata;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	/*
5938c2ecf20Sopenharmony_ci	 * We work over the real file, so we can write data
5948c2ecf20Sopenharmony_ci	 * directly, no temp file is needed.
5958c2ecf20Sopenharmony_ci	 */
5968c2ecf20Sopenharmony_ci	tdata = tracing_data_get(pattrs, fd, false);
5978c2ecf20Sopenharmony_ci	if (!tdata)
5988c2ecf20Sopenharmony_ci		return -ENOMEM;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	err = tracing_data_put(tdata);
6018c2ecf20Sopenharmony_ci	return err;
6028c2ecf20Sopenharmony_ci}
603