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