18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * probe-file.c : operate ftrace k/uprobe events files
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Written by Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <errno.h>
88c2ecf20Sopenharmony_ci#include <fcntl.h>
98c2ecf20Sopenharmony_ci#include <sys/stat.h>
108c2ecf20Sopenharmony_ci#include <sys/types.h>
118c2ecf20Sopenharmony_ci#include <sys/uio.h>
128c2ecf20Sopenharmony_ci#include <unistd.h>
138c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
148c2ecf20Sopenharmony_ci#include "namespaces.h"
158c2ecf20Sopenharmony_ci#include "event.h"
168c2ecf20Sopenharmony_ci#include "strlist.h"
178c2ecf20Sopenharmony_ci#include "strfilter.h"
188c2ecf20Sopenharmony_ci#include "debug.h"
198c2ecf20Sopenharmony_ci#include "build-id.h"
208c2ecf20Sopenharmony_ci#include "dso.h"
218c2ecf20Sopenharmony_ci#include "color.h"
228c2ecf20Sopenharmony_ci#include "symbol.h"
238c2ecf20Sopenharmony_ci#include "strbuf.h"
248c2ecf20Sopenharmony_ci#include <api/fs/tracing_path.h>
258c2ecf20Sopenharmony_ci#include "probe-event.h"
268c2ecf20Sopenharmony_ci#include "probe-file.h"
278c2ecf20Sopenharmony_ci#include "session.h"
288c2ecf20Sopenharmony_ci#include "perf_regs.h"
298c2ecf20Sopenharmony_ci#include "string2.h"
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci/* 4096 - 2 ('\n' + '\0') */
328c2ecf20Sopenharmony_ci#define MAX_CMDLEN 4094
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic void print_open_warning(int err, bool uprobe)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	char sbuf[STRERR_BUFSIZE];
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	if (err == -ENOENT) {
398c2ecf20Sopenharmony_ci		const char *config;
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci		if (uprobe)
428c2ecf20Sopenharmony_ci			config = "CONFIG_UPROBE_EVENTS";
438c2ecf20Sopenharmony_ci		else
448c2ecf20Sopenharmony_ci			config = "CONFIG_KPROBE_EVENTS";
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci		pr_warning("%cprobe_events file does not exist"
478c2ecf20Sopenharmony_ci			   " - please rebuild kernel with %s.\n",
488c2ecf20Sopenharmony_ci			   uprobe ? 'u' : 'k', config);
498c2ecf20Sopenharmony_ci	} else if (err == -ENOTSUP)
508c2ecf20Sopenharmony_ci		pr_warning("Tracefs or debugfs is not mounted.\n");
518c2ecf20Sopenharmony_ci	else
528c2ecf20Sopenharmony_ci		pr_warning("Failed to open %cprobe_events: %s\n",
538c2ecf20Sopenharmony_ci			   uprobe ? 'u' : 'k',
548c2ecf20Sopenharmony_ci			   str_error_r(-err, sbuf, sizeof(sbuf)));
558c2ecf20Sopenharmony_ci}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_cistatic void print_both_open_warning(int kerr, int uerr)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	/* Both kprobes and uprobes are disabled, warn it. */
608c2ecf20Sopenharmony_ci	if (kerr == -ENOTSUP && uerr == -ENOTSUP)
618c2ecf20Sopenharmony_ci		pr_warning("Tracefs or debugfs is not mounted.\n");
628c2ecf20Sopenharmony_ci	else if (kerr == -ENOENT && uerr == -ENOENT)
638c2ecf20Sopenharmony_ci		pr_warning("Please rebuild kernel with CONFIG_KPROBE_EVENTS "
648c2ecf20Sopenharmony_ci			   "or/and CONFIG_UPROBE_EVENTS.\n");
658c2ecf20Sopenharmony_ci	else {
668c2ecf20Sopenharmony_ci		char sbuf[STRERR_BUFSIZE];
678c2ecf20Sopenharmony_ci		pr_warning("Failed to open kprobe events: %s.\n",
688c2ecf20Sopenharmony_ci			   str_error_r(-kerr, sbuf, sizeof(sbuf)));
698c2ecf20Sopenharmony_ci		pr_warning("Failed to open uprobe events: %s.\n",
708c2ecf20Sopenharmony_ci			   str_error_r(-uerr, sbuf, sizeof(sbuf)));
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ciint open_trace_file(const char *trace_file, bool readwrite)
758c2ecf20Sopenharmony_ci{
768c2ecf20Sopenharmony_ci	char buf[PATH_MAX];
778c2ecf20Sopenharmony_ci	int ret;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	ret = e_snprintf(buf, PATH_MAX, "%s/%s", tracing_path_mount(), trace_file);
808c2ecf20Sopenharmony_ci	if (ret >= 0) {
818c2ecf20Sopenharmony_ci		pr_debug("Opening %s write=%d\n", buf, readwrite);
828c2ecf20Sopenharmony_ci		if (readwrite && !probe_event_dry_run)
838c2ecf20Sopenharmony_ci			ret = open(buf, O_RDWR | O_APPEND, 0);
848c2ecf20Sopenharmony_ci		else
858c2ecf20Sopenharmony_ci			ret = open(buf, O_RDONLY, 0);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci		if (ret < 0)
888c2ecf20Sopenharmony_ci			ret = -errno;
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci	return ret;
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic int open_kprobe_events(bool readwrite)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	return open_trace_file("kprobe_events", readwrite);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_cistatic int open_uprobe_events(bool readwrite)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	return open_trace_file("uprobe_events", readwrite);
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ciint probe_file__open(int flag)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	int fd;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (flag & PF_FL_UPROBE)
1088c2ecf20Sopenharmony_ci		fd = open_uprobe_events(flag & PF_FL_RW);
1098c2ecf20Sopenharmony_ci	else
1108c2ecf20Sopenharmony_ci		fd = open_kprobe_events(flag & PF_FL_RW);
1118c2ecf20Sopenharmony_ci	if (fd < 0)
1128c2ecf20Sopenharmony_ci		print_open_warning(fd, flag & PF_FL_UPROBE);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	return fd;
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ciint probe_file__open_both(int *kfd, int *ufd, int flag)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	if (!kfd || !ufd)
1208c2ecf20Sopenharmony_ci		return -EINVAL;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	*kfd = open_kprobe_events(flag & PF_FL_RW);
1238c2ecf20Sopenharmony_ci	*ufd = open_uprobe_events(flag & PF_FL_RW);
1248c2ecf20Sopenharmony_ci	if (*kfd < 0 && *ufd < 0) {
1258c2ecf20Sopenharmony_ci		print_both_open_warning(*kfd, *ufd);
1268c2ecf20Sopenharmony_ci		return *kfd;
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	return 0;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci/* Get raw string list of current kprobe_events  or uprobe_events */
1338c2ecf20Sopenharmony_cistruct strlist *probe_file__get_rawlist(int fd)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	int ret, idx, fddup;
1368c2ecf20Sopenharmony_ci	FILE *fp;
1378c2ecf20Sopenharmony_ci	char buf[MAX_CMDLEN];
1388c2ecf20Sopenharmony_ci	char *p;
1398c2ecf20Sopenharmony_ci	struct strlist *sl;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	if (fd < 0)
1428c2ecf20Sopenharmony_ci		return NULL;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	sl = strlist__new(NULL, NULL);
1458c2ecf20Sopenharmony_ci	if (sl == NULL)
1468c2ecf20Sopenharmony_ci		return NULL;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	fddup = dup(fd);
1498c2ecf20Sopenharmony_ci	if (fddup < 0)
1508c2ecf20Sopenharmony_ci		goto out_free_sl;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	fp = fdopen(fddup, "r");
1538c2ecf20Sopenharmony_ci	if (!fp)
1548c2ecf20Sopenharmony_ci		goto out_close_fddup;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	while (!feof(fp)) {
1578c2ecf20Sopenharmony_ci		p = fgets(buf, MAX_CMDLEN, fp);
1588c2ecf20Sopenharmony_ci		if (!p)
1598c2ecf20Sopenharmony_ci			break;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci		idx = strlen(p) - 1;
1628c2ecf20Sopenharmony_ci		if (p[idx] == '\n')
1638c2ecf20Sopenharmony_ci			p[idx] = '\0';
1648c2ecf20Sopenharmony_ci		ret = strlist__add(sl, buf);
1658c2ecf20Sopenharmony_ci		if (ret < 0) {
1668c2ecf20Sopenharmony_ci			pr_debug("strlist__add failed (%d)\n", ret);
1678c2ecf20Sopenharmony_ci			goto out_close_fp;
1688c2ecf20Sopenharmony_ci		}
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci	fclose(fp);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	return sl;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ciout_close_fp:
1758c2ecf20Sopenharmony_ci	fclose(fp);
1768c2ecf20Sopenharmony_ci	goto out_free_sl;
1778c2ecf20Sopenharmony_ciout_close_fddup:
1788c2ecf20Sopenharmony_ci	close(fddup);
1798c2ecf20Sopenharmony_ciout_free_sl:
1808c2ecf20Sopenharmony_ci	strlist__delete(sl);
1818c2ecf20Sopenharmony_ci	return NULL;
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic struct strlist *__probe_file__get_namelist(int fd, bool include_group)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	char buf[128];
1878c2ecf20Sopenharmony_ci	struct strlist *sl, *rawlist;
1888c2ecf20Sopenharmony_ci	struct str_node *ent;
1898c2ecf20Sopenharmony_ci	struct probe_trace_event tev;
1908c2ecf20Sopenharmony_ci	int ret = 0;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	memset(&tev, 0, sizeof(tev));
1938c2ecf20Sopenharmony_ci	rawlist = probe_file__get_rawlist(fd);
1948c2ecf20Sopenharmony_ci	if (!rawlist)
1958c2ecf20Sopenharmony_ci		return NULL;
1968c2ecf20Sopenharmony_ci	sl = strlist__new(NULL, NULL);
1978c2ecf20Sopenharmony_ci	strlist__for_each_entry(ent, rawlist) {
1988c2ecf20Sopenharmony_ci		ret = parse_probe_trace_command(ent->s, &tev);
1998c2ecf20Sopenharmony_ci		if (ret < 0)
2008c2ecf20Sopenharmony_ci			break;
2018c2ecf20Sopenharmony_ci		if (include_group) {
2028c2ecf20Sopenharmony_ci			ret = e_snprintf(buf, 128, "%s:%s", tev.group,
2038c2ecf20Sopenharmony_ci					tev.event);
2048c2ecf20Sopenharmony_ci			if (ret >= 0)
2058c2ecf20Sopenharmony_ci				ret = strlist__add(sl, buf);
2068c2ecf20Sopenharmony_ci		} else
2078c2ecf20Sopenharmony_ci			ret = strlist__add(sl, tev.event);
2088c2ecf20Sopenharmony_ci		clear_probe_trace_event(&tev);
2098c2ecf20Sopenharmony_ci		/* Skip if there is same name multi-probe event in the list */
2108c2ecf20Sopenharmony_ci		if (ret == -EEXIST)
2118c2ecf20Sopenharmony_ci			ret = 0;
2128c2ecf20Sopenharmony_ci		if (ret < 0)
2138c2ecf20Sopenharmony_ci			break;
2148c2ecf20Sopenharmony_ci	}
2158c2ecf20Sopenharmony_ci	strlist__delete(rawlist);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	if (ret < 0) {
2188c2ecf20Sopenharmony_ci		strlist__delete(sl);
2198c2ecf20Sopenharmony_ci		return NULL;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci	return sl;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci/* Get current perf-probe event names */
2258c2ecf20Sopenharmony_cistruct strlist *probe_file__get_namelist(int fd)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	return __probe_file__get_namelist(fd, false);
2288c2ecf20Sopenharmony_ci}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ciint probe_file__add_event(int fd, struct probe_trace_event *tev)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	int ret = 0;
2338c2ecf20Sopenharmony_ci	char *buf = synthesize_probe_trace_command(tev);
2348c2ecf20Sopenharmony_ci	char sbuf[STRERR_BUFSIZE];
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	if (!buf) {
2378c2ecf20Sopenharmony_ci		pr_debug("Failed to synthesize probe trace event.\n");
2388c2ecf20Sopenharmony_ci		return -EINVAL;
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	pr_debug("Writing event: %s\n", buf);
2428c2ecf20Sopenharmony_ci	if (!probe_event_dry_run) {
2438c2ecf20Sopenharmony_ci		if (write(fd, buf, strlen(buf)) < (int)strlen(buf)) {
2448c2ecf20Sopenharmony_ci			ret = -errno;
2458c2ecf20Sopenharmony_ci			pr_warning("Failed to write event: %s\n",
2468c2ecf20Sopenharmony_ci				   str_error_r(errno, sbuf, sizeof(sbuf)));
2478c2ecf20Sopenharmony_ci		}
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci	free(buf);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return ret;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic int __del_trace_probe_event(int fd, struct str_node *ent)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	char *p;
2578c2ecf20Sopenharmony_ci	char buf[128];
2588c2ecf20Sopenharmony_ci	int ret;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	/* Convert from perf-probe event to trace-probe event */
2618c2ecf20Sopenharmony_ci	ret = e_snprintf(buf, 128, "-:%s", ent->s);
2628c2ecf20Sopenharmony_ci	if (ret < 0)
2638c2ecf20Sopenharmony_ci		goto error;
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	p = strchr(buf + 2, ':');
2668c2ecf20Sopenharmony_ci	if (!p) {
2678c2ecf20Sopenharmony_ci		pr_debug("Internal error: %s should have ':' but not.\n",
2688c2ecf20Sopenharmony_ci			 ent->s);
2698c2ecf20Sopenharmony_ci		ret = -ENOTSUP;
2708c2ecf20Sopenharmony_ci		goto error;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci	*p = '/';
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	pr_debug("Writing event: %s\n", buf);
2758c2ecf20Sopenharmony_ci	ret = write(fd, buf, strlen(buf));
2768c2ecf20Sopenharmony_ci	if (ret < 0) {
2778c2ecf20Sopenharmony_ci		ret = -errno;
2788c2ecf20Sopenharmony_ci		goto error;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	return 0;
2828c2ecf20Sopenharmony_cierror:
2838c2ecf20Sopenharmony_ci	pr_warning("Failed to delete event: %s\n",
2848c2ecf20Sopenharmony_ci		   str_error_r(-ret, buf, sizeof(buf)));
2858c2ecf20Sopenharmony_ci	return ret;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ciint probe_file__get_events(int fd, struct strfilter *filter,
2898c2ecf20Sopenharmony_ci			   struct strlist *plist)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct strlist *namelist;
2928c2ecf20Sopenharmony_ci	struct str_node *ent;
2938c2ecf20Sopenharmony_ci	const char *p;
2948c2ecf20Sopenharmony_ci	int ret = -ENOENT;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (!plist)
2978c2ecf20Sopenharmony_ci		return -EINVAL;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	namelist = __probe_file__get_namelist(fd, true);
3008c2ecf20Sopenharmony_ci	if (!namelist)
3018c2ecf20Sopenharmony_ci		return -ENOENT;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	strlist__for_each_entry(ent, namelist) {
3048c2ecf20Sopenharmony_ci		p = strchr(ent->s, ':');
3058c2ecf20Sopenharmony_ci		if ((p && strfilter__compare(filter, p + 1)) ||
3068c2ecf20Sopenharmony_ci		    strfilter__compare(filter, ent->s)) {
3078c2ecf20Sopenharmony_ci			ret = strlist__add(plist, ent->s);
3088c2ecf20Sopenharmony_ci			if (ret == -ENOMEM) {
3098c2ecf20Sopenharmony_ci				pr_err("strlist__add failed with -ENOMEM\n");
3108c2ecf20Sopenharmony_ci				goto out;
3118c2ecf20Sopenharmony_ci			}
3128c2ecf20Sopenharmony_ci			ret = 0;
3138c2ecf20Sopenharmony_ci		}
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ciout:
3168c2ecf20Sopenharmony_ci	strlist__delete(namelist);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	return ret;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ciint probe_file__del_strlist(int fd, struct strlist *namelist)
3228c2ecf20Sopenharmony_ci{
3238c2ecf20Sopenharmony_ci	int ret = 0;
3248c2ecf20Sopenharmony_ci	struct str_node *ent;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	strlist__for_each_entry(ent, namelist) {
3278c2ecf20Sopenharmony_ci		ret = __del_trace_probe_event(fd, ent);
3288c2ecf20Sopenharmony_ci		if (ret < 0)
3298c2ecf20Sopenharmony_ci			break;
3308c2ecf20Sopenharmony_ci	}
3318c2ecf20Sopenharmony_ci	return ret;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ciint probe_file__del_events(int fd, struct strfilter *filter)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	struct strlist *namelist;
3378c2ecf20Sopenharmony_ci	int ret;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	namelist = strlist__new(NULL, NULL);
3408c2ecf20Sopenharmony_ci	if (!namelist)
3418c2ecf20Sopenharmony_ci		return -ENOMEM;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	ret = probe_file__get_events(fd, filter, namelist);
3448c2ecf20Sopenharmony_ci	if (ret < 0)
3458c2ecf20Sopenharmony_ci		goto out;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	ret = probe_file__del_strlist(fd, namelist);
3488c2ecf20Sopenharmony_ciout:
3498c2ecf20Sopenharmony_ci	strlist__delete(namelist);
3508c2ecf20Sopenharmony_ci	return ret;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci/* Caller must ensure to remove this entry from list */
3548c2ecf20Sopenharmony_cistatic void probe_cache_entry__delete(struct probe_cache_entry *entry)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	if (entry) {
3578c2ecf20Sopenharmony_ci		BUG_ON(!list_empty(&entry->node));
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci		strlist__delete(entry->tevlist);
3608c2ecf20Sopenharmony_ci		clear_perf_probe_event(&entry->pev);
3618c2ecf20Sopenharmony_ci		zfree(&entry->spev);
3628c2ecf20Sopenharmony_ci		free(entry);
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic struct probe_cache_entry *
3678c2ecf20Sopenharmony_ciprobe_cache_entry__new(struct perf_probe_event *pev)
3688c2ecf20Sopenharmony_ci{
3698c2ecf20Sopenharmony_ci	struct probe_cache_entry *entry = zalloc(sizeof(*entry));
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	if (entry) {
3728c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&entry->node);
3738c2ecf20Sopenharmony_ci		entry->tevlist = strlist__new(NULL, NULL);
3748c2ecf20Sopenharmony_ci		if (!entry->tevlist)
3758c2ecf20Sopenharmony_ci			zfree(&entry);
3768c2ecf20Sopenharmony_ci		else if (pev) {
3778c2ecf20Sopenharmony_ci			entry->spev = synthesize_perf_probe_command(pev);
3788c2ecf20Sopenharmony_ci			if (!entry->spev ||
3798c2ecf20Sopenharmony_ci			    perf_probe_event__copy(&entry->pev, pev) < 0) {
3808c2ecf20Sopenharmony_ci				probe_cache_entry__delete(entry);
3818c2ecf20Sopenharmony_ci				return NULL;
3828c2ecf20Sopenharmony_ci			}
3838c2ecf20Sopenharmony_ci		}
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	return entry;
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ciint probe_cache_entry__get_event(struct probe_cache_entry *entry,
3908c2ecf20Sopenharmony_ci				 struct probe_trace_event **tevs)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	struct probe_trace_event *tev;
3938c2ecf20Sopenharmony_ci	struct str_node *node;
3948c2ecf20Sopenharmony_ci	int ret, i;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	ret = strlist__nr_entries(entry->tevlist);
3978c2ecf20Sopenharmony_ci	if (ret > probe_conf.max_probes)
3988c2ecf20Sopenharmony_ci		return -E2BIG;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	*tevs = zalloc(ret * sizeof(*tev));
4018c2ecf20Sopenharmony_ci	if (!*tevs)
4028c2ecf20Sopenharmony_ci		return -ENOMEM;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	i = 0;
4058c2ecf20Sopenharmony_ci	strlist__for_each_entry(node, entry->tevlist) {
4068c2ecf20Sopenharmony_ci		tev = &(*tevs)[i++];
4078c2ecf20Sopenharmony_ci		ret = parse_probe_trace_command(node->s, tev);
4088c2ecf20Sopenharmony_ci		if (ret < 0)
4098c2ecf20Sopenharmony_ci			break;
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci	return i;
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci/* For the kernel probe caches, pass target = NULL or DSO__NAME_KALLSYMS */
4158c2ecf20Sopenharmony_cistatic int probe_cache__open(struct probe_cache *pcache, const char *target,
4168c2ecf20Sopenharmony_ci			     struct nsinfo *nsi)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	char cpath[PATH_MAX];
4198c2ecf20Sopenharmony_ci	char sbuildid[SBUILD_ID_SIZE];
4208c2ecf20Sopenharmony_ci	char *dir_name = NULL;
4218c2ecf20Sopenharmony_ci	bool is_kallsyms = false;
4228c2ecf20Sopenharmony_ci	int ret, fd;
4238c2ecf20Sopenharmony_ci	struct nscookie nsc;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	if (target && build_id_cache__cached(target)) {
4268c2ecf20Sopenharmony_ci		/* This is a cached buildid */
4278c2ecf20Sopenharmony_ci		strlcpy(sbuildid, target, SBUILD_ID_SIZE);
4288c2ecf20Sopenharmony_ci		dir_name = build_id_cache__linkname(sbuildid, NULL, 0);
4298c2ecf20Sopenharmony_ci		goto found;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	if (!target || !strcmp(target, DSO__NAME_KALLSYMS)) {
4338c2ecf20Sopenharmony_ci		target = DSO__NAME_KALLSYMS;
4348c2ecf20Sopenharmony_ci		is_kallsyms = true;
4358c2ecf20Sopenharmony_ci		ret = sysfs__sprintf_build_id("/", sbuildid);
4368c2ecf20Sopenharmony_ci	} else {
4378c2ecf20Sopenharmony_ci		nsinfo__mountns_enter(nsi, &nsc);
4388c2ecf20Sopenharmony_ci		ret = filename__sprintf_build_id(target, sbuildid);
4398c2ecf20Sopenharmony_ci		nsinfo__mountns_exit(&nsc);
4408c2ecf20Sopenharmony_ci	}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	if (ret < 0) {
4438c2ecf20Sopenharmony_ci		pr_debug("Failed to get build-id from %s.\n", target);
4448c2ecf20Sopenharmony_ci		return ret;
4458c2ecf20Sopenharmony_ci	}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	/* If we have no buildid cache, make it */
4488c2ecf20Sopenharmony_ci	if (!build_id_cache__cached(sbuildid)) {
4498c2ecf20Sopenharmony_ci		ret = build_id_cache__add_s(sbuildid, target, nsi,
4508c2ecf20Sopenharmony_ci					    is_kallsyms, NULL);
4518c2ecf20Sopenharmony_ci		if (ret < 0) {
4528c2ecf20Sopenharmony_ci			pr_debug("Failed to add build-id cache: %s\n", target);
4538c2ecf20Sopenharmony_ci			return ret;
4548c2ecf20Sopenharmony_ci		}
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	dir_name = build_id_cache__cachedir(sbuildid, target, nsi, is_kallsyms,
4588c2ecf20Sopenharmony_ci					    false);
4598c2ecf20Sopenharmony_cifound:
4608c2ecf20Sopenharmony_ci	if (!dir_name) {
4618c2ecf20Sopenharmony_ci		pr_debug("Failed to get cache from %s\n", target);
4628c2ecf20Sopenharmony_ci		return -ENOMEM;
4638c2ecf20Sopenharmony_ci	}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	snprintf(cpath, PATH_MAX, "%s/probes", dir_name);
4668c2ecf20Sopenharmony_ci	fd = open(cpath, O_CREAT | O_RDWR, 0644);
4678c2ecf20Sopenharmony_ci	if (fd < 0)
4688c2ecf20Sopenharmony_ci		pr_debug("Failed to open cache(%d): %s\n", fd, cpath);
4698c2ecf20Sopenharmony_ci	free(dir_name);
4708c2ecf20Sopenharmony_ci	pcache->fd = fd;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci	return fd;
4738c2ecf20Sopenharmony_ci}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_cistatic int probe_cache__load(struct probe_cache *pcache)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	struct probe_cache_entry *entry = NULL;
4788c2ecf20Sopenharmony_ci	char buf[MAX_CMDLEN], *p;
4798c2ecf20Sopenharmony_ci	int ret = 0, fddup;
4808c2ecf20Sopenharmony_ci	FILE *fp;
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	fddup = dup(pcache->fd);
4838c2ecf20Sopenharmony_ci	if (fddup < 0)
4848c2ecf20Sopenharmony_ci		return -errno;
4858c2ecf20Sopenharmony_ci	fp = fdopen(fddup, "r");
4868c2ecf20Sopenharmony_ci	if (!fp) {
4878c2ecf20Sopenharmony_ci		close(fddup);
4888c2ecf20Sopenharmony_ci		return -EINVAL;
4898c2ecf20Sopenharmony_ci	}
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci	while (!feof(fp)) {
4928c2ecf20Sopenharmony_ci		if (!fgets(buf, MAX_CMDLEN, fp))
4938c2ecf20Sopenharmony_ci			break;
4948c2ecf20Sopenharmony_ci		p = strchr(buf, '\n');
4958c2ecf20Sopenharmony_ci		if (p)
4968c2ecf20Sopenharmony_ci			*p = '\0';
4978c2ecf20Sopenharmony_ci		/* #perf_probe_event or %sdt_event */
4988c2ecf20Sopenharmony_ci		if (buf[0] == '#' || buf[0] == '%') {
4998c2ecf20Sopenharmony_ci			entry = probe_cache_entry__new(NULL);
5008c2ecf20Sopenharmony_ci			if (!entry) {
5018c2ecf20Sopenharmony_ci				ret = -ENOMEM;
5028c2ecf20Sopenharmony_ci				goto out;
5038c2ecf20Sopenharmony_ci			}
5048c2ecf20Sopenharmony_ci			if (buf[0] == '%')
5058c2ecf20Sopenharmony_ci				entry->sdt = true;
5068c2ecf20Sopenharmony_ci			entry->spev = strdup(buf + 1);
5078c2ecf20Sopenharmony_ci			if (entry->spev)
5088c2ecf20Sopenharmony_ci				ret = parse_perf_probe_command(buf + 1,
5098c2ecf20Sopenharmony_ci								&entry->pev);
5108c2ecf20Sopenharmony_ci			else
5118c2ecf20Sopenharmony_ci				ret = -ENOMEM;
5128c2ecf20Sopenharmony_ci			if (ret < 0) {
5138c2ecf20Sopenharmony_ci				probe_cache_entry__delete(entry);
5148c2ecf20Sopenharmony_ci				goto out;
5158c2ecf20Sopenharmony_ci			}
5168c2ecf20Sopenharmony_ci			list_add_tail(&entry->node, &pcache->entries);
5178c2ecf20Sopenharmony_ci		} else {	/* trace_probe_event */
5188c2ecf20Sopenharmony_ci			if (!entry) {
5198c2ecf20Sopenharmony_ci				ret = -EINVAL;
5208c2ecf20Sopenharmony_ci				goto out;
5218c2ecf20Sopenharmony_ci			}
5228c2ecf20Sopenharmony_ci			ret = strlist__add(entry->tevlist, buf);
5238c2ecf20Sopenharmony_ci			if (ret == -ENOMEM) {
5248c2ecf20Sopenharmony_ci				pr_err("strlist__add failed with -ENOMEM\n");
5258c2ecf20Sopenharmony_ci				goto out;
5268c2ecf20Sopenharmony_ci			}
5278c2ecf20Sopenharmony_ci		}
5288c2ecf20Sopenharmony_ci	}
5298c2ecf20Sopenharmony_ciout:
5308c2ecf20Sopenharmony_ci	fclose(fp);
5318c2ecf20Sopenharmony_ci	return ret;
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_cistatic struct probe_cache *probe_cache__alloc(void)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	struct probe_cache *pcache = zalloc(sizeof(*pcache));
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	if (pcache) {
5398c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&pcache->entries);
5408c2ecf20Sopenharmony_ci		pcache->fd = -EINVAL;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci	return pcache;
5438c2ecf20Sopenharmony_ci}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_civoid probe_cache__purge(struct probe_cache *pcache)
5468c2ecf20Sopenharmony_ci{
5478c2ecf20Sopenharmony_ci	struct probe_cache_entry *entry, *n;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	list_for_each_entry_safe(entry, n, &pcache->entries, node) {
5508c2ecf20Sopenharmony_ci		list_del_init(&entry->node);
5518c2ecf20Sopenharmony_ci		probe_cache_entry__delete(entry);
5528c2ecf20Sopenharmony_ci	}
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_civoid probe_cache__delete(struct probe_cache *pcache)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	if (!pcache)
5588c2ecf20Sopenharmony_ci		return;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	probe_cache__purge(pcache);
5618c2ecf20Sopenharmony_ci	if (pcache->fd > 0)
5628c2ecf20Sopenharmony_ci		close(pcache->fd);
5638c2ecf20Sopenharmony_ci	free(pcache);
5648c2ecf20Sopenharmony_ci}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_cistruct probe_cache *probe_cache__new(const char *target, struct nsinfo *nsi)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	struct probe_cache *pcache = probe_cache__alloc();
5698c2ecf20Sopenharmony_ci	int ret;
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	if (!pcache)
5728c2ecf20Sopenharmony_ci		return NULL;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	ret = probe_cache__open(pcache, target, nsi);
5758c2ecf20Sopenharmony_ci	if (ret < 0) {
5768c2ecf20Sopenharmony_ci		pr_debug("Cache open error: %d\n", ret);
5778c2ecf20Sopenharmony_ci		goto out_err;
5788c2ecf20Sopenharmony_ci	}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	ret = probe_cache__load(pcache);
5818c2ecf20Sopenharmony_ci	if (ret < 0) {
5828c2ecf20Sopenharmony_ci		pr_debug("Cache read error: %d\n", ret);
5838c2ecf20Sopenharmony_ci		goto out_err;
5848c2ecf20Sopenharmony_ci	}
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	return pcache;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ciout_err:
5898c2ecf20Sopenharmony_ci	probe_cache__delete(pcache);
5908c2ecf20Sopenharmony_ci	return NULL;
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic bool streql(const char *a, const char *b)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	if (a == b)
5968c2ecf20Sopenharmony_ci		return true;
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_ci	if (!a || !b)
5998c2ecf20Sopenharmony_ci		return false;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	return !strcmp(a, b);
6028c2ecf20Sopenharmony_ci}
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_cistruct probe_cache_entry *
6058c2ecf20Sopenharmony_ciprobe_cache__find(struct probe_cache *pcache, struct perf_probe_event *pev)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	struct probe_cache_entry *entry = NULL;
6088c2ecf20Sopenharmony_ci	char *cmd = synthesize_perf_probe_command(pev);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	if (!cmd)
6118c2ecf20Sopenharmony_ci		return NULL;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	for_each_probe_cache_entry(entry, pcache) {
6148c2ecf20Sopenharmony_ci		if (pev->sdt) {
6158c2ecf20Sopenharmony_ci			if (entry->pev.event &&
6168c2ecf20Sopenharmony_ci			    streql(entry->pev.event, pev->event) &&
6178c2ecf20Sopenharmony_ci			    (!pev->group ||
6188c2ecf20Sopenharmony_ci			     streql(entry->pev.group, pev->group)))
6198c2ecf20Sopenharmony_ci				goto found;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci			continue;
6228c2ecf20Sopenharmony_ci		}
6238c2ecf20Sopenharmony_ci		/* Hit if same event name or same command-string */
6248c2ecf20Sopenharmony_ci		if ((pev->event &&
6258c2ecf20Sopenharmony_ci		     (streql(entry->pev.group, pev->group) &&
6268c2ecf20Sopenharmony_ci		      streql(entry->pev.event, pev->event))) ||
6278c2ecf20Sopenharmony_ci		    (!strcmp(entry->spev, cmd)))
6288c2ecf20Sopenharmony_ci			goto found;
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci	entry = NULL;
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_cifound:
6338c2ecf20Sopenharmony_ci	free(cmd);
6348c2ecf20Sopenharmony_ci	return entry;
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_cistruct probe_cache_entry *
6388c2ecf20Sopenharmony_ciprobe_cache__find_by_name(struct probe_cache *pcache,
6398c2ecf20Sopenharmony_ci			  const char *group, const char *event)
6408c2ecf20Sopenharmony_ci{
6418c2ecf20Sopenharmony_ci	struct probe_cache_entry *entry = NULL;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	for_each_probe_cache_entry(entry, pcache) {
6448c2ecf20Sopenharmony_ci		/* Hit if same event name or same command-string */
6458c2ecf20Sopenharmony_ci		if (streql(entry->pev.group, group) &&
6468c2ecf20Sopenharmony_ci		    streql(entry->pev.event, event))
6478c2ecf20Sopenharmony_ci			goto found;
6488c2ecf20Sopenharmony_ci	}
6498c2ecf20Sopenharmony_ci	entry = NULL;
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_cifound:
6528c2ecf20Sopenharmony_ci	return entry;
6538c2ecf20Sopenharmony_ci}
6548c2ecf20Sopenharmony_ci
6558c2ecf20Sopenharmony_ciint probe_cache__add_entry(struct probe_cache *pcache,
6568c2ecf20Sopenharmony_ci			   struct perf_probe_event *pev,
6578c2ecf20Sopenharmony_ci			   struct probe_trace_event *tevs, int ntevs)
6588c2ecf20Sopenharmony_ci{
6598c2ecf20Sopenharmony_ci	struct probe_cache_entry *entry = NULL;
6608c2ecf20Sopenharmony_ci	char *command;
6618c2ecf20Sopenharmony_ci	int i, ret = 0;
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci	if (!pcache || !pev || !tevs || ntevs <= 0) {
6648c2ecf20Sopenharmony_ci		ret = -EINVAL;
6658c2ecf20Sopenharmony_ci		goto out_err;
6668c2ecf20Sopenharmony_ci	}
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	/* Remove old cache entry */
6698c2ecf20Sopenharmony_ci	entry = probe_cache__find(pcache, pev);
6708c2ecf20Sopenharmony_ci	if (entry) {
6718c2ecf20Sopenharmony_ci		list_del_init(&entry->node);
6728c2ecf20Sopenharmony_ci		probe_cache_entry__delete(entry);
6738c2ecf20Sopenharmony_ci	}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	ret = -ENOMEM;
6768c2ecf20Sopenharmony_ci	entry = probe_cache_entry__new(pev);
6778c2ecf20Sopenharmony_ci	if (!entry)
6788c2ecf20Sopenharmony_ci		goto out_err;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	for (i = 0; i < ntevs; i++) {
6818c2ecf20Sopenharmony_ci		if (!tevs[i].point.symbol)
6828c2ecf20Sopenharmony_ci			continue;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci		command = synthesize_probe_trace_command(&tevs[i]);
6858c2ecf20Sopenharmony_ci		if (!command)
6868c2ecf20Sopenharmony_ci			goto out_err;
6878c2ecf20Sopenharmony_ci		ret = strlist__add(entry->tevlist, command);
6888c2ecf20Sopenharmony_ci		if (ret == -ENOMEM) {
6898c2ecf20Sopenharmony_ci			pr_err("strlist__add failed with -ENOMEM\n");
6908c2ecf20Sopenharmony_ci			goto out_err;
6918c2ecf20Sopenharmony_ci		}
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci		free(command);
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci	list_add_tail(&entry->node, &pcache->entries);
6968c2ecf20Sopenharmony_ci	pr_debug("Added probe cache: %d\n", ntevs);
6978c2ecf20Sopenharmony_ci	return 0;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ciout_err:
7008c2ecf20Sopenharmony_ci	pr_debug("Failed to add probe caches\n");
7018c2ecf20Sopenharmony_ci	probe_cache_entry__delete(entry);
7028c2ecf20Sopenharmony_ci	return ret;
7038c2ecf20Sopenharmony_ci}
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci#ifdef HAVE_GELF_GETNOTE_SUPPORT
7068c2ecf20Sopenharmony_cistatic unsigned long long sdt_note__get_addr(struct sdt_note *note)
7078c2ecf20Sopenharmony_ci{
7088c2ecf20Sopenharmony_ci	return note->bit32 ?
7098c2ecf20Sopenharmony_ci		(unsigned long long)note->addr.a32[SDT_NOTE_IDX_LOC] :
7108c2ecf20Sopenharmony_ci		(unsigned long long)note->addr.a64[SDT_NOTE_IDX_LOC];
7118c2ecf20Sopenharmony_ci}
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_cistatic unsigned long long sdt_note__get_ref_ctr_offset(struct sdt_note *note)
7148c2ecf20Sopenharmony_ci{
7158c2ecf20Sopenharmony_ci	return note->bit32 ?
7168c2ecf20Sopenharmony_ci		(unsigned long long)note->addr.a32[SDT_NOTE_IDX_REFCTR] :
7178c2ecf20Sopenharmony_ci		(unsigned long long)note->addr.a64[SDT_NOTE_IDX_REFCTR];
7188c2ecf20Sopenharmony_ci}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_cistatic const char * const type_to_suffix[] = {
7218c2ecf20Sopenharmony_ci	":s64", "", "", "", ":s32", "", ":s16", ":s8",
7228c2ecf20Sopenharmony_ci	"", ":u8", ":u16", "", ":u32", "", "", "", ":u64"
7238c2ecf20Sopenharmony_ci};
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci/*
7268c2ecf20Sopenharmony_ci * Isolate the string number and convert it into a decimal value;
7278c2ecf20Sopenharmony_ci * this will be an index to get suffix of the uprobe name (defining
7288c2ecf20Sopenharmony_ci * the type)
7298c2ecf20Sopenharmony_ci */
7308c2ecf20Sopenharmony_cistatic int sdt_arg_parse_size(char *n_ptr, const char **suffix)
7318c2ecf20Sopenharmony_ci{
7328c2ecf20Sopenharmony_ci	long type_idx;
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	type_idx = strtol(n_ptr, NULL, 10);
7358c2ecf20Sopenharmony_ci	if (type_idx < -8 || type_idx > 8) {
7368c2ecf20Sopenharmony_ci		pr_debug4("Failed to get a valid sdt type\n");
7378c2ecf20Sopenharmony_ci		return -1;
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	*suffix = type_to_suffix[type_idx + 8];
7418c2ecf20Sopenharmony_ci	return 0;
7428c2ecf20Sopenharmony_ci}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_cistatic int synthesize_sdt_probe_arg(struct strbuf *buf, int i, const char *arg)
7458c2ecf20Sopenharmony_ci{
7468c2ecf20Sopenharmony_ci	char *op, *desc = strdup(arg), *new_op = NULL;
7478c2ecf20Sopenharmony_ci	const char *suffix = "";
7488c2ecf20Sopenharmony_ci	int ret = -1;
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	if (desc == NULL) {
7518c2ecf20Sopenharmony_ci		pr_debug4("Allocation error\n");
7528c2ecf20Sopenharmony_ci		return ret;
7538c2ecf20Sopenharmony_ci	}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	/*
7568c2ecf20Sopenharmony_ci	 * Argument is in N@OP format. N is size of the argument and OP is
7578c2ecf20Sopenharmony_ci	 * the actual assembly operand. N can be omitted; in that case
7588c2ecf20Sopenharmony_ci	 * argument is just OP(without @).
7598c2ecf20Sopenharmony_ci	 */
7608c2ecf20Sopenharmony_ci	op = strchr(desc, '@');
7618c2ecf20Sopenharmony_ci	if (op) {
7628c2ecf20Sopenharmony_ci		op[0] = '\0';
7638c2ecf20Sopenharmony_ci		op++;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci		if (sdt_arg_parse_size(desc, &suffix))
7668c2ecf20Sopenharmony_ci			goto error;
7678c2ecf20Sopenharmony_ci	} else {
7688c2ecf20Sopenharmony_ci		op = desc;
7698c2ecf20Sopenharmony_ci	}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	ret = arch_sdt_arg_parse_op(op, &new_op);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	if (ret < 0)
7748c2ecf20Sopenharmony_ci		goto error;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	if (ret == SDT_ARG_VALID) {
7778c2ecf20Sopenharmony_ci		ret = strbuf_addf(buf, " arg%d=%s%s", i + 1, new_op, suffix);
7788c2ecf20Sopenharmony_ci		if (ret < 0)
7798c2ecf20Sopenharmony_ci			goto error;
7808c2ecf20Sopenharmony_ci	}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	ret = 0;
7838c2ecf20Sopenharmony_cierror:
7848c2ecf20Sopenharmony_ci	free(desc);
7858c2ecf20Sopenharmony_ci	free(new_op);
7868c2ecf20Sopenharmony_ci	return ret;
7878c2ecf20Sopenharmony_ci}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_cistatic char *synthesize_sdt_probe_command(struct sdt_note *note,
7908c2ecf20Sopenharmony_ci					const char *pathname,
7918c2ecf20Sopenharmony_ci					const char *sdtgrp)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	struct strbuf buf;
7948c2ecf20Sopenharmony_ci	char *ret = NULL;
7958c2ecf20Sopenharmony_ci	int i, args_count, err;
7968c2ecf20Sopenharmony_ci	unsigned long long ref_ctr_offset;
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	if (strbuf_init(&buf, 32) < 0)
7998c2ecf20Sopenharmony_ci		return NULL;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	err = strbuf_addf(&buf, "p:%s/%s %s:0x%llx",
8028c2ecf20Sopenharmony_ci			sdtgrp, note->name, pathname,
8038c2ecf20Sopenharmony_ci			sdt_note__get_addr(note));
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	ref_ctr_offset = sdt_note__get_ref_ctr_offset(note);
8068c2ecf20Sopenharmony_ci	if (ref_ctr_offset && err >= 0)
8078c2ecf20Sopenharmony_ci		err = strbuf_addf(&buf, "(0x%llx)", ref_ctr_offset);
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	if (err < 0)
8108c2ecf20Sopenharmony_ci		goto error;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	if (!note->args)
8138c2ecf20Sopenharmony_ci		goto out;
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	if (note->args) {
8168c2ecf20Sopenharmony_ci		char **args = argv_split(note->args, &args_count);
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci		if (args == NULL)
8198c2ecf20Sopenharmony_ci			goto error;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci		for (i = 0; i < args_count; ++i) {
8228c2ecf20Sopenharmony_ci			if (synthesize_sdt_probe_arg(&buf, i, args[i]) < 0) {
8238c2ecf20Sopenharmony_ci				argv_free(args);
8248c2ecf20Sopenharmony_ci				goto error;
8258c2ecf20Sopenharmony_ci			}
8268c2ecf20Sopenharmony_ci		}
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci		argv_free(args);
8298c2ecf20Sopenharmony_ci	}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ciout:
8328c2ecf20Sopenharmony_ci	ret = strbuf_detach(&buf, NULL);
8338c2ecf20Sopenharmony_cierror:
8348c2ecf20Sopenharmony_ci	strbuf_release(&buf);
8358c2ecf20Sopenharmony_ci	return ret;
8368c2ecf20Sopenharmony_ci}
8378c2ecf20Sopenharmony_ci
8388c2ecf20Sopenharmony_ciint probe_cache__scan_sdt(struct probe_cache *pcache, const char *pathname)
8398c2ecf20Sopenharmony_ci{
8408c2ecf20Sopenharmony_ci	struct probe_cache_entry *entry = NULL;
8418c2ecf20Sopenharmony_ci	struct list_head sdtlist;
8428c2ecf20Sopenharmony_ci	struct sdt_note *note;
8438c2ecf20Sopenharmony_ci	char *buf;
8448c2ecf20Sopenharmony_ci	char sdtgrp[64];
8458c2ecf20Sopenharmony_ci	int ret;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&sdtlist);
8488c2ecf20Sopenharmony_ci	ret = get_sdt_note_list(&sdtlist, pathname);
8498c2ecf20Sopenharmony_ci	if (ret < 0) {
8508c2ecf20Sopenharmony_ci		pr_debug4("Failed to get sdt note: %d\n", ret);
8518c2ecf20Sopenharmony_ci		return ret;
8528c2ecf20Sopenharmony_ci	}
8538c2ecf20Sopenharmony_ci	list_for_each_entry(note, &sdtlist, note_list) {
8548c2ecf20Sopenharmony_ci		ret = snprintf(sdtgrp, 64, "sdt_%s", note->provider);
8558c2ecf20Sopenharmony_ci		if (ret < 0)
8568c2ecf20Sopenharmony_ci			break;
8578c2ecf20Sopenharmony_ci		/* Try to find same-name entry */
8588c2ecf20Sopenharmony_ci		entry = probe_cache__find_by_name(pcache, sdtgrp, note->name);
8598c2ecf20Sopenharmony_ci		if (!entry) {
8608c2ecf20Sopenharmony_ci			entry = probe_cache_entry__new(NULL);
8618c2ecf20Sopenharmony_ci			if (!entry) {
8628c2ecf20Sopenharmony_ci				ret = -ENOMEM;
8638c2ecf20Sopenharmony_ci				break;
8648c2ecf20Sopenharmony_ci			}
8658c2ecf20Sopenharmony_ci			entry->sdt = true;
8668c2ecf20Sopenharmony_ci			ret = asprintf(&entry->spev, "%s:%s=%s", sdtgrp,
8678c2ecf20Sopenharmony_ci					note->name, note->name);
8688c2ecf20Sopenharmony_ci			if (ret < 0)
8698c2ecf20Sopenharmony_ci				break;
8708c2ecf20Sopenharmony_ci			entry->pev.event = strdup(note->name);
8718c2ecf20Sopenharmony_ci			entry->pev.group = strdup(sdtgrp);
8728c2ecf20Sopenharmony_ci			list_add_tail(&entry->node, &pcache->entries);
8738c2ecf20Sopenharmony_ci		}
8748c2ecf20Sopenharmony_ci		buf = synthesize_sdt_probe_command(note, pathname, sdtgrp);
8758c2ecf20Sopenharmony_ci		if (!buf) {
8768c2ecf20Sopenharmony_ci			ret = -ENOMEM;
8778c2ecf20Sopenharmony_ci			break;
8788c2ecf20Sopenharmony_ci		}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci		ret = strlist__add(entry->tevlist, buf);
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci		free(buf);
8838c2ecf20Sopenharmony_ci		entry = NULL;
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci		if (ret == -ENOMEM) {
8868c2ecf20Sopenharmony_ci			pr_err("strlist__add failed with -ENOMEM\n");
8878c2ecf20Sopenharmony_ci			break;
8888c2ecf20Sopenharmony_ci		}
8898c2ecf20Sopenharmony_ci	}
8908c2ecf20Sopenharmony_ci	if (entry) {
8918c2ecf20Sopenharmony_ci		list_del_init(&entry->node);
8928c2ecf20Sopenharmony_ci		probe_cache_entry__delete(entry);
8938c2ecf20Sopenharmony_ci	}
8948c2ecf20Sopenharmony_ci	cleanup_sdt_note_list(&sdtlist);
8958c2ecf20Sopenharmony_ci	return ret;
8968c2ecf20Sopenharmony_ci}
8978c2ecf20Sopenharmony_ci#endif
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_cistatic int probe_cache_entry__write(struct probe_cache_entry *entry, int fd)
9008c2ecf20Sopenharmony_ci{
9018c2ecf20Sopenharmony_ci	struct str_node *snode;
9028c2ecf20Sopenharmony_ci	struct stat st;
9038c2ecf20Sopenharmony_ci	struct iovec iov[3];
9048c2ecf20Sopenharmony_ci	const char *prefix = entry->sdt ? "%" : "#";
9058c2ecf20Sopenharmony_ci	int ret;
9068c2ecf20Sopenharmony_ci	/* Save stat for rollback */
9078c2ecf20Sopenharmony_ci	ret = fstat(fd, &st);
9088c2ecf20Sopenharmony_ci	if (ret < 0)
9098c2ecf20Sopenharmony_ci		return ret;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	pr_debug("Writing cache: %s%s\n", prefix, entry->spev);
9128c2ecf20Sopenharmony_ci	iov[0].iov_base = (void *)prefix; iov[0].iov_len = 1;
9138c2ecf20Sopenharmony_ci	iov[1].iov_base = entry->spev; iov[1].iov_len = strlen(entry->spev);
9148c2ecf20Sopenharmony_ci	iov[2].iov_base = (void *)"\n"; iov[2].iov_len = 1;
9158c2ecf20Sopenharmony_ci	ret = writev(fd, iov, 3);
9168c2ecf20Sopenharmony_ci	if (ret < (int)iov[1].iov_len + 2)
9178c2ecf20Sopenharmony_ci		goto rollback;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci	strlist__for_each_entry(snode, entry->tevlist) {
9208c2ecf20Sopenharmony_ci		iov[0].iov_base = (void *)snode->s;
9218c2ecf20Sopenharmony_ci		iov[0].iov_len = strlen(snode->s);
9228c2ecf20Sopenharmony_ci		iov[1].iov_base = (void *)"\n"; iov[1].iov_len = 1;
9238c2ecf20Sopenharmony_ci		ret = writev(fd, iov, 2);
9248c2ecf20Sopenharmony_ci		if (ret < (int)iov[0].iov_len + 1)
9258c2ecf20Sopenharmony_ci			goto rollback;
9268c2ecf20Sopenharmony_ci	}
9278c2ecf20Sopenharmony_ci	return 0;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_cirollback:
9308c2ecf20Sopenharmony_ci	/* Rollback to avoid cache file corruption */
9318c2ecf20Sopenharmony_ci	if (ret > 0)
9328c2ecf20Sopenharmony_ci		ret = -1;
9338c2ecf20Sopenharmony_ci	if (ftruncate(fd, st.st_size) < 0)
9348c2ecf20Sopenharmony_ci		ret = -2;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	return ret;
9378c2ecf20Sopenharmony_ci}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ciint probe_cache__commit(struct probe_cache *pcache)
9408c2ecf20Sopenharmony_ci{
9418c2ecf20Sopenharmony_ci	struct probe_cache_entry *entry;
9428c2ecf20Sopenharmony_ci	int ret = 0;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	/* TBD: if we do not update existing entries, skip it */
9458c2ecf20Sopenharmony_ci	ret = lseek(pcache->fd, 0, SEEK_SET);
9468c2ecf20Sopenharmony_ci	if (ret < 0)
9478c2ecf20Sopenharmony_ci		goto out;
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	ret = ftruncate(pcache->fd, 0);
9508c2ecf20Sopenharmony_ci	if (ret < 0)
9518c2ecf20Sopenharmony_ci		goto out;
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	for_each_probe_cache_entry(entry, pcache) {
9548c2ecf20Sopenharmony_ci		ret = probe_cache_entry__write(entry, pcache->fd);
9558c2ecf20Sopenharmony_ci		pr_debug("Cache committed: %d\n", ret);
9568c2ecf20Sopenharmony_ci		if (ret < 0)
9578c2ecf20Sopenharmony_ci			break;
9588c2ecf20Sopenharmony_ci	}
9598c2ecf20Sopenharmony_ciout:
9608c2ecf20Sopenharmony_ci	return ret;
9618c2ecf20Sopenharmony_ci}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_cistatic bool probe_cache_entry__compare(struct probe_cache_entry *entry,
9648c2ecf20Sopenharmony_ci				       struct strfilter *filter)
9658c2ecf20Sopenharmony_ci{
9668c2ecf20Sopenharmony_ci	char buf[128], *ptr = entry->spev;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	if (entry->pev.event) {
9698c2ecf20Sopenharmony_ci		snprintf(buf, 128, "%s:%s", entry->pev.group, entry->pev.event);
9708c2ecf20Sopenharmony_ci		ptr = buf;
9718c2ecf20Sopenharmony_ci	}
9728c2ecf20Sopenharmony_ci	return strfilter__compare(filter, ptr);
9738c2ecf20Sopenharmony_ci}
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ciint probe_cache__filter_purge(struct probe_cache *pcache,
9768c2ecf20Sopenharmony_ci			      struct strfilter *filter)
9778c2ecf20Sopenharmony_ci{
9788c2ecf20Sopenharmony_ci	struct probe_cache_entry *entry, *tmp;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	list_for_each_entry_safe(entry, tmp, &pcache->entries, node) {
9818c2ecf20Sopenharmony_ci		if (probe_cache_entry__compare(entry, filter)) {
9828c2ecf20Sopenharmony_ci			pr_info("Removed cached event: %s\n", entry->spev);
9838c2ecf20Sopenharmony_ci			list_del_init(&entry->node);
9848c2ecf20Sopenharmony_ci			probe_cache_entry__delete(entry);
9858c2ecf20Sopenharmony_ci		}
9868c2ecf20Sopenharmony_ci	}
9878c2ecf20Sopenharmony_ci	return 0;
9888c2ecf20Sopenharmony_ci}
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_cistatic int probe_cache__show_entries(struct probe_cache *pcache,
9918c2ecf20Sopenharmony_ci				     struct strfilter *filter)
9928c2ecf20Sopenharmony_ci{
9938c2ecf20Sopenharmony_ci	struct probe_cache_entry *entry;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	for_each_probe_cache_entry(entry, pcache) {
9968c2ecf20Sopenharmony_ci		if (probe_cache_entry__compare(entry, filter))
9978c2ecf20Sopenharmony_ci			printf("%s\n", entry->spev);
9988c2ecf20Sopenharmony_ci	}
9998c2ecf20Sopenharmony_ci	return 0;
10008c2ecf20Sopenharmony_ci}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci/* Show all cached probes */
10038c2ecf20Sopenharmony_ciint probe_cache__show_all_caches(struct strfilter *filter)
10048c2ecf20Sopenharmony_ci{
10058c2ecf20Sopenharmony_ci	struct probe_cache *pcache;
10068c2ecf20Sopenharmony_ci	struct strlist *bidlist;
10078c2ecf20Sopenharmony_ci	struct str_node *nd;
10088c2ecf20Sopenharmony_ci	char *buf = strfilter__string(filter);
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	pr_debug("list cache with filter: %s\n", buf);
10118c2ecf20Sopenharmony_ci	free(buf);
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	bidlist = build_id_cache__list_all(true);
10148c2ecf20Sopenharmony_ci	if (!bidlist) {
10158c2ecf20Sopenharmony_ci		pr_debug("Failed to get buildids: %d\n", errno);
10168c2ecf20Sopenharmony_ci		return -EINVAL;
10178c2ecf20Sopenharmony_ci	}
10188c2ecf20Sopenharmony_ci	strlist__for_each_entry(nd, bidlist) {
10198c2ecf20Sopenharmony_ci		pcache = probe_cache__new(nd->s, NULL);
10208c2ecf20Sopenharmony_ci		if (!pcache)
10218c2ecf20Sopenharmony_ci			continue;
10228c2ecf20Sopenharmony_ci		if (!list_empty(&pcache->entries)) {
10238c2ecf20Sopenharmony_ci			buf = build_id_cache__origname(nd->s);
10248c2ecf20Sopenharmony_ci			printf("%s (%s):\n", buf, nd->s);
10258c2ecf20Sopenharmony_ci			free(buf);
10268c2ecf20Sopenharmony_ci			probe_cache__show_entries(pcache, filter);
10278c2ecf20Sopenharmony_ci		}
10288c2ecf20Sopenharmony_ci		probe_cache__delete(pcache);
10298c2ecf20Sopenharmony_ci	}
10308c2ecf20Sopenharmony_ci	strlist__delete(bidlist);
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	return 0;
10338c2ecf20Sopenharmony_ci}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_cienum ftrace_readme {
10368c2ecf20Sopenharmony_ci	FTRACE_README_PROBE_TYPE_X = 0,
10378c2ecf20Sopenharmony_ci	FTRACE_README_KRETPROBE_OFFSET,
10388c2ecf20Sopenharmony_ci	FTRACE_README_UPROBE_REF_CTR,
10398c2ecf20Sopenharmony_ci	FTRACE_README_USER_ACCESS,
10408c2ecf20Sopenharmony_ci	FTRACE_README_MULTIPROBE_EVENT,
10418c2ecf20Sopenharmony_ci	FTRACE_README_IMMEDIATE_VALUE,
10428c2ecf20Sopenharmony_ci	FTRACE_README_END,
10438c2ecf20Sopenharmony_ci};
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_cistatic struct {
10468c2ecf20Sopenharmony_ci	const char *pattern;
10478c2ecf20Sopenharmony_ci	bool avail;
10488c2ecf20Sopenharmony_ci} ftrace_readme_table[] = {
10498c2ecf20Sopenharmony_ci#define DEFINE_TYPE(idx, pat)			\
10508c2ecf20Sopenharmony_ci	[idx] = {.pattern = pat, .avail = false}
10518c2ecf20Sopenharmony_ci	DEFINE_TYPE(FTRACE_README_PROBE_TYPE_X, "*type: * x8/16/32/64,*"),
10528c2ecf20Sopenharmony_ci	DEFINE_TYPE(FTRACE_README_KRETPROBE_OFFSET, "*place (kretprobe): *"),
10538c2ecf20Sopenharmony_ci	DEFINE_TYPE(FTRACE_README_UPROBE_REF_CTR, "*ref_ctr_offset*"),
10548c2ecf20Sopenharmony_ci	DEFINE_TYPE(FTRACE_README_USER_ACCESS, "*u]<offset>*"),
10558c2ecf20Sopenharmony_ci	DEFINE_TYPE(FTRACE_README_MULTIPROBE_EVENT, "*Create/append/*"),
10568c2ecf20Sopenharmony_ci	DEFINE_TYPE(FTRACE_README_IMMEDIATE_VALUE, "*\\imm-value,*"),
10578c2ecf20Sopenharmony_ci};
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_cistatic bool scan_ftrace_readme(enum ftrace_readme type)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci	int fd;
10628c2ecf20Sopenharmony_ci	FILE *fp;
10638c2ecf20Sopenharmony_ci	char *buf = NULL;
10648c2ecf20Sopenharmony_ci	size_t len = 0;
10658c2ecf20Sopenharmony_ci	bool ret = false;
10668c2ecf20Sopenharmony_ci	static bool scanned = false;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	if (scanned)
10698c2ecf20Sopenharmony_ci		goto result;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	fd = open_trace_file("README", false);
10728c2ecf20Sopenharmony_ci	if (fd < 0)
10738c2ecf20Sopenharmony_ci		return ret;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	fp = fdopen(fd, "r");
10768c2ecf20Sopenharmony_ci	if (!fp) {
10778c2ecf20Sopenharmony_ci		close(fd);
10788c2ecf20Sopenharmony_ci		return ret;
10798c2ecf20Sopenharmony_ci	}
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	while (getline(&buf, &len, fp) > 0)
10828c2ecf20Sopenharmony_ci		for (enum ftrace_readme i = 0; i < FTRACE_README_END; i++)
10838c2ecf20Sopenharmony_ci			if (!ftrace_readme_table[i].avail)
10848c2ecf20Sopenharmony_ci				ftrace_readme_table[i].avail =
10858c2ecf20Sopenharmony_ci					strglobmatch(buf, ftrace_readme_table[i].pattern);
10868c2ecf20Sopenharmony_ci	scanned = true;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	fclose(fp);
10898c2ecf20Sopenharmony_ci	free(buf);
10908c2ecf20Sopenharmony_ci
10918c2ecf20Sopenharmony_ciresult:
10928c2ecf20Sopenharmony_ci	if (type >= FTRACE_README_END)
10938c2ecf20Sopenharmony_ci		return false;
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_ci	return ftrace_readme_table[type].avail;
10968c2ecf20Sopenharmony_ci}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_cibool probe_type_is_available(enum probe_type type)
10998c2ecf20Sopenharmony_ci{
11008c2ecf20Sopenharmony_ci	if (type >= PROBE_TYPE_END)
11018c2ecf20Sopenharmony_ci		return false;
11028c2ecf20Sopenharmony_ci	else if (type == PROBE_TYPE_X)
11038c2ecf20Sopenharmony_ci		return scan_ftrace_readme(FTRACE_README_PROBE_TYPE_X);
11048c2ecf20Sopenharmony_ci
11058c2ecf20Sopenharmony_ci	return true;
11068c2ecf20Sopenharmony_ci}
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_cibool kretprobe_offset_is_supported(void)
11098c2ecf20Sopenharmony_ci{
11108c2ecf20Sopenharmony_ci	return scan_ftrace_readme(FTRACE_README_KRETPROBE_OFFSET);
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_cibool uprobe_ref_ctr_is_supported(void)
11148c2ecf20Sopenharmony_ci{
11158c2ecf20Sopenharmony_ci	return scan_ftrace_readme(FTRACE_README_UPROBE_REF_CTR);
11168c2ecf20Sopenharmony_ci}
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_cibool user_access_is_supported(void)
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci	return scan_ftrace_readme(FTRACE_README_USER_ACCESS);
11218c2ecf20Sopenharmony_ci}
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_cibool multiprobe_event_is_supported(void)
11248c2ecf20Sopenharmony_ci{
11258c2ecf20Sopenharmony_ci	return scan_ftrace_readme(FTRACE_README_MULTIPROBE_EVENT);
11268c2ecf20Sopenharmony_ci}
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_cibool immediate_value_is_supported(void)
11298c2ecf20Sopenharmony_ci{
11308c2ecf20Sopenharmony_ci	return scan_ftrace_readme(FTRACE_README_IMMEDIATE_VALUE);
11318c2ecf20Sopenharmony_ci}
1132