18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#ifndef _GNU_SOURCE
38c2ecf20Sopenharmony_ci# define _GNU_SOURCE
48c2ecf20Sopenharmony_ci#endif
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <stdio.h>
78c2ecf20Sopenharmony_ci#include <stdlib.h>
88c2ecf20Sopenharmony_ci#include <string.h>
98c2ecf20Sopenharmony_ci#include <linux/string.h>
108c2ecf20Sopenharmony_ci#include <errno.h>
118c2ecf20Sopenharmony_ci#include <unistd.h>
128c2ecf20Sopenharmony_ci#include "fs.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "tracing_path.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic char tracing_mnt[PATH_MAX]  = "/sys/kernel/debug";
178c2ecf20Sopenharmony_cistatic char tracing_path[PATH_MAX]        = "/sys/kernel/debug/tracing";
188c2ecf20Sopenharmony_cistatic char tracing_events_path[PATH_MAX] = "/sys/kernel/debug/tracing/events";
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistatic void __tracing_path_set(const char *tracing, const char *mountpoint)
218c2ecf20Sopenharmony_ci{
228c2ecf20Sopenharmony_ci	snprintf(tracing_mnt, sizeof(tracing_mnt), "%s", mountpoint);
238c2ecf20Sopenharmony_ci	snprintf(tracing_path, sizeof(tracing_path), "%s/%s",
248c2ecf20Sopenharmony_ci		 mountpoint, tracing);
258c2ecf20Sopenharmony_ci	snprintf(tracing_events_path, sizeof(tracing_events_path), "%s/%s%s",
268c2ecf20Sopenharmony_ci		 mountpoint, tracing, "events");
278c2ecf20Sopenharmony_ci}
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic const char *tracing_path_tracefs_mount(void)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	const char *mnt;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	mnt = tracefs__mount();
348c2ecf20Sopenharmony_ci	if (!mnt)
358c2ecf20Sopenharmony_ci		return NULL;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	__tracing_path_set("", mnt);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	return tracing_path;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic const char *tracing_path_debugfs_mount(void)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	const char *mnt;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	mnt = debugfs__mount();
478c2ecf20Sopenharmony_ci	if (!mnt)
488c2ecf20Sopenharmony_ci		return NULL;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	__tracing_path_set("tracing/", mnt);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	return tracing_path;
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ciconst char *tracing_path_mount(void)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	const char *mnt;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	mnt = tracing_path_tracefs_mount();
608c2ecf20Sopenharmony_ci	if (mnt)
618c2ecf20Sopenharmony_ci		return mnt;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	mnt = tracing_path_debugfs_mount();
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	return mnt;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_civoid tracing_path_set(const char *mntpt)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	__tracing_path_set("tracing/", mntpt);
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cichar *get_tracing_file(const char *name)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	char *file;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	if (asprintf(&file, "%s/%s", tracing_path_mount(), name) < 0)
788c2ecf20Sopenharmony_ci		return NULL;
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return file;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_civoid put_tracing_file(char *file)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	free(file);
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cichar *get_events_file(const char *name)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	char *file;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	if (asprintf(&file, "%s/events/%s", tracing_path_mount(), name) < 0)
938c2ecf20Sopenharmony_ci		return NULL;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	return file;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_civoid put_events_file(char *file)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	free(file);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ciDIR *tracing_events__opendir(void)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	DIR *dir = NULL;
1068c2ecf20Sopenharmony_ci	char *path = get_tracing_file("events");
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	if (path) {
1098c2ecf20Sopenharmony_ci		dir = opendir(path);
1108c2ecf20Sopenharmony_ci		put_events_file(path);
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	return dir;
1148c2ecf20Sopenharmony_ci}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ciint tracing_path__strerror_open_tp(int err, char *buf, size_t size,
1178c2ecf20Sopenharmony_ci				   const char *sys, const char *name)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	char sbuf[128];
1208c2ecf20Sopenharmony_ci	char filename[PATH_MAX];
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	snprintf(filename, PATH_MAX, "%s/%s", sys, name ?: "*");
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	switch (err) {
1258c2ecf20Sopenharmony_ci	case ENOENT:
1268c2ecf20Sopenharmony_ci		/*
1278c2ecf20Sopenharmony_ci		 * We will get here if we can't find the tracepoint, but one of
1288c2ecf20Sopenharmony_ci		 * debugfs or tracefs is configured, which means you probably
1298c2ecf20Sopenharmony_ci		 * want some tracepoint which wasn't compiled in your kernel.
1308c2ecf20Sopenharmony_ci		 * - jirka
1318c2ecf20Sopenharmony_ci		 */
1328c2ecf20Sopenharmony_ci		if (debugfs__configured() || tracefs__configured()) {
1338c2ecf20Sopenharmony_ci			/* sdt markers */
1348c2ecf20Sopenharmony_ci			if (!strncmp(filename, "sdt_", 4)) {
1358c2ecf20Sopenharmony_ci				snprintf(buf, size,
1368c2ecf20Sopenharmony_ci					"Error:\tFile %s/%s not found.\n"
1378c2ecf20Sopenharmony_ci					"Hint:\tSDT event cannot be directly recorded on.\n"
1388c2ecf20Sopenharmony_ci					"\tPlease first use 'perf probe %s:%s' before recording it.\n",
1398c2ecf20Sopenharmony_ci					tracing_events_path, filename, sys, name);
1408c2ecf20Sopenharmony_ci			} else {
1418c2ecf20Sopenharmony_ci				snprintf(buf, size,
1428c2ecf20Sopenharmony_ci					 "Error:\tFile %s/%s not found.\n"
1438c2ecf20Sopenharmony_ci					 "Hint:\tPerhaps this kernel misses some CONFIG_ setting to enable this feature?.\n",
1448c2ecf20Sopenharmony_ci					 tracing_events_path, filename);
1458c2ecf20Sopenharmony_ci			}
1468c2ecf20Sopenharmony_ci			break;
1478c2ecf20Sopenharmony_ci		}
1488c2ecf20Sopenharmony_ci		snprintf(buf, size, "%s",
1498c2ecf20Sopenharmony_ci			 "Error:\tUnable to find debugfs/tracefs\n"
1508c2ecf20Sopenharmony_ci			 "Hint:\tWas your kernel compiled with debugfs/tracefs support?\n"
1518c2ecf20Sopenharmony_ci			 "Hint:\tIs the debugfs/tracefs filesystem mounted?\n"
1528c2ecf20Sopenharmony_ci			 "Hint:\tTry 'sudo mount -t debugfs nodev /sys/kernel/debug'");
1538c2ecf20Sopenharmony_ci		break;
1548c2ecf20Sopenharmony_ci	case EACCES: {
1558c2ecf20Sopenharmony_ci		snprintf(buf, size,
1568c2ecf20Sopenharmony_ci			 "Error:\tNo permissions to read %s/%s\n"
1578c2ecf20Sopenharmony_ci			 "Hint:\tTry 'sudo mount -o remount,mode=755 %s'\n",
1588c2ecf20Sopenharmony_ci			 tracing_events_path, filename, tracing_path_mount());
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci		break;
1618c2ecf20Sopenharmony_ci	default:
1628c2ecf20Sopenharmony_ci		snprintf(buf, size, "%s", str_error_r(err, sbuf, sizeof(sbuf)));
1638c2ecf20Sopenharmony_ci		break;
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	return 0;
1678c2ecf20Sopenharmony_ci}
168